一. 订单渲染结算页
1. 用户收件地址查询: 登录人名称-> 收件人地址信息-> 表tb-address
(1) com.changgou.user.service.impl.AddressServiceImpl类 /*** * 收件地址查询 * @param username * @return */ @Override public List<Address> list(String username) { Address address = new Address(); address.setUsername(username); return addressMapper.select(address); } (2) com.changgou.user.controller.AddressController类 /**** * 用户收件地址 */ @GetMapping(value = "/list") public Result<List<Address>> list(){ //获取用户登录信息 Map<String, String> userMap = tokenDecode.getUserInfo(); String username = userMap.get("username"); //查询用户收件地址 List<Address> addressList = addressService.list(username); return new Result(true, StatusCode.OK,"查询成功!",addressList); }
2. 拦截器获取令牌
@Component public class FeignInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate requestTemplate) { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); if (requestAttributes!=null){ HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); if (request!=null){ Enumeration<String> headerNames = request.getHeaderNames(); if (headerNames!=null){ while (headerNames.hasMoreElements()){ String headerName = headerNames.nextElement(); if (headerName.equals("authorization")){ String headerValue = request.getHeader(headerName); requestTemplate.header(headerName,headerValue); } } } } } } }
3. 通过令牌动态获取登录人信息-> TokenDecode中通过JWTHelper中的decodeAndVerfify
public class TokenDecode { //公钥 private static final String PUBLIC_KEY = "public.key"; private static String publickey=""; /*** * 获取用户信息 * @return */ public Map<String,String> getUserInfo(){ //获取授权信息 OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails(); //令牌解码 return dcodeToken(details.getTokenValue()); } /*** * 读取令牌数据 */ public Map<String,String> dcodeToken(String token){ //校验Jwt Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(getPubKey())); //获取Jwt原始内容 String claims = jwt.getClaims(); return JSON.parseObject(claims,Map.class); } /** * 获取非对称加密公钥 Key * @return 公钥 Key */ public String getPubKey() { if(!StringUtils.isEmpty(publickey)){ return publickey; } Resource resource = new ClassPathResource(PUBLIC_KEY); try { InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream()); BufferedReader br = new BufferedReader(inputStreamReader); publickey = br.lines().collect(Collectors.joining("\n")); return publickey; } catch (IOException ioe) { return null; } } }
4. 购物车数据回显
@Autowired private CartFeign cartFeign; @RequestMapping("ready/order") public String readyOrder(Model model) { //1. 收件人地址信息 List<Address> addressList = addressFeign.list().getData(); model.addAttribute("address",addressList); //2. 购物车信息 Map map = cartFeign.list(); List<OrderItem> oderItemList = (List<OrderItem>) map.get("orderItemList"); Integer totalMoney = (Integer) map.get("totalMoney"); Integer totalNum = (Integer) map.get("totalNum"); model.addAttribute("carts",oderItemList); model.addAttribute("totalMoney",totalMoney); model.addAttribute("totalNum", totalNum); //3.默认收件人信息 for (Address address : addressList) { if ("1".equals(address.getIsDefault())){ //默认收件人 model.addAttribute("deAddr",address); break; } } return "order"; }
二. 用户下单实现
1. 需要操作的表:
tb_order: 订单表的相关信息(orderId);
tb_order_item: 订单中每一项商品信息明细表(skuList)
2. 业务流程: 提交订单-> 到达订单微服务-> 保存到MySQL(订单表和订单明细表)-> 订单微服务远程调用goods微服务-> 较少goods表的商品库存
(1) OrderServiceImpl.java. 拿到购物车信息-> 封装到order表和order_item表-> 删除购物车 /** * 增加 * @param order */ @Override @GlobalTransactional(name = "order_add") //Fescar全局事务注解 public String add(Order order){ //1.获取购物车相关数据(redis) Map cartMap = cartService.list(order.getUsername()); List<OrderItem> orderItemList = (List<OrderItem>) cartMap.get("orderItemList"); //2. 统计订单总金额和数量 //3. 填充订单数据并保存到tb_order表中 order.setTotalNum((Integer) cartMap.get("totalNum")); order.setTotalMoney((Integer) cartMap.get("totalMoney")); order.setPayMoney((Integer) cartMap.get("totalMoney")); order.setCreateTime(new Date()); order.setUpdateTime(new Date()); order.setBuyerRate("0"); // 0:未评价; 1:已评价 order.setSourceType("1"); //1: 来源web端 order.setOrderStatus("0"); //0:订单未完成; 1:已完成; 2:已退货 order.setPayStatus("0"); //0:未支付; 1:已支付 order.setConsignStatus("0"); //0:未发货; 1:已发货 //设置订单号 String orderId = idWorker.nextId()+""; order.setId(orderId); //保存order到tb_order表中 orderMapper.insertSelective(order); //4. 填充当前订单项数据并保存到tb_order_item for (OrderItem orderItem : orderItemList) { orderItem.setId(idWorker.nextId()+""); orderItem.setIsReturn("0"); //0:未退货; 1:已退货 orderItem.setOrderId(orderId); orderItemMapper.insertSelective(orderItem); } //4.2 扣减库存并增加销量 skuFeign.decrCount(order.getUsername()); //4.3 增加用户积分, 此方法已经被下面的分布式事务消息队列实现 //userFeign.addPoints(10); //在订单数据库中的任务表tb_task添加任务数据 Task task = new Task(); task.setCreateTime(new Date()); task.setUpdateTime(new Date()); task.setMqExchange(RabbitMQConfig.EX_BUYING_ADDPOINTUSER); task.setMqRoutingkey(RabbitMQConfig.CG_BUYING_ADDPOINT_KEY); Map map = new HashMap(); map.put("username", order.getUsername()); map.put("orderId", orderId); map.put("point", order.getPayMoney()); task.setRequestBody(JSON.toJSONString(map)); taskMapper.insertSelective(task); // //5. 删除购物车的数据 redisTemplate.delete("cart_"+order.getUsername()); //orderMapper.insert(order); //发送延迟消息 rabbitTemplate.convertAndSend("", "queue.ordercreate", orderId); return orderId; } (2) orderController.java以feign的形式进行暴露, 给web渲染服务OrderController.java调用 @Autowired private OrderFeign orderFeign; @PostMapping("/add") @ResponseBody public Result add(Order order) { Result result = orderFeign.add(order); return result; }
三. 库存变更实现
1. 业务: order微服务-> 传用户名到goods微服务-> goods微服务找到redis中购物车数据-> 执行库存减少
Goods商品微服务中: (1) SkuMapper.java public interface SkuMapper extends Mapper<Sku> { //扣减库存并增加销量 @Update("update tb_sku set num=num-#{num},sale_num=sale_num+#{num} where id=#{skuId} and num >=#{num}") int decrCount(OrderItem orderItem); } (2) SkuServiceImpl.java @Autowired private RedisTemplate redisTemplate; //删减库存 @Override public void decrCount(String username) { //1. 获取购物车中数据 List<OrderItem> orderItemList = redisTemplate.boundHashOps("cart_" + username).values(); //2. 循环扣减库存并增加销量 for (OrderItem orderItem : orderItemList) { //返回受影响的数据库行数 int count = skuMapper.decrCount(orderItem); if (count<=0){ throw new RuntimeException("库存不足,请重试!"); } } } (3) SkuController.java //扣减库存 @PostMapping("/decr/count") public Result decrCount(@RequestParam("username") String username) { skuService.decrCount(username); return new Result(true, StatusCode.OK, "库存扣减成功"); } (4) service_goods_api中SkuFeign.java //扣减库存 @PostMapping("/sku/decr/count") public Result decrCount(@RequestParam("username") String username);
2. Order订单微服务调用goods微服务:
(1) 商品微服务整合了Oauth2, order微服务需要传递令牌-> 使用FeignInterceptor拦截器
(2) 拦截器以@Bean形式生命在Order订单微服务中