4.4.3 封装消息处理工具

在org.liufeng.course.util包下创建一个消息处理工具类MessageUtil,该类主要包含了前述内容讲解的解析请求消息和响应消息对象转XML中涉及的方法。MessageUtil类的源代码如下所示。

  1. package org.liufeng.course.util;
  2.  
  3. import java.io.InputStream;
  4. import java.io.Writer;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import java.util.Map;
  8. import javax.servlet.http.HttpServletRequest;
  9. import org.dom4j.Document;
  10. import org.dom4j.Element;
  11. import org.dom4j.io.SAXReader;
  12. import org.liufeng.course.message.resp.Article;
  13. import org.liufeng.course.message.resp.ImageMessage;
  14. import org.liufeng.course.message.resp.MusicMessage;
  15. import org.liufeng.course.message.resp.NewsMessage;
  16. import org.liufeng.course.message.resp.TextMessage;
  17. import org.liufeng.course.message.resp.VideoMessage;
  18. import org.liufeng.course.message.resp.VoiceMessage;
  19. import com.thoughtworks.xstream.XStream;
  20. import com.thoughtworks.xstream.core.util.QuickWriter;
  21. import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
  22. import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
  23. import com.thoughtworks.xstream.io.xml.XppDriver;
  24.  
  25. /**
  26. * 消息处理工具类
  27. *
  28. * @author liufeng
  29. * @date 2013-09-15
  30. */
  31. public class MessageUtil {
  32. // 请求消息类型:文本
  33. public static final String REQ_MESSAGE_TYPE_TEXT = "text";
  34. // 请求消息类型:图片
  35. public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
  36. // 请求消息类型:语音
  37. public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
  38. // 请求消息类型:视频
  39. public static final String REQ_MESSAGE_TYPE_VIDEO = "video";
  40. // 请求消息类型:地理位置
  41. public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
  42. // 请求消息类型:链接
  43. public static final String REQ_MESSAGE_TYPE_LINK = "link";
  44.  
  45. // 请求消息类型:事件推送
  46. public static final String REQ_MESSAGE_TYPE_EVENT = "event";
  47.  
  48. // 事件类型:subscribe(订阅)
  49. public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
  50. // 事件类型:unsubscribe(取消订阅)
  51. public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
  52. // 事件类型:scan(关注用户扫描带参数二维码)
  53. public static final String EVENT_TYPE_SCAN = "scan";
  54. // 事件类型:LOCATION(上报地理位置)
  55. public static final String EVENT_TYPE_LOCATION = "LOCATION";
  56. // 事件类型:CLICK(自定义菜单)
  57. public static final String EVENT_TYPE_CLICK = "CLICK";
  58.  
  59. // 响应消息类型:文本
  60. public static final String RESP_MESSAGE_TYPE_TEXT = "text";
  61. // 响应消息类型:图片
  62. public static final String RESP_MESSAGE_TYPE_IMAGE = "image";
  63. // 响应消息类型:语音
  64. public static final String RESP_MESSAGE_TYPE_VOICE = "voice";
  65. // 响应消息类型:视频
  66. public static final String RESP_MESSAGE_TYPE_VIDEO = "video";
  67. // 响应消息类型:音乐
  68. public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
  69. // 响应消息类型:图文
  70. public static final String RESP_MESSAGE_TYPE_NEWS = "news";
  71.  
  72. /**
  73. * 解析微信发来的请求(XML)
  74. *
  75. * @param request
  76. * @return Map<String, String>
  77. * @throws Exception
  78. */
  79. @SuppressWarnings("unchecked")
  80. public static Map<String, String> parseXml(HttpServletRequest request)
  81. throws Exception {
  82. // 将解析结果存储在HashMap中
  83. Map<String, String> map = new HashMap<String, String>();
  84.  
  85. // 从request中取得输入流
  86. InputStream inputStream = request.getInputStream();
  87. // 读取输入流
  88. SAXReader reader = new SAXReader();
  89. Document document = reader.read(inputStream);
  90. // 得到XML根元素
  91. Element root = document.getRootElement();
  92. // 得到根元素的所有子节点
  93. List<Element> elementList = root.elements();
  94.  
  95. // 遍历所有子节点
  96. for (Element e : elementList)
  97. map.put(e.getName(), e.getText());
  98.  
  99. // 释放资源
  100. inputStream.close();
  101. inputStream = null;
  102.  
  103. return map;
  104. }
  105.  
  106. /**
  107. * 扩展xstream使其支持CDATA
  108. */
  109. private static XStream xstream = new XStream(new XppDriver() {
  110. public HierarchicalStreamWriter createWriter(Writer out) {
  111. return new PrettyPrintWriter(out) {
  112. // 对所有XML节点的转换都增加CDATA标记
  113. boolean cdata = true;
  114.  
  115. @SuppressWarnings("unchecked")
  116. public void startNode(String name, Class clazz) {
  117. super.startNode(name, clazz);
  118. }
  119.  
  120. protected void writeText(QuickWriter writer, String text) {
  121. if (cdata) {
  122. writer.write("<![CDATA[");
  123. writer.write(text);
  124. writer.write("]]>");
  125. } else {
  126. writer.write(text);
  127. }
  128. }
  129. };
  130. }
  131. });
  132.  
  133. /**
  134. * 文本消息对象转换成XML
  135. *
  136. * @param textMessage 文本消息对象
  137. * @return xml
  138. */
  139. public static String messageToXml(TextMessage textMessage) {
  140. xstream.alias("xml", textMessage.getClass());
  141. return xstream.toXML(textMessage);
  142. }
  143.  
  144. /**
  145. * 图片消息对象转换成XML
  146. *
  147. * @param imageMessage 图片消息对象
  148. * @return xml
  149. */
  150. public static String messageToXml(ImageMessage imageMessage) {
  151. xstream.alias("xml", imageMessage.getClass());
  152. return xstream.toXML(imageMessage);
  153. }
  154.  
  155. /**
  156. * 语音消息对象转换成XML
  157. *
  158. * @param voiceMessage 语音消息对象
  159. * @return xml
  160. */
  161. public static String messageToXml(VoiceMessage voiceMessage) {
  162. xstream.alias("xml", voiceMessage.getClass());
  163. return xstream.toXML(voiceMessage);
  164. }
  165.  
  166. /**
  167. * 视频消息对象转换成XML
  168. *
  169. * @param videoMessage 视频消息对象
  170. * @return xml
  171. */
  172. public static String messageToXml(VideoMessage videoMessage) {
  173. xstream.alias("xml", videoMessage.getClass());
  174. return xstream.toXML(videoMessage);
  175. }
  176.  
  177. /**
  178. * 音乐消息对象转换成XML
  179. *
  180. * @param musicMessage 音乐消息对象
  181. * @return xml
  182. */
  183. public static String messageToXml(MusicMessage musicMessage) {
  184. xstream.alias("xml", musicMessage.getClass());
  185. return xstream.toXML(musicMessage);
  186. }
  187.  
  188. /**
  189. * 图文消息对象转换成XML
  190. *
  191. * @param newsMessage 图文消息对象
  192. * @return xml
  193. */
  194. public static String messageToXml(NewsMessage newsMessage) {
  195. xstream.alias("xml", newsMessage.getClass());
  196. xstream.alias("item", new Article().getClass());
  197. return xstream.toXML(newsMessage);
  198. }
  199. }

在MessageUtil类中定义了一系列成员变量,包括请求消息类型(文本、图片、语音、视频、地理位置、链接和事件推送)、事件类型(订阅、取消订阅、扫描带参数二维码、上报地理位置和自定义菜单)和响应消息类型(文本、图片、语音、视频、音乐和图文)。