定时订单消息关单功能开发
This commit is contained in:
parent
64efdd1f5e
commit
4c80b3e53f
@ -0,0 +1,18 @@
|
||||
package net.jieyuu.model;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class OrderMessage {
|
||||
/**
|
||||
* 消息id
|
||||
*/
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 订单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
|
||||
}
|
@ -2,10 +2,11 @@ package net.jieyuu.mapper;
|
||||
|
||||
import net.jieyuu.model.ProductOrderDO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author jieyuu
|
||||
@ -13,4 +14,5 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
*/
|
||||
public interface ProductOrderMapper extends BaseMapper<ProductOrderDO> {
|
||||
|
||||
void updateOrderPayState(@Param("outTradeNo") String outTradeNo, @Param("newState") String newState, @Param("oldState") String oldState);
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
package net.jieyuu.mq;
|
||||
|
||||
import com.rabbitmq.client.Channel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.jieyuu.model.OrderMessage;
|
||||
import net.jieyuu.service.ProductOrderService;
|
||||
import org.springframework.amqp.core.Message;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RabbitListener(queues = "${mqconfig.order_close_queue}")
|
||||
public class ProductOrderMQListener {
|
||||
|
||||
|
||||
@Autowired
|
||||
private ProductOrderService productOrderService;
|
||||
|
||||
/**
|
||||
* 消息重复消费,幂等性保障
|
||||
*
|
||||
* @param orderMessage
|
||||
* @param message
|
||||
* @param channel
|
||||
* @throws IOException
|
||||
*/
|
||||
@RabbitHandler
|
||||
public void closeProductOrder(OrderMessage orderMessage, Message message, Channel channel) throws IOException {
|
||||
log.info("监听到消息:closeProductOrder:{} ", orderMessage);
|
||||
long msgTag = message.getMessageProperties().getDeliveryTag();
|
||||
|
||||
try {
|
||||
boolean flag = productOrderService.closeProductOrder(orderMessage);
|
||||
if (flag) {// 关单成功
|
||||
channel.basicAck(msgTag, false);
|
||||
} else {// 失败
|
||||
channel.basicAck(msgTag, true);// 重新入队
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("定时关单失败:{}", orderMessage);
|
||||
channel.basicReject(msgTag, true);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package net.jieyuu.service;
|
||||
|
||||
import net.jieyuu.model.OrderMessage;
|
||||
import net.jieyuu.model.ProductOrderDO;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import net.jieyuu.request.ConfirmOrderRequest;
|
||||
@ -31,4 +32,11 @@ public interface ProductOrderService extends IService<ProductOrderDO> {
|
||||
* @return
|
||||
*/
|
||||
String queryProductOrderState(String outTradeNo);
|
||||
|
||||
/**
|
||||
* 队列监听定时关单接口
|
||||
*
|
||||
* @param orderMessage
|
||||
*/
|
||||
boolean closeProductOrder(OrderMessage orderMessage);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.jieyuu.config.RabbitMQConfig;
|
||||
import net.jieyuu.enums.*;
|
||||
import net.jieyuu.exception.BizException;
|
||||
import net.jieyuu.feign.CouponFeignService;
|
||||
@ -11,11 +12,8 @@ import net.jieyuu.feign.ProductFeignService;
|
||||
import net.jieyuu.feign.UserFeignService;
|
||||
import net.jieyuu.interceptor.LoginInterceptor;
|
||||
import net.jieyuu.mapper.ProductOrderItemMapper;
|
||||
import net.jieyuu.model.LoginUser;
|
||||
import net.jieyuu.model.OrderItemVO;
|
||||
import net.jieyuu.model.ProductOrderDO;
|
||||
import net.jieyuu.model.*;
|
||||
import net.jieyuu.mapper.ProductOrderMapper;
|
||||
import net.jieyuu.model.ProductOrderItemDO;
|
||||
import net.jieyuu.request.ConfirmOrderRequest;
|
||||
import net.jieyuu.request.LockCouponRecordRequest;
|
||||
import net.jieyuu.request.LockProductRequest;
|
||||
@ -26,6 +24,8 @@ import net.jieyuu.utils.CommonUtil;
|
||||
import net.jieyuu.utils.JsonData;
|
||||
import net.jieyuu.vo.CouponRecordVO;
|
||||
import net.jieyuu.vo.ProductOrderAddressVO;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -62,6 +62,12 @@ public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, Pro
|
||||
@Autowired
|
||||
private ProductOrderItemMapper productOrderItemMapper;
|
||||
|
||||
@Autowired
|
||||
private RabbitTemplate rabbitTemplate;
|
||||
|
||||
@Autowired
|
||||
private RabbitMQConfig rabbitMQConfig;
|
||||
|
||||
/**
|
||||
* * 防重提交
|
||||
* * 用户微服务-确认收货地址
|
||||
@ -110,12 +116,17 @@ public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, Pro
|
||||
ProductOrderDO productOrderDO = this.saveProductOrder(orderRequest, loginUser, orderOutTradeNo, addressVO);
|
||||
|
||||
//创建订单项
|
||||
this.saveproductOrderItems(orderOutTradeNo, productOrderDO.getId(), orderItemList);
|
||||
// 发送延迟消息,用于自动关单 todo
|
||||
this.saveProductOrderItems(orderOutTradeNo, productOrderDO.getId(), orderItemList);
|
||||
|
||||
// 发送延迟消息,用于自动关单
|
||||
OrderMessage orderMessage = new OrderMessage();
|
||||
orderMessage.setOutTradeNo(orderOutTradeNo);
|
||||
orderMessage.setMessageId(productOrderDO.getId());
|
||||
rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(), rabbitMQConfig.getOrderCloseDelayRoutingKey(), orderMessage);
|
||||
|
||||
//创建支付 todo
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -126,7 +137,7 @@ public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, Pro
|
||||
* @param orderId
|
||||
* @param orderItemList
|
||||
*/
|
||||
private void saveproductOrderItems(String orderOutTradeNo, Long orderId, List<OrderItemVO> orderItemList) {
|
||||
private void saveProductOrderItems(String orderOutTradeNo, Long orderId, List<OrderItemVO> orderItemList) {
|
||||
|
||||
List<ProductOrderItemDO> orderItemDOList = orderItemList.stream().map(obj -> {
|
||||
ProductOrderItemDO itemDO = new ProductOrderItemDO();
|
||||
@ -361,4 +372,35 @@ public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, Pro
|
||||
return productOrderDO.getState();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean closeProductOrder(OrderMessage orderMessage) {
|
||||
ProductOrderDO productOrderDO = productOrderMapper.selectOne(new QueryWrapper<ProductOrderDO>().eq("out_trade_no", orderMessage.getOutTradeNo()));
|
||||
|
||||
if (productOrderDO == null) {
|
||||
log.warn("直接确认消息,订单不存在:{}", orderMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (productOrderDO.getState().equalsIgnoreCase(ProductOrderStateEnum.PAY.name())) {// 成功消费
|
||||
log.info("直接确认消息,订单支付成功:{}", orderMessage);
|
||||
return true;
|
||||
}
|
||||
// 向第三方支付查询支付情况 todo
|
||||
|
||||
|
||||
|
||||
String payResult = "";
|
||||
// 订单结果为空,支付不成功,取消订单
|
||||
if (StringUtils.isBlank(payResult)) {
|
||||
productOrderMapper.updateOrderPayState(orderMessage.getOutTradeNo(), ProductOrderStateEnum.CANCEL.name(), ProductOrderStateEnum.NEW.name());
|
||||
log.info("结果为空,则未支付成功,本地取消订单:{}", orderMessage);
|
||||
return true;
|
||||
} else {
|
||||
// 将订单状态改为已经支付
|
||||
log.warn("支付成功,主动修改订单状态为已支付,造成该元婴的情况可能是支付通道回调有问题:{}", orderMessage);
|
||||
productOrderMapper.updateOrderPayState(orderMessage.getOutTradeNo(), ProductOrderStateEnum.PAY.name(), ProductOrderStateEnum.NEW.name());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,25 +4,35 @@
|
||||
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="net.jieyuu.model.ProductOrderDO">
|
||||
<id column="id" property="id" />
|
||||
<result column="out_trade_no" property="outTradeNo" />
|
||||
<result column="state" property="state" />
|
||||
<result column="create_time" property="createTime" />
|
||||
<result column="total_amount" property="totalAmount" />
|
||||
<result column="pay_amount" property="payAmount" />
|
||||
<result column="pay_type" property="payType" />
|
||||
<result column="nickname" property="nickname" />
|
||||
<result column="head_img" property="headImg" />
|
||||
<result column="user_id" property="userId" />
|
||||
<result column="del" property="del" />
|
||||
<result column="update_time" property="updateTime" />
|
||||
<result column="order_type" property="orderType" />
|
||||
<result column="receiver_address" property="receiverAddress" />
|
||||
<id column="id" property="id"/>
|
||||
<result column="out_trade_no" property="outTradeNo"/>
|
||||
<result column="state" property="state"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="total_amount" property="totalAmount"/>
|
||||
<result column="pay_amount" property="payAmount"/>
|
||||
<result column="pay_type" property="payType"/>
|
||||
<result column="nickname" property="nickname"/>
|
||||
<result column="head_img" property="headImg"/>
|
||||
<result column="user_id" property="userId"/>
|
||||
<result column="del" property="del"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
<result column="order_type" property="orderType"/>
|
||||
<result column="receiver_address" property="receiverAddress"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, out_trade_no, state, create_time, total_amount, pay_amount, pay_type, nickname, head_img, user_id, del, update_time, order_type, receiver_address
|
||||
id
|
||||
, out_trade_no, state, create_time, total_amount, pay_amount, pay_type, nickname, head_img, user_id, del, update_time, order_type, receiver_address
|
||||
</sql>
|
||||
|
||||
|
||||
<!-- 更新订单状态 乐观锁使用 -->
|
||||
<update id="updateOrderPayState">
|
||||
update product_order
|
||||
set `state` = #{newState}
|
||||
where out_trade_no = #{outTradeNo}
|
||||
and `state` = #{oldState}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
@ -3,6 +3,7 @@ package biz;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.jieyuu.OrderApplication;
|
||||
import net.jieyuu.model.CouponRecordMessage;
|
||||
import net.jieyuu.model.OrderMessage;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
@ -21,14 +22,13 @@ public class DemoApplicationTests {
|
||||
@Test
|
||||
public void send() {
|
||||
rabbitTemplate.convertAndSend("order.event.exchange", "order.close.delay.routing.key", "this is a new order");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCouponRecordRelease() {
|
||||
CouponRecordMessage message = new CouponRecordMessage();
|
||||
OrderMessage message = new OrderMessage();
|
||||
message.setOutTradeNo("123456abc");
|
||||
message.setTaskId(1l);
|
||||
message.setMessageId(1l);
|
||||
rabbitTemplate.convertAndSend("order.event.exchange", "order.close.delay.routing.key", message);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user