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;
}
}
```