赞
踩
模板根据需求设置(注意:参数长度不能超出微信规定,否则将发送失败)
参数要求规则
依赖
<!--json——jar--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.54</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.5.6</version> </dependency> <!-- httpRequest --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.4.1</version> </dependency> <dependency> <groupId>commons-httpclient</groupId> <artifactId>commons-httpclient</artifactId> <version>3.1</version> </dependency>
请求地址、appid、密钥等信息;信息配置到application配置中,方便统一管理;
package com.andon.wxPush.conf; import lombok.Data; import org.springframework.stereotype.Service; import org.springframework.beans.factory.annotation.Value; /** * @Description: 读取 Properties配置信息的类 */ @Service("wxConfiguration") @Data public class WxConfiguration { //获取微信access_token请求地址 @Value("${wxConfig.url.WX_ACCESS_TOKEN_URL}") private String wxAccessTokenUrl; //发送微信公众号模板消息请求地址 @Value("${wxConfig.url.SEND_MESSAGE_TEMPLATE_URL}") private String sendMessageTemplateUrl; //小程序唯一凭证,即 AppID @Value("${wxConfig.appid}") private String appId; //小程序唯一凭证密钥,即 AppSecret @Value("${wxConfig.secret}") private String secret; //模板id @Value("${wxConfig.templateId}") private String templateId; }
发送请求工具类
package com.andon.wxPush.utils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.andon.wxPush.template.HttpResult; import com.google.common.base.Splitter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.LaxRedirectStrategy; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.Map; import static org.apache.tomcat.util.file.ConfigFileLoader.getURI; @Component @Slf4j public class HttpUtils { public HttpResult stringPostJson(String path, String content) throws Exception{ return stringPost(path, null, content, "utf-8", "utf-8", "application/json"); } public HttpResult stringPost(String path, Map<String,String> headerMap, String content, String contentencode, String encode, String contentType) throws Exception{ StringEntity entity = new StringEntity(content, contentencode); entity.setContentType(contentType); return post(path, headerMap, entity, encode); } private HttpResult post(String path, Map<String,String> headerMap, HttpEntity entity, String encode){ HttpResult httpResult = new HttpResult(); CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; try{ HttpPost httpPost = new HttpPost(getURI(path)); LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy(); httpClient = HttpClientBuilder.create().setRedirectStrategy(redirectStrategy).build(); RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(120000) .setConnectTimeout(120000) .setConnectionRequestTimeout(120000) .setCircularRedirectsAllowed(true) .setRedirectsEnabled(true) .setMaxRedirects(5) .build(); httpPost.setConfig(requestConfig); // httpPost.setHeader("User-Agent", header); if(headerMap != null && headerMap.size() > 0){ for(String name:headerMap.keySet()) { httpPost.addHeader(name, headerMap.get(name)); } } httpPost.setEntity(entity); response = httpClient.execute(httpPost); httpResult.setStatus(response.getStatusLine().getStatusCode()); if(httpResult.getStatus() == 200){ HttpEntity resEntity = response.getEntity(); httpResult.setBody(EntityUtils.toString(resEntity, encode)); } }catch(Exception ex){ log.error("post请求出错", ex); }finally{ try{ if(response != null){ response.close(); } if(httpClient != null){ httpClient.close(); } }catch(Exception ex) { log.error("post请求关闭资源出错", ex); } } return httpResult; } public JSONObject stringGetJson(String url) { JSONObject jsonObject = null; //通过HttpClients.createDefault()获取到CloseableHttpClient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); //创建HttpGet 对象,参数为请求的地址 HttpGet method = new HttpGet(url); try { //执行方法请求接口得到响应 HttpResponse response = httpclient.execute(method); //解析响应数据 String content = EntityUtils.toString(response.getEntity(), "UTF-8"); //转为json格式 jsonObject = JSON.parseObject(content); EntityUtils.consume(response.getEntity());//完全消耗 } catch (Exception e) { log.error("get请求出错", e); e.printStackTrace(); } finally { try { //释放连接 method.releaseConnection(); httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } return jsonObject; } }
json处理工具类
package com.andon.wxPush.utils; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import java.text.SimpleDateFormat; @Slf4j public class JsonUtils { private static ObjectMapper json; static { json = new ObjectMapper(); json.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); json.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } /** * 序列化为JSON字符串 */ public static String ObjectToString(Object object) { try { return (json.writeValueAsString(object)); } catch (Exception e) { log.error("序列化为JSON字符串出错",e); } return null; } public static <T> T getObject(String jsonString, Class<T> clazz) { if (StringUtils.isEmpty(jsonString)) return null; try { return json.readValue(jsonString, clazz); } catch (Exception e) { log.error("将JSON字符串转化为Map出错",e); return null; } } }
消息模板
package com.andon.wxPush.template; import lombok.Data; import java.util.Map; import java.util.TreeMap; @Data public class WxSendMessageTemplate { /** * 接收者openId */ private String touser; /** * 模板ID */ private String template_id; /** * 模板跳转链接 */ private String url; /** * 模板跳转链接 */ private Map<String,String> miniprogram; /** * 消息data */ private TreeMap<String, TreeMap<String, String>> data; /** * 参数 * * @param value 值 * @param color 颜色 * @return params */ public static TreeMap<String, String> item(String value, String color) { TreeMap<String, String> params = new TreeMap<String, String>(); params.put("value", value); params.put("color", color); return params; } }
结果模板
package com.andon.wxPush.template;
import lombok.Data;
@Data
public class HttpResult {
private Integer status = 601;
private String body;
}
消息推送
package com.andon.wxPush.service.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.andon.util.DateUtil; import com.andon.wxPush.conf.WxConfiguration; import com.andon.wxPush.service.WxSendMsgService; import com.andon.wxPush.template.HttpResult; import com.andon.wxPush.template.WxSendMessageTemplate; import com.andon.wxPush.utils.HttpUtils; import com.andon.wxPush.utils.JsonUtils; import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.util.Date; import java.util.Map; import java.util.TreeMap; @Service @Slf4j public class WxSendMsgServiceImpl implements WxSendMsgService { //凭证有效时间 private static final String KEY_EXPIRES_IN = "expiresIn"; // private static final String KEY_TOKEN = "accessToken"; //拼接缓存前缀 private static final String ACCESS_TOKEN_KEY_PREFIX = "AccessToken_"; @Resource private WxConfiguration wxConfiguration; @Resource private HttpUtils httpUtils; /** * accessToken缓存 */ private static Map<String, Map<String, Object>> accessTokenMap = Maps.newConcurrentMap(); /** * 推送模板 * @param templateMsg * @return */ @Override public JSONObject noticeTemplate(JSONObject templateMsg) { // 模版ID String templateId = wxConfiguration.getTemplateId(); TreeMap<String, TreeMap<String, String>> params = new TreeMap<>(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //微信公众号根据具体模板参数组装 params.put("keyword4", WxSendMessageTemplate.item(sdf.format(new Date()), "#000000")); //告警时间 params.put("keyword3", WxSendMessageTemplate.item(templateMsg.getString("andonName"), "#000000")); //报警类型 params.put("keyword1", WxSendMessageTemplate.item(templateMsg.getString("equipmentName"), "#000000")); //设备名称 params.put("keyword2", WxSendMessageTemplate.item(templateMsg.getString("installPlace"), "#000000")); //设备位置 params.put("first", WxSendMessageTemplate.item(templateMsg.getString("andonContent"), "#000000")); //告警内容 WxSendMessageTemplate wxTemplateMsg = new WxSendMessageTemplate(); // 模版ID wxTemplateMsg.setTemplate_id(templateId); // openId wxTemplateMsg.setTouser(templateMsg.getString("openId")); // 关键字赋值 wxTemplateMsg.setData(params); String data = JsonUtils.ObjectToString(wxTemplateMsg); System.out.println(data); return this.handleSendMsgLog(data); } //捕获异常 private JSONObject handleSendMsgLog(String data) { JSONObject resultDto = new JSONObject(); try { resultDto = this.sendTemplateMsg(data); System.out.println("handleSendMsgLog:" + resultDto.toJSONString()); } catch (Exception exception) { log.error("发送微信模版失败", exception); } // TODO 可以记录一下发送记录的日志 return resultDto; } //发送模板 public JSONObject sendTemplateMsg(String data) throws Exception { // 获取token JSONObject accessTokenRes = this.getAccessToken(); String accessToken = accessTokenRes.getString("access_token"); // 发送消息 HttpResult httpResult = null; try { httpResult = httpUtils.stringPostJson(wxConfiguration.getSendMessageTemplateUrl() + accessToken, data); } catch (Exception e) { e.printStackTrace(); } return JSON.parseObject(httpResult.getBody()); } /** * 获取全局access_token */ public JSONObject getAccessToken() { //拼接获取缓存key String key = ACCESS_TOKEN_KEY_PREFIX.concat(wxConfiguration.getAppId()).concat(wxConfiguration.getSecret()); Map<String, Object> accessTokenJson = accessTokenMap.get(key); if (accessTokenJson != null) { long expiresIn = (Long) accessTokenJson.get(KEY_EXPIRES_IN); if (System.currentTimeMillis() < expiresIn) { return (JSONObject) accessTokenJson.get(KEY_TOKEN); } accessTokenMap.remove(key); } synchronized (this) { accessTokenJson = accessTokenMap.get(key); // 多线程环境下,其他线程可能已经获得最新corpAccessToken,直接返回 if (accessTokenJson != null) { return (JSONObject) accessTokenJson.get(KEY_TOKEN); } String url = String.format(wxConfiguration.getWxAccessTokenUrl(), wxConfiguration.getAppId(), wxConfiguration.getSecret()); JSONObject resJson = httpUtils.stringGetJson(url); if (resJson != null && StringUtils.isNotEmpty(resJson.getString("access_token"))) { accessTokenJson = this.seAccessToken(resJson); } if (accessTokenJson == null) { try { throw new Exception(); } catch (Exception e) { log.error("设置access_token缓存失败"); e.printStackTrace(); } } //放入缓存中 accessTokenMap.put(key, accessTokenJson); JSONObject accessTokenJsonRes = (JSONObject) accessTokenJson.get(KEY_TOKEN); if (accessTokenJsonRes == null) { try { throw new Exception(); } catch (Exception e) { log.error("获取access_token错误"); e.printStackTrace(); } } return accessTokenJsonRes; } } //设置access_token private Map<String, Object> seAccessToken(JSONObject jsonObject) { Map<String, Object> token = Maps.newHashMap(); // 减去3分钟,以免过时 token.put(KEY_EXPIRES_IN, (jsonObject.getLongValue("expires_in") - 3 * 60) * 1000 + System.currentTimeMillis()); token.put(KEY_TOKEN, jsonObject); return token; } }
发送测试
微信公众号接收效果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。