微信接口文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/template-message.html
调用微信服务消息的请求接口为:https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
还有一个地址为微信公众号的消息推送接口:https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token=ACCESS_TOKEN
这里用服务消息的接口而不是公众号消息推送的接口,公众号接口需要付费开通权限
关于服务推送form_id问题:
- form_id有时效性,网上有说7天,但文档中没有维护。
- form_id用过一次就失效。
- form_id要真机提供才有效
1.模板实体类
public class TemplateData {private String value;//color在服务消息通知中废弃,但在公众号消息通知仍存在private String color;public TemplateData(String value,String color){ this.value = value; this.color = color; }//get set 省略}public class TemplateMessage {/** 接收者openid */private String touser;/** 所需下发的模板消息的id */private String templateId;/**小程序要跳转的页面url*/private String page;/** * 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id * */private String formId;/** 模板数据 */private Map<String,TemplateData> data;/** 模板需要放大的关键词,不填则默认无放大 */private String emphasiseyword;//get set 省略}2.获取token
public class AccessTokenRequestHandler extends RequestHandler {public AccessTokenRequestHandler(HttpServletRequest request,HttpServletResponse response) {super(request, response);}private static String access_token = "";/** * 获取小程序凭证access_token * @return */public static String getMinAccessToken() {if ("".equals(access_token)) {// 如果为空直接获取return getMinTokenReal();}if (tokenIsExpire(access_token)) {// 如果过期重新获取return getMinTokenReal();}return access_token;}/** * 实际获取小程序access_token的方法 * @return */protected static String getMinTokenReal() {//获取token所需参数url,grant_type,appid,appsecret用自己的String requestUrl = TOKENURL + "?grant_type=" +GRANT_TYPE + "&appid="+ APPID + "&secret=" + APPSECRET;String resContent = "";TenpayHttpClient httpClient = new TenpayHttpClient();httpClient.setMethod("GET");httpClient.setReqContent(requestUrl);if (httpClient.call()) {resContent = httpClient.getResContent();if (resContent.indexOf(ConstantUtil.ACCESS_TOKEN) > 0) {access_token = JsonUtil.getJsonValue(resContent, ConstantUtil.ACCESS_TOKEN);} else {System.out.println("获取access_token值返回错误!!!");}} else {System.out.println("后台调用通信失败");System.out.println(httpClient.getResponseCode());System.out.println(httpClient.getErrInfo());// 有可能因为网络原因,请求已经处理,但未收到应答。}return access_token;}}3.发起https请求并获取结果
public class WeixinUtil {private static Logger log = LoggerFactory.getLogger(WeixinUtil.class); /** * 发起https请求并获取结果 * * @param requestUrl 请求地址 * @param requestMethod 请求方式(GET、POST) * @param outputStr 提交的数据 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) */ public static String httpRequest(String requestUrl, String requestMethod, String outputStr) { StringBuffer buffer = new StringBuffer(); try { // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection(); httpUrlConn.setSSLSocketFactory(ssf); httpUrlConn.setDoOutput(true); httpUrlConn.setDoInput(true); httpUrlConn.setUseCaches(false); // 设置请求方式(GET/POST) httpUrlConn.setRequestMethod(requestMethod); if ("GET".equalsIgnoreCase(requestMethod)) httpUrlConn.connect(); // 当有数据需要提交时 if (null != outputStr) { OutputStream outputStream = httpUrlConn.getOutputStream(); // 注意编码格式,防止中文乱码 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 将返回的输入流转换成字符串 InputStream inputStream = httpUrlConn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } bufferedReader.close(); inputStreamReader.close(); // 释放资源 inputStream.close(); inputStream = null; httpUrlConn.disconnect(); } catch (ConnectException ce) { log.error("Weixin server connection timed out."); } catch (Exception e) { log.error("https request error:{}", e); } return buffer.toString(); } }4.发送
public class WXMsgRun {public static TemplateMessage TemplateMessage(String opinid, String pagepath, String formId,Map<String, TemplateData> data, String emphasiseyword) {TemplateMessage templateMessage = new TemplateMessage();templateMessage.setTouser(opinid);templateMessage.setPagepath(pagepath);templateMessage.setFormId(formId);templateMessage.setData(data);templateMessage.setEmphasiseyword(emphasiseyword);return templateMessage;}/** * */public static void sendOrderPayMessage(String... 相关模板字段的值自己配) {Map<String, TemplateData> data = new HashMap<String, TemplateData>();data.put("keyword1", new TemplateData(xxxxx, null));data.put("keyword2", new TemplateData(yyyyy, null));sendMessage(opinid, page, data, formId, null);}/** * * @param opinid 被推送用户的openid* @param page 消息推送后小程序跳转的页面路径* @param data 封装的主体数据* @param formId 小程序提交的表单id* @param emphasiseyword 需要强调的关键字段 格式为 "keyword1.DATA" */public static void sendMessage(String opinid,String page,Map<String, TemplateData> data, String formId, String emphasiseyword) {sendWechatMsgToUser(opinid, page, formId, data, emphasiseyword);}private static void sendWechatMsgToUser(TemplateMessage templateMessage) {WXSendMsgJob job = new WXSendMsgJob(TemplateMessage);//我的方法用线程处理,也可不用,只是个demoThreadPoolManager.getInstance().addExecuteTask(job);}}public class WXMessageUtil {private static Logger log = LoggerFactory.getLogger(WXMessageUtil.class);public static JSONObject dataJsonmsg(Map<String, TemplateData> data) { JSONObject json = new JSONObject(); for (Map.Entry<String,TemplateData> entry : data.entrySet()) { JSONObject keyJson = new JSONObject(); TemplateData dta= entry.getValue(); keyJson.put("value",dta.getValue()); keyJson.put("color", dta.getColor()); json.put(entry.getKey(), keyJson); } return json; }/** * 发送微信消息(模板消息) * * @param touser 用户 OpenID * @param templatId 模板消息ID * @return */public static JSONObject sendWechatMsgToUser(String touser, String templatId, String page, String formId, Map<String, TemplateData> data, String emphasiseyword) {//String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="//+ AccessTokenRequestHandler.getAccessToken();String url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token="+ AccessTokenRequestHandler.getMinAccessToken();JSONObject json = new JSONObject();JSONObject jsonDataMsg = dataJsonmsg(data);json.put("touser", touser);json.put("template_id", templatId);json.put("page", page);json.put("form_id", formId);json.put("data", jsonDataMsg);json.put("emphasis_keyword", emphasiseyword);System.out.println("post数据包"+json.toString());JSONObject parseObject = null;try {String requestMethod = "POST";String result = WeixinUtil.httpRequest(url, requestMethod, json.toString());parseObject = JSON.parseObject(result);log.info("发送微信消息返回信息:" + parseObject);log.info("发送微信消息返回信息编码:" + parseObject.get("errcode"));String errmsg = (String) parseObject.get("errmsg"); log.info("获取模板编号返回信息:" + errmsg);if (!"ok".equals(errmsg)) { // 如果为errmsg为ok,则代表发送成功log.info("失败信息" + parseObject.toJSONString());//失败处理}} catch (Exception e) {e.printStackTrace();}return parseObject;}}微信小程序













