订单模块

 

 

 

 

 

之前设置了spring的session共享

 认证拦截

订单服务中的所有请求都是必须在认证的情况下处理的  所有我们需要添加一个校验是否认证的拦截器

先去session中获取信息  如果不为空则放行  如果为空 那么需要登陆 跳转到登录页

public class AuthInterceptor  implements HandlerInterceptor {
    // 本地线程对象  Map<thread,Object>
    public static ThreadLocal<MemberVO> threadLocal = new ThreadLocal();
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 通过HttpSession获取当前登录的用户信息
        HttpSession session = request.getSession();
        Object attribute = session.getAttribute(AuthConstant.AUTH_SESSION_REDIS);
        if(attribute != null){
            MemberVO memberVO = (MemberVO) attribute;
            threadLocal.set(memberVO);
            return true;
        }
        // 如果 attribute == null 说明没有登录,那么我们就需要重定向到登录页面
        session.setAttribute(AuthConstant.AUTH_SESSION_MSG,"请先登录");
        response.sendRedirect("http://auth.msb.com/login.html");
        return false;
    }
}

 注册拦截器   拦截所有访问order服务资源时被拦截器拦截  

@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/**");
        
    }
}

 session同级域名

@Configuration
public class MySessionConfig {
    @Bean
    public CookieSerializer cookieSerializer(){
        DefaultCookieSerializer cookieSerializer=new DefaultCookieSerializer();
        cookieSerializer.setDomainName("msb.com");//设置同级域名
        cookieSerializer.setCookieName("mall-session");
        return cookieSerializer;
    }
    @Bean 
    public RedisSerializer<Object> redisSerializer(){
        return new GenericJackson2JsonRedisSerializer();
    }
}

配置线程池

@Configuration
public class MyThreadPoolConfig {
    @Bean
    public ThreadPoolExecutor threadPoolExecutor(){
        /*配置线程池*/
        return new ThreadPoolExecutor(20,
                200,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10000),
                Executors.defaultThreadFactory(),
                new  ThreadPoolExecutor.AbortPolicy());
    }
}

配置远程调用时  请求头丢失配置

@Configuration
public class MallFeginConfig {
    
    @Bean
    public RequestInterceptor requestInterceptor(){
        
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                
                ServletRequestAttributes requestAttributes =(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = requestAttributes.getRequest();
                String cookie = request.getHeader("Cookie");
                if(!StringUtils.isEmpty(cookie)){
                requestTemplate.header("Cookie", cookie);
                }
            }
        };
    }
}

controller

@Controller
public class OrderWebController {
    
    @Autowired
    private OrderService orderService;
    
    @GetMapping("/toTrade")
    public String toTrade(Model model){
        //todo 查询订单确认页需要的信息
       OrderConfirmVO vo=orderService.confirmOder();
        model.addAttribute("confirmVo",vo);
        return "confirm";
    }
    
    
}

impl    在这里面我们开启了异步多线程执行  导致无法拉取到主线程中的threadLocal信息  所以我们需要RequestContextHolder获取主线程的请求参数信息 添加到异步线程中的请求头中

 /**
     * 获取订单确认页中需要获取的相关信息
     * @return
     */
    @Override
    public OrderConfirmVO confirmOder() {
        OrderConfirmVO vo=new OrderConfirmVO();
        MemberVO memberVO = AuthInterceptor.threadLocal.get();
        //获取到 RequestContextHolder 的相关信息 ******************
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            //同步主线程中的相关信息
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //根据存储在session中的member信息的id
            Long id = memberVO.getId();
            //1查询当前登陆用户对应的会员的地址信息
            List<MemberAddressVO> address = memberFeginService.getAddress(id);
            vo.setAddress(address);
        }, executor);
        //因为创建了异步任务  开启了新的线程 导致threadLocal无法拉取到信息   ps拦截器中的requestAttributes无法拉取到请求中的信息  说明不在同一个线程中
        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            //同步主线程中的相关信息
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //因为fegin在远程调用时会出现请求头丢失的情况
            //2查询购物车中选中的商品信息   这里会报错[text/html;charset=UTF-8]  因为cart服务中有拦截器 会获取session中的信息 session没有获取到就会重定向到html页面中 导致报错
            //所以我们需要重写请求拦截器 拦截header将session设置到里面   
            List<OderItemsVO> userCartItems = cartFeginService.getUserCartItems();
            vo.setItems(userCartItems);
        }, executor);
        try {
            CompletableFuture.allOf(future1).get();
        } catch (Exception e) {
            e.printStackTrace();
        } 
    
        //3计算订单的总金额 和支付的总金额
        
        return vo;
    }
}

memberFeginService.getAddress(id);的远程调用 impl

 @Override
    public List<MemberReceiveAddressEntity> getAddress(Long memberId) {
    
        return baseMapper.selectList(new QueryWrapper<MemberReceiveAddressEntity>().eq("member_id", memberId));
         
    }
cartFeginService.getUserCartItems() 的远程调用 impl
 /**
     * 获取当前登陆用户选中的商品信息
     * @return
     */
    @Override
    public List<CartItem> getUserCartItems() {
       
        BoundHashOperations<String, Object, Object> operations = getCartKeyOperation();
        List<Object> values = operations.values();//获取redis中的所有value
        List<CartItem> list = values.stream().map(item -> {
            String json = (String) item;//将value转换成json字符串
            CartItem cartItem = JSON.parseObject(json, CartItem.class);//然后转换成对象
            return cartItem;
        }).filter(item -> {
            return item.isCheck();//过滤  只返回item.isCheck()是true的对象
        }).collect(Collectors.toList());
        return list;
    }

  private BoundHashOperations<String, Object, Object> getCartKeyOperation() {
        MemberVO memberVO = AuthInterceptor.threadLocal.get();//获取当前的用户信息
        String cartKey = CartConstant.CART_PREFIX + memberVO.getId(); //将用户的id绑定一个对象 存储在redis中的键
        BoundHashOperations<String, Object, Object> hashOperations = redisTemplate.boundHashOps(cartKey);//当我们操作hashOperations
        return hashOperations;
    }

 

 
posted @ 2022-06-14 20:51  花心大萝卜li  阅读(65)  评论(0)    收藏  举报