学习java是一个漫长的过程,这需要学习的人投入大量的精力和时间沉浸其中,才能有所得。今天主要为大家介绍一下,微信公众号数据交互原理图解,以及展示接入开发模式和响应的代码。
1.首先我们应该准备:微信公众号和外网映射工具(开发调试)。并且与微信的对接的URL应该可以满足两个条件,一是在公网上能够访问,二是只支持80端口;如下图所示:
然后进入微信公众号平台,再进入开发者中心,在开发者中心中找到开发者文档,实现代码展示如下:
package org.gpf.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.gpf.util.CheckUtil; /** * 接收微信服务器发送的4个参数并返回echostr */ public class WeixinServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 接收微信服务器以Get请求发送的4个参数 String signature = request.getParameter("signature"); String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String echostr = request.getParameter("echostr"); PrintWriter out = response.getWriter(); if (CheckUtil.checkSignature(signature, timestamp, nonce)) { out.print(echostr); // 校验通过,原样返回echostr参数内容 } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
校验工具类代码展示如下:
package org.gpf.util; import java.util.Arrays; import org.apache.commons.codec.digest.DigestUtils; /** * 校验的工具类 */ public class CheckUtil { private static final String token = "weixin"; public static boolean checkSignature(String signature, String timestamp, String nonce) { String[] arr = new String[] { token , timestamp , nonce }; // 排序 Arrays.sort(arr); // 生成字符串 StringBuilder content = new StringBuilder(); for (int i = 0; i < arr.length; i++) { content.append(arr[i]); } // sha 1加密 String temp = getSHA 1String(content.toString()); return temp.equals(signature); // 与微信传递过来的签名进行比较 } private static String getSHA 1String(String data) { return DigestUtils.sha 1Hex(data); // 使用commons codec生成sha 1字符串 } }
Servlet配置代码展示如下:
servlet > <servlet-name>WeixinServlet</servlet-name> < servlet - class > org.gpf.servlet.WeixinServlet < /servlet-class> < /servlet> < servlet - mapping > <servlet-name>WeixinServlet</servlet-name> < url - pattern > /wx.do</url - pattern > </servlet-mapping>
接下来通过映射工具将本地的服务器映射到公网,从公网访问Servlet。图片展示如下:
需要注意的是,开发模式和编辑模式是互斥的,如果启动了开发模式,那么自定义菜单和自动回复将失效。
2.然后是消息的接收和响应
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。所以需要更改我们的Servlet中的doPost方法,因为微信服务器与我们的服务器之间是通过XML传递数据的,所以需要实现消息实体与XML之间的互相转换。可以采用第三方jar包XStream完成。
处理微信服务器与本机服务器进行交互的Servlet代码展示如下:
package org.gpf.servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.dom4j.DocumentException; import org.gpf.po.TextMeaasge; import org.gpf.util.CheckUtil; import org.gpf.util.MessageUtil; /** * 微信消息的接收和响应 */ public class WeixinServlet extends HttpServlet { /** * 接收微信服务器发送的4个参数并返回echostr */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 接收微信服务器以Get请求发送的4个参数 String signature = request.getParameter("signature"); String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String echostr = request.getParameter("echostr"); PrintWriter out = response.getWriter(); if (CheckUtil.checkSignature(signature, timestamp, nonce)) { out.print(echostr); // 校验通过,原样返回echostr参数内容 } } /** * 接收并处理微信客户端发送的请求 */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/xml;charset=utf-8"); PrintWriter out = response.getWriter(); try { Map < String, String > map = MessageUtil.xmlToMap(request); String toUserName = map.get("ToUserName"); String fromUserName = map.get("FromUserName"); String msgType = map.get("MsgType"); String content = map.get("Content"); String message = null; if ("text".equals(msgType)) { // 对文本消息进行处理 TextMeaasge text = new TextMeaasge(); text.setFromUserName(toUserName); // 发送和回复是反向的 text.setToUserName(fromUserName); text.setMsgType("text"); text.setCreateTime(new Date() .getTime()); text.setContent("你发送的消息是:" + content); message = MessageUtil.textMessageToXML(text); System.out.println(message); } out.print(message); // 将回应发送给微信服务器 } catch (DocumentException e) { e.printStackTrace(); } finally { out.close(); } } }
按照微信的接口文档编写的文本消息实体类代码展示如下:
package org.gpf.util; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.gpf.po.TextMeaasge; import com.thoughtworks.xstream.XStream; /** * 实现消息的格式转换(Map类型和XML的互转) */ public class MessageUtil { /** * 将XML转换成Map集合 */ public static Map < String, String > xmlToMap(HttpServletRequest request) throws IOException, DocumentException { Map < String, String > map = new HashMap < String, String > (); SAXReader reader = new SAXReader(); // 使用dom4j解析xml InputStream ins = request.getInputStream(); // 从request中获取输入流 Document doc = reader.read(ins); Element root = doc.getRootElement(); // 获取根元素 List < Element > list = root.elements(); // 获取所有节点 for (Element e: list) { map.put(e.getName(), e.getText()); System.out.println(e.getName() + "--->" + e.getText()); } ins.close(); return map; } /** * 将文本消息对象转换成XML */ public static String textMessageToXML(TextMeaasge textMessage) { XStream xstream = new XStream(); // 使用XStream将实体类的实例转换成xml格式 xstream.alias("xml", textMessage.getClass()); // 将xml的默认根节点替换成“xml” return xstream.toXML(textMessage); } }
以上就是关于微信公众号数据交互原理图解,以及接入开发模式的代码展示。想要了解更多java基础,敬请关注奇Q工具网。
推荐阅读: