1. Prepare
1. Preparation Services
And interfacing micro-channel url to meet the following conditions:
(1) the public has access to the Internet
(2) port only supports 80 ports
Here, if the service is a public network access to the best mapping may be performed by other external networks or peanut shell mapping tool, such as ngrok .
2. The principle of data exchange
Development mode and edit mode are mutually exclusive, open development model when the edit mode automatically reply with a custom menu fail; open Edit mode or an automatic reply from when developing custom menu mode will fail.
Data exchange principle development model are as follows:
We need to develop public task is Wearnes number of the server, including business logic, authentication, and other operations.
2. Access background
Reference number of public development documents: Development -> Developer Tools - "developer documentation, there are documents like docking nails, and other guides have access to interface documentation.
https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html
1. The first step: Fill in the server configuration
Step 2: Verify message is from the micro-channel server (for authentication servers in their own micro channel)
Developer information submitted after the micro channel server sends a GET request to the URL address of the server filled, carries GET request parameters as follows:
Developer test signature is performed by the request check (check mode below). If confirmed the GET request to the server from the micro-letter, please return it unchanged echostr content parameters, the access into effect, become a successful developer, or access failure. Encryption / verification process is as follows:
1) The token, timestamp, nonce three parameters lexicographically sorting 2) the blending of three parameters sha1 string into a string encrypted 3) string developer obtained can be compared with an encrypted signature, identify the source of the request in the micro-channel
SpringMVC received code is as follows:
package cn.qlq.controller.weixin; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import cn.qlq.controller.UserController; import cn.qlq.utils.weixin.WeixinCheckUtils; @Controller @RequestMapping("weixin") public class WeixinController { private static final Logger logger = LoggerFactory.getLogger(UserController.class); @ResponseBody @RequestMapping("index") public String index(@RequestParam(required = false) String signature, @RequestParam(required = false) String timestamp, @RequestParam(required = false) String nonce, @RequestParam(required = false) String echostr) { logger.debug("signature: {}, timestamp: {}, nonce: {}, echostr: {}", signature, timestamp, nonce, echostr); if (StringUtils.isNoneBlank(signature, timestamp, nonce) && WeixinCheckUtils.checkSignature(signature, timestamp, nonce)) { return echostr; } return "error"; } }
Verification tools as follows:
package cn.qlq.utils.weixin; import java.security.MessageDigest; import java.util.Arrays; public class WeixinCheckUtils { // token, consistent with the public micro-channel number background Private static Final String token = "devqiaolq" ; public static boolean checkSignature(String signature, String timestamp, String nonce) { String[] arr = new String[] { token, timestamp, nonce }; // Sort Arrays.sort (arr); // 生成字符串 StringBuffer content = new StringBuffer(); for (int i = 0; i < arr.length; i++) { content.append(arr[i]); } // sha1加密 String temp = getSha1(content.toString()); return temp.equals(signature); } public static String getSha1(String str) { if (str == null || str.length() == 0) { return null; } char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; try { MessageDigest mdTemp = MessageDigest.getInstance("SHA1"); mdTemp.update(str.getBytes("UTF-8")); byte[] md = mdTemp.digest(); int j = md.length; char buf[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; buf[k++] = hexDigits[byte0 >>> 4 & 0xf]; buf[k++] = hexDigits[byte0 & 0xf]; } return new String(buf); } catch (Exception e) { return null; } } }
Note: If login filter, micro-channel release request remember in the filter.
3. The third step: implement business logic based interface document
1. After you first need to enable developer mode :( enable developers to model your own custom menus will not take effect)
Receiving a response text message 2
When ordinary users micro-channel message to the public accounts, micro-letters POST XML data server message packets to fill out the developer's URL.
xml data format of a text message is as follows:
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId> </xml>
Parameters explanation:
parameter | description |
---|---|
ToUserName | Developers Micro Signal |
FromUserName | Sender account (the OpenID a) |
CreateTime | Message creation time (integer) |
MsgType | Message type, text to text |
Content | Text message content |
MsgId | Message id, 64-bit integer |
(1) establishing TextMessage entity class corresponding to the background:
package cn.qlq.bean.weixin; public class TextMessage { /** * Developers Micro Signal */ private String ToUserName; /** * Sender account (the OpenID a) * / Private String FromUserName; /** * Message creation time (integer) */ private long CreateTime; /** * text */ private String MsgType; /** * Text message content */ private String Content; /** * Message id, 64-bit integer */ private String MsgId; @Override public String toString() { return "TextMessage{" + "ToUserName='" + ToUserName + '\'' + ", FromUserName='" + FromUserName + '\'' + ", CreateTime=" + CreateTime + ", MsgType='" + MsgType + '\'' + ", Content='" + Content + '\'' + ", MsgId='" + MsgId + '\'' + '}'; } public String getToUserName() { return ToUserName; } public void setToUserName(String toUserName) { ToUserName = toUserName; } public String getFromUserName() { return FromUserName; } public void setFromUserName (String fromUserName) { FromUserName = fromUserName; } public long getCreateTime() { return CreateTime; } public void setCreateTime(long createTime) { CreateTime = createTime; } public String getMsgType() { return MsgType; } public void setMsgType(String msgType) { MsgType = msgType; } public String getContent() { return Content; } public void setContent(String content) { Content = content; } public String getMsgId() { return MsgId; } public void setMsgId(String msgId) { MsgId = msgId; } }
(2) preparation of tools to achieve xml (xml received data) are converted into the transfer map and TextMessage object xml (xml response data format)
pom added:
<!--微信转换XML所需包 --> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream --> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.10</version> </dependency>
Tools:
package cn.qlq.utils.weixin; 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 com.thoughtworks.xstream.XStream; import cn.qlq.bean.weixin.TextMessage; public class MessageUtils { /** * Xml data transfer map * * @param request * @return * @throws IOException * @throws DocumentException */ public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException { Map<String, String> map = new HashMap<>(); SAXReader reader = new SAXReader(); InputStream inputStream = request.getInputStream(); Document document = reader.read(inputStream); Element root = document.getRootElement (); List<Element> list = root.elements(); for (Element element : list) { map.put(element.getName(), element.getText()); } inputStream.close(); return map; } /** * To convert the text message object into xml * * @param textMessage * @return */ public static String textMessageToXml(TextMessage textMessage) { XStream the XStream = new new the XStream (); // replace the root element into xml xml xStream.alias ( "xml" , textMessage.getClass ()); return xStream.toXML (textMessage); } }
(3) receive messages and response messages rewriting Controller
package cn.qlq.controller.weixin; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.dom4j.DocumentException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import cn.qlq.bean.weixin.TextMessage; import cn.qlq.controller.UserController; import cn.qlq.utils.weixin.MessageUtils; import cn.qlq.utils.weixin.WeixinCheckUtils; @Controller @RequestMapping("weixin") public class WeixinController { private static final Logger logger = LoggerFactory.getLogger(UserController.class); @RequestMapping(value = "index", method = { RequestMethod.GET, RequestMethod.POST }) public void index(HttpServletRequest request, HttpServletResponse response) throws IOException { // the request, the response code are set to UTF-8 (Chinese prevent distortion) Request.setCharacterEncoding ( "UTF-8"); // time WeChat server POST message using a UTF-8 encoding, but also when receiving with the same code, otherwise the Chinese will be garbled; response.setCharacterEncoding ( "UTF-8"); // in the response message (reply message to the user), will also be encoding is set to UTF-8, the principle above; String Method, = request.getMethod () toLowerCase ().; logger.info("method: {}", method); // verify that the request is a micro-channel IF ( "GET" .equals (Method)) { doGet(request, response); return; } // the POST request message received, and the customer response to the message doPost (request, response); } /** * Post after receiving a request message for message processing and message return * * @param request * @param response * @throws IOException */ private void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { PrintWriter out = response.getWriter(); try { Map<String, String> map = MessageUtils.xmlToMap(request); String fromUserName = map.get("FromUserName"); String toUserName = map.get("ToUserName"); String msgType = map.get("MsgType"); String content = map.get("Content"); logger.info("map: {}", map); if (StringUtils.isNotBlank(content)) { System.out.println ( "received message:" + content + ", you can search by keyword or do other" ); } String message = null; if ("text".equals(msgType)) { TextMessage TextMessage = new new TextMessage (); // return message, and so to speak fromuser toUser exchange textMessage.setFromUserName (toUserName); textMessage.setToUserName (fromUserName); textMessage.setMsgType(msgType); textMessage.setCreateTime(new Date().getTime()); textMessage.setContent ( "message you send is:" + Content); logger.info("textMessage: {}", textMessage); message = MessageUtils.textMessageToXml(textMessage); } Out.print (Message); // send the message to the client } the catch (DocumentException E) { logger.error("dispose post request error", e); } finally { out.close(); } } /** * Get request for authentication micro-channel configuration * * @param request * @param response * @throws IOException */ private void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { Signature String = request.getParameter ( "Signature"); // micro-channel encrypted signature String = request.getParameter timestamp ( "timestamp"); // timestamp String = request.getParameter the nonce ( "the nonce"); // random number String = request.getParameter echostr ( "echostr"); // random string logger.info ( "Signature: {}, timestamp: {}, the nonce: {}, echostr: {}" , Signature, timestamp, the nonce, echostr) ; if (StringUtils.isNoneBlank(signature, timestamp, nonce) && WeixinCheckUtils.checkSignature(signature, timestamp, nonce)) { response.getWriter().write(echostr); } } }
test:
Java server log is as follows:
23 is 2019-10-23: 34 is: the INFO 15.625 244 500 --- [-NiO-8088-Exec. 9] cn.qlq.controller.UserController: Method: POST
2019-10-23 23 is: 34 is: the INFO 244 500 --- 15.633 [nio-8088-exec-9 ] cn.qlq.controller.UserController: map: {MsgId = 22503405793257008, fromUserName = o_qAo0u6Snhoc7Z45RfSxYatMWpo, CreateTime = 1571844638, Content = how a, ToUserName = gh_fc4bd5c2fda8, MsgType = text }
received message : how, you can search by keyword or do other
2019-10-23 23: 34: 15.635 INFO 244500 --- [nio-8088-exec-9] cn.qlq.controller.UserController: textMessage: TextMessage { ToUserName = 'o_qAo0u6Snhoc7Z45RfSxYatMWpo', fromUserName = 'gh_fc4bd5c2fda8', CreateTime = 1571844855635, MsgType = 'text', Content = ' message you send is: how', MsgId = 'null'}
2019-10-23 23:34: 20.288 INFO 244500 --- [nio-8088 -exec-3] cn.qlq.controller.UserController: method: post
2019-10-23 23: 34: 20.295 INFO 244500 --- [nio-8088-exec-3] cn.qlq.controller.UserController: map: {MsgId = 22503406289173072, FromUserName = o_qAo0u6Snhoc7Z45RfSxYatMWpo, CreateTime = 1571844642, what Content = meaning, ToUserName = gh_fc4bd5c2fda8, MsgType = text }
received message is: What do you mean, you can search by keyword or do other
2019-10-23 23: 34: 20.296 INFO 244500 --- [nio-8088-exec -3] cn.qlq.controller.UserController: textMessage: TextMessage { ToUserName = 'o_qAo0u6Snhoc7Z45RfSxYatMWpo', fromUserName = 'gh_fc4bd5c2fda8', CreateTime = 1571844860296, MsgType = 'text', Content = ' message you send is: What does it mean' MsgId = 'null'}