document
API test

监听解锁

POST

Description or Example

# Bug修复 ## 调用订单微服务抛异常 > 异常总是显示无法解析html页面 ```java GET http://order.bitmall.com/order/order/orderStatus/123 Redirections: -> http://auth.bitmall.com/login.html HTTP/1.1 200 OK Server: nginx/1.10.3 Date: Mon, 11 Sep 2023 12:06:03 GMT Content-Type: text/html;charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive Content-Language: zh-CN <!DOCTYPE html> <html lang="en"> ``` > 通过测试可知, 系统给我重定向到了登录页, 原因是我们没有登录, 但实际上, 我们是已经登陆过了的, 因此, 本质原因是没有读取到Session里面的信息, 即当前微服务没有配置SpringSession, 要想解决当前问题, 配置即可 ### BUT > **这里不可以强行加上登录信息, 因为用户可能下完订单后就退出了, 如果, 还对登录拦截的话, 过期的订单就无法释放库存了, 因此, 不能拦截登陆状态** > 应该在对应的过滤器加上该路径 ## 为什么`List<init>`失效 > 这个适合@RequestMapping有关, 因为这个注解默认发送的是`GET`请求, 这会导致集合参数无法正常的构建, 因此, 我们将他改成`@PostMapping`指定Post请求即可 # 知识点 ## 为什么都返回R > 返回RG更多是标准化返回,即使不返回R,因异常的消息重新入队,也不会造成消息丢失 ## 监听器不太注意异常捕获, 为什么? > 因为这里采取的是手动ACK模式, 如果异常, 根本不会ACK, 消息自然不会丢失 ## 为什么另一个微服务会疯狂的输出? > 因为消息处理失败重新入队了, 但是, 处理消息的监听器只有一个, 因此, 当消息重新入对后又被当前监听器处理, 不断失败, 不断重试, 因此会出现这种情况 # 核心代码 ```java @RabbitListener(queues = "stock-release-stock-queue") @Component public class WareListener { @Autowired private WareFeignService wareFeignService; @Autowired private OrderFeignService orderFeignService; @Autowired private SendMsgUtil sendMsgUtil; /** * 被动释放库存的监听器 */ @RabbitHandler public void PassiveReleaseStock(WareTO wareTO, Message message, Channel channel) throws IOException { try { // 1. 判断是否存在工作单(判断工作单详情也一样) {获取工作单的同时还能获取订单号} Long taskId = wareTO.getTaskId(); R info = wareFeignService.getTaskDetail(taskId); if (!ifNoProblem(message, channel, info)) return; WareOrderTaskBO orderTaskBO = info.getData("wareOrderTask", new TypeReference<WareOrderTaskBO>() {}); if (orderTaskBO != null) { // 存在工作单 String orderSn = orderTaskBO.getOrderSn(); // 获取订单号 info = orderFeignService.getOrderStatus(orderSn); if (!ifNoProblem(message, channel, info)) return; Integer status = info.getData(new TypeReference<Integer>() { }); if (status == null || OrderStatusEnum.CANCLED.getCode().equals(status)) { // 不存在订单状态 或者 订单状态是未支付, 都需要解锁 info = wareFeignService.unLockSkuStock(wareTO.getTaskDetailId().toString()); if (!ifNoProblem(message, channel, info)) return; } } // 不存在工作单, 说明ware锁定库存整体回滚了, 不需要解锁 channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); // 记录日志 sendMsgUtil.finish(message.getMessageProperties().getMessageId()); }catch (Exception e) { // 有任何的异常都需要重新入队 // 其实不这样干也可以, 因为不ACK也会重新入队 channel.basicReject(message.getMessageProperties().getDeliveryTag(), true); } } /** * 主动释放库存 * @param orderSn * @param message * @param channel * @throws IOException */ @RabbitHandler public void activeReleaseStock(String orderSn, Message message, Channel channel) throws IOException { try { // 通过订单号获取工作单 R info = wareFeignService.getTaskByOrderSn(orderSn); if (!ifNoProblem(message, channel, info)) return; WareOrderTaskBO orderTaskBO = info.getData(new TypeReference<WareOrderTaskBO>() { }); Long taskId = orderTaskBO.getId(); // 工作单号 // 通过工作单获取工作单详情 info = wareFeignService.getAllTaskDetailByTaskId(taskId.toString()); if (!ifNoProblem(message, channel, info)) return; List<WareOrderTaskDetailTO> details = info.getData(new TypeReference<List<WareOrderTaskDetailTO>>() { }); // 所有的工作单详情 if (details != null && !details.isEmpty()) { info = wareFeignService.unLockSkusStock(details); if (!ifNoProblem(message, channel, info)) return; } // 执行到这, 完全没有问题, 确认消息 channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); // 记录日志 sendMsgUtil.finish(message.getMessageProperties().getMessageId()); }catch (Exception e) { channel.basicReject(message.getMessageProperties().getDeliveryTag(), true); } } private Boolean ifNoProblem(Message message, Channel channel, R info) throws IOException { if (info.getCode() != 0) { // 有问题, 需要重新入队 channel.basicReject(message.getMessageProperties().getDeliveryTag(), true); return false; } // true是没有问题 return true; } } ```