微信消息推送开发

随着微信使用越来越广泛,因其也产生了许多二次开发的小功能,今天要介绍的就是微信服务号的中的消息模板推送。

 

添加模板消息方式如上面,如果不满足可以添加自定义的,但是需要审核,周期为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);
            }
        }
    }
View Code
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;
    }
}
View Code

这里需要注意的是,微信获取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;
    }
}
View Code
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);
    }
View Code

这样我们就可以获取到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";
    }
View Code

这样就发送成功了,返回成的结果为:{"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;
    }
}
View Code
// 将对象转成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;
    }
View Code

在这过程中也遇到一些问题,其中最难的是遇到{"errcode":48001,"errmsg":"api unauthorized hint: [L5EA1a05308051!]"}这个错误,一开始以为没有微信没有认证,但去看了以及认证了,也有该接口权限,一直再找问题出现在哪。最后发现是调用错接口了。

 

这是第一次开发这个功能,如果不正确的地方,请指正,谢谢!

 

posted @ 2019-01-28 10:32  静喧  阅读(7362)  评论(0编辑  收藏  举报