微信消息推送开发
随着微信使用越来越广泛,因其也产生了许多二次开发的小功能,今天要介绍的就是微信服务号的中的消息模板推送。
添加模板消息方式如上面,如果不满足可以添加自定义的,但是需要审核,周期为7到15天。消息模板内容一般如下:
我们需要用到的是模板Id,显示内容,first、keyword1、keyword2、keyword3、keyword4、remark我们传过来的值。
如果想要使用模板推送消息,我们首先得获取到access_token凭证,该凭证有效期为2个小时。我们可以获取的时候存起来,这里我是使用redis存储。
具体获取方式如下代码:
public static AccessToken getAccessToken() throws Exception { //获取凭证地址 String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET"; CloseableHttpClient httpCilent = HttpClients.createDefault(); HttpGet httpGet = new HttpGet(accessTokenUrl); try { CloseableHttpResponse response = httpCilent.execute(httpGet); System.out.println("code===="+response.getStatusLine().getStatusCode()); if (response.getStatusLine().getStatusCode() == 200) { String entity = EntityUtils.toString(response.getEntity()); System.out.println("entity===="+entity); AccessToken accessToken = JSONObject.parseObject(entity, AccessToken.class); return accessToken; }else { logger.error("获取access_token发送get请求获取到的状态为:"+response.getStatusLine().getStatusCode()); return null; } } catch (IOException e) { logger.error("获取access_token出错",e); throw new Exception("获取access_token出错",e); }finally { try { httpCilent.close(); } catch (IOException e) { logger.error("关闭请求连接失败",e); throw new Exception("关闭请求连接失败",e); } } }
public class AccessToken { // 获取到的凭证 private String access_token; // 凭证有效时间,单位:秒 private Integer expires_in; public String getAccess_token() { return access_token; } public void setAccess_token(String access_token) { this.access_token = access_token; } public Integer getExpires_in() { return expires_in; } public void setExpires_in(Integer expires_in) { this.expires_in = expires_in; } }
这里需要注意的是,微信获取access_token的接口有多种,这里我们使用的是这个接口:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET
使用的get请求,其会返回一个json字符串:{"access_token":"xxx","expires_in":7200}的结果。其中还有一步很重要,就是需要设置ip白名单,如果不设置获取不到access_token。
获取到access_token后,还需要填充内容,具体的封装方式如下:
public class WechatTemplateMsg { //发送人的openid private String touser; //消息模板Id private String template_id; //模板跳转链接 private String url; //data数据 private TreeMap<String, TreeMap<String, String>> data; //设置参数值,color可为空 public static TreeMap<String,String> init(String value,String color){ TreeMap<String, String> params = new TreeMap<String, String>(); params.put("value", value); params.put("color", color); return params; } 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 getUrl() { return url; } public void setUrl(String url) { this.url = url; } public TreeMap<String, TreeMap<String, String>> getData() { return data; } public void setData(TreeMap<String, TreeMap<String, String>> data) { this.data = data; } }
public String leaderSendTemplate(String openid,String repairDate,String repairInfoCount,String resultCount) { //封装信息 TreeMap<String, TreeMap<String, String>> params = new TreeMap<>(); params.put("first",WechatTemplateMsg.init("","#000000")); //报表时间 params.put("keyword1",WechatTemplateMsg.init(repairDate,"#000000")); //报修数量 params.put("keyword2",WechatTemplateMsg.init(repairInfoCount,"#000000")); //维修完成数量 params.put("keyword3",WechatTemplateMsg.init(resultCount,"#000000")); //内容 params.put("remark",WechatTemplateMsg.init("","#173177")); ResourceBundle resource = ResourceBundle.getBundle("properties/pay"); String template_id =resource.getString("Leader_ID");//模板Id String leaderUrl =resource.getString("leaderUrl");//转跳地址 WechatTemplateMsg templateMsg = new WechatTemplateMsg(); templateMsg.setTouser(openid);//报修人OpenId templateMsg.setTemplate_id(template_id); templateMsg.setUrl(leaderUrl);//跳转地址 templateMsg.setData(params);//参数 return JsonUtil.toJsonString(templateMsg); }
这样我们就可以获取到String的date了,其中date的数据格式如下:
{"touser":"openid","template_id":"模板id","url":"需要转跳地址","data":{"first":{"color":"#000000","value":"您好,存在新 的待维修单,请查看!"},"keyword1":{"color":"#000000","value":"一体机1"},"keyword2":{"color":"#000000","value":"2019-01-28 10:00"},"keyword3":{"color":"#000000","value":"地址"},"keyword4":{"color":"#000000","value":"无"},"remark":{"color":"#173177","value":"感谢您的使用"}}}
我们就可以使用access_token或date发送消息了,具体如下:
public static String sendDate(String access_token,String data) throws Exception { String sendUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESSTOKEN"; sendUrl = sendUrl.replace("ACCESSTOKEN",access_token); logger.info("sendUrl"+sendUrl); CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(sendUrl); try { //转换参数 StringEntity dateSet = new StringEntity(data, ContentType.APPLICATION_JSON); // 设置post求情参数 httpPost.setEntity(dateSet); HttpResponse httpResponse = httpClient.execute(httpPost); if (httpResponse.getStatusLine().getStatusCode() == 200) { //发送成功 String entity = EntityUtils.toString(httpResponse.getEntity()); logger.info("返回结果:"+entity); //返回结果 ResultTemplateDate resultTemplateDate = JSONObject.parseObject(entity, ResultTemplateDate.class); return resultTemplateDate.getErrcode(); }else { logger.error("StatusCode:"+httpResponse.getStatusLine().getStatusCode()); } } catch (IOException e) { logger.info("发送消息失败",e); throw new Exception("发送消息失败",e); }finally { try { httpClient.close(); } catch (IOException e) { logger.error("关闭HttpClients异常"); throw new Exception("关闭HttpClients异常",e); } } return "-1"; }
这样就发送成功了,返回成的结果为:{"errcode":0,"errmsg":"ok","msgid":655130036042940416}。
以下为一些工具类:
public class ResultTemplateDate { //返回消息代码:0:成功 /* * 常见错误状态码: 40001:不合法的调用凭证 、40003:不合法的OpenID * 40030:不合法的refresh_token、 * 40036:不合法的template_id长度、40037:不合法的template_id * 41009: 缺失openid参数 **/ private String errcode; //返回信息:“ok”:成功 private String errmsg; public String getErrcode() { return errcode; } public void setErrcode(String errcode) { this.errcode = errcode; } public String getErrmsg() { return errmsg; } public void setErrmsg(String errmsg) { this.errmsg = errmsg; } }
// 将对象转成String public static String toJsonString(Object obj) { if (obj == null) { return "{}"; } if (obj instanceof String) { if (StringUtils.isEmpty(obj.toString())) { return "{}"; } } String json = ""; try { if (gson != null) { json = gson.toJson(obj); } } catch (Exception e) { return "{}"; } return json; }
在这过程中也遇到一些问题,其中最难的是遇到{"errcode":48001,"errmsg":"api unauthorized hint: [L5EA1a05308051!]"}这个错误,一开始以为没有微信没有认证,但去看了以及认证了,也有该接口权限,一直再找问题出现在哪。最后发现是调用错接口了。
这是第一次开发这个功能,如果不正确的地方,请指正,谢谢!