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; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Java和C#下的参数验证方法