com.wtxy.weixin.service
CoreService.java
1 package com.wtxy.weixin.service; 2 3 import java.util.Date; 4 import java.util.Map; 5 6 import javax.servlet.http.HttpServletRequest; 7 8 import com.wtxy.util.MessageUtil; 9 import com.wtxy.weixin.message.TextMessage; 10 11 /** 12 * 核心服务类 13 * 14 * @author Ran 15 * @date 2016-04-21 16 */ 17 public class CoreService { 18 /** 19 * 处理微信发来的请求 20 * 21 * @param request 22 * @return xml 23 */ 24 public static String processRequest(HttpServletRequest request) { 25 // xml格式的消息数据 26 String respXML = null; 27 28 TextMessage textMessage = new TextMessage(); 29 // 默认返回的文本消息内容 30 String respContent = "未知的消息类型!"; 31 try { 32 // 调用parseXml方法解析请求消息 33 Map<String, String> requestMap = MessageUtil.parseXML(request); 34 // 发送方帐号 35 String fromUserName = requestMap.get("FromUserName"); 36 // 开发者微信号 37 String toUserName = requestMap.get("ToUserName"); 38 // 消息类型 39 String msgType = requestMap.get("MsgType"); 40 41 // 回复文本消息 42 textMessage.setToUserName(fromUserName); 43 textMessage.setFromUserName(toUserName); 44 textMessage.setCreateTime(new Date().getTime()); 45 textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT); 46 47 // 文本消息 48 if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) { 49 String content = requestMap.get("Content"); 50 if (content.equals("开灯")){ 51 respContent = "灯已开!"; 52 //respContent = "您发送的是文本消息!内容是: "+content; 53 }else if(content.equals("关灯")){ 54 respContent = "灯已关!"; 55 } 56 57 } 58 // 图片消息 59 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) { 60 respContent = "您发送的是图片消息!"; 61 } 62 // 语音消息 63 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) { 64 respContent = "您发送的是语音消息!"; 65 } 66 // 视频消息 67 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VIDEO)) { 68 respContent = "您发送的是视频消息!"; 69 } 70 // 地理位置消息 71 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) { 72 respContent = "您发送的是地理位置消息!"; 73 } 74 // 链接消息 75 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) { 76 respContent = "您发送的是链接消息!"; 77 } 78 // 事件推送 79 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) { 80 // 事件类型 81 String eventType = requestMap.get("Event"); 82 // 关注 83 if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) { 84 respContent = "欢迎关注 智能管家wtxy!"; 85 } 86 // 取消关注 87 else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) { 88 // TODO 取消订阅后用户不会再收到公众账号发送的消息,因此不需要回复 89 } 90 // 扫描带参数二维码 91 else if (eventType.equals(MessageUtil.EVENT_TYPE_SCAN)) { 92 // TODO 处理扫描带参数二维码事件 93 } 94 // 上报地理位置 95 else if (eventType.equals(MessageUtil.EVENT_TYPE_LOCATION)) { 96 // TODO 处理上报地理位置事件 97 } 98 // 自定义菜单 99 else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) { 100 // TODO 处理菜单点击事件 101 } 102 } 103 // 设置文本消息的内容 104 textMessage.setContent(respContent); 105 // 将文本消息对象转换成xml 106 respXML = MessageUtil.messageToXML(textMessage); 107 } catch (Exception e) { 108 e.printStackTrace(); 109 } 110 return respXML; 111 } 112 }
com.wtxy.servlet
CoreServlet.java
1 package com.wtxy.servlet; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 import com.wtxy.util.SignUtil; 12 import com.wtxy.weixin.service.CoreService; 13 14 15 public class CoreServlet extends HttpServlet { 16 17 private static final long serialVersionUID = 4440739483644821987L; 18 19 /** 20 * 请求校验(确认请求来自微信服务器) 21 */ 22 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 23 // 微信加密签名 24 String signature = request.getParameter("signature"); 25 // 时间戳 26 String timestamp = request.getParameter("timestamp"); 27 // 随机数 28 String nonce = request.getParameter("nonce"); 29 // 随机字符串 30 String echostr = request.getParameter("echostr"); 31 32 PrintWriter out = response.getWriter(); 33 // 请求校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败 34 if (SignUtil.checkSignature(signature, timestamp, nonce)) { 35 out.print(echostr); 36 } 37 out.close(); 38 out = null; 39 } 40 41 /** 42 * 处理微信服务器发来的消息 43 */ 44 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 45 // 将请求、响应的编码均设置为UTF-8(防止中文乱码) 46 request.setCharacterEncoding("UTF-8"); 47 response.setCharacterEncoding("UTF-8"); 48 49 // 接收参数微信加密签名、 时间戳、随机数 50 String signature = request.getParameter("signature"); 51 String timestamp = request.getParameter("timestamp"); 52 String nonce = request.getParameter("nonce"); 53 54 PrintWriter out = response.getWriter(); 55 // 请求校验 56 if (SignUtil.checkSignature(signature, timestamp, nonce)) { 57 // 调用核心服务类接收处理请求 58 String respXML = CoreService.processRequest(request); 59 out.write(respXML); 60 } 61 out.close(); 62 out = null; 63 } 64 65 }
com.wtxy.util
MessageUtil.java
SignUtil
1 package com.wtxy.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 9 import javax.servlet.http.HttpServletRequest; 10 11 import org.dom4j.Document; 12 import org.dom4j.Element; 13 import org.dom4j.io.SAXReader; 14 15 import com.thoughtworks.xstream.XStream; 16 import com.thoughtworks.xstream.core.util.QuickWriter; 17 import com.thoughtworks.xstream.io.HierarchicalStreamWriter; 18 import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; 19 import com.thoughtworks.xstream.io.xml.XppDriver; 20 import com.wtxy.weixin.message.Article; 21 import com.wtxy.weixin.message.ImageMessage; 22 import com.wtxy.weixin.message.MusicMessage; 23 import com.wtxy.weixin.message.NewsMessage; 24 import com.wtxy.weixin.message.TextMessage; 25 import com.wtxy.weixin.message.VideoMessage; 26 import com.wtxy.weixin.message.VoiceMessage; 27 28 public class MessageUtil { 29 // 请求消息类型:文本 30 public static final String REQ_MESSAGE_TYPE_TEXT = "text"; 31 // 请求消息类型:图片 32 public static final String REQ_MESSAGE_TYPE_IMAGE = "image"; 33 // 请求消息类型:语音 34 public static final String REQ_MESSAGE_TYPE_VOICE = "voice"; 35 // 请求消息类型:视频 36 public static final String REQ_MESSAGE_TYPE_VIDEO = "video"; 37 // 请求消息类型:地理位置 38 public static final String REQ_MESSAGE_TYPE_LOCATION = "location"; 39 // 请求消息类型:链接 40 public static final String REQ_MESSAGE_TYPE_LINK = "link"; 41 42 // 请求消息类型:事件推送 43 public static final String REQ_MESSAGE_TYPE_EVENT = "event"; 44 45 // 事件类型:subscribe(订阅) 46 public static final String EVENT_TYPE_SUBSCRIBE = "subscribe"; 47 // 事件类型:unsubscribe(取消订阅) 48 public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe"; 49 // 事件类型:scan(用户已关注时的扫描带参数二维码) 50 public static final String EVENT_TYPE_SCAN = "scan"; 51 // 事件类型:LOCATION(上报地理位置) 52 public static final String EVENT_TYPE_LOCATION = "LOCATION"; 53 // 事件类型:CLICK(自定义菜单) 54 public static final String EVENT_TYPE_CLICK = "CLICK"; 55 56 // 响应消息类型:文本 57 public static final String RESP_MESSAGE_TYPE_TEXT = "text"; 58 // 响应消息类型:图片 59 public static final String RESP_MESSAGE_TYPE_IMAGE = "image"; 60 // 响应消息类型:语音 61 public static final String RESP_MESSAGE_TYPE_VOICE = "voice"; 62 // 响应消息类型:视频 63 public static final String RESP_MESSAGE_TYPE_VIDEO = "video"; 64 // 响应消息类型:音乐 65 public static final String RESP_MESSAGE_TYPE_MUSIC = "music"; 66 // 响应消息类型:图文 67 public static final String RESP_MESSAGE_TYPE_NEWS = "news"; 68 69 /** 70 * 解析微信发来的请求(XML) 71 * 72 * @param request 73 * @return Map<String, String> 74 * @throws Exception 75 */ 76 //@SuppressWarnings("unchecked") 77 public static HashMap<String, String> parseXML(HttpServletRequest request) throws Exception { 78 // 将解析结果存储在HashMap中 79 HashMap<String, String> map = new HashMap<String, String>(); 80 81 // 从request中取得输入流 82 InputStream inputStream = request.getInputStream(); 83 // 读取输入流 84 SAXReader reader = new SAXReader(); 85 Document document = reader.read(request.getInputStream()); 86 // 得到xml根元素 87 Element root = document.getRootElement(); 88 89 recursiveParseXML(root,map); 90 91 inputStream.close(); 92 inputStream = null; 93 94 return map; 95 } 96 97 private static void recursiveParseXML(Element root,HashMap<String, String> map){ 98 // 得到根元素的所有子节点 99 List<Element> elementList = root.elements(); 100 //判断有没有子元素列表 101 if(elementList.size() == 0){ 102 map.put(root.getName(), root.getText()); 103 }else{ 104 //遍历 105 for (Element e : elementList){ 106 recursiveParseXML(e,map); 107 } 108 } 109 } 110 111 /** 112 * 扩展xstream使其支持CDATA 113 */ 114 private static XStream xstream = new XStream(new XppDriver() { 115 public HierarchicalStreamWriter createWriter(Writer out) { 116 return new PrettyPrintWriter(out) { 117 // 对所有xml节点的转换都增加CDATA标记 118 boolean cdata = true; 119 120 //@SuppressWarnings("unchecked") 121 public void startNode(String name, Class clazz) { 122 super.startNode(name, clazz); 123 } 124 125 protected void writeText(QuickWriter writer, String text) { 126 if (cdata) { 127 writer.write("<![CDATA["); 128 writer.write(text); 129 writer.write("]]>"); 130 } else { 131 writer.write(text); 132 } 133 } 134 }; 135 } 136 }); 137 138 /** 139 * 文本消息对象转换成xml 140 * 141 * @param textMessage 文本消息对象 142 * @return xml 143 */ 144 public static String messageToXML(TextMessage textMessage) { 145 xstream.alias("xml", TextMessage.class); 146 return xstream.toXML(textMessage); 147 } 148 149 /** 150 * 图片消息对象转换成xml 151 * 152 * @param imageMessage 图片消息对象 153 * @return xml 154 */ 155 public static String messageToXML(ImageMessage imageMessage) { 156 xstream.alias("xml", ImageMessage.class); 157 return xstream.toXML(imageMessage); 158 } 159 160 /** 161 * 语音消息对象转换成xml 162 * 163 * @param voiceMessage 语音消息对象 164 * @return xml 165 */ 166 public static String messageToXML(VoiceMessage voiceMessage) { 167 xstream.alias("xml", VoiceMessage.class); 168 return xstream.toXML(voiceMessage); 169 } 170 171 /** 172 * 视频消息对象转换成xml 173 * 174 * @param videoMessage 视频消息对象 175 * @return xml 176 */ 177 public static String messageToXML(VideoMessage videoMessage) { 178 xstream.alias("xml", VideoMessage.class); 179 return xstream.toXML(videoMessage); 180 } 181 182 /** 183 * 音乐消息对象转换成xml 184 * 185 * @param musicMessage 音乐消息对象 186 * @return xml 187 */ 188 public static String messageToXML(MusicMessage musicMessage) { 189 xstream.alias("xml", MusicMessage.class); 190 return xstream.toXML(musicMessage); 191 } 192 193 /** 194 * 图文消息对象转换成xml 195 * 196 * @param newsMessage 图文消息对象 197 * @return xml 198 */ 199 public static String messageToXML(NewsMessage newsMessage) { 200 xstream.alias("xml", NewsMessage.class); 201 xstream.alias("item", Article.class); 202 return xstream.toXML(newsMessage); 203 } 204 }
1 package com.wtxy.util; 2 3 import java.security.MessageDigest; 4 import java.security.NoSuchAlgorithmException; 5 import java.util.Arrays; 6 7 /** 8 * 请求校验工具类 9 * 10 * @author Ran 11 * @date 2016-04-21 12 */ 13 public class SignUtil { 14 // 与开发模式接口配置信息中的Token保持一致 15 private static String token = "weixin"; 16 17 /** 18 * 校验签名 19 * 20 * @param signature 微信加密签名 21 * @param timestamp 时间戳 22 * @param nonce 随机数 23 * @return 24 */ 25 public static boolean checkSignature(String signature, String timestamp, String nonce) { 26 // 对token、timestamp和nonce按字典排序 27 String[] paramArr = new String[] { token, timestamp, nonce }; 28 Arrays.sort(paramArr); 29 30 // 将排序后的结果拼接成一个字符串 31 String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]); 32 33 String ciphertext = null; 34 try { 35 MessageDigest md = MessageDigest.getInstance("SHA-1"); 36 // 对接后的字符串进行sha1加密 37 byte[] digest = md.digest(content.toString().getBytes()); 38 ciphertext = byteToStr(digest); 39 } catch (NoSuchAlgorithmException e) { 40 e.printStackTrace(); 41 } 42 43 // 将sha1加密后的字符串与signature进行对比 44 return ciphertext != null ? ciphertext.equals(signature.toUpperCase()) : false; 45 } 46 47 /** 48 * 将字节数组转换为十六进制字符串 49 * 50 * @param byteArray 51 * @return 52 */ 53 private static String byteToStr(byte[] byteArray) { 54 String strDigest = ""; 55 for (int i = 0; i < byteArray.length; i++) { 56 strDigest += byteToHexStr(byteArray[i]); 57 } 58 return strDigest; 59 } 60 61 /** 62 * 将字节转换为十六进制字符串 63 * 64 * @param mByte 65 * @return 66 */ 67 private static String byteToHexStr(byte mByte) { 68 char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 69 char[] tempArr = new char[2]; 70 tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; 71 tempArr[1] = Digit[mByte & 0X0F]; 72 73 String s = new String(tempArr); 74 return s; 75 } 76 }
com.wtxy.weixin.message
Article.java
BaseMessage.java
Image.java
ImageMessage.java
Music.java
MusicMessage.java
NewsMessage.java
TextMessage.java
Video.java
VideoMessage.java
Voice.java
VoiceMessage.java
1 package com.wtxy.weixin.message; 2 3 public class Article { 4 private String Title; 5 private String Description; 6 private String PicUrl; 7 private String Url; 8 9 public String getTitle() { 10 return Title; 11 } 12 public void setTitle(String title) { 13 Title = title; 14 } 15 public String getDescription() { 16 return Description; 17 } 18 public void setDescription(String description) { 19 Description = description; 20 } 21 public String getPicUrl() { 22 return PicUrl; 23 } 24 public void setPicUrl(String picUrl) { 25 PicUrl = picUrl; 26 } 27 public String getUrl() { 28 return Url; 29 } 30 public void setUrl(String url) { 31 Url = url; 32 } 33 34 35 36 }
1 package com.wtxy.weixin.message; 2 3 public class BaseMessage { 4 // 接收方帐号(收到的OpenID) 5 private String ToUserName; 6 // 开发者微信号 7 private String FromUserName; 8 // 消息创建时间 (整型) 9 private long CreateTime; 10 // 消息类型(text/music/news) 11 private String MsgType; 12 13 14 public String getToUserName() { 15 return ToUserName; 16 } 17 public void setToUserName(String toUserName) { 18 ToUserName = toUserName; 19 } 20 public String getFromUserName() { 21 return FromUserName; 22 } 23 public void setFromUserName(String fromUserName) { 24 FromUserName = fromUserName; 25 } 26 public long getCreateTime() { 27 return CreateTime; 28 } 29 public void setCreateTime(long createTime) { 30 CreateTime = createTime; 31 } 32 public String getMsgType() { 33 return MsgType; 34 } 35 public void setMsgType(String msgType) { 36 MsgType = msgType; 37 } 38 39 40 }
1 package com.wtxy.weixin.message; 2 3 public class Image { 4 private String Mediald; 5 6 public String getMediald() { 7 return Mediald; 8 } 9 10 public void setMediald(String mediald) { 11 Mediald = mediald; 12 } 13 14 }
1 package com.wtxy.weixin.message; 2 3 public class ImageMessage extends BaseMessage { 4 private Image Image; 5 6 public Image getImage() { 7 return Image; 8 } 9 10 public void setImage(Image image) { 11 Image = image; 12 } 13 14 }
1 package com.wtxy.weixin.message; 2 3 public class Music { 4 private String Title; 5 private String Description; 6 private String MusicUrl; 7 private String HQMusicUrl; 8 private String ThumbMediaId; 9 public String getTitle() { 10 return Title; 11 } 12 public void setTitle(String title) { 13 Title = title; 14 } 15 public String getDescription() { 16 return Description; 17 } 18 public void setDescription(String description) { 19 Description = description; 20 } 21 public String getMusicUrl() { 22 return MusicUrl; 23 } 24 public void setMusicUrl(String musicUrl) { 25 MusicUrl = musicUrl; 26 } 27 public String getHQMusicUrl() { 28 return HQMusicUrl; 29 } 30 public void setHQMusicUrl(String hQMusicUrl) { 31 HQMusicUrl = hQMusicUrl; 32 } 33 public String getThumbMediaId() { 34 return ThumbMediaId; 35 } 36 public void setThumbMediaId(String thumbMediaId) { 37 ThumbMediaId = thumbMediaId; 38 } 39 40 41 42 }
1 package com.wtxy.weixin.message; 2 3 public class MusicMessage extends BaseMessage { 4 private Music Music; 5 6 public Music getMusic() { 7 return Music; 8 } 9 10 public void setMusic(Music music) { 11 Music = music; 12 } 13 14 15 }
1 package com.wtxy.weixin.message; 2 3 import java.util.List; 4 5 public class NewsMessage extends BaseMessage { 6 private int ArticleCount; 7 private List<Article>Articles; 8 9 public int getArticleCount() { 10 return ArticleCount; 11 } 12 public void setArticleCount(int articleCount) { 13 ArticleCount = articleCount; 14 } 15 public List<Article> getArticles() { 16 return Articles; 17 } 18 public void setArticles(List<Article> articles) { 19 Articles = articles; 20 } 21 22 23 24 }
1 package com.wtxy.weixin.message; 2 3 public class TextMessage extends BaseMessage { 4 private String Content; 5 6 public String getContent() { 7 return Content; 8 } 9 10 public void setContent(String content) { 11 Content = content; 12 } 13 14 }
1 package com.wtxy.weixin.message; 2 3 public class Video { 4 //媒体文件id 5 private String MediaId; 6 // 7 private String Title; 8 9 private String Description; 10 11 12 public String getMediaId() { 13 return MediaId; 14 } 15 16 public void setMediaId(String mediaId) { 17 MediaId = mediaId; 18 } 19 20 public String getTitle() { 21 return Title; 22 } 23 24 public void setTitle(String title) { 25 Title = title; 26 } 27 28 public String getDescription() { 29 return Description; 30 } 31 32 public void setDescription(String description) { 33 Description = description; 34 } 35 }
1 package com.wtxy.weixin.message; 2 3 public class VideoMessage extends BaseMessage { 4 //语音 5 private Video Video; 6 7 public Video getVideo() { 8 return Video; 9 } 10 11 public void setVideo(Video video) { 12 Video = video; 13 } 14 15 }
1 package com.wtxy.weixin.message; 2 3 public class Voice { 4 //媒体文件id 5 private String MediaId; 6 7 public String getMediaId() { 8 return MediaId; 9 } 10 11 public void setMediaId(String mediaId) { 12 MediaId = mediaId; 13 } 14 15 }
1 package com.wtxy.weixin.message; 2 3 public class VoiceMessage extends BaseMessage { 4 private Voice Voice; 5 6 public Voice getVoice() { 7 return Voice; 8 } 9 10 public void setVoice(Voice voice) { 11 Voice = voice; 12 } 13 14 }