day18 订单服务,完成订单确认页功能

1.订单服务基本概念

1.订单中心

  • 电商系统涉及到3流,分别是信息流、资金流、物流,而订单系统作为中枢将三者有机的集合起来。
  • 订单模块是电商系统的枢纽,在订单这个环节上需求获取多个模块的数据和信息,同时对这些信息进行加工处理后流向下个环节,这一系列就构成了订单的信息流通。

2.订单构成

image-20221113223649570

2.环境搭建

  • 上传nginx资源
  • html替换路径

3.订单登陆拦截

  • 购物单点击去结算,必须是登陆状态下才允许结算,所以在跳转到结算页时必须做登陆校验
@Configuration
public class LoginUserInterceptor implements HandlerInterceptor {
    public static ThreadLocal<MemberResponseVo> loginUser = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object attribute = request.getSession().getAttribute(AuthConstant.LOGIN_USER);
        if (Objects.nonNull(attribute) && attribute instanceof MemberResponseVo) {
            MemberResponseVo vo = (MemberResponseVo) attribute;
            loginUser.set(vo);
            return true;
        }
        request.getSession().setAttribute("msg", "请先进行登录");
        response.sendRedirect("http://auth.dreammall.com/login.html");
        return false;
    }
}

@Configuration
public class DreamMallOrderWebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginUserInterceptor loginUserInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginUserInterceptor).addPathPatterns("/**");
    }
}

4.订单确认页功能实现

  • controller层

      /**
         * 去结算确认页
         * @param model
         * @param request
         * @return
         * @throws ExecutionException
         * @throws InterruptedException
         */
        @GetMapping(value = "/toTrade")
        public String toTrade(Model model, HttpServletRequest request){
            OrderConfirmVo confirmVo = orderService.confirmOrder();
    
            model.addAttribute("confirmOrderData",confirmVo);
            //展示订单确认的数据
            return "confirm";
        }
    
  • service层实现

        @Override
        public OrderConfirmVo confirmOrder() {
    
            //构建OrderConfirmVo
            OrderConfirmVo confirmVo = new OrderConfirmVo();
    
            //获取当前用户登录的信息
            MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
    
            //获取当前线程请求头信息(解决Feign异步调用丢失请求头问题)
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    
            //开启第一个异步任务
            CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {
                //每一个线程都来共享之前的请求数据
                RequestContextHolder.setRequestAttributes(requestAttributes);
    
                //1、远程查询所有的收获地址列表
                List<MemberAddressVo> address = memberFeignService.getAddress(memberResponseVo.getId());
                confirmVo.setMemberAddressVos(address);
            }, threadPoolExecutor);
    
            //开启第二个异步任务
            CompletableFuture<Void> cartInfoFuture = CompletableFuture.runAsync(() -> {
                //每一个线程都来共享之前的请求数据
                RequestContextHolder.setRequestAttributes(requestAttributes);
    
                //2、远程查询购物车所有选中的购物项
                List<OrderItemVo> currentCartItems = cartFeignService.getCurrentCartItems();
                confirmVo.setItems(currentCartItems);
                //feign在远程调用之前要构造请求,调用很多的拦截器
            }, threadPoolExecutor).thenRunAsync(() -> {
                List<OrderItemVo> items = confirmVo.getItems();
                //获取全部商品的id
                List<Long> skuIds = items.stream()
                        .map((OrderItemVo::getSkuId))
                        .collect(Collectors.toList());
    
                //远程查询商品库存信息
                R skuHasStock = wareFeignService.getSkuHasStock(skuIds);
                List<SkuStockVo> skuStockVos = skuHasStock.getData("data", new TypeReference<List<SkuStockVo>>() {});
                if (CollectionUtil.isNotEmpty(skuStockVos)) {
                    //将skuStockVos集合转换为map
                    Map<Long, Boolean> skuHasStockMap = skuStockVos.stream().collect(Collectors.toMap(SkuStockVo::getSkuId, SkuStockVo::getHasStock));
                    confirmVo.setStocks(skuHasStockMap);
                }
            }, threadPoolExecutor);
    
            //3、查询用户积分
            Integer integration = memberResponseVo.getIntegration();
            confirmVo.setIntegration(integration);
            //4、价格数据自动计算
            CompletableFuture.allOf(addressFuture, cartInfoFuture).join();
            return confirmVo;
        }
    }
    
  • 主要遇到的问题

    • feign远程调用导致request头中丢失cookie,从而cart模块从分布式session无法获取到数据

      image-20221202220320277

  • 解决方式如下

    // 自定义requestInterceptor 将当前线程的reuqest头中的cookie再次设置到请求头
    @Configuration
    public class DreamMallFeignConfig {
    
    
        @Bean("requestInterceptor")
        public RequestInterceptor requestInterceptor() {
            return template -> {
                // 获取当前线程请求
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                // 将cookie再次设置到请求头中
                if (null != requestAttributes) {
                    String cookie = requestAttributes.getRequest().getHeader("Cookie");
                    template.header("Cookie", cookie);
                }
            };
        }
    }
    
  • 第二个问题,多线程下依然存在丢失cookie的情况

    通过上下文参数传递的方式解决

    image-20221202220718653

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值