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有所帮助,也希望大家继续关注新内容的更新,不要错过哦!