java微信开发第二步 获取消息和回复消息
接着上一篇java微信开发API第一步服务器接入进行学习,下面介绍java微信开发第二步:获取消息和回复消息,具体内容如下
*本示例根据微信开发文档:http://mp.weixin.qq.com/wiki/home/index.html最新版(4/3/20165:34:36PM)进行开发演示。
*编辑平台:myeclipse10.7+win32+jdk1.7+tomcat7.0
*服务器:阿里云windowsserver200864bits
*平台要求:servlet使用注解方式,平台要求:j2ee6.0+、jdk6.0+、tomcat7.0+
*演示更加注重于api解析。
*为了便于测试说明,每个测试用例为独立,不依赖于其它方法。对于封装,不多加考虑。
*演示尽可能按照API要求进行,目的:了解文档使用方式,达到举一反三的效果。
*知识要求:牢固的java基础、了解http网络通信知识、对于javaweb有足够了解、json解析
*在每篇文章结束会给出该部分演示源码。在分析完API之后,会以源码包的形式给出所有演示源码。
*当前时间:4/3/20165:32:57PM,以该时间为准。
一、文档原文-消息管理(摘要)
文档地址:http://mp.weixin.qq.com/wiki/17/f298879f8fb29ab98b2f2971d42552fd.html
消息管理
接收消息-接收普通消息
接收消息-接收事件推送
发送消息-被动回复消息
发送消息-被动回复时的加解密
发送消息-客服消息
发送消息-群发接口
发送消息-模板消息接口
发送消息-模板消息运营规范
获取公众号自动回复配置
二、文档理解
1、接收消息
文档这样解释:当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
理解:微信服务器将用户发送的消息通过Post流的形式返回给req。当我们想要获取用户发送的消息时,可以通过req.getInputStream()获取。当然,我们可以根据文档上关于消息的返回的xml格式,进行必要的解析。
实现:
/* *该部分我们获取用户发送的信息,并且解析成<K,V>的形式进行显示 */ //解析用户发送过来的信息 InputStreamis=req.getInputStream();//拿取请求流 //将解析结果存储在HashMap中 Map<String,String>map=newHashMap<String,String>(); //解析xml,将获取到的返回结果xml进行解析成我们习惯的文字信息 SAXReaderreader=newSAXReader();//第三方jar:dom4j【百度:saxreader解析xml】 Documentdocument=null; try{ document=reader.read(is); }catch(DocumentExceptione1){ //TODOAuto-generatedcatchblock e1.printStackTrace(); } //得到xml根元素 Elementroot=document.getRootElement(); //得到根元素的所有子节点 List<Element>elementList=root.elements(); //遍历所有子节点 for(Elemente:elementList) map.put(e.getName(),e.getText()); //测试输出 Set<String>keySet=map.keySet(); //测试输出解析后用户发过来的信息 System.out.println(TAG+":解析用户发送过来的信息开始"); for(Stringkey:keySet){ System.out.println(key+":"+map.get(key)); } System.out.println(TAG+":解析用户发送过来的信息结束");
2、发送消息
文档这样解释:当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。
理解:用户发送请求,会产生一个POST请求,我们可以通过Respone进行回复消息。但是,回复的内容有严格的格式要求,只有满足格式要求,微信服务器才会进行处理返回给用户。通过查看文档“消息管理”模块,我们可以看到微信中有各种各样的消息,每类消息都有自己特定的格式要求,我们必须按照要求才可以正常的给用户返回特定的信息。我们尝试按照文档的要求格式给用户回复文本信息、图文消息。重点:按照文档要求构造需要的参数。特别注意:参数区分大小写。
1)、实现1-回复普通文本消息:
//实例1:发送普通文本消息,请查看文档关于“回复文本消息”的xml格式 //第一步:按照回复文本信息构造需要的参数 TextMsgtextMsg=newTextMsg(); textMsg.setToUserName(map.get("FromUserName"));//发送和接收信息“User”刚好相反 textMsg.setFromUserName(map.get("ToUserName")); textMsg.setCreateTime(newDate().getTime());//消息创建时间(整型) textMsg.setMsgType("text");//文本类型消息 textMsg.setContent("我是服务器回复给用户的信息"); ////第二步,将构造的信息转化为微信识别的xml格式【百度:xstreambean转xml】 XStreamxStream=newXStream(); xStream.alias("xml",textMsg.getClass()); StringtextMsg2Xml=xStream.toXML(textMsg); System.out.println(textMsg2Xml); ////第三步,发送xml的格式信息给微信服务器,服务器转发给用户 PrintWriterprintWriter=resp.getWriter(); printWriter.print(textMsg2Xml);
2)、实现2-回复图文消息:
//实例2,发送图文消息。请查看文档关于“回复图文消息”的xml格式 //第一步:按照回复图文信息构造需要的参数 List<Article>articles=newArrayList<Article>(); Articlea=newArticle(); a.setTitle("我是图片标题"); a.setUrl("www.baidu.com");//该地址是点击图片跳转后 a.setPicUrl("http://b.hiphotos.baidu.com/image/pic/item/08f790529822720ea5d058ba7ccb0a46f21fab50.jpg");//该地址是一个有效的图片地址 a.setDescription("我是图片的描述"); articles.add(a); PicAndTextMsgpicAndTextMsg=newPicAndTextMsg(); picAndTextMsg.setToUserName(map.get("FromUserName"));//发送和接收信息“User”刚好相反 picAndTextMsg.setFromUserName(map.get("ToUserName")); picAndTextMsg.setCreateTime(newDate().getTime());//消息创建时间(整型) picAndTextMsg.setMsgType("news");//图文类型消息 picAndTextMsg.setArticleCount(1); picAndTextMsg.setArticles(articles); //第二步,将构造的信息转化为微信识别的xml格式【百度:xstreambean转xml】 XStreamxStream=newXStream(); xStream.alias("xml",picAndTextMsg.getClass()); xStream.alias("item",a.getClass()); StringpicAndTextMsg2Xml=xStream.toXML(picAndTextMsg); System.out.println(picAndTextMsg2Xml); //第三步,发送xml的格式信息给微信服务器,服务器转发给用户 PrintWriterprintWriter=resp.getWriter(); printWriter.print(picAndTextMsg2Xml);
该部分所有操作源码,可以直接使用
CoreServlet.java(包括服务器接入、接收用户发送消息、回复普通文字消息、回复图文消息。需要第三方jar:dom4j、xstream)
packagecom.gist.servlet; importjava.io.IOException; importjava.io.InputStream; importjava.io.PrintWriter; importjava.security.MessageDigest; importjava.security.NoSuchAlgorithmException; importjava.util.ArrayList; importjava.util.Arrays; importjava.util.Date; importjava.util.HashMap; importjava.util.List; importjava.util.Map; importjava.util.Set; importjavax.servlet.ServletException; importjavax.servlet.annotation.WebServlet; importjavax.servlet.http.HttpServlet; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importorg.dom4j.Document; importorg.dom4j.DocumentException; importorg.dom4j.Element; importorg.dom4j.io.SAXReader; importcom.gist.bean.Article; importcom.gist.bean.PicAndTextMsg; importcom.thoughtworks.xstream.XStream; /** *@author高远</n>邮箱:wgyscsf@163.com</n>博客http://blog.csdn.net/wgyscsf</n> *编写时期2016-4-3下午4:34:05 */ @WebServlet("/CoreServlet") publicclassCoreServletextendsHttpServlet{ privatestaticfinallongserialVersionUID=1L; StringTAG="CoreServlet"; /* *第二步:验证服务器地址的有效性开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上, *GET请求携带四个参数:signature、timestamp、nonce、echostr *开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容, *则接入生效,成为开发者成功,否则接入失败。 * *加密/校验流程如下:1.将token、timestamp、nonce三个参数进行字典序排序2. *将三个参数字符串拼接成一个字符串进行sha1加密3.开发者获得加密后的字符串可与signature对比,标识该请求来源于微信 */ /* *字典排序(lexicographical *order)是一种对于随机变量形成序列的排序方法。其方法是,按照字母顺序,或者数字小大顺序,由小到大的形成序列。 */ @Override protectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp) throwsServletException,IOException{ //设置编码 req.setCharacterEncoding("utf-8"); resp.setContentType("html/text;charset=utf-8"); resp.setCharacterEncoding("utf-8"); //获取输出流 PrintWriterprintWriter=resp.getWriter(); //设置一个全局的token,开发者自己设置。api这样解释:Token可由开发者可以任意填写, //用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性) Stringtoken="wgyscsf"; //根据api说明,获取上述四个参数 Stringsignature=req.getParameter("signature"); Stringtimestamp=req.getParameter("timestamp"); Stringnonce=req.getParameter("nonce"); Stringechostr=req.getParameter("echostr"); ////temp:临时打印,观看返回参数情况 //System.out.println(TAG+":signature:"+signature+",timestamp:" //+timestamp+",nonce:"+nonce+",echostr:"+echostr); //根据api所说的“加密/校验流程”进行接入。共计三步 //第一步:将token、timestamp、nonce三个参数进行字典序排序 String[]parms=newString[]{token,timestamp,nonce};//将需要字典序排列的字符串放到数组中 Arrays.sort(parms);//按照api要求进行字典序排序 //第二步:将三个参数字符串拼接成一个字符串进行sha1加密 //拼接字符串 StringparmsString="";//注意,此处不能=null。 for(inti=0;i<parms.length;i++){ parmsString+=parms[i]; } //sha1加密 StringmParms=null;//加密后的结果 MessageDigestdigest=null; try{ digest=java.security.MessageDigest.getInstance("SHA"); }catch(NoSuchAlgorithmExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } digest.update(parmsString.getBytes()); bytemessageDigest[]=digest.digest(); //CreateHexString StringBufferhexString=newStringBuffer(); //字节数组转换为十六进制数 for(inti=0;i<messageDigest.length;i++){ StringshaHex=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[thisisatest]]></Content> *<MsgId>1234567890123456</MsgId></xml>那么,我们就可以进行统一处理。 */ /* *我们先获取输入流,看输入流里面的信息。通过测试打印输出流,我们可以看到每次用户请求,都会收到req请求,请求格式是xml格式,该信息在文档中有说明。 */ /* *特别注意,req.getInputStream()只能获取一次,并且只能读取一次。如果想要多次读取,需要另外想办法。为了简单起见, *我们只获取一次req.getInputStream(),不再打印输出流信息。直接打印解析后的信息。 */ @Override protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp) throwsServletException,IOException{ //设置编码 req.setCharacterEncoding("utf-8"); resp.setContentType("html/text;charset=utf-8"); resp.setCharacterEncoding("utf-8"); /* *该部分我们获取用户发送的信息,并且解析成<K,V>的形式进行显示 */ //解析用户发送过来的信息 InputStreamis=req.getInputStream();//拿取请求流 //将解析结果存储在HashMap中 Map<String,String>map=newHashMap<String,String>(); //解析xml,将获取到的返回结果xml进行解析成我们习惯的文字信息 SAXReaderreader=newSAXReader();//第三方jar:dom4j【百度:saxreader解析xml】 Documentdocument=null; try{ document=reader.read(is); }catch(DocumentExceptione1){ //TODOAuto-generatedcatchblock e1.printStackTrace(); } //得到xml根元素 Elementroot=document.getRootElement(); //得到根元素的所有子节点 List<Element>elementList=root.elements(); //遍历所有子节点 for(Elemente:elementList) map.put(e.getName(),e.getText()); //测试输出 Set<String>keySet=map.keySet(); //测试输出解析后用户发过来的信息 System.out.println(TAG+":解析用户发送过来的信息开始"); for(Stringkey:keySet){ System.out.println(key+":"+map.get(key)); } System.out.println(TAG+":解析用户发送过来的信息结束"); /* *该部分我们尝试按照文档的要求格式给用户回复文本信息、图文消息。重点:按照文档要求构造需要的参数。特别注意:参数区分大小写。 */ ////实例1:发送普通文本消息,请查看文档关于“回复文本消息”的xml格式 // ////第一步:按照回复文本信息构造需要的参数 //TextMsgtextMsg=newTextMsg(); //textMsg.setToUserName(map.get("FromUserName"));//发送和接收信息“User”刚好相反 //textMsg.setFromUserName(map.get("ToUserName")); //textMsg.setCreateTime(newDate().getTime());//消息创建时间(整型) //textMsg.setMsgType("text");//文本类型消息 //textMsg.setContent("我是服务器回复给用户的信息"); // //////第二步,将构造的信息转化为微信识别的xml格式【百度:xstreambean转xml】 //XStreamxStream=newXStream(); //xStream.alias("xml",textMsg.getClass()); //StringtextMsg2Xml=xStream.toXML(textMsg); //System.out.println(textMsg2Xml); // //////第三步,发送xml的格式信息给微信服务器,服务器转发给用户 //PrintWriterprintWriter=resp.getWriter(); //printWriter.print(textMsg2Xml); ////实例2,发送图文消息。请查看文档关于“回复图文消息”的xml格式 //第一步:按照回复图文信息构造需要的参数 List<Article>articles=newArrayList<Article>(); Articlea=newArticle(); a.setTitle("我是图片标题"); a.setUrl("www.baidu.com");//该地址是点击图片跳转后 a.setPicUrl("http://b.hiphotos.baidu.com/image/pic/item/08f790529822720ea5d058ba7ccb0a46f21fab50.jpg");//该地址是一个有效的图片地址 a.setDescription("我是图片的描述"); articles.add(a); PicAndTextMsgpicAndTextMsg=newPicAndTextMsg(); picAndTextMsg.setToUserName(map.get("FromUserName"));//发送和接收信息“User”刚好相反 picAndTextMsg.setFromUserName(map.get("ToUserName")); picAndTextMsg.setCreateTime(newDate().getTime());//消息创建时间(整型) picAndTextMsg.setMsgType("news");//图文类型消息 picAndTextMsg.setArticleCount(1); picAndTextMsg.setArticles(articles); //第二步,将构造的信息转化为微信识别的xml格式【百度:xstreambean转xml】 XStreamxStream=newXStream(); xStream.alias("xml",picAndTextMsg.getClass()); xStream.alias("item",a.getClass()); StringpicAndTextMsg2Xml=xStream.toXML(picAndTextMsg); System.out.println(picAndTextMsg2Xml); //第三步,发送xml的格式信息给微信服务器,服务器转发给用户 PrintWriterprintWriter=resp.getWriter(); printWriter.print(picAndTextMsg2Xml); } }
TestMsg.java(普通文字消息bean)
packagecom.gist.bean; /** *@author高远</n>邮箱:wgyscsf@163.com</n>博客http://blog.csdn.net/wgyscsf</n> *编写时期2016-4-4下午2:09:27 */ publicclassTextMsg{ privateStringToUserName; privateStringFromUserName; privatelongCreateTime; privateStringMsgType; @Override publicStringtoString(){ return"TextMsg[ToUserName="+ToUserName+",FromUserName=" +FromUserName+",CreateTime="+CreateTime+",MsgType=" +MsgType+",Content="+Content+"]"; } privateStringContent; publicTextMsg(StringtoUserName,StringfromUserName,longcreateTime, StringmsgType,Stringcontent){ super(); ToUserName=toUserName; FromUserName=fromUserName; CreateTime=createTime; MsgType=msgType; Content=content; } publicTextMsg(){ super(); } publicStringgetToUserName(){ returnToUserName; } publicvoidsetToUserName(StringtoUserName){ ToUserName=toUserName; } publicStringgetFromUserName(){ returnFromUserName; } publicvoidsetFromUserName(StringfromUserName){ FromUserName=fromUserName; } publiclonggetCreateTime(){ returnCreateTime; } publicvoidsetCreateTime(longcreateTime){ CreateTime=createTime; } publicStringgetMsgType(){ returnMsgType; } publicvoidsetMsgType(StringmsgType){ MsgType=msgType; } publicStringgetContent(){ returnContent; } publicvoidsetContent(Stringcontent){ Content=content; } }
Article.java(图文消息内部Articlebean)
packagecom.gist.bean; /** *@author高远</n>邮箱:wgyscsf@163.com</n>博客http://blog.csdn.net/wgyscsf</n> *编写时期2016-4-4下午2:47:08 */ publicclassArticle{ privateStringTitle; @Override publicStringtoString(){ return"item[Title="+Title+",Description="+Description +",PicUrl="+PicUrl+",Url="+Url+"]"; } publicStringgetTitle(){ returnTitle; } publicvoidsetTitle(Stringtitle){ Title=title; } publicStringgetDescription(){ returnDescription; } publicvoidsetDescription(Stringdescription){ Description=description; } publicStringgetPicUrl(){ returnPicUrl; } publicvoidsetPicUrl(StringpicUrl){ PicUrl=picUrl; } publicStringgetUrl(){ returnUrl; } publicvoidsetUrl(Stringurl){ Url=url; } privateStringDescription; privateStringPicUrl; privateStringUrl; }
PicAndTextMsg.java(图文消息bean)
packagecom.gist.bean; importjava.util.List; /** *@author高远</n>邮箱:wgyscsf@163.com</n>博客http://blog.csdn.net/wgyscsf</n> *编写时期2016-4-4下午2:47:08 */ publicclassPicAndTextMsg{ privateStringToUserName; privateStringFromUserName; privatelongCreateTime; privateStringMsgType; privateintArticleCount; privateList<Article>Articles; @Override publicStringtoString(){ return"PicAndTextMsg[ToUserName="+ToUserName+",FromUserName=" +FromUserName+",CreateTime="+CreateTime+",MsgType=" +MsgType+",ArticleCount="+ArticleCount+",Articles=" +Articles+"]"; } publicStringgetToUserName(){ returnToUserName; } publicvoidsetToUserName(StringtoUserName){ ToUserName=toUserName; } publicStringgetFromUserName(){ returnFromUserName; } publicvoidsetFromUserName(StringfromUserName){ FromUserName=fromUserName; } publiclonggetCreateTime(){ returnCreateTime; } publicvoidsetCreateTime(longcreateTime){ CreateTime=createTime; } publicStringgetMsgType(){ returnMsgType; } publicvoidsetMsgType(StringmsgType){ MsgType=msgType; } publicintgetArticleCount(){ returnArticleCount; } publicvoidsetArticleCount(intarticleCount){ ArticleCount=articleCount; } publicList<Article>getArticles(){ returnArticles; } publicvoidsetArticles(List<Article>articles){ Articles=articles; } }
更多精彩内容请点击《Android微信开发教程汇总》,《java微信开发教程汇总》欢迎大家学习阅读。
以上就是本文的全部内容,希望对大家学习开java微信API有所帮助,也希望大家继续关注新内容的更新,不要错过哦!