这里有新鲜出炉的Java设计模式,程序狗速度看过来!
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台(即JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称。
这篇文章主要为大家详细介绍了java微信开发API第二步,获取消息和回复消息,感兴趣的小伙伴们可以参考一下
微信开发API如何获取和回复消息,下面就为大家进行介绍
一、说明
* 本示例根据微信开发文档:http://mp.weixin.qq.com/wiki/home/index.html最新版(4/3/2016 5:34:36 PM )进行开发演示。
* 编辑平台:myeclipse10.7+win32+jdk1.7+tomcat7.0
* 服务器:阿里云 windows server 2008 64bits
* 平台要求:servlet使用注解方式,平台要求:j2ee6.0+、jdk6.0+、tomcat7.0+
* 演示更加注重于api解析。
* 为了便于测试说明,每个测试用例为独立,不依赖于其它方法。对于封装,不多加考虑。
* 演示尽可能按照API要求进行,目的:了解文档使用方式,达到举一反三的效果。
* 知识要求:牢固的java基础、了解http网络通信知识、对于javaweb有足够了解、json解析
* 在每篇文章结束会给出该部分演示源码。在分析完API之后,会以源码包的形式给出所有演示源码。
* 当前时间:4/3/2016 5:32:57 PM ,以该时间为准。
二、文档原文-消息管理(摘要)
•文档地址:http://mp.weixin.qq.com/wiki/17/f298879f8fb29ab98b2f2971d42552fd.html
•消息管理
◦接收消息-接收普通消息
◦接收消息-接收事件推送
◦发送消息-被动回复消息
◦发送消息-被动回复时的加解密
◦发送消息-客服消息
◦发送消息-群发接口
◦发送消息-模板消息接口
◦发送消息-模板消息运营规范
◦获取公众号自动回复配置
三、文档理解
•接收消息
◦文档这样解释:当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
◦理解:微信服务器将用户发送的消息通过Post流的形式返回给req。当我们想要获取用户发送的消息时,可以通过req.getInputStream()获取。当然,我们可以根据文档上关于消息的返回的xml格式,进行必要的解析。
◦
实现:
- /*
- * 该部分我们获取用户发送的信息,并且解析成<K,V>的形式进行显示
- */
- // 解析用户发送过来的信息
- InputStream is = req.getInputStream(); // 拿取请求流
- // 将解析结果存储在HashMap中
- Map < String,
- String > map = new HashMap < String,
- String > ();
- // 解析xml,将获取到的返回结果xml进行解析成我们习惯的文字信息
- SAXReader reader = new SAXReader(); // 第三方jar:dom4j【百度:saxreader解析xml】
- Document document = null;
- try {
- document = reader.read(is);
- } catch(DocumentException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- // 得到xml根元素
- Element root = document.getRootElement();
- // 得到根元素的所有子节点
- List < Element > elementList = root.elements();
- // 遍历所有子节点
- for (Element e: elementList) map.put(e.getName(), e.getText());
- // 测试输出
- Set < String > keySet = map.keySet();
- // 测试输出解析后用户发过来的信息
- System.out.println(TAG + ":解析用户发送过来的信息开始");
- for (String key: keySet) {
- System.out.println(key + ":" + map.get(key));
- }
- System.out.println(TAG + ":解析用户发送过来的信息结束");
•发送消息
◦文档这样解释:当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。
◦理解:用户发送请求,会产生一个POST请求,我们可以通过Respone进行回复消息。但是,回复的内容有严格的格式要求,只有满足格式要求,微信服务器才会进行处理返回给用户。通过查看文档“消息管理”模块,我们可以看到微信中有各种各样的消息,每类消息都有自己特定的格式要求,我们必须按照要求才可以正常的给用户返回特定的信息。我们尝试按照文档的要求格式给用户回复文本信息、图文消息。重点:按照文档要求构造需要的参数。特别注意:参数区分大小写。
◦实现1-回复普通文本消息:
- //实例1:发送普通文本消息,请查看文档关于“回复文本消息”的xml格式
- // 第一步:按照回复文本信息构造需要的参数
- TextMsg textMsg = new TextMsg();
- textMsg.setToUserName(map.get("FromUserName")); // 发送和接收信息“User”刚好相反
- textMsg.setFromUserName(map.get("ToUserName"));
- textMsg.setCreateTime(new Date().getTime()); // 消息创建时间 (整型)
- textMsg.setMsgType("text"); // 文本类型消息
- textMsg.setContent("我是服务器回复给用户的信息");
- // // 第二步,将构造的信息转化为微信识别的xml格式【百度:xstream bean转xml】
- XStream xStream = new XStream();
- xStream.alias("xml", textMsg.getClass());
- String textMsg2Xml = xStream.toXML(textMsg);
- System.out.println(textMsg2Xml);
- // // 第三步,发送xml的格式信息给微信服务器,服务器转发给用户
- PrintWriter printWriter = resp.getWriter();
- printWriter.print(textMsg2Xml);
◦实现2-回复图文消息:
- //实例2,发送图文消息。请查看文档关于“回复图文消息”的xml格式
- // 第一步:按照回复图文信息构造需要的参数
- List < Article > articles = new ArrayList < Article > ();
- Article a = new Article();
- a.setTitle("我是图片标题");
- a.setUrl("www.baidu.com"); // 该地址是点击图片跳转后
- a.setPicUrl("http://b.hiphotos.baidu.com/image/pic/item/08f790529822720ea5d058ba7ccb0a46f21fab50.jpg"); // 该地址是一个有效的图片地址
- a.setDescription("我是图片的描述");
- articles.add(a);
- PicAndTextMsg picAndTextMsg = new PicAndTextMsg();
- picAndTextMsg.setToUserName(map.get("FromUserName")); // 发送和接收信息“User”刚好相反
- picAndTextMsg.setFromUserName(map.get("ToUserName"));
- picAndTextMsg.setCreateTime(new Date().getTime()); // 消息创建时间 (整型)
- picAndTextMsg.setMsgType("news"); // 图文类型消息
- picAndTextMsg.setArticleCount(1);
- picAndTextMsg.setArticles(articles);
- // 第二步,将构造的信息转化为微信识别的xml格式【百度:xstream bean转xml】
- XStream xStream = new XStream();
- xStream.alias("xml", picAndTextMsg.getClass());
- xStream.alias("item", a.getClass());
- String picAndTextMsg2Xml = xStream.toXML(picAndTextMsg);
- System.out.println(picAndTextMsg2Xml);
- // 第三步,发送xml的格式信息给微信服务器,服务器转发给用户
- PrintWriter printWriter = resp.getWriter();
- printWriter.print(picAndTextMsg2Xml);
该部分所有操作源码,可以直接使用
•CoreServlet.java(包括服务器接入、接收用户发送消息、回复普通文字消息、回复图文消息。需要第三方jar:dom4j、xstream)
- package com.gist.servlet;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.PrintWriter;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.dom4j.Document;
- import org.dom4j.DocumentException;
- import org.dom4j.Element;
- import org.dom4j.io.SAXReader;
- import com.gist.bean.Article;
- import com.gist.bean.PicAndTextMsg;
- import com.thoughtworks.xstream.XStream;
- /**
- * @author 高远</n> 邮箱:wgyscsf@163.com</n> 博客 http://blog.csdn.net/wgyscsf</n>
- * 编写时期 2016-4-3 下午4:34:05
- */
- @WebServlet("/CoreServlet") public class CoreServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
- String TAG = "CoreServlet";
- /*
- * 第二步:验证服务器地址的有效性 开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,
- * GET请求携带四个参数:signature、timestamp、nonce、echostr
- * 开发者通过检验signature对请求进行校验(下面有校验方式)。 若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,
- * 则接入生效, 成为开发者成功,否则接入失败。
- *
- * 加密/校验流程如下: 1. 将token、timestamp、nonce三个参数进行字典序排序 2.
- * 将三个参数字符串拼接成一个字符串进行sha1加密 3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
- */
- /*
- * 字典排序(lexicographical
- * order)是一种对于随机变量形成序列的排序方法。其方法是,按照字母顺序,或者数字小大顺序,由小到大的形成序列。
- */
- @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
- IOException {
- // 设置编码
- req.setCharacterEncoding("utf-8");
- resp.setContentType("html/text;charset=utf-8");
- resp.setCharacterEncoding("utf-8");
- // 获取输出流
- PrintWriter printWriter = resp.getWriter();
- // 设置一个全局的token,开发者自己设置。api这样解释:Token可由开发者可以任意填写,
- // 用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)
- String token = "wgyscsf";
- // 根据api说明,获取上述四个参数
- String signature = req.getParameter("signature");
- String timestamp = req.getParameter("timestamp");
- String nonce = req.getParameter("nonce");
- String echostr = req.getParameter("echostr");
- // // temp:临时打印,观看返回参数情况
- // System.out.println(TAG + ":signature:" + signature + ",timestamp:"
- // + timestamp + ",nonce:" + nonce + ",echostr:" + echostr);
- // 根据api所说的“加密/校验流程”进行接入。共计三步
- // 第一步:将token、timestamp、nonce三个参数进行字典序排序
- String[] parms = new String[] {
- token,
- timestamp,
- nonce
- }; // 将需要字典序排列的字符串放到数组中
- Arrays.sort(parms); // 按照api要求进行字典序排序
- // 第二步:将三个参数字符串拼接成一个字符串进行sha1加密
- // 拼接字符串
- String parmsString = ""; // 注意,此处不能=null。
- for (int i = 0; i < parms.length; i++) {
- parmsString += parms[i];
- }
- // sha1加密
- String mParms = null; // 加密后的结果
- MessageDigest digest = null;
- try {
- digest = java.security.MessageDigest.getInstance("SHA");
- } catch(NoSuchAlgorithmException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- digest.update(parmsString.getBytes());
- byte messageDigest[] = digest.digest();
- // Create Hex String
- StringBuffer hexString = new StringBuffer();
- // 字节数组转换为 十六进制 数
- for (int i = 0; i < messageDigest.length; i++) {
- String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
- if (shaHex.length() < 2) {
- hexString.append(0);
- }
- hexString.append(shaHex);
- }
- mParms = hexString.toString(); // 加密结果
- /*
- * api要求: 若确认此次GET请求来自微信服务器,请原样返回echostr参数内容, 则接入生效, 成为开发者成功,否则接入失败。
- */
- // 第三步: 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信接入成功。
- // System.out.println(TAG + ":" + mParms + "---->" + signature);
- if (mParms.equals(signature)) {
- // System.out.println(TAG + ":" + mParms + "---->" + signature);
- printWriter.write(echostr);
- } else {
- // 接入失败,不用回写
- // System.out.println(TAG + "接入失败");
- }
- }
- /*
- * 查看api文档关于收发消息推送的消息格式基本一致。 如以下格式: <xml>
- * <ToUserName><![CDATA[toUser]]></ToUserName>
- * <FromUserName><![CDATA[fromUser]]></FromUserName>
- * <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType>
- * <Content><![CDATA[this is a test]]></Content>
- * <MsgId>1234567890123456</MsgId> </xml> 那么,我们就可以进行统一处理。
- */
- /*
- * 我们先获取输入流,看输入流里面的信息。通过测试打印输出流,我们可以看到每次用户请求,都会收到req请求,请求格式是xml格式,该信息在文档中有说明。
- */
- /*
- * 特别注意,req.getInputStream()只能获取一次,并且只能读取一次。如果想要多次读取,需要另外想办法。为了简单起见,
- * 我们只获取一次req.getInputStream(),不再打印输出流信息。直接打印解析后的信息。
- */
- @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
- IOException {
- // 设置编码
- req.setCharacterEncoding("utf-8");
- resp.setContentType("html/text;charset=utf-8");
- resp.setCharacterEncoding("utf-8");
- /*
- * 该部分我们获取用户发送的信息,并且解析成<K,V>的形式进行显示
- */
- // 解析用户发送过来的信息
- InputStream is = req.getInputStream(); // 拿取请求流
- // 将解析结果存储在HashMap中
- Map < String,
- String > map = new HashMap < String,
- String > ();
- // 解析xml,将获取到的返回结果xml进行解析成我们习惯的文字信息
- SAXReader reader = new SAXReader(); // 第三方jar:dom4j【百度:saxreader解析xml】
- Document document = null;
- try {
- document = reader.read(is);
- } catch(DocumentException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- // 得到xml根元素
- Element root = document.getRootElement();
- // 得到根元素的所有子节点
- List < Element > elementList = root.elements();
- // 遍历所有子节点
- for (Element e: elementList) map.put(e.getName(), e.getText());
- // 测试输出
- Set < String > keySet = map.keySet();
- // 测试输出解析后用户发过来的信息
- System.out.println(TAG + ":解析用户发送过来的信息开始");
- for (String key: keySet) {
- System.out.println(key + ":" + map.get(key));
- }
- System.out.println(TAG + ":解析用户发送过来的信息结束");
- /*
- * 该部分我们尝试按照文档的要求格式给用户回复文本信息、图文消息。重点:按照文档要求构造需要的参数。特别注意:参数区分大小写。
- */
- // //实例1:发送普通文本消息,请查看文档关于“回复文本消息”的xml格式
- //
- // // 第一步:按照回复文本信息构造需要的参数
- // TextMsg textMsg = new TextMsg();
- // textMsg.setToUserName(map.get("FromUserName"));// 发送和接收信息“User”刚好相反
- // textMsg.setFromUserName(map.get("ToUserName"));
- // textMsg.setCreateTime(new Date().getTime());// 消息创建时间 (整型)
- // textMsg.setMsgType("text");// 文本类型消息
- // textMsg.setContent("我是服务器回复给用户的信息");
- //
- // // // 第二步,将构造的信息转化为微信识别的xml格式【百度:xstream bean转xml】
- // XStream xStream = new XStream();
- // xStream.alias("xml", textMsg.getClass());
- // String textMsg2Xml = xStream.toXML(textMsg);
- // System.out.println(textMsg2Xml);
- //
- // // // 第三步,发送xml的格式信息给微信服务器,服务器转发给用户
- // PrintWriter printWriter = resp.getWriter();
- // printWriter.print(textMsg2Xml);
- // //实例2,发送图文消息。请查看文档关于“回复图文消息”的xml格式
- // 第一步:按照回复图文信息构造需要的参数
- List < Article > articles = new ArrayList < Article > ();
- Article a = new Article();
- a.setTitle("我是图片标题");
- a.setUrl("www.baidu.com"); // 该地址是点击图片跳转后
- a.setPicUrl("http://b.hiphotos.baidu.com/image/pic/item/08f790529822720ea5d058ba7ccb0a46f21fab50.jpg"); // 该地址是一个有效的图片地址
- a.setDescription("我是图片的描述");
- articles.add(a);
- PicAndTextMsg picAndTextMsg = new PicAndTextMsg();
- picAndTextMsg.setToUserName(map.get("FromUserName")); // 发送和接收信息“User”刚好相反
- picAndTextMsg.setFromUserName(map.get("ToUserName"));
- picAndTextMsg.setCreateTime(new Date().getTime()); // 消息创建时间 (整型)
- picAndTextMsg.setMsgType("news"); // 图文类型消息
- picAndTextMsg.setArticleCount(1);
- picAndTextMsg.setArticles(articles);
- // 第二步,将构造的信息转化为微信识别的xml格式【百度:xstream bean转xml】
- XStream xStream = new XStream();
- xStream.alias("xml", picAndTextMsg.getClass());
- xStream.alias("item", a.getClass());
- String picAndTextMsg2Xml = xStream.toXML(picAndTextMsg);
- System.out.println(picAndTextMsg2Xml);
- // 第三步,发送xml的格式信息给微信服务器,服务器转发给用户
- PrintWriter printWriter = resp.getWriter();
- printWriter.print(picAndTextMsg2Xml);
- }
- }
•TestMsg.java(普通文字消息bean)
- package com.gist.bean;
- /**
- * @author 高远</n> 邮箱:wgyscsf@163.com</n> 博客 http://blog.csdn.net/wgyscsf</n>
- * 编写时期 2016-4-4 下午2:09:27
- */
- public class TextMsg {
- private String ToUserName;
- private String FromUserName;
- private long CreateTime;
- private String MsgType;
- @Override public String toString() {
- return "TextMsg [ToUserName=" + ToUserName + ", FromUserName=" + FromUserName + ", CreateTime=" + CreateTime + ", MsgType=" + MsgType + ", Content=" + Content + "]";
- }
- private String Content;
- public TextMsg(String toUserName, String fromUserName, long createTime, String msgType, String content) {
- super();
- ToUserName = toUserName;
- FromUserName = fromUserName;
- CreateTime = createTime;
- MsgType = msgType;
- Content = content;
- }
- public TextMsg() {
- super();
- }
- 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 String getContent() {
- return Content;
- }
- public void setContent(String content) {
- Content = content;
- }
- }
•Article.java(图文消息内部Article bean)
- package com.gist.bean;
- /**
- * @author 高远</n> 邮箱:wgyscsf@163.com</n> 博客 http://blog.csdn.net/wgyscsf</n>
- * 编写时期 2016-4-4 下午2:47:08
- */
- public class Article {
- private String Title;
- @Override public String toString() {
- return "item [Title=" + Title + ", Description=" + Description + ", PicUrl=" + PicUrl + ", Url=" + 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 getPicUrl() {
- return PicUrl;
- }
- public void setPicUrl(String picUrl) {
- PicUrl = picUrl;
- }
- public String getUrl() {
- return Url;
- }
- public void setUrl(String url) {
- Url = url;
- }
- private String Description;
- private String PicUrl;
- private String Url;
- }
•PicAndTextMsg.java(图文消息 bean)
- package com.gist.bean;
- import java.util.List;
- /**
- * @author 高远</n> 邮箱:wgyscsf@163.com</n> 博客 http://blog.csdn.net/wgyscsf</n>
- * 编写时期 2016-4-4 下午2:47:08
- */
- public class PicAndTextMsg {
- private String ToUserName;
- private String FromUserName;
- private long CreateTime;
- private String MsgType;
- private int ArticleCount;
- private List < Article > Articles;
- @Override public String toString() {
- return "PicAndTextMsg [ToUserName=" + ToUserName + ", FromUserName=" + FromUserName + ", CreateTime=" + CreateTime + ", MsgType=" + MsgType + ", ArticleCount=" + ArticleCount + ", Articles=" + Articles + "]";
- }
- 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 getArticleCount() {
- return ArticleCount;
- }
- public void setArticleCount(int articleCount) {
- ArticleCount = articleCount;
- }
- public List < Article > getArticles() {
- return Articles;
- }
- public void setArticles(List < Article > articles) {
- Articles = articles;
- }
- }
来源: http://www.phperz.com/article/17/1114/360523.html