Merge remote-tracking branch 'origin/main'

This commit is contained in:
小朱 2025-05-06 09:15:16 +08:00
commit 2e6608483b
8 changed files with 203 additions and 69 deletions

View File

@ -14,8 +14,6 @@ import org.springframework.scheduling.annotation.EnableScheduling;
*/ */
@SpringBootApplication @SpringBootApplication
@MapperScan("com.cdzy.payment.mapper") @MapperScan("com.cdzy.payment.mapper")
//引入Spring Task
@EnableScheduling
public class EbikePaymentApplication { public class EbikePaymentApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(EbikePaymentApplication.class, args); SpringApplication.run(EbikePaymentApplication.class, args);

View File

@ -0,0 +1,48 @@
package com.cdzy.payment.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* 作业调度配置
*
* @author dingchao
* @date 2025/5/2
* @modified by:
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "task-scheduler-pool")
public class ScheduledTaskConfig {
/**
* 线程池大小
*/
private int poolSize;
/**
* 线程名称前缀
*/
private String threadNamePrefix;
/**
* 等待任务在关闭时完成
*/
private boolean waitForTasksToCompleteOnShutdown;
/**
* 等待终止的秒数
*/
private int awaitTerminationSeconds;
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(poolSize);
taskScheduler.setThreadNamePrefix(threadNamePrefix);
taskScheduler.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
taskScheduler.setAwaitTerminationSeconds(awaitTerminationSeconds);
taskScheduler.initialize();
return taskScheduler;
}
}

View File

@ -7,7 +7,6 @@ import com.wechat.pay.java.core.util.PemUtil;
import com.wechat.pay.java.service.payments.jsapi.JsapiService; import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.refund.RefundService; import com.wechat.pay.java.service.refund.RefundService;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -21,7 +20,6 @@ import java.security.PrivateKey;
* @date 2025/4/24 * @date 2025/4/24
* @modified by: * @modified by:
*/ */
@Slf4j
@Data @Data
@Configuration @Configuration
@ConfigurationProperties(prefix = "payment.wx-pay") @ConfigurationProperties(prefix = "payment.wx-pay")

View File

@ -0,0 +1,75 @@
package com.cdzy.payment.controller;
import com.alibaba.fastjson2.JSONObject;
import com.cdzy.payment.model.dto.HandleNotifyResult;
import com.cdzy.payment.service.WxPayService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 微信支付通知回调接口
* <br>通知接口不能鉴权
*
* @author dingchao
* @date 2025/5/6
* @modified by:
*/
@RestController
@RequestMapping("/wxPayment/notify")
public class EbikeWxPayNotifyController {
@Resource
private WxPayService wxPayService;
/**
* 支付回调通知
*
* @param request 支付回调请求
* @param response 支付回调响应
* @return 支付回调响应
*/
@PostMapping("/pay")
public String payNotify(HttpServletRequest request, HttpServletResponse response) {
HandleNotifyResult r = wxPayService.handlePayNotify(request);
if(!r.isSuccess()) {
response.setStatus(500);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", "SYSTEM_ERROR");
jsonObject.put("message", r.getMessage());
return jsonObject.toJSONString();
}
response.setStatus(200);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", "SUCCESS");
jsonObject.put("message", "OK");
return jsonObject.toJSONString();
}
/**
* 退款回调通知
*
* @param request 退款回调请求
* @param response 退款回调响应
* @return 退款回调响应
*/
@PostMapping("/refund")
public String refundNotify(HttpServletRequest request, HttpServletResponse response) {
HandleNotifyResult r = wxPayService.handleRefundNotify(request);
if(!r.isSuccess()) {
response.setStatus(500);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", "SYSTEM_ERROR");
jsonObject.put("message", r.getMessage());
return jsonObject.toJSONString();
}
response.setStatus(200);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", "SUCCESS");
jsonObject.put("message", "OK");
return jsonObject.toJSONString();
}
}

View File

@ -17,9 +17,6 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/** /**
* 用户订单微信支付 控制层 * 用户订单微信支付 控制层
* *
@ -106,55 +103,4 @@ public class EbikeWxPaymentController {
return r == null?JsonResult.failed(String.format("退款单号{%s}查询退款失败", outRefundNo)):JsonResult.success(r); return r == null?JsonResult.failed(String.format("退款单号{%s}查询退款失败", outRefundNo)):JsonResult.success(r);
} }
// ================通知回调接口===============
// TODO 通知接口不能鉴权
/**
* 支付回调通知
*
* @param request 支付回调请求
* @param response 支付回调响应
* @return 支付回调响应
*/
@PostMapping("/pay/notify")
public String payNotify(HttpServletRequest request, HttpServletResponse response) {
HandleNotifyResult r = wxPayService.handlePayNotify(request);
if(!r.isSuccess()) {
response.setStatus(500);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", "SYSTEM_ERROR");
jsonObject.put("message", r.getMessage());
return jsonObject.toJSONString();
}
response.setStatus(200);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", "SUCCESS");
jsonObject.put("message", "OK");
return jsonObject.toJSONString();
}
/**
* 退款回调通知
*
* @param request 退款回调请求
* @param response 退款回调响应
* @return 退款回调响应
*/
@PostMapping("/refund/notify")
public String refundNotify(HttpServletRequest request, HttpServletResponse response) {
HandleNotifyResult r = wxPayService.handleRefundNotify(request);
if(!r.isSuccess()) {
response.setStatus(500);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", "SYSTEM_ERROR");
jsonObject.put("message", r.getMessage());
return jsonObject.toJSONString();
}
response.setStatus(200);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", "SUCCESS");
jsonObject.put("message", "OK");
return jsonObject.toJSONString();
}
} }

View File

@ -0,0 +1,69 @@
package com.cdzy.payment.task;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
/**
* 定时作业调度器
*
* @author dingchao
* @date 2025/5/2
* @modified by:
*/
@Slf4j
@Component
public class ScheduledTaskManager {
// 每隔30秒执行1次
private final static String CRON_EXPRESSION = "0/30 * * * *?";
// @Scheduled任务线程默认串行执行需要考虑并发问题
@Resource
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
@Resource
private WsPayTask wxPayTask;
@PostConstruct
public void init() {
// 启动定时任务
// 1. 每隔30秒执行1次查询创建未超过5分钟并且未支付的订单
threadPoolTaskScheduler.schedule(new Runnable() {
@Override
public void run() {
try {
wxPayTask.checkOrderStatus();
}catch (Exception e) {
log.error("checkOrderStatus 执行异常", e);
}
}
}, new CronTrigger(CRON_EXPRESSION));
// 2. 每隔30秒执行1次查询创建超过5分钟并且未支付的订单
threadPoolTaskScheduler.schedule(new Runnable() {
@Override
public void run() {
try {
wxPayTask.closeOrder();
} catch (Exception e) {
log.error("closeOrder 执行异常", e);
}
}
}, new CronTrigger(CRON_EXPRESSION));
// 3. 每隔30秒执行1次查询创建未超过5分钟并且未成功的退款单
threadPoolTaskScheduler.schedule(new Runnable() {
@Override
public void run() {
try {
wxPayTask.checkRefundStatus();
} catch (Exception e) {
log.error("checkRefundStatus 执行异常", e);
}
}
}, new CronTrigger(CRON_EXPRESSION));
}
}

View File

@ -8,11 +8,9 @@ import com.cdzy.payment.service.EbikeRefundService;
import com.cdzy.payment.service.WxPayService; import com.cdzy.payment.service.WxPayService;
import com.wechat.pay.java.service.payments.model.Transaction; import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.Refund; import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.Status;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service;
import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@ -24,7 +22,7 @@ import java.util.List;
* @modified by: * @modified by:
*/ */
@Slf4j @Slf4j
@Component @Service
public class WsPayTask { public class WsPayTask {
@Resource @Resource
@ -36,11 +34,10 @@ public class WsPayTask {
@Resource @Resource
private EbikeRefundService ebikeRefundService; private EbikeRefundService ebikeRefundService;
// TODO @Scheduled任务线程默认串行执行需要考虑并发问题
/** /**
* 每隔30秒执行1次查询创建未超过5分钟并且未支付的订单 * 查询创建未超过5分钟并且未支付的订单
*/ */
@Scheduled(cron = "0/30 * * * * ?")
public void checkOrderStatus() throws Exception { public void checkOrderStatus() throws Exception {
log.info("checkOrderStatus 执行......"); log.info("checkOrderStatus 执行......");
// 1. 查询未支付的订单 // 1. 查询未支付的订单
@ -57,9 +54,8 @@ public class WsPayTask {
} }
/** /**
* 每隔30秒执行1次查询创建超过5分钟并且未支付的订单 * 查询创建超过5分钟并且未支付的订单
*/ */
@Scheduled(cron = "0/30 * * * * ?")
public void closeOrder() throws Exception { public void closeOrder() throws Exception {
log.info("closeOrder 执行......"); log.info("closeOrder 执行......");
// 1. 查询未支付的超时订单 // 1. 查询未支付的超时订单
@ -80,9 +76,8 @@ public class WsPayTask {
} }
/** /**
* 每隔30秒执行1次查询创建未超过5分钟并且未成功的退款单 * 查询创建未超过5分钟并且未成功的退款单
*/ */
@Scheduled(cron = "0/30 * * * * ?")
public void checkRefundStatus() throws Exception { public void checkRefundStatus() throws Exception {
log.info("checkRefundStatus 执行......"); log.info("checkRefundStatus 执行......");

View File

@ -41,3 +41,8 @@ payment:
pay-notify_url: http://192.168.2.156:10017/wxPayment/pay-notify pay-notify_url: http://192.168.2.156:10017/wxPayment/pay-notify
refund-notify_url: http://192.168.2.156:10017/wxPayment/refund-notify refund-notify_url: http://192.168.2.156:10017/wxPayment/refund-notify
expire-minutes: 5 expire-minutes: 5
task-scheduler-pool:
poolSize: 100
threadNamePrefix: task-scheduled-
waitForTasksToCompleteOnShutdown: true
awaitTerminationSeconds: 30