支付退款+异步主动查询订单情况
parent
d6f55e9bf1
commit
f6f36fddd8
|
@ -36,5 +36,10 @@
|
||||||
<artifactId>alipay-easysdk</artifactId>
|
<artifactId>alipay-easysdk</artifactId>
|
||||||
<version>2.2.0</version>
|
<version>2.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</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.domin.pojo.PayDetail;
|
||||||
import com.group.common.result.R;
|
import com.group.common.result.R;
|
||||||
import com.group.order.config.AliPayConfig;
|
import com.group.order.config.AliPayConfig;
|
||||||
|
import com.group.order.mq.OrderProduct;
|
||||||
import com.group.order.pojo.ReqPay;
|
import com.group.order.pojo.ReqPay;
|
||||||
import com.group.order.service.KillOrderService;
|
import com.group.order.service.KillOrderService;
|
||||||
import com.group.order.service.PayDetailService;
|
import com.group.order.service.PayDetailService;
|
||||||
|
@ -45,10 +46,8 @@ public class KillOrderController {
|
||||||
*/
|
*/
|
||||||
@PostMapping("/addOrder")
|
@PostMapping("/addOrder")
|
||||||
public R addOrder(@RequestBody KillOrderEntity killOrderEntity) {
|
public R addOrder(@RequestBody KillOrderEntity killOrderEntity) {
|
||||||
if (killOrderService.save(killOrderEntity)) {
|
|
||||||
return R.error();
|
return killOrderService.addOrder(killOrderEntity);
|
||||||
}
|
|
||||||
return R.ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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> {
|
public interface KillOrderService extends IService<KillOrderEntity> {
|
||||||
R payKill(ReqPay pay, HttpServletResponse response);
|
R payKill(ReqPay pay, HttpServletResponse response);
|
||||||
|
|
||||||
|
R addOrder(KillOrderEntity killOrderEntity);
|
||||||
|
|
||||||
|
R refund(Integer id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
package com.group.order.service.impl;
|
package com.group.order.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.group.common.domin.pojo.KillOrderEntity;
|
import com.group.common.domin.pojo.KillOrderEntity;
|
||||||
|
|
||||||
import com.group.common.domin.pojo.PayDetail;
|
import com.group.common.domin.pojo.PayDetail;
|
||||||
import com.group.common.result.R;
|
import com.group.common.result.R;
|
||||||
|
import com.group.order.config.AliPayUtil;
|
||||||
import com.group.order.mapper.KillOrderMapper;
|
import com.group.order.mapper.KillOrderMapper;
|
||||||
import com.group.order.mapper.PayDetailMapper;
|
import com.group.order.mapper.PayDetailMapper;
|
||||||
|
import com.group.order.mq.OrderProduct;
|
||||||
import com.group.order.payMethod.PayContext;
|
import com.group.order.payMethod.PayContext;
|
||||||
import com.group.order.payMethod.PayType;
|
import com.group.order.payMethod.PayType;
|
||||||
import com.group.order.pojo.ReqPay;
|
import com.group.order.pojo.ReqPay;
|
||||||
|
@ -73,4 +76,37 @@ public class KillOrderServiceImpl extends ServiceImpl<KillOrderMapper, KillOrder
|
||||||
type.pay(payDetail,response);
|
type.pay(payDetail,response);
|
||||||
return R.ok();
|
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