支付退款+异步主动查询订单情况
parent
d6f55e9bf1
commit
f6f36fddd8
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue