首页 > 技术文章 > SpringBoot 2.X 发送微信公众平台模板消息

guduershi 2020-07-27 15:30 原文

1、微信模板消息官方文档

  http://mp.weixin.qq.com/debug/cgi-bin/readtmpl?t=tmplmsg/faq_tmpl

2、申请微信公众平台接口测试账号

       http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

 

 

关注测试号二维码

 

 

新增测试模板

 

 

 3、配置和代码

①新建配置类WeChatConfig,和微信支付用了同一个文件

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component
@Configuration
@PropertySource(value = "classpath:wxpay.properties")
public class WeChatConfig {
    // 获取accessToken的接口
    public static final String GET_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    // 发送消息的接口
    public static final String PUSH_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s";

    @Value("${wechat.appid}")
    private String appId;

    @Value("${wechat.appsecret}")
    private String appsecret;

    @Value("${wechat.templateId}")
    private String templateId;

    @Value("${wechat.forwardUrl}")
    private String forwardUrl;

    // 发送消息的接口的访问凭证
    private String accessToken;

    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public String getAppsecret() {
        return appsecret;
    }

    public void setAppsecret(String appsecret) {
        this.appsecret = appsecret;
    }

    public String getTemplateId() {
        return templateId;
    }

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

    public String getForwardUrl() {
        return forwardUrl;
    }

    public void setForwardUrl(String forwardUrl) {
        this.forwardUrl = forwardUrl;
    }

    public String getAccessToken() {
        return accessToken;
    }

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

}

 

②配置wxpay.properties

#Wechat发送微信模板消息
wechat.appid=wxcc6efdba2803335c
wechat.appsecret=
#模板消息id
wechat.templateId=Ef3UeXmHSU8FY9eiHHE7FY559vNZ2zs1gHKfv8EowEE
#跳转地址
wechat.forwardUrl=http://www.baidu.com

  

③注入Http请求对象

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;


@Configuration
public class RestConfig {

    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

}

  

④微信接口凭证返回实体类

import com.fasterxml.jackson.annotation.JsonProperty;



public class AccessToken {
    @JsonProperty("access_token")
    private String accessToken;

    @JsonProperty("expires_in")
    private Long expiresIn;

    public String getAccessToken() {
        return accessToken;
    }

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

    public Long getExpiresIn() {
        return expiresIn;
    }

    public void setExpiresIn(Long expiresIn) {
        this.expiresIn = expiresIn;
    }

}

  

⑤定时获取微信接口凭证的token

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;


@Component
public class WeChatAccessTokenTask {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private WeChatConfig weChatConfig;

    /**
     * initialDelay: 初始化2s后执行第一次
     * fixedDelay:微信默认Token过期时间为7200s,这里定时7100s执行一次定时任务
     */
    @Scheduled(initialDelay = 2000, fixedDelay = 7100 * 1000)
    public void refreshToken() {
        // 请求方式: GET
        // URL:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

        AccessToken accessToken = restTemplate.getForObject(
                String.format(WeChatConfig.GET_TOKEN_URL, weChatConfig.getAppId(), weChatConfig.getAppsecret()),
                AccessToken.class);
        // 将获取的accessToken注入wechatConf
        weChatConfig.setAccessToken(accessToken.getAccessToken());
    }
}

  

⑥发送模板消息的请求参数封装类

import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonProperty;


public class WeChatTemplate {
    @JsonProperty("touser")
    private String toUser;

    @JsonProperty("template_id")
    private String templateId;

    private String url;

    private Map<String,String> miniprogram;

    private Map<String, Map<String, String>> data = new HashMap<>();

    public static Map<String, String> initData(String value, String color) {
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("value", value);
        data.put("color", color);
        return data;
    }

    public String getToUser() {
        return toUser;
    }

    public void setToUser(String toUser) {
        this.toUser = toUser;
    }

    public String getTemplateId() {
        return templateId;
    }

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

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Map<String, String> getMiniprogram() {
        return miniprogram;
    }

    public void setMiniprogram(Map<String, String> miniprogram) {
        this.miniprogram = miniprogram;
    }

    public Map<String, Map<String, String>> getData() {
        return data;
    }

    public void setData(Map<String, Map<String, String>> data) {
        this.data = data;
    }

}

  

⑦发送模板消息的返回参数封装类

public class WeiXinResponse {
    private Integer errcode;
    private String errmsg;
    private Long msgid;

    public Integer getErrcode() {
        return errcode;
    }

    public void setErrcode(Integer errcode) {
        this.errcode = errcode;
    }

    public String getErrmsg() {
        return errmsg;
    }

    public void setErrmsg(String errmsg) {
        this.errmsg = errmsg;
    }

    public Long getMsgid() {
        return msgid;
    }

    public void setMsgid(Long msgid) {
        this.msgid = msgid;
    }

}

  

⑧发送微信模板消息接口

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Objects;


@RestController
@CrossOrigin
public class WeChatMessage {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private WeChatConfig weChatConfig;

    @RequestMapping("/sendWxMessage")
    public Object sendMessage(@RequestBody String json) {
        Map<String, Object> map = JSONObject.parseObject(json, Map.class);
        WeChatTemplate weChatTemplate = new WeChatTemplate();
        // 设置模板id
        weChatTemplate.setTemplateId(weChatConfig.getTemplateId());
        //获取openid
        String openid = map.get("openid").toString();
        // 设置接收用户openId
        weChatTemplate.setToUser(openid);
        //点击详情跳转的地址
        weChatTemplate.setUrl(weChatConfig.getForwardUrl());
        //设置模板dada参数
        LocalDate date = LocalDate.now();
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        weChatTemplate.getData().put("date", WeChatTemplate.initData(date.getMonthValue()+"月"+date.getDayOfMonth()+"日"+"\n",""));
        weChatTemplate.getData().put("topic", WeChatTemplate.initData("店长您好,有一笔新的让利单,需要您的确认。"+"\n", "#0000EE"));
        weChatTemplate.getData().put("time", WeChatTemplate.initData(time, ""));
        //调用微信接口,发送模板消息
        WeiXinResponse result = restTemplate.postForObject(String.format(WeChatConfig.PUSH_MESSAGE_URL, weChatConfig.getAccessToken()),
                weChatTemplate, WeiXinResponse.class);
        if (Objects.nonNull(result)){
            return ResultJson.ok();
        }
        return ResultJson.failure(ResultCode.SEND_MESSAGE_FAIL);
    }
}

  

⑨后端返回统一格式

import lombok.Data;
import java.io.Serializable;


@Data
public class ResultJson<T> implements Serializable{

    private static final long serialVersionUID = 783015033603078674L;
    private int code;
    private String msg;
    private T data;

    public static ResultJson ok() {
        return ok("");
    }

    public static ResultJson ok(Object o) {
        return new ResultJson(ResultCode.SUCCESS, o);
    }

    public static ResultJson failure(ResultCode code) {
        return failure(code, "");
    }

    public static ResultJson failure(ResultCode code, Object o) {
        return new ResultJson(code, o);
    }

    public ResultJson (ResultCode resultCode) {
        setResultCode(resultCode);
    }

    public ResultJson (ResultCode resultCode,T data) {
        setResultCode(resultCode);
        this.data = data;
    }

    public void setResultCode(ResultCode resultCode) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
    }

    @Override
    public String toString() {
        return "{" +
                "\"code\":" + code +
                ", \"msg\":\"" + msg + '\"' +
                ", \"data\":\"" + data + '\"'+
                '}';
    }
}

  

⑩返回状态码

public enum ResultCode {
    /*
    请求返回状态码和说明信息
     */
    SUCCESS(200, "成功"),
    SEND_MESSAGE_FAIL(401, "消息发送失败"),
    NOT_FOUND(404, "请求的资源不存在"),
    OPERATE_ERROR(405, "操作失败,请求操作的资源不存在"),
    TIME_OUT(408, "请求超时"),


    SERVER_ERROR(500, "服务器内部错误"),

;
    private int code;
    private String msg;

    ResultCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

}

  

4、访问接口进行测试,公众号收到信息

 

 

 

  

推荐阅读