In recent projects, the enterprise wechat application needs to use the mass message sending function to notify the customer of the alarm messages generated by the system through the enterprise wechat mass sending, so as to deal with the faults in time. It is relatively simple to use. Here is a record of the process for future reference. There is a little introduction to terms in the front of the article, If you want to see how to use it quickly and directly, click here to skip the introduction of basic terms and start directly.
1, Introduction to basic terms
1.corpid
Each enterprise has a unique corpid. To obtain this information, you can view the "enterprise ID" (with administrator permission) under "my enterprise" - enterprise information "in the management background
2.userid
Each member has a unique userid, the so-called "account". In the management background - > address book - > click the details page of a member to see it.
3. Department id
Each department has a unique id. in the management background - > address book - > organizational structure - > click the dot on the right of a department to see it
4.tagid
Each tag has a unique tag id. in the management background - > address book - > tag, select a tag, and there will be a "tag details" button in the upper right corner. Click to see it
5.agentid
Each application has a unique agentid. In the management background - > applications and applets - > applications, click an application to see the agentid.
6.secret
Secret is the "key" used to ensure data security in enterprise applications. Each application has an independent access key. In order to ensure data security, secret must not be disclosed.
Self built application secret. In the management background->""Apps and applets"->""Apply"->"Self built ", click an application to see it. Basic application secret. Some basic applications (such as "approval" and "punch in" applications) support passing API Perform the operation. In the management background->""Apps and applets"->"application->""Basic ", click to enter an application and click to open“ API"Small button, you can see. Address book management secret. In "administrative tools"-"View in "address book synchronization" (to be opened)“ API Interface synchronization "); Customer contact management secret. In the "customer contact" column, click open“ API"Small button, you can see.
7.access_token
The access_token is an important ticket when the enterprise background goes to the enterprise wechat background to obtain information. It is generated by corpid and secret. All interfaces need to carry this information during communication to verify the access rights of the interface
2, Mass sending application messages through enterprise wechat server API
1. Preparation of HTTP interface calling tool class
Because Http calls are needed, two Http call tools are prepared in advance. One is implemented by Java's Jdk and does not rely on any jar package. It can be used for testing. If you do not call much, it can also be used for production. The other is httpClient that relies on apache and has the function of connection pool. It is recommended to be used for production. Because the code accounts for too much content, the code is located in the text At the end of the chapter, You can directly jump to the code deployment view, and click to jump
2. Get access_token
Official interface documents: https://work.weixin.qq.com/api/doc/90000/90135/91039
Request method: GET (HTTPS)
Request URL: https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET
Test code:
public static void main(String[] args) throws InterruptedException { //Here replace your corpid and corpsecret with the correct ones String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ww160d****&corpsecret=BAtr2B***************"; System.out.println(HttpsKit.get(url)); //Close the connection pool. Do not close it in the formal environment HttpsKit.closeConnectionPool(); }
Response results:
{"errcode":0,"errmsg":"ok","access_token":"vMpg1HNU8PHf0qqNSfVGMXw2Gg0HN16LnvMH3J4LXeoY5MMA25PiO2ZabcdHJ6bRi5PqUuyLf94aRBb3yTKs344h5eU35doprLeIKtuf9xfKOk8VQ6F_GeTuxmcV_qQH0CLOrc5y9cXT9SCEi7LpQCiS4F4ssdff0zu-jyGmlEtUBplqSF8xDQBJ3aj6-hfg","expires_in":7200}
3. Call the group application message sending interface
Official document of group application message sending interface: https://work.weixin.qq.com/api/doc/90000/90135/90236
The application supports pushing text, picture, video, file, picture and text, etc.
Request method: POST (HTTPS)
Request address: https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN
Take the text message as an example. The access_token is in the request address. Other parameters are encapsulated in json. For other parameters, please refer to the above document for details. For example, the following screenshot is obtained from the official document
The test code is as follows:
public static void main(String[] args) throws InterruptedException { String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=JhLKJB2cZssssssssssssssssssssssssssssssssssssU2HHQ"; String data = "{\"touser\":\"@all\",\"msgtype\":\"text\",\"agentid\":1000001,\"text\":{\"content\":\"Application group sending alarm message under test,Excuse me, please ignore.\"}}"; System.out.println(HttpsKit.postJson(url, data)); //Close the connection pool. Do not close it in the formal environment HttpsKit.closeConnectionPool(); }
4. The HTTP interface calling tool class code is provided as follows:
Tool class 1: implemented using URLConnection provided with pure jdk
package cn.gzsendi.system.utils; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class HttpRestUtils { private final String GET = "GET"; private final String POST = "POST"; private final String CharacterSet = "UTF-8"; public String doGet(String url) throws Exception{ String method = this.GET; return load(url,null,method); } public String doPost(String url, String params) throws Exception{ String method = this.POST; return load(url,params,method); } /** * @param url * @param params * @param method * @return * @throws Exception */ public String load(String url,String params,String method) throws Exception { HttpURLConnection conn = null; try { boolean isHttps = url.startsWith("https"); URL restURL = new URL(url); conn = (HttpURLConnection) restURL.openConnection(); //https requests need extra processing if(isHttps) { TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); SSLSocketFactory ssf = sslContext.getSocketFactory(); ((HttpsURLConnection)conn).setSSLSocketFactory(ssf); ((HttpsURLConnection)conn).setHostnameVerifier(new TrustAnyHostnameVerifier()); } conn.setDoOutput(true); conn.setAllowUserInteraction(false); conn.setUseCaches(false); conn.setRequestMethod(method); conn.connect(); OutputStreamWriter out = null; OutputStream outputStream = null; if(this.POST.equals(method) && params != null){ outputStream = conn.getOutputStream(); out = new OutputStreamWriter(outputStream, this.CharacterSet); out.write(params); out.close(); } InputStream inputStream = conn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, this.CharacterSet); BufferedReader bReader = new BufferedReader(inputStreamReader); String line = ""; StringBuffer resultStr = new StringBuffer(); while (null != (line = bReader.readLine())) { resultStr.append(line); } // Release resources bReader.close(); inputStreamReader.close(); inputStream.close(); inputStream = null; if(out!=null) out.close(); if(outputStream!=null)outputStream.close(); return resultStr.toString(); } catch (Exception e) { e.printStackTrace(); } finally { if(conn != null) conn.disconnect(); } return null; } private class TrustAnyHostnameVerifier implements HostnameVerifier { public boolean verify(String hostname, SSLSession session) { // Directly return true return true; } } private class MyX509TrustManager implements X509TrustManager { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } } }
Tool class 2: write an implementation class using apache's httpclient
Note: pom dependency. My tool class uses common IO, httpclient, and log4j. If you don't want log4j, you can adjust and delete it according to the code. Common IO is the same. You can also use other methods to modify the code.
<!-- httpclient start --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.12</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5.12</version> </dependency> <!-- httpclient end --> <!-- common-io start --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.7</version> </dependency> <!-- common-io end --> <!-- log start --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!-- log end -->
package cn.gzsendi.system.utils; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TimerTask; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; import org.apache.commons.codec.CharEncoding; import org.apache.commons.io.IOUtils; import org.apache.http.Consts; import org.apache.http.HttpEntity; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpRequest; import org.apache.http.NameValuePair; import org.apache.http.NoHttpResponseException; import org.apache.http.client.HttpRequestRetryHandler; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.LayeredConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HttpContext; import org.apache.http.ssl.SSLContextBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HttpsKit { private static Logger logger = LoggerFactory.getLogger(HttpsKit.class); private static final int CONNECT_TIMEOUT = 10000;// Set the timeout for connection establishment to 10000ms private static final int SOCKET_TIMEOUT = 30000; // How long is there no data transmission private static final int HttpIdelTimeout = 30000;//free time private static final int HttpMonitorInterval = 10000;//How often private static final int MAX_CONN = 200; // maximum connection private static final int Max_PRE_ROUTE = 200; //Set the maximum number of connections to the route, private static CloseableHttpClient httpClient; // Client singleton sending request private static PoolingHttpClientConnectionManager manager; // Connection pool management class private static ScheduledExecutorService monitorExecutor; private static final String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded"; private static final String APPLICATION_JSON = "application/json"; private final static Object syncLock = new Object(); // Equivalent to thread lock, used for thread safety private static RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(CONNECT_TIMEOUT) .setConnectTimeout(CONNECT_TIMEOUT) .setSocketTimeout(SOCKET_TIMEOUT).build(); private static CloseableHttpClient getHttpClient() { if (httpClient == null) { // When multiple threads call getHttpClient at the same time under multithreading, it is easy to create httpClient objects repeatedly, so a synchronization lock is added synchronized (syncLock) { if (httpClient == null) { try { httpClient = createHttpClient(); } catch (KeyManagementException e) { logger.error("error",e); } catch (NoSuchAlgorithmException e) { logger.error("error",e); } catch (KeyStoreException e) { logger.error("error",e); } // Start the monitoring thread and close the abnormal and idle threads monitorExecutor = Executors.newScheduledThreadPool(1); monitorExecutor.scheduleAtFixedRate(new TimerTask() { @Override public void run() { // Close abnormal connection manager.closeExpiredConnections(); // Close 5s idle connections manager.closeIdleConnections(HttpIdelTimeout,TimeUnit.MILLISECONDS); logger.info(manager.getTotalStats().toString()); //logger.info("close expired and idle for over "+HttpIdelTimeout+"ms connection"); } }, HttpMonitorInterval, HttpMonitorInterval, TimeUnit.MILLISECONDS); } } } return httpClient; } /** * Building httpclient instances * @return * @throws KeyStoreException * @throws NoSuchAlgorithmException * @throws KeyManagementException */ private static CloseableHttpClient createHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { SSLContextBuilder builder = new SSLContextBuilder(); // All trust without identification builder.loadTrustMaterial(null, new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { return true; } }); ConnectionSocketFactory plainSocketFactory = PlainConnectionSocketFactory.getSocketFactory(); LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE); Registry<ConnectionSocketFactory> registry = RegistryBuilder .<ConnectionSocketFactory> create() .register("http", plainSocketFactory) .register("https", sslSocketFactory).build(); manager = new PoolingHttpClientConnectionManager(registry); // Set connection parameters manager.setMaxTotal(MAX_CONN); // maximum connection manager.setDefaultMaxPerRoute(Max_PRE_ROUTE); // Maximum number of routing connections // When the request fails, retry the request HttpRequestRetryHandler handler = new HttpRequestRetryHandler() { @Override public boolean retryRequest(IOException e, int i, HttpContext httpContext) { if (i > 3) { // Retry more than 3 times, abandon the request logger.error("retry has more than 3 time, give up request"); return false; } if (e instanceof NoHttpResponseException) { // The server is not responding. The server may be disconnected. You should try again logger.error("receive no response from server, retry"); return true; } if (e instanceof SSLHandshakeException) { // SSL handshake exception logger.error("SSL hand shake exception"); return false; } if (e instanceof InterruptedIOException) { // overtime logger.error("InterruptedIOException"); return false; } if (e instanceof UnknownHostException) { // Server unreachable logger.error("server host unknown"); return false; } if (e instanceof ConnectTimeoutException) { // connection timed out logger.error("Connection Time out"); return false; } if (e instanceof SSLException) { logger.error("SSLException"); return false; } HttpClientContext context = HttpClientContext.adapt(httpContext); HttpRequest request = context.getRequest(); if (!(request instanceof HttpEntityEnclosingRequest)) { // If the request is not a request to close the connection return true; } return false; } }; CloseableHttpClient client = HttpClients.custom().setConnectionManager(manager).setRetryHandler(handler).build(); return client; } public static String get(String url) { HttpGet httpGet = new HttpGet(url); httpGet.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"); httpGet.setConfig(requestConfig); CloseableHttpResponse response = null; InputStream in = null; String result = null; try { response = getHttpClient().execute(httpGet,HttpClientContext.create()); HttpEntity entity = response.getEntity(); if (entity != null) { in = entity.getContent(); result = IOUtils.toString(in, "utf-8"); } } catch (IOException e) { logger.error("error",e); } finally { try { if (in != null) in.close(); } catch (IOException e) { logger.error("error",e); } try { if (response != null) response.close(); } catch (IOException e) { logger.error("error",e); } } return result; } public static String postJson(String url,Map<String,Object> requestParams) { return postJson(url, JsonUtil.toJSONString(requestParams)); } public static String postJson(String url,Map<String,Object> requestParams,Map<String,Object> headerParams) { return postJson(url, JsonUtil.toJSONString(requestParams),headerParams); } public static String postJson(String url,String requestParamStr) { return postJson(url, requestParamStr, null); } public static String postJson(String url,String requestParamStr,Map<String,Object> headerParams) { HttpPost httppost = new HttpPost(url); httppost.setHeader("Content-Type", APPLICATION_JSON+";charset=" + CharEncoding.UTF_8); httppost.setHeader("Accept",APPLICATION_JSON+";charset=" +CharEncoding.UTF_8); httppost.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"); if(headerParams != null && headerParams.size()>0){ for(String headerName : headerParams.keySet()) { httppost.setHeader(headerName,headerParams.get(headerName)+""); } } StringEntity se = new StringEntity(requestParamStr,CharEncoding.UTF_8); se.setContentType(APPLICATION_JSON+";charset=" +CharEncoding.UTF_8); httppost.setEntity(se); httppost.setConfig(requestConfig); CloseableHttpResponse response = null; InputStream in = null; String result = null; try { response = getHttpClient().execute(httppost,HttpClientContext.create()); HttpEntity entity = response.getEntity(); if (entity != null) { in = entity.getContent(); result = IOUtils.toString(in, "utf-8"); } } catch (IOException e) { logger.error("error",e); } finally { try { if (in != null) in.close(); } catch (IOException e) { logger.error("error",e); } try { if (response != null) response.close(); } catch (IOException e) { logger.error("error",e); } } return result; } //requestParamStr---------->>> name=test&age=12 public static String postFormUrlencoded(String url,String requestParamStr) { return postFormUrlencoded(url, requestParamStr ,null); } public static String postFormUrlencoded(String url,String requestParamStr,Map<String,Object> headerParams) { Map<String,String> requestParams = new HashMap<String,String>(); String[] strs = requestParamStr.split("&"); for(String str : strs) { String[] keyValues = str.split("="); if(keyValues.length == 2) { requestParams.put(keyValues[0], keyValues[1]); } } return postFormUrlencoded(url, requestParams,headerParams); } public static String postFormUrlencoded(String url,Map<String,String> requestParams) { return postFormUrlencoded(url,requestParams,null); } public static String postFormUrlencoded(String url,Map<String,String> requestParams,Map<String,Object> headerParams) { HttpPost httppost = new HttpPost(url); //application/json httppost.setHeader("Content-Type", APPLICATION_FORM_URLENCODED+";charset=" + CharEncoding.UTF_8); httppost.setHeader("Accept",APPLICATION_FORM_URLENCODED+";charset=" +CharEncoding.UTF_8); httppost.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"); if(headerParams != null && headerParams.size()>0){ for(String headerName : headerParams.keySet()) { httppost.setHeader(headerName,headerParams.get(headerName)+""); } } List<NameValuePair> formparams = new ArrayList<NameValuePair>(); for(String keyStr : requestParams.keySet()) { formparams.add(new BasicNameValuePair(keyStr, requestParams.get(keyStr))); } UrlEncodedFormEntity uefe = new UrlEncodedFormEntity(formparams, Consts.UTF_8); httppost.setEntity(uefe); httppost.setConfig(requestConfig); CloseableHttpResponse response = null; InputStream in = null; String result = null; try { response = getHttpClient().execute(httppost,HttpClientContext.create()); HttpEntity entity = response.getEntity(); if (entity != null) { in = entity.getContent(); result = IOUtils.toString(in, "utf-8"); } } catch (IOException e) { logger.error("error",e); } finally { try { if (in != null) in.close(); if (response != null) response.close(); } catch (IOException e) { logger.error("error",e); } } return result; } /** * Close connection pool */ public static void closeConnectionPool() { try { if(httpClient != null) httpClient.close(); if(manager != null) manager.close(); if(monitorExecutor != null) monitorExecutor.shutdown(); } catch (IOException e) { logger.error("error",e); } } }