当前位置:   article > 正文

Java实现微信公众号模板消息管理群发和单发_微信公众平台 模板消息

微信公众平台 模板消息

微信公众号开发模板消息管理发送

一. 能力开通

微信文档参考: https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html

1. 登录微信公众平台:https://mp.weixin.qq.com/

2. 按照图示依次进入

在这里插入图片描述
如果是未开通能力的账户, 在未开通里面寻找,根据提示填入相关信息即可
在这里插入图片描述
进入模板库,添加符合自己需求的模板消息, 在我的模板中查看模板id,如图:
在这里插入图片描述
在这里插入图片描述
查看模板消息的内容,以第四个为例
在这里插入图片描述
至此模板消息的功能开通完成!

二. 表结构设计以及java代码编写

1. 表结构设计

1.1 根据添加的消息模板和文档里面所需的参数设计表

消息内容
在这里插入图片描述
表结构(根据功能需求设计, 不必完全一样)
在这里插入图片描述

2. java实现该功能

2.1 模板消息实体类

package net.huashitong.ssydt.wechat.entity;

import io.swagger.annotations.ApiModelProperty;
import net.huashitong.ssydt.base.entity.BaseEntity;
import net.huashitong.ssydt.base.entity.LongEntity;

/**
 * @author xiazz
 * @Date 2022/11/3
 * @Description: t_template_message 公众号模板消息
 */
public class TemplateMessage extends BaseEntity {
    @ApiModelProperty("id")
    private String id;
    @ApiModelProperty("模板id")
    private String templateId;
    @ApiModelProperty("推送时间")
    private String pushTime;
    @ApiModelProperty("副标题")
    private String firstData;
    @ApiModelProperty("关键词1")
    private String keyword1;
    @ApiModelProperty("关键词2")
    private String keyword2;
    @ApiModelProperty("关键词3")
    private String keyword3;
    @ApiModelProperty("消息跳转的url")
    private String referUrl;
    @ApiModelProperty("关联的appid")
    private String relateAppid;
    @ApiModelProperty("备注")
    private String remark;
    @ApiModelProperty("用户的openid")
    private String openid;
    @ApiModelProperty("推送类型: 1所有用户 2单个指定用户")
    private Integer pushType;
    @ApiModelProperty("推送状态: 0未推送 1已推送")
    private Integer pushStatus;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getTemplateId() {
        return templateId;
    }

    public void setTemplateId(String templateId) {
        this.templateId = templateId;
    }

    public String getPushTime() {
        return pushTime;
    }

    public void setPushTime(String pushTime) {
        this.pushTime = pushTime;
    }

    public String getFirstData() {
        return firstData;
    }

    public void setFirstData(String firstData) {
        this.firstData = firstData;
    }

    public String getKeyword1() {
        return keyword1;
    }

    public void setKeyword1(String keyword1) {
        this.keyword1 = keyword1;
    }

    public String getKeyword2() {
        return keyword2;
    }

    public void setKeyword2(String keyword2) {
        this.keyword2 = keyword2;
    }

    public String getKeyword3() {
        return keyword3;
    }

    public void setKeyword3(String keyword3) {
        this.keyword3 = keyword3;
    }

    public String getReferUrl() {
        return referUrl;
    }

    public void setReferUrl(String referUrl) {
        this.referUrl = referUrl;
    }

    public String getRelateAppid() {
        return relateAppid;
    }

    public void setRelateAppid(String relateAppid) {
        this.relateAppid = relateAppid;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public String getOpenid() {
        return openid;
    }

    public void setOpenid(String openid) {
        this.openid = openid;
    }

    public Integer getPushType() {
        return pushType;
    }

    public void setPushType(Integer pushType) {
        this.pushType = pushType;
    }

    public Integer getPushStatus() {
        return pushStatus;
    }

    public void setPushStatus(Integer pushStatus) {
        this.pushStatus = pushStatus;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144

2.2 模板消息管理的增删改查功能(根据功能需求编写即可, 不赘述)

2.3 模板消息的发送功能(重点看!!!)

@ApiOperation("发送模板消息")
    @GetMapping("/send/{id}")
    public Result<String> sendMsg(@PathVariable("id") String id) {
        String colorBlue = "#173177";
        String colorRed = "#DC143C";
        // 根据id获取详细的模板消息参数
        TemplateMessage templateMessage = templateMessageService.info(id);
        if (Objects.isNull(templateMessage) || Objects.equals(1,templateMessage.getPushStatus())) {
            throw new ServiceException("消息不存在或者已推送");
        }

        // 模板参数
        Map<String, WeChatTemplateMsg> sendMsg = new HashMap<String, WeChatTemplateMsg>();
        sendMsg.put("first",new WeChatTemplateMsg(templateMessage.getFirstData()));
        sendMsg.put("keyword1",new WeChatTemplateMsg(templateMessage.getKeyword1(),colorRed)); // 考试名称
        sendMsg.put("keyword2",new WeChatTemplateMsg(templateMessage.getKeyword2())); // 考试单位
        sendMsg.put("keyword3",new WeChatTemplateMsg(templateMessage.getKeyword3(),colorRed)); // 考试时间
        sendMsg.put("remark",new WeChatTemplateMsg(templateMessage.getRemark(),colorBlue));
        String accessToken = getAccessToken().getAccess_token();
        // 测试: 向单个用户发送
        String send = send(accessToken,"oJcdptwBGx3bSa8-FbepyxB-2Okc", templateMessage.getTemplateId(),
                templateMessage.getReferUrl(),templateMessage.getRelateAppid(), sendMsg);
        JSONObject jsonObject = JSONObject.parseObject(send);
        Integer errcode = (Integer) jsonObject.get("errcode");
        if (Objects.equals(0,errcode)) {
            try {
                templateMessage.setPushStatus(1); // 设置为已推送
                templateMessageService.update(templateMessage);
            } catch (Exception e) {
                throw new ServiceException("消息状态更新失败,原因: " + e.getMessage());
            }
        }
        return ResultUtils.getSuccessResults("发送完成");
        // 线上:向所有已关注公众号的用户发送模板消息
        logger.info("模板消息开始发送......");
        long start = System.currentTimeMillis();
        List<String> openidList = new ArrayList<>();
        Integer total = getOpenIdList(openidList, accessToken, "");
        logger.info("关注该公众账号的总用户数:" + total);
        logger.info("获取到的公众号的总用户数:" + openidList.size());
        // 用户数量较多, 使用多线程发送
        if (total == openidList.size()) {
            ExecutorService executor = Executors.newFixedThreadPool(35);
            for (String openid : openidList) {
                executor.execute(new SendTask(accessToken, openid, templateMessage, sendMsg));
            }
        }
        long end = System.currentTimeMillis();
        // 更新消息状态
        try {
            templateMessage.setPushStatus(1); // 设置为已推送
            templateMessageService.update(templateMessage);
        } catch (Exception e) {
            throw new ServiceException("消息状态更新失败,原因: " + e.getMessage());
        }
        logger.info("模板消息发送完成,共耗时:" + (end - start) + "ms");
        return ResultUtils.getSuccessResults("发送完成");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

获取accessToken

public static AccessToken getAccessToken() {
        String sb = "https://api.weixin.qq.com/cgi-bin/token?" +
                "grant_type=client_credential" +
                "&appid=" + "公众号appId" +
                "&secret=" + "公众号AppSecret";
        HttpRequest request = HttpRequest.get(sb);
        HttpResponse response = request.send();

        return JSON.parseObject(response.bodyText(),AccessToken.class);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

获取所有已关注的用户openid列表, 微信最多返回一万条, 这里采用递归取全部

/**
     * @date: 2022/11/2
     * @description: 获取关注者的(openid列表)
     */
    public static Integer getOpenIdList(List<String> openidList,String accessToken,String nextOpenid) {
        RestTemplate restTemplate = getInstance("UTF-8");
        Map<String, String> params = new HashMap<>();
        params.put("access_token", accessToken);  //
        params.put("next_openid", nextOpenid);  //
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(
                "https://api.weixin.qq.com/cgi-bin/user/get?access_token={access_token}&next_openid={next_openid}", String.class, params
        );

        String body = responseEntity.getBody();
        JSONObject jsonObject = JSON.parseObject(body);
        // 解析成JSONObject 并获取(叫data的JSON对象)JSONObject
        // 获取 JSONObject 中的 JSONArray
        JSONArray array = jsonObject.getJSONObject("data").getJSONArray("openid");
        List<String> currentOpenidList = array.toJavaList(String.class);
        openidList.addAll(currentOpenidList);
        Integer total = (Integer) jsonObject.get("total");
        if (openidList.size() < total) {
            nextOpenid = (String) jsonObject.get("next_openid");
            getOpenIdList(openidList,accessToken,nextOpenid);
        }
        return total;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

工作线程类

public class SendTask implements Runnable {
        private String accessToken;
        private String openid;
        private TemplateMessage templateMessage;
        private Map<String,WeChatTemplateMsg> dataMap;

        public SendTask(String accessToken,String openid,TemplateMessage templateMessage,Map<String,WeChatTemplateMsg> dataMap){
            this.accessToken = accessToken;
            this.openid = openid;
            this.templateMessage = templateMessage;
            this.dataMap = dataMap;

        }

        public SendTask() {}

        public String getAccessToken() {
            return accessToken;
        }

        public void setAccessToken(String accessToken) {
            this.accessToken = accessToken;
        }

        public String getOpenid() {
            return openid;
        }

        public void setOpenids(String openid) {
            this.openid = openid;
        }

        public TemplateMessage getTemplateMessage() {
            return templateMessage;
        }

        public void setTemplateMessage(TemplateMessage templateMessage) {
            this.templateMessage = templateMessage;
        }

        public Map<String,WeChatTemplateMsg> getDataMap() {
            return dataMap;
        }

        public void setDataMap(Map<String,WeChatTemplateMsg> dataMap) {
            this.dataMap = dataMap;
        }

        //多线程入口
        @Override
        public void run() {
            TemplateMessage templateMessage1 = this.templateMessage;
            String send = send(this.accessToken, openid, templateMessage1.getTemplateId(), templateMessage1.getReferUrl(), templateMessage1.getRelateAppid(),
                    this.dataMap);
            JSONObject jsonObject = JSONObject.parseObject(send);
            Integer errcode = (Integer) jsonObject.get("errcode");
            if (Objects.equals(0,errcode)) {
                logger.info("已向openid为" + openid + "发送通知");
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

消息发送的send方法

/**
     * 2、发送模版消息
     * openId     用户Id
     * templateId 模板Id
     * data       模板参数
     * @param data
     */
    public static String send(String accessToken,String openId, String templateId, String referUrl,String relateAppid, Map<String, WeChatTemplateMsg> data) {
        RestTemplate restTemplate = getInstance("UTF-8");
        String sendUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
        String url = sendUrl.replace("ACCESS_TOKEN", accessToken);
        //拼接base参数
        Map<String, Object> sendBody = new HashMap<>();
        if (StringUtils.isNotBlank(relateAppid)) {
            Map<String, String> miniprogramMap = new HashMap<>();
            miniprogramMap.put("appid", relateAppid);
            miniprogramMap.put("pagepath", "/pages/index/index?foo=bar");
            sendBody.put("miniprogram",miniprogramMap);// 关联的小程序
        }
        if (StringUtils.isNotBlank(referUrl)) {
            sendBody.put("url", referUrl);// 点击模板信息跳转地址
        }
        sendBody.put("touser", openId);               // openId
        sendBody.put("data", data);                   // 模板参数
        sendBody.put("template_id", templateId);      // 模板Id
        ResponseEntity<String> forEntity = restTemplate.postForEntity(url, sendBody, String.class);
        return forEntity.getBody();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

三. 实现效果

管理后台(因功能需求有进行删减, 不必完全一致!!!)

在这里插入图片描述

收到的推送

在这里插入图片描述

四. 总结

过程中遇到了一些问题, 比如微信一次只给一万条的限制(使用递归获取前每发完一万条要重启一次服务), 使用单线程发送过慢的问题(亲测一万条数据花费1个半小时), 好在后面都解决了, 特此记录! 如果有什么不明白或者觉得说得不对的地方, 欢迎在评论区指正, 互相学习

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/178573
推荐阅读
相关标签
  

闽ICP备14008679号