本文讲解的是一个订单支付过程需要处理的业务,并讲解在Spring Boot中监听redis失效的key方法来处理订单问题。
一、提交订单信息(submitOrder实现类)
/**
* @Author: SmallPang
* @Description: 添加订单信息
* @Date: 2020/2/26
* @Param order: 订单实体
* @return: com.pang.front.Model.Result
**/
@Override
public Result submitOrder(Order order, List<IDSum> idSumList) {
Result result = new Result();
result.setMsg("添加订单失败");
order.setOrderStatus("待付款");
int orderNum = orderMapper.submitOrder(order);
int uoNum = orderMapper.insertUOTable(order.getUserID(), order.getOrderID());
int ogNum = orderMapper.insertOGTable(order.getOrderID(), idSumList);
if (orderNum + uoNum + ogNum == idSumList.size() + 2) {
result.setSuccess(true);
result.setMsg("添加订单成功");
//删除购物车该商品
orderMapper.deleteShoppingCart(order.getUserID(), idSumList);
//减库存
orderMapper.reduceGoodsSum(idSumList);
//待付款订单写入redis
redisUtil.set("Order:" + order.getOrderID().toString(), idSumList, 9000L);
return result;
}
return result;
}
分析24行:redisUtil.set(“Order:” + order.getOrderID().toString(), idSumList, 9000L);
将待支付的订单ID存进redis中,String类型。
二、订单支付
public String returnUrl(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException, AlipayApiException {
response.setContentType("text/html;charset=utf-8");
System.out.println("进入了returnUrl");
boolean verifyResult = rsaCheckV1(request);
if(verifyResult){
//验证成功
//请在这里加上商户的业务逻辑程序代码,如保存支付宝交易号
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
System.out.println("returnUrl的商户订单号:" + out_trade_no);
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
System.out.println("returnUrl的支付宝交易号:" + trade_no);
String ids = (String) request.getSession().getAttribute("ids");
if(!StringUtils.isEmpty(ids)){
String[] split = ids.split(",");
for (String s : split) {
}
}
Map<String, String> map = new HashMap<>();
map.put("orderID", out_trade_no);
rabbitTemplate.convertAndSend("pang.direct", "pang.news", map);
return "redirect:/my_order";
}else{
return "redirect:error";
}
}
分析24行:rabbitTemplate.convertAndSend(“pang.direct”, “pang.news”, map);
支付成功,将订单ID传入RabbitMQ,使用消息队列异步处理
三、监听消息队列
@RabbitHandler
@RabbitListener(queues = "pang.news")
public void successPay(JSONObject message) {
System.out.println("监听的获得的数据" + message.getString("orderID"));
Long orderID = Long.parseLong(message.getString("orderID"));
System.out.println("监听获得的ID" + orderID);
int rtnNum = orderMapper.changeOrderStatus(orderID);
if (rtnNum == 1) {
redisUtil.del("orderID:" + orderID);
}
}
成功支付订单之后,进行改变订单状态。(没有进行减库操作是因为我设计的是在提交订单的时候就进行减库操作了)
四、订单支付过期处理
1、配置一个redis监听器的Config
@Configuration
public class RedisListenerConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(new RedisExpiredListener(), new PatternTopic("__keyevent@__:expired"));
return container;
}
}
分析7行:"__keyevent@__:expired"
如果是需要只监听redis中db1分库,写成"_keyevent@1_:expired",否则则是监听全部分库
2、定义redis监听器
/**
* @Author: SmallPang
* @Description: 监听所有db的过期事件__keyevent@*__:expired"
* @Date: 2020/5/12
* @Param null:
* @return: null
**/
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
@Autowired
OrderMapper orderMapper;
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/**
* @Author: SmallPang
* @Description: 针对redis数据失效事件,进行数据处理
* @Date: 2020/5/12
* @Param message: 监听信息
* @Param pattern:
* @return: void
**/
@Override
public void onMessage(Message message, byte[] pattern) {
// 用户做自己的业务处理即可,注意message.toString()可以获取失效的key
String keyMessage = message.toString();
if(keyMessage.startsWith("Order:")){
//如果是Order:开头的key,进行处理
Long orderID = Long.parseLong(keyMessage.split(":")[1]);
System.out.println("监听失效的ID:" + orderID);
Order order = orderMapper.selectOrderByID(orderID);
if (order != null) {
List<OrderGoods> goodsIDList = orderMapper.getOrderList(order.getOrderID());
int rtnNum = orderMapper.rollbackInventory(goodsIDList);
if (rtnNum == goodsIDList.size()) {
System.out.println("库存回滚成功");
} else {
System.out.println("库存回滚失败");
}
}
}
}
}
其中:message就是监听得到的redis过期的key,找出失效的订单信息,进行库存回滚操作。