Recently, because the business needs to use wechat service number to push template messages, I studied it. Here, I also review and summarize the development process and precautions.
1, WeChat official account push template message, need to open the service number and need WeChat certification (this is only a few records). After application to the service number, the official account number (appid) and the service number (AppSecret) will be obtained in the public address > Development > basic configuration.
2. After having the appid, you need to configure the server
The URL filled in here is the background access address. Wechat will send a GET request through this URL. The request parameters are as follows:
In the background method, the request is verified by checking the signature. If it is confirmed that the GET request is from the wechat server and the echostr parameter is returned as is, the access will take effect, otherwise the access will fail. The encryption / verification process is as follows: - dictionary sort the three parameters token, timestamp and nonce (Note: the token here is the token filled in the configuration information) - splice the three parameter strings into a string for sha1 encryption - the developer obtains the encrypted string, which can be compared with signature, Identify that the request comes from wechat. After the URL is configured, the following token and EncodingAESKey can be filled in randomly. The token here is the token used for verification in the above URL. The last one is the message encryption method. Because it is a preliminary development, plaintext is selected, that is, the parameters are not encrypted for development and debugging. If necessary later, the other two methods can be selected, but the corresponding encryption and decryption operations are required when receiving and returning. Before submitting, you need to add the IP of the GET request server to the IP white list in the basic configuration to pass.
The verification request code is as follows:
Controller()
/** * Wechat service number binding verification interface * @param signature * @param timestamp * @param nonce * @param echostr * @return */ @GetMapping(value = "/verification/interface") public String wechatVerificationInterface(String signature, String timestamp, String nonce, String echostr) { logger.info("wechatVerificationInterface Receive message verification ground"); logger.info("Wechat encryption signature signature: " + signature); logger.info("time stamp timestamp: " + timestamp); logger.info("random number nonce: " + nonce); logger.info("Random string echostr: " + echostr); //Verify the wechat signature and judge whether it comes from the configured wechat terminal if (AppletsSignUtil.checkSignature(signature, timestamp, nonce)){ return echostr; } return null; }
Verify signature tool class
/** * @Description: Request verification tool class * @Author caiyu * @Date 2021/5/22 14:39 */ public class AppletsSignUtil { // It is consistent with the Token in the development mode interface configuration information private static String token = "leyizhuang"; /** * Verification signature * @param signature Wechat encryption signature * @param timestamp Time stamp * @param nonce Random number * @return */ public static boolean checkSignature(String signature, String timestamp, String nonce) { // Sort token, timestamp, and nonce by dictionary String[] paramArr = new String[] {token, timestamp, nonce}; Arrays.sort(paramArr); // Concatenate the sorted results into a string String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]); String ciphertext = null; try { MessageDigest md = MessageDigest.getInstance("SHA-1"); // The spliced string is sha1 encrypted byte[] digest = md.digest(content.toString().getBytes()); ciphertext = byteToStr(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } // Compare sha1 encrypted string with signature return ciphertext != null ? ciphertext.equals(signature.toUpperCase()) : false; } /** * Converts a byte array to a hexadecimal string * @param byteArray * @return */ private static String byteToStr(byte[] byteArray) { String strDigest = ""; for (int i = 0; i < byteArray.length; i++) { strDigest += byteToHexStr(byteArray[i]); } return strDigest; } /** * Converts a byte to a hexadecimal string * @param mByte * @return */ private static String byteToHexStr(byte mByte) { char[] Digit = { '0', '1' , '2', '3', '4' , '5', '6', '7' , '8', '9', 'A' , 'B', 'C', 'D' , 'E', 'F'}; char[] tempArr = new char[2]; tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; tempArr[1] = Digit[mByte & 0X0F]; String s = new String(tempArr); return s; } }
3. After the configuration is successful, the next step is to select the template to be sent. As mentioned earlier, wechat authentication is required to send template messages. After authentication, you can add in functions - > add function plug-ins - > template messages
After adding the function, you can select the required template type and fill in the application reason according to the prompt, and then select the template (up to 25 templates can be selected at present). Each template will have a template ID, which is used to specify the template when pushing the message
4. With the template ID, you can push this template message from the background.
The message code of push template is as follows:
/*** * Send template message * (Consumption success notification) */ public void sendCreateOrderTemplateMsg() throws UnsupportedEncodingException,MissingInformationException { private static final String SEND_MSG_API = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="; //Get token String token = this.getToken(); //Message template ID String template_id = XXXXXXXX; // Interface address String sendMsgApi = SEND_MSG_API + token; //openId is the unique identifier of the service number concerned by the micro signal String toUser = xxxxxx; //Global parameter map Map<String, Object> paramMap = new HashMap<String, Object>(); //The message topic displays the associated map Map<String, Object> dataMap = new HashMap<String, Object>(); //Define content and color according to your own template dataMap.put("first", new AppletsDO("Dear customers, latest transaction reminder:", "#173177")); dataMap.put("time", new AppletsDO("2021-06-17 14:00:51", "#173177")); dataMap.put("org", new AppletsDO("The beauty of Fusen's wealth", "#173177")); dataMap.put("type", new AppletsDO("Order consumption", "#173177")); dataMap.put("money", new AppletsDO("8163.0", "#173177")); dataMap.put("point", new AppletsDO("0", "#173177")); dataMap.put("remark", new AppletsDO("The points shall be counted and added together after the order is settled and has been shipped Add to your points account!", "#173177")); paramMap.put("touser", toUser); paramMap.put("template_id", template_id); paramMap.put("data", dataMap); //If you need to jump to the web page, you can add the following line of code to jump // paramMap.put("url",""); System.out.println(this.doGetPost(sendMsgApi, "POST", paramMap)); } /** * Get token * * @return token */ @Override public String getToken() { // Form of grant String grant_type = "client_credential"; // Interface address splicing parameters (appid is the appid of wechat service number, and secret is the secret key of service number) String getTokenApi = "https://api.weixin.qq.com/cgi-bin/token?grant_type=" + grant_type + "&appid=" + XXXXXX + "&secret=" + XXXXXX; String tokenJsonStr = this.doGetPost(getTokenApi, "GET", null); JSONObject tokenJson = JSONObject.parseObject(tokenJsonStr); String token = tokenJson.get("access_token").toString(); System.out.println("Obtained TOKEN : " + token); return token; } /** * Call interface post * @param apiPath */ public static String doGetPost(String apiPath,String type,Map<String,Object> paramMap){ OutputStreamWriter out = null; InputStream is = null; String result = null; try{ URL url = new URL(apiPath);// Create connection HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setDoInput(true); connection.setUseCaches(false); connection.setInstanceFollowRedirects(true); connection.setRequestMethod(type) ; // Set request mode connection.setRequestProperty("Accept", "application/json"); // Format received data connection.setRequestProperty("Content-Type", "application/json"); // Set the format for sending data connection.connect(); if(type.equals("POST")){ out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // utf-8 coding out.append(JSON.toJSONString(paramMap)); out.flush(); out.close(); } // Read response is = connection.getInputStream(); int length = (int) connection.getContentLength();// Get length if (length != -1) { byte[] data = new byte[length]; byte[] temp = new byte[512]; int readLen = 0; int destPos = 0; while ((readLen = is.read(temp)) > 0) { System.arraycopy(temp, 0, data, destPos, readLen); destPos += readLen; } result = new String(data, "UTF-8"); // utf-8 coding } } catch (IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } return result; }
The final effect is as follows:
So far, even if a simple template push is completed, this is only to build the sending channel. In fact, we need to send different templates according to different business scenarios. Most importantly, we need to obtain the openid of each follower before sending messages. Then let's talk about the pit I stepped on to get openid. If a great God passes by, you are welcome to point out the maze