1. Overview of public platform
1.1 overview of public platform
The official account of official account is the platform for operators to provide information and services to WeChat users through the official account. The platform of public platform development is the foundation of providing services. After creating public numbers and obtaining interface permissions on the public platform website, developers can connect the backend interface to the WeChat public number. The WeChat public platform is the basis for providing services.
Official documents:
https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html
1.2 Introduction Guide
In order to lower the threshold and make up for deficiencies, we have prepared the Developer Guide to explain the basic and common functions of wechat open platform, which is designed to help you get started with the developer model of wechat open platform.
For developers who are familiar with the use of interfaces or have some public platform development experience, please skip this article directly. This article will not bring you great coding skills or in-depth explanation of interfaces. For queries about existing interfaces, you can visit the official account community exchange, contact Tencent customer service or use WeChat feedback.
Compared with the open platform, docking to the public platform is relatively simple. The whole process only needs to configure the development configuration and obtain the token through AppID and AppSecret. All subsequent interfaces are called through the token.
Developer guidelines:
https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Getting_Started_Guide.html
2. Docking process
2.1 access overview
To access wechat public platform development, developers need to follow the following steps:
1. Fill in server configuration
2. Verify the validity of the server address
3. Implement business logic according to interface documents
be careful:
1. the premise of completing the server configuration is to register the official account and have the relevant authority to register official account types.
2. The configuration server also needs to be able to connect to the external network callback, which needs to penetrate the internal network in advance( Sunny ngrok tutorial ), or ECs.
Different types of official account are:
https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Explanation_of_interface_privileges.html
Global return code Description:
https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Global_Return_Code.html
2.2 fill in server configuration
After logging into the official website of wechat public platform, on the development basic settings page of the official website of the public platform, check the protocol to become a developer, click the "modify configuration" button, and fill in the server address (URL), Token and encoding aeskey, where the URL is the interface URL used by the developer to receive wechat messages and events. The Token can be filled in arbitrarily by the developer for signature generation (the Token will be compared with the Token contained in the interface URL to verify the security). EncodingAESKey is filled in manually or randomly generated by the developer and will be used as the encryption and decryption key of the message body.
At the same time, developers can choose message encryption and decryption modes: plaintext mode, compatibility mode and security mode. The mode selection and server configuration will take effect immediately after submission. Please fill in and select carefully. The default state of encryption and decryption mode is plaintext mode. To select compatibility mode and security mode, relevant encryption and decryption codes need to be configured in advance, For details, please refer to the document of message body signature and encryption and decryption .
Fill in the server configuration description:
https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
The configuration information is as follows
2.3 interface domain name Description
Public platform interface domain name Description
Developers can choose the best access domain name (lower delay and higher stability) according to their own server deployment. In addition, other access domain names can be used for disaster recovery. In case of network link failure, alternative domain names can be considered for access. Please use the domain name for API interface requests, and do not use IP as access. If it is necessary to open the network policy, the developer can obtain the latest IP information regularly from the IP address of the wechat server.
General domain name (api.weixin.qq.com), which will be used to access the nearest access point designated by the official;
General remote disaster recovery domain name (api2.weixin.qq.com). When the above domain name is not accessible, you can access this domain name instead;
Shanghai domain name (sh.api.weixin.qq.com), which will be used to access the access point in Shanghai;
Shenzhen domain name (sz.api.weixin.qq.com), which will be used to access the access point in Shenzhen;
Hong Kong Domain Name (hk.api.weixin.qq.com), which will be used to access the access point in Hong Kong.
Description of public platform interface domain name:
https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Interface_field_description.html
2.4 obtaining Access token
access_token is the global only interface calling credential for official account. When calling the interfaces, the official account needs to use access_. token. Developers need to keep it properly. access_ At least 512 character space should be reserved for token storage. access_ The validity period of the token is currently 2 hours. It needs to be refreshed regularly. Repeated acquisition will result in the access obtained last time_ The token is invalid.
Get Access token:
https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
3. Project realization
3.1 create project
When creating a springboot project, there are still many places where the code can be optimized, such as messages can be used as strategies, enumeration types, constants and authorization information in the code can be cached, etc. because only tests are done here, they can be optimized by themselves in combination with tests.
In order to facilitate the test, these authorization parameters are put into the collection memory, so they are lost every time you restart. In the later stage, it is necessary to optimize the redis cache persistence. The validity period of the verification ticket is 12 hours. Therefore, in order to test, you can write them dead, and you can get others from memory.
In addition, there are many open-source wechat development frameworks that can be used for reference. Here, we rely on the introduction of wechat development framework Weixin java tools binarywang just for learning, research and use.
weixin-Java-tools: https://gitee.com/itwu/weixin-java-tools#https://mp.weixin.qq.com/s/nIk_xOf6dxkhKfqq830Cuw
3.2 project dependency
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.4</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.zrj</groupId> <artifactId>wechat</artifactId> <version>0.0.1-SNAPSHOT</version> <name>wechat</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--Database connection--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--Common tools--> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.1.1-jre</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.6.3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.72</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency> <!--swagger2 rely on--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.6.1</version> </dependency> <!--Wechat encryption and decryption--> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.9</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> </dependency> <dependency> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> <version>2.1.1</version> </dependency> <!--Field verification--> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.4.14</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency> <!-- Wechat development framework weixin-Java-tools binarywang--> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-common</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-mp</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-open</artifactId> <version>4.1.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
3.3 project configuration
Not used here for the time being
3.4 encryption and decryption tools
Message encryption and decryption Description:
https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/Before_Develop/Message_encryption_and_decryption.html
Download address of encryption and decryption tool: https://res.wx.qq.com/op_res/-serEQ6xSDVIjfoOHcX78T1JAYX-pM_fghzfiNYoD8uHVd3fOeC0PC_pvlg4-kmP
1. After downloading and decompressing, select the corresponding tool class according to the corresponding language, directly type it into a jar package and put it into the private server reference or the project reference.
2. The rack package commons-codec-1.9 (or other versions such as commons-codec-1.8) needs to be imported
3. official account official account should be noted that the encryption and decryption parameters are different from the public number, because the xml returned is different. If the official account is used to add the secret numbers, there will be null pointer. It needs to be adjusted according to the result of return. After the public number is encrypted, xml is ToUser and Encrypt tags. The return of open platform is AppId and Encrypt tags, Encrypt is encrypted content.
/** * For org.apache.commons.codec.binary.Base64, * The rack package commons-codec-1.9 (or other versions such as commons-codec-1.8) needs to be imported * Official download address: http://commons.apache.org/proper/commons-codec/download_codec.cgi */ /** * Provide the encryption and decryption interface (UTF8 encoded string) for receiving and pushing messages to the public platform * <ol> * <li>The third party replies the encrypted message to the public platform</li> * <li>The third party receives the message sent by the public platform, verifies the security of the message, and decrypts the message</ li> * </ol> * Description: exception java.security.invalidkeyexception: solution to illegal key size * <ol> * <li>Download JCE unrestricted permission policy file (JDK7) on the official website at: * http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html</li> * <li>After downloading and decompressing, you can see local_policy.jar and US_export_policy.jar and readme.txt</li> * <li>If JRE is installed, put two jar files in% JRE_ Overwrite the original file in the home% \ lib \ security directory</li> * <li>If JDK is installed, put two jar files into% JDK_ Overwrite the original file in the home% \ JRE \ lib \ security directory</li> * </ol> */
3.5 code implementation
WechatMpService
package com.zrj.wechat.service; import com.zrj.wechat.entity.Response; /** * Wechat public platform interface * * @author zrj * @since 2021/9/23 **/ public interface WechatMpService { /** * Wechat public platform service test service * * @param signature Wechat encryption signature combines the token parameter filled in by the developer with the timestamp parameter and nonce parameter in the request. * @param timestamp time stamp * @param nonce random number * @param echostr Random string * @return Random string */ String security(String signature, String timestamp, String nonce, String echostr); /** * Wechat public platform message and event push and receive service * * @param signature Wechat encryption signature combines the token parameter filled in by the developer with the timestamp parameter and nonce parameter in the request * @param timestamp time stamp * @param nonce random number * @param echostr Random string * @param postData Message body * @return If you get, you only need to return SUCCESS */ String event(String signature, String timestamp, String nonce, String echostr, String postData); /** * Obtain AccessToken on wechat public platform */ Response getAccessToken(); /** * Automatic recovery rules for official account numbers */ Response getCurrentAutoreplyInfo(); /** * Get the IP address of wechat server */ Response getApiDomainIp(); /** * Network detection */ Response check(); /** * Get list of successful publications */ Response batchGetFreePublish(); /** * Custom menu / get custom menu configuration (get default menu and all personalized menu information) */ Response<Object> getMenu(); /** * Custom menu / get the current custom menu (website function publishing menu and menu set through API call) */ Response<Object> getCurrentMenu(); /** * Customize menu / create menu */ Response createMenu(); /** * Customize menu / delete menu */ Response deleteMenu(); }
WechatMpServiceImpl
package com.zrj.wechat.service.impl; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.zrj.wechat.aes.WXBizMsgCrypt; import com.zrj.wechat.constants.WechatConstants; import com.zrj.wechat.entity.Response; import com.zrj.wechat.enums.WechatEventEnum; import com.zrj.wechat.service.WechatMpService; import com.zrj.wechat.utils.Demo; import com.zrj.wechat.utils.SignaUtil; import com.zrj.wechat.utils.WechatUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; /** * Wechat public platform interface implementation class * * @author zrj * @since 2021/9/27 **/ @Slf4j @Service("WechatMpServiceImpl") public class WechatMpServiceImpl implements WechatMpService { //Get access_ Fill in client with token_ credential public static final String GRANT_TYPE = "client_credential"; //Third party user unique voucher public static final String APP_ID = "wx0e5c56c1257a4503"; //Third party user's unique credential key, i.e. appSecret public static final String APPSECRET = "eb136535b688f2056d1999a71d2e01d1"; //Get access_token interface address public static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token"; //Token access_token, which can be put into Redis cache for easy access and regular refresh public static final String ACCESS_TOKEN = "50_MokEH1zPUczovVi9mArB_tfzD0ttJbjpQesziWsrT5Y0zrIkyoAY0rSRQXDzmGmENJpwBfh9g5fFmSsBcfnURO3PHnybpgz64thgq5pGkGXrQ1uw49VkqAuswtTmGQk5j1guxCghIN9O0mYqXUSbADADAY"; //The official account token (Token) can be optimized to the configuration center, which is customized and consistent with the public platform configuration. public static final String MP_TOKEN = "zrj"; //Official account developer ID(AppID) public static final String PMP_APP_ID = "wx0e5c56c1257a4503"; //Official account message encryption key EncodingAESKey public static final String MP_ENCODING_AES_KEY = "tVNZZP2WuEJwZDF1TpIZB0vcIGjjfAcnZxUAYHvKbl6"; //Automatic recovery rules for official account numbers public static final String GET_CURRENT_AUTOREPLY_INFO = "https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info"; //Get the IP address of wechat server public static final String GET_API_DOMAIN_IP = "https://api.weixin.qq.com/cgi-bin/get_api_domain_ip"; //Network detection public static final String CHECK = "https://api.weixin.qq.com/cgi-bin/callback/check?access_token=ACCESS_TOKEN"; //Publishing capability: get the list of successful releases public static final String BATCH_GET_FREE_PUBLISH = "https://api.weixin.qq.com/cgi-bin/freepublish/batchget?access_token=ACCESS_TOKEN"; //GET the user-defined menu configuration (GET the default menu and all personalized menu information). The user-defined menu query interface can only query the menu configuration set using the API private static final String getMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/get"; //Currently used custom menus (website function publishing menu and menu set through API call) GET private static final String getCurrentMenuUrl = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info"; //Create menu POST private static final String createMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN"; //Delete menu GET private static final String deleteMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/delete"; /** * Wechat public platform service test service * * @param signature Wechat encryption signature combines the token parameter filled in by the developer with the timestamp parameter and nonce parameter in the request. * @param timestamp time stamp * @param nonce random number * @param echostr Random string * @return Random string */ @Override public String security(String signature, String timestamp, String nonce, String echostr) { log.info("[Wechat public platform server address URL [service] request parameters: signature: [{}],timestamp: [{}],nonce: [{}],echostr: [{}]", signature, timestamp, nonce, echostr); if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) { log.info("[Wechat public platform server address URL Service] request parameter is null!"); throw new IllegalArgumentException("The request parameter is illegal, please verify!"); } if (SignaUtil.checkSignature(signature, timestamp, nonce)) { log.info("[Wechat public platform server address URL Service] wechat authentication illegal request!"); } log.info("[Wechat public platform server address URL Service success]"); return echostr; } /** * Wechat public platform message and event push and receive service * If the wechat server fails to receive a response within five seconds, it will disconnect and re initiate the request. It will retry three times in total * If developers want to enhance security, they can open message encryption at the developer center, so that users will continue to encrypt messages and send official account messages to the official account. * If the server cannot guarantee to process and reply within five seconds, it must make the following reply, so that the wechat server will not process this and will not initiate retry (in this case, you can use the customer service message interface for asynchronous reply), otherwise, a serious error message will appear. See the following description for details: * 1,Directly reply to success (recommended method) 2. Directly reply to an empty string (refers to an empty string with byte length of 0, rather than the content field in the XML structure is empty) * WeChat will send a system to the user in the official account session, "if the official account is temporarily unable to provide services, please try again later": * 1,The developer did not reply to any content within 5 seconds. 2. The developer replied to abnormal data, such as JSON data * In addition, please note that when replying to multimedia messages such as pictures (gif moving pictures are not supported), you need to upload temporary materials to the wechat server through the material management interface in advance. You can use temporary materials in material management or permanent materials. * Note: 3 seconds of trouble in the test, "the official account is temporarily unable to provide services, please try again later", directly return to "success", no exception. * * @param signature Wechat encryption signature combines the token parameter filled in by the developer with the timestamp parameter and nonce parameter in the request * @param timestamp time stamp * @param nonce random number * @param echostr Random string * @param postData Message body * @return If you get, you only need to return SUCCESS */ @Override public String event(String signature, String timestamp, String nonce, String echostr, String postData) { log.info("[Wechat public platform message event receiving service] request parameters: signature: [{}],timestamp: [{}],nonce: [{}],echostr: [{}],postData: [{}]", timestamp, nonce, echostr, signature, postData); //Configure url validation if (StrUtil.isEmpty(postData)) { log.info("[Wechat public platform message event receiving service] if the message body is empty, it will directly return the successful verification and the random number echostr: {}", echostr); return echostr; } // The 3 seconds of the test failed to indicate that the official account is temporarily unable to provide services. Please try again later, and return directly to "success", no exception. //if (true) { // return "success"; //} //Receive event messages try { //This class is the decryption class provided by the wechat official website. It requires message verification Token, message encryption Key and service platform appid WXBizMsgCrypt pc = new WXBizMsgCrypt(WechatConstants.PLATFORM_COMPONENT_TOKEN, WechatConstants.PLATFORM_AES_KEY, WechatConstants.PLATFORM_APP_ID); //Encryption mode: decryption required //String xml = pc.decryptMsg(signature, timestamp, nonce, postData); //Plaintext mode String xml = postData; // Convert xml to map Map<String, String> result = WechatUtils.xmlToMap(xml); log.info("[Wechat public platform message event receiving service] receives text messages:{}", result); //Build the message body to return and reply to the text message Map<String, Object> respMsgMap = new HashMap<>(16); if (WechatEventEnum.MSGTYPE_TEXT.getCode().equals(result.get("MsgType"))) { log.info("[Wechat public platform message event receiving service] text message type"); respMsgMap.put("ToUserName", "<![CDATA[" + result.get("ToUserName") + "]]>"); respMsgMap.put("FromUserName", "<![CDATA[" + result.get("FromUserName") + "]]>"); respMsgMap.put("CreateTime", result.get("CreateTime")); respMsgMap.put("MsgType", "<![CDATA[" + result.get("MsgType") + "]]>"); respMsgMap.put("Content", "<![CDATA[Thank you for looking so good and paying attention to me[rose][rose][rose]]]>"); } else { log.info("[Wechat public platform message event receiving service] other types of messages will not be processed temporarily"); respMsgMap.putAll(result); } String respMsgXml = WechatUtils.mapToXml(respMsgMap); log.info("[Wechat public platform message event receiving service succeeded] message reply:{}", respMsgXml); return respMsgXml; } catch (Exception e) { log.info("[Wechat public platform message event receiving service] event receiving exception:", e); return WechatConstants.TICKET_FAIL; } } /** * Obtain AccessToken on wechat public platform * ?grant_type=client_credential&appid=APPID&secret=APPSECRET */ @Override public Response getAccessToken() { log.info("[Wechat public platform access AccessToken Services]"); try { //Build request parameters Map<String, Object> paramMap = new HashMap<>(16); paramMap.put("grant_type", GRANT_TYPE); paramMap.put("appid", APP_ID); paramMap.put("secret", APPSECRET); log.info("[Wechat public platform access AccessToken [interface] request parameters:[{}],Request address:[{}]", JSON.toJSONString(paramMap), GET_ACCESS_TOKEN_URL); //Execute the request and get the result String result = HttpUtil.get(GET_ACCESS_TOKEN_URL, paramMap); JSONObject resultJsonObject = JSON.parseObject(result); log.info("[Wechat public platform access AccessToken [interface] response result:[{}]", resultJsonObject); return Response.success("", resultJsonObject); } catch (Exception e) { log.info("[Wechat public platform message event receiving service] event receiving exception:", e); return Response.fail("Wechat public platform message event receiving service exception"); } } /** * Automatic recovery rules for official account numbers * ?access_token=ACCESS_TOKEN */ @Override public Response getCurrentAutoreplyInfo() { log.info("[Get the automatic return rule for official account number."); try { //Build request parameters Map<String, Object> paramMap = new HashMap<>(16); paramMap.put("access_token", ACCESS_TOKEN); log.info("[Get the official account's automatic return rule: request parameter:{}],Request address:[{}]", JSON.toJSONString(paramMap), GET_ACCESS_TOKEN_URL); //Execute the request and get the result String result = HttpUtil.get(GET_CURRENT_AUTOREPLY_INFO, paramMap); JSONObject resultJsonObject = JSON.parseObject(result); log.info("[Get the automatic reply rule of official account.{}]", resultJsonObject); return Response.success("", resultJsonObject); } catch (Exception e) { log.info("[Get the automatic reply rule of official account] handle exceptions:", e); return Response.fail("Get the automatic rule of the official account exception."); } } /** * Get the IP address of wechat server * https://api.weixin.qq.com/cgi-bin/get_api_domain_ip?access_token=ACCESS_TOKEN */ @Override public Response getApiDomainIp() { log.info("[Get wechat server IP Address]"); try { //Build request parameters Map<String, Object> paramMap = new HashMap<>(16); paramMap.put("access_token", ACCESS_TOKEN); log.info("[Get wechat server IP [address] request parameters:[{}],Request address:[{}]", JSON.toJSONString(paramMap), GET_API_DOMAIN_IP); //Execute the request and get the result String result = HttpUtil.get(GET_API_DOMAIN_IP, paramMap); JSONObject resultJsonObject = JSON.parseObject(result); log.info("[Get wechat server IP [address] response result:[{}]", resultJsonObject); return Response.success("", resultJsonObject); } catch (Exception e) { log.info("[Get wechat server IP Address] exception handling:", e); return Response.fail("Get wechat server IP Address exception"); } } /** * Network detection */ @Override public Response check() { log.info("[[network detection service]"); try { //Build request address access_token Yes Calling interface credentials String getCheckUrl = CHECK.replaceAll("ACCESS_TOKEN", ACCESS_TOKEN); //Build request parameters Map<String, Object> paramMap = new HashMap<>(16); //action is The allowable values of the detection actions performed: dns (domain name resolution), ping (ping detection), all (both dns and ping) paramMap.put("action", "all"); //check_operator is The specified platform detects from an operator. The allowed values are CHINANET (Telecom export), UNICOM (UNICOM export), CAP (Tencent self built export), DEFAULT (select the operator according to ip) paramMap.put("check_operator", "DEFAULT"); String jsonString = JSON.toJSONString(paramMap); log.info("[[network detection] request parameters:[{}],Request address:[{}]", jsonString, getCheckUrl); //Execute the request and get the result String result = HttpUtil.post(getCheckUrl, jsonString); JSONObject resultJsonObject = JSON.parseObject(result); log.info("[[network detection] response result:[{}]", resultJsonObject); return Response.success("", resultJsonObject); } catch (Exception e) { log.info("[Network detection] processing exception:", e); return Response.fail("Network detection exception"); } } /** * Get list of successful publications */ @Override public Response batchGetFreePublish() { log.info("[Release capability/Get list of successful releases]"); try { //Build request address access_token Yes Calling interface credentials String getFreePublishUrl = BATCH_GET_FREE_PUBLISH.replaceAll("ACCESS_TOKEN", ACCESS_TOKEN); //Build request parameters Map<String, Object> paramMap = new HashMap<>(16); //Offset is Return from the offset position of all materials, and 0 means return from the first material paramMap.put("offset", 0); //count is Returns the number of materials, with a value between 1 and 20 paramMap.put("count", 20); //no_content no 1 means no content field is returned, 0 means normal return, and the default is 0 paramMap.put("no_content", 0); String jsonString = JSON.toJSONString(paramMap); log.info("[Get request parameters of [successfully published list]:[{}],Request address:[{}]", jsonString, getFreePublishUrl); //Execute the request and get the result String result = HttpUtil.post(getFreePublishUrl, jsonString); JSONObject resultJsonObject = JSON.parseObject(result); log.info("[Get the response result of [successfully published list]:[{}]", resultJsonObject); return Response.success("", resultJsonObject); } catch (Exception e) { log.info("[Get successfully published list] exception handling:", e); return Response.fail("Exception in getting successful publishing list"); } } /** * Customize menu / get custom menu configuration * There is no personalized menu in phase I by default * [Get the response result of custom menu configuration: [{"errcode":48001,"errmsg":"api unauthorized rid: 6174118f-158c1dc7-5cf547b1"}] */ @Override public Response<Object> getMenu() { log.info("[Get custom menu configuration]"); try { //Build request parameters Map<String, Object> paramMap = new HashMap<>(16); paramMap.put("access_token", ACCESS_TOKEN); log.info("[To obtain the request parameters for custom menu configuration:[{}],Request address:[{}]", JSON.toJSONString(paramMap), getMenuUrl); //Execute the request and get the result String result = HttpUtil.get(getMenuUrl, paramMap); JSONObject resultJsonObject = JSON.parseObject(result); log.info("[Get the response result of custom menu configuration:[{}]", resultJsonObject); return Response.success("", resultJsonObject); } catch (Exception e) { log.info("[Get custom menu configuration] exception handling:", e); return Response.fail("Get custom menu configuration exception"); } } /** * Custom menu / get the current custom menu (website function publishing menu and menu set through API call) */ @Override public Response<Object> getCurrentMenu() { log.info("[Get current custom menu]"); try { //Build request parameters Map<String, Object> paramMap = new HashMap<>(16); paramMap.put("access_token", ACCESS_TOKEN); log.info("[Get the request parameters of current custom menu:[{}],Request address:[{}]", JSON.toJSONString(paramMap), getCurrentMenuUrl); //Execute the request and get the result String result = HttpUtil.get(getCurrentMenuUrl, paramMap); JSONObject resultJsonObject = JSON.parseObject(result); log.info("[Get the response result of current custom menu:[{}]", resultJsonObject); return Response.success("", resultJsonObject); } catch (Exception e) { log.info("[Get current custom menu] exception handling:", e); return Response.fail("Get current custom menu exception"); } } /** * Customize menu / create menu * Currently, it supports click, view and mixing */ @Override public Response createMenu() { log.info("[Customize menu/Create menu]"); try { //Build request address access_token Yes Calling interface credentials String getCreateMenuUrl = createMenuUrl.replaceAll("ACCESS_TOKEN", ACCESS_TOKEN); //Build request object String jsonString = JSON.toJSONString(Demo.buildMenuResp()); log.info("[Customize menu/Create menu] request parameters:[{}],Request address:[{}]", jsonString, getCreateMenuUrl); //Execute the request and get the result String result = HttpUtil.post(getCreateMenuUrl, jsonString); JSONObject resultJsonObject = JSON.parseObject(result); log.info("[Customize menu/Create menu] response result:[{}]", resultJsonObject); if (0 != resultJsonObject.getIntValue("errcode")) { return Response.fail("Customize menu/Failed to create menu"); } log.info("[Customize menu/[menu created successfully]"); return Response.success("Customize menu/Menu created successfully", resultJsonObject); } catch (Exception e) { log.info("[Customize menu/Create menu] exception handling:", e); return Response.fail("Customize menu/Menu creation succeeded exception"); } } /** * Customize menu / delete menu */ @Override public Response deleteMenu() { log.info("[Customize menu/Delete menu]"); try { //Build request parameters Map<String, Object> paramMap = new HashMap<>(16); paramMap.put("access_token", ACCESS_TOKEN); log.info("[Customize menu/Delete menu] request parameters:[{}],Request address:[{}]", JSON.toJSONString(paramMap), deleteMenuUrl); //Execute the request and get the result String result = HttpUtil.get(deleteMenuUrl, paramMap); JSONObject resultJsonObject = JSON.parseObject(result); log.info("[Customize menu/Delete menu] response result:[{}]", resultJsonObject); return Response.success("", resultJsonObject); } catch (Exception e) { log.info("[Customize menu/Delete menu] exception handling:", e); return Response.fail("Customize menu/Delete menu exception"); } } }
WechatMpController
package com.zrj.wechat.controller; import com.zrj.wechat.entity.Response; import com.zrj.wechat.service.WechatMpService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; /** * Wechat public platform * * @author zrj * @since 2021/10/23 **/ @Slf4j @RestController @RequestMapping("/wechat/mp") @Api(tags = "Wechat public platform service", description = "Wechat public platform service") public class WechatMpController { @Resource private WechatMpService wechatMpService; /** * Wechat public platform service test service */ @GetMapping("/test") @ApiOperation(value = "Wechat public platform service test service", notes = "Remarks on test method", httpMethod = "GET") public Response test() { log.info("[Wechat public platform service test succeeded]"); return Response.success("Wechat public platform service test succeeded", null); } /** * Wechat public platform server address URL service * Official account - basic configuration - server configuration - server address (URL): http://zrj.free.idcfengye.com/wechat/token/security * https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html * The IP address of the calling interface is not in the white list, please set it in the interface IP white list. * * @param signature Wechat encryption signature combines the token parameter filled in by the developer with the timestamp parameter and nonce parameter in the request * @param timestamp time stamp * @param nonce random number * @param echostr Random string * @return Random string */ @GetMapping(value = "/security", produces = "text/plain;charset=utf-8") @ApiOperation(value = "Wechat public platform server address URL service", notes = "Wechat authentication description", httpMethod = "GET") public String security(@RequestParam(name = "signature", required = false) String signature, @RequestParam(name = "timestamp", required = false) String timestamp, @RequestParam(name = "nonce", required = false) String nonce, @RequestParam(name = "echostr", required = false) String echostr) { return wechatMpService.security(signature, timestamp, nonce, echostr); } /** * Wechat public platform message and event push and receive service * Official account development tool public platform test account test number management interface configuration information (URL): http://zrj.free.idcfengye.com/wechat/token/event * https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index * 1.Authorization event receive URL * 2.Verification note * * @param signature Wechat encryption signature combines the token parameter filled in by the developer with the timestamp parameter and nonce parameter in the request * @param timestamp time stamp * @param nonce random number * @param echostr Random string * @param postData Message body * @return java.lang.String */ @PostMapping(value = "/event", produces = "application/xml; charset=UTF-8") @ApiOperation(value = "Wechat public platform authorization event reception URL Verification note") public String event(@RequestParam("signature") String signature, @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce, @RequestParam(required = false) String echostr, @RequestBody(required = false) String postData) { return wechatMpService.event(signature, timestamp, nonce, echostr, postData); } /** * Obtain AccessToken on wechat public platform * access_token The official account is the only interface call credential for public numbers. When calling the interfaces, the official account needs to use access_. token. * Developers need to keep it properly. access_ At least 512 character space should be reserved for token storage. access_ The validity period of the token is currently 2 hours. It needs to be refreshed regularly. Repeated acquisition will result in the access obtained last time_ The token is invalid. * https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html * The IP address of the calling interface is not in the white list, please set it in the interface IP white list. */ @GetMapping("/token") @ApiOperation(value = "Wechat public platform access AccessToken") public Response getAccessToken() { return wechatMpService.getAccessToken(); } /** * Automatic recovery rules for official account numbers */ @GetMapping("/getCurrentAutoreplyInfo") @ApiOperation(value = "Automatic recovery rules for official account numbers") public Response getCurrentAutoreplyInfo() { return wechatMpService.getCurrentAutoreplyInfo(); } /** * Get the IP address of wechat server */ @GetMapping("/getApiDomainIp") @ApiOperation(value = "Get wechat server IP address") public Response getApiDomainIp() { return wechatMpService.getApiDomainIp(); } /** * Network detection */ @PostMapping("/check") @ApiOperation(value = "Network detection") public Response check() { return wechatMpService.check(); } /** * Publishing capability / get list of successful releases */ @GetMapping("/batchGetFreePublish") @ApiOperation(value = "Release capability/Get list of successful publications") public Response batchGetFreePublish() { return wechatMpService.batchGetFreePublish(); } /** * Customize menu / get custom menu configuration */ @GetMapping("/getMenu") @ApiOperation(value = "Customize menu/Get custom menu", httpMethod = "GET") public Response<Object> getMenu() { return wechatMpService.getMenu(); } /** * Custom menu / get current custom menu */ @GetMapping("/getCurrentMenu") @ApiOperation(value = "Customize menu/Get current custom menu", httpMethod = "GET") public Response<Object> getCurrentMenu() { return wechatMpService.getCurrentMenu(); } /** * Customize menu / create menu */ @PostMapping("/createMenu") @ApiOperation(value = "Customize menu/create menu") public Response<String> createMenu() { return wechatMpService.createMenu(); } /** * Customize menu / delete menu */ @GetMapping("/deleteMenu") @ApiOperation(value = "Customize menu/Delete menu") public Response<Object> deleteMenu() { return wechatMpService.deleteMenu(); } }