Browse Source

feat(async): 添加异步线程池配置及任务处理功能

- 新增异步线程池配置类 AsyncConfig,支持自定义线程池参数- 实现两种线程池:核心业务线程池和 IO 密集型任务线程池
- 添加线程池属性配置类 ThreadPoolProperties,支持 YAML 动态配置
- 创建自定义线程工厂 CustomThreadFactory,设置线程优先级与异常处理
- 提供 DirectAsyncService 和 DirectCompletableFutureService 示例服务
- 在 application-dev.yml 中增加 async.thread-pool 相关配置项
- 优化订单服务中的代码格式与空格问题
-为微信支付回调添加可重入锁防止并发处理重复通知
- 统一代码风格,修复多个 if 判断条件的空格问题
wzq 2 days ago
parent
commit
e9533f33d0

+ 105 - 0
national-motion-base-core/src/main/java/org/jeecg/async/AsyncConfig.java

@@ -0,0 +1,105 @@
+package org.jeecg.async;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.AsyncConfigurer;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import javax.annotation.Resource;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 异步任务配置类
+ * 功能:配置线程池参数、异常处理、优雅关闭等
+ */
+@Slf4j
+@Configuration
+@EnableAsync
+@EnableConfigurationProperties(ThreadPoolProperties.class)
+public class AsyncConfig implements AsyncConfigurer {
+
+    @Resource
+    private ThreadPoolProperties threadPoolProperties;
+
+    /**
+     * 核心业务线程池 - 用于处理重要异步任务
+     */
+    @Bean(name = "businessTaskExecutor")
+    public ThreadPoolTaskExecutor businessTaskExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        
+        // 核心线程池配置
+        executor.setCorePoolSize(threadPoolProperties.getCorePoolSize());
+        executor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize());
+        executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
+        executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
+        
+        // 线程配置
+        executor.setThreadNamePrefix(threadPoolProperties.getThreadNamePrefix());
+        executor.setAllowCoreThreadTimeOut(threadPoolProperties.isAllowCoreThreadTimeOut());
+        
+        // 拒绝策略配置
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        
+        // 优雅关闭配置
+        executor.setWaitForTasksToCompleteOnShutdown(true);
+        executor.setAwaitTerminationSeconds(threadPoolProperties.getAwaitTerminationSeconds());
+        
+        // 线程工厂自定义(设置线程优先级、守护线程等)
+        executor.setThreadFactory(new CustomThreadFactory());
+        
+        executor.initialize();
+        return executor;
+    }
+
+    /**
+     * IO密集型任务线程池 - 适用于网络请求、文件操作等
+     */
+    @Bean(name = "ioIntensiveTaskExecutor")
+    public ThreadPoolTaskExecutor ioIntensiveTaskExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        
+        // IO密集型任务可以设置更大的线程数
+        int cpuCores = Runtime.getRuntime().availableProcessors();
+        executor.setCorePoolSize(cpuCores * 2);
+        executor.setMaxPoolSize(cpuCores * 4);
+        executor.setQueueCapacity(500);
+        executor.setKeepAliveSeconds(120);
+        executor.setThreadNamePrefix("io-task-");
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        executor.setWaitForTasksToCompleteOnShutdown(true);
+        executor.setAwaitTerminationSeconds(60);
+        executor.initialize();
+        
+        return executor;
+    }
+
+    /**
+     * 默认异步执行器(覆盖Spring默认配置)
+     */
+    @Override
+    public Executor getAsyncExecutor() {
+        return businessTaskExecutor();
+    }
+
+    /**
+     * 异步任务异常处理
+     * 用于处理无返回值的@Async方法的异常
+     *  第一层:业务异常处理
+     */
+    @Override
+    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
+        return (throwable, method, params) -> {
+            // 记录异步任务执行异常
+            log.info("异步任务执行异常 - 方法: {}, 异常: {}", method.getName(), throwable.getMessage());
+            // 这里可以接入日志框架、告警系统等
+            throwable.printStackTrace();
+        };
+    }
+}

+ 46 - 0
national-motion-base-core/src/main/java/org/jeecg/async/CustomThreadFactory.java

@@ -0,0 +1,46 @@
+package org.jeecg.async;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 自定义线程工厂
+ * 用于设置线程优先级、守护线程状态等
+ */
+public class CustomThreadFactory implements ThreadFactory {
+    private final AtomicInteger threadNumber = new AtomicInteger(1);
+    private final String namePrefix;
+    private final ThreadGroup group;
+
+    public CustomThreadFactory() {
+        SecurityManager s = System.getSecurityManager();
+        group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
+        namePrefix = "custom-async-thread-";
+    }
+
+    @Override
+    public Thread newThread(Runnable r) {
+        Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
+        
+        // 设置线程为非守护线程
+        if (t.isDaemon()) {
+            t.setDaemon(false);
+        }
+        
+        // 设置线程优先级
+        if (t.getPriority() != Thread.NORM_PRIORITY) {
+            t.setPriority(Thread.NORM_PRIORITY);
+        }
+        
+        // 设置线程异常处理器
+        t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+            //当线程中发生未捕获的异常时,就会调用这个处理器。第二层:系统级异常处理
+            @Override
+            public void uncaughtException(Thread t, Throwable e) {
+                System.err.println("线程执行异常: " + t.getName() + ", 异常: " + e.getMessage());
+            }
+        });
+        
+        return t;
+    }
+}

+ 42 - 0
national-motion-base-core/src/main/java/org/jeecg/async/DirectAsyncService.java

@@ -0,0 +1,42 @@
+package org.jeecg.async;
+
+import org.apache.poi.ss.formula.functions.T;
+import org.jeecg.common.api.vo.Result;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * 使用@async 进行异步任务处理
+ */
+@Service
+public class DirectAsyncService {
+    
+    /**
+     * 使用默认线程池执行异步任务
+     */
+    @Async
+    public void processOrderAsync(String orderId) {
+        // 异步处理订单逻辑
+        System.out.println("订单处理线程: " + Thread.currentThread().getName());
+    }
+    
+    /**
+     * 使用指定的IO密集型线程池
+     */
+    @Async("ioIntensiveTaskExecutor")
+    public CompletableFuture<String> downloadFileAsync(String fileUrl) {
+        // 异步下载文件
+        return CompletableFuture.completedFuture("下载完成");
+    }
+    
+    /**
+     * 有返回值的异步任务
+     */
+    @Async("businessTaskExecutor")
+    public CompletableFuture<Result<T>> heavyCalculationAsync(String data) {
+        // 复杂的计算任务
+        return CompletableFuture.completedFuture(Result.OK("计算完成"));
+    }
+}

+ 45 - 0
national-motion-base-core/src/main/java/org/jeecg/async/DirectCompletableFutureService.java

@@ -0,0 +1,45 @@
+package org.jeecg.async;
+
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * 使用 CompletableFuture 进行异步任务处理
+ */
+@Service
+@AllArgsConstructor
+public class DirectCompletableFutureService {
+
+    @Autowired
+    @Qualifier("businessTaskExecutor")
+    private ThreadPoolTaskExecutor businessTaskExecutor;
+
+
+    /**
+     * 执行有返回值的异步任务
+     */
+    public CompletableFuture<String> executeTaskWithResult(String taskData) {
+        // 使用 supplyAsync 并指定自定义线程池
+        return CompletableFuture.supplyAsync(() -> {
+            // 这里是你的异步任务逻辑
+            System.out.println("执行线程: " + Thread.currentThread().getName());
+            return "处理结果: " + taskData;
+        }, businessTaskExecutor); // 关键:传入线程池实例
+    }
+
+    /**
+     * 执行无返回值的异步任务
+     */
+    public CompletableFuture<Void> executeTaskWithoutResult() {
+        // 使用 runAsync 并指定自定义线程池
+        return CompletableFuture.runAsync(() -> {
+            // 异步任务逻辑
+            System.out.println("执行无返回值任务");
+        }, businessTaskExecutor);
+    }
+}

+ 60 - 0
national-motion-base-core/src/main/java/org/jeecg/async/ThreadPoolProperties.java

@@ -0,0 +1,60 @@
+package org.jeecg.async;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 线程池配置属性类
+ * 支持在application.yml中动态配置
+ */
+@Component
+@ConfigurationProperties(prefix = "async.thread-pool")
+public class ThreadPoolProperties {
+    
+    // 核心线程数
+    private int corePoolSize = 10;
+    
+    // 最大线程数
+    private int maxPoolSize = 50;
+    
+    // 队列容量
+    private int queueCapacity = 1000;
+    
+    // 线程空闲存活时间(秒)
+    private int keepAliveSeconds = 60;
+    
+    // 线程名称前缀
+    private String threadNamePrefix = "async-business-";
+    
+    // 是否允许核心线程超时
+    private boolean allowCoreThreadTimeOut = false;
+    
+    // 优雅关闭等待时间(秒)
+    private int awaitTerminationSeconds = 30;
+
+    // getter和setter方法
+    public int getCorePoolSize() { return corePoolSize; }
+    public void setCorePoolSize(int corePoolSize) { this.corePoolSize = corePoolSize; }
+    
+    public int getMaxPoolSize() { return maxPoolSize; }
+    public void setMaxPoolSize(int maxPoolSize) { this.maxPoolSize = maxPoolSize; }
+    
+    public int getQueueCapacity() { return queueCapacity; }
+    public void setQueueCapacity(int queueCapacity) { this.queueCapacity = queueCapacity; }
+    
+    public int getKeepAliveSeconds() { return keepAliveSeconds; }
+    public void setKeepAliveSeconds(int keepAliveSeconds) { this.keepAliveSeconds = keepAliveSeconds; }
+    
+    public String getThreadNamePrefix() { return threadNamePrefix; }
+    public void setThreadNamePrefix(String threadNamePrefix) { this.threadNamePrefix = threadNamePrefix; }
+    
+    public boolean isAllowCoreThreadTimeOut() { return allowCoreThreadTimeOut; }
+    public void setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) { 
+        this.allowCoreThreadTimeOut = allowCoreThreadTimeOut; 
+    }
+    
+    public int getAwaitTerminationSeconds() { return awaitTerminationSeconds; }
+    public void setAwaitTerminationSeconds(int awaitTerminationSeconds) { 
+        this.awaitTerminationSeconds = awaitTerminationSeconds; 
+    }
+}

+ 48 - 38
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/WeChatPayService.java

@@ -39,6 +39,7 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * @author wangzhiqiang
@@ -73,6 +74,9 @@ public class WeChatPayService {
     @Resource
     private WeChatProfitSharingService weChatProfitSharingService;
 
+    // 声明一个可重入锁
+    private final ReentrantLock lock = new ReentrantLock();
+
     /**
      * 小程序支付拉起
      *
@@ -206,49 +210,55 @@ public class WeChatPayService {
             return result;
         }
         log.info("最终拿到的微信支付通知数据:" + res);
-
-        // 处理支付成功后的业务 例如 将订单状态修改为已支付 具体参数键值可参考文档 注意!!! 微信可能会多次发送重复的通知 因此要判断业务是否已经处理过了 避免重复处理
-        try {
-            String orderCode = res.getString("out_trade_no");
-            //查询订单,判断是否已修改为已支付状态
-            AppOrder appOrder = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, orderCode).last("limit 1"));
-            if (ObjectUtil.isNotEmpty(appOrder) && appOrder.getCallbackStatus() == 1) {
+        String orderCode = res.getString("out_trade_no");
+        if (lock.tryLock()) {
+            // 处理支付成功后的业务 例如 将订单状态修改为已支付 具体参数键值可参考文档 注意!!! 微信可能会多次发送重复的通知 因此要判断业务是否已经处理过了 避免重复处理
+            try {
+                //查询订单,判断是否已修改为已支付状态
+                AppOrder appOrder = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, orderCode).last("limit 1"));
+                if (ObjectUtil.isNotEmpty(appOrder) && appOrder.getCallbackStatus() == 1) {
+                    result.put("code", "SUCCESS");
+                    result.put("message", "OK");
+                    result.put("orderCode", orderCode);
+                    return result;
+                }
+                if (ObjectUtil.isNotEmpty(appOrder)) {
+                    if (Objects.equals(appOrder.getOrderStatus(), CommonConstant.ORDER_STATUS_0)) {
+                        appOrder.setOrderStatus(CommonConstant.ORDER_STATUS_1);
+                        appOrder.setPayStatus(CommonConstant.ORDER_STATUS_1);
+                        appOrder.setPayTime(new Date());
+                        appOrder.setPayType(CommonConstant.STATUS_0_INT);
+                        appOrder.setPayId(res.getString("transaction_id"));
+                        appOrder.setPayTime(dealDateFormat(res.getString("success_time")));
+
+                        List<AppOrderProInfo> proInfoList = appOrderProInfoMapper.selectList(Wrappers.<AppOrderProInfo>lambdaQuery().eq(AppOrderProInfo::getOrderId, appOrder.getId()));
+                        if (ObjectUtil.isNotEmpty(proInfoList)) {
+                            for (AppOrderProInfo appOrderProInfo : proInfoList) {
+                                appOrderProInfo.setOrderStatus(CommonConstant.ORDER_STATUS_1);
+                                appOrderProInfoMapper.updateById(appOrderProInfo);
+                            }
+                        }
+                        appOrder.setCallbackStatus(CommonConstant.STATUS_1_INT);
+                        appOrderMapper.updateById(appOrder);
+                        //创建预分账详情
+                        if (appOrder.getOrProfitSharing() == 1) {
+                            addProfitSharingInfos(appOrder);
+                        }
+                    }
+                }
                 result.put("code", "SUCCESS");
                 result.put("message", "OK");
                 result.put("orderCode", orderCode);
                 return result;
+            } catch (Exception e) {
+                log.error("微信支付回调异常:" + e.getMessage());
+                result.put("code", "FAIL");
+                result.put("message", "失败");
+                return result;
+            }finally {
+                lock.unlock();
             }
-            if (ObjectUtil.isNotEmpty(appOrder)) {
-                if (Objects.equals(appOrder.getOrderStatus(), CommonConstant.ORDER_STATUS_0)) {
-                    appOrder.setOrderStatus(CommonConstant.ORDER_STATUS_1);
-                    appOrder.setPayStatus(CommonConstant.ORDER_STATUS_1);
-                    appOrder.setPayTime(new Date());
-                    appOrder.setPayType(CommonConstant.STATUS_0_INT);
-                    appOrder.setPayId(res.getString("transaction_id"));
-                    appOrder.setPayTime(dealDateFormat(res.getString("success_time")));
-
-                    List<AppOrderProInfo> proInfoList = appOrderProInfoMapper.selectList(Wrappers.<AppOrderProInfo>lambdaQuery().eq(AppOrderProInfo::getOrderId, appOrder.getId()));
-                    if (ObjectUtil.isNotEmpty(proInfoList)) {
-                        for (AppOrderProInfo appOrderProInfo : proInfoList) {
-                            appOrderProInfo.setOrderStatus(CommonConstant.ORDER_STATUS_1);
-                            appOrderProInfoMapper.updateById(appOrderProInfo);
-                        }
-                    }
-                    appOrder.setCallbackStatus(CommonConstant.STATUS_1_INT);
-                    appOrderMapper.updateById(appOrder);
-                    //创建预分账详情
-                    if (appOrder.getOrProfitSharing() == 1) {
-                        addProfitSharingInfos(appOrder);
-                    }
-                }
-
-            }
-            result.put("code", "SUCCESS");
-            result.put("message", "OK");
-            result.put("orderCode", orderCode);
-            return result;
-        } catch (Exception e) {
-            log.error("微信支付回调异常:" + e.getMessage());
+        }else {
             result.put("code", "FAIL");
             result.put("message", "失败");
             return result;

+ 56 - 49
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/OrderServiceImpl.java

@@ -68,6 +68,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.stream.Collectors;
 
 import static org.jeecg.modules.hikiot.HikiotTool.addFace;
@@ -116,7 +117,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
     private AppCoursesVerificationRecordMapper appCoursesVerificationRecordMapper;
     @Resource
     private AppContractSignMapper appContractSignMapper;
-//    @Resource
+    //    @Resource
 //    private RedissonDelayQueue redissonDelayQueue;
     @Resource
     private AppDeviceMapper appDeviceMapper;
@@ -124,7 +125,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
     private WeChatPayService weChatPayService;
     @Resource
     private RedisTemplate<String, Object> redisTemplate;
-//    @Resource
+    //    @Resource
 //    private WechatPayV3Utils wechatPayV3Utils;
     @Resource
     private EvaluateMapper evaluateMapper;
@@ -597,12 +598,12 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                         String startTime = DateUtil.format(priceRule.getStartTime(), "HH:mm:ss");
                         String endTime = DateUtil.format(priceRule.getEndTime(), "HH:mm:ss");
                         String expireTime;
-                        if(priceRule.getEndTime() != null){
+                        if (priceRule.getEndTime() != null) {
                             expireTime = date + " " + endTime;
-                        }else {
+                        } else {
                             expireTime = date;
                         }
-                        if(startTime ==  null){
+                        if (startTime == null) {
                             startTime = DateUtil.format(new Date(), "yyyy-MM-dd");
                         }
                         AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
@@ -711,10 +712,10 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                         String startTime = DateUtil.format(appSite.getStartTime(), "HH:mm");
                         String endTime = DateUtil.format(appSite.getEndTime(), "HH:mm");
                         String expireTime = date + " " + endTime;
-                        if(null == appSite.getStartTime()){
+                        if (null == appSite.getStartTime()) {
                             startTime = "00:00";
                         }
-                        if(null == appSite.getEndTime()){
+                        if (null == appSite.getEndTime()) {
                             endTime = "23:59";
                         }
                         AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
@@ -779,9 +780,9 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                         AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
                         appOrderProInfo.setProductId(createOrderForm.getProductIds());
                         appOrderProInfo.setProductName(appGame.getName());
-                        if(appGame.getSiteType() == 1){
+                        if (appGame.getSiteType() == 1) {
                             appOrderProInfo.setAddress(appGameMapper.selectById(appGame.getId()).getAddress());
-                        }else {
+                        } else {
                             appOrderProInfo.setAddress(appSiteMapper.selectById(appGame.getSiteId()).getAddress());
                         }
                         appOrderProInfo.setType(CommonConstant.ORDER_PRO_INFO_TYPE_3);
@@ -814,7 +815,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                             .setUpdateBy(user.getId())
                             .setStatus(CommonConstant.STATUS_NORMAL)
                             .setDelFlag(CommonConstant.DEL_FLAG_0);
-                    if (ObjectUtil.isNotEmpty(appGame.getSiteId())){
+                    if (ObjectUtil.isNotEmpty(appGame.getSiteId())) {
                         appOrder.setAddressSiteId(appGame.getSiteId());
                     }
                     if (StrUtil.isNotBlank(createOrderForm.getGameCertificationForm())) {
@@ -843,9 +844,9 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                         AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
                         appOrderProInfo.setProductId(createOrderForm.getProductIds());
                         appOrderProInfo.setProductName(appGame.getName());
-                        if(appGame.getSiteType() == 1){
+                        if (appGame.getSiteType() == 1) {
                             appOrderProInfo.setAddress(appGameMapper.selectById(appGame.getId()).getAddress());
-                        }else {
+                        } else {
                             appOrderProInfo.setAddress(appSiteMapper.selectById(appGame.getSiteId()).getAddress());
                         }
                         appOrderProInfo.setTicketNo(ticketNo);
@@ -889,7 +890,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
             case 2:
                 //课程
                 AppCourses appCourse = appCoursesMapper.selectById(appOrder.getProductIds());
-                if (ObjectUtil.isEmpty(appCourse)){
+                if (ObjectUtil.isEmpty(appCourse)) {
                     log.error("当前课程不存在!");
                     throw new JeecgBootException("当前课程已下架!");
                 }
@@ -927,7 +928,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                     List<AppOrderProInfo> infoList = appOrderProInfoMapper.selectList(Wrappers.<AppOrderProInfo>lambdaQuery()
                             .eq(AppOrderProInfo::getProductId, appCourse.getId())
                             .eq(AppOrderProInfo::getFamilyUserId, familyUserId)
-                            .eq(AppOrderProInfo::getOrFreePro,CommonConstant.STATUS_0_INT)
+                            .eq(AppOrderProInfo::getOrFreePro, CommonConstant.STATUS_0_INT)
                             .notIn(AppOrderProInfo::getOrderStatus, CommonConstant.ORDER_STATUS_4, CommonConstant.ORDER_STATUS_5, CommonConstant.ORDER_STATUS_6)
                     );
 
@@ -1165,23 +1166,25 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                         //生成10位随机券号
                         .setTicketNo(appOrderProInfo.getTicketNo())
                         .setIsinStatus(CommonConstant.ISIN_STATUS_0);
-                if (appOrder.getType() == 0){
+                if (appOrder.getType() == 0) {
                     String s = createOrderForm.getProductIds().split(",")[0];
                     String priceRuleId = s.split("\\|")[0];
                     AppSitePriceRules priceRule = appSitePriceRulesMapper.selectById(priceRuleId);
                     AppSitePlace appSitePlace = appSitePlaceMapper.selectById(priceRule.getSitePlaceId());
                     AppSite appSite = appSiteMapper.selectById(appSitePlace.getSiteId());
                     appIsin.setUseAddress(appSite.getName());
-                }if (appOrder.getType() == 1){
+                }
+                if (appOrder.getType() == 1) {
                     AppGamePriceRules appGamePriceRules = appGamePriceRulesMapper.selectById(createOrderForm.getProductIds());
                     AppGame appGame = appGameMapper.findByPriceRules(appGamePriceRules.getId());
                     appIsin.setUseAddress(sysDepartMapper.selectOne(Wrappers.<SysDepart>lambdaQuery().eq(SysDepart::getOrgCode, appGame.getOrgCode())).getDepartName());
-                }if (appOrder.getType() == 2){
+                }
+                if (appOrder.getType() == 2) {
                     AppSite appSite = appSiteMapper.selectById(appCoursesMapper.selectById(appOrderProInfo.getProductId()).getAddressSiteId());
                     appIsin.setUseAddress(appSite.getName());
 
                     //判断当前课程是否是在学校上课
-                    if (appSite.getType() == 0){
+                    if (appSite.getType() == 0) {
                         //查询当前课程的课时
                         AppCourses appCourses = appCoursesMapper.selectById(appOrderProInfo.getProductId());
                         List<AppCoursesPriceRules> appCoursesPriceRules = appCoursesPriceRulesMapper.selectList(Wrappers.<AppCoursesPriceRules>lambdaQuery().eq(AppCoursesPriceRules::getCoursesId,
@@ -1215,7 +1218,8 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                             familyMembers.getRealNameImg());
                     JsonObject addUserJson = JsonParser.parseString(addUser).getAsJsonObject();
                     JsonObject addFaceJson = JsonParser.parseString(addFace).getAsJsonObject();
-                    if (addUserJson.get("code").getAsInt() != 0 && addFaceJson.get("code").getAsInt() != 0) throw new JeecgBootException("设备录入用户信息失败!请联系管理员");
+                    if (addUserJson.get("code").getAsInt() != 0 && addFaceJson.get("code").getAsInt() != 0)
+                        throw new JeecgBootException("设备录入用户信息失败!请联系管理员");
                 }
             }
         }
@@ -1235,7 +1239,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
         payForm.setOrderId(appOrder.getId()).setOrderCode(orderCode);
 
         //判断是否试听课(试听课不走订单)
-        if ((ObjectUtil.isNotEmpty(appOrder.getOrderOrFree()) && appOrder.getOrderOrFree() == 1) || appOrder.getPrice().compareTo(BigDecimal.ZERO)== 0) {
+        if ((ObjectUtil.isNotEmpty(appOrder.getOrderOrFree()) && appOrder.getOrderOrFree() == 1) || appOrder.getPrice().compareTo(BigDecimal.ZERO) == 0) {
             payForm.setOrPayOrder(0);
         } else {
             //分账能否成功,判断是否可以下单
@@ -1250,12 +1254,12 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
             String orgCode = appOrder.getOrgCode();
             SysDepart depart = sysDepartMapper.selectOne(Wrappers.lambdaQuery(SysDepart.class).eq(SysDepart::getOrgCode, orgCode).last("limit 1"));
             String deptId = depart.getId();
-            if(depart.getSystemType() == 2){
+            if (depart.getSystemType() == 2) {
                 deptId = depart.getParentId();
             }
             if (depart.getSystemType() != 0) {
                 SeparateAccounts separateAccounts = separateAccountsMapper.selectOne(Wrappers.lambdaQuery(SeparateAccounts.class).eq(SeparateAccounts::getDeptId, deptId));
-                if (ObjectUtil.isEmpty(separateAccounts)){
+                if (ObjectUtil.isEmpty(separateAccounts)) {
                     throw new JeecgBootException("商户信息未配置!请联系管理员");
                 }
                 //获取分账比例
@@ -1272,14 +1276,14 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                 //商户(分账给平台)
                 if (depart.getSystemType() == 1) {
                     BigDecimal[] allocate = RatiosUtil.allocate(price, new BigDecimal[]{SH, PT});
-                    if((appOrder.getPrice().subtract(FEE)).multiply(BigDecimal.valueOf(0.3)).compareTo(allocate[1].add(insurePrice)) < 0){
+                    if ((appOrder.getPrice().subtract(FEE)).multiply(BigDecimal.valueOf(0.3)).compareTo(allocate[1].add(insurePrice)) < 0) {
                         throw new JeecgBootException("订单金额不支持分账,无法下单!");
                     }
                 }
                 //门店(分账给平台及商户)
                 if (depart.getSystemType() == 2) {
                     BigDecimal[] allocate = RatiosUtil.allocate(price, MD, SH, PT);
-                    if((appOrder.getPrice().subtract(FEE)).multiply(BigDecimal.valueOf(0.3)).compareTo(allocate[1].add(allocate[2]).add(insurePrice)) < 0){
+                    if ((appOrder.getPrice().subtract(FEE)).multiply(BigDecimal.valueOf(0.3)).compareTo(allocate[1].add(allocate[2]).add(insurePrice)) < 0) {
                         throw new JeecgBootException("订单金额不支持分账,无法下单!");
                     }
                 }
@@ -1298,7 +1302,9 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
         }
         return payForm;
     }
+
     private static final BigDecimal MIN_THRESHOLD = new BigDecimal("0.01"); // 最小阈值
+
     /**
      * 计算千分之6并处理临界值
      *
@@ -1324,12 +1330,12 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                 : product.setScale(2, RoundingMode.DOWN);
     }
 
-    public Map<String, String> payment(String appOrderId){
+    public Map<String, String> payment(String appOrderId) {
         AppOrder appOrder = appOrderMapper.selectById(appOrderId);
         //查询商户信息
         String orgCode = appOrder.getOrgCode();
         SysDepart depart = sysDepartMapper.selectOne(Wrappers.lambdaQuery(SysDepart.class).eq(SysDepart::getOrgCode, orgCode).last("limit 1"));
-        if (Objects.equals(appOrder.getOrderStatus(), CommonConstant.ORDER_STATUS_4)){
+        if (Objects.equals(appOrder.getOrderStatus(), CommonConstant.ORDER_STATUS_4)) {
             throw new JeecgBootException("当前订单已过期,请重新下单!");
         }
 
@@ -1356,7 +1362,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
         // 在查询API和支付通知中原样返回 可作为自定义参数使用
         params.put("notify_url", WechatUrlConstants.PAY_V3_NOTIFY); //支付结果异步通知接口
         //分账必传参数
-        if (appOrder.getOrderType() != 0){
+        if (appOrder.getOrderType() != 0) {
             JSONObject settleInfo = new JSONObject();
             settleInfo.put("profit_sharing", Boolean.TRUE);
             params.put("settle_info", settleInfo);
@@ -1652,7 +1658,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
             appOrderInfoDTO.setLatitude(appGame.getLatitude());
             appOrderInfoDTO.setLongitude(appGame.getLongitude());
             if (appGame.getSiteType().equals(CommonConstant.STATUS_1_INT)) {
-                if (ObjectUtils.isNotEmpty(site)){
+                if (ObjectUtils.isNotEmpty(site)) {
                     appOrderInfoDTO.setPhone(site.getPhone());
                     appOrderInfoDTO.setAddressSiteId(site.getId());
                 }
@@ -1694,7 +1700,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
         if (CollUtil.isNotEmpty(insureOrderInfoList)) {
             appOrderInfoDTO.setInsureOrderInfoList(insureOrderInfoList);
         }
-        if(null == appOrderInfoDTO.getGameAddress()) {
+        if (null == appOrderInfoDTO.getGameAddress()) {
             appOrderInfoDTO.setGameAddress(appOrderInfoDTO.getProInfoList().get(0).getAddress());
         }
         return appOrderInfoDTO;
@@ -1815,7 +1821,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
     }
 
     @Override
-    public String orderQuery(String orderCode){
+    public String orderQuery(String orderCode) {
 
         //查询订单
         AppOrder appOrder = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, orderCode).last("limit 1"));
@@ -1836,10 +1842,10 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
         }
 
         //null代表查询失败 SUCCESS-成功 USERPAYING和ACCEPT为中间态 其他为支付失败
-        JSONObject res = weChatPayService.orderQueryByOutTradeNo(orderCode,depart.getMchId());
+        JSONObject res = weChatPayService.orderQueryByOutTradeNo(orderCode, depart.getMchId());
         String s = res == null ? null : res.getString("trade_state");
 //        String s = "SUCCESS";
-        if ("SUCCESS".equals(s) || appOrder.getOriginalPrice().compareTo(BigDecimal.ZERO)==0) {
+        if ("SUCCESS".equals(s) || appOrder.getOriginalPrice().compareTo(BigDecimal.ZERO) == 0) {
 
             if (ObjectUtil.isNotEmpty(appOrder) && Objects.equals(appOrder.getOrderStatus(), CommonConstant.ORDER_STATUS_0)) {
                 appOrder.setOrderStatus(1);
@@ -1858,7 +1864,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                     weChatPayService.addProfitSharingInfos(appOrder);
                 }
             }
-            if (ObjectUtil.isEmpty(appOrder.getTransactionId())){
+            if (ObjectUtil.isEmpty(appOrder.getTransactionId())) {
                 appOrder.setTransactionId(res.getString("transaction_id"));
                 appOrderMapper.updateById(appOrder);
             }
@@ -1928,9 +1934,9 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                 if (ObjectUtil.isNotEmpty(appSitePriceRules)) {
                     AppSitePlace appSitePlace = appSitePlaceMapper.selectOne(Wrappers.<AppSitePlace>lambdaQuery()
                             .eq(AppSitePlace::getId, appSitePriceRules.getSitePlaceId()));
-                    if(null != appSitePlace){
+                    if (null != appSitePlace) {
                         record.setEarlyRefundTime(appSitePlace.getEarlyRefundTime());
-                    }else {
+                    } else {
                         record.setEarlyRefundTime(60);
                     }
                 }
@@ -1942,10 +1948,10 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
             if (ObjectUtil.isNotEmpty(proInfoList)) {
                 List<AppOrderProInfo> infoList = proInfoList.stream().filter(orderProInfo -> !Objects.equals(orderProInfo.getType(), CommonConstant.ORDER_PRO_INFO_TYPE_6)).collect(Collectors.toList());
                 List<AppOrderProInfo> insureList = proInfoList.stream().filter(orderProInfo -> Objects.equals(orderProInfo.getType(), CommonConstant.ORDER_PRO_INFO_TYPE_6)).collect(Collectors.toList());
-                infoList.forEach(a->{
-                    if(null != record.getAddressSiteId()){
+                infoList.forEach(a -> {
+                    if (null != record.getAddressSiteId()) {
                         a.setAddress(appSiteMapper.selectById(record.getAddressSiteId()).getName());
-                    }else {
+                    } else {
                         a.setAddress(sysDepartMapper.selectOne(Wrappers.<SysDepart>lambdaQuery()
                                 .eq(SysDepart::getOrgCode, "A01").last("limit 1")).getDepartName());
                     }
@@ -1957,9 +1963,10 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
         });
         return pageOrders;
     }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public String refundOrder(RefundOrderForm refundOrderForm){
+    public String refundOrder(RefundOrderForm refundOrderForm) {
         AppOrder appOrder = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, refundOrderForm.getOrderCode()).last("limit 1"));
         //退款金额
         BigDecimal refundAmount = BigDecimal.ZERO;
@@ -1969,7 +1976,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
             if (appOrder.getProfitSharingStatus() > CommonConstant.NUMBER_0) {
                 throw new JeecgBootException("当前订单无法进行退款,请联系客服处理!");
             }
-            if(!Objects.equals(appOrder.getOrderType(), CommonConstant.ORDER_PRO_INFO_TYPE_1) && !appOrder.getOrderType().equals(CommonConstant.ORDER_PRO_INFO_TYPE_2)){
+            if (!Objects.equals(appOrder.getOrderType(), CommonConstant.ORDER_PRO_INFO_TYPE_1) && !appOrder.getOrderType().equals(CommonConstant.ORDER_PRO_INFO_TYPE_2)) {
                 throw new JeecgBootException("当前订单类型不支持退款!");
             }
             if (Objects.equals(appOrder.getOrderStatus(), CommonConstant.ORDER_STATUS_2)) {
@@ -1992,11 +1999,11 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
                     AppOrderProInfo appOrderProInfo = appOrderProInfoMapper.selectById(refundOrderProInfoId);
                     String productId = appOrderProInfo.getProductId();
                     AppSitePriceRules sitePriceRules = appSitePriceRulesMapper.selectById(productId);
-                    Instant originalInstant  = sitePriceRules.getStartTime().toInstant();
+                    Instant originalInstant = sitePriceRules.getStartTime().toInstant();
                     Instant time = originalInstant.minusSeconds(appSitePlace.getEarlyRefundTime() * 60);
                     Instant now = Instant.now();
                     if (!now.isBefore(time)) {
-                        throw new JeecgBootException("商品:"+ appOrderProInfo.getProductName() +" 已超过可退时间,无法进行退款!");
+                        throw new JeecgBootException("商品:" + appOrderProInfo.getProductName() + " 已超过可退时间,无法进行退款!");
                     }
                 }
             }
@@ -2009,14 +2016,14 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
             }
         }
         //调用退款逻辑
-        weChatPayService.refundOrder(appOrder,appOrderProInfoList,refundAmount, refundOrderForm.getReason(),refundOrderForm.getType());
+        weChatPayService.refundOrder(appOrder, appOrderProInfoList, refundAmount, refundOrderForm.getReason(), refundOrderForm.getType());
 
         return "申请成功,预计在3个工作日内处理!";
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public String gameRefundOrder(String orderCode,String reason){
+    public String gameRefundOrder(String orderCode, String reason) {
         AppOrder appOrder = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, orderCode).last("limit 1"));
 
         //保险支付金额
@@ -2042,7 +2049,7 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
             refundAmount = appOrder.getPrice().subtract(payAmount);
         }
         //调用退款逻辑
-        weChatPayService.refundOrder(appOrder,null,refundAmount, reason,2);
+        weChatPayService.refundOrder(appOrder, null, refundAmount, reason, 2);
 
         return "申请成功,预计在3个工作日内处理!";
     }
@@ -2115,14 +2122,14 @@ public class OrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder> impl
     public UserPayForm payOrder(String appOrderId) {
         UserPayForm payForm = new UserPayForm();
         AppOrder appOrder = appOrderMapper.selectById(appOrderId);
-        if (ObjectUtil.isEmpty(appOrder)){
+        if (ObjectUtil.isEmpty(appOrder)) {
             throw new JeecgBootException("当前订单不存在!");
         }
-        if (!Objects.equals(appOrder.getOrderStatus(), CommonConstant.ORDER_STATUS_0)){
-            if (appOrder.getOrderStatus().equals(CommonConstant.ORDER_STATUS_1) || appOrder.getPayStatus().equals(CommonConstant.STATUS_1_INT)){
+        if (!Objects.equals(appOrder.getOrderStatus(), CommonConstant.ORDER_STATUS_0)) {
+            if (appOrder.getOrderStatus().equals(CommonConstant.ORDER_STATUS_1) || appOrder.getPayStatus().equals(CommonConstant.STATUS_1_INT)) {
                 throw new JeecgBootException("当前订单已支付!");
             }
-            if(appOrder.getOrderStatus().equals(CommonConstant.ORDER_STATUS_4)){
+            if (appOrder.getOrderStatus().equals(CommonConstant.ORDER_STATUS_4)) {
                 throw new JeecgBootException("当前订单已过期取消,请重新下单!");
             }
         }

+ 12 - 1
national-motion-module-system/national-motion-system-start/src/main/resources/application-dev.yml

@@ -410,4 +410,15 @@ http:
       max:
         per_route: 50
     validate:
-      after_inactivity: 30000
+      after_inactivity: 30000
+
+# 异步线程池配置
+async:
+  thread-pool:
+    core-pool-size: 10
+    max-pool-size: 50
+    queue-capacity: 1000
+    keep-alive-seconds: 60
+    thread-name-prefix: "business-async-"
+    allow-core-thread-timeout: false
+    await-termination-seconds: 30