上次已经搭建好了开发环境,接着可以和微信公众号进行对接.
总体思路
- 服务器的验证
Servlet 用于和微信服务器通信.根据微信公众号开发者文档,微信服务器会发送GET请求给我们所填的URL的服务器.同时带有四个参数:signature,timestamp、nonce,echostr,需要将timestamp、nonce和自己设置的Token排序并进行sha1加密,再与其携带的signature参数比较.如果相等,则该请求来自微信服务器,并返回echostr.
- 消息的接受和发送
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
开发文档这样写的.所以要从用户发送的消息里提取信息的话,就要先解析xml数据.发送信息个用户也一样,需要将先数据打包成xml再post.
服务器的验证
既然微信服务器发送的是GET请求,新建一个WechatServlet类继承HttpServlet,可以重写Servlet的doGet方法,从请求里得到四个参数,再进行验证.
1
2
3
4
|
String signature=request.getParameter("signature");
String timestamp=request.getParameter("timestamp");
String nonce=request.getParameter("nonce");
String echostr=request.getParameter("echostr");
|
然后就是验证的工作了.
排序:
1
2
3
4
5
6
7
8
|
String array[]=new String[]{token,timestamp,nonce};
//将token、timestamp、nonce三个参数进行字典序排序
Arrays.sort(array);
//重组字符串
StringBuilder builder=new StringBuilder();
for (int i=0;i<array.length;i++){
builder.append(array[i]);
}
|
加密:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
MessageDigest md = null;
String tmpStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
// 将三个参数字符串拼接成一个字符串进行sha1加密
byte[] digest = md.digest(builder.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
builder= null;
if (tmpStr!=null&tmpStr.equals(signature.toUpperCase())){
isTrue=true;
}
return isTrue;
|
整体代码,看下图
填写Token和URL
在微信公众号里填写Token和URL,首先要在web.xml里配置Servlet.要填写的URL就是http://你的域名(或ip)/应用名/Servlet地址.
Token
就是自己在验证是设定的值.如果一切都没问题的话,
.
消息的接受和被动回复
- 用到两个开源项目,分别是xStream和dom4j.都是用来处理xml的.
- 新建一个MsgUtil类用来处理消息(解析xml,把对象打包成xml格式).
- 接受消息,以文本消息为例,xml的参数如下
xml的数据结构是这样的
1
2
3
4
5
6
7
8
|
<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>
|
- 可以把这些数据都封装成一个TextMsg对象,如果考虑到其他类型的消息,那么可以有一个BaseMsg类,让TextMsg,ImageMsg等等去继承他.
- 发送消息的xml结果也一样,少了MsgId这个参数而已.
- 嗯,每个参数值都有
![CDATA[]]标记
.待会在发送消息的时候也需要加上标记
接收消息
解析xml
重写doPost方法,把解析出来的数据放入一个Map.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException,IOException{
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter writer=response.getWriter();
MsgUtil msgUtil=new MsgUtil();
String sendMsg=null;
try {
//解析xml
Map<String,String> map=msgUtil.parseXml(request);
String ToUserName=map.get("ToUserName");
String FromUserName=map.get("FromUserName");
Long CreateTime= Long.valueOf(Integer.valueOf(map.get("CreateTime")));
String Content=map.get("Content");
String MsgType=map.get("MsgType");
}catch (Exception e){
e.printStackTrace();
}finally {
if (writer!=null){
writer.close();
}
}
|
被动发送消息
上面已经从用户发送过来的消息里得到了用户的openid(FromUserName).需要注意的是发送消息时,FromUserName就变成了公众号的Appid,ToUserName才是用户的openid.MsgUtil里添加一个方法:
1
2
3
4
5
6
7
8
9
10
11
|
public String initalMessage(String ToUserName,String FromUserName,String Content){
TextMsg textMsg=new TextMsg();
textMsg.setContent(Content);
textMsg.setFromUserName(ToUserName);
textMsg.setToUserName(FromUserName);
textMsg.setMsgType(MESSAGE_TEXT);
textMsg.setCreateTime(new Date().getTime());
//打包成xml格式
String xmlmsg=messageToXml(textMsg);
return xmlmsg;
}
|
然后在WechatServlet里调用,
1
2
3
4
5
6
|
if (msgUtil.MESSAGE_TEXT.equals(MsgType)){
sendMsg=msgUtil.initalMessage(ToUserName,FromUserName,"Hello "+Content);
if (Content.equals("view")){
//Todo
}
}
|
打包xml
思考
完成了基本的消息接收和被动的回复.个人感觉处理Json数据比xml数据更加方便,java有封装好的直接处理json的类.微信后台API是不是也应该适配一下,方便开发者?那么下次更新的是Access Token的获取和菜单的创建.==.