看着大家用公众号推消息推得不亦乐乎, 心里痒痒吧, 那就进来了解一下吧.
一, 提前准备: 公网服务器, 备案域名.
二, 先申请微信公众号, 如果你申请的是个人订阅号, 那么模板消息推送就没法进行了, 所以我们需要申请一个微信公众号测试账号. 如何操作, 请百度之.
三, 大概原理: 我们拿着账号的 appId 和 appSecret 就可以调用微信的接口, 获取一个叫做 access_token 的东西了, 然后剩余大部分接口, 我们拿着 access_token, 调取相应的微信接口就好了.
接下来以测试账号为例来说明:
我们可以看到测试号的 appId 和 appSecret:
image.PNG
这两个参数保管好, 不要泄露.
四, 配置服务器 url
在配置之前往先要开发对应的接口, 用以接收微信的请求:
- @Controller
- public class WxController {
- Logger logger = LoggerFactory.getLogger(WxController.class);
- @Autowired
- private WxConfig wxConfig;
- @RequestMapping("/wx")
- @ResponseBody
- public String responseWx(HttpServletRequest request){
- Map<String, String[]> parametersMap = request.getParameterMap();
- StringBuilder sb = new StringBuilder();
- for(Map.Entry<String, String[]> entry:parametersMap.entrySet()){
- sb.append(entry.getKey()).append(":").append(String.join(",",entry.getValue())).append(",");
- }
- logger.info("收到微信的消息:"+sb.toString());
- String returnStr = null;
- if(parametersMap.containsKey("signature")
- &¶metersMap.containsKey("timestamp")
- &¶metersMap.containsKey("nonce")
- &¶metersMap.containsKey("echostr")){// 微信 token 认证
- String signature = parametersMap.get("signature")[0];
- String timestamp = parametersMap.get("timestamp")[0];
- String nonce = parametersMap.get("nonce")[0];
- String echostr = parametersMap.get("echostr")[0];
- String[] arr = new String[]{wxConfig.token, timestamp, nonce};
- sort(arr);
- StringBuilder content = new StringBuilder();
- for (int i = 0; i <arr.length; i++) {
- content.append(arr[i]);
- }
- String mySignature = SHA1.encode(content.toString());
- if(mySignature.equalsIgnoreCase(signature)){
- returnStr = echostr;
- }
- }
- logger.info("返回给微信的消息:"+returnStr);
- return returnStr;
- }
- }
SHA1 校验的部分:
- public class SHA1 {
- /**
- * 加密
- * @param content
- * @return
- */
- public static String encode(String content) {
- if (content == null) {
- return null;
- }
- MessageDigest md = null;
- try {
- md = MessageDigest.getInstance("SHA-1");
- // 将三个参数字符串拼接成一个字符串进行 sha1 加密
- byte[] digest = md.digest(content.getBytes());
- return byteToStr(digest);
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
- return null;
- }
- /**
- * 将字节数组转换为十六进制字符串
- *
- * @param byteArray
- * @return
- */
- private static String byteToStr ( byte[] byteArray){
- String strDigest = "";
- for (int i = 0; i < byteArray.length; i++) {
- strDigest += byteToHexStr(byteArray[i]);
- }
- return strDigest;
- }
- /**
- * 将字节转换为十六进制字符串
- *
- * @param mByte
- * @return
- */
- private static String byteToHexStr ( byte mByte){
- char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
- char[] tempArr = new char[2];
- tempArr[0] = Digit[(mByte>>> 4) & 0X0F];
- tempArr[1] = Digit[mByte & 0X0F];
- String s = new String(tempArr);
- return s;
- }
- }
填写服务器的 url, 用来接收微信的认证消息, 其实就是微信给你的服务器发个消息, 你做出对应的响应, 微信就认为服务器是通的.
配置需要注意的是需要是: 如果是 http, 那么服务的端口必须是 80 端口, 如果是 https, 则是 443 端口:
image.PNG
五, 配置 JS 接口安全域名
如果模板消息有更多复杂的内容需要展示, 我们是无法一次性发送给微信进行展示的, 因此点击消息的详情, 就会跳入我们的页面. 不能谁的页面都跳转, 那不安全, 所以你要设置一下, 才给你跳.
image.PNG
六, 获取 access_token
- /**
- * 获取 accessToken
- *
- * @return
- * @throws ParseException
- * @throws IOException
- */
- public static String getAccessToken(String appId,String appSecret) {
- if(appId==null||appId.trim().isEmpty()){
- throw new RuntimeException("appId 为空");
- }
- if(appSecret==null||appSecret.trim().isEmpty()){
- throw new RuntimeException("appSecret 为空");
- }
- try {
- // 如果是空的, 或者超时, 刷新 access_token
- if (StringUtil.isEmpty(WxBean.ACCESS_TOKEN) || System.currentTimeMillis()>= WxBean.TOKEN_TIME_OUT) {
- String url = ACCESS_TOKEN_URL.replace("APP_ID", appId).replace("APP_SECRET", appSecret);
- // TODO 后期删除该日志 敏感信息
- logger.info("获取 access_token 的发送:"+url);
- String result = HttpUtil.doGet(url);
- logger.info("获取 access_token 的接口返回:"+result);
- if(result!=null&&!result.trim().isEmpty()){
- JSONObject jsonObject = JSONObject.parseObject(result);
- WxBean.ACCESS_TOKEN = jsonObject.getString("access_token");
- WxBean.TOKEN_TIME_OUT = System.currentTimeMillis() + (ACCESS_TOKEN_TIMEOUT_SECOND * 1000);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return WxBean.ACCESS_TOKEN;
- }
- /**
- * get 请求
- *
- * @param url
- * @return
- */
- public static String doGet(String url) {
- CloseableHttpResponse response = null;
- String result = null;
- try {
- CloseableHttpClient httpclient = HttpClients.createDefault();
- HttpGet httpGet = new HttpGet(url);
- response = httpclient.execute(httpGet);
- HttpEntity entity = response.getEntity();
- if (entity != null) {
- result = EntityUtils.toString(entity, "UTF-8");
- }
- EntityUtils.consume(entity);
- }catch (Exception e){
- e.printStackTrace();
- } finally {
- try {
- response.close();
- }catch (Exception e2){
- e2.printStackTrace();
- }
- }
- return result;
- }
- /**
- * POST 请求
- *
- */
- public static String doPost(String url, String msg){
- CloseableHttpResponse response = null;
- String result = null;
- try {
- CloseableHttpClient httpclient = HttpClients.createDefault();
- HttpPost httpPost = new HttpPost(url);
- httpPost.setEntity(new StringEntity(msg, "UTF-8"));
- response = httpclient.execute(httpPost);
- HttpEntity entity = response.getEntity();
- result = EntityUtils.toString(response.getEntity(), "UTF-8");
- EntityUtils.consume(entity);
- }catch (Exception e){
- e.printStackTrace();
- } finally {
- try {
- response.close();
- }catch (Exception e2){
- e2.printStackTrace();
- }
- }
- return result;
- }
六, 关注测试号
拿起你的手机, 扫一扫二维码, 我们就关注了该测试号, 当然界面很丑, 不管了. 现在右边就出现了微信号, 这个就是你的 openId. 不用苦苦的使用 JS-sdk 获取, 也不用调用用户列表接口, 就获取到了 openId. 当然这是测试号, 正式的可能情况有所不同.
image.PNG
七, 新建一个模板, 发送消息
模板:
标题随便写一个, 模板的地方值的注意的是, 如果觉得行间距太小, 不美观, 可以加空行.
image.PNG
建立模板之后, 我们就获取到了模板的 id. 现在万事俱备, 我们来发一个模板消息吧:
- @RequestMapping("/wxPushMsg")
- @ResponseBody
- public String wxPushMsg(){
- logger.info("推送模板消息");
- String accessToken = WxUtil.getAccessToken(wxConfig.appId,wxConfig.appSecret);
- logger.info("获取的 access_token 为:"+accessToken);
- String openId = "xxx";
- String templateId ="xxxxxxxxx";
- String url ="https://www.fantasyworldforyou.com/#/index";
- // 微信推送
- JSONObject jsonObject = new JSONObject();
- JSONObject data = new JSONObject();
- jsonObject.put("data",data);
- JSONObject msg1 = new JSONObject();// 内容值
- data.put("msg1", msg1);
- JSONObject msg2 = new JSONObject();// 内容值
- data.put("ms2", msg2);
- jsonObject.put("touser", openId);
- jsonObject.put("topcolor", "#FF0000");
- // 给楼栋管理员推送统计信息
- jsonObject.put("url", url+"?date="+ UuidUtil.getUUID());
- jsonObject.put("template_id", templateId);
- msg1.put("value", "你好 世界");
- msg1.put("color", "#173177");
- msg2.put("value", "哈哈哈");
- msg2.put("color", "#173177");
- String result = WxUtil.sendTemplateMessage(accessToken,jsonObject.toString());
- logger.info("返回:"+result);
- return result;
- }
- /**
- * 发送微信模板消息
- *
- * @param message
- * @return
- * @throws ParseException
- * @throws IOException
- */
- public static String sendTemplateMessage(String accessToken, String message) {
- String result = null;
- if(accessToken==null||accessToken.trim().isEmpty()){
- throw new RuntimeException("accessToken 为空");
- }
- String url = SEND_TEMPLATE_MESSAGE_URL.replace("ACCESS_TOKEN", accessToken);
- try {
- logger.info("发送微信模板消息消息体:"+message);
- result = HttpUtil.doPost(url, message);
- logger.info("发送微信模板消息返回:"+result);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return result;
- }
现在打开手机, 你会看到一个推送消息:
点击还可以查看详情, 就是我们自己的页面.
来源: http://www.jianshu.com/p/e1a913ee6d02