微信消息发送(小程序,公众号)
1.场景描述:
在小程序开发过程中需要发送消息,由于小程序消息(订阅消息)需要经常点击订阅,用户操作麻烦,所以将小程序与公众号进行关联;
优先发送消息到公众号。
2.Java代码实现
主要有以下几个类
WeChatMessageSendUtil //消息发送类
PubMessage //统一消息发送实体
MpTemplateMsg //公众号消息模板实体
miniprogram // 跳小程序所需数据,不需跳小程序可不用传该数据 (注意:路径前要去掉‘/’ ;如:pages/menu)
STemplateData //公众号消息模板参数
TemplateModel //订阅消息模板实体
TemplateData //订阅消息模板参数 Schedulers //定时器用于维护accessToken SysParam //获取配置文件参数 WeappTemplateMsg //作废
2.1.配置文件(application.properties)
#####################################微信小程序参数 for message ################################################# message.wxapp.appid=微信小程序appid message.wxapp.appsecret=微信小程序appsecret
2.2.java Class
import io.swagger.annotations.ApiModelProperty;
/**
* 跳小程序所需数据,不需跳小程序可不用传该数据
*/
public class miniprogram {
@ApiModelProperty(value = "所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系,暂不支持小游戏)", example = "")
private String appid;
@ApiModelProperty(value = "所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar),要求该小程序已发布,暂不支持小游戏", example = "")
private String page;
//private String pagepath;
public miniprogram() {
}
public miniprogram(String appid, String page) {
this.appid = appid;
this.page = page;
}
/*public miniprogram(String appid, String pagepath) {
this.appid = appid;
this.pagepath = pagepath;
}*/
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
//public String getPagepath() {
// return pagepath;
//}
//public void setPagepath(String pagepath) {
// this.pagepath = pagepath;
//}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
}
import io.swagger.annotations.ApiModelProperty;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.EntityListeners;
import java.util.Map;
@EntityListeners(AuditingEntityListener.class)
public class MpTemplateMsg {
@ApiModelProperty(value = "服务号", example = "")
private String appid;
@ApiModelProperty(value = "消息模板id", example = "")
private String template_id;
@ApiModelProperty(value = "模板跳转链接(海外帐号没有跳转能力)", example = "")
private String url="/index";
@ApiModelProperty(value = "模板参数", example = "")
Map<String, STemplateData> data;
@ApiModelProperty(value = "跳小程序所需数据,不需跳小程序可不用传该数据", example = "")
private miniprogram miniprogram;
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getTemplate_id() {
return template_id;
}
public void setTemplate_id(String template_id) {
this.template_id = template_id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map<String, STemplateData> getData() {
return data;
}
public void setData(Map<String, STemplateData> data) {
this.data = data;
}
public miniprogram getMiniprogram() {
return miniprogram;
}
public void setMiniprogram(miniprogram miniprogram) {
this.miniprogram = miniprogram;
}
}
import com.redlichee.core.entity.BaseEntity;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.EntityListeners;
import javax.persistence.Id;
@EntityListeners(AuditingEntityListener.class)
public class PubMessage extends BaseEntity {
@Id
//收件人openid
private String touser;
//小程序消息模板
private TemplateModel weapp_template_msg;
//服务号消息模板
private MpTemplateMsg mp_template_msg;
public PubMessage() {
}
public PubMessage(String touser, TemplateModel weapp_template_msg, MpTemplateMsg mp_template_msg) {
this.touser = touser;
this.weapp_template_msg = weapp_template_msg;
this.mp_template_msg = mp_template_msg;
}
public String getTouser() {
return touser;
}
public void setTouser(String touser) {
this.touser = touser;
}
public TemplateModel getWeapp_template_msg() {
return weapp_template_msg;
}
public void setWeapp_template_msg(TemplateModel weapp_template_msg) {
this.weapp_template_msg = weapp_template_msg;
}
public MpTemplateMsg getMp_template_msg() {
return mp_template_msg;
}
public void setMp_template_msg(MpTemplateMsg mp_template_msg) {
this.mp_template_msg = mp_template_msg;
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
@EnableScheduling
@Component
@Lazy(false)
public class Schedulers {
@Autowired
SysParam sysParam;
private static Logger logger = LoggerFactory.getLogger(Schedulers.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
//每隔2秒执行一次
/*@Scheduled(fixedRate = 2000)
public void testTasks2() {
System.out.println("定时任务执行时间:1111111111111");
}
*/
/**
* access_token 是小程序的全局唯一调用凭据
* access_token 的有效期为 2 个小时,需要定时刷新 access_token,重复获取会导致之前一次获取的
* access_token 失效
* 延迟一秒执行
*/
@Scheduled(initialDelay = 1000, fixedDelay = 6000*1000 )
public void getAccessToken(){
try {
String token = WeChatMessageSendUtil.getAccessToken(sysParam.getWXAPP_APP_ID(),sysParam.getWXAPP_APP_SECRET());
//将获取到的token放到内存
WeChatMessageSendUtil.ACCESSTOKEN = token;
logger.info("获取到的微信accessToken为"+token);
} catch (Exception e) {
logger.error("获取微信accessToken出错,信息如下");
e.printStackTrace();
}
}
}
public class STemplateData {
private String value;//
private String color;
public STemplateData() {
}
public STemplateData(String value, String color) {
this.value = value;
this.color = color;
}
public STemplateData(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "TemplateData{" +
"value='" + value + '\'' +
", color='" + color + '\'' +
'}';
}
}
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class SysParam {
@Value("${message.wxapp.appid}")
private String WXAPP_APP_ID;
@Value("${message.wxapp.appsecret}")
private String WXAPP_APP_SECRET;
public String getWXAPP_APP_ID() {
return WXAPP_APP_ID;
}
public void setWXAPP_APP_ID(String WXAPP_APP_ID) {
this.WXAPP_APP_ID = WXAPP_APP_ID;
}
public String getWXAPP_APP_SECRET() {
return WXAPP_APP_SECRET;
}
public void setWXAPP_APP_SECRET(String WXAPP_APP_SECRET) {
this.WXAPP_APP_SECRET = WXAPP_APP_SECRET;
}
}
public class TemplateData {
private String value;//
public TemplateData(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "TemplateData{" +
"value='" + value + '\'' +
'}';
}
}
import io.swagger.annotations.ApiModelProperty;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.EntityListeners;
import java.util.Map;
/**
* @author why
* 订阅消息模板实体
*/
@EntityListeners(AuditingEntityListener.class)
public class TemplateModel {
private String form_id;//收集到的用户formid
private String emphasis_keyword = "keyword1.DATA";//放大那个推送字段
@ApiModelProperty(value = "接收人的openId", example = "")
private String touser;
@ApiModelProperty(value = "消息模板id", example = "")
private String template_id;
@ApiModelProperty(value = "跳转页", example = "")
private String page="/index";
@ApiModelProperty(value = "参数", example = "")
Map<String, TemplateData> data;
public TemplateModel() {
}
public TemplateModel(String touser, String template_id, String page, Map<String, TemplateData> data) {
this.touser = touser;
this.template_id = template_id;
this.page = page;
this.data = data;
}
public String getTouser() {
return touser;
}
public void setTouser(String touser) {
this.touser = touser;
}
public String getTemplate_id() {
return template_id;
}
public void setTemplate_id(String template_id) {
this.template_id = template_id;
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
public Map<String, TemplateData> getData() {
return data;
}
public void setData(Map<String, TemplateData> data) {
this.data = data;
}
@Override
public String toString() {
return "WxSendModel{" +
"touser='" + touser + '\'' +
", template_id='" + template_id + '\'' +
", page='" + page + '\'' +
", data=" + data +
'}';
}
}
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
@Component
public class WeChatMessageSendUtil {
public static final String POST_PUB_MESSAGE = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN";
public static final String POST_APP_MESSAGE ="https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN";
public static String ACCESSTOKEN;
@Autowired
SysParam sysParam;
@Autowired
Schedulers schedulers;
public static void main(String[] args) {
}
/**
* 统一消息发送模板
*/
public Map<String,Object> send(PubMessage pubMessage){
Map<String,Object> resMap=new HashMap<>();
//获取token
if ( ACCESSTOKEN==null){
schedulers.getAccessToken();
}
String accessToken =ACCESSTOKEN;
//存储小程序消息模板信息
TemplateModel weapp_template_msg = pubMessage.getWeapp_template_msg();
pubMessage.setWeapp_template_msg(null);
RestTemplate restTemplate = new RestTemplate();
//发送服务号消息
ResponseEntity<String> responseEntity =
restTemplate.postForEntity(POST_PUB_MESSAGE.replace("ACCESS_TOKEN",accessToken), pubMessage, String.class);
String body = responseEntity.getBody();
JSONObject jsonObject = JSONObject.parseObject(body);
if ("40001".equals(jsonObject.get("errcode")+"")){//防止AccessToken过期
//AccessToken过期
String token = WeChatMessageSendUtil.getAccessToken(sysParam.getWXAPP_APP_ID(),sysParam.getWXAPP_APP_SECRET());
//将获取到的token放到内存
WeChatMessageSendUtil.ACCESSTOKEN = token;
accessToken=token;
responseEntity =restTemplate.postForEntity(POST_PUB_MESSAGE.replace("ACCESS_TOKEN",accessToken), pubMessage, String.class);
body = responseEntity.getBody();
jsonObject = JSONObject.parseObject(body);
}
if ("0".equals(jsonObject.get("errcode")+"")){
//服务号发送成功,不再发送小程消息
resMap.put("code","success");
resMap.put("msg","公众号消息发送成功");
resMap.put("data",pubMessage);
}else{
//服务号发送失败,发送订阅消息
String s = WxAppSend(weapp_template_msg, accessToken);
JSONObject jsonObject2 = JSONObject.parseObject(s);
if ("0".equals(jsonObject2.get("errcode")+"")){
resMap.put("code","success");
resMap.put("msg","小程序消息发送成功");
resMap.put("data",pubMessage);
}else{
resMap.put("code","error");
resMap.put("msg","小程序消息发送失败");
resMap.put("data",jsonObject2);
resMap.put("msg2","公众号消息发送失败");
resMap.put("data",jsonObject);
}
}
return resMap;
}
/**
* 订阅消息模板发送
* @param templateModel
* @param accessToken
* @return
*/
public static String WxAppSend(TemplateModel templateModel,String accessToken) {
String body ="";
try {
RestTemplate restTemplate = new RestTemplate();
String url = POST_APP_MESSAGE.replace("ACCESS_TOKEN",accessToken);
//拼接推送的模版
ResponseEntity<String> responseEntity =
restTemplate.postForEntity(url, templateModel, String.class);
body = responseEntity.getBody();
}catch (Exception e){
return e.getMessage();
}
return body;
}
/**
* 获取token
* @param appId
* @param secret
* @return
*/
public static String getAccessToken(String appId,String secret) {
Map<String, Object> map = null;
String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?" +
"grant_type=client_credential" +
"&appid="+appId+
"&secret="+secret;
try {
HttpClient client = HttpClientBuilder.create().build();//构建一个Client
HttpGet get = new HttpGet(access_token_url); //构建一个GET请求
HttpResponse response = client.execute(get);//提交GET请求
HttpEntity result = response.getEntity();//拿到返回的HttpResponse的"实体"
String content = EntityUtils.toString(result);
//System.out.println(content);
JSONObject res = JSONObject.parseObject(content);
//map = JsonUtil.parseJSON2Map(res);
return res.get("access_token")+"";
} catch (Exception e) {
e.printStackTrace();
System.out.println("获取信息失败");
}
return "error:access_token";
}
}
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如有问题,可以通过邮件985843242@qq.com联系。欢迎共同交流讨论。

浙公网安备 33010602011771号