从 0 到 1!SpringBoot 整合微信公众号模板消息推送(附源码)

931 阅读7分钟

今天领导希望将客户的订单、扣款等信息通过微信推送给客户,于是我就花了一天的时间将公司的系统整合微信公众号实现了模板消息推送。

接下来我将会手把手教会你,非常详细!

微信官方对接文档地址:

https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html

1.注册服务号

https://mp.weixin.qq.com/

注册服务号需要营业执照

然后就是绑定邮箱,填写必要信息,比如对公账户、统一社会信用代码等。

2.服务号认证

开通公众号之后需要进行认证。只有认证过的服务号才能开通模板消息功能

认证费用每年300元,认证后的公众号带有一个蓝标。

比如:

3.开通模板消息功能

点击公众号左侧菜单:+新的功能,点击模板消息,申请开通

开通模板消息功能需要申请,申请理由这里我也帮大家准备好了:

尊敬的公众号运营团队:
您好!
我谨以此申请书,正式向贵公众号运营团队申请开通模板消息功能。
申请背景:
随着移动互联网的快速发展,公众号已成为品牌与用户沟通的重要渠道。为了更好地服务用户,提高品牌知名度,我们希望通过开通模板消息功能,实现以下目标:
1.提升用户体验:通过模板消息,我们可以为用户提供个性化、及时的信息推送,增强用户粘性。
2.增强品牌互动:模板消息可以用于举办活动、调查问卷等,提高用户参与度,增强用户对品牌的认同感。
3.提高运营效率:模板消息可以帮助我们实现自动化运营,节省人力成本,提高工作效率。

模板消息功能介绍
1.模板消息类型
根据我们公众号的内容和运营需求,我们计划开通以下类型的模板消息:
(1)	订单通知:用户新增订单通知、退单通知、订单发货通知
2.模板消息内容
我们将根据不同类型的模板消息,设计相应的模板内容,确保内容简洁、美观、易读。具体包括:
(1)	订单通知:用于发布订单通知,提醒用户关注

4.设置服务类目

公众号点击账号详情,点击服务类目进行设置:服务类目要跟你所在企业的经营范围保持一致。

5.设置模板

点击模板消息-》模板库

找到一个符合你公司需求的一个模板,点击详情

选择关键词,填写场景说明,点击添加:

然后在我的模板里面,点击刚新增的模板详情:

复制模板ID,注意详细内容里面的参数,其中后缀DATA是官方默认的,不用管。前面的 amount2、thing3等参数需要我们在代码中进行设置。

6. 准备好appId和appSecret

APPID 和 APPSecret 一定要保存好,很关键

7. 设置IP白名单

我们要想通过公司的系统访问微信公众平台的服务器获取access_token,那么需要将公司服务器的公网IP设置成白名单。

如果你想通过自己的电脑向微信公众平台获取认证之后的 access_token,也需要将自己电脑的公网IP添加白名单。

8.获取 ACCESS_TOKEN

有一天,你公司的系统对公众号服务器说,嘿老哥,能不能帮忙给俺们的用户发送个消息通知?

公众号服务器说:你谁啊你?我认识你吗?

然后你公司的系统根据设置的 appId 和 appSecret 去请求微信公众号的服务器。

微信公众号的服务器先验证你公司公网IP是否在IP白名单内,如果在,就放行,进行下一步。

接着在验证 appId 和 appSecret之后,微信公众号的服务器给你公司的系统返回了一个标识(access_token)。接着对你说:后面不管是获取关注的用户还是给用户发送消息,都要带上这个标识(access_token),不然我哪知道你是谁?

你公司系统说:好的老哥,知道了。

微信公众号服务器:还有别忘了让用户关注你们公司的公众号,不然我后台没有用户的 openId,我也发不了消息通知。

你公司系统说:好的老哥,知道了。

看懂上面对话之后,这里我们先搭建 SpringBoot 环境:

1.安装依赖:Redis 和 Hutool

<!--redis-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--hutool-->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.15</version>
</dependency>

2.配置 application.yml

wechat:
  appId: xxxxxxxxxx
  appSecret: xxxxxxxxxxxxxxxxxxxxxx
  # 获取微信公众号 access_token 的地址
  tokenUrl: https://api.weixin.qq.com/cgi-bin/token
  # token类型
  tokenGrantType: client_credential
  #  发送模板消息的地址
  templateUrl: https://api.weixin.qq.com/cgi-bin/message/template/send
  #  获取用户列表的url,主要是 openId
  userListUrl: https://api.weixin.qq.com/cgi-bin/user/get
  #  获取用户详细信息的 url
  userInfoUrl: https://api.weixin.qq.com/cgi-bin/user/info

3.公众号开发配置类

/**
 * @author 知否技术
 * @description 微信公众号开发配置类
 * @date 2025-05-27 9:53
 */
@Component
@Data
public class WechatConfig {
    @Value("${wechat.appId}")
    private String appId;
    @Value("${wechat.appSecret}")
    private String appSecret;
    @Value("${wechat.tokenUrl}")
    private String tokenUrl;
    @Value("${wechat.tokenGrantType}")
    private String tokenGrantType;
    @Value("${wechat.templateUrl}")
    private String templateUrl;
    @Value("${wechat.userListUrl}")
    private String userListUrl;
    @Value("${wechat.userInfoUrl}")
    private String userInfoUrl;
}

4. 创建 WechatService

public interface WechatService {


    /**
     * 获取公众号 AccessToken
     * @return
     */
    String getAccessToken();

    /**
     * 获取公众号用户列表
     * @return
     */
    JSONObject getWechatUserList();

    /**
     * 获取公众号用户详细信息
     * @param openId
     * @return
     */
    JSONObject getWechatUserInfo(String openId);

    /**
     * 向微信公众号用户发送特定消息
     * @param messageJSONObject
     * @param openId
     * @param templateId
     * @param redirectUrl
     * @return
     */
    JSONObject sendWechatMessage(JSONObject messageJSONObject, String openId, String templateId,String redirectUrl);
}

5.获取微信公众号返回的标识(access_token)

因为微信公众号服务器返回的 access_token 有过期时间,所以这里我的设计思路是:先从 Redis 里面查询 access_token,如果 access_token 不存在,则向微信公众号服务器获取 access_token,设置过期时间之后存入 Redsis。最后再返回。

    @Autowired
    private WechatConfig  wechatConfig;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 获取公众平台Token
     * @return
     */
    @Override
    public String getAccessToken() {
        // 先判断 Redis 中是否存在
        String wechat_access_token = stringRedisTemplate.opsForValue().get("wechat_access_token");
        if(StrUtil.isBlank(wechat_access_token)){
            String accessTokenUrl  = wechatConfig.getTokenUrl()+"?grant_type=client_credential&";
            String requestUrl = accessTokenUrl + "appid=" + wechatConfig.getAppId() + "&secret=" + wechatConfig.getAppSecret();
            String result = HttpUtil.get(requestUrl);
            log.info("wechat_access_token:{}",result);
            JSONObject jsonObject = JSONObject.parseObject(result);
            wechat_access_token = jsonObject.getString("access_token");
            // 将 access_token 存入 Redis
            stringRedisTemplate.opsForValue().set("wechat_access_token", wechat_access_token, 7200, TimeUnit.SECONDS);
        }
        return  wechat_access_token;
    }

9.获取用户关注列表

这里主要是获取用户的 openid

  @Override
  public JSONObject getWechatUserList() {
      String accessToken = getAccessToken();
      String requestUrl =  wechatConfig.getUserListUrl()+"?access_token=" + accessToken + "&next_openid=";
      String result = HttpUtil.get(requestUrl);
      log.info("wechat_getUserList:{}",result);
      JSONObject jsonObject = JSONObject.parseObject(result);
      return jsonObject;
  }

10.向微信公众号用户发送模板消息

这个接口是 POST 请求,请求路径:

https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN

POST数据示例如下:

 {
           "touser":"OPENID",
           "template_id":"xxxxxxxxx",
           "url":"http://weixin.qq.com/download",  
           "data":{

                   "character_string1":{
                       "value":"ZF20251314520521"
                   },
                   "amount2": {
                       "value":"100"
                   },
                   "thing3": {
                       "value":"知否君"
                   },
                    "time4": {
                       "value":"2025年05月27日 15:00"
                   }
           }
       }
  • touser:接收者openid
  • template_id:模板ID
  • url:模板跳转链接
  • data:模板数据

其中 data 参数要和你在公众号设置的参数一致:

这里我们将发送模板消息的功能封装成一个公用的方法:

    @Override
    public JSONObject sendWechatMessage(JSONObject messageJSONObject, String openId, String templateId, String redirectUrl) {
        log.info("messageJSONObject:{}",messageJSONObject);
        String accessToken = getAccessToken();
        // 请求 url
        String templateUrl = wechatConfig.getTemplateUrl() +"?access_token=" + accessToken;
        JSONObject  jsonContent =  new JSONObject();
        jsonContent.put("touser",openId);
        jsonContent.put("url",redirectUrl);
        jsonContent.put("template_id",templateId);
        jsonContent.put("data",messageJSONObject);
        log.info("jsonContent:{}",jsonContent);
        String result = HttpUtil.createPost(templateUrl).body(jsonContent.toJSONString()).execute().body();
        log.info("wechat_sendWechatMessage:{}",result);
        JSONObject jsonResult = JSONObject.parseObject(result);
        return jsonResult;
    }

11. 测试

首先获取所有关注该公众号的用户的 openid,然后发送指定模板id的模板消息:

 @Test
    void wechatSendMessageTest() {
         JSONObject wechatUserList = wechatService.getWechatUserList();
        JSONObject data = wechatUserList.getJSONObject("data");
        JSONArray openids = data.getJSONArray("openid");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("character_string1", JSONUtil.createObj().putOpt("value","ZF20251314520521"));
        jsonObject.put("amount2",JSONUtil.createObj().putOpt("value","100"));
        jsonObject.put("thing3", JSONUtil.createObj().putOpt("value","知否君"));
        jsonObject.put("time4",JSONUtil.createObj().putOpt("value","2025年05月27日 15:00"));
        log.info("jsonObject:{}",jsonObject);

        for (Object openid : openids) {
            wechatService.sendWechatMessage(jsonObject,openid.toString(),"xxxxx","https://www.baidu.com");
        }

    }