package com.github.sd4324530.fastweixin.util; import com.github.sd4324530.fastweixin.message.aes.WXBizMsgCrypt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import javax.servlet.http.HttpServletRequest; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.XMLEvent; import java.io.*; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 消息工具类 * 用于解析微信平台消息xml报文 * * @author peiyu */ public final class MessageUtil { private static final Logger LOG = LoggerFactory.getLogger(MessageUtil.class); private static final String FORMAT = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%1$s]]></Encrypt></xml>"; /** * 此类不需要实例化 */ private MessageUtil() { } /** * 解析从微信服务器来的请求,将消息或者事件返回出去 * * @param request http请求对象 * @param token 用户设置的taken * @param appId 公众号的APPID * @param aesKey 用户设置的加密密钥 * @return 微信消息或者事件Map */ public static Map<String, Object> parseXml(HttpServletRequest request, String token, String appId, String aesKey) { Map<String, Object> map = new HashMap<String, Object>(); InputStream inputStream = null; try { inputStream = request.getInputStream(); if (StrUtil.isNotBlank(aesKey)) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); StreamUtil.copy(inputStream, outputStream); String body = outputStream.toString(); LOG.debug("收到的消息密文:{}", body); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); StringReader sr = new StringReader(body); InputSource is = new InputSource(sr); Document document = db.parse(is); Element root = document.getDocumentElement(); NodeList nodelist1 = root.getElementsByTagName("Encrypt"); WXBizMsgCrypt pc = new WXBizMsgCrypt(token, aesKey, appId); String msgSignature = request.getParameter("msg_signature"); String timeStamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); LOG.debug("msgSignature:{}", msgSignature); LOG.debug("timeStamp:{}", timeStamp); LOG.debug("nonce:{}", nonce); String encrypt = nodelist1.item(0).getTextContent(); String fromXML = String.format(FORMAT, encrypt); String message = pc.decryptMsg(msgSignature, timeStamp, nonce, fromXML); inputStream = new ByteArrayInputStream(message.getBytes()); } XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader reader = factory.createXMLEventReader(inputStream); while (reader.hasNext()) { XMLEvent event = reader.nextEvent(); if (event.isStartElement()) { String tagName = event.asStartElement().getName() .toString(); if("SendPicsInfo".equals(tagName)) { map.put(tagName, eventSendPicsInfo(reader)); } else if("SendLocationInfo".equals(tagName)) { map.put(tagName, eventSendLocationInfo(reader)); } else if("ScanCodeInfo".equals(tagName)) { map.put(tagName, eventScanCodePush(reader)); } else if("xml".equals(tagName)) { } else { map.put(tagName, reader.getElementText()); } } } } catch (IOException e) { LOG.error("IO出现异常", e); } catch (XMLStreamException e) { LOG.error("XML解析出现异常", e); } catch (Exception e) { LOG.error("其他异常", e); } finally { try { if (inputStream != null) { inputStream.close(); } } catch (IOException e) { LOG.error("IO出现异常", e); } } return map; } /** * Event为pic_sysphoto, pic_photo_or_album, pic_weixin时触发 * @param reader reader * @return 读取结果 * @throws XMLStreamException XML解析异常 */ protected static Map<String, Object> eventSendPicsInfo(XMLEventReader reader) throws XMLStreamException { Map<String, Object> sendPicsInfoMap = new HashMap<String, Object>(); while (reader.hasNext()){ XMLEvent event = reader.nextEvent(); if (event.isStartElement()) { String tagName = event.asStartElement().getName() .toString(); if("Count".equals(tagName)){ sendPicsInfoMap.put(tagName, reader.getElementText()); }else if("PicList".equals(tagName)){ // StringBuilder sb = new StringBuilder(); List<Map<String, String>> picList = CollectionUtil.newArrayList(); while(reader.hasNext()){ XMLEvent event1 = reader.nextEvent(); if(event1.isStartElement() && "PicMd5Sum".equals(event1.asStartElement().getName() .toString())){ Map<String, String> picMap = new HashMap<String, String>(); picMap.put("PicMd5Sum", reader.getElementText()); // sb.append(reader.getElementText()); // sb.append(","); picList.add(picMap); }else if(event1.isEndElement() && "PicList".equals(event1.asEndElement().getName().toString())){ break; } } // sendPicsInfoMap.put(tagName, sb.substring(0, sb.length())); sendPicsInfoMap.put(tagName, picList); } } } return sendPicsInfoMap; } /** * Event为location_select时触发 * @param reader reader * @return 读取结果 * @throws XMLStreamException XML解析异常 */ protected static Map<String, Object> eventSendLocationInfo(XMLEventReader reader) throws XMLStreamException{ Map<String, Object> sendLocationInfo = new HashMap<String, Object>(); while(reader.hasNext()){ XMLEvent event = reader.nextEvent(); if (event.isStartElement()) { String tagName = event.asStartElement().getName() .toString(); sendLocationInfo.put(tagName, reader.getElementText()); } } return sendLocationInfo; } /** * Event为scancode_push, scancode_waitmsg时触发 * @param reader reader * @return 读取结果 * @throws XMLStreamException XML解析异常 */ protected static Map<String, Object> eventScanCodePush(XMLEventReader reader) throws XMLStreamException{ Map<String, Object> scanCodePush = new HashMap<String, Object>(); while(reader.hasNext()){ XMLEvent event = reader.nextEvent(); if (event.isStartElement()) { String tagName = event.asStartElement().getName() .toString(); scanCodePush.put(tagName, reader.getElementText()); } } return scanCodePush; } }