订单结算页+下单业务

news2024/11/28 14:34:32

一、订单结算页

在这里插入图片描述

1.业务分析

(1) 获取用户收货地址信息
一般的收货地址都是多个,使用时选中一个,所以收货地址使用List集合封装

(2)获取购物车商品信息
购物车商品也是多个,使用List集合封装

(3)查询商品库存
查询每个商品是否有库存,显示是否有货,使用Map封装

(4)计算订单金额
使用BigDecimal计算,算出每个商品的总价(价格*件数)然后求和,最后扣除优惠价格得到结算价,还可以做积分业务

(5)页面防重复提交,保证幂等性
重复提交会重复执行下单业务,提交订单前在redis中存一个token令牌,然后在执行下单操作前去redis中去取这个token,如果能取到,代表是第一次提交页面,然后删除令牌,如果取不到证明令牌代表已经被删除了,表示页面不是第一次提交,告诉用户 “请问重复提交页面”
删令牌的操作需要保证原子性,取令牌,校验,删除是三次操作,如果其中一步错误就会导致删除失败,所以必须保证要么全部成功或全部失败,这就是原子性,所以使用redis提供的lua脚本取执行删令牌的操作

2.代码

(1)订单页面实体类设计

public class OrderConfirmVo {

    @Getter @Setter
    /** 会员收获地址列表 **/
    List<MemberAddressVo> memberAddressVos;

    @Getter @Setter
    /** 所有选中的购物项 **/
    List<OrderItemVo> items;

    /** 发票记录 **/
    @Getter @Setter
    /** 优惠券(会员积分) **/
    private Integer integration;

    /** 防止重复提交的令牌 **/
    @Getter @Setter
    private String orderToken;

    private Integer count;
    private BigDecimal total;
    private BigDecimal payPrice;

    @Getter @Setter
    Map<Long,Boolean> stocks;

    /**
     * 获取商品总数量
     */
    public Integer getCount() {
        Integer count = 0;
        if (items != null && items.size() > 0) {
            for (OrderItemVo item : items) {
                count += item.getCount();
            }
        }
        return count;
    }


    /** 订单总额 **/
    //BigDecimal total;
    //计算订单总额
    public BigDecimal getTotal() {
        BigDecimal totalNum = BigDecimal.ZERO;
        for (OrderItemVo item : items) {
            BigDecimal multiply = item.getPrice().multiply(new BigDecimal(Integer.toString(item.getCount())));
            totalNum = totalNum.add(multiply);
        }
        return totalNum;
    }


    /** 应付价格 **/
    //BigDecimal payPrice;
    public BigDecimal getPayPrice() {
        return getTotal();
    }
}

(1)业务使用异步编排提升效率

/**
     * 展示结算页信息
     *
     * Feign 丢失请求头的问题? 如果使用ThreadLocal的方式直接获取id会获取不到,远程调用没经过拦截器获取不到id
     * 异步丢失
     */
    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        MemberOAuthVo memberOAuthVo = OrderLoginIntercepter.threadLocal.get();
        //TODO :获取当前线程请求头信息(解决Feign异步调用丢失请求头问题)
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();


        CompletableFuture<Void> memberRunAsync = CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                //每一个线程都来共享之前的请求数据
                RequestContextHolder.setRequestAttributes(requestAttributes);

                //1.查询用户信息
                List<MemberAddressVo> list = memberFeignService.getMemberReceiveAddress(memberOAuthVo.getId());
                orderConfirmVo.setMemberAddressVos(list);
            }
        }, executor);

        CompletableFuture<Void> orderRunAsync = CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                //每一个线程都来共享之前的请求数据
                RequestContextHolder.setRequestAttributes(requestAttributes);

                //2.查询商品信息
                List<OrderItemVo> orderItemVos = cartFeignService.orderFeignCart(memberOAuthVo.getId());
                orderConfirmVo.setItems(orderItemVos);
            }
        }, executor).thenRunAsync(new Runnable() {
            @Override
            public void run() {
                //查库存  怎么查库存  查库存参数List<Long> skuIds
                List<Long> skuIds = orderConfirmVo.getItems().stream().map(item -> {
                    return item.getSkuId();
                }).collect(Collectors.toList());
                R<List<SkuHasStockVo>> r = wareFeignService.getSkuHasStock(skuIds);
                if (r.getCode() == 0){
                    List<SkuHasStockVo> data = r.getData(new TypeReference<List<SkuHasStockVo>>() {
                    });
                    // 下界 接收参数的类型,上界 返回的类型
                    //Function<? super T, ? extends K> keyMapper,
                    //Function<? super T, ? extends U> valueMapper
                    Map<Long, Boolean> collect = data.stream().collect(Collectors.toMap(new Function<SkuHasStockVo, Long>() {
                        @Override
                        public Long apply(SkuHasStockVo skuHasStockVo) {
                            return skuHasStockVo.getSkuId();
                        }
                    }, SkuHasStockVo::getHasStock));
                    orderConfirmVo.setStocks(collect);
                }

            }
        });

        //会员积分
        orderConfirmVo.setIntegration(memberOAuthVo.getIntegration());

        //设置订单token,防止页面重复提交,保证幂等性
        String key = OrderConstant.ORDER_TOKEN_PREFIX + memberOAuthVo.getId();
        String orderToken = UUID.randomUUID().toString().replace("_","");
        redisTemplate.opsForValue().set(key,orderToken) ;

        //set token
        orderConfirmVo.setOrderToken(orderToken);

        CompletableFuture.allOf(memberRunAsync,orderRunAsync).get();
        return orderConfirmVo;
    }

二、下单

1.业务分析

(1)校验页面幂等性
获取token令牌,删除令牌,校验成功进入下单操作,校验失败返回code
(2)创建订单
1.生成订单号,使用唯一ID生成,存入OrderSn
2.获取用户选中的地址信息,存入OrderEntity
3.获取购物车最新的商品信息,这里不能直接获取订单页的商品信息,防止购物车商品信息发生变化与订单页商品不一致
根据上送skuId取获取redis中存储的商品信息,然后筛选出已勾选的商品,并且查出该商品最新价格,最后存入List
(3) 验价
防止商品价格发生变化(可能订单页保存的价格与最新价格存在差异),在下单前进行比对,这里使用两价格相减取绝对值,考虑到存在优惠的问题,只要保证绝对值<0.05就表示验价通过
(4)保存订单数据
验价成功就可以保证订单,但需要添加事务@Transactional
(5)锁定库存
商品下单需要锁定库存,相当于订一批货,那么别人在去买这批货时就无法购买,先占个位置,如果超过支付时间未付款,就解锁库存,锁库存操作是给锁定库存添加需要购买的件数stock_locked + num,最大不能超过商品总库存 stock - stock_locked >= num
锁库存先查该skuId商品在那些仓库有库存,然后循环去锁库存,只要有一个仓库锁库存成功就代表成功,如果没有一个仓库能锁成功代表锁库存失败,告诉用户该商品库存不足,并且锁库存之前需要判断是否有仓库存在库存,没有就直接不用锁库存了

2.代码

(1)下单整体业务

@Transactional
    @Override
    public SubmitOrderResponseVo placeOrder(OrderSubmitVo submitVo) {
        SubmitOrderResponseVo submitOrderResponseVo = new SubmitOrderResponseVo();
        submitOrderResponseVo.setCode(0);
        MemberOAuthVo memberOAuthVo = OrderLoginIntercepter.threadLocal.get();
        String key = OrderConstant.ORDER_TOKEN_PREFIX + memberOAuthVo.getId();
        //原子性操作:1.取出token 2.对比token 3.删除token
        //execute(RedisScript<T> script, List<K> keys, Object... args)
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long luaReturn = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(key), submitVo.getOrderToken());
        //1-删除成功   0-删除失败
        if (luaReturn.equals(1L)){
            //令牌删除成功 -> 创建订单
            OrderCreateTo order = createOrder(submitVo);

            //验价 应付价格-
            BigDecimal payAmount = order.getOrder().getPayAmount();//应付价格
            BigDecimal payPrice = submitVo.getPayPrice();
            double abs = Math.abs(payAmount.subtract(payPrice).doubleValue());
            if (abs < 0.01){
                //验价成功 -> 保存订单信息 -> 锁定库存

                //TODO 保存订单信息
                saveOrder(order.getOrder(),order.getOrderItems());

                //远程锁定库存
                List<OrderItemEntity> orderItems = order.getOrderItems();
                List<OrderItemVo> collect = orderItems.stream().map(item -> {
                    OrderItemVo orderItemVo = new OrderItemVo();
                    orderItemVo.setSkuId(item.getSkuId());
                    orderItemVo.setCount(item.getSkuQuantity());
                    return orderItemVo;
                }).collect(Collectors.toList());
                OrderStockRequest orderStockRequest = new OrderStockRequest();
                orderStockRequest.setOrderSn(order.getOrder().getOrderSn());
                orderStockRequest.setItemVos(collect);
                //TODO 远程锁库存
                R r = wareFeignService.orderStock(orderStockRequest);
                if (r.getCode() == 0){
                    submitOrderResponseVo.setCode(0);
                    submitOrderResponseVo.setOrder(order.getOrder());
                    return submitOrderResponseVo;
                }else {
                    //锁库存失败
                    //锁定失败
                    String msg = (String) r.get("msg");
                    throw new SkuNoStockException(msg);
                }

            }else {
                //验价失败
                submitOrderResponseVo.setCode(2);
                return submitOrderResponseVo;
            }

        }else {
            //令牌删除失败
            submitOrderResponseVo.setCode(1);
            return submitOrderResponseVo;
        }

    }

(2)获取订单页信息

/**
     *  创建订单
     *     (1)用户信息:地址 1
     *     (2)购物车商品信息:应该直接查询购物车数据,不能获取结算页的商品数据,  list
     *     (3)下单金额  1
     *      (4) 验价
     */
    public OrderCreateTo createOrder(OrderSubmitVo submitVo){
        OrderCreateTo orderCreateTo = new OrderCreateTo();
        //订单号-唯一id
        String timeId = IdWorker.getTimeId();
        OrderEntity orderEntity = buildOrderEntity(submitVo, timeId);
        List<OrderItemEntity> orderItemEntityList = buildOrderItems(timeId);
        //封装:订单总额、应付总额
        OrderEntity order = computePrice(orderEntity,orderItemEntityList);
        orderCreateTo.setOrder(order);
        orderCreateTo.setOrderItems(orderItemEntityList);
        return orderCreateTo;
    }

    /**
     * 封装OrderEntity:
     * 订单总额、应付总额
     * 促销优化金额、积分抵扣金额、优惠券抵扣金额
     *
     */
    public OrderEntity computePrice(OrderEntity order,List<OrderItemEntity> orderItems){
        //订单总额
        BigDecimal totalAmount = new BigDecimal("0.0");
        //促销优化金额、积分抵扣金额、优惠券抵扣金额
        BigDecimal promotionAmount = new BigDecimal("0.0");
        BigDecimal integrationAmount = new BigDecimal("0.0");
        BigDecimal couponAmount = new BigDecimal("0.0");
        //积分、成长值
        Integer integration = 0;
        Integer growth = 0;
        for (OrderItemEntity orderItem : orderItems) {
            totalAmount = totalAmount.add(orderItem.getRealAmount());
            promotionAmount = promotionAmount.add(orderItem.getPromotionAmount());
            integrationAmount = integrationAmount.add(orderItem.getIntegrationAmount());
            couponAmount = couponAmount.add(orderItem.getCouponAmount());
            integration += orderItem.getGiftIntegration();
            growth += orderItem.getGiftGrowth();
        }

        //订单总额
        order.setTotalAmount(totalAmount);
        //应付总额 = 订单总额 + 运费
        order.setPayAmount(totalAmount.add(order.getFreightAmount()));
        //促销优化金额、积分抵扣金额、优惠券抵扣金额
        order.setPromotionAmount(promotionAmount);
        order.setIntegrationAmount(integrationAmount);
        order.setCouponAmount(couponAmount);
        //积分、成长值
        order.setIntegration(integration);
        order.setGrowth(growth);

        return order;
    }

    /**
     * 订单信息
     * OrderEntity
     *
     * 1.订单号
     * 2.用户地址信息
     * 3.运费金额
     */
    public OrderEntity buildOrderEntity(OrderSubmitVo submitVo,String timeId){
        OrderEntity orderEntity = new OrderEntity();

        orderEntity.setOrderSn(timeId);
        orderEntity.setCreateTime(new Date());

        //用户地址
        MemberOAuthVo memberOAuthVo = OrderLoginIntercepter.threadLocal.get();
        orderEntity.setMemberId(memberOAuthVo.getId());
        MemberAddressVo member = memberFeignService.getMember(memberOAuthVo.getId());
        orderEntity.setReceiverName(member.getName());
        orderEntity.setReceiverPhone(member.getPhone());
        orderEntity.setReceiverPostCode(member.getPostCode());
        orderEntity.setReceiverProvince(member.getProvince());
        orderEntity.setReceiverCity(member.getCity());
        orderEntity.setReceiverRegion(member.getRegion());
        orderEntity.setReceiverDetailAddress(member.getDetailAddress());

        //用户名
        orderEntity.setMemberUsername(memberOAuthVo.getUsername());

        //运费金额
        R r = wareFeignService.fare(submitVo.getAddrId());
        if (r.getCode() == 0){
            FareVo data = (FareVo)r.getData(new TypeReference<FareVo>() {
            });
            //运费金额
            orderEntity.setFreightAmount(data.getFare());
        }
        orderEntity.setPayType(submitVo.getPayType());

        //订单状态-0待付款
        orderEntity.setStatus(OrderConstant.ORDER_STATUS);

        //字段确认天数
        orderEntity.setAutoConfirmDay(7);

        return orderEntity;
    }

    /**
     * 订单商品
     * List<OrderItemEntity>  因为商品有多个,所以是list
     *
     * 1.订单号
     * 2.sku信息
     * 3.spu信息
     */
    public List<OrderItemEntity> buildOrderItems(String timeId){
        //查询redis商品信息
        MemberOAuthVo memberOAuthVo = OrderLoginIntercepter.threadLocal.get();
        List<OrderItemVo> orderItemVos = cartFeignService.orderFeignCart(memberOAuthVo.getId());
        List<OrderItemEntity> collect = orderItemVos.stream().map(item -> {
            OrderItemEntity orderItemEntity = new OrderItemEntity();
            //订单号
            orderItemEntity.setOrderSn(timeId);
            //spu信息
            SpuInfoEntity spuInfo = productFeignService.getSpuBySkuId(item.getSkuId());
            orderItemEntity.setSpuId(spuInfo.getId());
            orderItemEntity.setSpuName(spuInfo.getSpuName());
            orderItemEntity.setCategoryId(spuInfo.getCatalogId());
            //Sku信息
            orderItemEntity.setSkuId(item.getSkuId());
            orderItemEntity.setSkuName(item.getTitle());
            orderItemEntity.setSkuPic(item.getImage());
            orderItemEntity.setSkuPrice(item.getPrice());
            orderItemEntity.setSkuQuantity(item.getCount());
            //商品销售属性组合 List<String> -> String
            //集合 根据指定的分割符转换 为字符串
            String jsonString = JSON.toJSONString(item.getSkuAttrValues());
            orderItemEntity.setSkuAttrsVals(jsonString);
            //促销、优惠券、积分
            orderItemEntity.setPromotionAmount(BigDecimal.ZERO);
            orderItemEntity.setCouponAmount(BigDecimal.ZERO);
            orderItemEntity.setIntegrationAmount(BigDecimal.ZERO);
            //该商品经过优惠后的分解金额
            BigDecimal totalPrice = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity().toString()));
            BigDecimal realPrice = totalPrice.subtract(orderItemEntity.getPromotionAmount())
                            .subtract(orderItemEntity.getCouponAmount())
                                    .subtract(orderItemEntity.getIntegrationAmount());
            orderItemEntity.setRealAmount(realPrice);
            //赠送积分、成长值
            orderItemEntity.setGiftIntegration(totalPrice.intValue());
            orderItemEntity.setGiftGrowth(totalPrice.intValue());

            return orderItemEntity;
        }).collect(Collectors.toList());
        return collect;
    }

(3)锁定库存

    /**
     * 库存锁定
     *
     * 1.查询该商品在那些仓库有库存
     * 2.锁定库存,遍历仓库去锁定库存,只要有一个仓库锁定代表成功,如果没有一个仓库能锁成功,抛异常,该sku商品库存不足
     *
     */
//    @Transactional(rollbackFor = NoWareStockException.class)
    @Transactional
    @Override
    public boolean orderStock(OrderStockRequest orderStockRequest) {
        List<OrderItemVo> itemVos = orderStockRequest.getItemVos();
        List<SkuStockfromWare> collect = itemVos.stream().map(item -> {
            SkuStockfromWare skuStockfromWare = new SkuStockfromWare();
            skuStockfromWare.setSkuId(item.getSkuId());
            skuStockfromWare.setNum(item.getCount());
            //查询该商品在那些仓库有库存
            List<Long> wareId = wareSkuDao.skuStockfromWare(item.getSkuId());
            skuStockfromWare.setWareId(wareId);
            return skuStockfromWare;
        }).collect(Collectors.toList());

        //根据skuId遍历
        for (SkuStockfromWare skuStockfromWare : collect) {
            //判断是否锁定成功
            boolean flag = false;

            //判断该商品是否有仓库存在库存
            List<Long> wareIdList = skuStockfromWare.getWareId();
            if (wareIdList.size() < 0 || wareIdList == null){
                throw new NoWareStockException(skuStockfromWare.getSkuId());
            }
            for (Long wareId : wareIdList) {
                Long count = wareSkuDao.LockedStockFromWare(skuStockfromWare.getSkuId(),wareId,skuStockfromWare.getNum());
                if (count.equals(1L)){
                    //锁定成功
                    flag = true;
                    //该商品锁定库存成功就执行下一个商品
                    break;
                }

            }

            //如果没有一个仓库扣成功,代表此skuId的库存不足
            if (!flag){
                throw new SkuNoStockException(skuStockfromWare.getSkuId());
            }

        }
        return true;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/741858.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VSCode安装及环境配置详细教程(windows版本)

目录 安装VSCode 安装Python 检查环境变量 检查Python是否能运行 VSCode环境配置 切换成简体中文 添加Python插件 编写代码运行 &#xff01;&#xff01;请先在官网下载Python和VSCode安装包&#xff0c;保存至本地 Python官网&#xff1a;https://www.python.org/do…

多元回归预测 | Matlab基于灰狼算法(GWO)优化高斯过程回归(GWO-GPR)的数据回归预测,matlab代码,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab基于灰狼算法(GWO)优化高斯过程回归(GWO-GPR)的数据回归预测,matlab代码,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源…

APP测试要点有哪些?

我们日常购物、旅游、支付等活动都离不开手机&#xff0c;由此衍生了很多APP。 比如每天使用频率非常高的微信、支付宝、微博、抖音、王者荣耀等等。 APP测试主要进行功能测试、性能测试、自动化测试、安全性测试、兼容性测试、专项测试。 01、APP测试流程 APP测试流程与web测…

软考A计划-系统集成项目管理工程师-项目进度管理-上

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

python glob库glob函数返回为空时

这里的max函数会报空序列的错误&#xff0c;原因就是glob.glob函数读取不到文件的问题&#xff0c;推测是脚本所在文件夹与传入的文件夹地址不对造成的&#xff0c;比如C&#xff1a;/tor/data/jiaoben.py,而文件所在文件夹是C&#xff1a;/tor/biaobei/

自媒体13条监管新规来了:做自媒体还有前途吗?

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 各位自媒体人&#xff0c;大家一定要逐条逐句&#xff0c;认真研读&#xff0c;领会精神&#xff0c;掌握要求&#xff0c;规范运营好自己的账号&#xff0c;切莫越界踩线&#xff0c;多为广大网友…

邮箱推荐和(警告)使用qq邮箱的坏处

qq如果发布违规消息&#xff0c;比如群聊无意发布会导致你账号封号&#xff0c;而且随着次数增多&#xff0c;会导致永久封号&#xff0c;你的qq音乐&#xff0c;qq浏览器&#xff0c;qq游戏&#xff0c;{qq邮箱}&#xff0c;全部会无法登录&#xff0c;比如需要登陆邮箱验证码…

初学者也能轻松掌握的MQL4编程入门指南

MQL4编程是外汇交易中极为重要的一部分&#xff0c;掌握MQL4编程可以帮助交易者快速创建自己的交易算法&#xff0c;进而提高交易效率和盈利水平。但是对于初学者来说&#xff0c;MQL4编程可能会显得有些困难。本篇文章就是为初学者准备的&#xff0c;针对MQL4编程进行入门指导…

对RAM和ROM的理解

什么是RAM、ROM&#xff1f; RAM(Random Access Memory)随机存取存储器 ROM(Read Only Memory)只读存储器 先记住一件事 RAM断电将失去数据 ROM断电仍会保留数据 RAM、ROM、Flash、内存条、硬盘、SD卡到底怎么归类&#xff1f; 我们先来看下计算机的原理和计算机的需求 …

【Leetcode】59. 螺旋矩阵II

给定一个正整数 n&#xff0c;生成一个包含 1 到 n^2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的正方形矩阵。 示例: 输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ] 面试频率较高 1. 先定义一个空矩阵 2. startx表示行起始 starty表示列起始 3. 左闭右开…

信息安全-加密技术

一、概念 加密是利用数学方法将明文(plain text)转换为密文(cipher),从而达到保护数据的目的。 加密是一个使信息只对正确的接收者可读,其他用户看到的是乱码信息的过程。 加密技术作用 加密技术在网络上的作用就是防止私有化信息在网络上被拦截和窃取。通过加密可保…

性能测试:Jmeter-Beanshell请求加密实例

前言 进行性能测试时&#xff0c;有可能遇到一种场景&#xff1a;接口请求由于安全问题&#xff0c;需要进行加密发送。 这种场景下&#xff0c;使用Jmeter实现性能测试&#xff0c;则也需要使用同样的加密规则发送请求报文。 要实现此类性能测试有几种策略&#xff1a; 直…

纹理环绕方式

一般而言&#xff0c;纹理坐标范围(0,0)到(1,1)&#xff0c;若设置超出该范围&#xff0c;则会按照如下环绕方式处理。 设置纹理参数的函数原型为&#xff1a; 坐标信息&#xff1a; float vertices[] { // positions // colors // texture coords 0.9f, 0.9f, 0.0f, 1.0f,…

线上后端接口响应过慢排查记录_MySQLthread cache命中率过低导致的接口响应慢

文章目录 问题现象初步排查调整临时解决措施问题二次定位原因分析为什么会出现异常 问题现象 9点多&#xff0c;运营同学反馈系统某模块业务响应很慢&#xff0c;登录系统查看&#xff0c;后端接口响应耗时很久&#xff0c;需要好几秒&#xff1b; 查看对应的服务器资源情况&a…

纸箱视觉定位抓取软硬件方案

【检测目的】 产品定位抓取 【客户要求】 精度为0.1mm 【拍摄与处理效图一】 【拍摄与处理效图二】 【拍摄与处理效图三】 【拍摄与处理效图四】 【拍摄与处理效图五】 【实验原理及说明】 【实验原理及说明】 【实验原理及说明】 【方案评估】 根据目前的图像和处理结果来看…

数据结构与算法——数据结构有哪些,常用数据结构详解

数据结构是学习数据存储方式的一门学科&#xff0c;那么&#xff0c;数据存储方式有哪几种呢&#xff1f;下面将对数据结构的学习内容做一个简要的总结。 数据结构大致包含以下几种存储结构&#xff1a; 线性表&#xff0c;还可细分为顺序表、链表、栈和队列&#xff1b;树结…

云计算的学习(二)

二、计算虚拟化 1.计算虚拟化的介绍 1.1虚拟化简介 a.什么是虚拟化 将物理设备逻辑化&#xff0c;转化成文件或者文件夹&#xff0c;这个文件或文件夹一定包含两个部分&#xff1a;一部分用于记录设备配置信息&#xff0c;另一部分记录用户数据。 虚拟机摆脱了服务器的禁锢…

Centos7安装go语言环境

Centos7安装go语言环境 文章目录 下载解压缩配置变量验证已安装 下载 从go语言官网下载对应的二进制存档包 wget https://dl.google.com/go/go1.12.linux-amd64.tar.gz解压缩 解压缩到/usr/local&#xff0c;将自动在其中创建一个Go树 /usr/local/go tar -C /usr/local -xz…

HashMap学习总结

1. JDK 1.8 主要进行了哪些优化&#xff1f; 1&#xff09;底层数据结构从“数组链表”改成“数组链表红黑树”&#xff0c;主要是优化了 hash 冲突较严重时&#xff0c;链表过长的查找性能&#xff1a;O(n) -> O(logn)。 2&#xff09;计算 table 初始容量的方式发生了改…

GLM 130B和chatGLM2-6B模型结构

GLM-130B 一、预训练 采用双向注意力机制&#xff0c;对被遮挡的部分及逆行预测&#xff0c; 可以自由设置单词mask,句子smask,文章gmask,可以根据任务的不同设置mask&#xff0c;文本理解设置单词级别mask&#xff0c;文本生成色湖之句子级别的gmask&#xff0c;glm130B中设置…