微信公众号开发(二)
参考文章:Java微信公众号扫描带参数二维码事件
事件监听及自动回复消息
扫码回复、订阅回复、文本回复等
重新编写/verifyWxToken接口
@ResponseBody
@RequestMapping(value = "/verifyWxToken")
@RequestNoneAuthentication
public String verifyWxToken(HttpServletRequest request) throws IOException {
// 获得微信端返回的xml数据
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingaeskey, appId);
is = request.getInputStream();
isr = new InputStreamReader(is, "utf-8");
br = new BufferedReader(isr);
String str = null;
StringBuffer returnXml = new StringBuffer();
while ((str = br.readLine()) != null) {
//返回的是xml数据
returnXml.append(str);
}
logger.error("==========returnXml="+returnXml);
Map<String, String> encryptMap = WeiXinUtils.xmlToMap(returnXml.toString(),pc);
logger.error("==========encryptMap="+new Gson().toJson(encryptMap));
// 得到公众号传来的加密信息并解密,得到的是明文xml数据
String encrypt=encryptMap.get("Encrypt");
String decryptXml =null;
if(StringUtils.isNotBlank(encrypt)){
decryptXml = pc.decrypt(encrypt);//pc.decrypt(encryptMap.get("Encrypt"));encryptMsg
}
logger.error("==========decryptXml="+decryptXml);
// 将xml数据转换为map
Map<String, String> decryptMap = new HashMap<>();
if(StringUtils.isNotBlank(decryptXml)){
decryptMap=WeiXinUtils.xmlToMap(decryptXml,pc);
}
logger.error("==========decryptMap="+new Gson().toJson(decryptMap));
// 区分消息类型
String msgType = encryptMap.get("MsgType");
logger.error("==========msgType="+msgType);
// 普通消息
if ("text".equals(msgType)) { // 文本消息
return MyEventHandler.subscribe(encryptMap);
} else if ("image".equals(msgType)) { // 图片消息
// todo 处理图片消息
} else if ("voice".equals(msgType)) { //语音消息
// todo 处理语音消息
}
// 事件推送
else if ("event".equals(msgType)) { // 事件消息
// 区分事件推送
String event = encryptMap.get("Event");
if ("subscribe".equals(event)) { // 订阅事件 或 未关注扫描二维码事件
// 返回消息时ToUserName的值与FromUserName的互换
return MyEventHandler.subscribe(encryptMap);
} else if ("unsubscribe".equals(event)) { // 取消订阅事件
// todo 处理取消订阅事件
} else if ("SCAN".equals(event)) { // 已关注扫描二维码事件
// 返回消息时ToUserName的值与FromUserName的互换
return MyEventHandler.subscribe(encryptMap);
}
}
} catch (Exception e) {
logger.error("===verifyWxToken===处理异常,e:", e);
}finally {
if (null != is) {
is.close();
}
if (null != isr) {
isr.close();
}
if (null != br) {
br.close();
}
}
return "Success";
}
WeiXinUtils
public class WeiXinUtils{
/**
* XML格式字符串转换为Map
* import javax.xml.parsers.DocumentBuilder;
* import javax.xml.parsers.DocumentBuilderFactory;
* import javax.xml.transform.OutputKeys;
* import javax.xml.transform.Transformer;
* import javax.xml.transform.TransformerFactory;
* import javax.xml.transform.dom.DOMSource;
* import javax.xml.transform.stream.StreamResult
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static Map<String, String> xmlToMap(String strXML, WXBizMsgCrypt pc) throws Exception {
try {
Map<String, String> data = new HashMap<>();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
int startIndex=strXML.indexOf("<xml>");
String content=strXML.substring(startIndex);
int endIndex=content.indexOf("</xml>");
content=content.substring(0,endIndex+6);
System.out.println("centent:"+content);
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(content);
InputSource is = new InputSource(sr);
Document document = db.parse(is);
Element root = document.getDocumentElement();
NodeList nodeList = root.getChildNodes();
for (int idx = 0; idx < nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
sr.close();
} catch (Exception ex) {
// do nothing
}
return data;
} catch (Exception ex) {
logger.warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
throw ex;
}
}
/**
* 将Map转换为XML格式的字符串
*
* @param data Map类型数据
* @return XML格式的字符串
* @throws Exception
*/
public static String mapToXml(Map<String, String> data) throws Exception {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
org.w3c.dom.Document document = documentBuilder.newDocument();
org.w3c.dom.Element root = document.createElement("xml");
document.appendChild(root);
for (String key : data.keySet()) {
String value = data.get(key);
if (value == null) {
value = "";
}
value = value.trim();
org.w3c.dom.Element filed = document.createElement(key);
filed.appendChild(document.createTextNode(value));
root.appendChild(filed);
}
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DOMSource source = new DOMSource(document);
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
try {
writer.close();
} catch (Exception ex) {
}
return output;
}
}
MyEventHandler
public class MyEventHandler {
public static String subscribe(Map<String, String> decryptMap) throws Exception {
Map<String, String> returnMap = new HashMap<>();
returnMap.put("ToUserName", decryptMap.get("FromUserName"));
returnMap.put("FromUserName", decryptMap.get("ToUserName"));
returnMap.put("CreateTime", new Date().getTime()+"");
returnMap.put("MsgType", "text");
returnMap.put("Content", "https://www.baidu.com");
String encryptMsg = WeiXinUtils.mapToXml(returnMap);
return encryptMsg;
}
}