6.3 超时取消订单
This commit is contained in:
parent
1ce438395f
commit
21fcb40991
@ -12,11 +12,18 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(value = "item-service",fallbackFactory = ItemClientFallbackFactory.class)
|
||||
@FeignClient(value = "item-service",fallbackFactory = ItemClientFallbackFactory.class)
|
||||
public interface ItemClient {
|
||||
|
||||
@GetMapping("/items")
|
||||
List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
|
||||
|
||||
//批量扣减库存
|
||||
@PutMapping("/items/stock/deduct")
|
||||
void deductStock(@RequestBody List<OrderDetailDTO> items);
|
||||
|
||||
//批量恢复库存
|
||||
@PutMapping("/items/stock/restore")
|
||||
void restoreStock(@RequestBody List<OrderDetailDTO> items);
|
||||
|
||||
}
|
||||
|
18
hm-api/src/main/java/com/hmall/api/client/PayClient.java
Normal file
18
hm-api/src/main/java/com/hmall/api/client/PayClient.java
Normal file
@ -0,0 +1,18 @@
|
||||
package com.hmall.api.client;
|
||||
|
||||
import com.hmall.api.client.fallback.PayClientFallback;
|
||||
import com.hmall.api.dto.PayOrderDTO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
@FeignClient(value = "pay-service", fallbackFactory = PayClientFallback.class)
|
||||
public interface PayClient {
|
||||
/**
|
||||
* 根据交易订单id查询支付单
|
||||
* @param id 业务订单id
|
||||
* @return 支付单信息
|
||||
*/
|
||||
@GetMapping("/pay-orders/biz/{id}")
|
||||
PayOrderDTO queryPayOrderByBizOrderNo(@PathVariable("id") Long id);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.hmall.api.client.fallback;
|
||||
|
||||
import cn.hutool.db.sql.Order;
|
||||
import com.hmall.api.client.ItemClient;
|
||||
import com.hmall.api.dto.ItemDTO;
|
||||
import com.hmall.api.dto.OrderDetailDTO;
|
||||
@ -26,7 +27,12 @@ public class ItemClientFallbackFactory implements FallbackFactory<ItemClient> {
|
||||
@Override
|
||||
public void deductStock(List<OrderDetailDTO> items) {
|
||||
// 库存扣减业务需要触发事务回滚,查询失败,抛出异常
|
||||
log.error("[ITEM-FALLBACK] deductStock 降级,原因:", cause);
|
||||
log.error("扣减库存失败,原因:", cause);
|
||||
throw new BizIllegalException(cause);
|
||||
}
|
||||
@Override
|
||||
public void restoreStock(List<OrderDetailDTO> items){
|
||||
log.error("恢复商品库存失败,原因:",cause);
|
||||
throw new BizIllegalException(cause);
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.hmall.api.client.fallback;
|
||||
|
||||
import com.hmall.api.client.PayClient;
|
||||
import com.hmall.api.dto.PayOrderDTO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||
|
||||
@Slf4j
|
||||
public class PayClientFallback implements FallbackFactory<PayClient> {
|
||||
@Override
|
||||
public PayClient create(Throwable cause) {
|
||||
return new PayClient() {
|
||||
@Override
|
||||
public PayOrderDTO queryPayOrderByBizOrderNo(Long id) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
49
hm-api/src/main/java/com/hmall/api/dto/PayOrderDTO.java
Normal file
49
hm-api/src/main/java/com/hmall/api/dto/PayOrderDTO.java
Normal file
@ -0,0 +1,49 @@
|
||||
package com.hmall.api.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 支付订单
|
||||
* </p>
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(description = "支付单数据传输实体")
|
||||
public class PayOrderDTO {
|
||||
@ApiModelProperty("id")
|
||||
private Long id;
|
||||
@ApiModelProperty("业务订单号")
|
||||
private Long bizOrderNo;
|
||||
@ApiModelProperty("支付单号")
|
||||
private Long payOrderNo;
|
||||
@ApiModelProperty("支付用户id")
|
||||
private Long bizUserId;
|
||||
@ApiModelProperty("支付渠道编码")
|
||||
private String payChannelCode;
|
||||
@ApiModelProperty("支付金额,单位分")
|
||||
private Integer amount;
|
||||
@ApiModelProperty("付类型,1:h5,2:小程序,3:公众号,4:扫码,5:余额支付")
|
||||
private Integer payType;
|
||||
@ApiModelProperty("付状态,0:待提交,1:待支付,2:支付超时或取消,3:支付成功")
|
||||
private Integer status;
|
||||
@ApiModelProperty("拓展字段,用于传递不同渠道单独处理的字段")
|
||||
private String expandJson;
|
||||
@ApiModelProperty("第三方返回业务码")
|
||||
private String resultCode;
|
||||
@ApiModelProperty("第三方返回提示信息")
|
||||
private String resultMsg;
|
||||
@ApiModelProperty("支付成功时间")
|
||||
private LocalDateTime paySuccessTime;
|
||||
@ApiModelProperty("支付超时时间")
|
||||
private LocalDateTime payOverTime;
|
||||
@ApiModelProperty("支付二维码链接")
|
||||
private String qrCodeUrl;
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
@ApiModelProperty("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
@ -82,4 +82,10 @@ public class ItemController {
|
||||
public void deductStock(@RequestBody List<OrderDetailDTO> items){
|
||||
itemService.deductStock(items);
|
||||
}
|
||||
|
||||
@ApiOperation("批量恢复库存")
|
||||
@PutMapping("/stock/restore")
|
||||
public void restoreStock(@RequestBody List<OrderDetailDTO> items) {
|
||||
itemService.restoreStock(items);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,11 @@ import org.apache.ibatis.annotations.Update;
|
||||
* @since 2023-05-05
|
||||
*/
|
||||
public interface ItemMapper extends BaseMapper<Item> {
|
||||
|
||||
//减少库存
|
||||
@Update("UPDATE item SET stock = stock - #{num} WHERE id = #{itemId}")
|
||||
void updateStock(OrderDetailDTO orderDetail);
|
||||
|
||||
//恢复库存
|
||||
@Update("UPDATE item SET stock = stock + #{num} WHERE id = #{itemId}")
|
||||
void restoreStock(OrderDetailDTO orderDetail);
|
||||
}
|
||||
|
@ -21,4 +21,6 @@ public interface IItemService extends IService<Item> {
|
||||
void deductStock(List<OrderDetailDTO> items);
|
||||
|
||||
List<ItemDTO> queryItemByIds(Collection<Long> ids);
|
||||
|
||||
void restoreStock(List<OrderDetailDTO> items);
|
||||
}
|
||||
|
@ -67,4 +67,22 @@ public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements II
|
||||
// 5. 正常转换
|
||||
return BeanUtils.copyList(items, ItemDTO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void restoreStock(List<OrderDetailDTO> items) {
|
||||
String sqlStatement = "com.hmall.item.mapper.ItemMapper.restoreStock";
|
||||
boolean r = false;
|
||||
|
||||
try {
|
||||
r = executeBatch(items, (sqlSession, entity) ->
|
||||
sqlSession.update(sqlStatement, entity));
|
||||
} catch (Exception e) {
|
||||
throw new BizIllegalException("恢复库存异常,可能出现业务故障!", e);
|
||||
}
|
||||
|
||||
if (!r) {
|
||||
throw new BizIllegalException("恢复库存失败!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
package com.hmall.pay.controller;
|
||||
|
||||
import com.hmall.api.dto.PayOrderDTO;
|
||||
import com.hmall.common.exception.BizIllegalException;
|
||||
|
||||
import com.hmall.common.utils.BeanUtils;
|
||||
import com.hmall.pay.domain.dto.PayApplyDTO;
|
||||
import com.hmall.pay.domain.dto.PayOrderFormDTO;
|
||||
import com.hmall.pay.domain.po.PayOrder;
|
||||
import com.hmall.pay.domain.vo.PayOrderVO;
|
||||
import com.hmall.pay.enums.PayType;
|
||||
import com.hmall.pay.service.IPayOrderService;
|
||||
@ -46,4 +48,11 @@ public class PayController {
|
||||
payOrderFormDTO.setId(id);
|
||||
payOrderService.tryPayOrderByBalance(payOrderFormDTO);
|
||||
}
|
||||
|
||||
@ApiOperation("根据id查询支付单")
|
||||
@GetMapping("/biz/{id}")
|
||||
public PayOrderDTO queryPayOrderByBizOrderNo(@PathVariable("id") Long id){
|
||||
PayOrder payOrder = payOrderService.lambdaQuery().eq(PayOrder::getBizOrderNo, id).one();
|
||||
return BeanUtils.copyBean(payOrder, PayOrderDTO.class);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
package com.hmall.trade.constants;
|
||||
|
||||
public interface MQConstants {
|
||||
String DELAY_EXCHANGE_NAME = "trade.delay.direct";
|
||||
String DELAY_ORDER_QUEUE_NAME = "trade.delay.order.queue";
|
||||
String DELAY_ORDER_KEY = "delay.order.query";
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.hmall.trade.listener;
|
||||
|
||||
import com.hmall.api.client.PayClient;
|
||||
import com.hmall.api.dto.PayOrderDTO;
|
||||
import com.hmall.trade.constants.MQConstants;
|
||||
import com.hmall.trade.domain.po.Order;
|
||||
import com.hmall.trade.service.IOrderService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.amqp.rabbit.annotation.Exchange;
|
||||
import org.springframework.amqp.rabbit.annotation.Queue;
|
||||
import org.springframework.amqp.rabbit.annotation.QueueBinding;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class OrderDelayMessageListener {
|
||||
|
||||
private final IOrderService orderService;
|
||||
private final PayClient payClient;
|
||||
|
||||
@RabbitListener(bindings = @QueueBinding(
|
||||
value = @Queue(name = MQConstants.DELAY_ORDER_QUEUE_NAME),
|
||||
exchange = @Exchange(name = MQConstants.DELAY_EXCHANGE_NAME, delayed = "true"),
|
||||
key = MQConstants.DELAY_ORDER_KEY
|
||||
))
|
||||
public void listenOrderDelayMessage(Long orderId){
|
||||
// 1.查询订单
|
||||
Order order = orderService.getById(orderId);
|
||||
// 2.检测订单状态,判断是否已支付
|
||||
if(order == null || order.getStatus() != 1){
|
||||
// 订单不存在或者已经支付
|
||||
return;
|
||||
}
|
||||
// 3.未支付,需要查询支付流水状态
|
||||
PayOrderDTO payOrder = payClient.queryPayOrderByBizOrderNo(orderId);
|
||||
// 4.判断是否支付
|
||||
if(payOrder != null && payOrder.getStatus() == 3){
|
||||
// 4.1.已支付,标记订单状态为已支付
|
||||
orderService.markOrderPaySuccess(orderId);
|
||||
}else{
|
||||
orderService.cancelOrder(orderId);
|
||||
}
|
||||
}
|
||||
}
|
@ -22,7 +22,6 @@ public class PayStatusListener {
|
||||
key = "pay.success"
|
||||
))
|
||||
public void listenPaySuccess(Long orderId){
|
||||
log.info("MQtest:orderId:"+orderId);
|
||||
orderService.markOrderPaySuccess(orderId);
|
||||
}
|
||||
}
|
@ -18,4 +18,5 @@ public interface IOrderService extends IService<Order> {
|
||||
Long createOrder(OrderFormDTO orderFormDTO);
|
||||
|
||||
void markOrderPaySuccess(Long orderId);
|
||||
void cancelOrder(long orderId);
|
||||
}
|
||||
|
@ -6,9 +6,11 @@ import com.hmall.api.client.ItemClient;
|
||||
import com.hmall.api.dto.ItemDTO;
|
||||
import com.hmall.api.dto.OrderDetailDTO;
|
||||
import com.hmall.common.exception.BadRequestException;
|
||||
import com.hmall.common.utils.BeanUtils;
|
||||
import com.hmall.common.utils.UserContext;
|
||||
|
||||
|
||||
import com.hmall.trade.constants.MQConstants;
|
||||
import com.hmall.trade.domain.dto.OrderFormDTO;
|
||||
import com.hmall.trade.domain.po.Order;
|
||||
import com.hmall.trade.domain.po.OrderDetail;
|
||||
@ -17,6 +19,7 @@ import com.hmall.trade.service.IOrderDetailService;
|
||||
import com.hmall.trade.service.IOrderService;
|
||||
import io.seata.spring.annotation.GlobalTransactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@ -42,6 +45,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
private final ItemClient itemClient;
|
||||
private final IOrderDetailService detailService;
|
||||
private final CartClient cartClient;
|
||||
private final RabbitTemplate rabbitTemplate;
|
||||
|
||||
@Override
|
||||
@GlobalTransactional
|
||||
@ -85,11 +89,29 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("库存不足!");
|
||||
}
|
||||
// 5.发送延迟消息,检测订单支付状态
|
||||
rabbitTemplate.convertAndSend(
|
||||
MQConstants.DELAY_EXCHANGE_NAME,
|
||||
MQConstants.DELAY_ORDER_KEY,
|
||||
order.getId(),
|
||||
message -> {
|
||||
message.getMessageProperties().setDelay(10000);
|
||||
return message;
|
||||
}
|
||||
);
|
||||
return order.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markOrderPaySuccess(Long orderId) {
|
||||
// 1.查询订单
|
||||
Order old = getById(orderId);
|
||||
// 2.判断订单状态
|
||||
if (old == null || old.getStatus() != 1) {
|
||||
// 订单不存在或者订单状态不是1,放弃处理
|
||||
return;
|
||||
}
|
||||
// 3.尝试更新订单
|
||||
Order order = new Order();
|
||||
order.setId(orderId);
|
||||
order.setStatus(2);
|
||||
@ -113,4 +135,26 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
||||
}
|
||||
return details;
|
||||
}
|
||||
@Override
|
||||
@Transactional
|
||||
public void cancelOrder(long orderId) {
|
||||
// 1. 标记订单为已关闭,同时更新关闭时间和更新时间
|
||||
lambdaUpdate()
|
||||
.set(Order::getStatus, 5)
|
||||
.set(Order::getUpdateTime, LocalDateTime.now())
|
||||
.set(Order::getCloseTime, LocalDateTime.now())
|
||||
.eq(Order::getId, orderId)
|
||||
.ne(Order::getStatus, 5)
|
||||
.update();
|
||||
|
||||
// 恢复库存
|
||||
// 获取 OrderDetail 的 List
|
||||
List<OrderDetail> details = detailService.lambdaQuery()
|
||||
.eq(OrderDetail::getOrderId, orderId)
|
||||
.list();
|
||||
|
||||
// 构建 OrderDetailDTO 的 List
|
||||
List<OrderDetailDTO> dtos = BeanUtils.copyList(details, OrderDetailDTO.class);
|
||||
itemClient.restoreStock(dtos);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user