订单模块


之前设置了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; }

浙公网安备 33010602011771号