From 18f302b43b7fb64dbf1d986ab3b3ccc1e5f3297f Mon Sep 17 00:00:00 2001 From: liyj <1617420630@qq.com> Date: Fri, 19 Sep 2025 16:03:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=B0=8F=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=AE=A2=E9=98=85=E6=A8=A1=E6=9D=BF=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=9B=9E=E8=B0=83=E5=92=8C=E6=89=B9=E6=AC=A1=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/AccountController.java | 13 +++ .../controller/mobile/WeiXinController.java | 25 ++++- .../AccountUserBindConnectService.java | 9 +- .../AccountUserBindConnectServiceImpl.java | 59 ++++++++++- .../common/feignService/AccountService.java | 10 ++ .../account/AccountUserBindConnect.java | 3 + .../quartz/job/XcxSubSendMessageJob.java | 26 +++++ .../admin/ShopMessageTemplateController.java | 12 ++- .../service/ShopMessageTemplateService.java | 2 + .../impl/ShopMessageTemplateServiceImpl.java | 100 +++++++++++++++--- mall-shop/src/main/resources/application.yml | 3 +- sql/shop/dev/20250919_dml.sql | 1 + 12 files changed, 235 insertions(+), 28 deletions(-) create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/components/quartz/job/XcxSubSendMessageJob.java create mode 100644 sql/shop/dev/20250919_dml.sql diff --git a/mall-account/src/main/java/com/suisung/mall/account/controller/admin/AccountController.java b/mall-account/src/main/java/com/suisung/mall/account/controller/admin/AccountController.java index 0355e1c6..4636e6b1 100644 --- a/mall-account/src/main/java/com/suisung/mall/account/controller/admin/AccountController.java +++ b/mall-account/src/main/java/com/suisung/mall/account/controller/admin/AccountController.java @@ -477,5 +477,18 @@ public class AccountController { return accountUserBaseService.getOne(queryWrapper); } + @RequestMapping(value = "/getAllBindPage", method = RequestMethod.GET) + public List getAllBindPage(@RequestParam(name = "bind_type") Integer bind_type, + @RequestParam(name = "bindTmpl") String bindTmpl, + @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) { + return accountUserBindConnectService.getAllBindPage(bind_type,bindTmpl,pageNum,pageSize); + } + + @RequestMapping(value = "/getAllBindCount", method = RequestMethod.GET) + public long getAllBindCount(@RequestParam(name = "bind_type") Integer bind_type, + @RequestParam(name = "bindTmpl") String bindTmpl) { + return accountUserBindConnectService.getAllBindCount(bind_type,bindTmpl); + } } diff --git a/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/WeiXinController.java b/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/WeiXinController.java index 21715055..0c7bb886 100644 --- a/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/WeiXinController.java +++ b/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/WeiXinController.java @@ -1,5 +1,7 @@ package com.suisung.mall.account.controller.mobile; +import cn.hutool.json.JSONObject; +import com.suisung.mall.account.service.AccountUserBindConnectService; import com.suisung.mall.account.service.WeiXinService; import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.service.impl.BaseControllerImpl; @@ -7,10 +9,7 @@ import com.suisung.mall.common.utils.I18nUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -24,6 +23,9 @@ public class WeiXinController extends BaseControllerImpl { @Autowired private WeiXinService weiXinService; + @Autowired + private AccountUserBindConnectService accountUserBindConnectService; + /** *
      * 验证推送过来的消息的正确性
@@ -138,4 +140,19 @@ public class WeiXinController extends BaseControllerImpl {
         weiXinService.callbackPc(code, response);
     }
 
+
+    @ApiOperation(value = "小程序回调", notes = "小程序回调")
+    @RequestMapping(value = "/xcxCallBack")
+    public CommonResult xcxCallBack(@RequestBody JSONObject jsonObject,
+                                    @RequestParam("signature") String signature,
+                                    @RequestParam("timestamp") String timestamp,
+                                    @RequestParam("nonce") String nonce) {
+        boolean checked=weiXinService.checkSignature(timestamp, nonce, signature);
+        if(!checked){
+            return CommonResult.failed("校验失败");
+        }
+        accountUserBindConnectService.bindTmplId(jsonObject);
+        return CommonResult.success("小程序订阅消息模板绑定成功");
+    }
+
 }
diff --git a/mall-account/src/main/java/com/suisung/mall/account/service/AccountUserBindConnectService.java b/mall-account/src/main/java/com/suisung/mall/account/service/AccountUserBindConnectService.java
index 245274b0..a9ed7198 100644
--- a/mall-account/src/main/java/com/suisung/mall/account/service/AccountUserBindConnectService.java
+++ b/mall-account/src/main/java/com/suisung/mall/account/service/AccountUserBindConnectService.java
@@ -1,9 +1,10 @@
 package com.suisung.mall.account.service;
 
+import cn.hutool.json.JSONObject;
 import com.suisung.mall.common.modules.account.AccountUserBindConnect;
 import com.suisung.mall.common.pojo.req.WxUserInfoReq;
 import com.suisung.mall.core.web.service.IBaseService;
-
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -87,4 +88,10 @@ public interface AccountUserBindConnectService extends IBaseService getAllBindPage(Integer bind_type,String bindTmpl,Integer pageNum, Integer pageSize);
+
+    long getAllBindCount(Integer bind_type,String bindTmpl);
+
+    boolean bindTmplId(JSONObject jsonObject);
 }
diff --git a/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBindConnectServiceImpl.java b/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBindConnectServiceImpl.java
index 065220fc..d4f73e64 100644
--- a/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBindConnectServiceImpl.java
+++ b/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBindConnectServiceImpl.java
@@ -3,6 +3,8 @@ package com.suisung.mall.account.service.impl;
 import cn.hutool.core.convert.Convert;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.suisung.mall.account.mapper.AccountUserBindConnectMapper;
 import com.suisung.mall.account.service.AccountUserBaseService;
@@ -25,10 +27,7 @@ import org.springframework.dao.DuplicateKeyException;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
+import java.util.*;
 
 
 /**
@@ -501,4 +500,56 @@ public class AccountUserBindConnectServiceImpl extends BaseServiceImpl getAllBindPage(Integer bind_type,String bindTmpl,Integer pageNum, Integer pageSize) {
+        QueryWrapper queryWrapper = new QueryWrapper<>();
+        queryWrapper.select("bind_id,bind_type,user_id,user_type");
+        queryWrapper.eq("bind_type", bind_type)
+                .eq("user_type", CommonConstant.USER_TYPE_NORMAL)
+                .eq("bind_active", CommonConstant.Enable)
+                .eq("bind_tmpl",bindTmpl)
+                .orderByAsc("bind_time");
+        return this.lists(queryWrapper,pageNum,pageSize).getRecords();
+    }
+
+    @Override
+    public long getAllBindCount(Integer bind_type,String bindTmpl) {
+        QueryWrapper queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("bind_type", bind_type)
+                .eq("user_type", CommonConstant.USER_TYPE_NORMAL)
+                .eq("bind_active", CommonConstant.Enable)
+                .eq("bind_tmpl",bindTmpl)
+                .orderByAsc("bind_time");
+        return this.count(queryWrapper);
+    }
+
+    @Override
+    public boolean bindTmplId(JSONObject jsonObject) {
+        if (jsonObject == null) {
+            return false;
+        }
+        String openId=jsonObject.getStr("FromUserName");//用户openid
+        QueryWrapper queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("bind_id",openId)
+                .eq("user_type", CommonConstant.USER_TYPE_NORMAL)
+                .eq("bind_type",15)
+                .eq("bind_active", CommonConstant.Enable);
+        AccountUserBindConnect accountUserBindConnect= findOne(queryWrapper);
+        if (accountUserBindConnect != null) {
+            JSONArray jsonArray= jsonObject.getJSONArray("List");
+            if (jsonArray != null) {
+                JSONObject object= (JSONObject) jsonArray.get(0);
+                String templateId= object.getStr("TemplateId");//模板id
+                String SubscribeStatusString= object.getStr("SubscribeStatusString");//订阅结果(accept接收;reject拒收)参考地址https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/subscribe-message.html#%E8%AE%A2%E9%98%85%E6%B6%88%E6%81%AF%E8%AF%AD%E9%9F%B3%E6%8F%90%E9%86%92
+                if(SubscribeStatusString.equals("accept")){
+                    accountUserBindConnect.setBind_tmpl(templateId);
+                    updateById(accountUserBindConnect);
+                }
+            }
+        }
+        return true;
+    }
+
+
 }
diff --git a/mall-common/src/main/java/com/suisung/mall/common/feignService/AccountService.java b/mall-common/src/main/java/com/suisung/mall/common/feignService/AccountService.java
index 1d5a32bb..80df3e97 100644
--- a/mall-common/src/main/java/com/suisung/mall/common/feignService/AccountService.java
+++ b/mall-common/src/main/java/com/suisung/mall/common/feignService/AccountService.java
@@ -294,4 +294,14 @@ public interface AccountService {
      */
     @PostMapping(value = "/admin/account/account-base-config/get/value")
     String getAccountBaseConfigValue(@RequestParam(name = "config_key") String config_key);
+
+
+    @GetMapping(value = "/admin/account/accountController/getAllBindPage")
+    List getAllBindPage(@RequestParam(name = "bind_type") Integer bind_type,
+                                                @RequestParam(name = "bindTmpl") String bindTmpl,
+                                                @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
+                                                @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize);
+
+    @GetMapping(value = "/admin/account/accountController/getAllBindCount")
+    long getAllBindCount(@RequestParam(name = "bind_type") Integer bind_type,@RequestParam(name = "bindTmpl") String bindTmpl);
 }
diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/account/AccountUserBindConnect.java b/mall-common/src/main/java/com/suisung/mall/common/modules/account/AccountUserBindConnect.java
index dd1d5caa..eac1027c 100644
--- a/mall-common/src/main/java/com/suisung/mall/common/modules/account/AccountUserBindConnect.java
+++ b/mall-common/src/main/java/com/suisung/mall/common/modules/account/AccountUserBindConnect.java
@@ -105,4 +105,7 @@ public class AccountUserBindConnect implements Serializable {
     @ApiModelProperty(value = "更新时间")
     private Date updated_at;
 
+    @ApiModelProperty(value = "允许通知的消息通知模板id")
+    private String bind_tmpl;
+
 }
diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/components/quartz/job/XcxSubSendMessageJob.java b/mall-shop/src/main/java/com/suisung/mall/shop/components/quartz/job/XcxSubSendMessageJob.java
new file mode 100644
index 00000000..9c3c2f3d
--- /dev/null
+++ b/mall-shop/src/main/java/com/suisung/mall/shop/components/quartz/job/XcxSubSendMessageJob.java
@@ -0,0 +1,26 @@
+package com.suisung.mall.shop.components.quartz.job;
+
+import com.suisung.mall.shop.config.SpringUtil;
+import com.suisung.mall.shop.message.service.ShopMessageTemplateService;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.quartz.QuartzJobBean;
+
+
+/**
+ * 小程序订阅号消息发送 定时任务
+ */
+public class XcxSubSendMessageJob extends QuartzJobBean {
+
+    @Override
+    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+        Logger logger = LoggerFactory.getLogger(UpdateVoucherStatusJob.class);
+        ShopMessageTemplateService shopMessageTemplateService = SpringUtil.getBean(ShopMessageTemplateService.class);
+        logger.info("小程序订阅号消息发送消息开始--------start");
+        shopMessageTemplateService.sendToXcxAllUserMessage();
+        logger.info("小程序订阅号消息发送消息结束-------end");
+    }
+
+}
diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/message/controller/admin/ShopMessageTemplateController.java b/mall-shop/src/main/java/com/suisung/mall/shop/message/controller/admin/ShopMessageTemplateController.java
index 65c65e31..23dbe526 100644
--- a/mall-shop/src/main/java/com/suisung/mall/shop/message/controller/admin/ShopMessageTemplateController.java
+++ b/mall-shop/src/main/java/com/suisung/mall/shop/message/controller/admin/ShopMessageTemplateController.java
@@ -96,12 +96,22 @@ public class ShopMessageTemplateController extends BaseControllerImpl {
      * 发送消息推送
      * @return
      */
-    @ApiOperation(value = "消息模板表-编辑", notes = "消息模板表-编辑")
+    @ApiOperation(value = "发送消息推送", notes = "发送消息推送")
     @RequestMapping(value = "/sendToXcxUserMessage", method = RequestMethod.POST)
     public CommonResult sendToXcxUserMessage(@RequestParam(name = "userId") Integer userId) {
         return shopMessageTemplateService.sendToXcxUserMessage(userId);
     }
 
+    /**
+     * 发送消息推送给所有用户
+     * @return
+     */
+    @ApiOperation(value = "小程序消息推送", notes = "小程序消息推送")
+    @RequestMapping(value = "/sendToXcxAllUserMessage", method = RequestMethod.POST)
+    public CommonResult sendToXcxAllUserMessage() {
+         shopMessageTemplateService.sendToXcxAllUserMessage();
+         return CommonResult.success();
+    }
 
 }
 
diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/message/service/ShopMessageTemplateService.java b/mall-shop/src/main/java/com/suisung/mall/shop/message/service/ShopMessageTemplateService.java
index ddecfb2f..c326f11a 100644
--- a/mall-shop/src/main/java/com/suisung/mall/shop/message/service/ShopMessageTemplateService.java
+++ b/mall-shop/src/main/java/com/suisung/mall/shop/message/service/ShopMessageTemplateService.java
@@ -45,4 +45,6 @@ public interface ShopMessageTemplateService extends IBaseService mobiles, String tmplCode, Map tmplParams);
 
     CommonResult sendToXcxUserMessage(Integer user_id);
+
+    void sendToXcxAllUserMessage();
 }
diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java
index b46b35e9..150f1c43 100644
--- a/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java
+++ b/mall-shop/src/main/java/com/suisung/mall/shop/message/service/impl/ShopMessageTemplateServiceImpl.java
@@ -23,6 +23,7 @@ import com.suisung.mall.common.feignService.AccountService;
 import com.suisung.mall.common.feignService.SnsService;
 import com.suisung.mall.common.modules.account.AccountBaseConfig;
 import com.suisung.mall.common.modules.account.AccountUserBase;
+import com.suisung.mall.common.modules.account.AccountUserBindConnect;
 import com.suisung.mall.common.modules.account.AccountUserLogin;
 import com.suisung.mall.common.modules.message.ShopMessageTemplate;
 import com.suisung.mall.common.modules.store.ShopStoreBase;
@@ -42,6 +43,7 @@ import com.suisung.mall.shop.message.mapper.ShopMessageTemplateMapper;
 import com.suisung.mall.shop.message.service.ShopMessageTemplateService;
 import com.suisung.mall.shop.message.vo.WxTelMsgPushVo;
 import com.suisung.mall.shop.message.vo.WxXcxMsgPushVo;
+import com.suisung.mall.shop.sixun.utils.CommonUtil;
 import com.suisung.mall.shop.store.service.ShopStoreBaseService;
 import com.suisung.mall.shop.wechat.service.ShopWechatTplmsgService;
 import lombok.extern.slf4j.Slf4j;
@@ -55,10 +57,10 @@ import org.springframework.stereotype.Service;
 import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 import java.util.stream.Collectors;
 
 import static com.suisung.mall.common.utils.I18nUtil._;
@@ -96,6 +98,9 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("tplmsg_id", 1022);//todo 后期改为动态
+        ShopWechatTplmsg wechatTplmsg = shopWechatTplmsgService.getOne(queryWrapper);
+        ShopStoreBase shopStoreBase= shopStoreBaseService.get(wechatTplmsg.getStore_id());
+        Map args=new HashMap();
+        String[] activeProfiles = environment.getActiveProfiles();
+        String activeProfile = activeProfiles[0];
+        args.put("storeName", shopStoreBase.getStore_name());
+        args.put("evn",activeProfile);
+        Map timeArgs=getActiveTime();
+        args.putAll(timeArgs);
+        int total= (int) allBindCount;
+        Integer pages= CommonUtil.getPagesCount(total,BATCH_SIZE);
+        ExecutorService executor = Executors.newFixedThreadPool(6);
+        List> futures = new ArrayList<>();
+        for (int i=1;i<=pages;i++){
+            List finalList=accountService.getAllBindPage(BindCode.MOBILE,CommonConstant.BIND_SUB_TMPL_SKILL,i,BATCH_SIZE);
+            int finalI = i;
+            futures.add(executor.submit(() -> {
+                finalList.forEach(accountUserBindConnect -> {
+                    String open_id=accountUserBindConnect.getBind_openid();
+                    if(StrUtil.isNotEmpty(open_id)){
+                        String wechatTplData = getXcxWechatTplData(open_id, wechatTplmsg, args);
+                        String result = WxHttpUtil.request(WxHttpUtil.MethodType.POST, WxHttpUtil.WxType.XCX, accessToken, url, null, wechatTplData);
+                        JSONObject resultJson = JSONUtil.parseObj(result);
+                        Integer errcode = Convert.toInt(resultJson.get("errcode"));
+                        String errmsg = Convert.toStr(resultJson.get("errmsg"));
+                        if (errcode != 0) {
+                            log.error("微信公众号推送失败,失败原因:{}", errmsg);
+                        }
+                    }
+                });
+                return "完成推送批次:"+ finalI;
+            }));
+        }
+        // 等待所有任务完成
+        for (Future future : futures) {
+            try {
+                log.info("规格任务结果: {}", future.get());
+            } catch (Exception e) {
+                log.info("规格任务执行异常: {}", e.getMessage());
+            }
+        }
+        executor.shutdown();
+    }
 
 
     /**
@@ -750,19 +825,11 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl