فهرست منبع

Merge branch 'dev-redisson' into dev-feat

codingliang 1 سال پیش
والد
کامیت
3896f62503
21فایلهای تغییر یافته به همراه991 افزوده شده و 513 حذف شده
  1. 8 0
      pom.xml
  2. 60 0
      src/main/java/com/sqx/common/constant/RedisKey.java
  3. 26 0
      src/main/java/com/sqx/config/RedissonConfig.java
  4. 11 10
      src/main/java/com/sqx/modules/chat/service/impl/ChatConversationServiceImpl.java
  5. 6 6
      src/main/java/com/sqx/modules/coupon/controller/app/AppTbCouponUserController.java
  6. 100 103
      src/main/java/com/sqx/modules/errand/service/impl/TbIndentServiceImpl.java
  7. 2 2
      src/main/java/com/sqx/modules/order/controller/app/AppOrderController.java
  8. 9 1
      src/main/java/com/sqx/modules/order/service/AppOrderService.java
  9. 185 213
      src/main/java/com/sqx/modules/order/service/impl/AppAppOrderServiceImpl.java
  10. 61 61
      src/main/java/com/sqx/modules/order/task/OrderTask.java
  11. 12 12
      src/main/java/com/sqx/modules/pay/controller/CashController.java
  12. 10 14
      src/main/java/com/sqx/modules/pay/service/impl/CashOutServiceImpl.java
  13. 15 16
      src/main/java/com/sqx/modules/pay/service/impl/WxServiceImpl.java
  14. 12 10
      src/main/java/com/sqx/modules/shop/service/impl/ShopMessageServiceImpl.java
  15. 65 65
      src/main/java/com/sqx/modules/timedtask/controller/AutoSendOrder.java
  16. 18 0
      src/main/java/com/sqx/scheduler/config/ScheduledConfig.java
  17. 35 0
      src/main/java/com/sqx/scheduler/config/SchedulerLock.java
  18. 48 0
      src/main/java/com/sqx/scheduler/coupon/CouponScheduler.java
  19. 135 0
      src/main/java/com/sqx/scheduler/indent/IndentScheduler.java
  20. 160 0
      src/main/java/com/sqx/scheduler/order/OrderScheduler.java
  21. 13 0
      src/main/resources/application-dev.yml

+ 8 - 0
pom.xml

@@ -99,10 +99,18 @@
             <groupId>org.springframework</groupId>
             <artifactId>spring-context-support</artifactId>
         </dependency>
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson</artifactId>
+            <version>3.21.1</version>
+        </dependency>
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-configuration-processor</artifactId>

+ 60 - 0
src/main/java/com/sqx/common/constant/RedisKey.java

@@ -0,0 +1,60 @@
+package com.sqx.common.constant;
+
+/**
+ * redis key 管理
+ *
+ * @author : codingliang
+ * @date : 2024-09-09 11:50
+ */
+public interface RedisKey {
+
+    /**
+     * 插入订单锁
+     */
+    String INSERT_ORDER_LOCK = "wm:lock:order:insert:%s-%s";
+
+    /**
+     * 修改订单锁
+     */
+    String UPDATE_ORDER_LOCK = "wm:lock:order:update:%s";
+
+    /**
+     * 完成订单锁
+     */
+    String FINISH_ORDER_LOCK = "wm:lock:order:finish:%s";
+
+    /**
+     * 取消订单锁
+     */
+    String CANCEL_ORDER_LOCK = "wm:lock:order:cancel:%s";
+
+    /**
+     * 订单支付锁
+     */
+    String PAY_ORDER_LOCK = "wm:lock:order:pay:%s";
+
+    /**
+     * 提现锁
+     */
+    String CASH_OUT_LOCK = "wm:lock:cash:out:%s";
+
+    /**
+     * 跑腿订单更新锁
+     */
+    String UPDATE_INDENT_LOCK = "wm:lock:indent:%s";
+
+    /**
+     * 聊天发起锁
+     */
+    String CHAT_CONVERSATIONS_INSERT_LOCK = "wm:lock:chat:add:%s-%s";
+
+    /**
+     * 店铺审核锁
+     */
+    String SHOP_AUTHENTICATION_LOCK = "wm:lock:shop:auth:%s";
+
+    /**
+     * 用户购买vip锁
+     */
+    String USER_BUY_VIP_LOCK = "wm:lock:vip:buy:%s";
+}

+ 26 - 0
src/main/java/com/sqx/config/RedissonConfig.java

@@ -0,0 +1,26 @@
+package com.sqx.config;
+
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * redisson配置
+ *
+ * @auther: codingliang
+ * @date: 2023-10-19 13:20
+ * @description: redisson配置
+ */
+@Configuration
+public class RedissonConfig {
+
+    @Bean
+    public RedissonClient redissonClient(@Value("${spring.redis.host}") String url, @Value("${spring.redis.password}") String password, @Value("${spring.redis.port}") String port) {
+        Config config = new Config();
+        config.useSingleServer().setUsername("default").setPassword(password).setAddress("redis://" + url + ":" + port);
+        return Redisson.create(config);
+    }
+}

+ 11 - 10
src/main/java/com/sqx/modules/chat/service/impl/ChatConversationServiceImpl.java

@@ -3,6 +3,7 @@ package com.sqx.modules.chat.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sqx.common.constant.RedisKey;
 import com.sqx.common.utils.PageUtils;
 import com.sqx.common.utils.Result;
 import com.sqx.modules.app.entity.UserEntity;
@@ -13,22 +14,25 @@ import com.sqx.modules.chat.entity.ChatConversation;
 import com.sqx.modules.chat.service.ChatContentService;
 import com.sqx.modules.chat.service.ChatConversationService;
 import org.apache.commons.lang.StringUtils;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
 import java.text.SimpleDateFormat;
 import java.util.Date;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 
 @Service
 public class ChatConversationServiceImpl extends ServiceImpl<ChatConversationDao, ChatConversation> implements ChatConversationService {
 
-    private ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock();
     @Autowired
     private UserService userService;
     @Autowired
     private ChatContentService chatContentService;
+    @Resource
+    private RedissonClient redissonClient;
 
     @Override
     public PageUtils selectChatConversationPage(Integer page, Integer limit, Long userId, String nickName,String content){
@@ -53,8 +57,9 @@ public class ChatConversationServiceImpl extends ServiceImpl<ChatConversationDao
 
     @Override
     public Result insertChatConversations(ChatConversation chatConversation){
-        reentrantReadWriteLock.writeLock().lock();
-        try{
+        RLock lock = redissonClient.getLock(String.format(RedisKey.CHAT_CONVERSATIONS_INSERT_LOCK, chatConversation.getUserId(), chatConversation.getFocusedUserId()));
+        lock.lock();
+        try {
             ChatConversation chatConversation1 = selectChatConversation(chatConversation.getUserId(), chatConversation.getFocusedUserId());
             if(chatConversation1==null){
                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@@ -76,13 +81,9 @@ public class ChatConversationServiceImpl extends ServiceImpl<ChatConversationDao
                 return Result.success().put("data",chatConversation);
             }
             return Result.success().put("data",chatConversation1);
-        }catch (Exception e){
-            e.printStackTrace();
-            log.error("发起聊天出错"+e.getMessage(),e);
-        }finally {
-            reentrantReadWriteLock.writeLock().unlock();
+        } finally {
+            lock.unlock();
         }
-        return Result.error("系统繁忙,请稍后再试");
     }
 
 

+ 6 - 6
src/main/java/com/sqx/modules/coupon/controller/app/AppTbCouponUserController.java

@@ -65,12 +65,12 @@ public class AppTbCouponUserController extends AbstractController {
     }
 
 
-    //将所有超过失效时间的优惠券改为失效状态
-    @Scheduled(cron = "0 */1 * * * ?", zone = "Asia/Shanghai")
-    public void couponEnd(){
-
-        tbCouponUserService.updateExpiration();
-    }
+    // //将所有超过失效时间的优惠券改为失效状态
+    // @Scheduled(cron = "0 */1 * * * ?", zone = "Asia/Shanghai")
+    // public void couponEnd(){
+    //
+    //     tbCouponUserService.updateExpiration();
+    // }
 
 
 }

+ 100 - 103
src/main/java/com/sqx/modules/errand/service/impl/TbIndentServiceImpl.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sqx.common.constant.RedisKey;
 import com.sqx.common.exception.SqxException;
 import com.sqx.common.sms.SmsSendResult;
 import com.sqx.common.utils.DateUtils;
@@ -56,6 +57,8 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.gavaghan.geodesy.Ellipsoid;
 import org.gavaghan.geodesy.GlobalCoordinates;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
@@ -71,7 +74,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 @Service
 @Slf4j
@@ -114,7 +116,8 @@ public class TbIndentServiceImpl extends ServiceImpl<TbIndentDao, TbIndent> impl
     @Resource
     private TbIndentSmsSendLogService smsSendLogService;
 
-    private ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(true);
+    @Resource
+    private RedissonClient redissonClient;
 
     @Override
     public TbIndent findIndentByPayOrdersNo(String ordersNo) {
@@ -636,28 +639,30 @@ public class TbIndentServiceImpl extends ServiceImpl<TbIndentDao, TbIndent> impl
 
     @Override
     public Result indentReceiving(Long userId, String indentNumber) {
-        reentrantReadWriteLock.writeLock().lock();
-        try {
-            //判断骑手状态是否被封号
-            UserEntity userEntity1 = userService.selectUserById(userId);
-            if(userEntity1.getStatus()!=1){
-                return Result.error("您的帐号已被封禁,请联系客服解封!");
+        //判断骑手状态是否被封号
+        UserEntity userEntity1 = userService.selectUserById(userId);
+        if(userEntity1.getStatus()!=1){
+            return Result.error("您的帐号已被封禁,请联系客服解封!");
+        }
+        //判断骑手保证金是否大于可接单金额
+        UserEntity userMessage = userService.selectUserById(userId);
+        String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
+        CommonInfo one1 = commonInfoService.findOne(273);
+        Double cashDeposit = Double.valueOf(one1.getValue());
+        if(userMessage.getCashDeposit().compareTo(BigDecimal.valueOf(cashDeposit)) > 0 || userMessage.getCashDeposit().compareTo(BigDecimal.valueOf(cashDeposit)) == 0){
+            //判断骑手是否超过最大接单数量
+            String maxNumStr = commonInfoService.findOne(342).getValue();
+            Integer maxNum=Integer.parseInt(maxNumStr);
+            int i = tbIndentDao.selectIndentByRiderUserCount(userId);
+            if(i >= maxNum){
+                return Result.error("您已达最大接单数量,请先完成订单后再进行接单");
             }
-            //判断骑手保证金是否大于可接单金额
-            UserEntity userMessage = userService.selectUserById(userId);
-            String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
-            CommonInfo one1 = commonInfoService.findOne(273);
-            Double cashDeposit = Double.valueOf(one1.getValue());
-            if(userMessage.getCashDeposit().compareTo(BigDecimal.valueOf(cashDeposit)) > 0 ||userMessage.getCashDeposit().compareTo(BigDecimal.valueOf(cashDeposit))==0){
-                //  tbIndentDao.indentReceiving(userId, indentNumber, format);
-                //判断骑手是否超过最大接单数量
-                String maxNumStr = commonInfoService.findOne(342).getValue();
-                Integer maxNum=Integer.parseInt(maxNumStr);
-                int i = tbIndentDao.selectIndentByRiderUserCount(userId);
-                if(i>=maxNum){
-                    return Result.error("您已达最大接单数量,请先完成订单后再进行接单");
-                }
-                TbIndent tbIndent = tbIndentDao.findIndentByNumber(indentNumber);
+
+            TbIndent tbIndent;
+            RLock lock = redissonClient.getLock(String.format(RedisKey.UPDATE_INDENT_LOCK, indentNumber));
+            lock.lock();
+            try {
+                tbIndent = tbIndentDao.findIndentByNumber(indentNumber);
                 log.error("抢单:"+userId+"     "+tbIndent.getIndentState());
                 if(!"2".equals(tbIndent.getIndentState())){
                     return Result.error("订单已被抢走!");
@@ -672,73 +677,69 @@ public class TbIndentServiceImpl extends ServiceImpl<TbIndentDao, TbIndent> impl
 
                     tbIndentDao.indentReceiving(userId, indentNumber, format);
                 }
-                //消息推送(以前写的在下面放着)
-                CommonInfo five = commonInfoService.findOne(310);
-                List<String> msgList=new ArrayList<>();
-                msgList.add("接单项目");
-                msgList.add(userEntity1.getNickName());
-                msgList.add(format);
-                msgList.add("接单成功,请及时取货!");
-                SenInfoCheckUtil.sendRiderMsg(userEntity1.getRiderOpenId(),five.getValue(),msgList,4);
-                userService.pushToSingleRider("接单成功", "您已接单成功,请及时派送", userEntity1.getRiderClientid());
-
-                //用户推送
-                CommonInfo msg = commonInfoService.findOne(269);
-                UserEntity userEntity = userService.selectUserById(tbIndent.getUserId());
-                MessageInfo messageInfo = new MessageInfo();
-                messageInfo.setContent("骑手已接单");
-                messageInfo.setTitle("订单状态通知");
-                messageInfo.setState(String.valueOf(5));
-                messageInfo.setUserName(userEntity.getUserName());
-                messageInfo.setUserId(String.valueOf(userEntity.getUserId()));
-                messageInfo.setCreateAt(DateUtils.format(new Date()));
-                messageInfo.setIsSee("0");
-                messageService.saveBody(messageInfo);
+            } finally {
+                lock.unlock();
+            }
 
+            //消息推送(以前写的在下面放着)
+            CommonInfo five = commonInfoService.findOne(310);
+            List<String> msgList=new ArrayList<>();
+            msgList.add("接单项目");
+            msgList.add(userEntity1.getNickName());
+            msgList.add(format);
+            msgList.add("接单成功,请及时取货!");
+            SenInfoCheckUtil.sendRiderMsg(userEntity1.getRiderOpenId(),five.getValue(),msgList,4);
+            userService.pushToSingleRider("接单成功", "您已接单成功,请及时派送", userEntity1.getRiderClientid());
 
-                List<String> msgListUser = new ArrayList<>();
-                String value = commonInfoService.findOne(12).getValue();
-                msgListUser.add("骑手已接单");
-                msgListUser.add(tbIndent.getIndentNumber());
-                if(tbIndent.getOrderId()!=null){
-                    TbOrder order = appOrderService.getById(tbIndent.getOrderId());
-                    if(order!=null){
-                        Long shopId = order.getShopId();
-                        GoodsShop goodsShop = goodsShopDao.selectById(shopId);
-                        msgListUser.add(goodsShop.getShopName());
-                    }else{
-                        msgListUser.add(value);
-                    }
+            //用户推送
+            CommonInfo msg = commonInfoService.findOne(269);
+            UserEntity userEntity = userService.selectUserById(tbIndent.getUserId());
+            MessageInfo messageInfo = new MessageInfo();
+            messageInfo.setContent("骑手已接单");
+            messageInfo.setTitle("订单状态通知");
+            messageInfo.setState(String.valueOf(5));
+            messageInfo.setUserName(userEntity.getUserName());
+            messageInfo.setUserId(String.valueOf(userEntity.getUserId()));
+            messageInfo.setCreateAt(DateUtils.format(new Date()));
+            messageInfo.setIsSee("0");
+            messageService.saveBody(messageInfo);
+
+
+            List<String> msgListUser = new ArrayList<>();
+            String value = commonInfoService.findOne(12).getValue();
+            msgListUser.add("骑手已接单");
+            msgListUser.add(tbIndent.getIndentNumber());
+            if(tbIndent.getOrderId()!=null){
+                TbOrder order = appOrderService.getById(tbIndent.getOrderId());
+                if(order!=null){
+                    Long shopId = order.getShopId();
+                    GoodsShop goodsShop = goodsShopDao.selectById(shopId);
+                    msgListUser.add(goodsShop.getShopName());
                 }else{
                     msgListUser.add(value);
                 }
-                msgListUser.add(DateUtils.format(new Date()));
-                SenInfoCheckUtil.sendMsg(userEntity.getOpenId(), msg.getValue(), msgListUser, 1);
-                if(tbIndent.getOrderId()!=null){
-                    TbOrder order = appOrderService.getById(tbIndent.getOrderId());
-                    String shopTemplate = commonInfoService.findOne(354).getValue();
-                    List<String> msgListShop = new ArrayList<>();
-                    msgListShop.add(tbIndent.getIndentNumber());
-                    log.error("打印:"+tbIndent.getIndentNumber());
-                    msgListShop.add("骑手接单");
-                    msgListShop.add(DateUtils.format(new Date()));
-                    log.error("打印:"+msgListShop.toString());
-                    GoodsShop goodsShop = goodsShopDao.selectById(order.getShopId());
-                    UserEntity shopUser = userService.selectUserById(goodsShop.getUserId());
-                    SenInfoCheckUtil.sendShopMsg(shopUser.getShopOpenId(), shopTemplate, msgListShop, 9);
-                }
-            }else {
-                return Result.error("你的保证金不足,请缴纳保证金后再接单");
+            }else{
+                msgListUser.add(value);
             }
-            return Result.success();
-        }catch (Exception e){
-            e.printStackTrace();
-            log.error("骑手接单 异常:"+e.getMessage(),e);
-        }finally {
-            reentrantReadWriteLock.writeLock().unlock();
+            msgListUser.add(DateUtils.format(new Date()));
+            SenInfoCheckUtil.sendMsg(userEntity.getOpenId(), msg.getValue(), msgListUser, 1);
+            if(tbIndent.getOrderId()!=null){
+                TbOrder order = appOrderService.getById(tbIndent.getOrderId());
+                String shopTemplate = commonInfoService.findOne(354).getValue();
+                List<String> msgListShop = new ArrayList<>();
+                msgListShop.add(tbIndent.getIndentNumber());
+                log.error("打印:"+tbIndent.getIndentNumber());
+                msgListShop.add("骑手接单");
+                msgListShop.add(DateUtils.format(new Date()));
+                log.error("打印:"+msgListShop.toString());
+                GoodsShop goodsShop = goodsShopDao.selectById(order.getShopId());
+                UserEntity shopUser = userService.selectUserById(goodsShop.getUserId());
+                SenInfoCheckUtil.sendShopMsg(shopUser.getShopOpenId(), shopTemplate, msgListShop, 9);
+            }
+        }else {
+            return Result.error("你的保证金不足,请缴纳保证金后再接单");
         }
-        return Result.error("系统繁忙,请稍后再试!");
-
+        return Result.success();
     }
 
     @Override
@@ -926,25 +927,24 @@ public class TbIndentServiceImpl extends ServiceImpl<TbIndentDao, TbIndent> impl
     public Result riderDelivery(Long userId, RiderDeliveryDTO deliveryDTO) {
         // 添加拍照发短信逻辑
         // 因为原有的确认送达方法代码比较凌乱,且不好重新封装,所以这里就在原有确认收货方法之前添加拍照发短信逻辑
-        reentrantReadWriteLock.writeLock().lock();
-        try{
-            String indentNumber = deliveryDTO.getIndentNumber();
-            TbIndent indentOrder = tbIndentDao.findIndentByNumber(indentNumber);
-            if (ObjectUtil.isNull(indentOrder)) {
-                throw new SqxException("无效的跑腿订单id");
-            }
 
+        String indentNumber = deliveryDTO.getIndentNumber();
+        TbIndent indentOrder = tbIndentDao.findIndentByNumber(indentNumber);
+        if (ObjectUtil.isNull(indentOrder)) {
+            throw new SqxException("无效的跑腿订单id");
+        }
+
+        RLock lock = redissonClient.getLock(String.format(RedisKey.UPDATE_INDENT_LOCK, indentNumber));
+        lock.lock();
+        try {
             // 如果是外卖订单
             if (ObjectUtil.equal(indentOrder.getIndentType(), "5")) {
                 handTakeoutOrder(indentOrder, userId, deliveryDTO);
             }
 
             return finshOrder(userId, indentNumber, deliveryDTO.getItemCode());
-        } catch (Exception e){
-            log.error("完成订单异常:"+e.getMessage(),e);
-            throw new SqxException(e.getMessage());
         } finally {
-            reentrantReadWriteLock.writeLock().unlock();
+            lock.unlock();
         }
     }
 
@@ -1027,22 +1027,19 @@ public class TbIndentServiceImpl extends ServiceImpl<TbIndentDao, TbIndent> impl
 
     @Override
     public Result userDelivery(Long userId, String indentNumber) {
-        reentrantReadWriteLock.writeLock().lock();
-        try{
-            String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
+        String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
+        RLock lock = redissonClient.getLock(String.format(RedisKey.UPDATE_INDENT_LOCK, indentNumber));
+        lock.lock();
+        try {
             TbIndent indentByNumber = tbIndentDao.findIndentByNumber(indentNumber);
             tbIndentDao.userDelivery(userId, indentNumber, date);
             finshIndent(userId, indentNumber);
             log.info("操作完成订单5:"+indentByNumber.getOrderId());
             appOrderService.accomplishOrders(indentByNumber.getOrderId(),1);
             return Result.success();
-        }catch (Exception e){
-            e.printStackTrace();
-            log.error("用户确认收货异常:"+e.getMessage(),e);
-        }finally {
-            reentrantReadWriteLock.writeLock().unlock();
+        } finally {
+            lock.unlock();
         }
-        return Result.error("系统繁忙,请稍后再试!");
     }
 
     @Override

+ 2 - 2
src/main/java/com/sqx/modules/order/controller/app/AppOrderController.java

@@ -29,8 +29,8 @@ public class AppOrderController {
     @ApiOperation("生成订单(未结算状态)")
     @PostMapping(value = "/insertOrder")
     public Result insertOrder(@RequestAttribute Long userId, Long shopId, Long goodsId, Integer num, Long skuId, String skuMessage, Integer orderType){
-
-        return appOrderService.insertOrder(userId, shopId, goodsId, num, skuId, skuMessage, orderType);
+        appOrderService.insertOrder(userId, shopId, goodsId, num, skuId, skuMessage, orderType);
+        return Result.success();
     }
 
     @Login

+ 9 - 1
src/main/java/com/sqx/modules/order/service/AppOrderService.java

@@ -10,11 +10,12 @@ import com.sqx.modules.order.entity.TbOrder;
 import com.sqx.modules.pay.dto.PayOrderDTO;
 import com.sqx.modules.utils.excel.ExcelData;
 
+import java.time.LocalDateTime;
 import java.util.List;
 
 public interface AppOrderService extends IService<TbOrder> {
 
-    Result insertOrder(Long userId, Long shopId, Long goodsId, Integer num, Long skuId, String skuMessage, Integer orderType);
+    void insertOrder(Long userId, Long shopId, Long goodsId, Integer num, Long skuId, String skuMessage, Integer orderType);
 
     Result print(Long orderId);
 
@@ -160,4 +161,11 @@ public interface AppOrderService extends IService<TbOrder> {
      * @return 订单id集合
      */
     List<Long> getCurWaitReceivingOrderIds();
+
+    /**
+     * 获取 datetime 前正在制作中的订单
+     * @param datetime 时间
+     * @return 订单列表
+     */
+    List<TbOrder> getProdIngOrders(LocalDateTime datetime);
 }

+ 185 - 213
src/main/java/com/sqx/modules/order/service/impl/AppAppOrderServiceImpl.java

@@ -11,6 +11,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sqx.common.constant.RedisKey;
 import com.sqx.common.exception.SqxException;
 import com.sqx.common.sms.SmsSendResult;
 import com.sqx.common.utils.Constant;
@@ -77,9 +78,10 @@ import com.sqx.modules.utils.fieYun.FeiYunUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
 import org.apache.shiro.SecurityUtils;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
@@ -96,7 +98,6 @@ import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 @Service
 @Slf4j
@@ -161,107 +162,57 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
     @Autowired
     private TbIndentSmsTemplateService smsTemplateService;
 
-    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(true);
-
-    @Override
-    public Result insertOrder(Long userId, Long shopId, Long goodsId, Integer num, Long skuId, String skuMessage, Integer orderType) {
-        reentrantReadWriteLock.writeLock().lock();
-        try {
-            return addOrder(userId, shopId, goodsId, num, skuId, skuMessage, orderType);
-        } catch (Exception e) {
-            e.printStackTrace();
-            log.error("下单异常:" + e.getMessage(), e);
-        } finally {
-            reentrantReadWriteLock.writeLock().unlock();
-        }
-        return Result.error("系统繁忙,请稍后再试!");
-    }
-
-    /**
-     * 判断店铺当前时间是否营业时间范围内
-     * @param shopId 店铺id
-     * @return boolean
-     */
-    private boolean isShopBusinessTime(Long shopId) {
-        GoodsShop goodsShop = goodsShopDao.selectById(shopId);
-        if (goodsShop == null) {
-            throw new SqxException("无效的店铺id");
-        }
-        String businessHours = goodsShop.getBusinessHours();
-        String lockHours = goodsShop.getLockHours();
+    @Autowired
+    private RedissonClient redissonClient;
 
-        // 营业时间和闭店时间有一个为空,则直接返回true,默认全天营业
-        if (StringUtils.isEmpty(businessHours) || StringUtils.isEmpty(lockHours)) {
-            return true;
-        }
+    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern(DateUtils.TIME_PATTERN1);
 
-        LocalTime now = LocalTime.now();
 
-        return now.isAfter(LocalTime.parse(businessHours)) && now.isBefore(LocalTime.parse(lockHours));
-    }
 
     @Transactional
-    public Result addOrder(Long userId, Long shopId, Long goodsId, Integer num, Long skuId, String skuMessage, Integer orderType) {
+    @Override
+    public void insertOrder(Long userId, Long shopId, Long goodsId, Integer num, Long skuId, String skuMessage, Integer orderType) {
         // 判断当前时间是否在店铺营业范围内
         if (!isShopBusinessTime(shopId)) {
-            return Result.error("店铺已打烊!");
+            throw new SqxException("店铺已打烊!");
         }
 
         //先判断该商品的库存是否足够
         GoodsShopRelevancy goodsShopRelevancy = goodsShopRelevancyDao.selectOne(new QueryWrapper<GoodsShopRelevancy>().eq("shop_id", shopId).eq("goods_id", goodsId));
         if (goodsShopRelevancy.getInventory() < num) {
-            return Result.error("该商品库存不足!");
+            throw new SqxException("该商品库存不足!");
         }
-        TbOrder order = new TbOrder();
-        order = appOrderDao.selectOne(new QueryWrapper<TbOrder>()
-                .eq("user_id", userId).eq("shop_id", shopId).eq("status", 1));
-        Goods goods = goodsDao.selectById(goodsId);
-        UserEntity userEntity = userDao.selectById(userId);
-        TbOrder tbOrder = new TbOrder();
-        String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
-        if (order == null) {
-            tbOrder.setUserId(userId);
-            tbOrder.setUserName(userEntity.getUserName());
-            tbOrder.setPhone(userEntity.getPhone());
-            tbOrder.setOrderNumber(getGeneralOrder());
-            tbOrder.setIsPay(0);
-            tbOrder.setDeleteFlag(0);
-            tbOrder.setStatus(1);
-            tbOrder.setShopId(shopId);
-            //创建订单,订单发起人就是该登录用户
-            tbOrder.setParentUserId(userId);
-            tbOrder.setCreateTime(format);
-            tbOrder.setAddGoodsTime(format);
-            appOrderDao.insertOrder(tbOrder);
 
-            TbOrder tbOrder1 = new TbOrder();
-            tbOrder1.setOrderId(tbOrder.getOrderId());
-            tbOrder1.setParentId(tbOrder.getOrderId());
-            appOrderDao.updateById(tbOrder1);
-            //添加订单-商品表
-            Long orderId = tbOrder.getOrderId();
-            OrderGoods orderGoods = new OrderGoods();
-            orderGoods.setOrderId(orderId);
-            orderGoods.setGoodsName(goods.getGoodsName());
-            orderGoods.setSkuId(skuId);
-            GoodsSku goodsSku = goodsSkuDao.selectById(skuId);
-            orderGoods.setGoodsPrice(goodsSku.getSkuPrice());
-            orderGoods.setSkuMessage(skuMessage);
-            orderGoods.setGoodsNum(num);
-            orderGoods.setGoodsPack(goods.getPackMoney());
-            orderGoods.setGoodsPicture(goods.getGoodsCover());
-            orderGoods.setGoodsId(goods.getGoodsId());
-            orderGoods.setUserId(userId);
-            orderGoodsDao.insert(orderGoods);
-        } else {
-            //添加订单-商品表
-            Long orderId = order.getOrderId();
-            OrderGoods orderGoods = orderGoodsDao.selectOne(new QueryWrapper<OrderGoods>().eq("order_id", orderId).eq("goods_id", goods.getGoodsId()).eq("sku_id", skuId).eq("user_id", userId));
-            if (orderGoods != null) {
-                orderGoods.setGoodsNum(orderGoods.getGoodsNum() + 1);
-                orderGoodsDao.updateById(orderGoods);
-            } else {
-                orderGoods = new OrderGoods();
+        RLock lock = redissonClient.getLock(String.format(RedisKey.INSERT_ORDER_LOCK, userId, shopId));
+        lock.lock();
+        try {
+            TbOrder order = appOrderDao.selectOne(new QueryWrapper<TbOrder>().eq("user_id", userId).eq("shop_id", shopId).eq("status", 1));
+            Goods goods = goodsDao.selectById(goodsId);
+            String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
+            if (order == null) {
+                UserEntity userEntity = userDao.selectById(userId);
+                TbOrder tbOrder = new TbOrder();
+                tbOrder.setUserId(userId);
+                tbOrder.setUserName(userEntity.getUserName());
+                tbOrder.setPhone(userEntity.getPhone());
+                tbOrder.setOrderNumber(getGeneralOrder());
+                tbOrder.setIsPay(0);
+                tbOrder.setDeleteFlag(0);
+                tbOrder.setStatus(1);
+                tbOrder.setShopId(shopId);
+                //创建订单,订单发起人就是该登录用户
+                tbOrder.setParentUserId(userId);
+                tbOrder.setCreateTime(format);
+                tbOrder.setAddGoodsTime(format);
+                appOrderDao.insertOrder(tbOrder);
+
+                TbOrder tbOrder1 = new TbOrder();
+                tbOrder1.setOrderId(tbOrder.getOrderId());
+                tbOrder1.setParentId(tbOrder.getOrderId());
+                appOrderDao.updateById(tbOrder1);
+                //添加订单-商品表
+                Long orderId = tbOrder.getOrderId();
+                OrderGoods orderGoods = new OrderGoods();
                 orderGoods.setOrderId(orderId);
                 orderGoods.setGoodsName(goods.getGoodsName());
                 orderGoods.setSkuId(skuId);
@@ -274,16 +225,61 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
                 orderGoods.setGoodsId(goods.getGoodsId());
                 orderGoods.setUserId(userId);
                 orderGoodsDao.insert(orderGoods);
+            } else {
+                //添加订单-商品表
+                Long orderId = order.getOrderId();
+                OrderGoods orderGoods = orderGoodsDao.selectOne(new QueryWrapper<OrderGoods>().eq("order_id", orderId).eq("goods_id", goods.getGoodsId()).eq("sku_id", skuId).eq("user_id", userId));
+                if (orderGoods != null) {
+                    orderGoods.setGoodsNum(orderGoods.getGoodsNum() + 1);
+                    orderGoodsDao.updateById(orderGoods);
+                } else {
+                    orderGoods = new OrderGoods();
+                    orderGoods.setOrderId(orderId);
+                    orderGoods.setGoodsName(goods.getGoodsName());
+                    orderGoods.setSkuId(skuId);
+                    GoodsSku goodsSku = goodsSkuDao.selectById(skuId);
+                    orderGoods.setGoodsPrice(goodsSku.getSkuPrice());
+                    orderGoods.setSkuMessage(skuMessage);
+                    orderGoods.setGoodsNum(num);
+                    orderGoods.setGoodsPack(goods.getPackMoney());
+                    orderGoods.setGoodsPicture(goods.getGoodsCover());
+                    orderGoods.setGoodsId(goods.getGoodsId());
+                    orderGoods.setUserId(userId);
+                    orderGoodsDao.insert(orderGoods);
+                }
+                //修改订单表最后一次添加商品的时间
+                TbOrder tbOrder1 = new TbOrder();
+                tbOrder1.setOrderId(orderId);
+                tbOrder1.setAddGoodsTime(format);
+                appOrderDao.updateById(tbOrder1);
             }
-            //修改订单表最后一次添加商品的时间
-            TbOrder tbOrder1 = new TbOrder();
-            tbOrder1.setOrderId(orderId);
-            tbOrder1.setAddGoodsTime(format);
-            appOrderDao.updateById(tbOrder1);
+        } finally {
+            lock.unlock();
         }
-        return Result.success();
     }
 
+    /**
+     * 判断店铺当前时间是否营业时间范围内
+     * @param shopId 店铺id
+     * @return boolean
+     */
+    private boolean isShopBusinessTime(Long shopId) {
+        GoodsShop goodsShop = goodsShopDao.selectById(shopId);
+        if (goodsShop == null) {
+            throw new SqxException("无效的店铺id");
+        }
+        String businessHours = goodsShop.getBusinessHours();
+        String lockHours = goodsShop.getLockHours();
+
+        // 营业时间和闭店时间有一个为空,则直接返回true,默认全天营业
+        if (StringUtils.isEmpty(businessHours) || StringUtils.isEmpty(lockHours)) {
+            return true;
+        }
+
+        LocalTime now = LocalTime.now();
+
+        return now.isAfter(LocalTime.parse(businessHours)) && now.isBefore(LocalTime.parse(lockHours));
+    }
 
     @Override
     public Result shareTheBill(Long userId, Long shopId) {
@@ -368,8 +364,6 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
             pages = new Page<>();
         }
         return evaluateDao.getEvaluateList(pages, evaluate);
-
-
     }
 
     @Override
@@ -423,8 +417,6 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
         return parentOrder;
     }
 
-    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern(DateUtils.TIME_PATTERN1);
-
     /**
      * 校验订单类型
      */
@@ -1448,10 +1440,7 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
     @Transactional
     @Override
     public Result updateGoodsNum(Long orderGoodsId, Integer type, Integer num, Long shopId) {
-        /*reentrantReadWriteLock.writeLock().lock();
-        try{*/
-        //type = 1增加商品数  = 2 减少商品数
-
+        // type = 1增加商品数  = 2 减少商品数
         OrderGoods orderGoods = orderGoodsDao.selectById(orderGoodsId);
         if(orderGoods==null){
             return Result.error("系统繁忙,请稍后再试!");
@@ -1478,12 +1467,6 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
                 orderGoodsDao.updateById(orderGoods2);
             }
         }
-        /*}catch (Exception e){
-            e.printStackTrace();
-            log.error("减少购物车商品出错:"+e.getMessage(),e);
-        }finally {
-            reentrantReadWriteLock.writeLock().unlock();
-        }*/
         return Result.success();
     }
 
@@ -1759,28 +1742,24 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
 
     @Override
     public Result updateOrder(TbOrder order) {
-        reentrantReadWriteLock.writeLock().lock();
+        RLock lock = redissonClient.getLock(String.format(RedisKey.UPDATE_ORDER_LOCK, order.getOrderId()));
+        lock.lock();
         try {
             return updateOrders(order);
-        } catch (Exception e) {
-            throw e;
         } finally {
-            reentrantReadWriteLock.writeLock().unlock();
+            lock.unlock();
         }
     }
 
     @Override
     public Result accomplishOrder(Long orderId) {
-        reentrantReadWriteLock.writeLock().lock();
+        RLock lock = redissonClient.getLock(String.format(RedisKey.FINISH_ORDER_LOCK, orderId));
+        lock.lock();
         try {
             return accomplishOrders(orderId,1);
-        } catch (Exception e) {
-            e.printStackTrace();
-            log.error("完成订单异常:" + e.getMessage(), e);
         } finally {
-            reentrantReadWriteLock.writeLock().unlock();
+            lock.unlock();
         }
-        return Result.error("系统繁忙,请稍后再试!");
     }
 
     /**
@@ -1977,52 +1956,52 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
         return Result.success();
     }
 
-    @Scheduled(cron = "0 */10 * * * ?")
-    public void orderEnd() {
-        CommonInfo one = commonInfoService.findOne(268);
-        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-        List<TbOrder> orderList = appOrderDao.selectList(new QueryWrapper<TbOrder>().eq("status", 3));
-        for (TbOrder tbOrder : orderList) {
-            LocalDateTime updateTime = LocalDateTime.parse(tbOrder.getUpdateTime(), df);
-            //计算当前订单什么时候超时完成
-            LocalDateTime overDateTime = updateTime.plusHours(Integer.parseInt(one.getValue()));
-            if (LocalDateTime.now().isAfter(overDateTime)) {
-                log.info("操作完成订单6:"+tbOrder.getOrderId());
-                accomplishOrders(tbOrder.getOrderId(),2);
-                //管理端完成订单,则消息通知用户
-                //添加消息记录
-                MessageInfo messageInfo = new MessageInfo();
-                messageInfo.setState(String.valueOf(5));
-                messageInfo.setTitle("订单完成");
-                messageInfo.setContent("您的订单已完成,欢迎下次光临");
-                messageInfo.setCreateAt(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
-                messageInfo.setUserId(tbOrder.getUserId().toString());
-                messageInfoDao.insert(messageInfo);
-                //设置小程序消息推送
-                CommonInfo one1 = commonInfoService.findOne(269);
-                List<String> msgList = new ArrayList<>();
-                Long shopId = tbOrder.getShopId();
-                GoodsShop goodsShop = goodsShopDao.selectById(shopId);
-                String orderNum1 = tbOrder.getOrderNumber();
-                msgList.add("订单完成");
-                msgList.add(orderNum1);
-                if (goodsShop != null && goodsShop.getShopName() != null) {
-                    String shopName = goodsShop.getShopName();
-                    msgList.add(shopName);
-                } else {
-                    msgList.add("");
-                }
-                msgList.add(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
-                UserEntity userEntity = userDao.selectById(tbOrder.getUserId());
-                if (userEntity != null && userEntity.getOpenId() != null) {
-                    SenInfoCheckUtil.sendMsg(userEntity.getOpenId(), one1.getValue(), msgList, 1);
-                    userService.pushToSingle("订单完成", "亲爱的用户您好,您的订单已完成,欢迎下次光临!", userEntity.getClientid());
-                }
-
-            }
-
-        }
-    }
+    // @Scheduled(cron = "0 */10 * * * ?")
+    // public void orderEnd() {
+    //     CommonInfo one = commonInfoService.findOne(268);
+    //     DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+    //     List<TbOrder> orderList = appOrderDao.selectList(new QueryWrapper<TbOrder>().eq("status", 3));
+    //     for (TbOrder tbOrder : orderList) {
+    //         LocalDateTime updateTime = LocalDateTime.parse(tbOrder.getUpdateTime(), df);
+    //         //计算当前订单什么时候超时完成
+    //         LocalDateTime overDateTime = updateTime.plusHours(Integer.parseInt(one.getValue()));
+    //         if (LocalDateTime.now().isAfter(overDateTime)) {
+    //             log.info("操作完成订单6:"+tbOrder.getOrderId());
+    //             accomplishOrders(tbOrder.getOrderId(),2);
+    //             //管理端完成订单,则消息通知用户
+    //             //添加消息记录
+    //             MessageInfo messageInfo = new MessageInfo();
+    //             messageInfo.setState(String.valueOf(5));
+    //             messageInfo.setTitle("订单完成");
+    //             messageInfo.setContent("您的订单已完成,欢迎下次光临");
+    //             messageInfo.setCreateAt(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+    //             messageInfo.setUserId(tbOrder.getUserId().toString());
+    //             messageInfoDao.insert(messageInfo);
+    //             //设置小程序消息推送
+    //             CommonInfo one1 = commonInfoService.findOne(269);
+    //             List<String> msgList = new ArrayList<>();
+    //             Long shopId = tbOrder.getShopId();
+    //             GoodsShop goodsShop = goodsShopDao.selectById(shopId);
+    //             String orderNum1 = tbOrder.getOrderNumber();
+    //             msgList.add("订单完成");
+    //             msgList.add(orderNum1);
+    //             if (goodsShop != null && goodsShop.getShopName() != null) {
+    //                 String shopName = goodsShop.getShopName();
+    //                 msgList.add(shopName);
+    //             } else {
+    //                 msgList.add("");
+    //             }
+    //             msgList.add(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+    //             UserEntity userEntity = userDao.selectById(tbOrder.getUserId());
+    //             if (userEntity != null && userEntity.getOpenId() != null) {
+    //                 SenInfoCheckUtil.sendMsg(userEntity.getOpenId(), one1.getValue(), msgList, 1);
+    //                 userService.pushToSingle("订单完成", "亲爱的用户您好,您的订单已完成,欢迎下次光临!", userEntity.getClientid());
+    //             }
+    //
+    //         }
+    //
+    //     }
+    // }
 
     @Transactional
     @Override
@@ -2064,15 +2043,13 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
 
     @Override
     public Result userCancelOrder(Long orderId){
-        reentrantReadWriteLock.writeLock().lock();
+        RLock lock = redissonClient.getLock(String.format(RedisKey.CANCEL_ORDER_LOCK, orderId));
+        lock.lock();
         try {
             return userCancelOrders(orderId);
-        }catch (Exception e){
-            e.printStackTrace();
-        }finally {
-            reentrantReadWriteLock.writeLock().unlock();
+        } finally {
+            lock.unlock();
         }
-        return Result.error("系统繁忙,请稍后再试!");
     }
 
 
@@ -2226,18 +2203,15 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
 
     @Override
     public Result adminCancelOrder(Long orderId){
-        reentrantReadWriteLock.writeLock().lock();
+        RLock lock = redissonClient.getLock(String.format(RedisKey.CANCEL_ORDER_LOCK, orderId));
+        lock.lock();
         try {
             return adminCancelOrders(orderId);
-        }catch (Exception e){
-            e.printStackTrace();
-        }finally {
-            reentrantReadWriteLock.writeLock().unlock();
+        } finally {
+            lock.unlock();
         }
-        return Result.error("系统繁忙,请稍后再试!");
     }
 
-
     @Transactional
     public Result adminCancelOrders(Long orderId) {
         String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
@@ -2369,23 +2343,16 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
             tbOrderList.getRecords().get(i).setOrderGoodsList(list);
         }
         if (shopId != null && userId != null) {
-            reentrantReadWriteLock.writeLock().lock();
-            try {
-                UserBrowse userBrowse = userBrowseDao.selectOne(new QueryWrapper<UserBrowse>().eq("user_id", userId).eq("by_browse_id", shopId));
-                String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
-                if (userBrowse != null) {
-                    userBrowse.setUpdateTime(format);
-                } else {
-                    userBrowse = new UserBrowse();
-                    userBrowse.setUserId(userId);
-                    userBrowse.setByBrowseId(shopId);
-                    userBrowse.setUpdateTime(format);
-                    userBrowseDao.insert(userBrowse);
-                }
-            } catch (Exception e) {
-                e.printStackTrace();
-            } finally {
-                reentrantReadWriteLock.writeLock().unlock();
+            UserBrowse userBrowse = userBrowseDao.selectOne(new QueryWrapper<UserBrowse>().eq("user_id", userId).eq("by_browse_id", shopId));
+            String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
+            if (userBrowse != null) {
+                userBrowse.setUpdateTime(format);
+            } else {
+                userBrowse = new UserBrowse();
+                userBrowse.setUserId(userId);
+                userBrowse.setByBrowseId(shopId);
+                userBrowse.setUpdateTime(format);
+                userBrowseDao.insert(userBrowse);
             }
         }
         PageUtils pageUtils = new PageUtils(tbOrderList);
@@ -2403,24 +2370,29 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
     }
 
 
-    @Scheduled(cron = "0 */1 * * * ?")
-    public void makeOrders(){
-        //自动制作完成订单
-        String value = commonInfoService.findOne(418).getValue();
-        if("是".equals(value)){
-            String minute = commonInfoService.findOne(419).getValue();
-            LocalDateTime minusMinutes = LocalDateTime.now().minusMinutes(Long.valueOf(minute));
-            List<TbOrder> tbOrders = baseMapper.selectMakeOrdersList(minusMinutes);
-            for (TbOrder order:tbOrders){
-                try{
-                    order.setStatus(3);
-                    updateOrder(order);
-                }catch (Exception e){
-                    e.printStackTrace();
-                    log.error("自动完成异常:"+e.getMessage(),e);
-                }
-            }
-        }
+    // @Scheduled(cron = "0 */1 * * * ?")
+    // public void makeOrders(){
+    //     //自动制作完成订单
+    //     String value = commonInfoService.findOne(418).getValue();
+    //     if("是".equals(value)){
+    //         String minute = commonInfoService.findOne(419).getValue();
+    //         LocalDateTime minusMinutes = LocalDateTime.now().minusMinutes(Long.valueOf(minute));
+    //         List<TbOrder> tbOrders = baseMapper.selectMakeOrdersList(minusMinutes);
+    //         for (TbOrder order:tbOrders){
+    //             try{
+    //                 order.setStatus(3);
+    //                 updateOrder(order);
+    //             }catch (Exception e){
+    //                 e.printStackTrace();
+    //                 log.error("自动完成异常:"+e.getMessage(),e);
+    //             }
+    //         }
+    //     }
+    // }
+
+    @Override
+    public List<TbOrder> getProdIngOrders(LocalDateTime minusMinutes) {
+        return baseMapper.selectMakeOrdersList(minusMinutes);
     }
 
     /**

+ 61 - 61
src/main/java/com/sqx/modules/order/task/OrderTask.java

@@ -1,61 +1,61 @@
-package com.sqx.modules.order.task;
-
-import cn.hutool.core.collection.CollUtil;
-import com.sqx.modules.order.entity.TbOrder;
-import com.sqx.modules.order.service.AppOrderService;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * 订单定时任务
- *
- * @author : codingliang
- * @date : 2024-08-19 20:42
- */
-@Slf4j
-@Async
-@Component
-@RequiredArgsConstructor
-public class OrderTask {
-
-    private final AppOrderService orderService;
-
-    /**
-     * 预约订单自动接单
-     * 5分钟运行一次
-     */
-    @Scheduled(cron = "0 */5 * * * ?")
-    public void reservationAutoReceivingOrder() {
-        log.info("预约订单自动接单任务运行....");
-        List<Long> orderIds = orderService.getCurWaitReceivingOrderIds();
-        if (CollUtil.isEmpty(orderIds)) {
-            log.info("没有符合条件的预约订单,预约订单自动接单任务运行....");
-            return;
-        }
-
-        List<TbOrder> waitOrders = orderIds.stream().map(orderId -> {
-            TbOrder waitOrder = new TbOrder();
-            waitOrder.setOrderId(orderId);
-            waitOrder.setStatus(6);
-
-            return waitOrder;
-        }).collect(Collectors.toList());
-
-
-        for (TbOrder waitOrder : waitOrders) {
-            log.info("预约订单id:{},正在自动接单", waitOrder.getOrderId());
-            try {
-                orderService.updateOrder(waitOrder);
-            } catch (Exception e) {
-                e.printStackTrace();
-                log.error("预约单id:{},自动接单失败,失败原因:{}", waitOrder.getOrderId(), e.getMessage());
-            }
-        }
-    }
-}
+// package com.sqx.modules.order.task;
+//
+// import cn.hutool.core.collection.CollUtil;
+// import com.sqx.modules.order.entity.TbOrder;
+// import com.sqx.modules.order.service.AppOrderService;
+// import lombok.RequiredArgsConstructor;
+// import lombok.extern.slf4j.Slf4j;
+// import org.springframework.scheduling.annotation.Async;
+// import org.springframework.scheduling.annotation.Scheduled;
+// import org.springframework.stereotype.Component;
+//
+// import java.util.List;
+// import java.util.stream.Collectors;
+//
+// /**
+//  * 订单定时任务
+//  *
+//  * @author : codingliang
+//  * @date : 2024-08-19 20:42
+//  */
+// @Slf4j
+// @Async
+// @Component
+// @RequiredArgsConstructor
+// public class OrderTask {
+//
+//     private final AppOrderService orderService;
+//
+//     /**
+//      * 预约订单自动接单
+//      * 5分钟运行一次
+//      */
+//     @Scheduled(cron = "0 */5 * * * ?")
+//     public void reservationAutoReceivingOrder() {
+//         log.info("预约订单自动接单任务运行....");
+//         List<Long> orderIds = orderService.getCurWaitReceivingOrderIds();
+//         if (CollUtil.isEmpty(orderIds)) {
+//             log.info("没有符合条件的预约订单,预约订单自动接单任务运行....");
+//             return;
+//         }
+//
+//         List<TbOrder> waitOrders = orderIds.stream().map(orderId -> {
+//             TbOrder waitOrder = new TbOrder();
+//             waitOrder.setOrderId(orderId);
+//             waitOrder.setStatus(6);
+//
+//             return waitOrder;
+//         }).collect(Collectors.toList());
+//
+//
+//         for (TbOrder waitOrder : waitOrders) {
+//             log.info("预约订单id:{},正在自动接单", waitOrder.getOrderId());
+//             try {
+//                 orderService.updateOrder(waitOrder);
+//             } catch (Exception e) {
+//                 e.printStackTrace();
+//                 log.error("预约单id:{},自动接单失败,失败原因:{}", waitOrder.getOrderId(), e.getMessage());
+//             }
+//         }
+//     }
+// }

+ 12 - 12
src/main/java/com/sqx/modules/pay/controller/CashController.java

@@ -11,13 +11,13 @@ import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
 import com.alipay.api.request.AlipayFundTransUniTransferRequest;
 import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
 import com.alipay.api.response.AlipayFundTransUniTransferResponse;
+import com.sqx.common.constant.RedisKey;
 import com.sqx.common.utils.PageUtils;
 import com.sqx.common.utils.Result;
 import com.sqx.modules.app.dao.UserCashOutDao;
 import com.sqx.modules.app.entity.UserEntity;
 import com.sqx.modules.app.entity.UserMoneyDetails;
 import com.sqx.modules.app.service.UserMoneyDetailsService;
-import com.sqx.modules.app.service.UserMoneyService;
 import com.sqx.modules.app.service.UserService;
 import com.sqx.modules.common.entity.CommonInfo;
 import com.sqx.modules.common.service.CommonInfoService;
@@ -25,7 +25,6 @@ import com.sqx.modules.message.entity.MessageInfo;
 import com.sqx.modules.message.service.MessageService;
 import com.sqx.modules.pay.config.AliPayConstants;
 import com.sqx.modules.pay.controller.query.CashOutQueryDTO;
-import com.sqx.modules.pay.dao.CashOutDao;
 import com.sqx.modules.pay.entity.AliPayWithdrawModel;
 import com.sqx.modules.pay.entity.CashOut;
 import com.sqx.modules.pay.service.CashOutService;
@@ -44,6 +43,8 @@ import lombok.extern.slf4j.Slf4j;
 import lombok.val;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.exception.ExceptionUtils;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -52,6 +53,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
@@ -59,7 +61,6 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
  * @author fang
@@ -89,11 +90,9 @@ public class CashController {
     private MessageService messageService;
     @Autowired
     private UserCashOutDao userCashOutDao;
-    @Autowired
-    private CashOutDao cashOutDao;
-    @Autowired
-    private UserMoneyService userMoneyService;
-    private ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(true);
+
+    @Resource
+    private RedissonClient redissonClient;
 
     @RequestMapping(value = "/sendMsgByUserId", method = RequestMethod.GET)
     @ApiOperation("管理平台主动推送消息(指定用户)")
@@ -307,7 +306,8 @@ public class CashController {
     }
 
     private Result wxPay(CashOut one){
-        reentrantReadWriteLock.writeLock().lock();
+        RLock lock = redissonClient.getLock(String.format(RedisKey.CASH_OUT_LOCK, one.getUserId()));
+        lock.lock();
         try{
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
             UserEntity userEntity = userService.getById(one.getUserId());
@@ -397,7 +397,7 @@ public class CashController {
             e.printStackTrace();
             log.error("转账出错了!!!"+e.getMessage(),e);
         }finally {
-            reentrantReadWriteLock.writeLock().unlock();
+            lock.unlock();
         }
         return Result.error("转账失败!");
     }
@@ -405,7 +405,7 @@ public class CashController {
 
 
     private Result aliPay(CashOut one) {
-        reentrantReadWriteLock.writeLock().lock();
+        RLock lock = redissonClient.getLock(String.format(RedisKey.CASH_OUT_LOCK, one.getUserId()));
         try {
             log.error("进来了!!!");
             if (one == null) {
@@ -545,7 +545,7 @@ public class CashController {
             e.printStackTrace();
             log.error("转账异常"+e.getMessage());
         }finally {
-            reentrantReadWriteLock.writeLock().unlock();
+            lock.unlock();
         }
         return Result.error("系统繁忙,请稍后再试!");
     }

+ 10 - 14
src/main/java/com/sqx/modules/pay/service/impl/CashOutServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sqx.common.constant.RedisKey;
 import com.sqx.common.exception.SqxException;
 import com.sqx.common.utils.PageUtils;
 import com.sqx.common.utils.Result;
@@ -15,7 +16,6 @@ import com.sqx.modules.app.entity.UserEntity;
 import com.sqx.modules.app.entity.UserMoney;
 import com.sqx.modules.app.entity.UserMoneyDetails;
 import com.sqx.modules.app.service.UserMoneyDetailsService;
-import com.sqx.modules.app.service.UserMoneyService;
 import com.sqx.modules.app.service.UserService;
 import com.sqx.modules.common.entity.CommonInfo;
 import com.sqx.modules.common.service.CommonInfoService;
@@ -32,10 +32,11 @@ import com.sqx.modules.pay.service.CashOutService;
 import com.sqx.modules.pay.vo.CashOutVO;
 import com.sqx.modules.shop.entity.ShopBankCardInfo;
 import com.sqx.modules.shop.service.ShopBankCardInfoService;
-import com.sqx.modules.sys.dao.SysUserDao;
 import com.sqx.modules.utils.AmountCalUtils;
 import com.sqx.modules.utils.excel.ExcelData;
 import org.apache.commons.lang.StringUtils;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -54,7 +55,6 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.stream.Collectors;
 
 /**
@@ -95,14 +95,13 @@ public class CashOutServiceImpl extends ServiceImpl<CashOutDao, CashOut> impleme
     @Autowired
     private ErrandComplaintDao complaintDao;
     @Autowired
-    private SysUserDao sysUserDao;
-    @Autowired
     private UserMoneyDetailsService userMoneyDetailsService;
     @Autowired
-    private UserMoneyService userMoneyService;
-    @Autowired
     private ShopBankCardInfoService shopBankCardInfoService;
-    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(true);
+    @Autowired
+    private RedissonClient redissonClient;
+
+
 
     @Override
     public PageUtils selectCashOutList(CashOutQueryDTO queryDTO) {
@@ -275,15 +274,12 @@ public class CashOutServiceImpl extends ServiceImpl<CashOutDao, CashOut> impleme
 
     @Override
     public Result cashMoney(Long userId, Long shopId, Double money, Integer classify, Integer type) {
-        reentrantReadWriteLock.writeLock().lock();
+        RLock lock = redissonClient.getLock(String.format(RedisKey.CASH_OUT_LOCK, userId));
+        lock.lock();
         try {
             return cashMoneys(userId, shopId, money, classify, type);
-        } catch (Exception e) {
-            e.printStackTrace();
-            log.error("发起提现出错!" + e.getMessage(), e);
-            throw new SqxException(e.getMessage());
         } finally {
-            reentrantReadWriteLock.writeLock().unlock();
+            lock.unlock();
         }
     }
 

+ 15 - 16
src/main/java/com/sqx/modules/pay/service/impl/WxServiceImpl.java

@@ -5,7 +5,7 @@ import com.alibaba.fastjson.JSONObject;
 import com.github.wxpay.sdk.WXPay;
 import com.github.wxpay.sdk.WXPayConstants;
 import com.github.wxpay.sdk.WXPayUtil;
-import com.sqx.common.exception.SqxException;
+import com.sqx.common.constant.RedisKey;
 import com.sqx.common.utils.Result;
 import com.sqx.modules.app.dao.UserDao;
 import com.sqx.modules.app.dao.UserMoneyDetailsDao;
@@ -35,17 +35,19 @@ import com.sqx.modules.utils.AmountCalUtils;
 import com.sqx.modules.utils.MD5Util;
 import com.sqx.modules.utils.WXConfigUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
  * @author fang
@@ -89,19 +91,19 @@ public class WxServiceImpl implements WxService {
     @Autowired
     private UserMoneyDetailsService userMoneyDetailsService;
 
-    private ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(true);
-
     private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
+    @Resource
+    private RedissonClient redissonClient;
+
     @Override
     public Result balanceOrder(Long userId, PayOrderDTO payOrderDTO) {
-        reentrantReadWriteLock.writeLock().lock();
+        RLock lock = redissonClient.getLock(String.format(RedisKey.PAY_ORDER_LOCK, payOrderDTO.getParentId()));
+        lock.lock();
         try{
             return balanceOrders(userId, payOrderDTO);
-        } catch (Exception e){
-            throw new SqxException(e.getMessage());
         } finally {
-            reentrantReadWriteLock.writeLock().unlock();
+            lock.unlock();
         }
     }
 
@@ -144,16 +146,13 @@ public class WxServiceImpl implements WxService {
 
     @Override
     public Result balanceBuyVip(Long userId) {
-        reentrantReadWriteLock.writeLock().lock();
-        try{
+        RLock lock = redissonClient.getLock(String.format(RedisKey.USER_BUY_VIP_LOCK, userId));
+        lock.lock();
+        try {
             return balanceBuyVips(userId);
-        }catch (Exception e){
-            e.printStackTrace();
-            log.error("下单异常:"+e.getMessage(),e);
-        }finally {
-            reentrantReadWriteLock.writeLock().unlock();
+        } finally {
+            lock.unlock();
         }
-        return Result.error("系统繁忙,请稍后再试!");
     }
 
     @Override

+ 12 - 10
src/main/java/com/sqx/modules/shop/service/impl/ShopMessageServiceImpl.java

@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sqx.common.constant.RedisKey;
 import com.sqx.common.exception.SqxException;
 import com.sqx.common.utils.Constant;
 import com.sqx.common.utils.PageUtils;
@@ -49,17 +50,19 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.RandomStringUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.shiro.crypto.hash.Sha256Hash;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 @Slf4j
 @Service
@@ -99,7 +102,9 @@ public class ShopMessageServiceImpl extends ServiceImpl<ShopMessageDao, GoodsSho
     private UserService userService;
     @Autowired
     private AppOrderDao appOrderDao;
-    private ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(true);
+
+    @Resource
+    private RedissonClient redissonClient;
 
     @Transactional
     @Override
@@ -128,16 +133,13 @@ public class ShopMessageServiceImpl extends ServiceImpl<ShopMessageDao, GoodsSho
 
     @Override
     public Result auditShopAuthentication(Long shopId, ShopAuditDTO dto) {
-        reentrantReadWriteLock.writeLock().lock();
-        try{
+        RLock lock = redissonClient.getLock(String.format(RedisKey.SHOP_AUTHENTICATION_LOCK, shopId));
+        lock.lock();
+        try {
             return auditAuthentication(shopId, dto);
-        }catch (Exception e){
-            e.printStackTrace();
-            log.error("操作异常:"+e.getMessage(),e);
-        }finally {
-            reentrantReadWriteLock.writeLock().unlock();
+        } finally {
+            lock.unlock();
         }
-        return Result.error("系统繁忙,请稍后再试!");
     }
 
     @Transactional

+ 65 - 65
src/main/java/com/sqx/modules/timedtask/controller/AutoSendOrder.java

@@ -62,71 +62,71 @@ public class AutoSendOrder {
     @Autowired
     private PayDetailsDao payDetailsDao;
 
-    //定时自动给骑手推单
-    @Scheduled(cron = "0 * * * * ?", zone = "Asia/Shanghai")
-    public void autoSendOrder(){
-        CommonInfo three = commonInfoService.findOne(304);
-        if("是".equals(three.getValue())){
-            //查看所有支付以后两分钟后的订单(排除同城服务订单)
-            CommonInfo two = commonInfoService.findOne(302);
-            CommonInfo one = commonInfoService.findOne(303);
-            CommonInfo four = commonInfoService.findOne(273);
-            CommonInfo five = commonInfoService.findOne(310);
-            Integer maxNum = Integer.parseInt(commonInfoService.findOne(342).getValue());
-            Double cashDeposit = Double.valueOf(four.getValue());
-            Double distance = Double.valueOf(one.getValue());
-            String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
-            String date = getCurrentTime(Integer.valueOf(two.getValue()));
-            List<TbIndent> tbIndents = tbIndentDao.selectSendOrder(date);
-            //遍历这些订单,查出距离这些订单最近的骑手(骑手需要没有接单,且在订单位置xx米内)
-            for(int i = 0;i<tbIndents.size();i++){
-                GoodsShop goodsShop = goodsShopDao.selectById(tbIndents.get(i).getShopId());
-                    try{
-                        if("3".equals(tbIndents.get(i).getIndentType())&&"0".equals(tbIndents.get(i).getBuyType())){
-                            //没有起点位置,只有终点位置。通过终点位置查距离内最近的骑手
-                            Long userId = tbIndentDao.selectRiderByDictance(tbIndents.get(i).getUserLng(), tbIndents.get(i).getUserLat(),
-                                    distance,cashDeposit,maxNum);
-                            if(userId!=null){
-                                tbIndentDao.indentReceiv(userId, tbIndents.get(i).getIndentNumber(), format,"4");
-                                //自动推单以后,消息通知骑手
-                                UserEntity userEntity = userDao.selectById(userId);
-                                List<String> msgList=new ArrayList<>();
-                                msgList.add("接单项目");
-                                msgList.add(userEntity.getNickName());
-                                msgList.add(format);
-                                msgList.add("系统自动推单");
-                                SenInfoCheckUtil.sendRiderMsg(userEntity.getRiderOpenId(),five.getValue(),msgList,4);
-                                userService.pushToSingleRider("系统自动推单", "系统已为您自动派单,请及时前往派送!", userEntity.getRiderClientid());
-                                userService.sendMsgDXB(userEntity.getPhone(), "autosend", 0);
-                            }
-                        }else {
-                            if(goodsShop!=null&&goodsShop.getAutoSendOrder()!=null&&goodsShop.getAutoSendOrder()==0){
-                                //有起点位置,通过起点位置查距离内最近的骑手
-                                Long userId = tbIndentDao.selectRiderByDictance(tbIndents.get(i).getShopLng(), tbIndents.get(i).getShopLat(),
-                                        distance, cashDeposit,maxNum);
-                                if(userId!=null){
-                                    tbIndentDao.indentReceiv(userId, tbIndents.get(i).getIndentNumber(), format,"3");
-                         //           tbIndentDao.indentReceiving(userId, tbIndents.get(i).getIndentNumber(), format);
-                                    //自动推单以后,消息通知骑手
-                                    UserEntity userEntity = userDao.selectById(userId);
-                                    List<String> msgList=new ArrayList<>();
-                                    msgList.add("接单项目");
-                                    msgList.add(userEntity.getNickName());
-                                    msgList.add(format);
-                                    msgList.add("系统自动推单");
-                                    SenInfoCheckUtil.sendRiderMsg(userEntity.getRiderOpenId(),five.getValue(),msgList,4);
-                                    userService.pushToSingleRider("系统自动推单", "系统已为您自动派单,请及时前往派送!", userEntity.getRiderClientid());
-                                    userService.sendMsgDXB(userEntity.getPhone(), "autosend", 0);
-                                }
-                            }
-                        }
-                    }catch (Exception e){
-                        e.printStackTrace();
-                        log.error("定时任务自动退单异常,异常订单id:"+tbIndents.get(i).getIndentId()+",异常:"+e.getMessage(),e);
-                    }
-                }
-            }
-    }
+    // //定时自动给骑手推单
+    // @Scheduled(cron = "0 * * * * ?", zone = "Asia/Shanghai")
+    // public void autoSendOrder(){
+    //     CommonInfo three = commonInfoService.findOne(304);
+    //     if("是".equals(three.getValue())){
+    //         //查看所有支付以后两分钟后的订单(排除同城服务订单)
+    //         CommonInfo two = commonInfoService.findOne(302);
+    //         CommonInfo one = commonInfoService.findOne(303);
+    //         CommonInfo four = commonInfoService.findOne(273);
+    //         CommonInfo five = commonInfoService.findOne(310);
+    //         Integer maxNum = Integer.parseInt(commonInfoService.findOne(342).getValue());
+    //         Double cashDeposit = Double.valueOf(four.getValue());
+    //         Double distance = Double.valueOf(one.getValue());
+    //         String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
+    //         String date = getCurrentTime(Integer.valueOf(two.getValue()));
+    //         List<TbIndent> tbIndents = tbIndentDao.selectSendOrder(date);
+    //         //遍历这些订单,查出距离这些订单最近的骑手(骑手需要没有接单,且在订单位置xx米内)
+    //         for(int i = 0;i<tbIndents.size();i++){
+    //             GoodsShop goodsShop = goodsShopDao.selectById(tbIndents.get(i).getShopId());
+    //                 try{
+    //                     if("3".equals(tbIndents.get(i).getIndentType())&&"0".equals(tbIndents.get(i).getBuyType())){
+    //                         //没有起点位置,只有终点位置。通过终点位置查距离内最近的骑手
+    //                         Long userId = tbIndentDao.selectRiderByDictance(tbIndents.get(i).getUserLng(), tbIndents.get(i).getUserLat(),
+    //                                 distance,cashDeposit,maxNum);
+    //                         if(userId!=null){
+    //                             tbIndentDao.indentReceiv(userId, tbIndents.get(i).getIndentNumber(), format,"4");
+    //                             //自动推单以后,消息通知骑手
+    //                             UserEntity userEntity = userDao.selectById(userId);
+    //                             List<String> msgList=new ArrayList<>();
+    //                             msgList.add("接单项目");
+    //                             msgList.add(userEntity.getNickName());
+    //                             msgList.add(format);
+    //                             msgList.add("系统自动推单");
+    //                             SenInfoCheckUtil.sendRiderMsg(userEntity.getRiderOpenId(),five.getValue(),msgList,4);
+    //                             userService.pushToSingleRider("系统自动推单", "系统已为您自动派单,请及时前往派送!", userEntity.getRiderClientid());
+    //                             userService.sendMsgDXB(userEntity.getPhone(), "autosend", 0);
+    //                         }
+    //                     }else {
+    //                         if(goodsShop!=null&&goodsShop.getAutoSendOrder()!=null&&goodsShop.getAutoSendOrder()==0){
+    //                             //有起点位置,通过起点位置查距离内最近的骑手
+    //                             Long userId = tbIndentDao.selectRiderByDictance(tbIndents.get(i).getShopLng(), tbIndents.get(i).getShopLat(),
+    //                                     distance, cashDeposit,maxNum);
+    //                             if(userId!=null){
+    //                                 tbIndentDao.indentReceiv(userId, tbIndents.get(i).getIndentNumber(), format,"3");
+    //                      //           tbIndentDao.indentReceiving(userId, tbIndents.get(i).getIndentNumber(), format);
+    //                                 //自动推单以后,消息通知骑手
+    //                                 UserEntity userEntity = userDao.selectById(userId);
+    //                                 List<String> msgList=new ArrayList<>();
+    //                                 msgList.add("接单项目");
+    //                                 msgList.add(userEntity.getNickName());
+    //                                 msgList.add(format);
+    //                                 msgList.add("系统自动推单");
+    //                                 SenInfoCheckUtil.sendRiderMsg(userEntity.getRiderOpenId(),five.getValue(),msgList,4);
+    //                                 userService.pushToSingleRider("系统自动推单", "系统已为您自动派单,请及时前往派送!", userEntity.getRiderClientid());
+    //                                 userService.sendMsgDXB(userEntity.getPhone(), "autosend", 0);
+    //                             }
+    //                         }
+    //                     }
+    //                 }catch (Exception e){
+    //                     e.printStackTrace();
+    //                     log.error("定时任务自动退单异常,异常订单id:"+tbIndents.get(i).getIndentId()+",异常:"+e.getMessage(),e);
+    //                 }
+    //             }
+    //         }
+    // }
 
     //定时取消商家长时间未接单的订单
  //   @Scheduled(cron = "0 * * * * ?", zone = "Asia/Shanghai")

+ 18 - 0
src/main/java/com/sqx/scheduler/config/ScheduledConfig.java

@@ -0,0 +1,18 @@
+package com.sqx.scheduler.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+/**
+ * 调度配置
+ *
+ * @auther: codingliang
+ * @date: 2023/5/19 23:15
+ * @description: 调度配置
+ */
+@EnableAsync
+@EnableScheduling
+@Configuration
+public class ScheduledConfig {
+}

+ 35 - 0
src/main/java/com/sqx/scheduler/config/SchedulerLock.java

@@ -0,0 +1,35 @@
+package com.sqx.scheduler.config;
+
+/**
+ * 锁
+ *
+ * @author : codingliang
+ * @date : 2024-09-09 10:08
+ */
+public interface SchedulerLock {
+
+    /**
+     * 预约订单自动接单锁
+     */
+    String ORDER_OF_RESERVATION_AUTO_RECEIVING_LOCK = "wm:lock:order:reservation:auto-receiving";
+
+    /**
+     * 制作中订单自动完成锁
+     */
+    String ORDER_OF_PROD_AUTO_COMPLETED_LOCK = "wm:lock:order:make:auto-prod-completed";
+
+    /**
+     * 待收货订单自动完成锁
+     */
+    String ORDER_OF_WAIT_DELIVERY_AUTO_FINISH_LOCK = "wm:lock:order:wait-delivery:auto-finish";
+
+    /**
+     * 用户优惠券自动过期锁
+     */
+    String COUPON_OF_USER_EXPIRATION_LOCK = "wm:lock:coupon:exp";
+
+    /**
+     * 跑腿订单自动推送锁
+     */
+    String INDENT_AUTO_PUSH_LOCK = "wm:lock:indent:push";
+}

+ 48 - 0
src/main/java/com/sqx/scheduler/coupon/CouponScheduler.java

@@ -0,0 +1,48 @@
+package com.sqx.scheduler.coupon;
+
+import com.sqx.modules.coupon.service.TbCouponService;
+import com.sqx.modules.coupon.service.TbCouponUserService;
+import com.sqx.scheduler.config.SchedulerLock;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+/**
+ * 优惠券定时任务
+ *
+ * @author : codingliang
+ * @date : 2024-09-09 12:22
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class CouponScheduler {
+
+    private final TbCouponUserService tbCouponUserService;
+    private final RedissonClient redissonClient;
+
+    /**
+     * 将所有超过失效时间的优惠券改为失效状态
+     * 每分钟运行一次
+     */
+    @Async
+    @Scheduled(cron = "0 */1 * * * ?", zone = "Asia/Shanghai")
+    public void couponEnd(){
+        RLock lock = redissonClient.getLock(SchedulerLock.COUPON_OF_USER_EXPIRATION_LOCK);
+        lock.lock();
+        try {
+            log.info("用户优惠券自动过期任务运行");
+            tbCouponUserService.updateExpiration();
+            log.info("用户优惠券自动过期任务运行成功");
+        } catch (Exception e) {
+            log.error("用户优惠券自动过期任务运行失败,【{}】", e);
+        } finally {
+            lock.unlock();
+        }
+
+    }
+}

+ 135 - 0
src/main/java/com/sqx/scheduler/indent/IndentScheduler.java

@@ -0,0 +1,135 @@
+package com.sqx.scheduler.indent;
+
+import com.sqx.modules.app.dao.UserDao;
+import com.sqx.modules.app.entity.UserEntity;
+import com.sqx.modules.app.service.UserService;
+import com.sqx.modules.common.entity.CommonInfo;
+import com.sqx.modules.common.service.CommonInfoService;
+import com.sqx.modules.errand.dao.TbIndentDao;
+import com.sqx.modules.errand.entity.TbIndent;
+import com.sqx.modules.goods.dao.GoodsShopDao;
+import com.sqx.modules.goods.entity.GoodsShop;
+import com.sqx.modules.utils.SenInfoCheckUtil;
+import com.sqx.scheduler.config.SchedulerLock;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 跑腿订单定时任务
+ *
+ * @author : codingliang
+ * @date : 2024-09-09 12:28
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class IndentScheduler {
+
+    private final CommonInfoService commonInfoService;
+    private final TbIndentDao tbIndentDao;
+    private final GoodsShopDao goodsShopDao;
+    private final UserService userService;
+    private final UserDao userDao;
+
+    private final RedissonClient redissonClient;
+
+    /**
+     * 定时自动给骑手推单
+     * 每分钟运行一次
+     */
+    @Async
+    @Scheduled(cron = "0 * * * * ?", zone = "Asia/Shanghai")
+    public void autoSendOrder(){
+        RLock lock = redissonClient.getLock(SchedulerLock.INDENT_AUTO_PUSH_LOCK);
+        lock.lock();
+        try {
+            log.info("自动给骑手推单任务开始运行");
+            CommonInfo three = commonInfoService.findOne(304);
+            if("是".equals(three.getValue())){
+                //查看所有支付以后两分钟后的订单(排除同城服务订单)
+                CommonInfo two = commonInfoService.findOne(302);
+                CommonInfo one = commonInfoService.findOne(303);
+                CommonInfo four = commonInfoService.findOne(273);
+                CommonInfo five = commonInfoService.findOne(310);
+                Integer maxNum = Integer.parseInt(commonInfoService.findOne(342).getValue());
+                Double cashDeposit = Double.valueOf(four.getValue());
+                Double distance = Double.valueOf(one.getValue());
+                String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
+                String date = getCurrentTime(Integer.valueOf(two.getValue()));
+                List<TbIndent> tbIndents = tbIndentDao.selectSendOrder(date);
+                //遍历这些订单,查出距离这些订单最近的骑手(骑手需要没有接单,且在订单位置xx米内)
+                for(int i = 0;i<tbIndents.size();i++){
+                    GoodsShop goodsShop = goodsShopDao.selectById(tbIndents.get(i).getShopId());
+                    try{
+                        if("3".equals(tbIndents.get(i).getIndentType())&&"0".equals(tbIndents.get(i).getBuyType())){
+                            //没有起点位置,只有终点位置。通过终点位置查距离内最近的骑手
+                            Long userId = tbIndentDao.selectRiderByDictance(tbIndents.get(i).getUserLng(), tbIndents.get(i).getUserLat(),
+                                    distance,cashDeposit,maxNum);
+                            if(userId!=null){
+                                tbIndentDao.indentReceiv(userId, tbIndents.get(i).getIndentNumber(), format,"4");
+                                //自动推单以后,消息通知骑手
+                                UserEntity userEntity = userDao.selectById(userId);
+                                List<String> msgList=new ArrayList<>();
+                                msgList.add("接单项目");
+                                msgList.add(userEntity.getNickName());
+                                msgList.add(format);
+                                msgList.add("系统自动推单");
+                                SenInfoCheckUtil.sendRiderMsg(userEntity.getRiderOpenId(),five.getValue(),msgList,4);
+                                userService.pushToSingleRider("系统自动推单", "系统已为您自动派单,请及时前往派送!", userEntity.getRiderClientid());
+                                userService.sendMsgDXB(userEntity.getPhone(), "autosend", 0);
+                            }
+                        }else {
+                            if(goodsShop!=null&&goodsShop.getAutoSendOrder()!=null&&goodsShop.getAutoSendOrder()==0){
+                                //有起点位置,通过起点位置查距离内最近的骑手
+                                Long userId = tbIndentDao.selectRiderByDictance(tbIndents.get(i).getShopLng(), tbIndents.get(i).getShopLat(),
+                                        distance, cashDeposit,maxNum);
+                                if(userId!=null){
+                                    tbIndentDao.indentReceiv(userId, tbIndents.get(i).getIndentNumber(), format,"3");
+                                    //           tbIndentDao.indentReceiving(userId, tbIndents.get(i).getIndentNumber(), format);
+                                    //自动推单以后,消息通知骑手
+                                    UserEntity userEntity = userDao.selectById(userId);
+                                    List<String> msgList=new ArrayList<>();
+                                    msgList.add("接单项目");
+                                    msgList.add(userEntity.getNickName());
+                                    msgList.add(format);
+                                    msgList.add("系统自动推单");
+                                    SenInfoCheckUtil.sendRiderMsg(userEntity.getRiderOpenId(),five.getValue(),msgList,4);
+                                    userService.pushToSingleRider("系统自动推单", "系统已为您自动派单,请及时前往派送!", userEntity.getRiderClientid());
+                                    userService.sendMsgDXB(userEntity.getPhone(), "autosend", 0);
+                                }
+                            }
+                        }
+                    } catch (Exception e){
+                        e.printStackTrace();
+                        log.error("定时任务自动退单异常,异常订单id:"+tbIndents.get(i).getIndentId()+",异常:"+e.getMessage(),e);
+                    }
+                }
+            }
+            log.info("自动给骑手推单任务运行成功");
+        } catch (Exception e) {
+            log.error("自动给骑手推单任务开始运行失败,【{}】", e);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    private String getCurrentTime(int i){
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Calendar beforeTime = Calendar.getInstance();
+        beforeTime.add(Calendar.MINUTE, -i);
+        Date beforeD = beforeTime.getTime();
+        String time = sdf.format(beforeD);
+        return time;
+    }
+}

+ 160 - 0
src/main/java/com/sqx/scheduler/order/OrderScheduler.java

@@ -0,0 +1,160 @@
+package com.sqx.scheduler.order;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.sqx.modules.common.entity.CommonInfo;
+import com.sqx.modules.common.service.CommonInfoService;
+import com.sqx.modules.order.entity.TbOrder;
+import com.sqx.modules.order.service.AppOrderService;
+import com.sqx.scheduler.config.SchedulerLock;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 订单定时任务
+ *
+ * @author : codingliang
+ * @date : 2024-08-19 20:42
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class OrderScheduler {
+
+    private final RedissonClient redissonClient;
+    private final AppOrderService orderService;
+    private final CommonInfoService commonInfoService;
+
+    /**
+     * 预约订单自动接单
+     * 5分钟运行一次
+     */
+    @Async
+    @Scheduled(cron = "0 */5 * * * ?")
+    public void reservationAutoReceivingOrder() {
+        RLock lock = redissonClient.getLock(SchedulerLock.ORDER_OF_RESERVATION_AUTO_RECEIVING_LOCK);
+        lock.lock();
+        try {
+            log.info("预约订单自动接单任务开始运行");
+            List<Long> orderIds = orderService.getCurWaitReceivingOrderIds();
+            if (CollUtil.isEmpty(orderIds)) {
+                log.info("没有符合条件的预约订单,预约订单自动接单任务运行....");
+                return;
+            }
+
+            List<TbOrder> waitOrders = orderIds.stream().map(orderId -> {
+                TbOrder waitOrder = new TbOrder();
+                waitOrder.setOrderId(orderId);
+                waitOrder.setStatus(6);
+
+                return waitOrder;
+            }).collect(Collectors.toList());
+
+            for (TbOrder waitOrder : waitOrders) {
+                log.info("预约订单id:{},正在自动接单", waitOrder.getOrderId());
+                try {
+                    orderService.updateOrder(waitOrder);
+                    log.info("预约订单id:{},自动接单成功", waitOrder.getOrderId());
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    log.error("预约单id:{},自动接单失败,失败原因:{}", waitOrder.getOrderId(), e.getMessage());
+                }
+            }
+
+            log.info("预约订单自动接单任务运行成功");
+        } catch (Exception e) {
+            log.error("预约订单自动接单任务运行失败失败原因:{}", e.getMessage());
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * 制作中订单自动制作完成
+     * 每分钟30秒时运行一次
+     */
+    @Async
+    @Scheduled(cron = "30 */1 * * * ?")
+    public void prodIngOrderAutoCompleted(){
+        RLock lock = redissonClient.getLock(SchedulerLock.ORDER_OF_PROD_AUTO_COMPLETED_LOCK);
+        lock.lock();
+        try {
+            log.info("自动制作完成制作中订单任务开始运行");
+            // 获取配置:是否开启制作中订单自动完成
+            String value = commonInfoService.findOne(418).getValue();
+            if("是".equals(value)){
+                String minute = commonInfoService.findOne(419).getValue();
+                LocalDateTime minusMinutes = LocalDateTime.now().minusMinutes(Long.valueOf(minute));
+
+                // 获取制作中状态的订单列表
+                List<TbOrder> orders = orderService.getProdIngOrders(minusMinutes);
+                if (CollUtil.isEmpty(orders)) {
+                    log.info("当前时间段没有需要自动制作完成的订单");
+                } else {
+                    for (TbOrder order: orders){
+                        try {
+                            log.info("订单:{},开始自动制作完成", order.getOrderId());
+                            order.setStatus(3);
+                            orderService.updateOrder(order);
+                            log.info("订单:{},自动制作完成", order.getOrderId());
+                        } catch (Exception e){
+                            e.printStackTrace();
+                            log.error("订单:{},自动完成异常,异常原因:【{}】", order.getOrderId(), e);
+                        }
+                    }
+                }
+            }
+            log.info("自动制作完成制作中订单任务运行成功");
+        } catch (Exception e) {
+            log.error("制作中订单自动制作完成任务运行失败失败原因:【{}】", e);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * 自动完成订单
+     * 每30s运行一次
+     */
+    @Async
+    @Scheduled(cron = "45 */1 * * * ?")
+    public void autoFinishOrder() {
+        RLock lock = redissonClient.getLock(SchedulerLock.ORDER_OF_WAIT_DELIVERY_AUTO_FINISH_LOCK);
+        lock.lock();
+        try {
+            log.info("自动完成订单任务开始运行");
+            CommonInfo one = commonInfoService.findOne(268);
+            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+            // 查询所有 待取餐/派送中 状态的订单
+            QueryWrapper<TbOrder> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("status", 3);
+            List<TbOrder> orders = orderService.list(queryWrapper);
+
+            for (TbOrder order: orders) {
+                LocalDateTime updateTime = LocalDateTime.parse(order.getUpdateTime(), df);
+                // 计算当前订单什么时候超时完成
+                LocalDateTime overDateTime = updateTime.plusHours(Integer.parseInt(one.getValue()));
+                if (LocalDateTime.now().isAfter(overDateTime)) {
+                    log.info("订单id:{},开始自动完成", order.getOrderId());
+                    orderService.accomplishOrders(order.getOrderId(),2);
+                    log.info("订单id:{},完成自动完成", order.getOrderId());
+                }
+            }
+            log.info("自动完成订单任务运行成功");
+        } catch (Exception e) {
+            log.info("自动完成订单任务运行异常,异常", e);
+        } finally {
+            lock.unlock();
+        }
+    }
+}

+ 13 - 0
src/main/resources/application-dev.yml

@@ -32,6 +32,19 @@ spring:
                 wall:
                     config:
                         multi-statement-allow: true
+    redis:
+        host: 103.131.169.54
+        port: 6379
+        password: dev@redis@1234
+        database: 3
+        timeout: 5000
+        lettuce:
+            shutdown-timeout: 100
+            pool:
+                max-active: 3
+                min-idle: 2
+                max-idle: 3
+                max-wait: -1
 secure-api:
     # 开启SecureApi功能,如果为false则其余配置项均不生效
     enabled: true