博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java微信公众平台开发_03_消息管理之被动回复消息
阅读量:6372 次
发布时间:2019-06-23

本文共 42921 字,大约阅读时间需要 143 分钟。

GitHub源码:https://github.com/shirayner/weixin_gz

一、本节要点

1.回调url

上一节,我们启用服务器配置的时候,填写了一个服务器地址(url),如下图,这个url就是回调url,是开发者用来接收微信消息和事件的接口URL 。也就是说,用户在微信公众号中发送的消息会被推送到这个回调url,而我们可以接收用户的消息,并进行回复。

 

 

2.被动回复消息的流程

官方文档:

 

我们在上一节中设置的消息加解密方式是安全模式。因此在用户发给公众号的消息(接收消息)以及公众号被动回复用户消息(回复消息)都会加密,

流程

用户发送消息之后,微信服务器将消息传递给 第三方服务器,第三方服务器接收到消息后,再对消息做出相应的回复消息。

接收消息:需先从request请求对象的输入流中获取请求参数和已加密的请求消息,再对已加密的请求消息进行解密操作,即可获得明文。

                  然后就行对明文消息的业务处理了。

回复消息:封装好回复消息后,需先对回复消息进行加密,获得已已加密消息,然后再通过http请求调用被动回复消息的接口,来发送消息。

 

 

3.被动回复消息加解密

3.1接收消息的  解密

 (1)从请求的输入流中获取加密的请求消息

//1.获取加密的请求消息:使用输入流获得加密请求消息postData            ServletInputStream in = request.getInputStream();            BufferedReader reader =new BufferedReader(new InputStreamReader(in));              String tempStr="";   //作为输出字符串的临时串,用于判断是否读取完毕              while(null!=(tempStr=reader.readLine())){                  postData+=tempStr;              }              logger.info("postData:"+postData);
View Code

(2)对加密的请求消息进行解密获得明文 

WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(Env.TOKEN,Env.ENCODING_AES_KEY,Env.APP_ID);                result=wxcpt.DecryptMsg(msgSignature, timeStamp, nonce, postData);
View Code

(3)解密算法

直接调用微信官方的 WXBizMsgCrypt 类的 DecryptMsg(String, String, String, String) 方法即可。

 

3.2 回复消息的加密

直接用官方加解密工具类。

wxcpt = new WXBizMsgCrypt(Env.TOKEN,Env.ENCODING_AES_KEY,Env.APP_ID);                replyMsg=wxcpt.EncryptMsg(replyMsg, timeStamp, nonce);
View Code

 

4.消息对象的封装

根据官方文档消息的xml传输格式,我们可以将消息封装成对象。请参见后面的代码实现部分

 

5.数据传输—对象 转成  xml字符串

 根据官方文档,数据是以XML数据包的形式进行传输的。因此,我们需要

(1)解析微信发来的请求(xmlStr),从xml字符串中获取需要的信息

(2)回复消息时,将消息对象转成xml字符串。

 

我们是使用dom4j,xstream来进行这个转换的,因此需要导入jar包,maven依赖如下:

dom4j
dom4j
1.6.1
com.thoughtworks.xstream
xstream
1.4.10

 

具体请参见代码实现的 MessageUtil 部分。

5.1  解析微信发来的请求(XML),获取请求参数 

/**     * @desc :1.解析微信发来的请求(XML),获取请求参数      *       * @param request     * @return     * @throws Exception Map
*/ public static Map
parseXml(HttpServletRequest request) throws Exception { // 将解析结果存储在HashMap中 Map
map = new HashMap
(); // 从request中取得输入流 InputStream inputStream = request.getInputStream(); // 读取输入流 SAXReader reader = new SAXReader(); Document document = reader.read(inputStream); // 得到xml根元素 Element root = document.getRootElement(); // 得到根元素的所有子节点 List
elementList = root.elements(); // 遍历所有子节点 for (Element e : elementList) map.put(e.getName(), e.getText()); // 释放资源 inputStream.close(); inputStream = null; return map; }
View Code

 

5.2 将文本消息转成xml字符串

/**      * 2.文本消息对象转换成xml      *       * @param textMessage 文本消息对象      * @return xml      */      public static String textMessageToXml(TextMessage textMessage) {          xstream.alias("xml", textMessage.getClass());          return xstream.toXML(textMessage);      }
View Code

 

 

 二、代码实现

1.微信配置类—Env.java

微信公众号接入配置类

package com.ray.weixin.gz.config;/**@desc  : 微信公众号接入配置 *  * @author: shirayner * @date  : 2017年9月27日 下午4:57:36 */public class Env {    /**     * 1. 企业应用接入秘钥相关     */   // public static final String APP_ID = "wx4ddse2334debebef2cc";    //public static final String APP_SECRET = "068e2599abf88ba72frrgbfs6f3c56e";      //测试号    public static final String APP_ID = "wxa00642deff56g062";    public static final String APP_SECRET = "fcc96fefdgdhtj1a46af7993784917";        /**     * 2.服务器配置:     * 启用并设置服务器配置后,用户发给公众号的消息以及开发者需要的事件推送,将被微信转发到该URL中     */    public static final String TOKEN = "weixin";    public static final String ENCODING_AES_KEY = "JvJ1Dww6tjUU2psC3pdewegreHfovfWP3LfX1xrriz1";              }
View Code

 

 

2.HTTP请求工具类—HttpHelper.java

package com.ray.weixin.gz.util;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import org.apache.http.Consts;import org.apache.http.Header;import org.apache.http.HeaderElement;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.HttpStatus;import org.apache.http.NameValuePair;import org.apache.http.client.config.RequestConfig;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.FileEntity;import org.apache.http.entity.StringEntity;import org.apache.http.entity.mime.MultipartEntityBuilder;import org.apache.http.entity.mime.content.FileBody;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.protocol.BasicHttpContext;import org.apache.http.util.EntityUtils;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;/** * HTTP请求封装,建议直接使用sdk的API */public class HttpHelper {    /**     * @desc :1.发起GET请求     *       * @param url     * @return JSONObject     * @throws Exception      */    public static JSONObject doGet(String url) throws Exception {        //1.生成一个请求        HttpGet httpGet = new HttpGet(url);        //2.配置请求的属性        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();//2000        httpGet.setConfig(requestConfig);        //3.发起请求,获取响应信息            //3.1 创建httpClient         CloseableHttpClient httpClient = HttpClients.createDefault();        CloseableHttpResponse response = null;        try {            //3.2 发起请求,获取响应信息                response = httpClient.execute(httpGet, new BasicHttpContext());            //如果返回结果的code不等于200,说明出错了              if (response.getStatusLine().getStatusCode() != 200) {                System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()                        + ", url=" + url);                return null;            }            //4.解析请求结果            HttpEntity entity = response.getEntity();      //reponse返回的数据在entity中             if (entity != null) {                String resultStr = EntityUtils.toString(entity, "utf-8");  //将数据转化为string格式                  System.out.println("GET请求结果:"+resultStr);                JSONObject result = JSON.parseObject(resultStr);    //将String转换为 JSONObject                if(result.getInteger("errcode")==null) {                    return result;                }else if (0 == result.getInteger("errcode")) {                    return result;                }else {                    System.out.println("request url=" + url + ",return value=");                    System.out.println(resultStr);                    int errCode = result.getInteger("errcode");                    String errMsg = result.getString("errmsg");                    throw new Exception("error code:"+errCode+", error message:"+errMsg);                 }            }        } catch (IOException e) {            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());            e.printStackTrace();        } finally {            if (response != null) try {                response.close();                     //释放资源            } catch (IOException e) {                e.printStackTrace();            }        }        return null;    }    /** 2.发起POST请求     * @desc :     *       * @param url   请求url     * @param data  请求参数(json)     * @return     * @throws Exception JSONObject     */    public static JSONObject doPost(String url, Object data) throws Exception {        //1.生成一个请求        HttpPost httpPost = new HttpPost(url);        //2.配置请求属性        //2.1 设置请求超时时间        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(100000).build();        httpPost.setConfig(requestConfig);        //2.2 设置数据传输格式-json        httpPost.addHeader("Content-Type", "application/json");        //2.3 设置请求实体,封装了请求参数        StringEntity requestEntity = new StringEntity(JSON.toJSONString(data), "utf-8");        httpPost.setEntity(requestEntity);        //3.发起请求,获取响应信息            //3.1 创建httpClient         CloseableHttpClient httpClient = HttpClients.createDefault();        CloseableHttpResponse response = null;        try {            //3.3 发起请求,获取响应            response = httpClient.execute(httpPost, new BasicHttpContext());            if (response.getStatusLine().getStatusCode() != 200) {                System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()                        + ", url=" + url);                return null;            }            //获取响应内容            HttpEntity entity = response.getEntity();            if (entity != null) {                String resultStr = EntityUtils.toString(entity, "utf-8");                System.out.println("POST请求结果:"+resultStr);                //解析响应内容                JSONObject result = JSON.parseObject(resultStr);                if(result.getInteger("errcode")==null) {                    return result;                }else if (0 == result.getInteger("errcode")) {                    return result;                }else {                    System.out.println("request url=" + url + ",return value=");                    System.out.println(resultStr);                    int errCode = result.getInteger("errcode");                    String errMsg = result.getString("errmsg");                    throw new Exception("error code:"+errCode+", error message:"+errMsg);                 }            }        } catch (IOException e) {            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());            e.printStackTrace();        } finally {            if (response != null) try {                response.close();              //释放资源            } catch (IOException e) {                e.printStackTrace();            }        }        return null;    }    /**     * @desc : 3.上传文件     *       * @param url   请求url     * @param file  上传的文件     * @return     * @throws Exception JSONObject     */    public static JSONObject uploadMedia(String url, File file) throws Exception {        HttpPost httpPost = new HttpPost(url);        CloseableHttpResponse response = null;        CloseableHttpClient httpClient = HttpClients.createDefault();        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();        httpPost.setConfig(requestConfig);                //2.3 设置请求实体,封装了请求参数        HttpEntity requestEntity = MultipartEntityBuilder.create().addPart("media",                new FileBody(file, ContentType.create("multipart/form-data", Consts.UTF_8), file.getName())).build();        //FileEntity requestEntity = new FileEntity(file,ContentType.MULTIPART_FORM_DATA);        httpPost.setEntity(requestEntity);        try {            response = httpClient.execute(httpPost, new BasicHttpContext());            if (response.getStatusLine().getStatusCode() != 200) {                System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()                        + ", url=" + url);                return null;            }            HttpEntity entity = response.getEntity();            if (entity != null) {                String resultStr = EntityUtils.toString(entity, "utf-8");                JSONObject result = JSON.parseObject(resultStr);                //上传临时素材成功                if (result.getString("errcode")== null) {                    // 成功                    //result.remove("errcode");                    //result.remove("errmsg");                    return result;                } else {                    System.out.println("request url=" + url + ",return value=");                    System.out.println(resultStr);                    int errCode = result.getInteger("errcode");                    String errMsg = result.getString("errmsg");                    throw new Exception("error code:"+errCode+", error message:"+errMsg);                 }            }        } catch (IOException e) {            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());            e.printStackTrace();        } finally {            if (response != null) try {                response.close();                  //释放资源            } catch (IOException e) {                e.printStackTrace();            }        }        return null;    }    /**     * @desc : 上传PDF     * 见微信电子发票章节     * 9. 向用户提供发票或其它消费凭证PDF     *       * @param url     * @param file     * @return     * @throws Exception      *   JSONObject     */    public static JSONObject uploadPDF(String url, File file) throws Exception {        HttpPost httpPost = new HttpPost(url);        CloseableHttpResponse response = null;        CloseableHttpClient httpClient = HttpClients.createDefault();        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();        httpPost.setConfig(requestConfig);                //2.3 设置请求实体,封装了请求参数        HttpEntity requestEntity = MultipartEntityBuilder.create().addPart("media",                new FileBody(file, ContentType.create("multipart/form-data", Consts.UTF_8), file.getName())).build();        httpPost.setEntity(requestEntity);        try {            response = httpClient.execute(httpPost, new BasicHttpContext());            if (response.getStatusLine().getStatusCode() != 200) {                System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()                        + ", url=" + url);                return null;            }            HttpEntity entity = response.getEntity();            if (entity != null) {                String resultStr = EntityUtils.toString(entity, "utf-8");                JSONObject result = JSON.parseObject(resultStr);                //上传临时素材成功                if (result.getString("errcode")== null) {                    // 成功                    //result.remove("errcode");                    //result.remove("errmsg");                    return result;                } else {                    System.out.println("request url=" + url + ",return value=");                    System.out.println(resultStr);                    int errCode = result.getInteger("errcode");                    String errMsg = result.getString("errmsg");                    throw new Exception("error code:"+errCode+", error message:"+errMsg);                 }            }        } catch (IOException e) {            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());            e.printStackTrace();        } finally {            if (response != null) try {                response.close();                  //释放资源            } catch (IOException e) {                e.printStackTrace();            }        }        return null;    }    /**     * @desc : 4.下载文件 -get     *       * @param url  请求url     * @param fileDir  下载路径     * @return     * @throws Exception File     */    public static File downloadMedia(String url, String fileDir) throws Exception  {        //1.生成一个请求        HttpGet httpGet = new HttpGet(url);        //2.配置请求属性        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(100000).build();        httpGet.setConfig(requestConfig);        //3.发起请求,获取响应信息            //3.1 创建httpClient         CloseableHttpClient httpClient = HttpClients.createDefault();        CloseableHttpResponse response = null;        //4.设置本地保存的文件          //File file = new File(fileDir);        File file = null;        try {            //5. 发起请求,获取响应信息                response = httpClient.execute(httpGet, new BasicHttpContext());            System.out.println("HttpStatus.SC_OK:"+HttpStatus.SC_OK);              System.out.println("response.getStatusLine().getStatusCode():"+response.getStatusLine().getStatusCode());              System.out.println("http-header:"+JSON.toJSONString( response.getAllHeaders() ));              System.out.println("http-filename:"+getFileName(response) );              //请求成功              if(HttpStatus.SC_OK==response.getStatusLine().getStatusCode()){                  //6.取得请求内容                  HttpEntity entity = response.getEntity();                  if (entity != null) {                      //这里可以得到文件的类型 如image/jpg /zip /tiff 等等 但是发现并不是十分有效,有时明明后缀是.rar但是取到的是null,这点特别说明                      System.out.println(entity.getContentType());                      //可以判断是否是文件数据流                      System.out.println(entity.isStreaming());                      //6.1 输出流                    //6.1.1获取文件名,拼接文件路径                    String fileName=getFileName(response);                    fileDir=fileDir+fileName;                    file = new File(fileDir);                    //6.1.2根据文件路径获取输出流                    FileOutputStream output = new FileOutputStream(file);                      //6.2 输入流:从钉钉服务器返回的文件流,得到网络资源并写入文件                      InputStream input = entity.getContent();                      //6.3 将数据写入文件:将输入流中的数据写入到输出流                    byte b[] = new byte[1024];                      int j = 0;                      while( (j = input.read(b))!=-1){                          output.write(b,0,j);                      }                      output.flush();                      output.close();                   }                  if (entity != null) {                      entity.consumeContent();                  }              }          } catch (IOException e) {            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());            e.printStackTrace();        } finally {            if (response != null) try {                response.close();                       //释放资源            } catch (IOException e) {                e.printStackTrace();            }        }        return file;    }    /**     * @desc : 5.下载文件 - post     *       * @param url  请求url     * @param data  post请求参数     * @param fileDir 文件下载路径     * @return     * @throws Exception File     */    public static File downloadMedia(String url, Object data, String fileDir) throws Exception  {        //1.生成一个请求        HttpPost httpPost = new HttpPost(url);        //2.配置请求属性        //2.1 设置请求超时时间        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(100000).build();        httpPost.setConfig(requestConfig);        //2.2 设置数据传输格式-json        httpPost.addHeader("Content-Type", "application/json");        //2.3 设置请求参数        StringEntity requestEntity = new StringEntity(JSON.toJSONString(data), "utf-8");        httpPost.setEntity(requestEntity);        //3.发起请求,获取响应信息            //3.1 创建httpClient         CloseableHttpClient httpClient = HttpClients.createDefault();        CloseableHttpResponse response = null;        //4.设置本地保存的文件          //File file = new File(fileDir);        File file = null;        try {            //5. 发起请求,获取响应信息                response = httpClient.execute(httpPost, new BasicHttpContext());            System.out.println("HttpStatus.SC_OK:"+HttpStatus.SC_OK);              System.out.println("response.getStatusLine().getStatusCode():"+response.getStatusLine().getStatusCode());              System.out.println("http-header:"+JSON.toJSONString( response.getAllHeaders() ));              System.out.println("http-filename:"+getFileName(response) );              //请求成功              if(HttpStatus.SC_OK==response.getStatusLine().getStatusCode()){                  //6.取得请求内容                  HttpEntity entity = response.getEntity();                  if (entity != null) {                      //这里可以得到文件的类型 如image/jpg /zip /tiff 等等 但是发现并不是十分有效,有时明明后缀是.rar但是取到的是null,这点特别说明                      System.out.println(entity.getContentType());                      //可以判断是否是文件数据流                      System.out.println(entity.isStreaming());                      //6.1 输出流                    //6.1.1获取文件名,拼接文件路径                    String fileName=getFileName(response);                    fileDir=fileDir+fileName;                    file = new File(fileDir);                    //6.1.2根据文件路径获取输出流                    FileOutputStream output = new FileOutputStream(file);                      //6.2 输入流:从钉钉服务器返回的文件流,得到网络资源并写入文件                      InputStream input = entity.getContent();                      //6.3 将数据写入文件:将输入流中的数据写入到输出流                    byte b[] = new byte[1024];                      int j = 0;                      while( (j = input.read(b))!=-1){                          output.write(b,0,j);                      }                      output.flush();                      output.close();                   }                  if (entity != null) {                      entity.consumeContent();                  }              }          } catch (IOException e) {            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());            e.printStackTrace();        } finally {            if (response != null) try {                response.close();                       //释放资源            } catch (IOException e) {                e.printStackTrace();            }        }        return file;    }    /** 5. 获取response header中Content-Disposition中的filename值      * @desc :     *       * @param response  响应     * @return String     */    public static String getFileName(HttpResponse response) {          Header contentHeader = response.getFirstHeader("Content-Disposition");          String filename = null;          if (contentHeader != null) {              HeaderElement[] values = contentHeader.getElements();              if (values.length == 1) {                  NameValuePair param = values[0].getParameterByName("filename");                  if (param != null) {                      try {                          //filename = new String(param.getValue().toString().getBytes(), "utf-8");                          //filename=URLDecoder.decode(param.getValue(),"utf-8");                          filename = param.getValue();                      } catch (Exception e) {                          e.printStackTrace();                      }                  }              }          }          return filename;      }  }
View Code

 

3、接收消息的封装

3.1 消息基类—BaseMessage

package com.ray.weixin.gz.model.message.request;    /** *   @desc  : 消息基类(普通用户 -> 公众帐号)  *  * @author: shirayner * @date  : 2017年11月13日 上午10:58:08 */public class BaseMessage {      // 开发者微信号      private String ToUserName;      // 发送方帐号(一个OpenID)      private String FromUserName;      // 消息创建时间 (整型)      private long CreateTime;      // 消息类型(text/image/location/link)      private String MsgType;      // 消息id,64位整型      private long MsgId;        public String getToUserName() {          return ToUserName;      }        public void setToUserName(String toUserName) {          ToUserName = toUserName;      }        public String getFromUserName() {          return FromUserName;      }        public void setFromUserName(String fromUserName) {          FromUserName = fromUserName;      }        public long getCreateTime() {          return CreateTime;      }        public void setCreateTime(long createTime) {          CreateTime = createTime;      }        public String getMsgType() {          return MsgType;      }        public void setMsgType(String msgType) {          MsgType = msgType;      }        public long getMsgId() {          return MsgId;      }        public void setMsgId(long msgId) {          MsgId = msgId;      }  }
View Code

 

3.2 文本消息—TextMessage

package com.ray.weixin.gz.model.message.request;    /** * @desc  : 文本消息  *  * @author: shirayner * @date  : 2017年11月13日 上午11:04:09 */public class TextMessage extends BaseMessage {      // 消息内容      private String Content;        public String getContent() {          return Content;      }        public void setContent(String content) {          Content = content;      }  }
View Code

 

3.3 图片消息—ImageMessage

package com.ray.weixin.gz.model.message.request;     /** * @desc  : 图片消息  *  * @author: shirayner * @date  : 2017年11月13日 上午11:04:33 */public class ImageMessage extends BaseMessage {      // 图片链接      private String PicUrl;        public String getPicUrl() {          return PicUrl;      }        public void setPicUrl(String picUrl) {          PicUrl = picUrl;      }  }
View Code

 

3.4 链接消息—LinkMessage

package com.ray.weixin.gz.model.message.request;    /** * @desc  :链接消息   *  * @author: shirayner * @date  : 2017年11月13日 上午11:05:46 */public class LinkMessage extends BaseMessage {      // 消息标题      private String Title;      // 消息描述      private String Description;      // 消息链接      private String Url;        public String getTitle() {          return Title;      }        public void setTitle(String title) {          Title = title;      }        public String getDescription() {          return Description;      }        public void setDescription(String description) {          Description = description;      }        public String getUrl() {          return Url;      }        public void setUrl(String url) {          Url = url;      }  }
View Code

 

3.5 地理位置消息—LocationMessage

package com.ray.weixin.gz.model.message.request;    /** * @desc  : 地理位置消息  *  * @author: shirayner * @date  : 2017年11月13日 上午11:07:39 */public class LocationMessage extends BaseMessage {      // 地理位置维度      private String Location_X;      // 地理位置经度      private String Location_Y;      // 地图缩放大小      private String Scale;      // 地理位置信息      private String Label;        public String getLocation_X() {          return Location_X;      }        public void setLocation_X(String location_X) {          Location_X = location_X;      }        public String getLocation_Y() {          return Location_Y;      }        public void setLocation_Y(String location_Y) {          Location_Y = location_Y;      }        public String getScale() {          return Scale;      }        public void setScale(String scale) {          Scale = scale;      }        public String getLabel() {          return Label;      }        public void setLabel(String label) {          Label = label;      }  }
View Code

 

3.6 音频消息—VoiceMessage

package com.ray.weixin.gz.model.message.request;      /** * @desc  :音频消息   *  * @author: shirayner * @date  : 2017年11月13日 上午11:08:25 */public class VoiceMessage extends BaseMessage {      // 媒体ID      private String MediaId;      // 语音格式      private String Format;        public String getMediaId() {          return MediaId;      }        public void setMediaId(String mediaId) {          MediaId = mediaId;      }        public String getFormat() {          return Format;      }        public void setFormat(String format) {          Format = format;      }  }
View Code

 

4. 回复消息的封装

4.1 消息基类—BaseMessage

package com.ray.weixin.gz.model.message.response;  /** * @desc  : 消息基类(公众帐号 -> 普通用户)  *  * @author: shirayner * @date  : 2017年11月13日 上午11:10:32 */public class BaseMessage {      // 接收方帐号(收到的OpenID)      private String ToUserName;      // 开发者微信号      private String FromUserName;      // 消息创建时间 (整型)      private long CreateTime;      // 消息类型(text/music/news)      private String MsgType;      // 位0x0001被标志时,星标刚收到的消息      private int FuncFlag;        public String getToUserName() {          return ToUserName;      }        public void setToUserName(String toUserName) {          ToUserName = toUserName;      }        public String getFromUserName() {          return FromUserName;      }        public void setFromUserName(String fromUserName) {          FromUserName = fromUserName;      }        public long getCreateTime() {          return CreateTime;      }        public void setCreateTime(long createTime) {          CreateTime = createTime;      }        public String getMsgType() {          return MsgType;      }        public void setMsgType(String msgType) {          MsgType = msgType;      }        public int getFuncFlag() {          return FuncFlag;      }        public void setFuncFlag(int funcFlag) {          FuncFlag = funcFlag;      }  }
View Code

 

4.2 文本消息—TextMessage

package com.ray.weixin.gz.model.message.response;     /** * @desc  :  *  * @author: shirayner * @date  : 2017年11月13日 上午11:10:58 */public class TextMessage extends BaseMessage {      // 回复的消息内容      private String Content;        public String getContent() {          return Content;      }        public void setContent(String content) {          Content = content;      }  }
View Code

 

4.3 音乐消息—MusicMessage

Music

package com.ray.weixin.gz.model.message.response;     /** * @desc  : 音乐model  *  * @author: shirayner * @date  : 2017年11月13日 上午11:12:47 */public class Music {      // 音乐名称      private String Title;      // 音乐描述      private String Description;      // 音乐链接      private String MusicUrl;      // 高质量音乐链接,WIFI环境优先使用该链接播放音乐      private String HQMusicUrl;        public String getTitle() {          return Title;      }        public void setTitle(String title) {          Title = title;      }        public String getDescription() {          return Description;      }        public void setDescription(String description) {          Description = description;      }        public String getMusicUrl() {          return MusicUrl;      }        public void setMusicUrl(String musicUrl) {          MusicUrl = musicUrl;      }        public String getHQMusicUrl() {          return HQMusicUrl;      }        public void setHQMusicUrl(String musicUrl) {          HQMusicUrl = musicUrl;      }    }
View Code

MusicMessage

package com.ray.weixin.gz.model.message.response;     /** * @desc  : 音乐消息  *  * @author: shirayner * @date  : 2017年11月13日 上午11:12:06 */public class MusicMessage extends BaseMessage {      // 音乐      private Music Music;        public Music getMusic() {          return Music;      }        public void setMusic(Music music) {          Music = music;      }  }
View Code

 

4.4 图文消息—NewsMessage

Article

package com.ray.weixin.gz.model.message.response;    /** * @desc  :  图文model  *  * @author: shirayner * @date  : 2017年11月13日 上午11:15:30 */public class Article {      // 图文消息名称      private String Title;      // 图文消息描述      private String Description;      // 图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80,限制图片链接的域名需要与开发者填写的基本资料中的Url一致      private String PicUrl;      // 点击图文消息跳转链接      private String Url;        public String getTitle() {          return Title;      }        public void setTitle(String title) {          Title = title;      }        public String getDescription() {          return null == Description ? "" : Description;      }        public void setDescription(String description) {          Description = description;      }        public String getPicUrl() {          return null == PicUrl ? "" : PicUrl;      }        public void setPicUrl(String picUrl) {          PicUrl = picUrl;      }        public String getUrl() {          return null == Url ? "" : Url;      }        public void setUrl(String url) {          Url = url;      }    }
View Code

NewsMessage

package com.ray.weixin.gz.model.message.response;    import java.util.List;     /** * @desc  : 图文消息 *  * @author: shirayner * @date  : 2017年11月13日 上午11:13:36 */public class NewsMessage extends BaseMessage {      // 图文消息个数,限制为10条以内      private int ArticleCount;      // 多条图文消息信息,默认第一个item为大图      private List
Articles; public int getArticleCount() { return ArticleCount; } public void setArticleCount(int articleCount) { ArticleCount = articleCount; } public List
getArticles() { return Articles; } public void setArticles(List
articles) { Articles = articles; } }
View Code

 

5.接收微信消息和事件—WeiXinServlet.java

package com.ray.weixin.gz.controller;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import com.qq.weixin.mp.aes.AesException;import com.qq.weixin.mp.aes.WXBizMsgCrypt;import com.ray.weixin.gz.config.Env;import com.ray.weixin.gz.service.message.ReplyMessageService;/** * Servlet implementation class WeiXinServlet */         public class WeiXinServlet extends HttpServlet {    private static final Logger logger = LogManager.getLogger(WeiXinServlet.class);    private static final long serialVersionUID = 1L;    /**     * Default constructor.      */    public WeiXinServlet() {        // TODO Auto-generated constructor stub    }    //1.接收  回调模式  的请求    protected void doGet(HttpServletRequest request, HttpServletResponse response)  {        logger.info("get--------------");        //一、校验URL        //1.准备校验参数        // 微信加密签名          String msgSignature = request.getParameter("signature");          // 时间戳          String timeStamp = request.getParameter("timestamp");          // 随机数          String nonce = request.getParameter("nonce");          // 随机字符串          String echoStr = request.getParameter("echostr");          PrintWriter out=null;        try {            //2.校验url            //2.1 创建加解密类            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(Env.TOKEN,Env.ENCODING_AES_KEY,Env.APP_ID);            //2.2进行url校验            //不抛异常就说明校验成功            String sEchoStr= wxcpt.verifyUrl_WXGZ(msgSignature, Env.TOKEN, timeStamp, nonce,echoStr);            //2.3若校验成功,则原样返回 echoStr            out = response.getWriter();             out.print(sEchoStr);          } catch (AesException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } finally {            if (out != null) {                out.close();                  out = null;                       //释放资源            }        }    }    //2.接收  微信消息和事件  的请求    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        logger.info("post--------------");        //1.将请求、响应的编码均设置为UTF-8(防止中文乱码)          request.setCharacterEncoding("UTF-8");          response.setCharacterEncoding("UTF-8");          //2.调用消息业务类接收消息、处理消息          String respMessage = ReplyMessageService.reply(request);          //3.响应消息          PrintWriter out = response.getWriter();          out.print(respMessage);          out.close();     }}
View Code

 

6.被动回复消息业务类—ReplyMessageService.java

package com.ray.weixin.gz.service.message;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.Date;import java.util.Map;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import com.alibaba.fastjson.JSON;import com.qq.weixin.mp.aes.AesException;import com.qq.weixin.mp.aes.WXBizMsgCrypt;import com.ray.weixin.gz.config.Env;import com.ray.weixin.gz.model.message.response.TextMessage;import com.ray.weixin.gz.util.MessageUtil;/**@desc  : 发送消息-被动回复消息业务类 * Passive reply message * @author: shirayner * @date  : 2017年10月31日 下午12:24:41 */public class ReplyMessageService {    private static final Logger logger = LogManager.getLogger(ReplyMessageService.class);    /**     * @desc :1.回复消息     *       * @param request     * @return      *   String 回复消息的加密xml字符串     */    public static String reply( HttpServletRequest request ) {        String parms=JSON.toJSONString(request.getParameterMap());         logger.info("parms:"+parms);        //1.解密:从request中获取消息明文        String xmlMsg=decryptMsg(request);        logger.info(xmlMsg);        //2.获取回复消息(明文)        String replyMsg = getReplyMsg( xmlMsg);        //3.根据消息加密方式判断是否加密        String timeStamp = request.getParameter("timestamp");   // 时间戳            String nonce = request.getParameter("nonce");          // 随机数          String encryptType=request.getParameter("encrypt_type");        //3.1 安全模式-加密:将回复消息加密        if(null!=encryptType) {            WXBizMsgCrypt wxcpt=null;            try {                wxcpt = new WXBizMsgCrypt(Env.TOKEN,Env.ENCODING_AES_KEY,Env.APP_ID);                replyMsg=wxcpt.EncryptMsg(replyMsg, timeStamp, nonce);            } catch (AesException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        return replyMsg;    }    /**     * @desc :2.从request中获取消息明文     *  从request中获取加密消息,将其解密并返回     * @param request     * @return String   消息明文     */    public static String decryptMsg(HttpServletRequest request) {        String postData="";   // 密文,对应POST请求的数据        String result="";     // 明文,解密之后的结果        String msgSignature = request.getParameter("msg_signature"); // 微信加密签名          String timeStamp = request.getParameter("timestamp");   // 时间戳            String nonce = request.getParameter("nonce");          // 随机数          String encryptType=request.getParameter("encrypt_type");        try {            //1.获取加密的请求消息:使用输入流获得加密请求消息postData            ServletInputStream in = request.getInputStream();            BufferedReader reader =new BufferedReader(new InputStreamReader(in));              String tempStr="";   //作为输出字符串的临时串,用于判断是否读取完毕              while(null!=(tempStr=reader.readLine())){                  postData+=tempStr;              }              logger.info("postData:"+postData);            //2.获取消息明文:对加密的请求消息进行解密获得明文             if(null!=encryptType) {                logger.info("安全模式:消息被加密");                WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(Env.TOKEN,Env.ENCODING_AES_KEY,Env.APP_ID);                result=wxcpt.DecryptMsg(msgSignature, timeStamp, nonce, postData);            }else {                logger.info("明文模式");                result=postData;            }        } catch (IOException e) {            e.printStackTrace();        } catch (AesException e) {            e.printStackTrace();        }          return result;    }    /**     * @desc :获取回复消息     *       * @param request     * @return String  返回加密后的回复消息     */    public static String getReplyMsg(String xmlMsg){        String replyMsg = null;         try {            //2.解析微信发来的请求,解析xml字符串            Map
requestMap= MessageUtil.parseXml(xmlMsg); //3.获取请求参数 //3.1 企业微信CorpID String fromUserName = requestMap.get("FromUserName"); //3.2 成员UserID String toUserName = requestMap.get("ToUserName"); //3.3 消息类型与事件 String msgType = requestMap.get("MsgType"); String eventType = requestMap.get("Event"); String eventKey = requestMap.get("EventKey"); logger.info("fromUserName:"+fromUserName); logger.info("toUserName:"+toUserName); logger.info("msgType:"+msgType); logger.info("Event:"+eventType+" eventKey:"+eventKey); //4.组装 回复文本消息 TextMessage textMessage = new TextMessage(); textMessage.setToUserName(fromUserName); textMessage.setFromUserName(toUserName); textMessage.setCreateTime(new Date().getTime()); textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT); //4.1.获取回复消息的内容 :消息的分类处理 String replyContent=getReplyContentByMsgType(msgType, eventType, eventKey); textMessage.setContent(replyContent); System.out.println("replyContent:"+replyContent); //5.获取xml字符串: 将(被动回复消息型的)文本消息对象 转成 xml字符串 replyMsg = MessageUtil.textMessageToXml(textMessage); } catch (Exception e) { e.printStackTrace(); } return replyMsg; } /** * @desc :3.处理消息:根据消息类型获取回复内容 * * @param msgType 消息类型 * @return String 回复内容 */ public static String getReplyContentByMsgType(String msgType,String eventType,String eventKey){ String replyContent=""; //1.文本消息 if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) { replyContent = "您发送的是文本消息!"; } //2.图片消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) { replyContent = "您发送的是图片消息!"; } //3.地理位置消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) { replyContent = "您发送的是地理位置消息 !"; } //4.链接消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) { replyContent = "您发送的是链接消息!"; } //5.音频消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) { replyContent = "您发送的是音频消息!"; } //6.事件推送 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) { replyContent=getReplyContentByEventType(eventType, eventKey); } //7.请求异常 else { replyContent="请求处理异常,请稍候尝试!"; } return replyContent; } /** * @desc :5.处理消息:根据事件类型获取回复内容 * * @param eventType 事件类型 * @param eventKey 事件key值 * @return * String */ public static String getReplyContentByEventType(String eventType,String eventKey){ String respContent=""; // 订阅 if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) { respContent = "欢迎关注!"; } // 取消订阅 else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) { // TODO 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息 } //上报地理位置事件 else if(eventType.equals("LOCATION")){ } // 自定义菜单点击事件 else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) { if (eventKey.equals("12")) { } else if (eventKey.equals("13")) { respContent = "周边搜索菜单项被点击!"; } else if (eventKey.equals("14")) { respContent = "历史上的今天菜单项被点击!"; } else if (eventKey.equals("21")) { respContent = "歌曲点播菜单项被点击!"; } else if (eventKey.equals("22")) { respContent = "经典游戏菜单项被点击!"; } else if (eventKey.equals("23")) { respContent = "美女电台菜单项被点击!"; } else if (eventKey.equals("24")) { respContent = "人脸识别菜单项被点击!"; } else if (eventKey.equals("25")) { respContent = "聊天唠嗑菜单项被点击!"; } else if (eventKey.equals("31")) { respContent = "Q友圈菜单项被点击!"; } else if (eventKey.equals("32")) { respContent = "电影排行榜菜单项被点击!"; } else if (eventKey.equals("33")) { respContent = "幽默笑话菜单项被点击!"; } } return respContent; } }
View Code

 

三、参考资料

1.

2.

 

转载地址:http://noyqa.baihongyu.com/

你可能感兴趣的文章
安卓中高级开发面试知识点之——缓存
查看>>
Java的初始化顺序
查看>>
js 判断回文字符串
查看>>
shields小徽章是如何生成的?以及搭建自己的shield服务器
查看>>
猫头鹰的深夜翻译:spring事务管理
查看>>
记一次使用Spring REST Docs + travis + github自动生成API接口文档的操作步骤(下)...
查看>>
1、集合 2、Iterator迭代器 3、增强for循环 4、泛型
查看>>
关于/var/run/docker.sock
查看>>
SCrapy爬虫大战京东商城
查看>>
用 JavaScript 实现链表操作 - 11 Alternating Split
查看>>
Laravel优秀扩展包整理
查看>>
日志分析之识别真假蜘蛛与处理办法
查看>>
太多脚本将会毁掉持续交付
查看>>
一地鸡毛 OR 绝地反击,2019年区块链发展指南
查看>>
卢森堡大学发布RepuCoin系统,可破解区块链51%攻击
查看>>
国内云计算厂商众生相:四大阵营十几家企业生存盘点
查看>>
细说Unicode(一) Unicode初认识
查看>>
Node.js有了新的管理者
查看>>
Java 20年:历史与未来
查看>>
彻底理解Javascript中的原型链与继承
查看>>