支付退款+异步主动查询订单情况

idcard
2024-05-07 19:00:03 +08:00
parent d6f55e9bf1
commit f6f36fddd8
9 changed files with 396 additions and 4 deletions

View File

@ -36,5 +36,10 @@
<artifactId>alipay-easysdk</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,76 @@
package com.group.order.config;
import cn.hutool.json.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.group.common.domin.pojo.PayDetail;
import com.group.common.result.R;
import com.group.order.service.PayDetailService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
/**
*
*/
@Component
@Log4j2
public class AliPayUtil {
@Autowired
private AlipayClient alipayClient;
public R refund(PayDetail payDetail) {
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", payDetail.getPayDetail());
bizContent.put("refund_amount", payDetail.getPayPrice());
bizContent.put("out_request_no", "HZ01RF002");
request.setBizContent(bizContent.toString());
try {
AlipayTradeRefundResponse response = alipayClient.execute(request);
log.info("调用接口回复: " + response);
if (response.isSuccess()) {
log.info("退款成功");
return R.ok().put("data",response.getBody());
} else {
log.info("退款失败");
return R.error();
}
} catch (AlipayApiException e) {
throw new RuntimeException(e);
}
}
public R selectOrder(PayDetail payDetail) {
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setOutTradeNo(payDetail.getPayDetail());
ArrayList<String> list = new ArrayList<>();
list.add("trade_settle_info");
list.add("fund_bill_list");
model.setQueryOptions(list);
//设置支付宝交易号
model.setTradeNo(payDetail.getPayPay());
request.setBizModel(model);
try {
AlipayTradeQueryResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
return R.ok();
} else {
return R.error();
}
} catch (AlipayApiException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,49 @@
package com.group.order.config;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitAdminConfig {
@Value("${spring.rabbitmq.host}")
private String host;
@Value("${spring.rabbitmq.username}")
private String username;
@Value("${spring.rabbitmq.password}")
private String password;
@Value("${spring.rabbitmq.virtualhost}")
private String virtualhost;
/**
* RabbitMQ
* @return
*/
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses(host);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost(virtualhost);
return connectionFactory;
}
/**
* RabbitAdmin
* @param connectionFactory
* @return
*/
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
}

View File

@ -0,0 +1,92 @@
package com.group.order.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration
public class RabbitMQConfig {
public static final String DELAY_QUEUE_NAME="delay_queue";
public static final String DELAY_EXCHANGE_NAME="delay_exchange";
public static final String DEAD_QUEUE_NAME="dead_queue";
public static final String DEAD_EXCHANGE_NAME ="dead_exchange";
public static final String DEAD_ROUTING_KEY="dead_routing_key";
public static final String DELAY_ROUTING_KEY="delay_routing_key";
//创建消息转换器
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
@Bean
public Queue delayQueue(){
return QueueBuilder
.durable(DELAY_QUEUE_NAME)
.deadLetterExchange(DEAD_EXCHANGE_NAME)
.deadLetterRoutingKey(DEAD_ROUTING_KEY)
.ttl(30*60*1000)
.build();
}
@Bean
public Queue deadLetterQueue(){
return QueueBuilder
.durable(DEAD_QUEUE_NAME)
.build();
}
@Bean
public Exchange delayExchange(){
return new DirectExchange(DELAY_EXCHANGE_NAME);
}
@Bean
public Exchange deadLetterExchange(){
return new DirectExchange(DEAD_EXCHANGE_NAME);
}
@Bean
public Binding delayBinding(){
return BindingBuilder
.bind(delayQueue())
.to((DirectExchange)delayExchange())
.with(DELAY_ROUTING_KEY);
}
@Bean
public Binding deadLetterBinding(){
return BindingBuilder
.bind(deadLetterQueue())
.to((DirectExchange)deadLetterExchange())
.with(DEAD_ROUTING_KEY);
}
//完成rabbitTemplate模版配置
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(messageConverter());
return rabbitTemplate;
}
//配置监听器容器
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory){
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(messageConverter());
return factory;
}
}

View File

@ -6,6 +6,7 @@ import com.group.common.domin.pojo.KillOrderEntity;
import com.group.common.domin.pojo.PayDetail;
import com.group.common.result.R;
import com.group.order.config.AliPayConfig;
import com.group.order.mq.OrderProduct;
import com.group.order.pojo.ReqPay;
import com.group.order.service.KillOrderService;
import com.group.order.service.PayDetailService;
@ -45,10 +46,8 @@ public class KillOrderController {
*/
@PostMapping("/addOrder")
public R addOrder(@RequestBody KillOrderEntity killOrderEntity) {
if (killOrderService.save(killOrderEntity)) {
return R.error();
}
return R.ok();
return killOrderService.addOrder(killOrderEntity);
}
/**
@ -115,6 +114,24 @@ public class KillOrderController {
}
}
@Autowired
private OrderProduct orderProduct;
/**
* 使
*/
@GetMapping("/test")
public void test(@RequestParam String message){
orderProduct.sendMessage(message);
}
/**
* 退
*/
@GetMapping("/refund/{id}")
public R refund(@PathVariable("id")Integer id){
return killOrderService.refund(id);
}

View File

@ -0,0 +1,83 @@
package com.group.order.mq;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.group.common.domin.pojo.KillOrderEntity;
import com.group.common.domin.pojo.PayDetail;
import com.group.common.result.R;
import com.group.order.config.AliPayUtil;
import com.group.order.config.RabbitMQConfig;
import com.group.order.service.KillOrderService;
import com.group.order.service.PayDetailService;
import com.rabbitmq.client.Channel;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
/**
* id
*/
@Component
@Log4j2
public class OrderConsumer {
@Autowired
private KillOrderService killOrderService;
@Autowired
private PayDetailService payDetailService;
@Autowired
private AliPayUtil aliPayUtil;
@RabbitListener(queues = RabbitMQConfig.DEAD_QUEUE_NAME)
public void orderConsumer(Message message, Channel channel) {
Integer orderId = Integer.valueOf(new String(message.getBody()));
//延迟队列是为了保证订单在一段时间的有效性
//通过订单id获取订单
KillOrderEntity entity = killOrderService.getById(orderId);
//通过订单的状态判断是否已经成功支付
//如果已经成功支付
if (entity.getKillState().equals(2)){
return;
}
//获取支付明细判断是否正在支付中
List<PayDetail> list = payDetailService
.list(
new LambdaQueryWrapper<PayDetail>()
.eq(PayDetail::getPayOrder, orderId)
);
//如果没有支付明细
if (list.isEmpty()){
//修改订单支付状态为失败
entity.setKillState(3);
killOrderService.updateById(entity);
}
//最新的支付流水
PayDetail payDetail = list.get(list.size() - 1);
//如果支付明细支付成功,但是订单状态未修改
if (payDetail.getPayState().equals(2)){
entity.setKillState(2);
killOrderService.updateById(entity);
}
//如果支付状态为正在支付
if (payDetail.getPayState().equals(1)){
//向支付宝主动发起请求查询订单状态
R r = aliPayUtil.selectOrder(payDetail);
if (r.get("code").equals(0)){
log.info(r.get("data"));
payDetail.setPayState(2);
payDetailService.updateById(payDetail);
entity.setKillState(2);
killOrderService.updateById(entity);
}
}
}
}

View File

@ -0,0 +1,30 @@
package com.group.order.mq;
import com.group.order.config.RabbitAdminConfig;
import com.group.order.config.RabbitMQConfig;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* id
*/
@Component
@Log4j2
public class OrderProduct {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendMessage(String message){
log.info("当前时间:{} 发送一条信息给两个TTL队列{}",new Date().toString(),message);
rabbitTemplate.convertAndSend(
RabbitMQConfig.DELAY_EXCHANGE_NAME,
RabbitMQConfig.DELAY_ROUTING_KEY
,message
);
}
}

View File

@ -12,4 +12,8 @@ import javax.servlet.http.HttpServletResponse;
*/
public interface KillOrderService extends IService<KillOrderEntity> {
R payKill(ReqPay pay, HttpServletResponse response);
R addOrder(KillOrderEntity killOrderEntity);
R refund(Integer id);
}

View File

@ -1,13 +1,16 @@
package com.group.order.service.impl;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.group.common.domin.pojo.KillOrderEntity;
import com.group.common.domin.pojo.PayDetail;
import com.group.common.result.R;
import com.group.order.config.AliPayUtil;
import com.group.order.mapper.KillOrderMapper;
import com.group.order.mapper.PayDetailMapper;
import com.group.order.mq.OrderProduct;
import com.group.order.payMethod.PayContext;
import com.group.order.payMethod.PayType;
import com.group.order.pojo.ReqPay;
@ -73,4 +76,37 @@ public class KillOrderServiceImpl extends ServiceImpl<KillOrderMapper, KillOrder
type.pay(payDetail,response);
return R.ok();
}
@Autowired
private OrderProduct orderProduct;
@Override
public R addOrder(KillOrderEntity killOrderEntity) {
if (save(killOrderEntity)){
//添加订单之后,添加到延迟队列中,保证订单的时效性,超时自动失效
orderProduct.sendMessage(killOrderEntity.getId()+"");
return R.ok();
}
return R.error();
}
@Autowired
private AliPayUtil aliPayUtil;
@Override
public R refund(Integer id) {
KillOrderEntity entity = getById(id);
List<PayDetail> list = payDetailService.list(new LambdaQueryWrapper<PayDetail>().eq(PayDetail::getPayOrder, id));
PayDetail payDetail = list.get(list.size() - 1);
R refund = aliPayUtil.refund(payDetail);
if (refund.get("code").equals(0)){
//修改订单状态
entity.setKillState(4);
updateById(entity);
//修改支付流水详情的状态
payDetail.setPayState(4);
payDetailService.updateById(payDetail);
}
return R.error();
}
}