前面两章已经介绍了如何接入微信公众平台,这一章说说消息的接收和发送
可以先了解公众平台的消息api接口(接收消息,发送消息)
http://mp.weixin.qq.com/wiki/index.php
接收消息
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF
接收的消息类型有6种,分别为:
可以根据官方的api提供的字段建立对应的实体类
如:文本消息
有很多属性是所有消息类型都需要的,可以把这些信息提取出来建立一个基类
1. package
2.
3. /**
4. * 消息基类(用户 -> 公众帐号)
5. *
6. */
7. public class
8. /**
9. * 开发者微信号
10. */
11. private
12. /**
13. * 发送方帐号(一个OpenID)
14. */
15. private
16. /**
17. * 消息创建时间 (整型)
18. */
19. private long
20.
21. /**
22. * 消息类型 text、image、location、link
23. */
24. private
25.
26. /**
27. * 消息id,64位整型
28. */
29. private long
30.
31. public
32. return
33. }
34.
35. public void
36. ToUserName = toUserName;
37. }
38.
39. public
40. return
41. }
42.
43. public void
44. FromUserName = fromUserName;
45. }
46.
47. public long
48. return
49. }
50.
51. public void setCreateTime(long
52. CreateTime = createTime;
53. }
54.
55. public
56. return
57. }
58.
59. public void
60. MsgType = msgType;
61. }
62.
63. public long
64. return
65. }
66.
67. public void setMsgId(long
68. MsgId = msgId;
69. }
70.
71. }
接收的文本消息
1. package
2.
3. /**
4. * 文本消息
5. */
6. public class TextMessage extends
7. /**
8. * 回复的消息内容
9. */
10. private
11.
12. public
13. return
14. }
15.
16. public void
17. Content = content;
18. }
19. }
接收的图片消息
1. package
2.
3. public class ImageMessage extends
4.
5. private
6.
7. public
8. return
9. }
10.
11. public void
12. this.picUrl = picUrl;
13. }
14.
15. }
接收的链接消息
1. package
2.
3.
4. public class LinkMessage extends
5. /**
6. * 消息标题
7. */
8. private
9. /**
10. * 消息描述
11. */
12. private
13. /**
14. * 消息链接
15. */
16. private
17.
18. public
19. return
20. }
21.
22. public void
23. Title = title;
24. }
25.
26. public
27. return
28. }
29.
30. public void
31. Description = description;
32. }
33.
34. public
35. return
36. }
37.
38. public void
39. Url = url;
40. }
41.
42. }
接收的语音消息
1. package
2.
3. /**
4. * 语音消息
5. *
6. * @author Caspar
7. *
8. */
9. public class VoiceMessage extends
10. /**
11. * 媒体ID
12. */
13. private
14. /**
15. * 语音格式
16. */
17. private
18.
19. public
20. return
21. }
22.
23. public void
24. MediaId = mediaId;
25. }
26.
27. public
28. return
29. }
30.
31. public void
32. Format = format;
33. }
34.
35. }
接收的地理位置消息
1. package
2.
3.
4. /**
5. * 位置消息
6. *
7. * @author caspar
8. *
9. */
10. public class LocationMessage extends
11. /**
12. * 地理位置维度
13. */
14. private
15. /**
16. * 地理位置经度
17. */
18. private
19.
20. /**
21. * 地图缩放大小
22. */
23. private
24.
25. /**
26. * 地理位置信息
27. */
28. private
29.
30. public
31. return
32. }
33.
34. public void
35. Location_X = location_X;
36. }
37.
38. public
39. return
40. }
41.
42. public void
43. Location_Y = location_Y;
44. }
45.
46. public
47. return
48. }
49.
50. public void
51. Scale = scale;
52. }
53.
54. public
55. return
56. }
57.
58. public void
59. Label = label;
60. }
61.
62. }
发送被动响应消息
对于每一个POST请求,开发者在响应包(Get)中返回特定XML结构,对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。请注意,回复图片等多媒体消息时需要预先上传多媒体文件到微信服务器,只支持认证服务号。
同样,建立响应消息的对应实体类
也把公共的属性提取出来,封装成基类
响应消息的基类
1. package
2.
3. /**
4. * 消息基类(公众帐号 -> 用户)
5. */
6. public class
7.
8. /**
9. * 接收方帐号(收到的OpenID)
10. */
11. private
12. /**
13. * 开发者微信号
14. */
15. private
16. /**
17. * 消息创建时间 (整型)
18. */
19. private long
20.
21. /**
22. * 消息类型
23. */
24. private
25.
26. /**
27. * 位0x0001被标志时,星标刚收到的消息
28. */
29. private int
30.
31. public
32. return
33. }
34.
35. public void
36. ToUserName = toUserName;
37. }
38.
39. public
40. return
41. }
42.
43. public void
44. FromUserName = fromUserName;
45. }
46.
47. public long
48. return
49. }
50.
51. public void setCreateTime(long
52. CreateTime = createTime;
53. }
54.
55. public
56. return
57. }
58.
59. public void
60. MsgType = msgType;
61. }
62.
63. public int
64. return
65. }
66.
67. public void setFuncFlag(int
68. FuncFlag = funcFlag;
69. }
70. }
响应文本消息
1. package
2.
3.
4. /**
5. * 文本消息
6. */
7. public class TextMessage extends
8. /**
9. * 回复的消息内容
10. */
11. private
12.
13. public
14. return
15. }
16.
17. public void
18. Content = content;
19. }
20. }
响应图文消息
1. package
2.
3. import
4.
5. /**
6. * 多图文消息,
7. * 单图文的时候 Articles 只放一个就行了
8. * @author Caspar.chen
9. */
10. public class NewsMessage extends
11. /**
12. * 图文消息个数,限制为10条以内
13. */
14. private int
15. /**
16. * 多条图文消息信息,默认第一个item为大图
17. */
18. private
19.
20. public int
21. return
22. }
23.
24. public void setArticleCount(int
25. ArticleCount = articleCount;
26. }
27.
28. public
29. return
30. }
31.
32. public void
33. Articles = articles;
34. }
35. }
图文消息的定义
1. package
2.
3. /**
4. * 图文消息
5. *
6. */
7. public class
8. /**
9. * 图文消息名称
10. */
11. private
12.
13. /**
14. * 图文消息描述
15. */
16. private
17.
18. /**
19. * 图片链接,支持JPG、PNG格式,<br>
20. * 较好的效果为大图640*320,小图80*80
21. */
22. private
23.
24. /**
25. * 点击图文消息跳转链接
26. */
27. private
28.
29. public
30. return
31. }
32.
33. public void
34. Title = title;
35. }
36.
37. public
38. return null == Description ? ""
39. }
40.
41. public void
42. Description = description;
43. }
44.
45. public
46. return null == PicUrl ? ""
47. }
48.
49. public void
50. PicUrl = picUrl;
51. }
52.
53. public
54. return null == Url ? ""
55. }
56.
57. public void
58. Url = url;
59. }
60.
61. }
响应音乐消息
1. package
2.
3.
4.
5. /**
6. * 音乐消息
7. */
8. public class MusicMessage extends
9. /**
10. * 音乐
11. */
12. private
13.
14. public
15. return
16. }
17.
18. public void
19. Music = music;
20. }
21. }
音乐消息的定义
1. package
2.
3. /**
4. * 音乐消息
5. */
6. public class
7. /**
8. * 音乐名称
9. */
10. private
11.
12. /**
13. * 音乐描述
14. */
15. private
16.
17. /**
18. * 音乐链接
19. */
20. private
21.
22. /**
23. * 高质量音乐链接,WIFI环境优先使用该链接播放音乐
24. */
25. private
26.
27. public
28. return
29. }
30.
31. public void
32. Title = title;
33. }
34.
35. public
36. return
37. }
38.
39. public void
40. Description = description;
41. }
42.
43. public
44. return
45. }
46.
47. public void
48. MusicUrl = musicUrl;
49. }
50.
51. public
52. return
53. }
54.
55. public void
56. HQMusicUrl = musicUrl;
57. }
58.
59. }
构建好之后的项目结构图为
到这里,请求消息和响应消息的实体类都定义好了
解析请求消息
用户向微信公众平台发送消息后,微信公众平台会通过post请求发送给我们。
上一章中WeixinController 类的post方法我们空着
现在我们要在这里处理用户请求了。
因为微信的发送和接收都是用xml格式的,所以我们需要处理请求过来的xml格式。
发送的时候也需要转化成xml格式再发送给微信,所以封装了消息处理的工具类,用到dome4j和xstream两个jar包
1. package
2.
3. import
4. import
5. import
6. import
7. import
8.
9. import
10.
11. import
12. import
13. import
14.
15. import
16. import
17. import
18. import
19. import
20. import
21. import
22. import
23. import
24.
25. /**
26. * 消息工具类
27. *
28. */
29. public class
30.
31. /**
32. * 解析微信发来的请求(XML)
33. *
34. * @param request
35. * @return
36. * @throws Exception
37. */
38. public static Map<String, String> parseXml(HttpServletRequest request) throws
39. // 将解析结果存储在HashMap中
40. new
41.
42. // 从request中取得输入流
43. InputStream inputStream = request.getInputStream();
44. // 读取输入流
45. new
46. Document document = reader.read(inputStream);
47. // 得到xml根元素
48. Element root = document.getRootElement();
49. // 得到根元素的所有子节点
50.
51. @SuppressWarnings("unchecked")
52. List<Element> elementList = root.elements();
53.
54. // 遍历所有子节点
55. for
56. map.put(e.getName(), e.getText());
57.
58. // 释放资源
59. inputStream.close();
60. null;
61.
62. return
63. }
64.
65. /**
66. * 文本消息对象转换成xml
67. *
68. * @param textMessage 文本消息对象
69. * @return xml
70. */
71. public static
72. "xml", textMessage.getClass());
73. return
74. }
75.
76. /**
77. * 音乐消息对象转换成xml
78. *
79. * @param musicMessage 音乐消息对象
80. * @return xml
81. */
82. public static
83. "xml", musicMessage.getClass());
84. return
85. }
86.
87. /**
88. * 图文消息对象转换成xml
89. *
90. * @param newsMessage 图文消息对象
91. * @return xml
92. */
93. public static
94. "xml", newsMessage.getClass());
95. "item", new
96. return
97. }
98.
99. /**
100. * 扩展xstream,使其支持CDATA块
101. *
102. */
103. private static XStream xstream = new XStream(new
104. public
105. return new
106. // 对所有xml节点的转换都增加CDATA标记
107. boolean cdata = true;
108. protected void
109. if
110. "<![CDATA[");
111. writer.write(text);
112. "]]>");
113. else
114. writer.write(text);
115. }
116. }
117. };
118. }
119. });
120.
121.
122. }
接下来在处理业务逻辑,建立一个接收并响应消息的service类,并针对用户输入的1或2回复不同的信息给用户
1. package
2.
3. import
4. import
5.
6. import
7.
8. import
9. import
10.
11. import
12. import
13. import
14. import
15.
16. @Service("coreService")
17. public class CoreServiceImpl implements
18.
19. public static Logger log = Logger.getLogger(CoreServiceImpl.class);
20.
21.
22. @Override
23. public
24. null;
25. try
26. // xml请求解析
27. Map<String, String> requestMap = MessageUtil.parseXml(request);
28.
29. // 发送方帐号(open_id)
30. "FromUserName");
31. // 公众帐号
32. "ToUserName");
33. // 消息类型
34. "MsgType");
35.
36. new
37. textMessage.setToUserName(fromUserName);
38. textMessage.setFromUserName(toUserName);
39. new
40. textMessage.setMsgType(Constant.RESP_MESSAGE_TYPE_TEXT);
41. 0);
42. // 文本消息
43. if
44. // 接收用户发送的文本消息内容
45. "Content");
46.
47. if ("1".equals(content)) {
48. "1是很好的");
49. // 将文本消息对象转换成xml字符串
50. respMessage = MessageUtil.textMessageToXml(textMessage);
51. else if ("2".equals(content)) {
52. "我不是2货");
53. // 将文本消息对象转换成xml字符串
54. respMessage = MessageUtil.textMessageToXml(textMessage);
55. }
56. }
57.
58.
59. catch
60. e.printStackTrace();
61. }
62. return
63. }
64.
65.
66. }
接下来在controller里面的post方法里面调用即可
WeixinController类的完整代码
1. package
2.
3. import
4. import
5. import
6.
7. import
8. import
9. import
10.
11. import
12. import
13. import
14.
15. import
16. import
17.
18. @Controller
19. @RequestMapping("/weixinCore")
20. public class
21.
22. @Resource(name="coreService")
23. private
24.
25. @RequestMapping(method = RequestMethod.GET)
26. public void
27. // 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
28. "signature");
29. // 时间戳
30. "timestamp");
31. // 随机数
32. "nonce");
33. // 随机字符串
34. "echostr");
35.
36. null;
37. try
38. out = response.getWriter();
39. // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,否则接入失败
40. if
41. out.print(echostr);
42. }
43. catch
44. e.printStackTrace();
45. finally
46. out.close();
47. null;
48. }
49. }
50.
51. @RequestMapping(method = RequestMethod.POST)
52. public void
53. try
54. "UTF-8");
55. catch
56. e.printStackTrace();
57. }
58. "UTF-8");
59.
60. // 调用核心业务类接收消息、处理消息
61. String respMessage = coreService.processRequest(request);
62.
63. // 响应消息
64. null;
65. try
66. out = response.getWriter();
67. out.print(respMessage);
68. catch
69. e.printStackTrace();
70. finally
71. out.close();
72. null;
73. }
74. }
75.
76. }
效果如下:
ok,大功告成,消息的接收和发送就写完了。