From 7553130cd5f906ec35c20db8a66834fdfd00e34c Mon Sep 17 00:00:00 2001 From: ecoolper Date: Tue, 18 Apr 2017 17:29:13 +0800 Subject: [PATCH 001/179] weixin-java-tools usage jodd-http --- .../wxpay/service/impl/WxPayServiceImplTest.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java index 93b0b8b552..b59bd1eb79 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java @@ -1,5 +1,7 @@ package com.github.binarywang.wxpay.service.impl; +import static org.testng.Assert.*; + import com.github.binarywang.utils.qrcode.QrcodeUtils; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; @@ -10,15 +12,14 @@ import me.chanjar.weixin.common.exception.WxErrorException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.testng.annotations.*; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; -import static org.testng.Assert.*; - /** * 测试支付相关接口 * Created by Binary Wang on 2016/7/28. @@ -264,4 +265,5 @@ public void testAuthcode2Openid() throws Exception { this.logger.info(result); } + } From 30cdad539c33b103cb9b79e5aaf7815e844b299d Mon Sep 17 00:00:00 2001 From: ecoolper Date: Tue, 18 Apr 2017 17:33:11 +0800 Subject: [PATCH 002/179] weixin-java-tools pay usage jodd-http --- .../wxpay/service/impl/WxPayServiceImpl.java | 34 +++++-------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java index c26d058392..ed609c2351 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java @@ -9,27 +9,19 @@ import com.google.common.collect.Maps; import jodd.http.HttpRequest; import jodd.http.HttpResponse; +import jodd.http.net.SSLSocketHttpConnectionProvider; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import org.apache.commons.lang3.CharEncoding; import org.apache.commons.lang3.StringUtils; -import org.apache.http.Consts; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.ssl.DefaultHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.net.ssl.SSLContext; import java.io.File; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Map; +import javax.net.ssl.SSLContext; /** * Created by Binary Wang on 2016/7/28. @@ -384,6 +376,7 @@ private String post(String url, String xmlParam) { /** * 由于暂时未找到使用jodd-http实现证书配置的办法,故而暂时使用httpclient + * ecoolper(20170418),修改为jodd-http方式 */ private String postWithKey(String url, String requestStr) throws WxErrorException { try { @@ -392,21 +385,12 @@ private String postWithKey(String url, String requestStr) throws WxErrorExceptio sslContext = this.getConfig().initSSLContext(); } - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, - new String[]{"TLSv1"}, null, new DefaultHostnameVerifier()); - - HttpPost httpPost = new HttpPost(url); - - try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build()) { - httpPost.setEntity(new StringEntity(new String(requestStr.getBytes(CharEncoding.UTF_8), CharEncoding.ISO_8859_1))); - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result); - return result; - } - } finally { - httpPost.releaseConnection(); - } + HttpRequest request =HttpRequest.post(url).withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext)); + request.bodyText(requestStr); + HttpResponse response =request.send(); + String result = response.bodyText(); + this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result); + return result; } catch (Exception e) { this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", url, requestStr, e.getMessage()); throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg(e.getMessage()).build(), e); From 0e6113b7658af6020b29e0b945b2a084d11ef740 Mon Sep 17 00:00:00 2001 From: ecoolper Date: Wed, 19 Apr 2017 10:39:06 +0800 Subject: [PATCH 003/179] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binarywang/wxpay/service/impl/WxPayServiceImpl.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java index ed609c2351..2572f0911a 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java @@ -375,7 +375,6 @@ private String post(String url, String xmlParam) { } /** - * 由于暂时未找到使用jodd-http实现证书配置的办法,故而暂时使用httpclient * ecoolper(20170418),修改为jodd-http方式 */ private String postWithKey(String url, String requestStr) throws WxErrorException { @@ -385,9 +384,9 @@ private String postWithKey(String url, String requestStr) throws WxErrorExceptio sslContext = this.getConfig().initSSLContext(); } - HttpRequest request =HttpRequest.post(url).withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext)); + HttpRequest request = HttpRequest.post(url).withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext)); request.bodyText(requestStr); - HttpResponse response =request.send(); + HttpResponse response = request.send(); String result = response.bodyText(); this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result); return result; From 897e13958707361effb6f0724f71d6899f0b4e0e Mon Sep 17 00:00:00 2001 From: ecoolper Date: Thu, 20 Apr 2017 17:34:45 +0800 Subject: [PATCH 004/179] jodd --- .../http/jodd/ApacheHttpClientBuilder.java | 53 ++++ .../jodd/DefaultApacheHttpClientBuilder.java | 292 ++++++++++++++++++ .../http/jodd/InputStreamResponseHandler.java | 28 ++ .../jodd/MediaDownloadRequestExecutor.java | 76 +++++ .../http/jodd/MediaUploadRequestExecutor.java | 39 +++ .../util/http/jodd/RequestExecutor.java | 25 ++ .../http/jodd/SimpleGetRequestExecutor.java | 43 +++ .../http/jodd/SimplePostRequestExecutor.java | 51 +++ .../weixin/common/util/http/jodd/URIUtil.java | 48 +++ .../util/http/jodd/Utf8ResponseHandler.java | 33 ++ 10 files changed, 688 insertions(+) create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/DefaultApacheHttpClientBuilder.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/InputStreamResponseHandler.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/Utf8ResponseHandler.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java new file mode 100644 index 0000000000..ce021a042a --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java @@ -0,0 +1,53 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.CloseableHttpClient; + +/** + * httpclient build interface + * @author kakotor + */ +public interface ApacheHttpClientBuilder { + + /** + * 构建httpclient实例 + * + * @return new instance of CloseableHttpClient + */ + CloseableHttpClient build(); + + /** + * 代理服务器地址 + * + * @param httpProxyHost + */ + ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); + + /** + * 代理服务器端口 + * + * @param httpProxyPort + */ + ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); + + /** + * 代理服务器用户名 + * + * @param httpProxyUsername + */ + ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); + + /** + * 代理服务器密码 + * + * @param httpProxyPassword + */ + ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); + + /** + * ssl连接socket工厂 + * + * @param sslConnectionSocketFactory + */ + ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/DefaultApacheHttpClientBuilder.java new file mode 100644 index 0000000000..3f667abe4d --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/DefaultApacheHttpClientBuilder.java @@ -0,0 +1,292 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.annotation.NotThreadSafe; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.HttpRequestRetryHandler; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.config.SocketConfig; +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.protocol.HttpContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * httpclient 连接管理器 + * + * @author kakotor + */ +@NotThreadSafe +public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder { + protected final Logger log = LoggerFactory.getLogger(DefaultApacheHttpClientBuilder.class); + private final AtomicBoolean prepared = new AtomicBoolean(false); + private int connectionRequestTimeout = 3000; + private int connectionTimeout = 5000; + private int soTimeout = 5000; + private int idleConnTimeout = 60000; + private int checkWaitTime = 60000; + private int maxConnPerHost = 10; + private int maxTotalConn = 50; + private String userAgent; + private HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { + @Override + public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { + return false; + } + }; + private SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory(); + private PlainConnectionSocketFactory plainConnectionSocketFactory = PlainConnectionSocketFactory.getSocketFactory(); + private String httpProxyHost; + private int httpProxyPort; + private String httpProxyUsername; + private String httpProxyPassword; + /** + * 闲置连接监控线程 + */ + private IdleConnectionMonitorThread idleConnectionMonitorThread; + private HttpClientBuilder httpClientBuilder; + + private DefaultApacheHttpClientBuilder() { + } + + public static DefaultApacheHttpClientBuilder get() { + return new DefaultApacheHttpClientBuilder(); + } + + @Override + public ApacheHttpClientBuilder httpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + return this; + } + + @Override + public ApacheHttpClientBuilder httpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + return this; + } + + @Override + public ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + return this; + } + + @Override + public ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + return this; + } + + @Override + public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory) { + this.sslConnectionSocketFactory = sslConnectionSocketFactory; + return this; + } + + /** + * 获取链接的超时时间设置,默认3000ms + *

+ * 设置为零时不超时,一直等待. + * 设置为负数是使用系统默认设置(非上述的3000ms的默认值,而是httpclient的默认设置). + *

+ * + * @param connectionRequestTimeout 获取链接的超时时间设置(单位毫秒),默认3000ms + */ + public void setConnectionRequestTimeout(int connectionRequestTimeout) { + this.connectionRequestTimeout = connectionRequestTimeout; + } + + /** + * 建立链接的超时时间,默认为5000ms.由于是在链接池获取链接,此设置应该并不起什么作用 + *

+ * 设置为零时不超时,一直等待. + * 设置为负数是使用系统默认设置(非上述的5000ms的默认值,而是httpclient的默认设置). + *

+ * + * @param connectionTimeout 建立链接的超时时间设置(单位毫秒),默认5000ms + */ + public void setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + /** + * 默认NIO的socket超时设置,默认5000ms. + * + * @param soTimeout 默认NIO的socket超时设置,默认5000ms. + * @see java.net.SocketOptions#SO_TIMEOUT + */ + public void setSoTimeout(int soTimeout) { + this.soTimeout = soTimeout; + } + + /** + * 空闲链接的超时时间,默认60000ms. + *

+ * 超时的链接将在下一次空闲链接检查是被销毁 + *

+ * + * @param idleConnTimeout 空闲链接的超时时间,默认60000ms. + */ + public void setIdleConnTimeout(int idleConnTimeout) { + this.idleConnTimeout = idleConnTimeout; + } + + /** + * 检查空间链接的间隔周期,默认60000ms. + * + * @param checkWaitTime 检查空间链接的间隔周期,默认60000ms. + */ + public void setCheckWaitTime(int checkWaitTime) { + this.checkWaitTime = checkWaitTime; + } + + /** + * 每路的最大链接数,默认10 + * + * @param maxConnPerHost 每路的最大链接数,默认10 + */ + public void setMaxConnPerHost(int maxConnPerHost) { + this.maxConnPerHost = maxConnPerHost; + } + + /** + * 最大总连接数,默认50 + * + * @param maxTotalConn 最大总连接数,默认50 + */ + public void setMaxTotalConn(int maxTotalConn) { + this.maxTotalConn = maxTotalConn; + } + + /** + * 自定义httpclient的User Agent + * + * @param userAgent User Agent + */ + public void setUserAgent(String userAgent) { + this.userAgent = userAgent; + } + + public IdleConnectionMonitorThread getIdleConnectionMonitorThread() { + return this.idleConnectionMonitorThread; + } + + private synchronized void prepare() { + if(prepared.get()){ + return; + } + Registry registry = RegistryBuilder.create() + .register("http", this.plainConnectionSocketFactory) + .register("https", this.sslConnectionSocketFactory) + .build(); + + @SuppressWarnings("resource") + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry); + connectionManager.setMaxTotal(this.maxTotalConn); + connectionManager.setDefaultMaxPerRoute(this.maxConnPerHost); + connectionManager.setDefaultSocketConfig( + SocketConfig.copy(SocketConfig.DEFAULT) + .setSoTimeout(this.soTimeout) + .build() + ); + + this.idleConnectionMonitorThread = new IdleConnectionMonitorThread( + connectionManager, this.idleConnTimeout, this.checkWaitTime); + this.idleConnectionMonitorThread.setDaemon(true); + this.idleConnectionMonitorThread.start(); + + this.httpClientBuilder = HttpClients.custom() + .setConnectionManager(connectionManager) + .setConnectionManagerShared(true) + .setDefaultRequestConfig( + RequestConfig.custom() + .setSocketTimeout(this.soTimeout) + .setConnectTimeout(this.connectionTimeout) + .setConnectionRequestTimeout(this.connectionRequestTimeout) + .build() + ) + .setRetryHandler(this.httpRequestRetryHandler); + + if (StringUtils.isNotBlank(this.httpProxyHost) + && StringUtils.isNotBlank(this.httpProxyUsername)) { + // 使用代理服务器 需要用户认证的代理服务器 + CredentialsProvider provider = new BasicCredentialsProvider(); + provider.setCredentials( + new AuthScope(this.httpProxyHost, this.httpProxyPort), + new UsernamePasswordCredentials(this.httpProxyUsername, + this.httpProxyPassword)); + this.httpClientBuilder.setDefaultCredentialsProvider(provider); + } + + if (StringUtils.isNotBlank(this.userAgent)) { + this.httpClientBuilder.setUserAgent(this.userAgent); + } + prepared.set(true); + } + + @Override + public CloseableHttpClient build() { + if(!prepared.get()){ + prepare(); + } + return this.httpClientBuilder.build(); + } + + public static class IdleConnectionMonitorThread extends Thread { + private final HttpClientConnectionManager connMgr; + private final int idleConnTimeout; + private final int checkWaitTime; + private volatile boolean shutdown; + + public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, int checkWaitTime) { + super("IdleConnectionMonitorThread"); + this.connMgr = connMgr; + this.idleConnTimeout = idleConnTimeout; + this.checkWaitTime = checkWaitTime; + } + + @Override + public void run() { + try { + while (!this.shutdown) { + synchronized (this) { + wait(this.checkWaitTime); + this.connMgr.closeExpiredConnections(); + this.connMgr.closeIdleConnections(this.idleConnTimeout, + TimeUnit.MILLISECONDS); + } + } + } catch (InterruptedException ignore) { + } + } + + public void trigger() { + synchronized (this) { + notifyAll(); + } + } + + public void shutdown() { + this.shutdown = true; + synchronized (this) { + notifyAll(); + } + } + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/InputStreamResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/InputStreamResponseHandler.java new file mode 100644 index 0000000000..a766d4c268 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/InputStreamResponseHandler.java @@ -0,0 +1,28 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.ResponseHandler; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.io.InputStream; + +public class InputStreamResponseHandler implements ResponseHandler { + + public static final ResponseHandler INSTANCE = new InputStreamResponseHandler(); + + @Override + public InputStream handleResponse(final HttpResponse response) throws IOException { + final StatusLine statusLine = response.getStatusLine(); + final HttpEntity entity = response.getEntity(); + if (statusLine.getStatusCode() >= 300) { + EntityUtils.consume(entity); + throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); + } + return entity == null ? null : entity.getContent(); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java new file mode 100644 index 0000000000..ff617e8ee5 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java @@ -0,0 +1,76 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File + * 视频文件不支持下载 + * + * @author Daniel Qian + */ +public class MediaDownloadRequestExecutor implements RequestExecutor { + + private File tmpDirFile; + + public MediaDownloadRequestExecutor() { + } + + public MediaDownloadRequestExecutor(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public File execute(ProxyInfo httpProxy, String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpRequest httpRequest = HttpRequest.post(uri); + HttpResponse response = httpRequest.send(); + String contentType = response.header("Content-Type"); + if (contentType != null && contentType.startsWith("application/json")) { + // application/json; encoding=utf-8 下载媒体文件出错 + throw new WxErrorException(WxError.fromJson(response.bodyText())); + } + + String fileName = getFileName(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + + InputStream inputStream = new ByteArrayInputStream(response.bodyBytes()); + String[] nameAndExt = fileName.split("\\."); + return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); + } + + private String getFileName(HttpResponse response) throws WxErrorException { + String content = response.header("Content-disposition"); + if (content == null || content.length() == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(content); + if (m.matches()) { + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java new file mode 100644 index 0000000000..43d7bbaef3 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.http.net.SocketHttpConnectionProvider; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.File; +import java.io.IOException; + +/** + * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String + * + * @author Daniel Qian + */ +public class MediaUploadRequestExecutor implements RequestExecutor { + + @Override + public WxMediaUploadResult execute(ProxyInfo httpProxy, String uri, File file) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); + provider.useProxy(httpProxy); + request.withConnectionProvider(provider); + } + request.form("media", file); + HttpResponse response = request.send(); + String responseContent =response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMediaUploadResult.fromJson(responseContent); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java new file mode 100644 index 0000000000..ccc827020f --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java @@ -0,0 +1,25 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.IOException; + +/** + * http请求执行器 + * + * @param 返回值类型 + * @param 请求参数类型 + */ +public interface RequestExecutor { + + /** + * @param httpProxy http代理对象,如果没有配置代理则为空 + * @param uri uri + * @param data 数据 + * @throws WxErrorException + * @throws IOException + */ + T execute(ProxyInfo httpProxy, String uri, E data) throws WxErrorException, IOException; + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java new file mode 100644 index 0000000000..de84ad7bcb --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java @@ -0,0 +1,43 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.http.net.SocketHttpConnectionProvider; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.IOException; + +/** + * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String + * + * @author Daniel Qian + */ +public class SimpleGetRequestExecutor implements RequestExecutor { + + @Override + public String execute(ProxyInfo httpProxy, String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpRequest request = HttpRequest.get(uri); + if (httpProxy != null) { + SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); + provider.useProxy(httpProxy); + request.withConnectionProvider(provider); + } + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java new file mode 100644 index 0000000000..276b131099 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java @@ -0,0 +1,51 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.http.net.SocketHttpConnectionProvider; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.IOException; + +/** + * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String + * + * @author Daniel Qian + */ +public class SimplePostRequestExecutor implements RequestExecutor { + + @Override + public String execute(ProxyInfo httpProxy, String uri, String postEntity) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); + provider.useProxy(httpProxy); + request.withConnectionProvider(provider); + } + if (postEntity != null) { + request.bodyText(postEntity); + } + HttpResponse response = request.send(); + + String responseContent = response.bodyText(); + if (responseContent.isEmpty()) { + throw new WxErrorException( + WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") + .build()); + } + + if (responseContent.startsWith("")) { + //xml格式输出直接返回 + return responseContent; + } + + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java new file mode 100644 index 0000000000..ac293d7924 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java @@ -0,0 +1,48 @@ +package me.chanjar.weixin.common.util.http.jodd; + + +import org.apache.commons.lang3.StringUtils; + +import java.io.UnsupportedEncodingException; + +public class URIUtil { + + private static final String ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()"; + + public static String encodeURIComponent(String input) { + if (StringUtils.isEmpty(input)) { + return input; + } + + int l = input.length(); + StringBuilder o = new StringBuilder(l * 3); + try { + for (int i = 0; i < l; i++) { + String e = input.substring(i, i + 1); + if (ALLOWED_CHARS.indexOf(e) == -1) { + byte[] b = e.getBytes("utf-8"); + o.append(getHex(b)); + continue; + } + o.append(e); + } + return o.toString(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return input; + } + + private static String getHex(byte buf[]) { + StringBuilder o = new StringBuilder(buf.length * 3); + for (int i = 0; i < buf.length; i++) { + int n = buf[i] & 0xff; + o.append("%"); + if (n < 0x10) { + o.append("0"); + } + o.append(Long.toString(n, 16).toUpperCase()); + } + return o.toString(); + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/Utf8ResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/Utf8ResponseHandler.java new file mode 100644 index 0000000000..e26d3e3366 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/Utf8ResponseHandler.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import org.apache.http.Consts; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.ResponseHandler; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +/** + * copy from {@link org.apache.http.impl.client.BasicResponseHandler} + * + * @author Daniel Qian + */ +public class Utf8ResponseHandler implements ResponseHandler { + + public static final ResponseHandler INSTANCE = new Utf8ResponseHandler(); + + @Override + public String handleResponse(final HttpResponse response) throws IOException { + final StatusLine statusLine = response.getStatusLine(); + final HttpEntity entity = response.getEntity(); + if (statusLine.getStatusCode() >= 300) { + EntityUtils.consume(entity); + throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); + } + return entity == null ? null : EntityUtils.toString(entity, Consts.UTF_8); + } + +} From d476047c4cf2c1382965c1fe885dc36d4e779905 Mon Sep 17 00:00:00 2001 From: ecoolper Date: Fri, 21 Apr 2017 21:55:02 +0800 Subject: [PATCH 005/179] mp usage jodd-http --- .../weixin/mp/api/WxMpCardService.java | 10 +- .../weixin/mp/api/WxMpConfigStorage.java | 2 +- .../mp/api/WxMpInMemoryConfigStorage.java | 2 +- .../me/chanjar/weixin/mp/api/WxMpService.java | 32 +- .../weixin/mp/api/WxMpStoreService.java | 2 +- .../mp/api/impl/WxMpDeviceServiceImpl.java | 2 +- .../mp/api/impl/WxMpUserTagServiceImpl.java | 8 +- .../api/impl/apache/WxMpCardServiceImpl.java | 251 +++++++++ .../{ => apache}/WxMpKefuServiceImpl.java | 29 +- .../{ => apache}/WxMpMaterialServiceImpl.java | 12 +- .../impl/apache/WxMpQrcodeServiceImpl.java | 120 +++++ .../impl/{ => apache}/WxMpServiceImpl.java | 26 +- .../apache/WxMpUserBlacklistServiceImpl.java | 52 ++ .../impl/{ => jodd}/WxMpCardServiceImpl.java | 43 +- .../mp/api/impl/jodd/WxMpKefuServiceImpl.java | 183 +++++++ .../impl/jodd/WxMpMaterialServiceImpl.java | 165 ++++++ .../{ => jodd}/WxMpQrcodeServiceImpl.java | 8 +- .../mp/api/impl/jodd/WxMpServiceImpl.java | 510 ++++++++++++++++++ .../WxMpUserBlacklistServiceImpl.java | 8 +- .../MaterialDeleteRequestExecutor.java | 6 +- .../MaterialNewsInfoRequestExecutor.java | 6 +- .../MaterialUploadRequestExecutor.java | 10 +- .../MaterialVideoInfoRequestExecutor.java | 6 +- ...lVoiceAndImageDownloadRequestExecutor.java | 27 +- .../MediaImgUploadRequestExecutor.java | 6 +- .../{ => apache}/QrCodeRequestExecutor.java | 16 +- .../jodd/MaterialDeleteRequestExecutor.java | 39 ++ .../jodd/MaterialNewsInfoRequestExecutor.java | 41 ++ .../jodd/MaterialUploadRequestExecutor.java | 53 ++ .../MaterialVideoInfoRequestExecutor.java | 39 ++ ...lVoiceAndImageDownloadRequestExecutor.java | 57 ++ .../jodd/MediaImgUploadRequestExecutor.java | 42 ++ .../util/http/jodd/QrCodeRequestExecutor.java | 60 +++ .../weixin/mp/api/WxMpBusyRetryTest.java | 11 +- .../mp/api/impl/WxMpStoreServiceImplTest.java | 2 +- .../weixin/mp/api/test/ApiTestModule.java | 2 +- .../weixin/mp/demo/WxMpDemoServer.java | 2 +- 37 files changed, 1772 insertions(+), 118 deletions(-) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpCardServiceImpl.java rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{ => apache}/WxMpKefuServiceImpl.java (92%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{ => apache}/WxMpMaterialServiceImpl.java (94%) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpQrcodeServiceImpl.java rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{ => apache}/WxMpServiceImpl.java (93%) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpUserBlacklistServiceImpl.java rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{ => jodd}/WxMpCardServiceImpl.java (89%) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpKefuServiceImpl.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpMaterialServiceImpl.java rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{ => jodd}/WxMpQrcodeServiceImpl.java (94%) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{ => jodd}/WxMpUserBlacklistServiceImpl.java (87%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/{ => apache}/MaterialDeleteRequestExecutor.java (90%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/{ => apache}/MaterialNewsInfoRequestExecutor.java (91%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/{ => apache}/MaterialUploadRequestExecutor.java (89%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/{ => apache}/MaterialVideoInfoRequestExecutor.java (90%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/{ => apache}/MaterialVoiceAndImageDownloadRequestExecutor.java (92%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/{ => apache}/MediaImgUploadRequestExecutor.java (91%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/{ => apache}/QrCodeRequestExecutor.java (87%) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialDeleteRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialNewsInfoRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialUploadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVideoInfoRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVoiceAndImageDownloadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MediaImgUploadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/QrCodeRequestExecutor.java diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java index d4a36c65b8..362da84ef8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java @@ -6,9 +6,15 @@ /** * 卡券相关接口 - * @author YuJian(mgcnrx11@hotmail.com) on 01/11/2016 + * @author YuJian(mgcnrx11@hotmail.com) on 01/11/2016 */ -public interface WxMpCardService { +public interface WxMpCardService { + + /** + * 得到WxMpService + * @return + */ + WxMpService getWxMpService(); /** * 获得卡券api_ticket,不强制刷新卡券api_ticket diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java index f4053899ee..dbff2a7abe 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import java.io.File; import java.util.concurrent.locks.Lock; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java index 4bd1daec7e..9181a401e5 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java @@ -2,7 +2,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.ToStringUtils; -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import java.io.File; import java.util.concurrent.locks.Lock; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index cf1401a571..edaa72c12f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -3,14 +3,14 @@ import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.apache.MediaUploadRequestExecutor; import me.chanjar.weixin.mp.bean.*; import me.chanjar.weixin.mp.bean.result.*; -import org.apache.http.HttpHost; /** * 微信API的Service */ -public interface WxMpService { +public interface WxMpService { /** *
@@ -224,15 +224,18 @@ public interface WxMpService {
    * 
    * Service没有实现某个API的时候,可以用这个,
    * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
-   * 可以参考,{@link me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor}的实现方法
+   * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
    * 
*/ - T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; - /** - * 获取代理对象 - */ - HttpHost getHttpProxy(); + T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException; + + + /** + * 获取代理对象 + */ + //HttpHost getHttpProxy(); /** * 注入 {@link WxMpConfigStorage} 的实现 @@ -345,4 +348,17 @@ public interface WxMpService { * @return WxMpDeviceService */ WxMpDeviceService getDeviceService(); + + /** + * + * @return + */ + H getHttpclient(); + + /** + * + * @return + */ + P getHttpProxy(); + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java index c214c46d9e..38dde803a7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java @@ -12,7 +12,7 @@ * @author binarywang(Binary Wang) * Created by Binary Wang on 2016-09-23. */ -public interface WxMpStoreService { +public interface WxMpStoreService { /** *
    * 创建门店
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java
index 5c94236511..3f7378e3dd 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java
@@ -16,7 +16,7 @@ public class WxMpDeviceServiceImpl implements WxMpDeviceService {
 
   private WxMpService wxMpService;
 
-  WxMpDeviceServiceImpl(WxMpService wxMpService) {
+  public WxMpDeviceServiceImpl(WxMpService wxMpService) {
     this.wxMpService = wxMpService;
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java
index d1bdae1e2d..a1fee9370c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java
@@ -1,14 +1,9 @@
 package me.chanjar.weixin.mp.api.impl;
 
-import java.util.List;
-
-import org.apache.commons.lang3.StringUtils;
-
 import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
-
 import me.chanjar.weixin.common.bean.result.WxError;
 import me.chanjar.weixin.common.exception.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpService;
@@ -16,6 +11,9 @@
 import me.chanjar.weixin.mp.bean.tag.WxTagListUser;
 import me.chanjar.weixin.mp.bean.tag.WxUserTag;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
 
 /**
  *
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpCardServiceImpl.java
new file mode 100644
index 0000000000..e9d9c789c0
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpCardServiceImpl.java
@@ -0,0 +1,251 @@
+package me.chanjar.weixin.mp.api.impl.apache;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.reflect.TypeToken;
+import me.chanjar.weixin.common.bean.WxCardApiSignature;
+import me.chanjar.weixin.common.bean.result.WxError;
+import me.chanjar.weixin.common.exception.WxErrorException;
+import me.chanjar.weixin.common.util.RandomUtils;
+import me.chanjar.weixin.common.util.crypto.SHA1;
+import me.chanjar.weixin.common.util.http.apache.SimpleGetRequestExecutor;
+import me.chanjar.weixin.mp.api.WxMpCardService;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.result.WxMpCardResult;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.apache.http.HttpHost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Arrays;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * Created by Binary Wang on 2016/7/27.
+ */
+public class WxMpCardServiceImpl implements WxMpCardService {
+
+  private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class);
+
+  private WxMpService wxMpService;
+
+  public WxMpCardServiceImpl(WxMpService wxMpService) {
+    this.wxMpService = wxMpService;
+  }
+
+  /**
+   * 得到WxMpService
+   * @return
+   */
+  @Override
+  public WxMpService getWxMpService(){
+      return this.wxMpService;
+  }
+
+  /**
+   * 获得卡券api_ticket,不强制刷新卡券api_ticket
+   *
+   * @return 卡券api_ticket
+   * @see #getCardApiTicket(boolean)
+   */
+  @Override
+  public String getCardApiTicket() throws WxErrorException {
+    return getCardApiTicket(false);
+  }
+
+  /**
+   * 
+   * 获得卡券api_ticket
+   * 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
+   *
+   * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
+   * .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94
+   * .9F.E6.88.90.E7.AE.97.E6.B3.95
+   * 
+ * + * @param forceRefresh 强制刷新 + * @return 卡券api_ticket + */ + @Override + public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { + Lock lock = getWxMpService().getWxMpConfigStorage().getCardApiTicketLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.getWxMpService().getWxMpConfigStorage().expireCardApiTicket(); + } + + if (this.getWxMpService().getWxMpConfigStorage().isCardApiTicketExpired()) { + String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; + String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + this.getWxMpService().getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); + } + } finally { + lock.unlock(); + } + return this.getWxMpService().getWxMpConfigStorage().getCardApiTicket(); + } + + /** + *
+   * 创建调用卡券api时所需要的签名
+   *
+   * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
+   * .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94
+   * .9F.E6.88.90.E7.AE.97.E6.B3.95
+   * 
+ * + * @param optionalSignParam 参与签名的参数数组。 + * 可以为下列字段:app_id, card_id, card_type, code, openid, location_id + *
注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空 + * @return 卡券Api签名对象 + */ + @Override + public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws + WxErrorException { + long timestamp = System.currentTimeMillis() / 1000; + String nonceStr = RandomUtils.getRandomStr(); + String cardApiTicket = getCardApiTicket(false); + + String[] signParam = Arrays.copyOf(optionalSignParam, optionalSignParam.length + 3); + signParam[optionalSignParam.length] = String.valueOf(timestamp); + signParam[optionalSignParam.length + 1] = nonceStr; + signParam[optionalSignParam.length + 2] = cardApiTicket; + String signature = SHA1.gen(signParam); + WxCardApiSignature cardApiSignature = new WxCardApiSignature(); + cardApiSignature.setTimestamp(timestamp); + cardApiSignature.setNonceStr(nonceStr); + cardApiSignature.setSignature(signature); + return cardApiSignature; + } + + /** + * 卡券Code解码 + * + * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 + * @return 解密后的Code + */ + @Override + public String decryptCardCode(String encryptCode) throws WxErrorException { + String url = "https://api.weixin.qq.com/card/code/decrypt"; + JsonObject param = new JsonObject(); + param.addProperty("encrypt_code", encryptCode); + String responseContent = this.wxMpService.post(url, param.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + JsonPrimitive jsonPrimitive = tmpJsonObject.getAsJsonPrimitive("code"); + return jsonPrimitive.getAsString(); + } + + /** + * 卡券Code查询 + * + * @param cardId 卡券ID代表一类卡券 + * @param code 单张卡券的唯一标准 + * @param checkConsume 是否校验code核销状态,填入true和false时的code异常状态返回数据不同 + * @return WxMpCardResult对象 + */ + @Override + public WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) throws WxErrorException { + String url = "https://api.weixin.qq.com/card/code/get"; + JsonObject param = new JsonObject(); + param.addProperty("card_id", cardId); + param.addProperty("code", code); + param.addProperty("check_consume", checkConsume); + String responseContent = this.wxMpService.post(url, param.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, + new TypeToken() { + }.getType()); + } + + /** + * 卡券Code核销。核销失败会抛出异常 + * + * @param code 单张卡券的唯一标准 + * @return 调用返回的JSON字符串。 + *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + */ + @Override + public String consumeCardCode(String code) throws WxErrorException { + return consumeCardCode(code, null); + } + + /** + * 卡券Code核销。核销失败会抛出异常 + * + * @param code 单张卡券的唯一标准 + * @param cardId 当自定义Code卡券时需要传入card_id + * @return 调用返回的JSON字符串。 + *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + */ + @Override + public String consumeCardCode(String code, String cardId) throws WxErrorException { + String url = "https://api.weixin.qq.com/card/code/consume"; + JsonObject param = new JsonObject(); + param.addProperty("code", code); + + if (cardId != null && !"".equals(cardId)) { + param.addProperty("card_id", cardId); + } + + return this.wxMpService.post(url, param.toString()); + } + + /** + * 卡券Mark接口。 + * 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住), + * 才能进一步调用核销接口,否则报错。 + * + * @param code 卡券的code码 + * @param cardId 卡券的ID + * @param openId 用券用户的openid + * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 + */ + @Override + public void markCardCode(String code, String cardId, String openId, boolean isMark) throws + WxErrorException { + String url = "https://api.weixin.qq.com/card/code/mark"; + JsonObject param = new JsonObject(); + param.addProperty("code", code); + param.addProperty("card_id", cardId); + param.addProperty("openid", openId); + param.addProperty("is_mark", isMark); + String responseContent = this.getWxMpService().post(url, param.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + WxMpCardResult cardResult = WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, + new TypeToken() { }.getType()); + if (!cardResult.getErrorCode().equals("0")) { + this.log.warn("朋友的券mark失败:{}", cardResult.getErrorMsg()); + } + } + + @Override + public String getCardDetail(String cardId) throws WxErrorException { + String url = "https://api.weixin.qq.com/card/get"; + JsonObject param = new JsonObject(); + param.addProperty("card_id", cardId); + String responseContent = this.wxMpService.post(url, param.toString()); + + // 判断返回值 + JsonObject json = (new JsonParser()).parse(responseContent).getAsJsonObject(); + String errcode = json.get("errcode").getAsString(); + if (!"0".equals(errcode)) { + String errmsg = json.get("errmsg").getAsString(); + WxError error = new WxError(); + error.setErrorCode(Integer.valueOf(errcode)); + error.setErrorMsg(errmsg); + throw new WxErrorException(error); + } + + return responseContent; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpKefuServiceImpl.java similarity index 92% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpKefuServiceImpl.java index 09a68adf89..0dc921f140 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpKefuServiceImpl.java @@ -1,28 +1,23 @@ -package me.chanjar.weixin.mp.api.impl; - -import java.io.File; -import java.util.Date; - -import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +package me.chanjar.weixin.mp.api.impl.apache; import com.google.gson.JsonObject; - import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.apache.MediaUploadRequestExecutor; import me.chanjar.weixin.mp.api.WxMpKefuService; import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfSessionRequest; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfMsgList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionGetResult; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList; +import me.chanjar.weixin.mp.bean.kefu.result.*; +import org.apache.http.HttpHost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Date; /** * @@ -34,7 +29,7 @@ public class WxMpKefuServiceImpl implements WxMpKefuService { .getLogger(WxMpKefuServiceImpl.class); private static final String API_URL_PREFIX = "https://api.weixin.qq.com/customservice"; private static final String API_URL_PREFIX_WITH_CGI_BIN = "https://api.weixin.qq.com/cgi-bin/customservice"; - private WxMpService wxMpService; + private WxMpService wxMpService; public WxMpKefuServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpMaterialServiceImpl.java similarity index 94% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpMaterialServiceImpl.java index af9fa54c35..13d5a754dc 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpMaterialServiceImpl.java @@ -1,12 +1,12 @@ -package me.chanjar.weixin.mp.api.impl; +package me.chanjar.weixin.mp.api.impl.apache; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; -import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.apache.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.apache.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.api.WxMpMaterialService; import me.chanjar.weixin.mp.api.WxMpService; @@ -14,8 +14,10 @@ import me.chanjar.weixin.mp.bean.material.WxMpMaterialArticleUpdate; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; import me.chanjar.weixin.mp.bean.material.*; -import me.chanjar.weixin.mp.util.http.*; +import me.chanjar.weixin.mp.util.http.apache.*; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.apache.http.HttpHost; +import org.apache.http.impl.client.CloseableHttpClient; import java.io.File; import java.io.IOException; @@ -30,7 +32,7 @@ public class WxMpMaterialServiceImpl implements WxMpMaterialService { private static final String MEDIA_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/media"; private static final String MATERIAL_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/material"; - private WxMpService wxMpService; + private WxMpService wxMpService; public WxMpMaterialServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpQrcodeServiceImpl.java new file mode 100644 index 0000000000..5db81fe1bb --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpQrcodeServiceImpl.java @@ -0,0 +1,120 @@ +package me.chanjar.weixin.mp.api.impl.apache; + +import com.google.gson.JsonObject; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpQrcodeService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import me.chanjar.weixin.mp.util.http.apache.QrCodeRequestExecutor; +import org.apache.http.HttpHost; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * Created by Binary Wang on 2016/7/21. + */ +public class WxMpQrcodeServiceImpl implements WxMpQrcodeService { + private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/qrcode"; + private WxMpService wxMpService; + + public WxMpQrcodeServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override + public WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds) throws WxErrorException { + if (sceneId == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("临时二维码场景值不能为0!").build()); + } + + //expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。 + if (expireSeconds != null && expireSeconds > 2592000) { + throw new WxErrorException(WxError.newBuilder().setErrorCode(-1) + .setErrorMsg("临时二维码有效时间最大不能超过2592000(即30天)!").build()); + } + + if (expireSeconds == null) { + expireSeconds = 30; + } + + String url = API_URL_PREFIX + "/create"; + JsonObject json = new JsonObject(); + json.addProperty("action_name", "QR_SCENE"); + json.addProperty("expire_seconds", expireSeconds); + + JsonObject actionInfo = new JsonObject(); + JsonObject scene = new JsonObject(); + scene.addProperty("scene_id", sceneId); + actionInfo.add("scene", scene); + json.add("action_info", actionInfo); + String responseContent = this.wxMpService.post(url, json.toString()); + return WxMpQrCodeTicket.fromJson(responseContent); + } + + @Override + public WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorException { + if (sceneId < 1 || sceneId > 100000) { + throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("永久二维码的场景值目前只支持1--100000!").build()); + } + + String url = API_URL_PREFIX + "/create"; + JsonObject json = new JsonObject(); + json.addProperty("action_name", "QR_LIMIT_SCENE"); + JsonObject actionInfo = new JsonObject(); + JsonObject scene = new JsonObject(); + scene.addProperty("scene_id", sceneId); + actionInfo.add("scene", scene); + json.add("action_info", actionInfo); + String responseContent = this.wxMpService.post(url, json.toString()); + return WxMpQrCodeTicket.fromJson(responseContent); + } + + @Override + public WxMpQrCodeTicket qrCodeCreateLastTicket(String sceneStr) throws WxErrorException { + String url = API_URL_PREFIX + "/create"; + JsonObject json = new JsonObject(); + json.addProperty("action_name", "QR_LIMIT_STR_SCENE"); + JsonObject actionInfo = new JsonObject(); + JsonObject scene = new JsonObject(); + scene.addProperty("scene_str", sceneStr); + actionInfo.add("scene", scene); + json.add("action_info", actionInfo); + String responseContent = this.wxMpService.post(url, json.toString()); + return WxMpQrCodeTicket.fromJson(responseContent); + } + + @Override + public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException { + String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode"; + return this.wxMpService.execute(new QrCodeRequestExecutor(), url, ticket); + } + + @Override + public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException { + String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s"; + try { + String resultUrl = String.format(url, + URLEncoder.encode(ticket, StandardCharsets.UTF_8.name())); + if (needShortUrl) { + return this.wxMpService.shortUrl(resultUrl); + } + + return resultUrl; + } catch (UnsupportedEncodingException e) { + WxError error = WxError.newBuilder().setErrorCode(-1) + .setErrorMsg(e.getMessage()).build(); + throw new WxErrorException(error); + } + } + + @Override + public String qrCodePictureUrl(String ticket) throws WxErrorException { + return qrCodePictureUrl(ticket, false); + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java similarity index 93% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java index 406e871267..75a6bd9616 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.mp.api.impl; +package me.chanjar.weixin.mp.api.impl.apache; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -12,8 +12,14 @@ import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.http.*; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.URIUtil; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.apache.SimplePostRequestExecutor; import me.chanjar.weixin.mp.api.*; +import me.chanjar.weixin.mp.api.impl.*; import me.chanjar.weixin.mp.bean.*; import me.chanjar.weixin.mp.bean.result.*; import org.apache.http.HttpHost; @@ -28,7 +34,7 @@ import java.io.IOException; import java.util.concurrent.locks.Lock; -public class WxMpServiceImpl implements WxMpService { +public class WxMpServiceImpl implements WxMpService { private static final JsonParser JSON_PARSER = new JsonParser(); @@ -242,7 +248,7 @@ public String buildQrConnectUrl(String redirectURI, String scope, private WxMpOAuth2AccessToken getOAuth2AccessToken(StringBuilder url) throws WxErrorException { try { - RequestExecutor executor = new SimpleGetRequestExecutor(); + RequestExecutor executor = new SimpleGetRequestExecutor(); String responseText = executor.execute(this.getHttpclient(), this.httpProxy, url.toString(), null); return WxMpOAuth2AccessToken.fromJson(responseText); } catch (IOException e) { @@ -286,7 +292,7 @@ public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, Strin } try { - RequestExecutor executor = new SimpleGetRequestExecutor(); + RequestExecutor executor = new SimpleGetRequestExecutor(); String responseText = executor.execute(getHttpclient(), this.httpProxy, url.toString(), null); return WxMpUser.fromJson(responseText); } catch (IOException e) { @@ -302,7 +308,7 @@ public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken url.append("&openid=").append(oAuth2AccessToken.getOpenId()); try { - RequestExecutor executor = new SimpleGetRequestExecutor(); + RequestExecutor executor = new SimpleGetRequestExecutor(); executor.execute(getHttpclient(), this.httpProxy, url.toString(), null); } catch (IOException e) { throw new RuntimeException(e); @@ -339,7 +345,7 @@ public String post(String url, String postData) throws WxErrorException { * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 */ @Override - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { int retryTimes = 0; do { try { @@ -373,7 +379,8 @@ public T execute(RequestExecutor executor, String uri, E data) thro throw new RuntimeException("微信服务端异常,超出重试次数"); } - protected synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + @Override + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { if (uri.indexOf("access_token=") != -1) { throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); } @@ -383,7 +390,7 @@ protected synchronized T executeInternal(RequestExecutor executor, uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; try { - return executor.execute(getHttpclient(), this.httpProxy, uriWithAccessToken, data); + return executor.execute(getHttpclient(), getHttpProxy(), uriWithAccessToken, data); } catch (WxErrorException e) { WxError error = e.getError(); /* @@ -415,6 +422,7 @@ public HttpHost getHttpProxy() { return this.httpProxy; } + @Override public CloseableHttpClient getHttpclient() { return this.httpClient; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpUserBlacklistServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpUserBlacklistServiceImpl.java new file mode 100644 index 0000000000..bf99b5fb6f --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpUserBlacklistServiceImpl.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.mp.api.impl.apache; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.apache.SimplePostRequestExecutor; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.WxMpUserBlacklistService; +import me.chanjar.weixin.mp.bean.result.WxMpUserBlacklistGetResult; +import org.apache.http.HttpHost; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author miller + */ +public class WxMpUserBlacklistServiceImpl implements WxMpUserBlacklistService { + private static final String API_BLACKLIST_PREFIX = "https://api.weixin.qq.com/cgi-bin/tags/members"; + private WxMpService wxMpService; + + public WxMpUserBlacklistServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override + public WxMpUserBlacklistGetResult getBlacklist(String nextOpenid) throws WxErrorException { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("begin_openid", nextOpenid); + String url = API_BLACKLIST_PREFIX + "/getblacklist"; + String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, jsonObject.toString()); + return WxMpUserBlacklistGetResult.fromJson(responseContent); + } + + @Override + public void pushToBlacklist(List openidList) throws WxErrorException { + Map map = new HashMap<>(); + map.put("openid_list", openidList); + String url = API_BLACKLIST_PREFIX + "/batchblacklist"; + this.wxMpService.execute(new SimplePostRequestExecutor(), url, new Gson().toJson(map)); + } + + @Override + public void pullFromBlacklist(List openidList) throws WxErrorException { + Map map = new HashMap<>(); + map.put("openid_list", openidList); + String url = API_BLACKLIST_PREFIX + "/batchunblacklist"; + this.wxMpService.execute(new SimplePostRequestExecutor(), url, new Gson().toJson(map)); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpCardServiceImpl.java similarity index 89% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpCardServiceImpl.java index 2e6bf88e50..0789b7eaf4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpCardServiceImpl.java @@ -1,41 +1,50 @@ -package me.chanjar.weixin.mp.api.impl; - -import java.util.Arrays; -import java.util.concurrent.locks.Lock; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +package me.chanjar.weixin.mp.api.impl.jodd; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import com.google.gson.reflect.TypeToken; - +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.jodd.SimpleGetRequestExecutor; import me.chanjar.weixin.mp.api.WxMpCardService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.result.WxMpCardResult; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.concurrent.locks.Lock; /** * Created by Binary Wang on 2016/7/27. */ -public class WxMpCardServiceImpl implements WxMpCardService { +public class WxMpCardServiceImpl implements WxMpCardService { private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class); - private WxMpService wxMpService; + private WxMpService wxMpService; public WxMpCardServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; } + /** + * 得到WxMpService + * @return + */ + @Override + public WxMpService getWxMpService(){ + return this.wxMpService; + } + /** * 获得卡券api_ticket,不强制刷新卡券api_ticket * @@ -62,27 +71,27 @@ public String getCardApiTicket() throws WxErrorException { */ @Override public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { - Lock lock = wxMpService.getWxMpConfigStorage().getCardApiTicketLock(); + Lock lock = getWxMpService().getWxMpConfigStorage().getCardApiTicketLock(); try { lock.lock(); if (forceRefresh) { - this.wxMpService.getWxMpConfigStorage().expireCardApiTicket(); + this.getWxMpService().getWxMpConfigStorage().expireCardApiTicket(); } - if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) { + if (this.getWxMpService().getWxMpConfigStorage().isCardApiTicketExpired()) { String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); + this.getWxMpService().getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); } } finally { lock.unlock(); } - return this.wxMpService.getWxMpConfigStorage().getCardApiTicket(); + return this.getWxMpService().getWxMpConfigStorage().getCardApiTicket(); } /** @@ -210,7 +219,7 @@ public void markCardCode(String code, String cardId, String openId, boolean isMa param.addProperty("card_id", cardId); param.addProperty("openid", openId); param.addProperty("is_mark", isMark); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.getWxMpService().post(url, param.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); WxMpCardResult cardResult = WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, new TypeToken() { }.getType()); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpKefuServiceImpl.java new file mode 100644 index 0000000000..9e7685b5a0 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpKefuServiceImpl.java @@ -0,0 +1,183 @@ +package me.chanjar.weixin.mp.api.impl.jodd; + +import com.google.gson.JsonObject; +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.jodd.MediaUploadRequestExecutor; +import me.chanjar.weixin.mp.api.WxMpKefuService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; +import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; +import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfSessionRequest; +import me.chanjar.weixin.mp.bean.kefu.result.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Date; + +/** + * + * @author Binary Wang + * + */ +public class WxMpKefuServiceImpl implements WxMpKefuService { + protected final Logger log = LoggerFactory + .getLogger(WxMpKefuServiceImpl.class); + private static final String API_URL_PREFIX = "https://api.weixin.qq.com/customservice"; + private static final String API_URL_PREFIX_WITH_CGI_BIN = "https://api.weixin.qq.com/cgi-bin/customservice"; + private WxMpService wxMpService; + + public WxMpKefuServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override + public boolean sendKefuMessage(WxMpKefuMessage message) + throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; + String responseContent = this.wxMpService.post(url, message.toJson()); + return responseContent != null; + } + + @Override + public WxMpKfList kfList() throws WxErrorException { + String url = API_URL_PREFIX_WITH_CGI_BIN + "/getkflist"; + String responseContent = this.wxMpService.get(url, null); + return WxMpKfList.fromJson(responseContent); + } + + @Override + public WxMpKfOnlineList kfOnlineList() throws WxErrorException { + String url = API_URL_PREFIX_WITH_CGI_BIN + "/getonlinekflist"; + String responseContent = this.wxMpService.get(url, null); + return WxMpKfOnlineList.fromJson(responseContent); + } + + @Override + public boolean kfAccountAdd(WxMpKfAccountRequest request) + throws WxErrorException { + String url = API_URL_PREFIX + "/kfaccount/add"; + String responseContent = this.wxMpService.post(url, request.toJson()); + return responseContent != null; + } + + @Override + public boolean kfAccountUpdate(WxMpKfAccountRequest request) + throws WxErrorException { + String url = API_URL_PREFIX + "/kfaccount/update"; + String responseContent = this.wxMpService.post(url, request.toJson()); + return responseContent != null; + } + + @Override + public boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErrorException { + String url = API_URL_PREFIX + "/kfaccount/inviteworker"; + String responseContent = this.wxMpService.post(url, request.toJson()); + return responseContent != null; + } + + @Override + public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) + throws WxErrorException { + String url = API_URL_PREFIX + "/kfaccount/uploadheadimg?kf_account=" + kfAccount; + WxMediaUploadResult responseContent = this.wxMpService + .execute(new MediaUploadRequestExecutor(), url, imgFile); + return responseContent != null; + } + + @Override + public boolean kfAccountDel(String kfAccount) throws WxErrorException { + String url = API_URL_PREFIX + "/kfaccount/del?kf_account=" + kfAccount; + String responseContent = this.wxMpService.get(url, null); + return responseContent != null; + } + + @Override + public boolean kfSessionCreate(String openid, String kfAccount) + throws WxErrorException { + WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid); + String url = API_URL_PREFIX + "/kfsession/create"; + String responseContent = this.wxMpService.post(url, request.toJson()); + return responseContent != null; + } + + @Override + public boolean kfSessionClose(String openid, String kfAccount) + throws WxErrorException { + WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid); + String url = API_URL_PREFIX + "/kfsession/close"; + String responseContent = this.wxMpService.post(url, request.toJson()); + return responseContent != null; + } + + @Override + public WxMpKfSessionGetResult kfSessionGet(String openid) + throws WxErrorException { + String url = API_URL_PREFIX + "/kfsession/getsession?openid=" + openid; + String responseContent = this.wxMpService.get(url, null); + return WxMpKfSessionGetResult.fromJson(responseContent); + } + + @Override + public WxMpKfSessionList kfSessionList(String kfAccount) + throws WxErrorException { + String url = API_URL_PREFIX + "/kfsession/getsessionlist?kf_account=" + kfAccount; + String responseContent = this.wxMpService.get(url, null); + return WxMpKfSessionList.fromJson(responseContent); + } + + @Override + public WxMpKfSessionWaitCaseList kfSessionGetWaitCase() + throws WxErrorException { + String url = API_URL_PREFIX + "/kfsession/getwaitcase"; + String responseContent = this.wxMpService.get(url, null); + return WxMpKfSessionWaitCaseList.fromJson(responseContent); + } + + @Override + public WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer number) throws WxErrorException { + if(number > 10000){ + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法参数请求,每次最多查询10000条记录!").build()); + } + + if(startTime.after(endTime)){ + throw new WxErrorException(WxError.newBuilder().setErrorMsg("起始时间不能晚于结束时间!").build()); + } + + String url = API_URL_PREFIX + "/msgrecord/getmsglist"; + + JsonObject param = new JsonObject(); + param.addProperty("starttime", startTime.getTime() / 1000); //starttime 起始时间,unix时间戳 + param.addProperty("endtime", endTime.getTime() / 1000); //endtime 结束时间,unix时间戳,每次查询时段不能超过24小时 + param.addProperty("msgid", msgId); //msgid 消息id顺序从小到大,从1开始 + param.addProperty("number", number); //number 每次获取条数,最多10000条 + + String responseContent = this.wxMpService.post(url, param.toString()); + + return WxMpKfMsgList.fromJson(responseContent); + } + + @Override + public WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorException { + int number = 10000; + WxMpKfMsgList result = this.kfMsgList(startTime,endTime, 1L, number); + + if(result != null && result.getNumber() == number){ + Long msgId = result.getMsgId(); + WxMpKfMsgList followingResult = this.kfMsgList(startTime,endTime, msgId, number); + while(followingResult != null && followingResult.getRecords().size() > 0){ + result.getRecords().addAll(followingResult.getRecords()); + result.setNumber(result.getNumber() + followingResult.getNumber()); + result.setMsgId(followingResult.getMsgId()); + followingResult = this.kfMsgList(startTime,endTime, followingResult.getMsgId(), number); + } + } + + return result; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpMaterialServiceImpl.java new file mode 100644 index 0000000000..f6c48f9af7 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpMaterialServiceImpl.java @@ -0,0 +1,165 @@ +package me.chanjar.weixin.mp.api.impl.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.jodd.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.jodd.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.api.WxMpMaterialService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.material.*; +import me.chanjar.weixin.mp.util.http.jodd.*; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * Created by Binary Wang on 2016/7/21. + */ +public class WxMpMaterialServiceImpl implements WxMpMaterialService { + private static final String MEDIA_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/media"; + private static final String MATERIAL_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/material"; + private WxMpService wxMpService; + + public WxMpMaterialServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override + public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException { + try { + return this.mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); + } catch (IOException e) { + e.printStackTrace(); + throw new WxErrorException(WxError.newBuilder().setErrorMsg(e.getMessage()).build()); + } + } + + @Override + public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { + String url = MEDIA_API_URL_PREFIX + "/upload?type=" + mediaType; + return this.wxMpService.execute(new MediaUploadRequestExecutor(), url, file); + } + + @Override + public File mediaDownload(String media_id) throws WxErrorException { + String url = MEDIA_API_URL_PREFIX + "/get"; + return this.wxMpService.execute( + new MediaDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), + url, + "media_id=" + media_id); + } + + @Override + public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException { + String url = MEDIA_API_URL_PREFIX + "/uploadimg"; + return this.wxMpService.execute(new MediaImgUploadRequestExecutor(), url, file); + } + + @Override + public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/add_material?type=" + mediaType; + return this.wxMpService.execute(new MaterialUploadRequestExecutor(), url, material); + } + + @Override + public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException { + if (news == null || news.isEmpty()) { + throw new IllegalArgumentException("news is empty!"); + } + String url = MATERIAL_API_URL_PREFIX + "/add_news"; + String responseContent = this.wxMpService.post(url, news.toJson()); + return WxMpMaterialUploadResult.fromJson(responseContent); + } + + @Override + public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/get_material"; + return this.wxMpService.execute(new MaterialVoiceAndImageDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, media_id); + } + + @Override + public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/get_material"; + return this.wxMpService.execute(new MaterialVideoInfoRequestExecutor(), url, media_id); + } + + @Override + public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/get_material"; + return this.wxMpService.execute(new MaterialNewsInfoRequestExecutor(), url, media_id); + } + + @Override + public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/update_news"; + String responseText = this.wxMpService.post(url, wxMpMaterialArticleUpdate.toJson()); + WxError wxError = WxError.fromJson(responseText); + if (wxError.getErrorCode() == 0) { + return true; + } else { + throw new WxErrorException(wxError); + } + } + + @Override + public boolean materialDelete(String media_id) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/del_material"; + return this.wxMpService.execute(new MaterialDeleteRequestExecutor(), url, media_id); + } + + @Override + public WxMpMaterialCountResult materialCount() throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/get_materialcount"; + String responseText = this.wxMpService.get(url, null); + WxError wxError = WxError.fromJson(responseText); + if (wxError.getErrorCode() == 0) { + return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialCountResult.class); + } else { + throw new WxErrorException(wxError); + } + } + + @Override + public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/batchget_material"; + Map params = new HashMap<>(); + params.put("type", WxConsts.MATERIAL_NEWS); + params.put("offset", offset); + params.put("count", count); + String responseText = this.wxMpService.post(url, WxGsonBuilder.create().toJson(params)); + WxError wxError = WxError.fromJson(responseText); + if (wxError.getErrorCode() == 0) { + return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialNewsBatchGetResult.class); + } else { + throw new WxErrorException(wxError); + } + } + + @Override + public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException { + String url = MATERIAL_API_URL_PREFIX + "/batchget_material"; + Map params = new HashMap<>(); + params.put("type", type); + params.put("offset", offset); + params.put("count", count); + String responseText = this.wxMpService.post(url, WxGsonBuilder.create().toJson(params)); + WxError wxError = WxError.fromJson(responseText); + if (wxError.getErrorCode() == 0) { + return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialFileBatchGetResult.class); + } else { + throw new WxErrorException(wxError); + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpQrcodeServiceImpl.java similarity index 94% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpQrcodeServiceImpl.java index 8659f2af9d..fba822b3f9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpQrcodeServiceImpl.java @@ -1,12 +1,14 @@ -package me.chanjar.weixin.mp.api.impl; +package me.chanjar.weixin.mp.api.impl.jodd; import com.google.gson.JsonObject; +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.mp.api.WxMpQrcodeService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; -import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.QrCodeRequestExecutor; import java.io.File; import java.io.UnsupportedEncodingException; @@ -18,7 +20,7 @@ */ public class WxMpQrcodeServiceImpl implements WxMpQrcodeService { private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/qrcode"; - private WxMpService wxMpService; + private WxMpService wxMpService; public WxMpQrcodeServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java new file mode 100644 index 0000000000..1480270ca3 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java @@ -0,0 +1,510 @@ +package me.chanjar.weixin.mp.api.impl.jodd; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import jodd.http.*; +import jodd.http.net.SocketHttpConnectionProvider; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.StandardSessionManager; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.RandomUtils; +import me.chanjar.weixin.common.util.crypto.SHA1; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.URIUtil; +import me.chanjar.weixin.common.util.http.jodd.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.jodd.SimplePostRequestExecutor; +import me.chanjar.weixin.mp.api.*; +import me.chanjar.weixin.mp.api.impl.*; +import me.chanjar.weixin.mp.bean.*; +import me.chanjar.weixin.mp.bean.result.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.concurrent.locks.Lock; + +public class WxMpServiceImpl implements WxMpService { + + private static final JsonParser JSON_PARSER = new JsonParser(); + + protected final Logger log = LoggerFactory.getLogger(this.getClass()); + protected WxSessionManager sessionManager = new StandardSessionManager(); + private WxMpConfigStorage wxMpConfigStorage; + private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); + private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); + private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); + private WxMpUserService userService = new WxMpUserServiceImpl(this); + private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this); + private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); + private WxMpCardService cardService = new WxMpCardServiceImpl(this); + private WxMpStoreService storeService = new WxMpStoreServiceImpl(this); + private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this); + private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this); + private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); + private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); + + private HttpConnectionProvider httpClient; + private ProxyInfo httpProxy; + private int retrySleepMillis = 1000; + private int maxRetryTimes = 5; + + private void initHttpClient() { + WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + } + + httpClient = JoddHttp.httpConnectionProvider; + } + + @Override + public boolean checkSignature(String timestamp, String nonce, String signature) { + try { + return SHA1.gen(this.getWxMpConfigStorage().getToken(), timestamp, nonce) + .equals(signature); + } catch (Exception e) { + return false; + } + } + + @Override + public String getAccessToken() throws WxErrorException { + return getAccessToken(false); + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.getWxMpConfigStorage().expireAccessToken(); + } + + if (this.getWxMpConfigStorage().isAccessTokenExpired()) { + String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + + "&appid=" + this.getWxMpConfigStorage().getAppId() + "&secret=" + + this.getWxMpConfigStorage().getSecret(); + + HttpRequest request = HttpRequest.get(url); + if (this.httpProxy != null) { + SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); + provider.useProxy(httpProxy); + request.withConnectionProvider(provider); + } + HttpResponse response = request.send(); + String resultContent = response.bodyText(); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), + accessToken.getExpiresIn()); + } + } finally { + lock.unlock(); + } + return this.getWxMpConfigStorage().getAccessToken(); + } + + @Override + public String getJsapiTicket() throws WxErrorException { + return getJsapiTicket(false); + } + + @Override + public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMpConfigStorage().getJsapiTicketLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.getWxMpConfigStorage().expireJsapiTicket(); + } + + if (this.getWxMpConfigStorage().isJsapiTicketExpired()) { + String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; + String responseContent = execute(new SimpleGetRequestExecutor(), url, null); + JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + this.getWxMpConfigStorage().updateJsapiTicket(jsapiTicket, expiresInSeconds); + } + } finally { + lock.unlock(); + } + return this.getWxMpConfigStorage().getJsapiTicket(); + } + + @Override + public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { + long timestamp = System.currentTimeMillis() / 1000; + String noncestr = RandomUtils.getRandomStr(); + String jsapiTicket = getJsapiTicket(false); + String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket, + "noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url); + WxJsapiSignature jsapiSignature = new WxJsapiSignature(); + jsapiSignature.setAppId(this.getWxMpConfigStorage().getAppId()); + jsapiSignature.setTimestamp(timestamp); + jsapiSignature.setNonceStr(noncestr); + jsapiSignature.setUrl(url); + jsapiSignature.setSignature(signature); + return jsapiSignature; + } + + @Override + public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; + String responseContent = this.post(url, news.toJson()); + return WxMpMassUploadResult.fromJson(responseContent); + } + + @Override + public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; + String responseContent = this.post(url, video.toJson()); + return WxMpMassUploadResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; + String responseContent = this.post(url, message.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; + String responseContent = this.post(url, message.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception { + String url = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; + String responseContent = this.post(url, wxMpMassPreviewMessage.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + + @Override + public String shortUrl(String long_url) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/shorturl"; + JsonObject o = new JsonObject(); + o.addProperty("action", "long2short"); + o.addProperty("long_url", long_url); + String responseContent = this.post(url, o.toString()); + JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("short_url").getAsString(); + } + + @Override + public WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException { + String url = "https://api.weixin.qq.com/semantic/semproxy/search"; + String responseContent = this.post(url, semanticQuery.toJson()); + return WxMpSemanticQueryResult.fromJson(responseContent); + } + + @Override + public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { + StringBuilder url = new StringBuilder(); + url.append("https://open.weixin.qq.com/connect/oauth2/authorize?"); + url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); + url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); + url.append("&response_type=code"); + url.append("&scope=").append(scope); + if (state != null) { + url.append("&state=").append(state); + } + url.append("#wechat_redirect"); + return url.toString(); + } + + @Override + public String buildQrConnectUrl(String redirectURI, String scope, + String state) { + StringBuilder url = new StringBuilder(); + url.append("https://open.weixin.qq.com/connect/qrconnect?"); + url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); + url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); + url.append("&response_type=code"); + url.append("&scope=").append(scope); + if (state != null) { + url.append("&state=").append(state); + } + + url.append("#wechat_redirect"); + return url.toString(); + } + + private WxMpOAuth2AccessToken getOAuth2AccessToken(StringBuilder url) throws WxErrorException { + try { + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(getHttpclient(), getHttpProxy(), url.toString(), null); + return WxMpOAuth2AccessToken.fromJson(responseText); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { + StringBuilder url = new StringBuilder(); + url.append("https://api.weixin.qq.com/sns/oauth2/access_token?"); + url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); + url.append("&secret=").append(this.getWxMpConfigStorage().getSecret()); + url.append("&code=").append(code); + url.append("&grant_type=authorization_code"); + + return this.getOAuth2AccessToken(url); + } + + @Override + public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { + StringBuilder url = new StringBuilder(); + url.append("https://api.weixin.qq.com/sns/oauth2/refresh_token?"); + url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); + url.append("&grant_type=refresh_token"); + url.append("&refresh_token=").append(refreshToken); + + return this.getOAuth2AccessToken(url); + } + + @Override + public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { + StringBuilder url = new StringBuilder(); + url.append("https://api.weixin.qq.com/sns/userinfo?"); + url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); + url.append("&openid=").append(oAuth2AccessToken.getOpenId()); + if (lang == null) { + url.append("&lang=zh_CN"); + } else { + url.append("&lang=").append(lang); + } + + try { + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(getHttpclient(), getHttpProxy(), url.toString(), null); + return WxMpUser.fromJson(responseText); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { + StringBuilder url = new StringBuilder(); + url.append("https://api.weixin.qq.com/sns/auth?"); + url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); + url.append("&openid=").append(oAuth2AccessToken.getOpenId()); + + try { + RequestExecutor executor = new SimpleGetRequestExecutor(); + executor.execute(getHttpclient(), getHttpProxy(), url.toString(), null); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (WxErrorException e) { + return false; + } + return true; + } + + @Override + public String[] getCallbackIP() throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/getcallbackip"; + String responseContent = get(url, null); + JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); + JsonArray ipList = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); + String[] ipArray = new String[ipList.size()]; + for (int i = 0; i < ipList.size(); i++) { + ipArray[i] = ipList.get(i).getAsString(); + } + return ipArray; + } + + @Override + public String get(String url, String queryParam) throws WxErrorException { + return execute(new SimpleGetRequestExecutor(), url, queryParam); + } + + @Override + public String post(String url, String postData) throws WxErrorException { + return execute(new SimplePostRequestExecutor(), url, postData); + } + + @Override + public HttpConnectionProvider getHttpclient() { + return this.httpClient; + } + + /** + * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 + */ + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + int retryTimes = 0; + do { + try { + T result = executeInternal(executor, uri, data); + this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, result); + return result; + } catch (WxErrorException e) { + if (retryTimes + 1 > this.maxRetryTimes) { + this.log.warn("重试达到最大次数【{}】", maxRetryTimes); + //最后一次重试失败后,直接抛出异常,不再等待 + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + WxError error = e.getError(); + // -1 系统繁忙, 1000ms后重试 + if (error.getErrorCode() == -1) { + int sleepMillis = this.retrySleepMillis * (1 << retryTimes); + try { + this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + Thread.sleep(sleepMillis); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + } else { + throw e; + } + } + } while (retryTimes++ < this.maxRetryTimes); + + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + @Override + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + if (uri.indexOf("access_token=") != -1) { + throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); + } + String accessToken = getAccessToken(false); + + String uriWithAccessToken = uri; + uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; + + try { + return executor.execute(getHttpclient(), getHttpProxy(), uriWithAccessToken, data); + } catch (WxErrorException e) { + WxError error = e.getError(); + /* + * 发生以下情况时尝试刷新access_token + * 40001 获取access_token时AppSecret错误,或者access_token无效 + * 42001 access_token超时 + */ + if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { + // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token + this.getWxMpConfigStorage().expireAccessToken(); + if (this.getWxMpConfigStorage().autoRefreshToken()) { + return this.execute(executor, uri, data); + } + } + + if (error.getErrorCode() != 0) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); + throw new WxErrorException(error); + } + return null; + } catch (IOException e) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); + throw new RuntimeException(e); + } + } + + @Override + public ProxyInfo getHttpProxy() { + return this.httpProxy; + } + + + @Override + public WxMpConfigStorage getWxMpConfigStorage() { + return this.wxMpConfigStorage; + } + + @Override + public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { + this.wxMpConfigStorage = wxConfigProvider; + this.initHttpClient(); + } + + @Override + public void setRetrySleepMillis(int retrySleepMillis) { + this.retrySleepMillis = retrySleepMillis; + } + + @Override + public void setMaxRetryTimes(int maxRetryTimes) { + this.maxRetryTimes = maxRetryTimes; + } + + @Override + public WxMpKefuService getKefuService() { + return this.kefuService; + } + + @Override + public WxMpMaterialService getMaterialService() { + return this.materialService; + } + + @Override + public WxMpMenuService getMenuService() { + return this.menuService; + } + + @Override + public WxMpUserService getUserService() { + return this.userService; + } + + @Override + public WxMpUserTagService getUserTagService() { + return this.tagService; + } + + @Override + public WxMpQrcodeService getQrcodeService() { + return this.qrCodeService; + } + + @Override + public WxMpCardService getCardService() { + return this.cardService; + } + + @Override + public WxMpDataCubeService getDataCubeService() { + return this.dataCubeService; + } + + @Override + public WxMpUserBlacklistService getBlackListService() { + return this.blackListService; + } + + @Override + public WxMpStoreService getStoreService() { + return this.storeService; + } + + @Override + public WxMpTemplateMsgService getTemplateMsgService() { + return this.templateMsgService; + } + + @Override + public WxMpDeviceService getDeviceService() { + return this.deviceService; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpUserBlacklistServiceImpl.java similarity index 87% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpUserBlacklistServiceImpl.java index b0b35343e8..f310b3d48f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpUserBlacklistServiceImpl.java @@ -1,9 +1,11 @@ -package me.chanjar.weixin.mp.api.impl; +package me.chanjar.weixin.mp.api.impl.jodd; import com.google.gson.Gson; import com.google.gson.JsonObject; +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import me.chanjar.weixin.common.util.http.jodd.SimplePostRequestExecutor; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpUserBlacklistService; import me.chanjar.weixin.mp.bean.result.WxMpUserBlacklistGetResult; @@ -17,7 +19,7 @@ */ public class WxMpUserBlacklistServiceImpl implements WxMpUserBlacklistService { private static final String API_BLACKLIST_PREFIX = "https://api.weixin.qq.com/cgi-bin/tags/members"; - private WxMpService wxMpService; + private WxMpService wxMpService; public WxMpUserBlacklistServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialDeleteRequestExecutor.java similarity index 90% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialDeleteRequestExecutor.java index 9502afe66d..b25d668dda 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialDeleteRequestExecutor.java @@ -1,9 +1,9 @@ -package me.chanjar.weixin.mp.util.http; +package me.chanjar.weixin.mp.util.http.apache; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -16,7 +16,7 @@ import java.util.HashMap; import java.util.Map; -public class MaterialDeleteRequestExecutor implements RequestExecutor { +public class MaterialDeleteRequestExecutor implements RequestExecutor { public MaterialDeleteRequestExecutor() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialNewsInfoRequestExecutor.java similarity index 91% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialNewsInfoRequestExecutor.java index f61602abdb..f29de11f9b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialNewsInfoRequestExecutor.java @@ -1,9 +1,9 @@ -package me.chanjar.weixin.mp.util.http; +package me.chanjar.weixin.mp.util.http.apache; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -18,7 +18,7 @@ import java.util.HashMap; import java.util.Map; -public class MaterialNewsInfoRequestExecutor implements RequestExecutor { +public class MaterialNewsInfoRequestExecutor implements RequestExecutor { public MaterialNewsInfoRequestExecutor() { super(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialUploadRequestExecutor.java similarity index 89% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialUploadRequestExecutor.java index b06c34a60d..d0c16f2dd7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialUploadRequestExecutor.java @@ -1,9 +1,9 @@ -package me.chanjar.weixin.mp.util.http; +package me.chanjar.weixin.mp.util.http.apache; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.bean.material.WxMpMaterial; import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; @@ -16,10 +16,12 @@ import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; -import java.io.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.Map; -public class MaterialUploadRequestExecutor implements RequestExecutor { +public class MaterialUploadRequestExecutor implements RequestExecutor { @Override public WxMpMaterialUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, WxMpMaterial material) throws WxErrorException, IOException { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVideoInfoRequestExecutor.java similarity index 90% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVideoInfoRequestExecutor.java index 4eb15e46ac..1617675533 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVideoInfoRequestExecutor.java @@ -1,9 +1,9 @@ -package me.chanjar.weixin.mp.util.http; +package me.chanjar.weixin.mp.util.http.apache; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; import org.apache.http.HttpHost; @@ -17,7 +17,7 @@ import java.util.HashMap; import java.util.Map; -public class MaterialVideoInfoRequestExecutor implements RequestExecutor { +public class MaterialVideoInfoRequestExecutor implements RequestExecutor { public MaterialVideoInfoRequestExecutor() { super(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVoiceAndImageDownloadRequestExecutor.java similarity index 92% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVoiceAndImageDownloadRequestExecutor.java index ceda65a687..3a29ccfaa8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVoiceAndImageDownloadRequestExecutor.java @@ -1,12 +1,10 @@ -package me.chanjar.weixin.mp.util.http; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; +package me.chanjar.weixin.mp.util.http.apache; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; import org.apache.commons.io.IOUtils; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -15,13 +13,14 @@ import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.InputStreamResponseHandler; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; -public class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { +public class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { public MaterialVoiceAndImageDownloadRequestExecutor() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MediaImgUploadRequestExecutor.java similarity index 91% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MediaImgUploadRequestExecutor.java index 2129e8a7a9..e253f4eeb9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MediaImgUploadRequestExecutor.java @@ -1,9 +1,9 @@ -package me.chanjar.weixin.mp.util.http; +package me.chanjar.weixin.mp.util.http.apache; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; @@ -21,7 +21,7 @@ /** * @author miller */ -public class MediaImgUploadRequestExecutor implements RequestExecutor { +public class MediaImgUploadRequestExecutor implements RequestExecutor { @Override public WxMediaImgUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File data) throws WxErrorException, IOException { if (data == null) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/QrCodeRequestExecutor.java similarity index 87% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/QrCodeRequestExecutor.java index 2486ca8090..b0823365b3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/QrCodeRequestExecutor.java @@ -1,11 +1,11 @@ -package me.chanjar.weixin.mp.util.http; +package me.chanjar.weixin.mp.util.http.apache; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.InputStreamResponseHandler; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; import org.apache.http.Header; import org.apache.http.HttpHost; @@ -26,20 +26,20 @@ * @author chanjarster * */ -public class QrCodeRequestExecutor implements RequestExecutor { +public class QrCodeRequestExecutor implements RequestExecutor { @Override - public File execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + public File execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, WxMpQrCodeTicket ticket) throws WxErrorException, IOException { if (ticket != null) { if (uri.indexOf('?') == -1) { uri += '?'; } - uri += uri.endsWith("?") - ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") + uri += uri.endsWith("?") + ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); } - + HttpGet httpGet = new HttpGet(uri); if (httpProxy != null) { RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialDeleteRequestExecutor.java new file mode 100644 index 0000000000..26485742e2 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialDeleteRequestExecutor.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; + +import java.io.IOException; + +public class MaterialDeleteRequestExecutor implements RequestExecutor { + + + public MaterialDeleteRequestExecutor() { + super(); + } + + @Override + public Boolean execute(HttpConnectionProvider httpclient, ProxyInfo httpProxy, String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + httpclient.useProxy(httpProxy); + } + request.withConnectionProvider(httpclient); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return true; + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialNewsInfoRequestExecutor.java new file mode 100644 index 0000000000..93b3a73505 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialNewsInfoRequestExecutor.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.IOException; + +public class MaterialNewsInfoRequestExecutor implements RequestExecutor { + + public MaterialNewsInfoRequestExecutor() { + super(); + } + + @Override + public WxMpMaterialNews execute(HttpConnectionProvider httpclient, ProxyInfo httpProxy, String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + httpclient.useProxy(httpProxy); + } + request.withConnectionProvider(httpclient); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + + String responseContent = request.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialUploadRequestExecutor.java new file mode 100644 index 0000000000..85b6665ee5 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialUploadRequestExecutor.java @@ -0,0 +1,53 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Map; + +public class MaterialUploadRequestExecutor implements RequestExecutor { + + @Override + public WxMpMaterialUploadResult execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, WxMpMaterial material) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + provider.useProxy(httpProxy); + } + request.withConnectionProvider(provider); + + if (material == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); + } + + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + request.form("media", file); + Map form = material.getForm(); + if (material.getForm() != null) { + request.form("description", WxGsonBuilder.create().toJson(form)); + } + + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialUploadResult.fromJson(responseContent); + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVideoInfoRequestExecutor.java new file mode 100644 index 0000000000..7b7272b749 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVideoInfoRequestExecutor.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; + +import java.io.IOException; + +public class MaterialVideoInfoRequestExecutor implements RequestExecutor { + + public MaterialVideoInfoRequestExecutor() { + super(); + } + + @Override + public WxMpMaterialVideoInfoResult execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + provider.useProxy(httpProxy); + } + request.withConnectionProvider(provider); + + request.query("media_id", materialId); + HttpResponse response =request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVoiceAndImageDownloadRequestExecutor.java new file mode 100644 index 0000000000..4d988bad7b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVoiceAndImageDownloadRequestExecutor.java @@ -0,0 +1,57 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import org.apache.commons.io.IOUtils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +public class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { + + + public MaterialVoiceAndImageDownloadRequestExecutor() { + super(); + } + + public MaterialVoiceAndImageDownloadRequestExecutor(File tmpDirFile) { + super(); + } + + @Override + public InputStream execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + provider.useProxy(httpProxy); + } + request.withConnectionProvider(provider); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + + InputStream inputStream = new ByteArrayInputStream(response.bodyBytes()); + // 下载媒体文件出错 + byte[] responseContent = IOUtils.toByteArray(inputStream); + String responseContentString = new String(responseContent, "UTF-8"); + if (responseContentString.length() < 100) { + try { + WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); + if (wxError.getErrorCode() != 0) { + throw new WxErrorException(wxError); + } + } catch (com.google.gson.JsonSyntaxException ex) { + return new ByteArrayInputStream(responseContent); + } + } + return new ByteArrayInputStream(responseContent); + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MediaImgUploadRequestExecutor.java new file mode 100644 index 0000000000..7c4b13f962 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MediaImgUploadRequestExecutor.java @@ -0,0 +1,42 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; + +import java.io.File; +import java.io.IOException; + +/** + * @author miller + */ +public class MediaImgUploadRequestExecutor implements RequestExecutor { + @Override + public WxMediaImgUploadResult execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, File data) throws WxErrorException, IOException { + if (data == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); + } + + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + provider.useProxy(httpProxy); + } + request.withConnectionProvider(provider); + + request.form("media", data); + HttpResponse response =request.send(); + + String responseContent =response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + + return WxMediaImgUploadResult.fromJson(responseContent); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/QrCodeRequestExecutor.java new file mode 100644 index 0000000000..d1b6f2c550 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/QrCodeRequestExecutor.java @@ -0,0 +1,60 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.MimeTypes; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; + +/** + * 获得QrCode图片 请求执行器 + * + * @author chanjarster + */ +public class QrCodeRequestExecutor implements RequestExecutor { + + @Override + public File execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, + WxMpQrCodeTicket ticket) throws WxErrorException, IOException { + if (ticket != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") + ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") + : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); + } + + + HttpRequest request = HttpRequest.get(uri); + if (httpProxy != null) { + provider.useProxy(httpProxy); + } + request.withConnectionProvider(provider); + + HttpResponse response = request.send(); + try ( + InputStream inputStream = new ByteArrayInputStream(response.bodyBytes());) { + String contentTypeHeader = response.header("Content-Type"); + // 出错 + if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { + String responseContent = response.bodyText(); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } + } + +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java index da6460878e..25dedbaa77 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java @@ -3,8 +3,11 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; -import org.testng.annotations.*; +import me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl; +import org.apache.http.HttpHost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -19,8 +22,8 @@ public Object[][] getService() { WxMpService service = new WxMpServiceImpl() { @Override - protected synchronized T executeInternal( - RequestExecutor executor, String uri, E data) + public synchronized T executeInternal( + RequestExecutor executor, String uri, E data) throws WxErrorException { this.log.info("Executed"); WxError error = new WxError(); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java index e4edca7491..baa34443f2 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java @@ -25,7 +25,7 @@ public class WxMpStoreServiceImplTest { private WxMpService wxMpService; /** - * Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpStoreServiceImpl#add(me.chanjar.weixin.mp.bean.store.WxMpStoreBaseInfo)}. + * Test method for {@link WxMpStoreServiceImpl#add(me.chanjar.weixin.mp.bean.store.WxMpStoreBaseInfo)}. * * @throws WxErrorException */ diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java index 31ad47b6f7..2cfaec543c 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java @@ -6,7 +6,7 @@ import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl; import java.io.IOException; import java.io.InputStream; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java index 1c1893762f..e2c75f83d6 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java @@ -5,7 +5,7 @@ import me.chanjar.weixin.mp.api.WxMpMessageHandler; import me.chanjar.weixin.mp.api.WxMpMessageRouter; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; From 0b0b5a90fc79e8e93238b3367a6311dbeed10aea Mon Sep 17 00:00:00 2001 From: ecoolper Date: Fri, 21 Apr 2017 23:36:22 +0800 Subject: [PATCH 006/179] common usage jodd-http --- .../http/DefaultApacheHttpClientBuilder.java | 292 ------------------ .../util/http/InputStreamResponseHandler.java | 28 -- .../common/util/http/RequestExecutor.java | 8 +- .../common/util/http/Utf8ResponseHandler.java | 33 -- .../{ => apache}/ApacheHttpClientBuilder.java | 2 +- .../DefaultApacheHttpClientBuilder.java | 2 +- .../InputStreamResponseHandler.java | 2 +- .../MediaDownloadRequestExecutor.java | 5 +- .../MediaUploadRequestExecutor.java | 5 +- .../SimpleGetRequestExecutor.java | 5 +- .../SimplePostRequestExecutor.java | 12 +- .../{jodd => apache}/Utf8ResponseHandler.java | 2 +- .../http/jodd/ApacheHttpClientBuilder.java | 53 ---- .../jodd/MediaDownloadRequestExecutor.java | 14 +- .../http/jodd/MediaUploadRequestExecutor.java | 10 +- .../util/http/jodd/RequestExecutor.java | 25 -- .../http/jodd/SimpleGetRequestExecutor.java | 10 +- .../http/jodd/SimplePostRequestExecutor.java | 10 +- .../weixin/common/util/http/jodd/URIUtil.java | 48 --- 19 files changed, 47 insertions(+), 519 deletions(-) delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/DefaultApacheHttpClientBuilder.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamResponseHandler.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/Utf8ResponseHandler.java rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/{ => apache}/ApacheHttpClientBuilder.java (95%) rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/{jodd => apache}/DefaultApacheHttpClientBuilder.java (99%) rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/{jodd => apache}/InputStreamResponseHandler.java (94%) rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/{ => apache}/MediaDownloadRequestExecutor.java (95%) rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/{ => apache}/MediaUploadRequestExecutor.java (92%) rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/{ => apache}/SimpleGetRequestExecutor.java (90%) rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/{ => apache}/SimplePostRequestExecutor.java (92%) rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/{jodd => apache}/Utf8ResponseHandler.java (95%) delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/DefaultApacheHttpClientBuilder.java deleted file mode 100644 index 030fe98fe2..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/DefaultApacheHttpClientBuilder.java +++ /dev/null @@ -1,292 +0,0 @@ -package me.chanjar.weixin.common.util.http; - -import org.apache.commons.lang3.StringUtils; -import org.apache.http.annotation.NotThreadSafe; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.HttpRequestRetryHandler; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.config.Registry; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.config.SocketConfig; -import org.apache.http.conn.HttpClientConnectionManager; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.socket.PlainConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.protocol.HttpContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * httpclient 连接管理器 - * - * @author kakotor - */ -@NotThreadSafe -public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder { - protected final Logger log = LoggerFactory.getLogger(DefaultApacheHttpClientBuilder.class); - private final AtomicBoolean prepared = new AtomicBoolean(false); - private int connectionRequestTimeout = 3000; - private int connectionTimeout = 5000; - private int soTimeout = 5000; - private int idleConnTimeout = 60000; - private int checkWaitTime = 60000; - private int maxConnPerHost = 10; - private int maxTotalConn = 50; - private String userAgent; - private HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { - @Override - public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { - return false; - } - }; - private SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory(); - private PlainConnectionSocketFactory plainConnectionSocketFactory = PlainConnectionSocketFactory.getSocketFactory(); - private String httpProxyHost; - private int httpProxyPort; - private String httpProxyUsername; - private String httpProxyPassword; - /** - * 闲置连接监控线程 - */ - private IdleConnectionMonitorThread idleConnectionMonitorThread; - private HttpClientBuilder httpClientBuilder; - - private DefaultApacheHttpClientBuilder() { - } - - public static DefaultApacheHttpClientBuilder get() { - return new DefaultApacheHttpClientBuilder(); - } - - @Override - public ApacheHttpClientBuilder httpProxyHost(String httpProxyHost) { - this.httpProxyHost = httpProxyHost; - return this; - } - - @Override - public ApacheHttpClientBuilder httpProxyPort(int httpProxyPort) { - this.httpProxyPort = httpProxyPort; - return this; - } - - @Override - public ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername) { - this.httpProxyUsername = httpProxyUsername; - return this; - } - - @Override - public ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword) { - this.httpProxyPassword = httpProxyPassword; - return this; - } - - @Override - public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory) { - this.sslConnectionSocketFactory = sslConnectionSocketFactory; - return this; - } - - /** - * 获取链接的超时时间设置,默认3000ms - *

- * 设置为零时不超时,一直等待. - * 设置为负数是使用系统默认设置(非上述的3000ms的默认值,而是httpclient的默认设置). - *

- * - * @param connectionRequestTimeout 获取链接的超时时间设置(单位毫秒),默认3000ms - */ - public void setConnectionRequestTimeout(int connectionRequestTimeout) { - this.connectionRequestTimeout = connectionRequestTimeout; - } - - /** - * 建立链接的超时时间,默认为5000ms.由于是在链接池获取链接,此设置应该并不起什么作用 - *

- * 设置为零时不超时,一直等待. - * 设置为负数是使用系统默认设置(非上述的5000ms的默认值,而是httpclient的默认设置). - *

- * - * @param connectionTimeout 建立链接的超时时间设置(单位毫秒),默认5000ms - */ - public void setConnectionTimeout(int connectionTimeout) { - this.connectionTimeout = connectionTimeout; - } - - /** - * 默认NIO的socket超时设置,默认5000ms. - * - * @param soTimeout 默认NIO的socket超时设置,默认5000ms. - * @see java.net.SocketOptions#SO_TIMEOUT - */ - public void setSoTimeout(int soTimeout) { - this.soTimeout = soTimeout; - } - - /** - * 空闲链接的超时时间,默认60000ms. - *

- * 超时的链接将在下一次空闲链接检查是被销毁 - *

- * - * @param idleConnTimeout 空闲链接的超时时间,默认60000ms. - */ - public void setIdleConnTimeout(int idleConnTimeout) { - this.idleConnTimeout = idleConnTimeout; - } - - /** - * 检查空间链接的间隔周期,默认60000ms. - * - * @param checkWaitTime 检查空间链接的间隔周期,默认60000ms. - */ - public void setCheckWaitTime(int checkWaitTime) { - this.checkWaitTime = checkWaitTime; - } - - /** - * 每路的最大链接数,默认10 - * - * @param maxConnPerHost 每路的最大链接数,默认10 - */ - public void setMaxConnPerHost(int maxConnPerHost) { - this.maxConnPerHost = maxConnPerHost; - } - - /** - * 最大总连接数,默认50 - * - * @param maxTotalConn 最大总连接数,默认50 - */ - public void setMaxTotalConn(int maxTotalConn) { - this.maxTotalConn = maxTotalConn; - } - - /** - * 自定义httpclient的User Agent - * - * @param userAgent User Agent - */ - public void setUserAgent(String userAgent) { - this.userAgent = userAgent; - } - - public IdleConnectionMonitorThread getIdleConnectionMonitorThread() { - return this.idleConnectionMonitorThread; - } - - private synchronized void prepare() { - if(prepared.get()){ - return; - } - Registry registry = RegistryBuilder.create() - .register("http", this.plainConnectionSocketFactory) - .register("https", this.sslConnectionSocketFactory) - .build(); - - @SuppressWarnings("resource") - PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry); - connectionManager.setMaxTotal(this.maxTotalConn); - connectionManager.setDefaultMaxPerRoute(this.maxConnPerHost); - connectionManager.setDefaultSocketConfig( - SocketConfig.copy(SocketConfig.DEFAULT) - .setSoTimeout(this.soTimeout) - .build() - ); - - this.idleConnectionMonitorThread = new IdleConnectionMonitorThread( - connectionManager, this.idleConnTimeout, this.checkWaitTime); - this.idleConnectionMonitorThread.setDaemon(true); - this.idleConnectionMonitorThread.start(); - - this.httpClientBuilder = HttpClients.custom() - .setConnectionManager(connectionManager) - .setConnectionManagerShared(true) - .setDefaultRequestConfig( - RequestConfig.custom() - .setSocketTimeout(this.soTimeout) - .setConnectTimeout(this.connectionTimeout) - .setConnectionRequestTimeout(this.connectionRequestTimeout) - .build() - ) - .setRetryHandler(this.httpRequestRetryHandler); - - if (StringUtils.isNotBlank(this.httpProxyHost) - && StringUtils.isNotBlank(this.httpProxyUsername)) { - // 使用代理服务器 需要用户认证的代理服务器 - CredentialsProvider provider = new BasicCredentialsProvider(); - provider.setCredentials( - new AuthScope(this.httpProxyHost, this.httpProxyPort), - new UsernamePasswordCredentials(this.httpProxyUsername, - this.httpProxyPassword)); - this.httpClientBuilder.setDefaultCredentialsProvider(provider); - } - - if (StringUtils.isNotBlank(this.userAgent)) { - this.httpClientBuilder.setUserAgent(this.userAgent); - } - prepared.set(true); - } - - @Override - public CloseableHttpClient build() { - if(!prepared.get()){ - prepare(); - } - return this.httpClientBuilder.build(); - } - - public static class IdleConnectionMonitorThread extends Thread { - private final HttpClientConnectionManager connMgr; - private final int idleConnTimeout; - private final int checkWaitTime; - private volatile boolean shutdown; - - public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, int checkWaitTime) { - super("IdleConnectionMonitorThread"); - this.connMgr = connMgr; - this.idleConnTimeout = idleConnTimeout; - this.checkWaitTime = checkWaitTime; - } - - @Override - public void run() { - try { - while (!this.shutdown) { - synchronized (this) { - wait(this.checkWaitTime); - this.connMgr.closeExpiredConnections(); - this.connMgr.closeIdleConnections(this.idleConnTimeout, - TimeUnit.MILLISECONDS); - } - } - } catch (InterruptedException ignore) { - } - } - - public void trigger() { - synchronized (this) { - notifyAll(); - } - } - - public void shutdown() { - this.shutdown = true; - synchronized (this) { - notifyAll(); - } - } - } -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamResponseHandler.java deleted file mode 100644 index 0cc1562b59..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamResponseHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -package me.chanjar.weixin.common.util.http; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; -import org.apache.http.client.HttpResponseException; -import org.apache.http.client.ResponseHandler; -import org.apache.http.util.EntityUtils; - -import java.io.IOException; -import java.io.InputStream; - -public class InputStreamResponseHandler implements ResponseHandler { - - public static final ResponseHandler INSTANCE = new InputStreamResponseHandler(); - - @Override - public InputStream handleResponse(final HttpResponse response) throws IOException { - final StatusLine statusLine = response.getStatusLine(); - final HttpEntity entity = response.getEntity(); - if (statusLine.getStatusCode() >= 300) { - EntityUtils.consume(entity); - throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); - } - return entity == null ? null : entity.getContent(); - } - -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java index 6d2dbe9ab8..9110e12a80 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java @@ -1,8 +1,6 @@ package me.chanjar.weixin.common.util.http; import me.chanjar.weixin.common.exception.WxErrorException; -import org.apache.http.HttpHost; -import org.apache.http.impl.client.CloseableHttpClient; import java.io.IOException; @@ -12,16 +10,16 @@ * @param 返回值类型 * @param 请求参数类型 */ -public interface RequestExecutor { +public interface RequestExecutor { /** - * @param httpclient 传入的httpClient + * @param httpClient * @param httpProxy http代理对象,如果没有配置代理则为空 * @param uri uri * @param data 数据 * @throws WxErrorException * @throws IOException */ - T execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, E data) throws WxErrorException, IOException; + T execute(H httpClient, P httpProxy, String uri, E data) throws WxErrorException, IOException; } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/Utf8ResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/Utf8ResponseHandler.java deleted file mode 100644 index 148ef9650d..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/Utf8ResponseHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -package me.chanjar.weixin.common.util.http; - -import org.apache.http.Consts; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; -import org.apache.http.client.HttpResponseException; -import org.apache.http.client.ResponseHandler; -import org.apache.http.util.EntityUtils; - -import java.io.IOException; - -/** - * copy from {@link org.apache.http.impl.client.BasicResponseHandler} - * - * @author Daniel Qian - */ -public class Utf8ResponseHandler implements ResponseHandler { - - public static final ResponseHandler INSTANCE = new Utf8ResponseHandler(); - - @Override - public String handleResponse(final HttpResponse response) throws IOException { - final StatusLine statusLine = response.getStatusLine(); - final HttpEntity entity = response.getEntity(); - if (statusLine.getStatusCode() >= 300) { - EntityUtils.consume(entity); - throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); - } - return entity == null ? null : EntityUtils.toString(entity, Consts.UTF_8); - } - -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java similarity index 95% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java index c932445d33..87a86dbae5 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.common.util.http; +package me.chanjar.weixin.common.util.http.apache; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java similarity index 99% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/DefaultApacheHttpClientBuilder.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java index 3f667abe4d..2bb1f07243 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/DefaultApacheHttpClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.common.util.http.jodd; +package me.chanjar.weixin.common.util.http.apache; import org.apache.commons.lang3.StringUtils; import org.apache.http.annotation.NotThreadSafe; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/InputStreamResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java similarity index 94% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/InputStreamResponseHandler.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java index a766d4c268..d4cea91da1 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/InputStreamResponseHandler.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.common.util.http.jodd; +package me.chanjar.weixin.common.util.http.apache; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaDownloadRequestExecutor.java similarity index 95% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaDownloadRequestExecutor.java index 57024f5001..5479a0b609 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaDownloadRequestExecutor.java @@ -1,8 +1,9 @@ -package me.chanjar.weixin.common.util.http; +package me.chanjar.weixin.common.util.http.apache; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestExecutor; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpHost; @@ -23,7 +24,7 @@ * 视频文件不支持下载 * @author Daniel Qian */ -public class MediaDownloadRequestExecutor implements RequestExecutor { +public class MediaDownloadRequestExecutor implements RequestExecutor { private File tmpDirFile; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaUploadRequestExecutor.java similarity index 92% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaUploadRequestExecutor.java index 54ded05a7a..66901d3b71 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaUploadRequestExecutor.java @@ -1,8 +1,9 @@ -package me.chanjar.weixin.common.util.http; +package me.chanjar.weixin.common.util.http.apache; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -21,7 +22,7 @@ * * @author Daniel Qian */ -public class MediaUploadRequestExecutor implements RequestExecutor { +public class MediaUploadRequestExecutor implements RequestExecutor { @Override public WxMediaUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File file) throws WxErrorException, IOException { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimpleGetRequestExecutor.java similarity index 90% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimpleGetRequestExecutor.java index ec221e28b8..fce598f4b5 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimpleGetRequestExecutor.java @@ -1,7 +1,8 @@ -package me.chanjar.weixin.common.util.http; +package me.chanjar.weixin.common.util.http.apache; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -15,7 +16,7 @@ * * @author Daniel Qian */ -public class SimpleGetRequestExecutor implements RequestExecutor { +public class SimpleGetRequestExecutor implements RequestExecutor { @Override public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimplePostRequestExecutor.java similarity index 92% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimplePostRequestExecutor.java index bdea8573c0..a63944bcf8 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimplePostRequestExecutor.java @@ -1,7 +1,8 @@ -package me.chanjar.weixin.common.util.http; - -import java.io.IOException; +package me.chanjar.weixin.common.util.http.apache; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; import org.apache.http.Consts; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -10,15 +11,14 @@ import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; +import java.io.IOException; /** * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String * * @author Daniel Qian */ -public class SimplePostRequestExecutor implements RequestExecutor { +public class SimplePostRequestExecutor implements RequestExecutor { @Override public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String postEntity) throws WxErrorException, IOException { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/Utf8ResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java similarity index 95% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/Utf8ResponseHandler.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java index e26d3e3366..697d4695e2 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/Utf8ResponseHandler.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.common.util.http.jodd; +package me.chanjar.weixin.common.util.http.apache; import org.apache.http.Consts; import org.apache.http.HttpEntity; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java deleted file mode 100644 index ce021a042a..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java +++ /dev/null @@ -1,53 +0,0 @@ -package me.chanjar.weixin.common.util.http.jodd; - -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.CloseableHttpClient; - -/** - * httpclient build interface - * @author kakotor - */ -public interface ApacheHttpClientBuilder { - - /** - * 构建httpclient实例 - * - * @return new instance of CloseableHttpClient - */ - CloseableHttpClient build(); - - /** - * 代理服务器地址 - * - * @param httpProxyHost - */ - ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); - - /** - * 代理服务器端口 - * - * @param httpProxyPort - */ - ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); - - /** - * 代理服务器用户名 - * - * @param httpProxyUsername - */ - ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); - - /** - * 代理服务器密码 - * - * @param httpProxyPassword - */ - ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); - - /** - * ssl连接socket工厂 - * - * @param sslConnectionSocketFactory - */ - ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java index ff617e8ee5..9e4b092f48 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java @@ -1,11 +1,13 @@ package me.chanjar.weixin.common.util.http.jodd; +import jodd.http.HttpConnectionProvider; import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestExecutor; import org.apache.commons.lang3.StringUtils; import java.io.ByteArrayInputStream; @@ -21,7 +23,7 @@ * * @author Daniel Qian */ -public class MediaDownloadRequestExecutor implements RequestExecutor { +public class MediaDownloadRequestExecutor implements RequestExecutor { private File tmpDirFile; @@ -33,7 +35,7 @@ public MediaDownloadRequestExecutor(File tmpDirFile) { } @Override - public File execute(ProxyInfo httpProxy, String uri, String queryParam) throws WxErrorException, IOException { + public File execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, String queryParam) throws WxErrorException, IOException { if (queryParam != null) { if (uri.indexOf('?') == -1) { uri += '?'; @@ -41,8 +43,12 @@ public File execute(ProxyInfo httpProxy, String uri, String queryParam) throws W uri += uri.endsWith("?") ? queryParam : '&' + queryParam; } - HttpRequest httpRequest = HttpRequest.post(uri); - HttpResponse response = httpRequest.send(); + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + provider.useProxy(httpProxy); + } + request.withConnectionProvider(provider); + HttpResponse response = request.send(); String contentType = response.header("Content-Type"); if (contentType != null && contentType.startsWith("application/json")) { // application/json; encoding=utf-8 下载媒体文件出错 diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java index 43d7bbaef3..7d3b3eb95c 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java @@ -1,12 +1,13 @@ package me.chanjar.weixin.common.util.http.jodd; +import jodd.http.HttpConnectionProvider; import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; -import jodd.http.net.SocketHttpConnectionProvider; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; import java.io.File; import java.io.IOException; @@ -16,16 +17,15 @@ * * @author Daniel Qian */ -public class MediaUploadRequestExecutor implements RequestExecutor { +public class MediaUploadRequestExecutor implements RequestExecutor { @Override - public WxMediaUploadResult execute(ProxyInfo httpProxy, String uri, File file) throws WxErrorException, IOException { + public WxMediaUploadResult execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, File file) throws WxErrorException, IOException { HttpRequest request = HttpRequest.post(uri); if (httpProxy != null) { - SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); provider.useProxy(httpProxy); - request.withConnectionProvider(provider); } + request.withConnectionProvider(provider); request.form("media", file); HttpResponse response = request.send(); String responseContent =response.bodyText(); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java deleted file mode 100644 index ccc827020f..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.chanjar.weixin.common.util.http.jodd; - -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.exception.WxErrorException; - -import java.io.IOException; - -/** - * http请求执行器 - * - * @param 返回值类型 - * @param 请求参数类型 - */ -public interface RequestExecutor { - - /** - * @param httpProxy http代理对象,如果没有配置代理则为空 - * @param uri uri - * @param data 数据 - * @throws WxErrorException - * @throws IOException - */ - T execute(ProxyInfo httpProxy, String uri, E data) throws WxErrorException, IOException; - -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java index de84ad7bcb..221e3b1ec8 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java @@ -1,11 +1,12 @@ package me.chanjar.weixin.common.util.http.jodd; +import jodd.http.HttpConnectionProvider; import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; -import jodd.http.net.SocketHttpConnectionProvider; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; import java.io.IOException; @@ -14,10 +15,10 @@ * * @author Daniel Qian */ -public class SimpleGetRequestExecutor implements RequestExecutor { +public class SimpleGetRequestExecutor implements RequestExecutor { @Override - public String execute(ProxyInfo httpProxy, String uri, String queryParam) throws WxErrorException, IOException { + public String execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, String queryParam) throws WxErrorException, IOException { if (queryParam != null) { if (uri.indexOf('?') == -1) { uri += '?'; @@ -27,10 +28,9 @@ public String execute(ProxyInfo httpProxy, String uri, String queryParam) throws HttpRequest request = HttpRequest.get(uri); if (httpProxy != null) { - SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); provider.useProxy(httpProxy); - request.withConnectionProvider(provider); } + request.withConnectionProvider(provider); HttpResponse response = request.send(); String responseContent = response.bodyText(); WxError error = WxError.fromJson(responseContent); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java index 276b131099..057abf8e57 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java @@ -1,11 +1,12 @@ package me.chanjar.weixin.common.util.http.jodd; +import jodd.http.HttpConnectionProvider; import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; -import jodd.http.net.SocketHttpConnectionProvider; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; import java.io.IOException; @@ -14,16 +15,15 @@ * * @author Daniel Qian */ -public class SimplePostRequestExecutor implements RequestExecutor { +public class SimplePostRequestExecutor implements RequestExecutor { @Override - public String execute(ProxyInfo httpProxy, String uri, String postEntity) throws WxErrorException, IOException { + public String execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, String postEntity) throws WxErrorException, IOException { HttpRequest request = HttpRequest.post(uri); if (httpProxy != null) { - SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); provider.useProxy(httpProxy); - request.withConnectionProvider(provider); } + request.withConnectionProvider(provider); if (postEntity != null) { request.bodyText(postEntity); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java deleted file mode 100644 index ac293d7924..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java +++ /dev/null @@ -1,48 +0,0 @@ -package me.chanjar.weixin.common.util.http.jodd; - - -import org.apache.commons.lang3.StringUtils; - -import java.io.UnsupportedEncodingException; - -public class URIUtil { - - private static final String ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()"; - - public static String encodeURIComponent(String input) { - if (StringUtils.isEmpty(input)) { - return input; - } - - int l = input.length(); - StringBuilder o = new StringBuilder(l * 3); - try { - for (int i = 0; i < l; i++) { - String e = input.substring(i, i + 1); - if (ALLOWED_CHARS.indexOf(e) == -1) { - byte[] b = e.getBytes("utf-8"); - o.append(getHex(b)); - continue; - } - o.append(e); - } - return o.toString(); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - return input; - } - - private static String getHex(byte buf[]) { - StringBuilder o = new StringBuilder(buf.length * 3); - for (int i = 0; i < buf.length; i++) { - int n = buf[i] & 0xff; - o.append("%"); - if (n < 0x10) { - o.append("0"); - } - o.append(Long.toString(n, 16).toUpperCase()); - } - return o.toString(); - } -} From 5726ca9c0443a6ee35fe9f5d5b298d99f16aaee6 Mon Sep 17 00:00:00 2001 From: ecoolper Date: Sat, 22 Apr 2017 00:29:42 +0800 Subject: [PATCH 007/179] cp usage jodd-http --- .../chanjar/weixin/cp/api/WxCpConfigStorage.java | 2 +- .../weixin/cp/api/WxCpInMemoryConfigStorage.java | 2 +- .../weixin/cp/api/WxCpJedisConfigStorage.java | 2 +- .../java/me/chanjar/weixin/cp/api/WxCpService.java | 8 +++++--- .../cp/api/{ => impl/apache}/WxCpServiceImpl.java | 14 +++++++++----- .../me/chanjar/weixin/cp/api/ApiTestModule.java | 1 + .../chanjar/weixin/cp/api/WxCpDepartAPITest.java | 1 + .../me/chanjar/weixin/cp/api/WxCpMediaAPITest.java | 1 + .../me/chanjar/weixin/cp/api/WxCpTagAPITest.java | 1 + .../me/chanjar/weixin/cp/api/WxCpUserAPITest.java | 1 + .../me/chanjar/weixin/cp/api/WxMenuAPITest.java | 1 + .../cp/api/{ => impl/apache}/WxCpBaseAPITest.java | 4 +++- .../api/{ => impl/apache}/WxCpBusyRetryTest.java | 9 ++++++--- .../api/{ => impl/apache}/WxCpMessageAPITest.java | 9 ++++----- .../me/chanjar/weixin/cp/demo/WxCpDemoServer.java | 2 +- weixin-java-cp/src/test/resources/testng.xml | 6 +++--- 16 files changed, 40 insertions(+), 24 deletions(-) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/{ => impl/apache}/WxCpServiceImpl.java (97%) rename weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/{ => impl/apache}/WxCpBaseAPITest.java (85%) rename weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/{ => impl/apache}/WxCpBusyRetryTest.java (86%) rename weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/{ => impl/apache}/WxCpMessageAPITest.java (93%) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java index eb1e57cafa..3484db3b88 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.cp.api; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import java.io.File; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java index 867dd6bb68..b1eeb8274a 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java @@ -2,7 +2,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.ToStringUtils; -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import java.io.File; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java index 9251396560..07f38ebbf9 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.cp.api; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index bd0b322f72..e8a0baf7f7 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -20,7 +20,7 @@ /** * 微信API的Service */ -public interface WxCpService { +public interface WxCpService { /** *
@@ -469,7 +469,7 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i
    * 
    * Service没有实现某个API的时候,可以用这个,
    * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
-   * 可以参考,{@link me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor}的实现方法
+   * 可以参考,{@link me.chanjar.weixin.common.util.http.jodd.MediaUploadRequestExecutor}的实现方法
    * 
* * @param executor 执行器 @@ -478,7 +478,9 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * @param 请求值类型 * @param 返回值类型 */ - T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + + T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException; /** * 注入 {@link WxCpConfigStorage} 的实现 diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java similarity index 97% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java index 0105e78d52..522c449f74 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.api.impl.apache; import com.google.gson.*; import com.google.gson.reflect.TypeToken; @@ -14,8 +14,12 @@ import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.*; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.URIUtil; +import me.chanjar.weixin.common.util.http.apache.*; import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.api.WxCpConfigStorage; +import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpDepart; import me.chanjar.weixin.cp.bean.WxCpMessage; import me.chanjar.weixin.cp.bean.WxCpTag; @@ -37,7 +41,7 @@ import java.util.List; import java.util.UUID; -public class WxCpServiceImpl implements WxCpService { +public class WxCpServiceImpl implements WxCpService { protected final Logger log = LoggerFactory.getLogger(WxCpServiceImpl.class); @@ -534,7 +538,7 @@ public String post(String url, String postData) throws WxErrorException { * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 */ @Override - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { int retryTimes = 0; do { try { @@ -570,7 +574,7 @@ public T execute(RequestExecutor executor, String uri, E data) thro throw new RuntimeException("微信服务端异常,超出重试次数"); } - protected synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { if (uri.contains("access_token=")) { throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java index 2a694ff32f..80265168de 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java @@ -9,6 +9,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; public class ApiTestModule implements Module { diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java index c0cc3251ae..1a3fb79557 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java @@ -2,6 +2,7 @@ import java.util.List; +import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java index d9fb2605d0..3f297968f7 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; +import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Guice; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java index aa26e9620a..d5ff3a3a80 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java @@ -1,6 +1,7 @@ package me.chanjar.weixin.cp.api; import com.google.inject.Inject; +import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; import me.chanjar.weixin.cp.bean.WxCpTag; import me.chanjar.weixin.cp.bean.WxCpUser; import org.testng.Assert; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java index 4d5a7a91f0..450cefa268 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java @@ -2,6 +2,7 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; import me.chanjar.weixin.cp.bean.WxCpDepart; import me.chanjar.weixin.cp.bean.WxCpUser; import org.testng.Assert; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java index c837e51e1d..a6fdfa9d88 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java @@ -5,6 +5,7 @@ import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.menu.WxMenuButton; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Guice; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBaseAPITest.java similarity index 85% rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBaseAPITest.java index 894bb3b67d..6fecf6e7e2 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBaseAPITest.java @@ -1,7 +1,9 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.api.impl.apache; import com.google.inject.Inject; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.WxCpConfigStorage; import org.apache.commons.lang3.StringUtils; import org.testng.Assert; import org.testng.annotations.Guice; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBusyRetryTest.java similarity index 86% rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBusyRetryTest.java index e1b005bd83..90b1d1b362 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBusyRetryTest.java @@ -1,8 +1,11 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.api.impl.apache; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.cp.api.WxCpService; +import org.apache.http.HttpHost; +import org.apache.http.impl.client.CloseableHttpClient; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -19,8 +22,8 @@ public Object[][] getService() { WxCpService service = new WxCpServiceImpl() { @Override - protected synchronized T executeInternal( - RequestExecutor executor, String uri, E data) + public synchronized T executeInternal( + RequestExecutor executor, String uri, E data) throws WxErrorException { this.log.info("Executed"); WxError error = new WxError(); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java similarity index 93% rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java index b7bcf7a377..968cfea944 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java @@ -1,13 +1,12 @@ -package me.chanjar.weixin.cp.api; - -import org.testng.annotations.Guice; -import org.testng.annotations.Test; +package me.chanjar.weixin.cp.api.impl.apache; import com.google.inject.Inject; - import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.ApiTestModule; import me.chanjar.weixin.cp.bean.WxCpMessage; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; /*** * 测试发送消息 diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java index dc667d88ba..eb78d66714 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java @@ -13,7 +13,7 @@ import me.chanjar.weixin.cp.api.WxCpMessageHandler; import me.chanjar.weixin.cp.api.WxCpMessageRouter; import me.chanjar.weixin.cp.api.WxCpService; -import me.chanjar.weixin.cp.api.WxCpServiceImpl; +import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; diff --git a/weixin-java-cp/src/test/resources/testng.xml b/weixin-java-cp/src/test/resources/testng.xml index ba92bc0c0c..04f960ed63 100644 --- a/weixin-java-cp/src/test/resources/testng.xml +++ b/weixin-java-cp/src/test/resources/testng.xml @@ -3,9 +3,9 @@ - - - + + + From 76330ef3c646704044a53cd3a595385c6dd48a80 Mon Sep 17 00:00:00 2001 From: ecoolper Date: Sat, 22 Apr 2017 13:34:22 +0800 Subject: [PATCH 008/179] =?UTF-8?q?=E8=A3=85=E9=A5=B0=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/MediaDownloadRequestExecutor.java | 161 ++++++++++++++++++ .../util/http/MediaUploadRequestExecutor.java | 95 +++++++++++ .../common/util/http/RequestExecutor.java | 10 +- .../weixin/common/util/http/RequestHttp.java | 20 +++ .../util/http/SimpleGetRequestExecutor.java | 91 ++++++++++ .../util/http/SimplePostRequestExecutor.java | 112 ++++++++++++ .../apache/MediaDownloadRequestExecutor.java | 94 ---------- .../apache/MediaUploadRequestExecutor.java | 55 ------ .../http/apache/SimpleGetRequestExecutor.java | 47 ----- .../apache/SimplePostRequestExecutor.java | 59 ------- .../jodd/MediaDownloadRequestExecutor.java | 82 --------- .../http/jodd/MediaUploadRequestExecutor.java | 39 ----- .../http/jodd/SimpleGetRequestExecutor.java | 43 ----- .../http/jodd/SimplePostRequestExecutor.java | 51 ------ 14 files changed, 483 insertions(+), 476 deletions(-) create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaDownloadRequestExecutor.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaUploadRequestExecutor.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimpleGetRequestExecutor.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimplePostRequestExecutor.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java new file mode 100644 index 0000000000..cfe382e1e6 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java @@ -0,0 +1,161 @@ +package me.chanjar.weixin.common.util.http; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File + * 视频文件不支持下载 + * + * @author Daniel Qian + */ +public class MediaDownloadRequestExecutor implements RequestExecutor { + + private File tmpDirFile; + + public MediaDownloadRequestExecutor(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public File execute(RequestHttp requestHttp, String uri, String queryParam) throws WxErrorException, IOException { + if (requestHttp.getHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getHttpProxy(); + return executeApache(httpClient, httpProxy, uri, queryParam); + } + if (requestHttp.getHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getHttpProxy(); + return executeJodd(provider, proxyInfo, uri, queryParam); + } else { + //这里需要抛出异常,需要优化 + return null; + } + } + + private String getFileNameJodd(HttpResponse response) throws WxErrorException { + String content = response.header("Content-disposition"); + if (content == null || content.length() == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(content); + if (m.matches()) { + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + private String getFileNameApache(CloseableHttpResponse response) throws WxErrorException { + Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); + if(contentDispositionHeader == null || contentDispositionHeader.length == 0){ + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(contentDispositionHeader[0].getValue()); + if(m.matches()){ + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + + private File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpGet httpGet = new HttpGet(uri); + if (httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = httpclient.execute(httpGet); + InputStream inputStream = InputStreamResponseHandler.INSTANCE + .handleResponse(response)) { + + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0) { + if (contentTypeHeader[0].getValue().startsWith(ContentType.APPLICATION_JSON.getMimeType())) { + // application/json; encoding=utf-8 下载媒体文件出错 + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + } + + String fileName = getFileNameApache(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + + String[] nameAndExt = fileName.split("\\."); + return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); + + } finally { + httpGet.releaseConnection(); + } + + } + + + private File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpRequest request = HttpRequest.post(uri); + if (proxyInfo != null) { + provider.useProxy(proxyInfo); + } + request.withConnectionProvider(provider); + HttpResponse response = request.send(); + String contentType = response.header("Content-Type"); + if (contentType != null && contentType.startsWith("application/json")) { + // application/json; encoding=utf-8 下载媒体文件出错 + throw new WxErrorException(WxError.fromJson(response.bodyText())); + } + + String fileName = getFileNameJodd(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + + InputStream inputStream = new ByteArrayInputStream(response.bodyBytes()); + String[] nameAndExt = fileName.split("\\."); + return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); + } + + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java new file mode 100644 index 0000000000..b891c46bc7 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java @@ -0,0 +1,95 @@ +package me.chanjar.weixin.common.util.http; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.IOException; + +/** + * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String + * + * @author Daniel Qian + */ +public class MediaUploadRequestExecutor implements RequestExecutor { + + @Override + public WxMediaUploadResult execute(RequestHttp requestHttp, String uri, File file) throws WxErrorException, IOException { + if (requestHttp.getHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getHttpProxy(); + return executeApache(httpClient, httpProxy, uri, file); + } + if (requestHttp.getHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getHttpProxy(); + return executeJodd(provider, proxyInfo, uri, file); + } else { + //这里需要抛出异常,需要优化 + return null; + } + + + } + + private WxMediaUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File file) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); + httpPost.setConfig(config); + } + if (file != null) { + HttpEntity entity = MultipartEntityBuilder + .create() + .addBinaryBody("media", file) + .setMode(HttpMultipartMode.RFC6532) + .build(); + httpPost.setEntity(entity); + httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); + } + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMediaUploadResult.fromJson(responseContent); + } finally { + httpPost.releaseConnection(); + } + } + + + private WxMediaUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, File file) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (proxyInfo != null) { + provider.useProxy(proxyInfo); + } + request.withConnectionProvider(provider); + request.form("media", file); + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMediaUploadResult.fromJson(responseContent); + } + + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java index 9110e12a80..78834701e7 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java @@ -10,16 +10,14 @@ * @param 返回值类型 * @param 请求参数类型 */ -public interface RequestExecutor { +public interface RequestExecutor { /** - * @param httpClient - * @param httpProxy http代理对象,如果没有配置代理则为空 - * @param uri uri - * @param data 数据 + * @param uri uri + * @param data 数据 * @throws WxErrorException * @throws IOException */ - T execute(H httpClient, P httpProxy, String uri, E data) throws WxErrorException, IOException; + T execute(RequestHttp requestHttp, String uri, E data) throws WxErrorException, IOException; } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java new file mode 100644 index 0000000000..785c1b8420 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java @@ -0,0 +1,20 @@ +package me.chanjar.weixin.common.util.http; + +/** + * Created by ecoolper on 2017/4/22. + */ +public interface RequestHttp { + + /** + * httpClient + * @return + */ + Object getHttpClient(); + + /** + * httpProxy + * @return + */ + Object getHttpProxy(); + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java new file mode 100644 index 0000000000..118239423a --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java @@ -0,0 +1,91 @@ +package me.chanjar.weixin.common.util.http; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; + +/** + * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String + * + * @author Daniel Qian + */ +public class SimpleGetRequestExecutor implements RequestExecutor { + + @Override + public String execute(RequestHttp requestHttp, String uri, String queryParam) throws WxErrorException, IOException { + if (requestHttp.getHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getHttpProxy(); + return executeApache(httpClient, httpProxy, uri, queryParam); + } + if (requestHttp.getHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getHttpProxy(); + return executeJodd(provider, proxyInfo, uri, queryParam); + } else { + //这里需要抛出异常,需要优化 + return null; + } + } + + + private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + HttpGet httpGet = new HttpGet(uri); + if (httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = httpclient.execute(httpGet)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } finally { + httpGet.releaseConnection(); + } + } + + + private String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpRequest request = HttpRequest.get(uri); + if (proxyInfo != null) { + provider.useProxy(proxyInfo); + } + request.withConnectionProvider(provider); + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java new file mode 100644 index 0000000000..39cb90d628 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java @@ -0,0 +1,112 @@ +package me.chanjar.weixin.common.util.http; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import org.apache.http.Consts; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; + +/** + * 用装饰模式实现 + * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String + * + * @author Daniel Qian + */ +public class SimplePostRequestExecutor implements RequestExecutor { + + @Override + public String execute(RequestHttp requestHttp, String uri, String postEntity) throws WxErrorException, IOException { + if (requestHttp.getHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getHttpProxy(); + return executeApache(httpClient, httpProxy, uri, postEntity); + } + if (requestHttp.getHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getHttpProxy(); + return executeJodd(provider, proxyInfo, uri, postEntity); + } else { + //这里需要抛出异常,需要优化 + return null; + } + } + + private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String postEntity) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); + httpPost.setConfig(config); + } + + if (postEntity != null) { + StringEntity entity = new StringEntity(postEntity, Consts.UTF_8); + httpPost.setEntity(entity); + } + + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + if (responseContent.isEmpty()) { + throw new WxErrorException( + WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") + .build()); + } + + if (responseContent.startsWith("")) { + //xml格式输出直接返回 + return responseContent; + } + + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } finally { + httpPost.releaseConnection(); + } + } + + + private String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String postEntity) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (proxyInfo != null) { + provider.useProxy(proxyInfo); + } + request.withConnectionProvider(provider); + if (postEntity != null) { + request.bodyText(postEntity); + } + HttpResponse response = request.send(); + + String responseContent = response.bodyText(); + if (responseContent.isEmpty()) { + throw new WxErrorException( + WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") + .build()); + } + + if (responseContent.startsWith("")) { + //xml格式输出直接返回 + return responseContent; + } + + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaDownloadRequestExecutor.java deleted file mode 100644 index 5479a0b609..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaDownloadRequestExecutor.java +++ /dev/null @@ -1,94 +0,0 @@ -package me.chanjar.weixin.common.util.http.apache; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import org.apache.commons.lang3.StringUtils; -import org.apache.http.Header; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.entity.ContentType; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File - * 视频文件不支持下载 - * @author Daniel Qian - */ -public class MediaDownloadRequestExecutor implements RequestExecutor { - - private File tmpDirFile; - - public MediaDownloadRequestExecutor() { - } - - public MediaDownloadRequestExecutor(File tmpDirFile) { - this.tmpDirFile = tmpDirFile; - } - - @Override - public File execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - - HttpGet httpGet = new HttpGet(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpGet.setConfig(config); - } - - try (CloseableHttpResponse response = httpclient.execute(httpGet); - InputStream inputStream = InputStreamResponseHandler.INSTANCE - .handleResponse(response)) { - - Header[] contentTypeHeader = response.getHeaders("Content-Type"); - if (contentTypeHeader != null && contentTypeHeader.length > 0) { - if (contentTypeHeader[0].getValue().startsWith(ContentType.APPLICATION_JSON.getMimeType())) { - // application/json; encoding=utf-8 下载媒体文件出错 - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - throw new WxErrorException(WxError.fromJson(responseContent)); - } - } - - String fileName = getFileName(response); - if (StringUtils.isBlank(fileName)) { - return null; - } - - String[] nameAndExt = fileName.split("\\."); - return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); - - } finally { - httpGet.releaseConnection(); - } - - } - - private String getFileName(CloseableHttpResponse response) throws WxErrorException { - Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); - if(contentDispositionHeader == null || contentDispositionHeader.length == 0){ - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - - Pattern p = Pattern.compile(".*filename=\"(.*)\""); - Matcher m = p.matcher(contentDispositionHeader[0].getValue()); - if(m.matches()){ - return m.group(1); - } - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaUploadRequestExecutor.java deleted file mode 100644 index 66901d3b71..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/MediaUploadRequestExecutor.java +++ /dev/null @@ -1,55 +0,0 @@ -package me.chanjar.weixin.common.util.http.apache; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.HttpMultipartMode; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.File; -import java.io.IOException; - -/** - * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String - * - * @author Daniel Qian - */ -public class MediaUploadRequestExecutor implements RequestExecutor { - - @Override - public WxMediaUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File file) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - if (file != null) { - HttpEntity entity = MultipartEntityBuilder - .create() - .addBinaryBody("media", file) - .setMode(HttpMultipartMode.RFC6532) - .build(); - httpPost.setEntity(entity); - httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); - } - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return WxMediaUploadResult.fromJson(responseContent); - } finally { - httpPost.releaseConnection(); - } - } - -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimpleGetRequestExecutor.java deleted file mode 100644 index fce598f4b5..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimpleGetRequestExecutor.java +++ /dev/null @@ -1,47 +0,0 @@ -package me.chanjar.weixin.common.util.http.apache; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.IOException; - -/** - * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String - * - * @author Daniel Qian - */ -public class SimpleGetRequestExecutor implements RequestExecutor { - - @Override - public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - HttpGet httpGet = new HttpGet(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpGet.setConfig(config); - } - - try (CloseableHttpResponse response = httpclient.execute(httpGet)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return responseContent; - } finally { - httpGet.releaseConnection(); - } - } - -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimplePostRequestExecutor.java deleted file mode 100644 index a63944bcf8..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/SimplePostRequestExecutor.java +++ /dev/null @@ -1,59 +0,0 @@ -package me.chanjar.weixin.common.util.http.apache; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import org.apache.http.Consts; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.IOException; - -/** - * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String - * - * @author Daniel Qian - */ -public class SimplePostRequestExecutor implements RequestExecutor { - - @Override - public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String postEntity) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - if (postEntity != null) { - StringEntity entity = new StringEntity(postEntity, Consts.UTF_8); - httpPost.setEntity(entity); - } - - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - if (responseContent.isEmpty()) { - throw new WxErrorException( - WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") - .build()); - } - - if (responseContent.startsWith("")) { - //xml格式输出直接返回 - return responseContent; - } - - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return responseContent; - } finally { - httpPost.releaseConnection(); - } - } - -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java deleted file mode 100644 index 9e4b092f48..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java +++ /dev/null @@ -1,82 +0,0 @@ -package me.chanjar.weixin.common.util.http.jodd; - -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import org.apache.commons.lang3.StringUtils; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File - * 视频文件不支持下载 - * - * @author Daniel Qian - */ -public class MediaDownloadRequestExecutor implements RequestExecutor { - - private File tmpDirFile; - - public MediaDownloadRequestExecutor() { - } - - public MediaDownloadRequestExecutor(File tmpDirFile) { - this.tmpDirFile = tmpDirFile; - } - - @Override - public File execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - - HttpRequest request = HttpRequest.post(uri); - if (httpProxy != null) { - provider.useProxy(httpProxy); - } - request.withConnectionProvider(provider); - HttpResponse response = request.send(); - String contentType = response.header("Content-Type"); - if (contentType != null && contentType.startsWith("application/json")) { - // application/json; encoding=utf-8 下载媒体文件出错 - throw new WxErrorException(WxError.fromJson(response.bodyText())); - } - - String fileName = getFileName(response); - if (StringUtils.isBlank(fileName)) { - return null; - } - - InputStream inputStream = new ByteArrayInputStream(response.bodyBytes()); - String[] nameAndExt = fileName.split("\\."); - return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); - } - - private String getFileName(HttpResponse response) throws WxErrorException { - String content = response.header("Content-disposition"); - if (content == null || content.length() == 0) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - - Pattern p = Pattern.compile(".*filename=\"(.*)\""); - Matcher m = p.matcher(content); - if (m.matches()) { - return m.group(1); - } - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java deleted file mode 100644 index 7d3b3eb95c..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.chanjar.weixin.common.util.http.jodd; - -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; - -import java.io.File; -import java.io.IOException; - -/** - * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String - * - * @author Daniel Qian - */ -public class MediaUploadRequestExecutor implements RequestExecutor { - - @Override - public WxMediaUploadResult execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, File file) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (httpProxy != null) { - provider.useProxy(httpProxy); - } - request.withConnectionProvider(provider); - request.form("media", file); - HttpResponse response = request.send(); - String responseContent =response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return WxMediaUploadResult.fromJson(responseContent); - } - -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java deleted file mode 100644 index 221e3b1ec8..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java +++ /dev/null @@ -1,43 +0,0 @@ -package me.chanjar.weixin.common.util.http.jodd; - -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; - -import java.io.IOException; - -/** - * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String - * - * @author Daniel Qian - */ -public class SimpleGetRequestExecutor implements RequestExecutor { - - @Override - public String execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - - HttpRequest request = HttpRequest.get(uri); - if (httpProxy != null) { - provider.useProxy(httpProxy); - } - request.withConnectionProvider(provider); - HttpResponse response = request.send(); - String responseContent = response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return responseContent; - } - -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java deleted file mode 100644 index 057abf8e57..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java +++ /dev/null @@ -1,51 +0,0 @@ -package me.chanjar.weixin.common.util.http.jodd; - -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; - -import java.io.IOException; - -/** - * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String - * - * @author Daniel Qian - */ -public class SimplePostRequestExecutor implements RequestExecutor { - - @Override - public String execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, String postEntity) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (httpProxy != null) { - provider.useProxy(httpProxy); - } - request.withConnectionProvider(provider); - if (postEntity != null) { - request.bodyText(postEntity); - } - HttpResponse response = request.send(); - - String responseContent = response.bodyText(); - if (responseContent.isEmpty()) { - throw new WxErrorException( - WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") - .build()); - } - - if (responseContent.startsWith("")) { - //xml格式输出直接返回 - return responseContent; - } - - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return responseContent; - } - -} From 9ac1aad0e4c439ad798252bd0e3e44500764fcca Mon Sep 17 00:00:00 2001 From: ecoolper Date: Sat, 22 Apr 2017 15:06:12 +0800 Subject: [PATCH 009/179] =?UTF-8?q?=E8=A3=85=E9=A5=B0=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/MediaDownloadRequestExecutor.java | 12 +- .../util/http/MediaUploadRequestExecutor.java | 12 +- .../weixin/common/util/http/RequestHttp.java | 4 +- .../util/http/SimpleGetRequestExecutor.java | 12 +- .../util/http/SimplePostRequestExecutor.java | 12 +- .../me/chanjar/weixin/cp/api/WxCpService.java | 9 +- .../cp/api/impl/apache/WxCpServiceImpl.java | 23 +- .../cp/api/impl/apache/WxCpBusyRetryTest.java | 4 +- .../weixin/mp/api/WxMpCardService.java | 2 +- .../me/chanjar/weixin/mp/api/WxMpService.java | 31 +-- .../{apache => }/WxMpCardServiceImpl.java | 8 +- .../impl/{jodd => }/WxMpKefuServiceImpl.java | 8 +- .../{jodd => }/WxMpMaterialServiceImpl.java | 12 +- .../{jodd => }/WxMpQrcodeServiceImpl.java | 8 +- .../WxMpUserBlacklistServiceImpl.java | 8 +- .../api/impl/apache/WxMpKefuServiceImpl.java | 183 ------------- .../impl/apache/WxMpMaterialServiceImpl.java | 168 ------------ .../impl/apache/WxMpQrcodeServiceImpl.java | 120 --------- .../mp/api/impl/apache/WxMpServiceImpl.java | 40 +-- .../apache/WxMpUserBlacklistServiceImpl.java | 52 ---- .../mp/api/impl/jodd/WxMpCardServiceImpl.java | 251 ------------------ .../mp/api/impl/jodd/WxMpServiceImpl.java | 40 +-- .../http/MaterialDeleteRequestExecutor.java | 93 +++++++ .../http/MaterialNewsInfoRequestExecutor.java | 93 +++++++ .../http/MaterialUploadRequestExecutor.java | 121 +++++++++ .../MaterialVideoInfoRequestExecutor.java | 92 +++++++ ...lVoiceAndImageDownloadRequestExecutor.java | 117 ++++++++ .../http/MediaImgUploadRequestExecutor.java | 103 +++++++ .../mp/util/http/QrCodeRequestExecutor.java | 116 ++++++++ .../apache/MaterialDeleteRequestExecutor.java | 50 ---- .../MaterialNewsInfoRequestExecutor.java | 52 ---- .../apache/MaterialUploadRequestExecutor.java | 68 ----- .../MaterialVideoInfoRequestExecutor.java | 50 ---- ...lVoiceAndImageDownloadRequestExecutor.java | 66 ----- .../apache/MediaImgUploadRequestExecutor.java | 55 ---- .../http/apache/QrCodeRequestExecutor.java | 66 ----- .../jodd/MaterialDeleteRequestExecutor.java | 39 --- .../jodd/MaterialNewsInfoRequestExecutor.java | 41 --- .../jodd/MaterialUploadRequestExecutor.java | 53 ---- .../MaterialVideoInfoRequestExecutor.java | 39 --- ...lVoiceAndImageDownloadRequestExecutor.java | 57 ---- .../jodd/MediaImgUploadRequestExecutor.java | 42 --- .../util/http/jodd/QrCodeRequestExecutor.java | 60 ----- .../weixin/mp/api/WxMpBusyRetryTest.java | 4 +- 44 files changed, 860 insertions(+), 1636 deletions(-) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{apache => }/WxMpCardServiceImpl.java (97%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{jodd => }/WxMpKefuServiceImpl.java (96%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{jodd => }/WxMpMaterialServiceImpl.java (94%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{jodd => }/WxMpQrcodeServiceImpl.java (94%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{jodd => }/WxMpUserBlacklistServiceImpl.java (87%) delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpKefuServiceImpl.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpMaterialServiceImpl.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpQrcodeServiceImpl.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpUserBlacklistServiceImpl.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpCardServiceImpl.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialDeleteRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialNewsInfoRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialUploadRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVideoInfoRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVoiceAndImageDownloadRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MediaImgUploadRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/QrCodeRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialDeleteRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialNewsInfoRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialUploadRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVideoInfoRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVoiceAndImageDownloadRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MediaImgUploadRequestExecutor.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/QrCodeRequestExecutor.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java index cfe382e1e6..a61c54a7ef 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java @@ -41,14 +41,14 @@ public MediaDownloadRequestExecutor(File tmpDirFile) { @Override public File execute(RequestHttp requestHttp, String uri, String queryParam) throws WxErrorException, IOException { - if (requestHttp.getHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getHttpProxy(); + if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); return executeApache(httpClient, httpProxy, uri, queryParam); } - if (requestHttp.getHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getHttpProxy(); + if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); return executeJodd(provider, proxyInfo, uri, queryParam); } else { //这里需要抛出异常,需要优化 diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java index b891c46bc7..6dd49b3ea6 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java @@ -30,14 +30,14 @@ public class MediaUploadRequestExecutor implements RequestExecutor @Override public String execute(RequestHttp requestHttp, String uri, String queryParam) throws WxErrorException, IOException { - if (requestHttp.getHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getHttpProxy(); + if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); return executeApache(httpClient, httpProxy, uri, queryParam); } - if (requestHttp.getHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getHttpProxy(); + if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); return executeJodd(provider, proxyInfo, uri, queryParam); } else { //这里需要抛出异常,需要优化 diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java index 39cb90d628..f35385de70 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java @@ -27,14 +27,14 @@ public class SimplePostRequestExecutor implements RequestExecutor { +public interface WxCpService { /** *
@@ -469,7 +470,7 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i
    * 
    * Service没有实现某个API的时候,可以用这个,
    * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
-   * 可以参考,{@link me.chanjar.weixin.common.util.http.jodd.MediaUploadRequestExecutor}的实现方法
+   * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
    * 
* * @param executor 执行器 @@ -478,9 +479,7 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * @param 请求值类型 * @param 返回值类型 */ - T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; - - T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException; + T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; /** * 注入 {@link WxCpConfigStorage} 的实现 diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java index 522c449f74..4369868f15 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java @@ -14,9 +14,9 @@ import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.URIUtil; -import me.chanjar.weixin.common.util.http.apache.*; +import me.chanjar.weixin.common.util.http.*; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.cp.api.WxCpConfigStorage; import me.chanjar.weixin.cp.api.WxCpService; @@ -41,7 +41,7 @@ import java.util.List; import java.util.UUID; -public class WxCpServiceImpl implements WxCpService { +public class WxCpServiceImpl implements WxCpService, RequestHttp { protected final Logger log = LoggerFactory.getLogger(WxCpServiceImpl.class); @@ -538,7 +538,7 @@ public String post(String url, String postData) throws WxErrorException { * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 */ @Override - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { int retryTimes = 0; do { try { @@ -574,7 +574,7 @@ public T execute(RequestExecutor exec throw new RuntimeException("微信服务端异常,超出重试次数"); } - public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { if (uri.contains("access_token=")) { throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); } @@ -584,7 +584,7 @@ public synchronized T executeInternal(RequestExecutor { * 得到WxMpService * @return */ - WxMpService getWxMpService(); + WxMpService getWxMpService(); /** * 获得卡券api_ticket,不强制刷新卡券api_ticket diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index edaa72c12f..0b96859412 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -2,15 +2,15 @@ import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.apache.MediaUploadRequestExecutor; import me.chanjar.weixin.mp.bean.*; import me.chanjar.weixin.mp.bean.result.*; /** * 微信API的Service */ -public interface WxMpService { +public interface WxMpService { /** *
@@ -133,7 +133,6 @@ public interface WxMpService {
    * 长链接转短链接接口
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=长链接转短链接接口
    * 
- * */ String shortUrl(String long_url) throws WxErrorException; @@ -153,8 +152,8 @@ public interface WxMpService { *
* * @param redirectURI 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode - * @param scope 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可 - * @param state 非必填,用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验 + * @param scope 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可 + * @param state 非必填,用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验 * @return url */ String buildQrConnectUrl(String redirectURI, String scope, String state); @@ -190,7 +189,7 @@ public interface WxMpService { * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以 *
* - * @param lang zh_CN, zh_TW, en + * @param lang zh_CN, zh_TW, en */ WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException; @@ -198,7 +197,6 @@ public interface WxMpService { *
    * 验证oauth2的access token是否有效
    * 
- * */ boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken); @@ -227,15 +225,12 @@ public interface WxMpService { * 可以参考,{@link MediaUploadRequestExecutor}的实现方法 *
*/ - T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; - - T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException; - + T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; - /** - * 获取代理对象 - */ - //HttpHost getHttpProxy(); + /** + * 获取代理对象 + */ + //HttpHost getRequestHttpProxy(); /** * 注入 {@link WxMpConfigStorage} 的实现 @@ -350,15 +345,13 @@ public interface WxMpService { WxMpDeviceService getDeviceService(); /** - * * @return */ - H getHttpclient(); + //Object getHttpclient(); /** - * * @return */ - P getHttpProxy(); + //Object getHttpProxy(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java similarity index 97% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpCardServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java index e9d9c789c0..9e64d0431c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.mp.api.impl.apache; +package me.chanjar.weixin.mp.api.impl; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -10,7 +10,7 @@ import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.http.apache.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; import me.chanjar.weixin.mp.api.WxMpCardService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.result.WxMpCardResult; @@ -30,7 +30,7 @@ public class WxMpCardServiceImpl implements WxMpCardService wxMpService; + private WxMpService wxMpService; public WxMpCardServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; @@ -41,7 +41,7 @@ public WxMpCardServiceImpl(WxMpService wxMpService) { * @return */ @Override - public WxMpService getWxMpService(){ + public WxMpService getWxMpService(){ return this.wxMpService; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java similarity index 96% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpKefuServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java index 9e7685b5a0..4667f32798 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpKefuServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java @@ -1,12 +1,10 @@ -package me.chanjar.weixin.mp.api.impl.jodd; +package me.chanjar.weixin.mp.api.impl; import com.google.gson.JsonObject; -import jodd.http.HttpConnectionProvider; -import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.jodd.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.mp.api.WxMpKefuService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; @@ -29,7 +27,7 @@ public class WxMpKefuServiceImpl implements WxMpKefuService { .getLogger(WxMpKefuServiceImpl.class); private static final String API_URL_PREFIX = "https://api.weixin.qq.com/customservice"; private static final String API_URL_PREFIX_WITH_CGI_BIN = "https://api.weixin.qq.com/cgi-bin/customservice"; - private WxMpService wxMpService; + private WxMpService wxMpService; public WxMpKefuServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java similarity index 94% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpMaterialServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java index f6c48f9af7..4242063bda 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpMaterialServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java @@ -1,19 +1,17 @@ -package me.chanjar.weixin.mp.api.impl.jodd; +package me.chanjar.weixin.mp.api.impl; -import jodd.http.HttpConnectionProvider; -import jodd.http.ProxyInfo; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.jodd.MediaDownloadRequestExecutor; -import me.chanjar.weixin.common.util.http.jodd.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.api.WxMpMaterialService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.material.*; -import me.chanjar.weixin.mp.util.http.jodd.*; +import me.chanjar.weixin.mp.util.http.*; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import java.io.File; @@ -29,7 +27,7 @@ public class WxMpMaterialServiceImpl implements WxMpMaterialService { private static final String MEDIA_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/media"; private static final String MATERIAL_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/material"; - private WxMpService wxMpService; + private WxMpService wxMpService; public WxMpMaterialServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java similarity index 94% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpQrcodeServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java index fba822b3f9..8659f2af9d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpQrcodeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java @@ -1,14 +1,12 @@ -package me.chanjar.weixin.mp.api.impl.jodd; +package me.chanjar.weixin.mp.api.impl; import com.google.gson.JsonObject; -import jodd.http.HttpConnectionProvider; -import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.mp.api.WxMpQrcodeService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; -import me.chanjar.weixin.mp.util.http.jodd.QrCodeRequestExecutor; +import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; import java.io.File; import java.io.UnsupportedEncodingException; @@ -20,7 +18,7 @@ */ public class WxMpQrcodeServiceImpl implements WxMpQrcodeService { private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/qrcode"; - private WxMpService wxMpService; + private WxMpService wxMpService; public WxMpQrcodeServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpUserBlacklistServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java similarity index 87% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpUserBlacklistServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java index f310b3d48f..b0b35343e8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpUserBlacklistServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java @@ -1,11 +1,9 @@ -package me.chanjar.weixin.mp.api.impl.jodd; +package me.chanjar.weixin.mp.api.impl; import com.google.gson.Gson; import com.google.gson.JsonObject; -import jodd.http.HttpConnectionProvider; -import jodd.http.ProxyInfo; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.jodd.SimplePostRequestExecutor; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpUserBlacklistService; import me.chanjar.weixin.mp.bean.result.WxMpUserBlacklistGetResult; @@ -19,7 +17,7 @@ */ public class WxMpUserBlacklistServiceImpl implements WxMpUserBlacklistService { private static final String API_BLACKLIST_PREFIX = "https://api.weixin.qq.com/cgi-bin/tags/members"; - private WxMpService wxMpService; + private WxMpService wxMpService; public WxMpUserBlacklistServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpKefuServiceImpl.java deleted file mode 100644 index 0dc921f140..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpKefuServiceImpl.java +++ /dev/null @@ -1,183 +0,0 @@ -package me.chanjar.weixin.mp.api.impl.apache; - -import com.google.gson.JsonObject; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.apache.MediaUploadRequestExecutor; -import me.chanjar.weixin.mp.api.WxMpKefuService; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; -import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; -import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfSessionRequest; -import me.chanjar.weixin.mp.bean.kefu.result.*; -import org.apache.http.HttpHost; -import org.apache.http.impl.client.CloseableHttpClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.util.Date; - -/** - * - * @author Binary Wang - * - */ -public class WxMpKefuServiceImpl implements WxMpKefuService { - protected final Logger log = LoggerFactory - .getLogger(WxMpKefuServiceImpl.class); - private static final String API_URL_PREFIX = "https://api.weixin.qq.com/customservice"; - private static final String API_URL_PREFIX_WITH_CGI_BIN = "https://api.weixin.qq.com/cgi-bin/customservice"; - private WxMpService wxMpService; - - public WxMpKefuServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } - - @Override - public boolean sendKefuMessage(WxMpKefuMessage message) - throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; - String responseContent = this.wxMpService.post(url, message.toJson()); - return responseContent != null; - } - - @Override - public WxMpKfList kfList() throws WxErrorException { - String url = API_URL_PREFIX_WITH_CGI_BIN + "/getkflist"; - String responseContent = this.wxMpService.get(url, null); - return WxMpKfList.fromJson(responseContent); - } - - @Override - public WxMpKfOnlineList kfOnlineList() throws WxErrorException { - String url = API_URL_PREFIX_WITH_CGI_BIN + "/getonlinekflist"; - String responseContent = this.wxMpService.get(url, null); - return WxMpKfOnlineList.fromJson(responseContent); - } - - @Override - public boolean kfAccountAdd(WxMpKfAccountRequest request) - throws WxErrorException { - String url = API_URL_PREFIX + "/kfaccount/add"; - String responseContent = this.wxMpService.post(url, request.toJson()); - return responseContent != null; - } - - @Override - public boolean kfAccountUpdate(WxMpKfAccountRequest request) - throws WxErrorException { - String url = API_URL_PREFIX + "/kfaccount/update"; - String responseContent = this.wxMpService.post(url, request.toJson()); - return responseContent != null; - } - - @Override - public boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErrorException { - String url = API_URL_PREFIX + "/kfaccount/inviteworker"; - String responseContent = this.wxMpService.post(url, request.toJson()); - return responseContent != null; - } - - @Override - public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) - throws WxErrorException { - String url = API_URL_PREFIX + "/kfaccount/uploadheadimg?kf_account=" + kfAccount; - WxMediaUploadResult responseContent = this.wxMpService - .execute(new MediaUploadRequestExecutor(), url, imgFile); - return responseContent != null; - } - - @Override - public boolean kfAccountDel(String kfAccount) throws WxErrorException { - String url = API_URL_PREFIX + "/kfaccount/del?kf_account=" + kfAccount; - String responseContent = this.wxMpService.get(url, null); - return responseContent != null; - } - - @Override - public boolean kfSessionCreate(String openid, String kfAccount) - throws WxErrorException { - WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid); - String url = API_URL_PREFIX + "/kfsession/create"; - String responseContent = this.wxMpService.post(url, request.toJson()); - return responseContent != null; - } - - @Override - public boolean kfSessionClose(String openid, String kfAccount) - throws WxErrorException { - WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid); - String url = API_URL_PREFIX + "/kfsession/close"; - String responseContent = this.wxMpService.post(url, request.toJson()); - return responseContent != null; - } - - @Override - public WxMpKfSessionGetResult kfSessionGet(String openid) - throws WxErrorException { - String url = API_URL_PREFIX + "/kfsession/getsession?openid=" + openid; - String responseContent = this.wxMpService.get(url, null); - return WxMpKfSessionGetResult.fromJson(responseContent); - } - - @Override - public WxMpKfSessionList kfSessionList(String kfAccount) - throws WxErrorException { - String url = API_URL_PREFIX + "/kfsession/getsessionlist?kf_account=" + kfAccount; - String responseContent = this.wxMpService.get(url, null); - return WxMpKfSessionList.fromJson(responseContent); - } - - @Override - public WxMpKfSessionWaitCaseList kfSessionGetWaitCase() - throws WxErrorException { - String url = API_URL_PREFIX + "/kfsession/getwaitcase"; - String responseContent = this.wxMpService.get(url, null); - return WxMpKfSessionWaitCaseList.fromJson(responseContent); - } - - @Override - public WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer number) throws WxErrorException { - if(number > 10000){ - throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法参数请求,每次最多查询10000条记录!").build()); - } - - if(startTime.after(endTime)){ - throw new WxErrorException(WxError.newBuilder().setErrorMsg("起始时间不能晚于结束时间!").build()); - } - - String url = API_URL_PREFIX + "/msgrecord/getmsglist"; - - JsonObject param = new JsonObject(); - param.addProperty("starttime", startTime.getTime() / 1000); //starttime 起始时间,unix时间戳 - param.addProperty("endtime", endTime.getTime() / 1000); //endtime 结束时间,unix时间戳,每次查询时段不能超过24小时 - param.addProperty("msgid", msgId); //msgid 消息id顺序从小到大,从1开始 - param.addProperty("number", number); //number 每次获取条数,最多10000条 - - String responseContent = this.wxMpService.post(url, param.toString()); - - return WxMpKfMsgList.fromJson(responseContent); - } - - @Override - public WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorException { - int number = 10000; - WxMpKfMsgList result = this.kfMsgList(startTime,endTime, 1L, number); - - if(result != null && result.getNumber() == number){ - Long msgId = result.getMsgId(); - WxMpKfMsgList followingResult = this.kfMsgList(startTime,endTime, msgId, number); - while(followingResult != null && followingResult.getRecords().size() > 0){ - result.getRecords().addAll(followingResult.getRecords()); - result.setNumber(result.getNumber() + followingResult.getNumber()); - result.setMsgId(followingResult.getMsgId()); - followingResult = this.kfMsgList(startTime,endTime, followingResult.getMsgId(), number); - } - } - - return result; - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpMaterialServiceImpl.java deleted file mode 100644 index 13d5a754dc..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpMaterialServiceImpl.java +++ /dev/null @@ -1,168 +0,0 @@ -package me.chanjar.weixin.mp.api.impl.apache; - -import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.apache.MediaDownloadRequestExecutor; -import me.chanjar.weixin.common.util.http.apache.MediaUploadRequestExecutor; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import me.chanjar.weixin.mp.api.WxMpMaterialService; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.material.WxMpMaterial; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialArticleUpdate; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; -import me.chanjar.weixin.mp.bean.material.*; -import me.chanjar.weixin.mp.util.http.apache.*; -import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.http.HttpHost; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * Created by Binary Wang on 2016/7/21. - */ -public class WxMpMaterialServiceImpl implements WxMpMaterialService { - private static final String MEDIA_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/media"; - private static final String MATERIAL_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/material"; - private WxMpService wxMpService; - - public WxMpMaterialServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } - - @Override - public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException { - try { - return this.mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); - } catch (IOException e) { - e.printStackTrace(); - throw new WxErrorException(WxError.newBuilder().setErrorMsg(e.getMessage()).build()); - } - } - - @Override - public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { - String url = MEDIA_API_URL_PREFIX + "/upload?type=" + mediaType; - return this.wxMpService.execute(new MediaUploadRequestExecutor(), url, file); - } - - @Override - public File mediaDownload(String media_id) throws WxErrorException { - String url = MEDIA_API_URL_PREFIX + "/get"; - return this.wxMpService.execute( - new MediaDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), - url, - "media_id=" + media_id); - } - - @Override - public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException { - String url = MEDIA_API_URL_PREFIX + "/uploadimg"; - return this.wxMpService.execute(new MediaImgUploadRequestExecutor(), url, file); - } - - @Override - public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException { - String url = MATERIAL_API_URL_PREFIX + "/add_material?type=" + mediaType; - return this.wxMpService.execute(new MaterialUploadRequestExecutor(), url, material); - } - - @Override - public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException { - if (news == null || news.isEmpty()) { - throw new IllegalArgumentException("news is empty!"); - } - String url = MATERIAL_API_URL_PREFIX + "/add_news"; - String responseContent = this.wxMpService.post(url, news.toJson()); - return WxMpMaterialUploadResult.fromJson(responseContent); - } - - @Override - public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException { - String url = MATERIAL_API_URL_PREFIX + "/get_material"; - return this.wxMpService.execute(new MaterialVoiceAndImageDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, media_id); - } - - @Override - public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException { - String url = MATERIAL_API_URL_PREFIX + "/get_material"; - return this.wxMpService.execute(new MaterialVideoInfoRequestExecutor(), url, media_id); - } - - @Override - public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException { - String url = MATERIAL_API_URL_PREFIX + "/get_material"; - return this.wxMpService.execute(new MaterialNewsInfoRequestExecutor(), url, media_id); - } - - @Override - public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException { - String url = MATERIAL_API_URL_PREFIX + "/update_news"; - String responseText = this.wxMpService.post(url, wxMpMaterialArticleUpdate.toJson()); - WxError wxError = WxError.fromJson(responseText); - if (wxError.getErrorCode() == 0) { - return true; - } else { - throw new WxErrorException(wxError); - } - } - - @Override - public boolean materialDelete(String media_id) throws WxErrorException { - String url = MATERIAL_API_URL_PREFIX + "/del_material"; - return this.wxMpService.execute(new MaterialDeleteRequestExecutor(), url, media_id); - } - - @Override - public WxMpMaterialCountResult materialCount() throws WxErrorException { - String url = MATERIAL_API_URL_PREFIX + "/get_materialcount"; - String responseText = this.wxMpService.get(url, null); - WxError wxError = WxError.fromJson(responseText); - if (wxError.getErrorCode() == 0) { - return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialCountResult.class); - } else { - throw new WxErrorException(wxError); - } - } - - @Override - public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException { - String url = MATERIAL_API_URL_PREFIX + "/batchget_material"; - Map params = new HashMap<>(); - params.put("type", WxConsts.MATERIAL_NEWS); - params.put("offset", offset); - params.put("count", count); - String responseText = this.wxMpService.post(url, WxGsonBuilder.create().toJson(params)); - WxError wxError = WxError.fromJson(responseText); - if (wxError.getErrorCode() == 0) { - return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialNewsBatchGetResult.class); - } else { - throw new WxErrorException(wxError); - } - } - - @Override - public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException { - String url = MATERIAL_API_URL_PREFIX + "/batchget_material"; - Map params = new HashMap<>(); - params.put("type", type); - params.put("offset", offset); - params.put("count", count); - String responseText = this.wxMpService.post(url, WxGsonBuilder.create().toJson(params)); - WxError wxError = WxError.fromJson(responseText); - if (wxError.getErrorCode() == 0) { - return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialFileBatchGetResult.class); - } else { - throw new WxErrorException(wxError); - } - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpQrcodeServiceImpl.java deleted file mode 100644 index 5db81fe1bb..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpQrcodeServiceImpl.java +++ /dev/null @@ -1,120 +0,0 @@ -package me.chanjar.weixin.mp.api.impl.apache; - -import com.google.gson.JsonObject; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.mp.api.WxMpQrcodeService; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; -import me.chanjar.weixin.mp.util.http.apache.QrCodeRequestExecutor; -import org.apache.http.HttpHost; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.File; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - -/** - * Created by Binary Wang on 2016/7/21. - */ -public class WxMpQrcodeServiceImpl implements WxMpQrcodeService { - private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/qrcode"; - private WxMpService wxMpService; - - public WxMpQrcodeServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } - - @Override - public WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds) throws WxErrorException { - if (sceneId == 0) { - throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("临时二维码场景值不能为0!").build()); - } - - //expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。 - if (expireSeconds != null && expireSeconds > 2592000) { - throw new WxErrorException(WxError.newBuilder().setErrorCode(-1) - .setErrorMsg("临时二维码有效时间最大不能超过2592000(即30天)!").build()); - } - - if (expireSeconds == null) { - expireSeconds = 30; - } - - String url = API_URL_PREFIX + "/create"; - JsonObject json = new JsonObject(); - json.addProperty("action_name", "QR_SCENE"); - json.addProperty("expire_seconds", expireSeconds); - - JsonObject actionInfo = new JsonObject(); - JsonObject scene = new JsonObject(); - scene.addProperty("scene_id", sceneId); - actionInfo.add("scene", scene); - json.add("action_info", actionInfo); - String responseContent = this.wxMpService.post(url, json.toString()); - return WxMpQrCodeTicket.fromJson(responseContent); - } - - @Override - public WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorException { - if (sceneId < 1 || sceneId > 100000) { - throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("永久二维码的场景值目前只支持1--100000!").build()); - } - - String url = API_URL_PREFIX + "/create"; - JsonObject json = new JsonObject(); - json.addProperty("action_name", "QR_LIMIT_SCENE"); - JsonObject actionInfo = new JsonObject(); - JsonObject scene = new JsonObject(); - scene.addProperty("scene_id", sceneId); - actionInfo.add("scene", scene); - json.add("action_info", actionInfo); - String responseContent = this.wxMpService.post(url, json.toString()); - return WxMpQrCodeTicket.fromJson(responseContent); - } - - @Override - public WxMpQrCodeTicket qrCodeCreateLastTicket(String sceneStr) throws WxErrorException { - String url = API_URL_PREFIX + "/create"; - JsonObject json = new JsonObject(); - json.addProperty("action_name", "QR_LIMIT_STR_SCENE"); - JsonObject actionInfo = new JsonObject(); - JsonObject scene = new JsonObject(); - scene.addProperty("scene_str", sceneStr); - actionInfo.add("scene", scene); - json.add("action_info", actionInfo); - String responseContent = this.wxMpService.post(url, json.toString()); - return WxMpQrCodeTicket.fromJson(responseContent); - } - - @Override - public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException { - String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode"; - return this.wxMpService.execute(new QrCodeRequestExecutor(), url, ticket); - } - - @Override - public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException { - String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s"; - try { - String resultUrl = String.format(url, - URLEncoder.encode(ticket, StandardCharsets.UTF_8.name())); - if (needShortUrl) { - return this.wxMpService.shortUrl(resultUrl); - } - - return resultUrl; - } catch (UnsupportedEncodingException e) { - WxError error = WxError.newBuilder().setErrorCode(-1) - .setErrorMsg(e.getMessage()).build(); - throw new WxErrorException(error); - } - } - - @Override - public String qrCodePictureUrl(String ticket) throws WxErrorException { - return qrCodePictureUrl(ticket, false); - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java index 75a6bd9616..5e6f863a93 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java @@ -12,12 +12,9 @@ import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.URIUtil; +import me.chanjar.weixin.common.util.http.*; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; -import me.chanjar.weixin.common.util.http.apache.SimpleGetRequestExecutor; -import me.chanjar.weixin.common.util.http.apache.SimplePostRequestExecutor; import me.chanjar.weixin.mp.api.*; import me.chanjar.weixin.mp.api.impl.*; import me.chanjar.weixin.mp.bean.*; @@ -34,7 +31,7 @@ import java.io.IOException; import java.util.concurrent.locks.Lock; -public class WxMpServiceImpl implements WxMpService { +public class WxMpServiceImpl implements WxMpService,RequestHttp { private static final JsonParser JSON_PARSER = new JsonParser(); @@ -248,8 +245,8 @@ public String buildQrConnectUrl(String redirectURI, String scope, private WxMpOAuth2AccessToken getOAuth2AccessToken(StringBuilder url) throws WxErrorException { try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(this.getHttpclient(), this.httpProxy, url.toString(), null); + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(this, url.toString(), null); return WxMpOAuth2AccessToken.fromJson(responseText); } catch (IOException e) { throw new RuntimeException(e); @@ -292,8 +289,8 @@ public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, Strin } try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(getHttpclient(), this.httpProxy, url.toString(), null); + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(this, url.toString(), null); return WxMpUser.fromJson(responseText); } catch (IOException e) { throw new RuntimeException(e); @@ -308,8 +305,8 @@ public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken url.append("&openid=").append(oAuth2AccessToken.getOpenId()); try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - executor.execute(getHttpclient(), this.httpProxy, url.toString(), null); + RequestExecutor executor = new SimpleGetRequestExecutor(); + executor.execute(this, url.toString(), null); } catch (IOException e) { throw new RuntimeException(e); } catch (WxErrorException e) { @@ -345,7 +342,7 @@ public String post(String url, String postData) throws WxErrorException { * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 */ @Override - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { int retryTimes = 0; do { try { @@ -379,8 +376,7 @@ public T execute(RequestExecutor exe throw new RuntimeException("微信服务端异常,超出重试次数"); } - @Override - public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { if (uri.indexOf("access_token=") != -1) { throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); } @@ -390,7 +386,7 @@ public synchronized T executeInternal(RequestExecutor wxMpService; - - public WxMpUserBlacklistServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } - - @Override - public WxMpUserBlacklistGetResult getBlacklist(String nextOpenid) throws WxErrorException { - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("begin_openid", nextOpenid); - String url = API_BLACKLIST_PREFIX + "/getblacklist"; - String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, jsonObject.toString()); - return WxMpUserBlacklistGetResult.fromJson(responseContent); - } - - @Override - public void pushToBlacklist(List openidList) throws WxErrorException { - Map map = new HashMap<>(); - map.put("openid_list", openidList); - String url = API_BLACKLIST_PREFIX + "/batchblacklist"; - this.wxMpService.execute(new SimplePostRequestExecutor(), url, new Gson().toJson(map)); - } - - @Override - public void pullFromBlacklist(List openidList) throws WxErrorException { - Map map = new HashMap<>(); - map.put("openid_list", openidList); - String url = API_BLACKLIST_PREFIX + "/batchunblacklist"; - this.wxMpService.execute(new SimplePostRequestExecutor(), url, new Gson().toJson(map)); - } -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpCardServiceImpl.java deleted file mode 100644 index 0789b7eaf4..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpCardServiceImpl.java +++ /dev/null @@ -1,251 +0,0 @@ -package me.chanjar.weixin.mp.api.impl.jodd; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonPrimitive; -import com.google.gson.reflect.TypeToken; -import jodd.http.HttpConnectionProvider; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.bean.WxCardApiSignature; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.RandomUtils; -import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.http.jodd.SimpleGetRequestExecutor; -import me.chanjar.weixin.mp.api.WxMpCardService; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.result.WxMpCardResult; -import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Arrays; -import java.util.concurrent.locks.Lock; - -/** - * Created by Binary Wang on 2016/7/27. - */ -public class WxMpCardServiceImpl implements WxMpCardService { - - private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class); - - private WxMpService wxMpService; - - public WxMpCardServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } - - /** - * 得到WxMpService - * @return - */ - @Override - public WxMpService getWxMpService(){ - return this.wxMpService; - } - - /** - * 获得卡券api_ticket,不强制刷新卡券api_ticket - * - * @return 卡券api_ticket - * @see #getCardApiTicket(boolean) - */ - @Override - public String getCardApiTicket() throws WxErrorException { - return getCardApiTicket(false); - } - - /** - *
-   * 获得卡券api_ticket
-   * 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
-   *
-   * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
-   * .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94
-   * .9F.E6.88.90.E7.AE.97.E6.B3.95
-   * 
- * - * @param forceRefresh 强制刷新 - * @return 卡券api_ticket - */ - @Override - public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { - Lock lock = getWxMpService().getWxMpConfigStorage().getCardApiTicketLock(); - try { - lock.lock(); - - if (forceRefresh) { - this.getWxMpService().getWxMpConfigStorage().expireCardApiTicket(); - } - - if (this.getWxMpService().getWxMpConfigStorage().isCardApiTicketExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; - String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); - int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.getWxMpService().getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); - } - } finally { - lock.unlock(); - } - return this.getWxMpService().getWxMpConfigStorage().getCardApiTicket(); - } - - /** - *
-   * 创建调用卡券api时所需要的签名
-   *
-   * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
-   * .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94
-   * .9F.E6.88.90.E7.AE.97.E6.B3.95
-   * 
- * - * @param optionalSignParam 参与签名的参数数组。 - * 可以为下列字段:app_id, card_id, card_type, code, openid, location_id - *
注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空 - * @return 卡券Api签名对象 - */ - @Override - public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws - WxErrorException { - long timestamp = System.currentTimeMillis() / 1000; - String nonceStr = RandomUtils.getRandomStr(); - String cardApiTicket = getCardApiTicket(false); - - String[] signParam = Arrays.copyOf(optionalSignParam, optionalSignParam.length + 3); - signParam[optionalSignParam.length] = String.valueOf(timestamp); - signParam[optionalSignParam.length + 1] = nonceStr; - signParam[optionalSignParam.length + 2] = cardApiTicket; - String signature = SHA1.gen(signParam); - WxCardApiSignature cardApiSignature = new WxCardApiSignature(); - cardApiSignature.setTimestamp(timestamp); - cardApiSignature.setNonceStr(nonceStr); - cardApiSignature.setSignature(signature); - return cardApiSignature; - } - - /** - * 卡券Code解码 - * - * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 - * @return 解密后的Code - */ - @Override - public String decryptCardCode(String encryptCode) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/code/decrypt"; - JsonObject param = new JsonObject(); - param.addProperty("encrypt_code", encryptCode); - String responseContent = this.wxMpService.post(url, param.toString()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - JsonPrimitive jsonPrimitive = tmpJsonObject.getAsJsonPrimitive("code"); - return jsonPrimitive.getAsString(); - } - - /** - * 卡券Code查询 - * - * @param cardId 卡券ID代表一类卡券 - * @param code 单张卡券的唯一标准 - * @param checkConsume 是否校验code核销状态,填入true和false时的code异常状态返回数据不同 - * @return WxMpCardResult对象 - */ - @Override - public WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/code/get"; - JsonObject param = new JsonObject(); - param.addProperty("card_id", cardId); - param.addProperty("code", code); - param.addProperty("check_consume", checkConsume); - String responseContent = this.wxMpService.post(url, param.toString()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, - new TypeToken() { - }.getType()); - } - - /** - * 卡券Code核销。核销失败会抛出异常 - * - * @param code 单张卡券的唯一标准 - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 - */ - @Override - public String consumeCardCode(String code) throws WxErrorException { - return consumeCardCode(code, null); - } - - /** - * 卡券Code核销。核销失败会抛出异常 - * - * @param code 单张卡券的唯一标准 - * @param cardId 当自定义Code卡券时需要传入card_id - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 - */ - @Override - public String consumeCardCode(String code, String cardId) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/code/consume"; - JsonObject param = new JsonObject(); - param.addProperty("code", code); - - if (cardId != null && !"".equals(cardId)) { - param.addProperty("card_id", cardId); - } - - return this.wxMpService.post(url, param.toString()); - } - - /** - * 卡券Mark接口。 - * 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住), - * 才能进一步调用核销接口,否则报错。 - * - * @param code 卡券的code码 - * @param cardId 卡券的ID - * @param openId 用券用户的openid - * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 - */ - @Override - public void markCardCode(String code, String cardId, String openId, boolean isMark) throws - WxErrorException { - String url = "https://api.weixin.qq.com/card/code/mark"; - JsonObject param = new JsonObject(); - param.addProperty("code", code); - param.addProperty("card_id", cardId); - param.addProperty("openid", openId); - param.addProperty("is_mark", isMark); - String responseContent = this.getWxMpService().post(url, param.toString()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - WxMpCardResult cardResult = WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, - new TypeToken() { }.getType()); - if (!cardResult.getErrorCode().equals("0")) { - this.log.warn("朋友的券mark失败:{}", cardResult.getErrorMsg()); - } - } - - @Override - public String getCardDetail(String cardId) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/get"; - JsonObject param = new JsonObject(); - param.addProperty("card_id", cardId); - String responseContent = this.wxMpService.post(url, param.toString()); - - // 判断返回值 - JsonObject json = (new JsonParser()).parse(responseContent).getAsJsonObject(); - String errcode = json.get("errcode").getAsString(); - if (!"0".equals(errcode)) { - String errmsg = json.get("errmsg").getAsString(); - WxError error = new WxError(); - error.setErrorCode(Integer.valueOf(errcode)); - error.setErrorMsg(errmsg); - throw new WxErrorException(error); - } - - return responseContent; - } -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java index 1480270ca3..fa342f66dd 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java @@ -14,10 +14,7 @@ import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.URIUtil; -import me.chanjar.weixin.common.util.http.jodd.SimpleGetRequestExecutor; -import me.chanjar.weixin.common.util.http.jodd.SimplePostRequestExecutor; +import me.chanjar.weixin.common.util.http.*; import me.chanjar.weixin.mp.api.*; import me.chanjar.weixin.mp.api.impl.*; import me.chanjar.weixin.mp.bean.*; @@ -28,7 +25,7 @@ import java.io.IOException; import java.util.concurrent.locks.Lock; -public class WxMpServiceImpl implements WxMpService { +public class WxMpServiceImpl implements WxMpService,RequestHttp { private static final JsonParser JSON_PARSER = new JsonParser(); @@ -248,8 +245,8 @@ public String buildQrConnectUrl(String redirectURI, String scope, private WxMpOAuth2AccessToken getOAuth2AccessToken(StringBuilder url) throws WxErrorException { try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(getHttpclient(), getHttpProxy(), url.toString(), null); + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(this, url.toString(), null); return WxMpOAuth2AccessToken.fromJson(responseText); } catch (IOException e) { throw new RuntimeException(e); @@ -292,8 +289,8 @@ public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, Strin } try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(getHttpclient(), getHttpProxy(), url.toString(), null); + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(this, url.toString(), null); return WxMpUser.fromJson(responseText); } catch (IOException e) { throw new RuntimeException(e); @@ -308,8 +305,8 @@ public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken url.append("&openid=").append(oAuth2AccessToken.getOpenId()); try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - executor.execute(getHttpclient(), getHttpProxy(), url.toString(), null); + RequestExecutor executor = new SimpleGetRequestExecutor(); + executor.execute(this, url.toString(), null); } catch (IOException e) { throw new RuntimeException(e); } catch (WxErrorException e) { @@ -341,15 +338,20 @@ public String post(String url, String postData) throws WxErrorException { return execute(new SimplePostRequestExecutor(), url, postData); } - @Override + //@Override public HttpConnectionProvider getHttpclient() { return this.httpClient; } + //@Override + public Object getHttpProxy() { + return null; + } + /** * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 */ - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { int retryTimes = 0; do { try { @@ -383,8 +385,7 @@ public T execute(RequestExecutor throw new RuntimeException("微信服务端异常,超出重试次数"); } - @Override - public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { if (uri.indexOf("access_token=") != -1) { throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); } @@ -394,7 +395,7 @@ public synchronized T executeInternal(RequestExecutor params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return true; + } + } finally { + httpPost.releaseConnection(); + } + } + + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java new file mode 100644 index 0000000000..8718006724 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java @@ -0,0 +1,93 @@ +package me.chanjar.weixin.mp.util.http; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class MaterialNewsInfoRequestExecutor implements RequestExecutor { + + public MaterialNewsInfoRequestExecutor() { + super(); + } + + @Override + public WxMpMaterialNews execute(RequestHttp requestHttp, String uri, + String materialId) throws WxErrorException, IOException { + if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); + return executeApache(httpClient, httpProxy, uri, materialId); + } + if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); + return executeJodd(provider, proxyInfo, uri, materialId); + } else { + //这里需要抛出异常,需要优化 + return null; + } + } + + public WxMpMaterialNews executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + } + } finally { + httpPost.releaseConnection(); + } + } + + + public WxMpMaterialNews executeJodd(HttpConnectionProvider httpclient, ProxyInfo httpProxy, String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + httpclient.useProxy(httpProxy); + } + request.withConnectionProvider(httpclient); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + + String responseContent = request.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java new file mode 100644 index 0000000000..a1e1a91bd3 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java @@ -0,0 +1,121 @@ +package me.chanjar.weixin.mp.util.http; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Map; + +public class MaterialUploadRequestExecutor implements RequestExecutor { + + @Override + public WxMpMaterialUploadResult execute(RequestHttp requestHttp, String uri, WxMpMaterial material) throws WxErrorException, IOException { + if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); + return executeApache(httpClient, httpProxy, uri, material); + } + if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); + return executeJodd(provider, proxyInfo, uri, material); + } else { + //这里需要抛出异常,需要优化 + return null; + } + } + + private WxMpMaterialUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, WxMpMaterial material) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + provider.useProxy(httpProxy); + } + request.withConnectionProvider(provider); + + if (material == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); + } + + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + request.form("media", file); + Map form = material.getForm(); + if (material.getForm() != null) { + request.form("description", WxGsonBuilder.create().toJson(form)); + } + + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialUploadResult.fromJson(responseContent); + } + } + + private WxMpMaterialUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + WxMpMaterial material) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (httpProxy != null) { + RequestConfig response = RequestConfig.custom().setProxy(httpProxy).build(); + httpPost.setConfig(response); + } + + if (material == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); + } + + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + + MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); + multipartEntityBuilder + .addBinaryBody("media", file) + .setMode(HttpMultipartMode.RFC6532); + Map form = material.getForm(); + if (material.getForm() != null) { + multipartEntityBuilder.addTextBody("description", WxGsonBuilder.create().toJson(form)); + } + + httpPost.setEntity(multipartEntityBuilder.build()); + httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); + + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialUploadResult.fromJson(responseContent); + } + } finally { + httpPost.releaseConnection(); + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java new file mode 100644 index 0000000000..fb5818926e --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java @@ -0,0 +1,92 @@ +package me.chanjar.weixin.mp.util.http; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class MaterialVideoInfoRequestExecutor implements RequestExecutor { + + public MaterialVideoInfoRequestExecutor() { + super(); + } + + @Override + public WxMpMaterialVideoInfoResult execute(RequestHttp requestHttp, String uri, String materialId) throws WxErrorException, IOException { + if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); + return executeApache(httpClient, httpProxy, uri, materialId); + } + if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); + return executeJodd(provider, proxyInfo, uri, materialId); + } else { + //这里需要抛出异常,需要优化 + return null; + } + } + + + private WxMpMaterialVideoInfoResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (proxyInfo != null) { + provider.useProxy(proxyInfo); + } + request.withConnectionProvider(provider); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); + } + } + + private WxMpMaterialVideoInfoResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); + } + } finally { + httpPost.releaseConnection(); + } + } + + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java new file mode 100644 index 0000000000..913ca0862f --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java @@ -0,0 +1,117 @@ +package me.chanjar.weixin.mp.util.http; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +public class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { + + + public MaterialVoiceAndImageDownloadRequestExecutor() { + super(); + } + + public MaterialVoiceAndImageDownloadRequestExecutor(File tmpDirFile) { + super(); + } + + @Override + public InputStream execute(RequestHttp requestHttp, String uri, String materialId) throws WxErrorException, IOException { + if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); + return executeApache(httpClient, httpProxy, uri, materialId); + } + if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); + return executeJodd(provider, proxyInfo, uri, materialId); + } else { + //这里需要抛出异常,需要优化 + return null; + } + } + + private InputStream executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (proxyInfo != null) { + provider.useProxy(proxyInfo); + } + request.withConnectionProvider(provider); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { + // 下载媒体文件出错 + byte[] responseContent = IOUtils.toByteArray(inputStream); + String responseContentString = new String(responseContent, "UTF-8"); + if (responseContentString.length() < 100) { + try { + WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); + if (wxError.getErrorCode() != 0) { + throw new WxErrorException(wxError); + } + } catch (com.google.gson.JsonSyntaxException ex) { + return new ByteArrayInputStream(responseContent); + } + } + return new ByteArrayInputStream(responseContent); + } + + } + + private InputStream executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = httpclient.execute(httpPost); + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + // 下载媒体文件出错 + byte[] responseContent = IOUtils.toByteArray(inputStream); + String responseContentString = new String(responseContent, "UTF-8"); + if (responseContentString.length() < 100) { + try { + WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); + if (wxError.getErrorCode() != 0) { + throw new WxErrorException(wxError); + } + } catch (com.google.gson.JsonSyntaxException ex) { + return new ByteArrayInputStream(responseContent); + } + } + return new ByteArrayInputStream(responseContent); + } finally { + httpPost.releaseConnection(); + } + } + + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java new file mode 100644 index 0000000000..c22bc31098 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java @@ -0,0 +1,103 @@ +package me.chanjar.weixin.mp.util.http; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.IOException; + +/** + * @author miller + */ +public class MediaImgUploadRequestExecutor implements RequestExecutor { + + @Override + public WxMediaImgUploadResult execute(RequestHttp requestHttp, String uri, File data) throws WxErrorException, IOException { + if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); + return executeApache(httpClient, httpProxy, uri, data); + } + if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); + return executeJodd(provider, proxyInfo, uri, data); + } else { + //这里需要抛出异常,需要优化 + return null; + } + + } + + + private WxMediaImgUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, File data) throws WxErrorException, IOException { + if (data == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); + } + + HttpRequest request = HttpRequest.post(uri); + if (proxyInfo != null) { + provider.useProxy(proxyInfo); + } + request.withConnectionProvider(provider); + + request.form("media", data); + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + + return WxMediaImgUploadResult.fromJson(responseContent); + } + + private WxMediaImgUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + File data) throws WxErrorException, IOException { + if (data == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); + } + + HttpPost httpPost = new HttpPost(uri); + if (httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); + httpPost.setConfig(config); + } + + HttpEntity entity = MultipartEntityBuilder + .create() + .addBinaryBody("media", data) + .setMode(HttpMultipartMode.RFC6532) + .build(); + httpPost.setEntity(entity); + httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); + + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + + return WxMediaImgUploadResult.fromJson(responseContent); + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java new file mode 100644 index 0000000000..c9ae525c29 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java @@ -0,0 +1,116 @@ +package me.chanjar.weixin.mp.util.http; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.MimeTypes; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; + +/** + * 获得QrCode图片 请求执行器 + * + * @author chanjarster + */ +public class QrCodeRequestExecutor implements RequestExecutor { + + @Override + public File execute(RequestHttp requestHttp, String uri, + WxMpQrCodeTicket ticket) throws WxErrorException, IOException { + if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); + return executeApache(httpClient, httpProxy, uri, ticket); + } + if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); + return executeJodd(provider, proxyInfo, uri, ticket); + } else { + //这里需要抛出异常,需要优化 + return null; + } + } + + private File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, WxMpQrCodeTicket ticket) throws WxErrorException, IOException { + if (ticket != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") + ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") + : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); + } + + HttpRequest request = HttpRequest.get(uri); + if (proxyInfo != null) { + provider.useProxy(proxyInfo); + } + request.withConnectionProvider(provider); + + HttpResponse response = request.send(); + String contentTypeHeader = response.header("Content-Type"); + if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { + String responseContent = response.bodyText(); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } + } + + private File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + WxMpQrCodeTicket ticket) throws WxErrorException, IOException { + if (ticket != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") + ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") + : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); + } + + HttpGet httpGet = new HttpGet(uri); + if (httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = httpclient.execute(httpGet); + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0) { + // 出错 + if (ContentType.TEXT_PLAIN.getMimeType().equals(contentTypeHeader[0].getValue())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + } + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } finally { + httpGet.releaseConnection(); + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialDeleteRequestExecutor.java deleted file mode 100644 index b25d668dda..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialDeleteRequestExecutor.java +++ /dev/null @@ -1,50 +0,0 @@ -package me.chanjar.weixin.mp.util.http.apache; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -public class MaterialDeleteRequestExecutor implements RequestExecutor { - - - public MaterialDeleteRequestExecutor() { - super(); - } - - @Override - public Boolean execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try(CloseableHttpResponse response = httpclient.execute(httpPost)){ - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return true; - } - }finally { - httpPost.releaseConnection(); - } - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialNewsInfoRequestExecutor.java deleted file mode 100644 index f29de11f9b..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialNewsInfoRequestExecutor.java +++ /dev/null @@ -1,52 +0,0 @@ -package me.chanjar.weixin.mp.util.http.apache; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; -import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -public class MaterialNewsInfoRequestExecutor implements RequestExecutor { - - public MaterialNewsInfoRequestExecutor() { - super(); - } - - @Override - public WxMpMaterialNews execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try(CloseableHttpResponse response = httpclient.execute(httpPost)){ - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); - } - }finally { - httpPost.releaseConnection(); - } - - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialUploadRequestExecutor.java deleted file mode 100644 index d0c16f2dd7..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialUploadRequestExecutor.java +++ /dev/null @@ -1,68 +0,0 @@ -package me.chanjar.weixin.mp.util.http.apache; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import me.chanjar.weixin.mp.bean.material.WxMpMaterial; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.HttpMultipartMode; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Map; - -public class MaterialUploadRequestExecutor implements RequestExecutor { - - @Override - public WxMpMaterialUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, WxMpMaterial material) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig response = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(response); - } - - if (material == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); - } - - File file = material.getFile(); - if (file == null || !file.exists()) { - throw new FileNotFoundException(); - } - - MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); - multipartEntityBuilder - .addBinaryBody("media", file) - .setMode(HttpMultipartMode.RFC6532); - Map form = material.getForm(); - if (material.getForm() != null) { - multipartEntityBuilder.addTextBody("description", WxGsonBuilder.create().toJson(form)); - } - - httpPost.setEntity(multipartEntityBuilder.build()); - httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); - - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialUploadResult.fromJson(responseContent); - } - } finally { - httpPost.releaseConnection(); - } - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVideoInfoRequestExecutor.java deleted file mode 100644 index 1617675533..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVideoInfoRequestExecutor.java +++ /dev/null @@ -1,50 +0,0 @@ -package me.chanjar.weixin.mp.util.http.apache; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -public class MaterialVideoInfoRequestExecutor implements RequestExecutor { - - public MaterialVideoInfoRequestExecutor() { - super(); - } - - @Override - public WxMpMaterialVideoInfoResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try(CloseableHttpResponse response = httpclient.execute(httpPost)){ - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialVideoInfoResult.fromJson(responseContent); - } - }finally { - httpPost.releaseConnection(); - } - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVoiceAndImageDownloadRequestExecutor.java deleted file mode 100644 index 3a29ccfaa8..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MaterialVoiceAndImageDownloadRequestExecutor.java +++ /dev/null @@ -1,66 +0,0 @@ -package me.chanjar.weixin.mp.util.http.apache; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -public class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { - - - public MaterialVoiceAndImageDownloadRequestExecutor() { - super(); - } - - public MaterialVoiceAndImageDownloadRequestExecutor(File tmpDirFile) { - super(); - } - - @Override - public InputStream execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try (CloseableHttpResponse response = httpclient.execute(httpPost); - InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);){ - // 下载媒体文件出错 - byte[] responseContent = IOUtils.toByteArray(inputStream); - String responseContentString = new String(responseContent, "UTF-8"); - if (responseContentString.length() < 100) { - try { - WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); - if (wxError.getErrorCode() != 0) { - throw new WxErrorException(wxError); - } - } catch (com.google.gson.JsonSyntaxException ex) { - return new ByteArrayInputStream(responseContent); - } - } - return new ByteArrayInputStream(responseContent); - }finally { - httpPost.releaseConnection(); - } - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MediaImgUploadRequestExecutor.java deleted file mode 100644 index e253f4eeb9..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/MediaImgUploadRequestExecutor.java +++ /dev/null @@ -1,55 +0,0 @@ -package me.chanjar.weixin.mp.util.http.apache; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; -import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.HttpMultipartMode; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.File; -import java.io.IOException; - -/** - * @author miller - */ -public class MediaImgUploadRequestExecutor implements RequestExecutor { - @Override - public WxMediaImgUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File data) throws WxErrorException, IOException { - if (data == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); - } - - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - HttpEntity entity = MultipartEntityBuilder - .create() - .addBinaryBody("media", data) - .setMode(HttpMultipartMode.RFC6532) - .build(); - httpPost.setEntity(entity); - httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); - - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - - return WxMediaImgUploadResult.fromJson(responseContent); - } - } -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/QrCodeRequestExecutor.java deleted file mode 100644 index b0823365b3..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/QrCodeRequestExecutor.java +++ /dev/null @@ -1,66 +0,0 @@ -package me.chanjar.weixin.mp.util.http.apache; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; -import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; -import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; -import org.apache.http.Header; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.entity.ContentType; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URLEncoder; -import java.util.UUID; - -/** - * 获得QrCode图片 请求执行器 - * @author chanjarster - * - */ -public class QrCodeRequestExecutor implements RequestExecutor { - - @Override - public File execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - WxMpQrCodeTicket ticket) throws WxErrorException, IOException { - if (ticket != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") - ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") - : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); - } - - HttpGet httpGet = new HttpGet(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpGet.setConfig(config); - } - - try (CloseableHttpResponse response = httpclient.execute(httpGet); - InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { - Header[] contentTypeHeader = response.getHeaders("Content-Type"); - if (contentTypeHeader != null && contentTypeHeader.length > 0) { - // 出错 - if (ContentType.TEXT_PLAIN.getMimeType().equals(contentTypeHeader[0].getValue())) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - throw new WxErrorException(WxError.fromJson(responseContent)); - } - } - return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); - } finally { - httpGet.releaseConnection(); - } - - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialDeleteRequestExecutor.java deleted file mode 100644 index 26485742e2..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialDeleteRequestExecutor.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.chanjar.weixin.mp.util.http.jodd; - -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; - -import java.io.IOException; - -public class MaterialDeleteRequestExecutor implements RequestExecutor { - - - public MaterialDeleteRequestExecutor() { - super(); - } - - @Override - public Boolean execute(HttpConnectionProvider httpclient, ProxyInfo httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (httpProxy != null) { - httpclient.useProxy(httpProxy); - } - request.withConnectionProvider(httpclient); - - request.query("media_id", materialId); - HttpResponse response = request.send(); - String responseContent = response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return true; - } - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialNewsInfoRequestExecutor.java deleted file mode 100644 index 93b3a73505..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialNewsInfoRequestExecutor.java +++ /dev/null @@ -1,41 +0,0 @@ -package me.chanjar.weixin.mp.util.http.jodd; - -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; -import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; - -import java.io.IOException; - -public class MaterialNewsInfoRequestExecutor implements RequestExecutor { - - public MaterialNewsInfoRequestExecutor() { - super(); - } - - @Override - public WxMpMaterialNews execute(HttpConnectionProvider httpclient, ProxyInfo httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (httpProxy != null) { - httpclient.useProxy(httpProxy); - } - request.withConnectionProvider(httpclient); - - request.query("media_id", materialId); - HttpResponse response = request.send(); - - String responseContent = request.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); - } - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialUploadRequestExecutor.java deleted file mode 100644 index 85b6665ee5..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialUploadRequestExecutor.java +++ /dev/null @@ -1,53 +0,0 @@ -package me.chanjar.weixin.mp.util.http.jodd; - -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import me.chanjar.weixin.mp.bean.material.WxMpMaterial; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Map; - -public class MaterialUploadRequestExecutor implements RequestExecutor { - - @Override - public WxMpMaterialUploadResult execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, WxMpMaterial material) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (httpProxy != null) { - provider.useProxy(httpProxy); - } - request.withConnectionProvider(provider); - - if (material == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); - } - - File file = material.getFile(); - if (file == null || !file.exists()) { - throw new FileNotFoundException(); - } - request.form("media", file); - Map form = material.getForm(); - if (material.getForm() != null) { - request.form("description", WxGsonBuilder.create().toJson(form)); - } - - HttpResponse response = request.send(); - String responseContent = response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialUploadResult.fromJson(responseContent); - } - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVideoInfoRequestExecutor.java deleted file mode 100644 index 7b7272b749..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVideoInfoRequestExecutor.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.chanjar.weixin.mp.util.http.jodd; - -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; - -import java.io.IOException; - -public class MaterialVideoInfoRequestExecutor implements RequestExecutor { - - public MaterialVideoInfoRequestExecutor() { - super(); - } - - @Override - public WxMpMaterialVideoInfoResult execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (httpProxy != null) { - provider.useProxy(httpProxy); - } - request.withConnectionProvider(provider); - - request.query("media_id", materialId); - HttpResponse response =request.send(); - String responseContent = response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialVideoInfoResult.fromJson(responseContent); - } - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVoiceAndImageDownloadRequestExecutor.java deleted file mode 100644 index 4d988bad7b..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MaterialVoiceAndImageDownloadRequestExecutor.java +++ /dev/null @@ -1,57 +0,0 @@ -package me.chanjar.weixin.mp.util.http.jodd; - -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import org.apache.commons.io.IOUtils; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; - -public class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { - - - public MaterialVoiceAndImageDownloadRequestExecutor() { - super(); - } - - public MaterialVoiceAndImageDownloadRequestExecutor(File tmpDirFile) { - super(); - } - - @Override - public InputStream execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (httpProxy != null) { - provider.useProxy(httpProxy); - } - request.withConnectionProvider(provider); - - request.query("media_id", materialId); - HttpResponse response = request.send(); - - InputStream inputStream = new ByteArrayInputStream(response.bodyBytes()); - // 下载媒体文件出错 - byte[] responseContent = IOUtils.toByteArray(inputStream); - String responseContentString = new String(responseContent, "UTF-8"); - if (responseContentString.length() < 100) { - try { - WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); - if (wxError.getErrorCode() != 0) { - throw new WxErrorException(wxError); - } - } catch (com.google.gson.JsonSyntaxException ex) { - return new ByteArrayInputStream(responseContent); - } - } - return new ByteArrayInputStream(responseContent); - } - -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MediaImgUploadRequestExecutor.java deleted file mode 100644 index 7c4b13f962..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/MediaImgUploadRequestExecutor.java +++ /dev/null @@ -1,42 +0,0 @@ -package me.chanjar.weixin.mp.util.http.jodd; - -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; - -import java.io.File; -import java.io.IOException; - -/** - * @author miller - */ -public class MediaImgUploadRequestExecutor implements RequestExecutor { - @Override - public WxMediaImgUploadResult execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, File data) throws WxErrorException, IOException { - if (data == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); - } - - HttpRequest request = HttpRequest.post(uri); - if (httpProxy != null) { - provider.useProxy(httpProxy); - } - request.withConnectionProvider(provider); - - request.form("media", data); - HttpResponse response =request.send(); - - String responseContent =response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - - return WxMediaImgUploadResult.fromJson(responseContent); - } -} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/QrCodeRequestExecutor.java deleted file mode 100644 index d1b6f2c550..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/QrCodeRequestExecutor.java +++ /dev/null @@ -1,60 +0,0 @@ -package me.chanjar.weixin.mp.util.http.jodd; - -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; -import jodd.util.MimeTypes; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URLEncoder; -import java.util.UUID; - -/** - * 获得QrCode图片 请求执行器 - * - * @author chanjarster - */ -public class QrCodeRequestExecutor implements RequestExecutor { - - @Override - public File execute(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, - WxMpQrCodeTicket ticket) throws WxErrorException, IOException { - if (ticket != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") - ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") - : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); - } - - - HttpRequest request = HttpRequest.get(uri); - if (httpProxy != null) { - provider.useProxy(httpProxy); - } - request.withConnectionProvider(provider); - - HttpResponse response = request.send(); - try ( - InputStream inputStream = new ByteArrayInputStream(response.bodyBytes());) { - String contentTypeHeader = response.header("Content-Type"); - // 出错 - if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { - String responseContent = response.bodyText(); - throw new WxErrorException(WxError.fromJson(responseContent)); - } - return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); - } - } - -} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java index 25dedbaa77..74777caef0 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java @@ -4,8 +4,6 @@ import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl; -import org.apache.http.HttpHost; -import org.apache.http.impl.client.CloseableHttpClient; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -23,7 +21,7 @@ public Object[][] getService() { @Override public synchronized T executeInternal( - RequestExecutor executor, String uri, E data) + RequestExecutor executor, String uri, E data) throws WxErrorException { this.log.info("Executed"); WxError error = new WxError(); From b03cb4b783bb7ea5fce3f9f1610bd26de596f4a2 Mon Sep 17 00:00:00 2001 From: ecoolper Date: Sat, 22 Apr 2017 20:11:57 +0800 Subject: [PATCH 010/179] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weixin-java-common/pom.xml | 5 +++++ .../http/MediaDownloadRequestExecutor.java | 22 ++++++++++++++++++- .../util/http/MediaUploadRequestExecutor.java | 20 +++++++++++++++++ .../weixin/common/util/http/RequestHttp.java | 4 ++-- .../util/http/SimpleGetRequestExecutor.java | 20 +++++++++++++++++ .../util/http/SimplePostRequestExecutor.java | 20 +++++++++++++++++ 6 files changed, 88 insertions(+), 3 deletions(-) diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 946c65c24e..29c2ec4c63 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -39,6 +39,11 @@ jetty-servlet test + + org.jodd + jodd-http + 3.7 + diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java index a61c54a7ef..b69438fa0c 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java @@ -85,6 +85,16 @@ private String getFileNameApache(CloseableHttpResponse response) throws WxErrorE } + /** + * apache-http实现方式 + * @param httpclient + * @param httpProxy + * @param uri + * @param queryParam + * @return + * @throws WxErrorException + * @throws IOException + */ private File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { if (queryParam != null) { if (uri.indexOf('?') == -1) { @@ -127,6 +137,16 @@ private File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, S } + /** + * jodd-http实现方式 + * @param provider + * @param proxyInfo + * @param uri + * @param queryParam + * @return + * @throws WxErrorException + * @throws IOException + */ private File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { if (queryParam != null) { if (uri.indexOf('?') == -1) { @@ -135,7 +155,7 @@ private File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, S uri += uri.endsWith("?") ? queryParam : '&' + queryParam; } - HttpRequest request = HttpRequest.post(uri); + HttpRequest request = HttpRequest.get(uri); if (proxyInfo != null) { provider.useProxy(proxyInfo); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java index 6dd49b3ea6..d5957d7fb5 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java @@ -47,6 +47,16 @@ public WxMediaUploadResult execute(RequestHttp requestHttp, String uri, File fil } + /** + * apache-http实现方式 + * @param httpclient + * @param httpProxy + * @param uri + * @param file + * @return + * @throws WxErrorException + * @throws IOException + */ private WxMediaUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File file) throws WxErrorException, IOException { HttpPost httpPost = new HttpPost(uri); if (httpProxy != null) { @@ -75,6 +85,16 @@ private WxMediaUploadResult executeApache(CloseableHttpClient httpclient, HttpHo } + /** + * jodd-http实现方式 + * @param provider + * @param proxyInfo + * @param uri + * @param file + * @return + * @throws WxErrorException + * @throws IOException + */ private WxMediaUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, File file) throws WxErrorException, IOException { HttpRequest request = HttpRequest.post(uri); if (proxyInfo != null) { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java index 68ee1f2f91..02225d46dd 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java @@ -6,13 +6,13 @@ public interface RequestHttp { /** - * httpClient + * 返回httpClient * @return */ Object getRequestHttpClient(); /** - * httpProxy + * 返回httpProxy * @return */ Object getRequestHttpProxy(); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java index e3460016d0..cb414d2bc8 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java @@ -40,6 +40,16 @@ public String execute(RequestHttp requestHttp, String uri, String queryParam) th } + /** + * apache-http实现方式 + * @param httpclient + * @param httpProxy + * @param uri + * @param queryParam + * @return + * @throws WxErrorException + * @throws IOException + */ private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { if (queryParam != null) { if (uri.indexOf('?') == -1) { @@ -66,6 +76,16 @@ private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, } + /** + * jodd-http实现方式 + * @param provider + * @param proxyInfo + * @param uri + * @param queryParam + * @return + * @throws WxErrorException + * @throws IOException + */ private String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { if (queryParam != null) { if (uri.indexOf('?') == -1) { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java index f35385de70..f687328935 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java @@ -42,6 +42,16 @@ public String execute(RequestHttp requestHttp, String uri, String postEntity) th } } + /** + * apache-http实现方式 + * @param httpclient + * @param httpProxy + * @param uri + * @param postEntity + * @return + * @throws WxErrorException + * @throws IOException + */ private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String postEntity) throws WxErrorException, IOException { HttpPost httpPost = new HttpPost(uri); if (httpProxy != null) { @@ -78,6 +88,16 @@ private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, } + /** + * jodd-http实现方式 + * @param provider + * @param proxyInfo + * @param uri + * @param postEntity + * @return + * @throws WxErrorException + * @throws IOException + */ private String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String postEntity) throws WxErrorException, IOException { HttpRequest request = HttpRequest.post(uri); if (proxyInfo != null) { From fe61393e3e8f09cf7e73fe504229dfbe2a3e9a5a Mon Sep 17 00:00:00 2001 From: ecoolper Date: Sat, 22 Apr 2017 20:28:04 +0800 Subject: [PATCH 011/179] =?UTF-8?q?=E5=B0=91=E6=8F=90=E4=BA=A4=E4=B8=80?= =?UTF-8?q?=E4=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cp/api/impl/jodd/WxCpServiceImpl.java | 686 ++++++++++++++++++ 1 file changed, 686 insertions(+) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java new file mode 100644 index 0000000000..8c41f04211 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java @@ -0,0 +1,686 @@ +package me.chanjar.weixin.cp.api.impl.jodd; + +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; +import jodd.http.*; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.menu.WxMenu; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.StandardSessionManager; +import me.chanjar.weixin.common.session.WxSession; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.RandomUtils; +import me.chanjar.weixin.common.util.crypto.SHA1; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.api.WxCpConfigStorage; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpDepart; +import me.chanjar.weixin.cp.bean.WxCpMessage; +import me.chanjar.weixin.cp.bean.WxCpTag; +import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.UUID; + +public class WxCpServiceImpl implements WxCpService, RequestHttp { + + protected final Logger log = LoggerFactory.getLogger(WxCpServiceImpl.class); + + /** + * 全局的是否正在刷新access token的锁 + */ + protected final Object globalAccessTokenRefreshLock = new Object(); + + /** + * 全局的是否正在刷新jsapi_ticket的锁 + */ + protected final Object globalJsapiTicketRefreshLock = new Object(); + + protected WxCpConfigStorage configStorage; + + protected HttpConnectionProvider httpClient; + + protected ProxyInfo httpProxy; + protected WxSessionManager sessionManager = new StandardSessionManager(); + /** + * 临时文件目录 + */ + protected File tmpDirFile; + private int retrySleepMillis = 1000; + private int maxRetryTimes = 5; + + @Override + public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) { + try { + return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data) + .equals(msgSignature); + } catch (Exception e) { + return false; + } + } + + @Override + public void userAuthenticated(String userId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId; + get(url, null); + } + + @Override + public String getAccessToken() throws WxErrorException { + return getAccessToken(false); + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + if (forceRefresh) { + this.configStorage.expireAccessToken(); + } + if (this.configStorage.isAccessTokenExpired()) { + synchronized (this.globalAccessTokenRefreshLock) { + if (this.configStorage.isAccessTokenExpired()) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" + + "&corpid=" + this.configStorage.getCorpId() + + "&corpsecret=" + this.configStorage.getCorpSecret(); + + HttpRequest request = HttpRequest.get(url); + if (this.httpProxy != null) { + httpClient.useProxy(this.httpProxy); + } + request.withConnectionProvider(httpClient); + HttpResponse response = request.send(); + + String resultContent = response.bodyText(); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.configStorage.updateAccessToken( + accessToken.getAccessToken(), accessToken.getExpiresIn()); + } + } + } + return this.configStorage.getAccessToken(); + } + + @Override + public String getJsapiTicket() throws WxErrorException { + return getJsapiTicket(false); + } + + @Override + public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { + if (forceRefresh) { + this.configStorage.expireJsapiTicket(); + } + if (this.configStorage.isJsapiTicketExpired()) { + synchronized (this.globalJsapiTicketRefreshLock) { + if (this.configStorage.isJsapiTicketExpired()) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket"; + String responseContent = execute(new SimpleGetRequestExecutor(), url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + this.configStorage.updateJsapiTicket(jsapiTicket, + expiresInSeconds); + } + } + } + return this.configStorage.getJsapiTicket(); + } + + @Override + public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { + long timestamp = System.currentTimeMillis() / 1000; + String noncestr = RandomUtils.getRandomStr(); + String jsapiTicket = getJsapiTicket(false); + String signature = SHA1.genWithAmple( + "jsapi_ticket=" + jsapiTicket, + "noncestr=" + noncestr, + "timestamp=" + timestamp, + "url=" + url + ); + WxJsapiSignature jsapiSignature = new WxJsapiSignature(); + jsapiSignature.setTimestamp(timestamp); + jsapiSignature.setNonceStr(noncestr); + jsapiSignature.setUrl(url); + jsapiSignature.setSignature(signature); + + // Fixed bug + jsapiSignature.setAppId(this.configStorage.getCorpId()); + + return jsapiSignature; + } + + @Override + public void messageSend(WxCpMessage message) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"; + post(url, message.toJson()); + } + + @Override + public void menuCreate(WxMenu menu) throws WxErrorException { + menuCreate(this.configStorage.getAgentId(), menu); + } + + @Override + public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" + + this.configStorage.getAgentId(); + post(url, menu.toJson()); + } + + @Override + public void menuDelete() throws WxErrorException { + menuDelete(this.configStorage.getAgentId()); + } + + @Override + public void menuDelete(Integer agentId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId; + get(url, null); + } + + @Override + public WxMenu menuGet() throws WxErrorException { + return menuGet(this.configStorage.getAgentId()); + } + + @Override + public WxMenu menuGet(Integer agentId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId; + try { + String resultContent = get(url, null); + return WxMenu.fromJson(resultContent); + } catch (WxErrorException e) { + // 46003 不存在的菜单数据 + if (e.getError().getErrorCode() == 46003) { + return null; + } + throw e; + } + } + + @Override + public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) + throws WxErrorException, IOException { + return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); + } + + @Override + public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; + return execute(new MediaUploadRequestExecutor(), url, file); + } + + @Override + public File mediaDownload(String mediaId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; + return execute( + new MediaDownloadRequestExecutor( + this.configStorage.getTmpDirFile()), + url, "media_id=" + mediaId); + } + + + @Override + public Integer departCreate(WxCpDepart depart) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; + String responseContent = execute( + new SimplePostRequestExecutor(), + url, + depart.toJson()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id")); + } + + @Override + public void departUpdate(WxCpDepart group) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update"; + post(url, group.toJson()); + } + + @Override + public void departDelete(Integer departId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId; + get(url, null); + } + + @Override + public List departGet() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; + String responseContent = get(url, null); + /* + * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } + * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } + */ + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("department"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public void userCreate(WxCpUser user) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; + post(url, user.toJson()); + } + + @Override + public void userUpdate(WxCpUser user) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; + post(url, user.toJson()); + } + + @Override + public void userDelete(String userid) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userid; + get(url, null); + } + + @Override + public void userDelete(String[] userids) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; + JsonObject jsonObject = new JsonObject(); + JsonArray jsonArray = new JsonArray(); + for (String userid : userids) { + jsonArray.add(new JsonPrimitive(userid)); + } + jsonObject.add("useridlist", jsonArray); + post(url, jsonObject.toString()); + } + + @Override + public WxCpUser userGet(String userid) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid; + String responseContent = get(url, null); + return WxCpUser.fromJson(responseContent); + } + + @Override + public List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; + String params = ""; + if (fetchChild != null) { + params += "&fetch_child=" + (fetchChild ? "1" : "0"); + } + if (status != null) { + params += "&status=" + status; + } else { + params += "&status=0"; + } + + String responseContent = get(url, params); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; + String params = ""; + if (fetchChild != null) { + params += "&fetch_child=" + (fetchChild ? "1" : "0"); + } + if (status != null) { + params += "&status=" + status; + } else { + params += "&status=0"; + } + + String responseContent = get(url, params); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public String tagCreate(String tagName) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; + JsonObject o = new JsonObject(); + o.addProperty("tagname", tagName); + String responseContent = post(url, o.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("tagid").getAsString(); + } + + @Override + public void tagUpdate(String tagId, String tagName) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; + JsonObject o = new JsonObject(); + o.addProperty("tagid", tagId); + o.addProperty("tagname", tagName); + post(url, o.toString()); + } + + @Override + public void tagDelete(String tagId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; + get(url, null); + } + + @Override + public List tagGet() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; + String responseContent = get(url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("taglist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public List tagGetUsers(String tagId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; + String responseContent = get(url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public void tagAddUsers(String tagId, List userIds, List partyIds) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + if (userIds != null) { + JsonArray jsonArray = new JsonArray(); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("userlist", jsonArray); + } + if (partyIds != null) { + JsonArray jsonArray = new JsonArray(); + for (String userId : partyIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("partylist", jsonArray); + } + post(url, jsonObject.toString()); + } + + @Override + public void tagRemoveUsers(String tagId, List userIds) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + JsonArray jsonArray = new JsonArray(); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("userlist", jsonArray); + post(url, jsonObject.toString()); + } + + @Override + public String oauth2buildAuthorizationUrl(String state) { + return this.oauth2buildAuthorizationUrl( + this.configStorage.getOauth2redirectUri(), + state + ); + } + + @Override + public String oauth2buildAuthorizationUrl(String redirectUri, String state) { + String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"; + url += "appid=" + this.configStorage.getCorpId(); + url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri); + url += "&response_type=code"; + url += "&scope=snsapi_base"; + if (state != null) { + url += "&state=" + state; + } + url += "#wechat_redirect"; + return url; + } + + @Override + public String[] oauth2getUserInfo(String code) throws WxErrorException { + return oauth2getUserInfo(this.configStorage.getAgentId(), code); + } + + @Override + public String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?" + + "code=" + code + + "&agentid=" + agentId; + String responseText = get(url, null); + JsonElement je = new JsonParser().parse(responseText); + JsonObject jo = je.getAsJsonObject(); + return new String[]{GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId"), GsonHelper.getString(jo, "OpenId")}; + } + + @Override + public int invite(String userId, String inviteTips) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/invite/send"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("userid", userId); + if (StringUtils.isNotEmpty(inviteTips)) { + jsonObject.addProperty("invite_tips", inviteTips); + } + String responseContent = post(url, jsonObject.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("type").getAsInt(); + } + + @Override + public String[] getCallbackIp() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip"; + String responseContent = get(url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); + String[] ips = new String[jsonArray.size()]; + for (int i = 0; i < jsonArray.size(); i++) { + ips[i] = jsonArray.get(i).getAsString(); + } + return ips; + } + + @Override + public String get(String url, String queryParam) throws WxErrorException { + return execute(new SimpleGetRequestExecutor(), url, queryParam); + } + + @Override + public String post(String url, String postData) throws WxErrorException { + return execute(new SimplePostRequestExecutor(), url, postData); + } + + /** + * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 + */ + @Override + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + int retryTimes = 0; + do { + try { + T result = this.executeInternal(executor, uri, data); + this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, result); + return result; + } catch (WxErrorException e) { + if (retryTimes + 1 > this.maxRetryTimes) { + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + //最后一次重试失败后,直接抛出异常,不再等待 + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + WxError error = e.getError(); + /* + * -1 系统繁忙, 1000ms后重试 + */ + if (error.getErrorCode() == -1) { + int sleepMillis = this.retrySleepMillis * (1 << retryTimes); + try { + this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + Thread.sleep(sleepMillis); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + } else { + throw e; + } + } + } while (retryTimes++ < this.maxRetryTimes); + + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + if (uri.contains("access_token=")) { + throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); + } + String accessToken = getAccessToken(false); + + String uriWithAccessToken = uri; + uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; + + try { + return executor.execute(this, uriWithAccessToken, data); + } catch (WxErrorException e) { + WxError error = e.getError(); + /* + * 发生以下情况时尝试刷新access_token + * 40001 获取access_token时AppSecret错误,或者access_token无效 + * 42001 access_token超时 + */ + if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { + // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token + this.configStorage.expireAccessToken(); + return execute(executor, uri, data); + } + + if (error.getErrorCode() != 0) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); + throw new WxErrorException(error); + } + return null; + } catch (IOException e) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); + throw new RuntimeException(e); + } + } + + protected HttpConnectionProvider getHttpclient() { + return this.httpClient; + } + + @Override + public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) { + this.configStorage = wxConfigProvider; + + if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) { + httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + } + + httpClient = JoddHttp.httpConnectionProvider; + } + + @Override + public void setRetrySleepMillis(int retrySleepMillis) { + this.retrySleepMillis = retrySleepMillis; + } + + + @Override + public void setMaxRetryTimes(int maxRetryTimes) { + this.maxRetryTimes = maxRetryTimes; + } + + @Override + public WxSession getSession(String id) { + if (this.sessionManager == null) { + return null; + } + return this.sessionManager.getSession(id); + } + + @Override + public WxSession getSession(String id, boolean create) { + if (this.sessionManager == null) { + return null; + } + return this.sessionManager.getSession(id, create); + } + + + @Override + public void setSessionManager(WxSessionManager sessionManager) { + this.sessionManager = sessionManager; + } + + @Override + public String replaceParty(String mediaId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("media_id", mediaId); + return post(url, jsonObject.toString()); + } + + @Override + public String replaceUser(String mediaId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("media_id", mediaId); + return post(url, jsonObject.toString()); + } + + @Override + public String getTaskResult(String joinId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?jobid=" + joinId; + return get(url, null); + } + + public File getTmpDirFile() { + return this.tmpDirFile; + } + + public void setTmpDirFile(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + + @Override + public Object getRequestHttpClient() { + return this.httpClient; + } + + @Override + public Object getRequestHttpProxy() { + return this.httpProxy; + } +} From 2019115b677a1288c55a94d244214ff5c3e44342 Mon Sep 17 00:00:00 2001 From: ecoolper Date: Sat, 22 Apr 2017 20:29:21 +0800 Subject: [PATCH 012/179] =?UTF-8?q?gradle=E9=85=8D=E7=BD=AE=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- settings.gradle | 4 +++- weixin-java-pay/build.gradle | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 weixin-java-pay/build.gradle diff --git a/settings.gradle b/settings.gradle index 1c0e0214c4..0ff1d35b7c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,9 @@ rootProject.name = 'weixin-java-parent' include ':weixin-java-common' include ':weixin-java-cp' include ':weixin-java-mp' +include ':weixin-java-pay' project(':weixin-java-common').projectDir = "$rootDir/weixin-java-common" as File project(':weixin-java-cp').projectDir = "$rootDir/weixin-java-cp" as File -project(':weixin-java-mp').projectDir = "$rootDir/weixin-java-mp" as File \ No newline at end of file +project(':weixin-java-mp').projectDir = "$rootDir/weixin-java-mp" as File +project(':weixin-java-pay').projectDir = "$rootDir/weixin-java-pay" as File diff --git a/weixin-java-pay/build.gradle b/weixin-java-pay/build.gradle new file mode 100644 index 0000000000..2f0c7e9a87 --- /dev/null +++ b/weixin-java-pay/build.gradle @@ -0,0 +1,12 @@ +description = 'WeiXin Java Tools - PAY' +dependencies { + compile project(':weixin-java-common') + testCompile group: 'junit', name: 'junit', version: '4.11' + testCompile group: 'org.testng', name: 'testng', version: '6.8.7' + testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5' + testCompile group: 'com.google.inject', name: 'guice', version: '3.0' + testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.0.RC0' + testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.3.0.RC0' + testCompile group: 'joda-time', name: 'joda-time', version: '2.9.4' +} +test.useTestNG() From dbf0a1505bc304db231a9e4466870d6d8dd97aef Mon Sep 17 00:00:00 2001 From: ecoolper Date: Mon, 24 Apr 2017 23:18:08 +0800 Subject: [PATCH 013/179] =?UTF-8?q?weixin-java-parent=20pom.xml=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0jodd-http?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pom.xml b/pom.xml index 2447fd71d4..c185f037dc 100644 --- a/pom.xml +++ b/pom.xml @@ -110,6 +110,17 @@ + + org.jodd + jodd-http + 3.7 + + + + com.squareup.okhttp3 + okhttp + 3.7.0 + org.slf4j slf4j-api From 49f9787e98d5c551811fa6308952b2fb8d0113cd Mon Sep 17 00:00:00 2001 From: ecoolper Date: Thu, 27 Apr 2017 18:27:01 +0800 Subject: [PATCH 014/179] =?UTF-8?q?1=E3=80=81=E6=8F=90=E5=8F=96=E4=BA=86?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E4=BB=A3=E7=A0=81=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?AbstractWxMPService=E3=80=81AbstractWxCPService=E7=B1=BB=202?= =?UTF-8?q?=E3=80=81=E5=AE=9E=E7=8E=B0=E4=BA=86okhttp=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=203=E3=80=81RequestExecute=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0executeApache=E3=80=81executeJodd=E3=80=81exe?= =?UTF-8?q?cuteOkhttp=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weixin-java-common/pom.xml | 5 - .../util/http/AbstractRequestExecutor.java | 43 +++++++ .../http/MediaDownloadRequestExecutor.java | 116 +++++++++++++---- .../util/http/MediaUploadRequestExecutor.java | 76 ++++++++---- .../common/util/http/RequestExecutor.java | 44 +++++++ .../weixin/common/util/http/RequestHttp.java | 6 +- .../util/http/SimpleGetRequestExecutor.java | 81 ++++++++---- .../util/http/SimplePostRequestExecutor.java | 74 ++++++++--- .../util/http/okhttp/OkhttpProxyInfo.java | 117 ++++++++++++++++++ 9 files changed, 464 insertions(+), 98 deletions(-) create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkhttpProxyInfo.java diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 29c2ec4c63..946c65c24e 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -39,11 +39,6 @@ jetty-servlet test - - org.jodd - jodd-http - 3.7 - diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java new file mode 100644 index 0000000000..23881e6635 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java @@ -0,0 +1,43 @@ +package me.chanjar.weixin.common.util.http; + +import java.io.IOException; + +import org.apache.http.HttpHost; +import org.apache.http.impl.client.CloseableHttpClient; + +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import okhttp3.ConnectionPool; + +/** + * Created by ecoolper on 2017/4/27. + */ +public abstract class AbstractRequestExecutor implements RequestExecutor { + + @Override + public T execute(RequestHttp requestHttp, String uri, E data) throws WxErrorException, IOException{ + if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { + //apache-http请求 + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); + return executeApache(httpClient, httpProxy, uri, data); + } + if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { + //jodd-http请求 + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); + return executeJodd(provider, proxyInfo, uri, data); + } else if (requestHttp.getRequestHttpClient() instanceof ConnectionPool) { + //okhttp请求 + ConnectionPool pool = (ConnectionPool) requestHttp.getRequestHttpClient(); + OkhttpProxyInfo proxyInfo = (OkhttpProxyInfo) requestHttp.getRequestHttpProxy(); + return executeOkhttp(pool, proxyInfo, uri, data); + } else { + //TODO 这里需要抛出异常,需要优化 + return null; + } + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java index b69438fa0c..e95f02de24 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java @@ -5,10 +5,14 @@ import jodd.http.HttpResponse; import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import okhttp3.*; + import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpHost; @@ -22,6 +26,8 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.InetSocketAddress; +import java.net.Proxy; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -31,7 +37,7 @@ * * @author Daniel Qian */ -public class MediaDownloadRequestExecutor implements RequestExecutor { +public class MediaDownloadRequestExecutor extends AbstractRequestExecutor { private File tmpDirFile; @@ -39,24 +45,7 @@ public MediaDownloadRequestExecutor(File tmpDirFile) { this.tmpDirFile = tmpDirFile; } - @Override - public File execute(RequestHttp requestHttp, String uri, String queryParam) throws WxErrorException, IOException { - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, queryParam); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, queryParam); - } else { - //这里需要抛出异常,需要优化 - return null; - } - } - - private String getFileNameJodd(HttpResponse response) throws WxErrorException { + private String getFileName(HttpResponse response) throws WxErrorException { String content = response.header("Content-disposition"); if (content == null || content.length() == 0) { throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); @@ -70,15 +59,15 @@ private String getFileNameJodd(HttpResponse response) throws WxErrorException { throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); } - private String getFileNameApache(CloseableHttpResponse response) throws WxErrorException { + private String getFileName(CloseableHttpResponse response) throws WxErrorException { Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); - if(contentDispositionHeader == null || contentDispositionHeader.length == 0){ + if (contentDispositionHeader == null || contentDispositionHeader.length == 0) { throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); } Pattern p = Pattern.compile(".*filename=\"(.*)\""); Matcher m = p.matcher(contentDispositionHeader[0].getValue()); - if(m.matches()){ + if (m.matches()) { return m.group(1); } throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); @@ -87,6 +76,7 @@ private String getFileNameApache(CloseableHttpResponse response) throws WxErrorE /** * apache-http实现方式 + * * @param httpclient * @param httpProxy * @param uri @@ -95,7 +85,7 @@ private String getFileNameApache(CloseableHttpResponse response) throws WxErrorE * @throws WxErrorException * @throws IOException */ - private File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { + public File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { if (queryParam != null) { if (uri.indexOf('?') == -1) { uri += '?'; @@ -112,7 +102,6 @@ private File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, S try (CloseableHttpResponse response = httpclient.execute(httpGet); InputStream inputStream = InputStreamResponseHandler.INSTANCE .handleResponse(response)) { - Header[] contentTypeHeader = response.getHeaders("Content-Type"); if (contentTypeHeader != null && contentTypeHeader.length > 0) { if (contentTypeHeader[0].getValue().startsWith(ContentType.APPLICATION_JSON.getMimeType())) { @@ -122,7 +111,7 @@ private File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, S } } - String fileName = getFileNameApache(response); + String fileName = getFileName(response); if (StringUtils.isBlank(fileName)) { return null; } @@ -139,6 +128,7 @@ private File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, S /** * jodd-http实现方式 + * * @param provider * @param proxyInfo * @param uri @@ -147,7 +137,7 @@ private File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, S * @throws WxErrorException * @throws IOException */ - private File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { + public File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { if (queryParam != null) { if (uri.indexOf('?') == -1) { uri += '?'; @@ -160,6 +150,7 @@ private File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, S provider.useProxy(proxyInfo); } request.withConnectionProvider(provider); + HttpResponse response = request.send(); String contentType = response.header("Content-Type"); if (contentType != null && contentType.startsWith("application/json")) { @@ -167,7 +158,7 @@ private File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, S throw new WxErrorException(WxError.fromJson(response.bodyText())); } - String fileName = getFileNameJodd(response); + String fileName = getFileName(response); if (StringUtils.isBlank(fileName)) { return null; } @@ -178,4 +169,75 @@ private File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, S } + /** + * okhttp现实方式 + * + * @param pool + * @param proxyInfo + * @param uri + * @param queryParam + * @return + * @throws WxErrorException + * @throws IOException + */ + public File executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + Request request = new Request.Builder().url(uri).get().build(); + + Response response = client.newCall(request).execute(); + + String contentType = response.header("Content-Type"); + if (contentType != null && contentType.startsWith("application/json")) { + // application/json; encoding=utf-8 下载媒体文件出错 + throw new WxErrorException(WxError.fromJson(response.body().toString())); + } + + String fileName = getFileName(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + + InputStream inputStream = new ByteArrayInputStream(response.body().bytes()); + String[] nameAndExt = fileName.split("\\."); + return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); + } + + private String getFileName(Response response) throws WxErrorException { + String content = response.header("Content-disposition"); + if (content == null || content.length() == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(content); + if (m.matches()) { + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java index d5957d7fb5..da3ebfff13 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java @@ -8,6 +8,9 @@ import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import okhttp3.*; + import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -20,35 +23,19 @@ import java.io.File; import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; /** * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String * * @author Daniel Qian */ -public class MediaUploadRequestExecutor implements RequestExecutor { - - @Override - public WxMediaUploadResult execute(RequestHttp requestHttp, String uri, File file) throws WxErrorException, IOException { - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, file); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, file); - } else { - //这里需要抛出异常,需要优化 - return null; - } - - - } +public class MediaUploadRequestExecutor extends AbstractRequestExecutor { /** * apache-http实现方式 + * * @param httpclient * @param httpProxy * @param uri @@ -57,7 +44,7 @@ public WxMediaUploadResult execute(RequestHttp requestHttp, String uri, File fil * @throws WxErrorException * @throws IOException */ - private WxMediaUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File file) throws WxErrorException, IOException { + public WxMediaUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File file) throws WxErrorException, IOException { HttpPost httpPost = new HttpPost(uri); if (httpProxy != null) { RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); @@ -87,6 +74,7 @@ private WxMediaUploadResult executeApache(CloseableHttpClient httpclient, HttpHo /** * jodd-http实现方式 + * * @param provider * @param proxyInfo * @param uri @@ -95,7 +83,7 @@ private WxMediaUploadResult executeApache(CloseableHttpClient httpclient, HttpHo * @throws WxErrorException * @throws IOException */ - private WxMediaUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, File file) throws WxErrorException, IOException { + public WxMediaUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, File file) throws WxErrorException, IOException { HttpRequest request = HttpRequest.post(uri); if (proxyInfo != null) { provider.useProxy(proxyInfo); @@ -112,4 +100,48 @@ private WxMediaUploadResult executeJodd(HttpConnectionProvider provider, ProxyIn } + /** + * okhttp现实方式 + * + * @param pool + * @param proxyInfo + * @param uri + * @param file + * @return + * @throws WxErrorException + * @throws IOException + */ + public WxMediaUploadResult executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, File file) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); + RequestBody body = new MultipartBody.Builder().addFormDataPart("media", null, fileBody).build(); + Request request = new Request.Builder().url(uri).post(body).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().toString(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMediaUploadResult.fromJson(responseContent); + } + + } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java index 78834701e7..c91a354c07 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java @@ -1,9 +1,16 @@ package me.chanjar.weixin.common.util.http; +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import okhttp3.ConnectionPool; import java.io.IOException; +import org.apache.http.HttpHost; +import org.apache.http.impl.client.CloseableHttpClient; + /** * http请求执行器 * @@ -20,4 +27,41 @@ public interface RequestExecutor { */ T execute(RequestHttp requestHttp, String uri, E data) throws WxErrorException, IOException; + /** + * apache-http实现方式 + * @param httpclient + * @param httpProxy + * @param uri + * @param data + * @return + * @throws WxErrorException + * @throws IOException + */ + T executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, E data) throws WxErrorException, IOException; + + /** + * jodd-http实现方式 + * @param provider + * @param proxyInfo + * @param uri + * @param data + * @return + * @throws WxErrorException + * @throws IOException + */ + T executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, E data) throws WxErrorException, IOException; + + + /** okhttp实现方式 + * @param pool + * @param proxyInfo + * @param uri + * @param data + * @return + * @throws WxErrorException + * @throws IOException + */ + T executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, E data) throws WxErrorException, IOException; + + } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java index 02225d46dd..5af68e0710 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java @@ -3,18 +3,18 @@ /** * Created by ecoolper on 2017/4/22. */ -public interface RequestHttp { +public interface RequestHttp { /** * 返回httpClient * @return */ - Object getRequestHttpClient(); + H getRequestHttpClient(); /** * 返回httpProxy * @return */ - Object getRequestHttpProxy(); + P getRequestHttpProxy(); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java index cb414d2bc8..50beb29f0c 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java @@ -7,6 +7,9 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import okhttp3.*; + import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -14,34 +17,20 @@ import org.apache.http.impl.client.CloseableHttpClient; import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.util.concurrent.TimeUnit; /** * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String * * @author Daniel Qian */ -public class SimpleGetRequestExecutor implements RequestExecutor { - - @Override - public String execute(RequestHttp requestHttp, String uri, String queryParam) throws WxErrorException, IOException { - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, queryParam); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, queryParam); - } else { - //这里需要抛出异常,需要优化 - return null; - } - } - +public class SimpleGetRequestExecutor extends AbstractRequestExecutor { /** * apache-http实现方式 + * * @param httpclient * @param httpProxy * @param uri @@ -50,7 +39,7 @@ public String execute(RequestHttp requestHttp, String uri, String queryParam) th * @throws WxErrorException * @throws IOException */ - private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { + public String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { if (queryParam != null) { if (uri.indexOf('?') == -1) { uri += '?'; @@ -78,6 +67,7 @@ private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, /** * jodd-http实现方式 + * * @param provider * @param proxyInfo * @param uri @@ -86,7 +76,7 @@ private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, * @throws WxErrorException * @throws IOException */ - private String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { + public String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { if (queryParam != null) { if (uri.indexOf('?') == -1) { uri += '?'; @@ -108,4 +98,53 @@ private String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, return responseContent; } + /** + * okHttp实现方式 + * + * @param pool + * @param proxyInfo + * @param uri + * @param queryParam + * @return + * @throws WxErrorException + * @throws IOException + */ + public String executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client =clientBuilder.build(); + + Request request = new Request.Builder().url(uri).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().toString(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + + } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java index f687328935..28ca7cb724 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java @@ -7,6 +7,9 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import okhttp3.*; + import org.apache.http.Consts; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -23,27 +26,11 @@ * * @author Daniel Qian */ -public class SimplePostRequestExecutor implements RequestExecutor { - - @Override - public String execute(RequestHttp requestHttp, String uri, String postEntity) throws WxErrorException, IOException { - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, postEntity); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, postEntity); - } else { - //这里需要抛出异常,需要优化 - return null; - } - } +public class SimplePostRequestExecutor extends AbstractRequestExecutor { /** * apache-http实现方式 + * * @param httpclient * @param httpProxy * @param uri @@ -52,7 +39,7 @@ public String execute(RequestHttp requestHttp, String uri, String postEntity) th * @throws WxErrorException * @throws IOException */ - private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String postEntity) throws WxErrorException, IOException { + public String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String postEntity) throws WxErrorException, IOException { HttpPost httpPost = new HttpPost(uri); if (httpProxy != null) { RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); @@ -90,6 +77,7 @@ private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, /** * jodd-http实现方式 + * * @param provider * @param proxyInfo * @param uri @@ -98,7 +86,7 @@ private String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, * @throws WxErrorException * @throws IOException */ - private String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String postEntity) throws WxErrorException, IOException { + public String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String postEntity) throws WxErrorException, IOException { HttpRequest request = HttpRequest.post(uri); if (proxyInfo != null) { provider.useProxy(proxyInfo); @@ -129,4 +117,50 @@ private String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, } + /** + * okHttp实现方式 + * + * @param pool + * @param proxyInfo + * @param uri + * @param postEntity + * @return + * @throws WxErrorException + * @throws IOException + */ + public String executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String postEntity) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + + MediaType mediaType = MediaType.parse("text/plain; charset=utf-8"); + RequestBody body = RequestBody.create(mediaType, postEntity); + + Request request = new Request.Builder().url(uri).post(body).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().toString(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + + } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkhttpProxyInfo.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkhttpProxyInfo.java new file mode 100644 index 0000000000..73ccdafaab --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkhttpProxyInfo.java @@ -0,0 +1,117 @@ +package me.chanjar.weixin.common.util.http.okhttp; + +import java.net.InetSocketAddress; +import java.net.Proxy; + +/** + * Created by ecoolper on 2017/4/26. + * Proxy information. + */ +public class OkhttpProxyInfo { + /** + * Proxy types. + */ + public enum ProxyType { + NONE, HTTP, SOCKS4, SOCKS5 + } + + private final String proxyAddress; + private final int proxyPort; + private final String proxyUsername; + private final String proxyPassword; + private final ProxyType proxyType; + + public OkhttpProxyInfo(ProxyType proxyType, String proxyHost, int proxyPort, String proxyUser, String proxyPassword) { + this.proxyType = proxyType; + this.proxyAddress = proxyHost; + this.proxyPort = proxyPort; + this.proxyUsername = proxyUser; + this.proxyPassword = proxyPassword; + } + + // ---------------------------------------------------------------- factory + + /** + * Creates directProxy. + */ + public static OkhttpProxyInfo directProxy() { + return new OkhttpProxyInfo(ProxyType.NONE, null, 0, null, null); + } + + /** + * Creates SOCKS4 proxy. + */ + public static OkhttpProxyInfo socks4Proxy(String proxyAddress, int proxyPort, String proxyUser) { + return new OkhttpProxyInfo(ProxyType.SOCKS4, proxyAddress, proxyPort, proxyUser, null); + } + + /** + * Creates SOCKS5 proxy. + */ + public static OkhttpProxyInfo socks5Proxy(String proxyAddress, int proxyPort, String proxyUser, String proxyPassword) { + return new OkhttpProxyInfo(ProxyType.SOCKS5, proxyAddress, proxyPort, proxyUser, proxyPassword); + } + + /** + * Creates HTTP proxy. + */ + public static OkhttpProxyInfo httpProxy(String proxyAddress, int proxyPort, String proxyUser, String proxyPassword) { + return new OkhttpProxyInfo(ProxyType.HTTP, proxyAddress, proxyPort, proxyUser, proxyPassword); + } + + // ---------------------------------------------------------------- getter + + /** + * Returns proxy type. + */ + public ProxyType getProxyType() { + return proxyType; + } + + /** + * Returns proxy address. + */ + public String getProxyAddress() { + return proxyAddress; + } + + /** + * Returns proxy port. + */ + public int getProxyPort() { + return proxyPort; + } + + /** + * Returns proxy user name or null if + * no authentication required. + */ + public String getProxyUsername() { + return proxyUsername; + } + + /** + * Returns proxy password or null. + */ + public String getProxyPassword() { + return proxyPassword; + } + + /** + * 返回 java.net.Proxy + * @return + */ + public Proxy getProxy() { + Proxy proxy = null; + if (getProxyType().equals(ProxyType.SOCKS5)) { + proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(getProxyAddress(), getProxyPort())); + } else if (getProxyType().equals(ProxyType.SOCKS4)) { + proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(getProxyAddress(), getProxyPort())); + } else if (getProxyType().equals(ProxyType.HTTP)) { + proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(getProxyAddress(), getProxyPort())); + } else if (getProxyType().equals(ProxyType.NONE)) { + proxy = new Proxy(Proxy.Type.DIRECT, new InetSocketAddress(getProxyAddress(), getProxyPort())); + } + return proxy; + } +} From ffa3544579b7cd471aac6bab4b98b60630946efc Mon Sep 17 00:00:00 2001 From: ecoolper Date: Thu, 27 Apr 2017 18:38:14 +0800 Subject: [PATCH 015/179] =?UTF-8?q?1=E3=80=81=E6=8F=90=E5=8F=96=E4=BA=86?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E4=BB=A3=E7=A0=81=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?AbstractWxMPService=E3=80=81AbstractWxCPService=E7=B1=BB=202?= =?UTF-8?q?=E3=80=81=E5=AE=9E=E7=8E=B0=E4=BA=86okhttp=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=203=E3=80=81RequestExecute=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0executeApache=E3=80=81executeJodd=E3=80=81exe?= =?UTF-8?q?cuteOkhttp=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 +- .../me/chanjar/weixin/cp/api/WxCpService.java | 5 + .../cp/api/impl/AbstractWxCpService.java | 632 +++++++++++++++++ .../cp/api/impl/apache/WxCpServiceImpl.java | 636 +----------------- .../cp/api/impl/jodd/WxCpServiceImpl.java | 635 +---------------- .../cp/api/impl/okhttp/WxCpServiceImpl.java | 90 +++ .../me/chanjar/weixin/mp/api/WxMpService.java | 8 +- .../mp/api/impl/AbstractWxMpService.java | 445 ++++++++++++ .../mp/api/impl/apache/WxMpServiceImpl.java | 518 ++------------ .../mp/api/impl/jodd/WxMpServiceImpl.java | 474 +------------ .../mp/api/impl/okhttp/WxMpServiceImpl.java | 96 +++ .../http/MaterialDeleteRequestExecutor.java | 89 ++- .../http/MaterialNewsInfoRequestExecutor.java | 60 +- .../http/MaterialUploadRequestExecutor.java | 76 ++- .../MaterialVideoInfoRequestExecutor.java | 63 +- ...lVoiceAndImageDownloadRequestExecutor.java | 74 +- .../http/MediaImgUploadRequestExecutor.java | 72 +- .../mp/util/http/QrCodeRequestExecutor.java | 66 +- .../weixin/mp/api/WxMpBusyRetryTest.java | 4 +- .../weixin/mp/api/test/ApiTestModule.java | 3 +- .../weixin/mp/demo/WxMpDemoServer.java | 4 +- weixin-java-pay/pom.xml | 7 - 22 files changed, 1693 insertions(+), 2369 deletions(-) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpService.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpService.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java diff --git a/pom.xml b/pom.xml index c185f037dc..b93c50ec48 100644 --- a/pom.xml +++ b/pom.xml @@ -107,14 +107,15 @@ 1.10 9.3.0.RC0 2.9.0 + + 3.7 org.jodd jodd-http - 3.7 - + ${jodd-http.version} com.squareup.okhttp3 diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index faa01d09e5..4b15fdb153 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -551,4 +551,9 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * 获取异步任务结果 */ String getTaskResult(String joinId) throws WxErrorException; + + /** + * 初始化http请求对象 + */ + void initHttp(); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpService.java new file mode 100644 index 0000000000..82fcdef9b3 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpService.java @@ -0,0 +1,632 @@ +package me.chanjar.weixin.cp.api.impl; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; + +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.menu.WxMenu; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.StandardSessionManager; +import me.chanjar.weixin.common.session.WxSession; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.RandomUtils; +import me.chanjar.weixin.common.util.crypto.SHA1; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.api.WxCpConfigStorage; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpDepart; +import me.chanjar.weixin.cp.bean.WxCpMessage; +import me.chanjar.weixin.cp.bean.WxCpTag; +import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +public abstract class AbstractWxCpService implements WxCpService, RequestHttp { + + protected final Logger log = LoggerFactory.getLogger(AbstractWxCpService.class); + + /** + * 全局的是否正在刷新access token的锁 + */ + protected final Object globalAccessTokenRefreshLock = new Object(); + + /** + * 全局的是否正在刷新jsapi_ticket的锁 + */ + protected final Object globalJsapiTicketRefreshLock = new Object(); + + protected WxCpConfigStorage configStorage; + + + protected WxSessionManager sessionManager = new StandardSessionManager(); + /** + * 临时文件目录 + */ + protected File tmpDirFile; + private int retrySleepMillis = 1000; + private int maxRetryTimes = 5; + + @Override + public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) { + try { + return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data) + .equals(msgSignature); + } catch (Exception e) { + return false; + } + } + + @Override + public void userAuthenticated(String userId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId; + get(url, null); + } + + @Override + public String getAccessToken() throws WxErrorException { + return getAccessToken(false); + } + + + @Override + public String getJsapiTicket() throws WxErrorException { + return getJsapiTicket(false); + } + + @Override + public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { + if (forceRefresh) { + this.configStorage.expireJsapiTicket(); + } + if (this.configStorage.isJsapiTicketExpired()) { + synchronized (this.globalJsapiTicketRefreshLock) { + if (this.configStorage.isJsapiTicketExpired()) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket"; + String responseContent = execute(new SimpleGetRequestExecutor(), url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + this.configStorage.updateJsapiTicket(jsapiTicket, + expiresInSeconds); + } + } + } + return this.configStorage.getJsapiTicket(); + } + + @Override + public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { + long timestamp = System.currentTimeMillis() / 1000; + String noncestr = RandomUtils.getRandomStr(); + String jsapiTicket = getJsapiTicket(false); + String signature = SHA1.genWithAmple( + "jsapi_ticket=" + jsapiTicket, + "noncestr=" + noncestr, + "timestamp=" + timestamp, + "url=" + url + ); + WxJsapiSignature jsapiSignature = new WxJsapiSignature(); + jsapiSignature.setTimestamp(timestamp); + jsapiSignature.setNonceStr(noncestr); + jsapiSignature.setUrl(url); + jsapiSignature.setSignature(signature); + + // Fixed bug + jsapiSignature.setAppId(this.configStorage.getCorpId()); + + return jsapiSignature; + } + + @Override + public void messageSend(WxCpMessage message) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"; + post(url, message.toJson()); + } + + @Override + public void menuCreate(WxMenu menu) throws WxErrorException { + menuCreate(this.configStorage.getAgentId(), menu); + } + + @Override + public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" + + this.configStorage.getAgentId(); + post(url, menu.toJson()); + } + + @Override + public void menuDelete() throws WxErrorException { + menuDelete(this.configStorage.getAgentId()); + } + + @Override + public void menuDelete(Integer agentId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId; + get(url, null); + } + + @Override + public WxMenu menuGet() throws WxErrorException { + return menuGet(this.configStorage.getAgentId()); + } + + @Override + public WxMenu menuGet(Integer agentId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId; + try { + String resultContent = get(url, null); + return WxMenu.fromJson(resultContent); + } catch (WxErrorException e) { + // 46003 不存在的菜单数据 + if (e.getError().getErrorCode() == 46003) { + return null; + } + throw e; + } + } + + @Override + public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) + throws WxErrorException, IOException { + return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); + } + + @Override + public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; + return execute(new MediaUploadRequestExecutor(), url, file); + } + + @Override + public File mediaDownload(String mediaId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; + return execute( + new MediaDownloadRequestExecutor( + this.configStorage.getTmpDirFile()), + url, "media_id=" + mediaId); + } + + + @Override + public Integer departCreate(WxCpDepart depart) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; + String responseContent = execute( + new SimplePostRequestExecutor(), + url, + depart.toJson()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id")); + } + + @Override + public void departUpdate(WxCpDepart group) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update"; + post(url, group.toJson()); + } + + @Override + public void departDelete(Integer departId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId; + get(url, null); + } + + @Override + public List departGet() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; + String responseContent = get(url, null); + /* + * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } + * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } + */ + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("department"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public void userCreate(WxCpUser user) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; + post(url, user.toJson()); + } + + @Override + public void userUpdate(WxCpUser user) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; + post(url, user.toJson()); + } + + @Override + public void userDelete(String userid) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userid; + get(url, null); + } + + @Override + public void userDelete(String[] userids) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; + JsonObject jsonObject = new JsonObject(); + JsonArray jsonArray = new JsonArray(); + for (String userid : userids) { + jsonArray.add(new JsonPrimitive(userid)); + } + jsonObject.add("useridlist", jsonArray); + post(url, jsonObject.toString()); + } + + @Override + public WxCpUser userGet(String userid) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid; + String responseContent = get(url, null); + return WxCpUser.fromJson(responseContent); + } + + @Override + public List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; + String params = ""; + if (fetchChild != null) { + params += "&fetch_child=" + (fetchChild ? "1" : "0"); + } + if (status != null) { + params += "&status=" + status; + } else { + params += "&status=0"; + } + + String responseContent = get(url, params); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; + String params = ""; + if (fetchChild != null) { + params += "&fetch_child=" + (fetchChild ? "1" : "0"); + } + if (status != null) { + params += "&status=" + status; + } else { + params += "&status=0"; + } + + String responseContent = get(url, params); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public String tagCreate(String tagName) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; + JsonObject o = new JsonObject(); + o.addProperty("tagname", tagName); + String responseContent = post(url, o.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("tagid").getAsString(); + } + + @Override + public void tagUpdate(String tagId, String tagName) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; + JsonObject o = new JsonObject(); + o.addProperty("tagid", tagId); + o.addProperty("tagname", tagName); + post(url, o.toString()); + } + + @Override + public void tagDelete(String tagId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; + get(url, null); + } + + @Override + public List tagGet() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; + String responseContent = get(url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("taglist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public List tagGetUsers(String tagId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; + String responseContent = get(url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public void tagAddUsers(String tagId, List userIds, List partyIds) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + if (userIds != null) { + JsonArray jsonArray = new JsonArray(); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("userlist", jsonArray); + } + if (partyIds != null) { + JsonArray jsonArray = new JsonArray(); + for (String userId : partyIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("partylist", jsonArray); + } + post(url, jsonObject.toString()); + } + + @Override + public void tagRemoveUsers(String tagId, List userIds) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + JsonArray jsonArray = new JsonArray(); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("userlist", jsonArray); + post(url, jsonObject.toString()); + } + + @Override + public String oauth2buildAuthorizationUrl(String state) { + return this.oauth2buildAuthorizationUrl( + this.configStorage.getOauth2redirectUri(), + state + ); + } + + @Override + public String oauth2buildAuthorizationUrl(String redirectUri, String state) { + String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"; + url += "appid=" + this.configStorage.getCorpId(); + url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri); + url += "&response_type=code"; + url += "&scope=snsapi_base"; + if (state != null) { + url += "&state=" + state; + } + url += "#wechat_redirect"; + return url; + } + + @Override + public String[] oauth2getUserInfo(String code) throws WxErrorException { + return oauth2getUserInfo(this.configStorage.getAgentId(), code); + } + + @Override + public String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?" + + "code=" + code + + "&agentid=" + agentId; + String responseText = get(url, null); + JsonElement je = new JsonParser().parse(responseText); + JsonObject jo = je.getAsJsonObject(); + return new String[]{GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId"), GsonHelper.getString(jo, "OpenId")}; + } + + @Override + public int invite(String userId, String inviteTips) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/invite/send"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("userid", userId); + if (StringUtils.isNotEmpty(inviteTips)) { + jsonObject.addProperty("invite_tips", inviteTips); + } + String responseContent = post(url, jsonObject.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("type").getAsInt(); + } + + @Override + public String[] getCallbackIp() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip"; + String responseContent = get(url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); + String[] ips = new String[jsonArray.size()]; + for (int i = 0; i < jsonArray.size(); i++) { + ips[i] = jsonArray.get(i).getAsString(); + } + return ips; + } + + @Override + public String get(String url, String queryParam) throws WxErrorException { + return execute(new SimpleGetRequestExecutor(), url, queryParam); + } + + @Override + public String post(String url, String postData) throws WxErrorException { + return execute(new SimplePostRequestExecutor(), url, postData); + } + + /** + * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 + */ + @Override + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + int retryTimes = 0; + do { + try { + T result = this.executeInternal(executor, uri, data); + this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",uri, data, result); + return result; + } catch (WxErrorException e) { + if (retryTimes + 1 > this.maxRetryTimes) { + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + //最后一次重试失败后,直接抛出异常,不再等待 + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + WxError error = e.getError(); + /* + * -1 系统繁忙, 1000ms后重试 + */ + if (error.getErrorCode() == -1) { + int sleepMillis = this.retrySleepMillis * (1 << retryTimes); + try { + this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + Thread.sleep(sleepMillis); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + } else { + throw e; + } + } + } while (retryTimes++ < this.maxRetryTimes); + + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + if (uri.contains("access_token=")) { + throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); + } + String accessToken = getAccessToken(false); + + String uriWithAccessToken = uri; + uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; + + try { + return executor.execute(this, uriWithAccessToken, data); + } catch (WxErrorException e) { + WxError error = e.getError(); + /* + * 发生以下情况时尝试刷新access_token + * 40001 获取access_token时AppSecret错误,或者access_token无效 + * 42001 access_token超时 + */ + if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { + // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token + this.configStorage.expireAccessToken(); + return execute(executor, uri, data); + } + + if (error.getErrorCode() != 0) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); + throw new WxErrorException(error); + } + return null; + } catch (IOException e) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); + throw new RuntimeException(e); + } + } + + @Override + public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) { + this.configStorage = wxConfigProvider; + this.initHttp(); + } + + @Override + public void setRetrySleepMillis(int retrySleepMillis) { + this.retrySleepMillis = retrySleepMillis; + } + + + @Override + public void setMaxRetryTimes(int maxRetryTimes) { + this.maxRetryTimes = maxRetryTimes; + } + + @Override + public WxSession getSession(String id) { + if (this.sessionManager == null) { + return null; + } + return this.sessionManager.getSession(id); + } + + @Override + public WxSession getSession(String id, boolean create) { + if (this.sessionManager == null) { + return null; + } + return this.sessionManager.getSession(id, create); + } + + + @Override + public void setSessionManager(WxSessionManager sessionManager) { + this.sessionManager = sessionManager; + } + + @Override + public String replaceParty(String mediaId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("media_id", mediaId); + return post(url, jsonObject.toString()); + } + + @Override + public String replaceUser(String mediaId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("media_id", mediaId); + return post(url, jsonObject.toString()); + } + + @Override + public String getTaskResult(String joinId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?jobid=" + joinId; + return get(url, null); + } + + public File getTmpDirFile() { + return this.tmpDirFile; + } + + public void setTmpDirFile(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java index 4369868f15..8e4d57e39e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java @@ -1,92 +1,34 @@ package me.chanjar.weixin.cp.api.impl.apache; -import com.google.gson.*; -import com.google.gson.reflect.TypeToken; + import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.bean.WxJsapiSignature; -import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.StandardSessionManager; -import me.chanjar.weixin.common.session.WxSession; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.util.RandomUtils; -import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.*; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; -import me.chanjar.weixin.common.util.json.GsonHelper; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.WxCpService; -import me.chanjar.weixin.cp.bean.WxCpDepart; -import me.chanjar.weixin.cp.bean.WxCpMessage; -import me.chanjar.weixin.cp.bean.WxCpTag; -import me.chanjar.weixin.cp.bean.WxCpUser; -import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; -import org.apache.commons.lang3.StringUtils; +import me.chanjar.weixin.cp.api.impl.AbstractWxCpService; + import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.CloseableHttpClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.UUID; - -public class WxCpServiceImpl implements WxCpService, RequestHttp { - - protected final Logger log = LoggerFactory.getLogger(WxCpServiceImpl.class); - - /** - * 全局的是否正在刷新access token的锁 - */ - protected final Object globalAccessTokenRefreshLock = new Object(); - - /** - * 全局的是否正在刷新jsapi_ticket的锁 - */ - protected final Object globalJsapiTicketRefreshLock = new Object(); - - protected WxCpConfigStorage configStorage; +public class WxCpServiceImpl extends AbstractWxCpService { protected CloseableHttpClient httpClient; - protected HttpHost httpProxy; - protected WxSessionManager sessionManager = new StandardSessionManager(); - /** - * 临时文件目录 - */ - protected File tmpDirFile; - private int retrySleepMillis = 1000; - private int maxRetryTimes = 5; @Override - public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) { - try { - return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data) - .equals(msgSignature); - } catch (Exception e) { - return false; - } + public CloseableHttpClient getRequestHttpClient() { + return httpClient; } @Override - public void userAuthenticated(String userId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId; - get(url, null); - } - - @Override - public String getAccessToken() throws WxErrorException { - return getAccessToken(false); + public HttpHost getRequestHttpProxy() { + return httpProxy; } @Override @@ -108,7 +50,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { httpGet.setConfig(config); } String resultContent = null; - try (CloseableHttpClient httpclient = getHttpclient(); + try (CloseableHttpClient httpclient = getRequestHttpClient(); CloseableHttpResponse response = httpclient.execute(httpGet)) { resultContent = new BasicResponseHandler().handleResponse(response); } finally { @@ -131,491 +73,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } @Override - public String getJsapiTicket() throws WxErrorException { - return getJsapiTicket(false); - } - - @Override - public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { - if (forceRefresh) { - this.configStorage.expireJsapiTicket(); - } - if (this.configStorage.isJsapiTicketExpired()) { - synchronized (this.globalJsapiTicketRefreshLock) { - if (this.configStorage.isJsapiTicketExpired()) { - String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); - int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.configStorage.updateJsapiTicket(jsapiTicket, - expiresInSeconds); - } - } - } - return this.configStorage.getJsapiTicket(); - } - - @Override - public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { - long timestamp = System.currentTimeMillis() / 1000; - String noncestr = RandomUtils.getRandomStr(); - String jsapiTicket = getJsapiTicket(false); - String signature = SHA1.genWithAmple( - "jsapi_ticket=" + jsapiTicket, - "noncestr=" + noncestr, - "timestamp=" + timestamp, - "url=" + url - ); - WxJsapiSignature jsapiSignature = new WxJsapiSignature(); - jsapiSignature.setTimestamp(timestamp); - jsapiSignature.setNonceStr(noncestr); - jsapiSignature.setUrl(url); - jsapiSignature.setSignature(signature); - - // Fixed bug - jsapiSignature.setAppId(this.configStorage.getCorpId()); - - return jsapiSignature; - } - - @Override - public void messageSend(WxCpMessage message) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"; - post(url, message.toJson()); - } - - @Override - public void menuCreate(WxMenu menu) throws WxErrorException { - menuCreate(this.configStorage.getAgentId(), menu); - } - - @Override - public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" - + this.configStorage.getAgentId(); - post(url, menu.toJson()); - } - - @Override - public void menuDelete() throws WxErrorException { - menuDelete(this.configStorage.getAgentId()); - } - - @Override - public void menuDelete(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId; - get(url, null); - } - - @Override - public WxMenu menuGet() throws WxErrorException { - return menuGet(this.configStorage.getAgentId()); - } - - @Override - public WxMenu menuGet(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId; - try { - String resultContent = get(url, null); - return WxMenu.fromJson(resultContent); - } catch (WxErrorException e) { - // 46003 不存在的菜单数据 - if (e.getError().getErrorCode() == 46003) { - return null; - } - throw e; - } - } - - @Override - public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) - throws WxErrorException, IOException { - return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); - } - - @Override - public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; - return execute(new MediaUploadRequestExecutor(), url, file); - } - - @Override - public File mediaDownload(String mediaId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; - return execute( - new MediaDownloadRequestExecutor( - this.configStorage.getTmpDirFile()), - url, "media_id=" + mediaId); - } - - - @Override - public Integer departCreate(WxCpDepart depart) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; - String responseContent = execute( - new SimplePostRequestExecutor(), - url, - depart.toJson()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id")); - } - - @Override - public void departUpdate(WxCpDepart group) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update"; - post(url, group.toJson()); - } - - @Override - public void departDelete(Integer departId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId; - get(url, null); - } - - @Override - public List departGet() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; - String responseContent = get(url, null); - /* - * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } - * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } - */ - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("department"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public void userCreate(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; - post(url, user.toJson()); - } - - @Override - public void userUpdate(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; - post(url, user.toJson()); - } - - @Override - public void userDelete(String userid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userid; - get(url, null); - } - - @Override - public void userDelete(String[] userids) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; - JsonObject jsonObject = new JsonObject(); - JsonArray jsonArray = new JsonArray(); - for (String userid : userids) { - jsonArray.add(new JsonPrimitive(userid)); - } - jsonObject.add("useridlist", jsonArray); - post(url, jsonObject.toString()); - } - - @Override - public WxCpUser userGet(String userid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid; - String responseContent = get(url, null); - return WxCpUser.fromJson(responseContent); - } - - @Override - public List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; - String params = ""; - if (fetchChild != null) { - params += "&fetch_child=" + (fetchChild ? "1" : "0"); - } - if (status != null) { - params += "&status=" + status; - } else { - params += "&status=0"; - } - - String responseContent = get(url, params); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; - String params = ""; - if (fetchChild != null) { - params += "&fetch_child=" + (fetchChild ? "1" : "0"); - } - if (status != null) { - params += "&status=" + status; - } else { - params += "&status=0"; - } - - String responseContent = get(url, params); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public String tagCreate(String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; - JsonObject o = new JsonObject(); - o.addProperty("tagname", tagName); - String responseContent = post(url, o.toString()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return tmpJsonElement.getAsJsonObject().get("tagid").getAsString(); - } - - @Override - public void tagUpdate(String tagId, String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; - JsonObject o = new JsonObject(); - o.addProperty("tagid", tagId); - o.addProperty("tagname", tagName); - post(url, o.toString()); - } - - @Override - public void tagDelete(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; - get(url, null); - } - - @Override - public List tagGet() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; - String responseContent = get(url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("taglist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public List tagGetUsers(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; - String responseContent = get(url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public void tagAddUsers(String tagId, List userIds, List partyIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("tagid", tagId); - if (userIds != null) { - JsonArray jsonArray = new JsonArray(); - for (String userId : userIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("userlist", jsonArray); - } - if (partyIds != null) { - JsonArray jsonArray = new JsonArray(); - for (String userId : partyIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("partylist", jsonArray); - } - post(url, jsonObject.toString()); - } - - @Override - public void tagRemoveUsers(String tagId, List userIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("tagid", tagId); - JsonArray jsonArray = new JsonArray(); - for (String userId : userIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("userlist", jsonArray); - post(url, jsonObject.toString()); - } - - @Override - public String oauth2buildAuthorizationUrl(String state) { - return this.oauth2buildAuthorizationUrl( - this.configStorage.getOauth2redirectUri(), - state - ); - } - - @Override - public String oauth2buildAuthorizationUrl(String redirectUri, String state) { - String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"; - url += "appid=" + this.configStorage.getCorpId(); - url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri); - url += "&response_type=code"; - url += "&scope=snsapi_base"; - if (state != null) { - url += "&state=" + state; - } - url += "#wechat_redirect"; - return url; - } - - @Override - public String[] oauth2getUserInfo(String code) throws WxErrorException { - return oauth2getUserInfo(this.configStorage.getAgentId(), code); - } - - @Override - public String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?" - + "code=" + code - + "&agentid=" + agentId; - String responseText = get(url, null); - JsonElement je = new JsonParser().parse(responseText); - JsonObject jo = je.getAsJsonObject(); - return new String[]{GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId"), GsonHelper.getString(jo, "OpenId")}; - } - - @Override - public int invite(String userId, String inviteTips) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/invite/send"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("userid", userId); - if (StringUtils.isNotEmpty(inviteTips)) { - jsonObject.addProperty("invite_tips", inviteTips); - } - String responseContent = post(url, jsonObject.toString()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return tmpJsonElement.getAsJsonObject().get("type").getAsInt(); - } - - @Override - public String[] getCallbackIp() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip"; - String responseContent = get(url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); - String[] ips = new String[jsonArray.size()]; - for (int i = 0; i < jsonArray.size(); i++) { - ips[i] = jsonArray.get(i).getAsString(); - } - return ips; - } - - @Override - public String get(String url, String queryParam) throws WxErrorException { - return execute(new SimpleGetRequestExecutor(), url, queryParam); - } - - @Override - public String post(String url, String postData) throws WxErrorException { - return execute(new SimplePostRequestExecutor(), url, postData); - } - - /** - * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 - */ - @Override - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { - int retryTimes = 0; - do { - try { - T result = this.executeInternal(executor, uri, data); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",uri, data, result); - return result; - } catch (WxErrorException e) { - if (retryTimes + 1 > this.maxRetryTimes) { - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); - //最后一次重试失败后,直接抛出异常,不再等待 - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - WxError error = e.getError(); - /* - * -1 系统繁忙, 1000ms后重试 - */ - if (error.getErrorCode() == -1) { - int sleepMillis = this.retrySleepMillis * (1 << retryTimes); - try { - this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); - Thread.sleep(sleepMillis); - } catch (InterruptedException e1) { - throw new RuntimeException(e1); - } - } else { - throw e; - } - } - } while (retryTimes++ < this.maxRetryTimes); - - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { - if (uri.contains("access_token=")) { - throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); - } - String accessToken = getAccessToken(false); - - String uriWithAccessToken = uri; - uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; - - try { - return executor.execute(this, uriWithAccessToken, data); - } catch (WxErrorException e) { - WxError error = e.getError(); - /* - * 发生以下情况时尝试刷新access_token - * 40001 获取access_token时AppSecret错误,或者access_token无效 - * 42001 access_token超时 - */ - if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { - // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token - this.configStorage.expireAccessToken(); - return execute(executor, uri, data); - } - - if (error.getErrorCode() != 0) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); - throw new WxErrorException(error); - } - return null; - } catch (IOException e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); - throw new RuntimeException(e); - } - } - - protected CloseableHttpClient getHttpclient() { - return this.httpClient; - } - - @Override - public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) { - this.configStorage = wxConfigProvider; + public void initHttp() { ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage .getApacheHttpClientBuilder(); if (null == apacheHttpClientBuilder) { @@ -633,78 +91,4 @@ public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) { this.httpClient = apacheHttpClientBuilder.build(); } - - @Override - public void setRetrySleepMillis(int retrySleepMillis) { - this.retrySleepMillis = retrySleepMillis; - } - - - @Override - public void setMaxRetryTimes(int maxRetryTimes) { - this.maxRetryTimes = maxRetryTimes; - } - - @Override - public WxSession getSession(String id) { - if (this.sessionManager == null) { - return null; - } - return this.sessionManager.getSession(id); - } - - @Override - public WxSession getSession(String id, boolean create) { - if (this.sessionManager == null) { - return null; - } - return this.sessionManager.getSession(id, create); - } - - - @Override - public void setSessionManager(WxSessionManager sessionManager) { - this.sessionManager = sessionManager; - } - - @Override - public String replaceParty(String mediaId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("media_id", mediaId); - return post(url, jsonObject.toString()); - } - - @Override - public String replaceUser(String mediaId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("media_id", mediaId); - return post(url, jsonObject.toString()); - } - - @Override - public String getTaskResult(String joinId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?jobid=" + joinId; - return get(url, null); - } - - public File getTmpDirFile() { - return this.tmpDirFile; - } - - public void setTmpDirFile(File tmpDirFile) { - this.tmpDirFile = tmpDirFile; - } - - - @Override - public Object getRequestHttpClient() { - return this.httpClient; - } - - @Override - public Object getRequestHttpProxy() { - return this.httpProxy; - } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java index 8c41f04211..f0af34746b 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java @@ -1,85 +1,24 @@ package me.chanjar.weixin.cp.api.impl.jodd; -import com.google.gson.*; -import com.google.gson.reflect.TypeToken; import jodd.http.*; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.bean.WxJsapiSignature; -import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.StandardSessionManager; -import me.chanjar.weixin.common.session.WxSession; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.util.RandomUtils; -import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.*; -import me.chanjar.weixin.common.util.json.GsonHelper; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.WxCpService; -import me.chanjar.weixin.cp.bean.WxCpDepart; -import me.chanjar.weixin.cp.bean.WxCpMessage; -import me.chanjar.weixin.cp.bean.WxCpTag; -import me.chanjar.weixin.cp.bean.WxCpUser; -import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.UUID; - -public class WxCpServiceImpl implements WxCpService, RequestHttp { - - protected final Logger log = LoggerFactory.getLogger(WxCpServiceImpl.class); - - /** - * 全局的是否正在刷新access token的锁 - */ - protected final Object globalAccessTokenRefreshLock = new Object(); - - /** - * 全局的是否正在刷新jsapi_ticket的锁 - */ - protected final Object globalJsapiTicketRefreshLock = new Object(); - - protected WxCpConfigStorage configStorage; +import me.chanjar.weixin.cp.api.impl.AbstractWxCpService; +public class WxCpServiceImpl extends AbstractWxCpService { protected HttpConnectionProvider httpClient; - protected ProxyInfo httpProxy; - protected WxSessionManager sessionManager = new StandardSessionManager(); - /** - * 临时文件目录 - */ - protected File tmpDirFile; - private int retrySleepMillis = 1000; - private int maxRetryTimes = 5; - @Override - public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) { - try { - return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data) - .equals(msgSignature); - } catch (Exception e) { - return false; - } - } @Override - public void userAuthenticated(String userId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId; - get(url, null); + public HttpConnectionProvider getRequestHttpClient() { + return httpClient; } @Override - public String getAccessToken() throws WxErrorException { - return getAccessToken(false); + public ProxyInfo getRequestHttpProxy() { + return httpProxy; } @Override @@ -116,571 +55,11 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } @Override - public String getJsapiTicket() throws WxErrorException { - return getJsapiTicket(false); - } - - @Override - public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { - if (forceRefresh) { - this.configStorage.expireJsapiTicket(); - } - if (this.configStorage.isJsapiTicketExpired()) { - synchronized (this.globalJsapiTicketRefreshLock) { - if (this.configStorage.isJsapiTicketExpired()) { - String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); - int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.configStorage.updateJsapiTicket(jsapiTicket, - expiresInSeconds); - } - } - } - return this.configStorage.getJsapiTicket(); - } - - @Override - public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { - long timestamp = System.currentTimeMillis() / 1000; - String noncestr = RandomUtils.getRandomStr(); - String jsapiTicket = getJsapiTicket(false); - String signature = SHA1.genWithAmple( - "jsapi_ticket=" + jsapiTicket, - "noncestr=" + noncestr, - "timestamp=" + timestamp, - "url=" + url - ); - WxJsapiSignature jsapiSignature = new WxJsapiSignature(); - jsapiSignature.setTimestamp(timestamp); - jsapiSignature.setNonceStr(noncestr); - jsapiSignature.setUrl(url); - jsapiSignature.setSignature(signature); - - // Fixed bug - jsapiSignature.setAppId(this.configStorage.getCorpId()); - - return jsapiSignature; - } - - @Override - public void messageSend(WxCpMessage message) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"; - post(url, message.toJson()); - } - - @Override - public void menuCreate(WxMenu menu) throws WxErrorException { - menuCreate(this.configStorage.getAgentId(), menu); - } - - @Override - public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" - + this.configStorage.getAgentId(); - post(url, menu.toJson()); - } - - @Override - public void menuDelete() throws WxErrorException { - menuDelete(this.configStorage.getAgentId()); - } - - @Override - public void menuDelete(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId; - get(url, null); - } - - @Override - public WxMenu menuGet() throws WxErrorException { - return menuGet(this.configStorage.getAgentId()); - } - - @Override - public WxMenu menuGet(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId; - try { - String resultContent = get(url, null); - return WxMenu.fromJson(resultContent); - } catch (WxErrorException e) { - // 46003 不存在的菜单数据 - if (e.getError().getErrorCode() == 46003) { - return null; - } - throw e; - } - } - - @Override - public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) - throws WxErrorException, IOException { - return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); - } - - @Override - public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; - return execute(new MediaUploadRequestExecutor(), url, file); - } - - @Override - public File mediaDownload(String mediaId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; - return execute( - new MediaDownloadRequestExecutor( - this.configStorage.getTmpDirFile()), - url, "media_id=" + mediaId); - } - - - @Override - public Integer departCreate(WxCpDepart depart) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; - String responseContent = execute( - new SimplePostRequestExecutor(), - url, - depart.toJson()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id")); - } - - @Override - public void departUpdate(WxCpDepart group) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update"; - post(url, group.toJson()); - } - - @Override - public void departDelete(Integer departId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId; - get(url, null); - } - - @Override - public List departGet() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; - String responseContent = get(url, null); - /* - * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } - * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } - */ - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("department"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public void userCreate(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; - post(url, user.toJson()); - } - - @Override - public void userUpdate(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; - post(url, user.toJson()); - } - - @Override - public void userDelete(String userid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userid; - get(url, null); - } - - @Override - public void userDelete(String[] userids) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; - JsonObject jsonObject = new JsonObject(); - JsonArray jsonArray = new JsonArray(); - for (String userid : userids) { - jsonArray.add(new JsonPrimitive(userid)); - } - jsonObject.add("useridlist", jsonArray); - post(url, jsonObject.toString()); - } - - @Override - public WxCpUser userGet(String userid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid; - String responseContent = get(url, null); - return WxCpUser.fromJson(responseContent); - } - - @Override - public List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; - String params = ""; - if (fetchChild != null) { - params += "&fetch_child=" + (fetchChild ? "1" : "0"); - } - if (status != null) { - params += "&status=" + status; - } else { - params += "&status=0"; - } - - String responseContent = get(url, params); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; - String params = ""; - if (fetchChild != null) { - params += "&fetch_child=" + (fetchChild ? "1" : "0"); - } - if (status != null) { - params += "&status=" + status; - } else { - params += "&status=0"; - } - - String responseContent = get(url, params); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public String tagCreate(String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; - JsonObject o = new JsonObject(); - o.addProperty("tagname", tagName); - String responseContent = post(url, o.toString()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return tmpJsonElement.getAsJsonObject().get("tagid").getAsString(); - } - - @Override - public void tagUpdate(String tagId, String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; - JsonObject o = new JsonObject(); - o.addProperty("tagid", tagId); - o.addProperty("tagname", tagName); - post(url, o.toString()); - } - - @Override - public void tagDelete(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; - get(url, null); - } - - @Override - public List tagGet() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; - String responseContent = get(url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("taglist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public List tagGetUsers(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; - String responseContent = get(url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public void tagAddUsers(String tagId, List userIds, List partyIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("tagid", tagId); - if (userIds != null) { - JsonArray jsonArray = new JsonArray(); - for (String userId : userIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("userlist", jsonArray); - } - if (partyIds != null) { - JsonArray jsonArray = new JsonArray(); - for (String userId : partyIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("partylist", jsonArray); - } - post(url, jsonObject.toString()); - } - - @Override - public void tagRemoveUsers(String tagId, List userIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("tagid", tagId); - JsonArray jsonArray = new JsonArray(); - for (String userId : userIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("userlist", jsonArray); - post(url, jsonObject.toString()); - } - - @Override - public String oauth2buildAuthorizationUrl(String state) { - return this.oauth2buildAuthorizationUrl( - this.configStorage.getOauth2redirectUri(), - state - ); - } - - @Override - public String oauth2buildAuthorizationUrl(String redirectUri, String state) { - String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"; - url += "appid=" + this.configStorage.getCorpId(); - url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri); - url += "&response_type=code"; - url += "&scope=snsapi_base"; - if (state != null) { - url += "&state=" + state; - } - url += "#wechat_redirect"; - return url; - } - - @Override - public String[] oauth2getUserInfo(String code) throws WxErrorException { - return oauth2getUserInfo(this.configStorage.getAgentId(), code); - } - - @Override - public String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?" - + "code=" + code - + "&agentid=" + agentId; - String responseText = get(url, null); - JsonElement je = new JsonParser().parse(responseText); - JsonObject jo = je.getAsJsonObject(); - return new String[]{GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId"), GsonHelper.getString(jo, "OpenId")}; - } - - @Override - public int invite(String userId, String inviteTips) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/invite/send"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("userid", userId); - if (StringUtils.isNotEmpty(inviteTips)) { - jsonObject.addProperty("invite_tips", inviteTips); - } - String responseContent = post(url, jsonObject.toString()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return tmpJsonElement.getAsJsonObject().get("type").getAsInt(); - } - - @Override - public String[] getCallbackIp() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip"; - String responseContent = get(url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); - String[] ips = new String[jsonArray.size()]; - for (int i = 0; i < jsonArray.size(); i++) { - ips[i] = jsonArray.get(i).getAsString(); - } - return ips; - } - - @Override - public String get(String url, String queryParam) throws WxErrorException { - return execute(new SimpleGetRequestExecutor(), url, queryParam); - } - - @Override - public String post(String url, String postData) throws WxErrorException { - return execute(new SimplePostRequestExecutor(), url, postData); - } - - /** - * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 - */ - @Override - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { - int retryTimes = 0; - do { - try { - T result = this.executeInternal(executor, uri, data); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, result); - return result; - } catch (WxErrorException e) { - if (retryTimes + 1 > this.maxRetryTimes) { - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); - //最后一次重试失败后,直接抛出异常,不再等待 - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - WxError error = e.getError(); - /* - * -1 系统繁忙, 1000ms后重试 - */ - if (error.getErrorCode() == -1) { - int sleepMillis = this.retrySleepMillis * (1 << retryTimes); - try { - this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); - Thread.sleep(sleepMillis); - } catch (InterruptedException e1) { - throw new RuntimeException(e1); - } - } else { - throw e; - } - } - } while (retryTimes++ < this.maxRetryTimes); - - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - - public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { - if (uri.contains("access_token=")) { - throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); - } - String accessToken = getAccessToken(false); - - String uriWithAccessToken = uri; - uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; - - try { - return executor.execute(this, uriWithAccessToken, data); - } catch (WxErrorException e) { - WxError error = e.getError(); - /* - * 发生以下情况时尝试刷新access_token - * 40001 获取access_token时AppSecret错误,或者access_token无效 - * 42001 access_token超时 - */ - if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { - // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token - this.configStorage.expireAccessToken(); - return execute(executor, uri, data); - } - - if (error.getErrorCode() != 0) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); - throw new WxErrorException(error); - } - return null; - } catch (IOException e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); - throw new RuntimeException(e); - } - } - - protected HttpConnectionProvider getHttpclient() { - return this.httpClient; - } - - @Override - public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) { - this.configStorage = wxConfigProvider; - + public void initHttp() { if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) { httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); } httpClient = JoddHttp.httpConnectionProvider; } - - @Override - public void setRetrySleepMillis(int retrySleepMillis) { - this.retrySleepMillis = retrySleepMillis; - } - - - @Override - public void setMaxRetryTimes(int maxRetryTimes) { - this.maxRetryTimes = maxRetryTimes; - } - - @Override - public WxSession getSession(String id) { - if (this.sessionManager == null) { - return null; - } - return this.sessionManager.getSession(id); - } - - @Override - public WxSession getSession(String id, boolean create) { - if (this.sessionManager == null) { - return null; - } - return this.sessionManager.getSession(id, create); - } - - - @Override - public void setSessionManager(WxSessionManager sessionManager) { - this.sessionManager = sessionManager; - } - - @Override - public String replaceParty(String mediaId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("media_id", mediaId); - return post(url, jsonObject.toString()); - } - - @Override - public String replaceUser(String mediaId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("media_id", mediaId); - return post(url, jsonObject.toString()); - } - - @Override - public String getTaskResult(String joinId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?jobid=" + joinId; - return get(url, null); - } - - public File getTmpDirFile() { - return this.tmpDirFile; - } - - public void setTmpDirFile(File tmpDirFile) { - this.tmpDirFile = tmpDirFile; - } - - - @Override - public Object getRequestHttpClient() { - return this.httpClient; - } - - @Override - public Object getRequestHttpProxy() { - return this.httpProxy; - } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java new file mode 100644 index 0000000000..39db38166c --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java @@ -0,0 +1,90 @@ +package me.chanjar.weixin.cp.api.impl.okhttp; + +import java.io.IOException; + +import jodd.http.*; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.cp.api.WxCpConfigStorage; +import me.chanjar.weixin.cp.api.impl.AbstractWxCpService; +import okhttp3.*; + +public class WxCpServiceImpl extends AbstractWxCpService { + protected ConnectionPool httpClient; + protected OkhttpProxyInfo httpProxy; + + + @Override + public ConnectionPool getRequestHttpClient() { + return httpClient; + } + + @Override + public OkhttpProxyInfo getRequestHttpProxy() { + return httpProxy; + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + if (forceRefresh) { + this.configStorage.expireAccessToken(); + } + if (this.configStorage.isAccessTokenExpired()) { + synchronized (this.globalAccessTokenRefreshLock) { + if (this.configStorage.isAccessTokenExpired()) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" + + "&corpid=" + this.configStorage.getCorpId() + + "&corpsecret=" + this.configStorage.getCorpSecret(); + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(httpClient); + //设置代理 + if (httpProxy != null) { + clientBuilder.proxy(getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + //请求的request + Request request = new Request.Builder().url(url).get().build(); + Response response = null; + try { + response = client.newCall(request).execute(); + } catch (IOException e) { + e.printStackTrace(); + } + String resultContent = response.body().toString(); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.configStorage.updateAccessToken(accessToken.getAccessToken(), + accessToken.getExpiresIn()); + } + } + } + return this.configStorage.getAccessToken(); + } + + @Override + public void initHttp() { + WxCpConfigStorage configStorage = this.configStorage; + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + httpProxy = new OkhttpProxyInfo(OkhttpProxyInfo.ProxyType.SOCKS5, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + } + + httpClient = new ConnectionPool(); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index 0b96859412..33333c44e3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -344,14 +344,10 @@ public interface WxMpService { */ WxMpDeviceService getDeviceService(); - /** - * @return - */ - //Object getHttpclient(); /** - * @return + * 初始化http请求对象 */ - //Object getHttpProxy(); + void initHttp(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpService.java new file mode 100644 index 0000000000..5c6b58eb04 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpService.java @@ -0,0 +1,445 @@ +package me.chanjar.weixin.mp.api.impl; + +import java.io.IOException; +import java.util.concurrent.locks.Lock; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.StandardSessionManager; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.RandomUtils; +import me.chanjar.weixin.common.util.crypto.SHA1; +import me.chanjar.weixin.common.util.http.*; +import me.chanjar.weixin.mp.api.*; +import me.chanjar.weixin.mp.bean.*; +import me.chanjar.weixin.mp.bean.result.*; + +public abstract class AbstractWxMpService implements WxMpService,RequestHttp { + + private static final JsonParser JSON_PARSER = new JsonParser(); + + protected final Logger log = LoggerFactory.getLogger(this.getClass()); + protected WxSessionManager sessionManager = new StandardSessionManager(); + private WxMpConfigStorage wxMpConfigStorage; + private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); + private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); + private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); + private WxMpUserService userService = new WxMpUserServiceImpl(this); + private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this); + private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); + private WxMpCardService cardService = new WxMpCardServiceImpl(this); + private WxMpStoreService storeService = new WxMpStoreServiceImpl(this); + private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this); + private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this); + private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); + private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); + + private int retrySleepMillis = 1000; + private int maxRetryTimes = 5; + + + @Override + public boolean checkSignature(String timestamp, String nonce, String signature) { + try { + return SHA1.gen(this.getWxMpConfigStorage().getToken(), timestamp, nonce) + .equals(signature); + } catch (Exception e) { + return false; + } + } + + @Override + public String getJsapiTicket() throws WxErrorException { + return getJsapiTicket(false); + } + + @Override + public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMpConfigStorage().getJsapiTicketLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.getWxMpConfigStorage().expireJsapiTicket(); + } + + if (this.getWxMpConfigStorage().isJsapiTicketExpired()) { + String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; + String responseContent = execute(new SimpleGetRequestExecutor(), url, null); + JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + this.getWxMpConfigStorage().updateJsapiTicket(jsapiTicket, expiresInSeconds); + } + } finally { + lock.unlock(); + } + return this.getWxMpConfigStorage().getJsapiTicket(); + } + + @Override + public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { + long timestamp = System.currentTimeMillis() / 1000; + String noncestr = RandomUtils.getRandomStr(); + String jsapiTicket = getJsapiTicket(false); + String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket, + "noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url); + WxJsapiSignature jsapiSignature = new WxJsapiSignature(); + jsapiSignature.setAppId(this.getWxMpConfigStorage().getAppId()); + jsapiSignature.setTimestamp(timestamp); + jsapiSignature.setNonceStr(noncestr); + jsapiSignature.setUrl(url); + jsapiSignature.setSignature(signature); + return jsapiSignature; + } + + @Override + public String getAccessToken() throws WxErrorException { + return getAccessToken(false); + } + + @Override + public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; + String responseContent = this.post(url, news.toJson()); + return WxMpMassUploadResult.fromJson(responseContent); + } + + @Override + public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; + String responseContent = this.post(url, video.toJson()); + return WxMpMassUploadResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; + String responseContent = this.post(url, message.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; + String responseContent = this.post(url, message.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception { + String url = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; + String responseContent = this.post(url, wxMpMassPreviewMessage.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + + @Override + public String shortUrl(String long_url) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/shorturl"; + JsonObject o = new JsonObject(); + o.addProperty("action", "long2short"); + o.addProperty("long_url", long_url); + String responseContent = this.post(url, o.toString()); + JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("short_url").getAsString(); + } + + @Override + public WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException { + String url = "https://api.weixin.qq.com/semantic/semproxy/search"; + String responseContent = this.post(url, semanticQuery.toJson()); + return WxMpSemanticQueryResult.fromJson(responseContent); + } + + @Override + public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { + StringBuilder url = new StringBuilder(); + url.append("https://open.weixin.qq.com/connect/oauth2/authorize?"); + url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); + url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); + url.append("&response_type=code"); + url.append("&scope=").append(scope); + if (state != null) { + url.append("&state=").append(state); + } + url.append("#wechat_redirect"); + return url.toString(); + } + + @Override + public String buildQrConnectUrl(String redirectURI, String scope, + String state) { + StringBuilder url = new StringBuilder(); + url.append("https://open.weixin.qq.com/connect/qrconnect?"); + url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); + url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); + url.append("&response_type=code"); + url.append("&scope=").append(scope); + if (state != null) { + url.append("&state=").append(state); + } + + url.append("#wechat_redirect"); + return url.toString(); + } + + private WxMpOAuth2AccessToken getOAuth2AccessToken(StringBuilder url) throws WxErrorException { + try { + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(this, url.toString(), null); + return WxMpOAuth2AccessToken.fromJson(responseText); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { + StringBuilder url = new StringBuilder(); + url.append("https://api.weixin.qq.com/sns/oauth2/access_token?"); + url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); + url.append("&secret=").append(this.getWxMpConfigStorage().getSecret()); + url.append("&code=").append(code); + url.append("&grant_type=authorization_code"); + + return this.getOAuth2AccessToken(url); + } + + @Override + public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { + StringBuilder url = new StringBuilder(); + url.append("https://api.weixin.qq.com/sns/oauth2/refresh_token?"); + url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); + url.append("&grant_type=refresh_token"); + url.append("&refresh_token=").append(refreshToken); + + return this.getOAuth2AccessToken(url); + } + + @Override + public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { + StringBuilder url = new StringBuilder(); + url.append("https://api.weixin.qq.com/sns/userinfo?"); + url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); + url.append("&openid=").append(oAuth2AccessToken.getOpenId()); + if (lang == null) { + url.append("&lang=zh_CN"); + } else { + url.append("&lang=").append(lang); + } + + try { + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(this, url.toString(), null); + return WxMpUser.fromJson(responseText); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { + StringBuilder url = new StringBuilder(); + url.append("https://api.weixin.qq.com/sns/auth?"); + url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); + url.append("&openid=").append(oAuth2AccessToken.getOpenId()); + + try { + RequestExecutor executor = new SimpleGetRequestExecutor(); + executor.execute(this, url.toString(), null); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (WxErrorException e) { + return false; + } + return true; + } + + @Override + public String[] getCallbackIP() throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/getcallbackip"; + String responseContent = get(url, null); + JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); + JsonArray ipList = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); + String[] ipArray = new String[ipList.size()]; + for (int i = 0; i < ipList.size(); i++) { + ipArray[i] = ipList.get(i).getAsString(); + } + return ipArray; + } + + @Override + public String get(String url, String queryParam) throws WxErrorException { + return execute(new SimpleGetRequestExecutor(), url, queryParam); + } + + @Override + public String post(String url, String postData) throws WxErrorException { + return execute(new SimplePostRequestExecutor(), url, postData); + } + + /** + * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 + */ + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + int retryTimes = 0; + do { + try { + T result = executeInternal(executor, uri, data); + this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, result); + return result; + } catch (WxErrorException e) { + if (retryTimes + 1 > this.maxRetryTimes) { + this.log.warn("重试达到最大次数【{}】", maxRetryTimes); + //最后一次重试失败后,直接抛出异常,不再等待 + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + WxError error = e.getError(); + // -1 系统繁忙, 1000ms后重试 + if (error.getErrorCode() == -1) { + int sleepMillis = this.retrySleepMillis * (1 << retryTimes); + try { + this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + Thread.sleep(sleepMillis); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + } else { + throw e; + } + } + } while (retryTimes++ < this.maxRetryTimes); + + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + if (uri.indexOf("access_token=") != -1) { + throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); + } + String accessToken = getAccessToken(false); + + String uriWithAccessToken = uri; + uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; + + try { + return executor.execute(this, uriWithAccessToken, data); + } catch (WxErrorException e) { + WxError error = e.getError(); + /* + * 发生以下情况时尝试刷新access_token + * 40001 获取access_token时AppSecret错误,或者access_token无效 + * 42001 access_token超时 + */ + if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { + // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token + this.getWxMpConfigStorage().expireAccessToken(); + if (this.getWxMpConfigStorage().autoRefreshToken()) { + return this.execute(executor, uri, data); + } + } + + if (error.getErrorCode() != 0) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); + throw new WxErrorException(error); + } + return null; + } catch (IOException e) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); + throw new RuntimeException(e); + } + } + + @Override + public WxMpConfigStorage getWxMpConfigStorage() { + return this.wxMpConfigStorage; + } + + @Override + public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { + this.wxMpConfigStorage = wxConfigProvider; + this.initHttp(); + } + + @Override + public void setRetrySleepMillis(int retrySleepMillis) { + this.retrySleepMillis = retrySleepMillis; + } + + @Override + public void setMaxRetryTimes(int maxRetryTimes) { + this.maxRetryTimes = maxRetryTimes; + } + + @Override + public WxMpKefuService getKefuService() { + return this.kefuService; + } + + @Override + public WxMpMaterialService getMaterialService() { + return this.materialService; + } + + @Override + public WxMpMenuService getMenuService() { + return this.menuService; + } + + @Override + public WxMpUserService getUserService() { + return this.userService; + } + + @Override + public WxMpUserTagService getUserTagService() { + return this.tagService; + } + + @Override + public WxMpQrcodeService getQrcodeService() { + return this.qrCodeService; + } + + @Override + public WxMpCardService getCardService() { + return this.cardService; + } + + @Override + public WxMpDataCubeService getDataCubeService() { + return this.dataCubeService; + } + + @Override + public WxMpUserBlacklistService getBlackListService() { + return this.blackListService; + } + + @Override + public WxMpStoreService getStoreService() { + return this.storeService; + } + + @Override + public WxMpTemplateMsgService getTemplateMsgService() { + return this.templateMsgService; + } + + @Override + public WxMpDeviceService getDeviceService() { + return this.deviceService; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java index 5e6f863a93..8c8085da74 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java @@ -1,73 +1,58 @@ package me.chanjar.weixin.mp.api.impl.apache; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.bean.WxJsapiSignature; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.StandardSessionManager; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.util.RandomUtils; -import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.http.*; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; -import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; -import me.chanjar.weixin.mp.api.*; -import me.chanjar.weixin.mp.api.impl.*; -import me.chanjar.weixin.mp.bean.*; -import me.chanjar.weixin.mp.bean.result.*; +import java.io.IOException; +import java.util.concurrent.locks.Lock; + import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.CloseableHttpClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.concurrent.locks.Lock; -public class WxMpServiceImpl implements WxMpService,RequestHttp { - - private static final JsonParser JSON_PARSER = new JsonParser(); +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.api.impl.AbstractWxMpService; - protected final Logger log = LoggerFactory.getLogger(this.getClass()); - protected WxSessionManager sessionManager = new StandardSessionManager(); - private WxMpConfigStorage wxMpConfigStorage; - private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); - private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); - private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); - private WxMpUserService userService = new WxMpUserServiceImpl(this); - private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this); - private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); - private WxMpCardService cardService = new WxMpCardServiceImpl(this); - private WxMpStoreService storeService = new WxMpStoreServiceImpl(this); - private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this); - private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this); - private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); - private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); +/** + * apache-http方式实现 + */ +public class WxMpServiceImpl extends AbstractWxMpService { private CloseableHttpClient httpClient; private HttpHost httpProxy; - private int retrySleepMillis = 1000; - private int maxRetryTimes = 5; @Override - public boolean checkSignature(String timestamp, String nonce, String signature) { - try { - return SHA1.gen(this.getWxMpConfigStorage().getToken(), timestamp, nonce) - .equals(signature); - } catch (Exception e) { - return false; - } + public CloseableHttpClient getRequestHttpClient() { + return httpClient; } @Override - public String getAccessToken() throws WxErrorException { - return getAccessToken(false); + public HttpHost getRequestHttpProxy() { + return httpProxy; + } + + @Override + public void initHttp() { + WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); + ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder(); + if (null == apacheHttpClientBuilder) { + apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); + } + + apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost()) + .httpProxyPort(configStorage.getHttpProxyPort()) + .httpProxyUsername(configStorage.getHttpProxyUsername()) + .httpProxyPassword(configStorage.getHttpProxyPassword()); + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort()); + } + + this.httpClient = apacheHttpClientBuilder.build(); } @Override @@ -86,11 +71,11 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { + this.getWxMpConfigStorage().getSecret(); try { HttpGet httpGet = new HttpGet(url); - if (this.httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); + if (this.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); httpGet.setConfig(config); } - try (CloseableHttpResponse response = getHttpclient().execute(httpGet)) { + try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) { String resultContent = new BasicResponseHandler().handleResponse(response); WxError error = WxError.fromJson(resultContent); if (error.getErrorCode() != 0) { @@ -111,425 +96,4 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } return this.getWxMpConfigStorage().getAccessToken(); } - - @Override - public String getJsapiTicket() throws WxErrorException { - return getJsapiTicket(false); - } - - @Override - public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { - Lock lock = this.getWxMpConfigStorage().getJsapiTicketLock(); - try { - lock.lock(); - - if (forceRefresh) { - this.getWxMpConfigStorage().expireJsapiTicket(); - } - - if (this.getWxMpConfigStorage().isJsapiTicketExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, null); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); - int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.getWxMpConfigStorage().updateJsapiTicket(jsapiTicket, expiresInSeconds); - } - } finally { - lock.unlock(); - } - return this.getWxMpConfigStorage().getJsapiTicket(); - } - - @Override - public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { - long timestamp = System.currentTimeMillis() / 1000; - String noncestr = RandomUtils.getRandomStr(); - String jsapiTicket = getJsapiTicket(false); - String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket, - "noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url); - WxJsapiSignature jsapiSignature = new WxJsapiSignature(); - jsapiSignature.setAppId(this.getWxMpConfigStorage().getAppId()); - jsapiSignature.setTimestamp(timestamp); - jsapiSignature.setNonceStr(noncestr); - jsapiSignature.setUrl(url); - jsapiSignature.setSignature(signature); - return jsapiSignature; - } - - @Override - public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; - String responseContent = this.post(url, news.toJson()); - return WxMpMassUploadResult.fromJson(responseContent); - } - - @Override - public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; - String responseContent = this.post(url, video.toJson()); - return WxMpMassUploadResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; - String responseContent = this.post(url, message.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; - String responseContent = this.post(url, message.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; - String responseContent = this.post(url, wxMpMassPreviewMessage.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public String shortUrl(String long_url) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/shorturl"; - JsonObject o = new JsonObject(); - o.addProperty("action", "long2short"); - o.addProperty("long_url", long_url); - String responseContent = this.post(url, o.toString()); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - return tmpJsonElement.getAsJsonObject().get("short_url").getAsString(); - } - - @Override - public WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/semantic/semproxy/search"; - String responseContent = this.post(url, semanticQuery.toJson()); - return WxMpSemanticQueryResult.fromJson(responseContent); - } - - @Override - public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { - StringBuilder url = new StringBuilder(); - url.append("https://open.weixin.qq.com/connect/oauth2/authorize?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); - url.append("&response_type=code"); - url.append("&scope=").append(scope); - if (state != null) { - url.append("&state=").append(state); - } - url.append("#wechat_redirect"); - return url.toString(); - } - - @Override - public String buildQrConnectUrl(String redirectURI, String scope, - String state) { - StringBuilder url = new StringBuilder(); - url.append("https://open.weixin.qq.com/connect/qrconnect?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); - url.append("&response_type=code"); - url.append("&scope=").append(scope); - if (state != null) { - url.append("&state=").append(state); - } - - url.append("#wechat_redirect"); - return url.toString(); - } - - private WxMpOAuth2AccessToken getOAuth2AccessToken(StringBuilder url) throws WxErrorException { - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(this, url.toString(), null); - return WxMpOAuth2AccessToken.fromJson(responseText); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/oauth2/access_token?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&secret=").append(this.getWxMpConfigStorage().getSecret()); - url.append("&code=").append(code); - url.append("&grant_type=authorization_code"); - - return this.getOAuth2AccessToken(url); - } - - @Override - public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/oauth2/refresh_token?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&grant_type=refresh_token"); - url.append("&refresh_token=").append(refreshToken); - - return this.getOAuth2AccessToken(url); - } - - @Override - public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/userinfo?"); - url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); - url.append("&openid=").append(oAuth2AccessToken.getOpenId()); - if (lang == null) { - url.append("&lang=zh_CN"); - } else { - url.append("&lang=").append(lang); - } - - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(this, url.toString(), null); - return WxMpUser.fromJson(responseText); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/auth?"); - url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); - url.append("&openid=").append(oAuth2AccessToken.getOpenId()); - - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - executor.execute(this, url.toString(), null); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (WxErrorException e) { - return false; - } - return true; - } - - @Override - public String[] getCallbackIP() throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/getcallbackip"; - String responseContent = get(url, null); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - JsonArray ipList = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); - String[] ipArray = new String[ipList.size()]; - for (int i = 0; i < ipList.size(); i++) { - ipArray[i] = ipList.get(i).getAsString(); - } - return ipArray; - } - - @Override - public String get(String url, String queryParam) throws WxErrorException { - return execute(new SimpleGetRequestExecutor(), url, queryParam); - } - - @Override - public String post(String url, String postData) throws WxErrorException { - return execute(new SimplePostRequestExecutor(), url, postData); - } - - /** - * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 - */ - @Override - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { - int retryTimes = 0; - do { - try { - T result = executeInternal(executor, uri, data); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, result); - return result; - } catch (WxErrorException e) { - if (retryTimes + 1 > this.maxRetryTimes) { - this.log.warn("重试达到最大次数【{}】", maxRetryTimes); - //最后一次重试失败后,直接抛出异常,不再等待 - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - WxError error = e.getError(); - // -1 系统繁忙, 1000ms后重试 - if (error.getErrorCode() == -1) { - int sleepMillis = this.retrySleepMillis * (1 << retryTimes); - try { - this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); - Thread.sleep(sleepMillis); - } catch (InterruptedException e1) { - throw new RuntimeException(e1); - } - } else { - throw e; - } - } - } while (retryTimes++ < this.maxRetryTimes); - - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { - if (uri.indexOf("access_token=") != -1) { - throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); - } - String accessToken = getAccessToken(false); - - String uriWithAccessToken = uri; - uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; - - try { - return executor.execute(this, uriWithAccessToken, data); - } catch (WxErrorException e) { - WxError error = e.getError(); - /* - * 发生以下情况时尝试刷新access_token - * 40001 获取access_token时AppSecret错误,或者access_token无效 - * 42001 access_token超时 - */ - if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { - // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token - this.getWxMpConfigStorage().expireAccessToken(); - if (this.getWxMpConfigStorage().autoRefreshToken()) { - return this.execute(executor, uri, data); - } - } - - if (error.getErrorCode() != 0) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); - throw new WxErrorException(error); - } - return null; - } catch (IOException e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); - throw new RuntimeException(e); - } - } - - //@Override - public HttpHost getHttpProxy() { - return this.httpProxy; - } - - //@Override - public CloseableHttpClient getHttpclient() { - return this.httpClient; - } - - private void initHttpClient() { - WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); - ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder(); - if (null == apacheHttpClientBuilder) { - apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); - } - - apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost()) - .httpProxyPort(configStorage.getHttpProxyPort()) - .httpProxyUsername(configStorage.getHttpProxyUsername()) - .httpProxyPassword(configStorage.getHttpProxyPassword()); - - if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { - this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort()); - } - - this.httpClient = apacheHttpClientBuilder.build(); - } - - @Override - public WxMpConfigStorage getWxMpConfigStorage() { - return this.wxMpConfigStorage; - } - - @Override - public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { - this.wxMpConfigStorage = wxConfigProvider; - this.initHttpClient(); - } - - @Override - public void setRetrySleepMillis(int retrySleepMillis) { - this.retrySleepMillis = retrySleepMillis; - } - - @Override - public void setMaxRetryTimes(int maxRetryTimes) { - this.maxRetryTimes = maxRetryTimes; - } - - @Override - public WxMpKefuService getKefuService() { - return this.kefuService; - } - - @Override - public WxMpMaterialService getMaterialService() { - return this.materialService; - } - - @Override - public WxMpMenuService getMenuService() { - return this.menuService; - } - - @Override - public WxMpUserService getUserService() { - return this.userService; - } - - @Override - public WxMpUserTagService getUserTagService() { - return this.tagService; - } - - @Override - public WxMpQrcodeService getQrcodeService() { - return this.qrCodeService; - } - - @Override - public WxMpCardService getCardService() { - return this.cardService; - } - - @Override - public WxMpDataCubeService getDataCubeService() { - return this.dataCubeService; - } - - @Override - public WxMpUserBlacklistService getBlackListService() { - return this.blackListService; - } - - @Override - public WxMpStoreService getStoreService() { - return this.storeService; - } - - @Override - public WxMpTemplateMsgService getTemplateMsgService() { - return this.templateMsgService; - } - - @Override - public WxMpDeviceService getDeviceService() { - return this.deviceService; - } - - @Override - public Object getRequestHttpClient() { - return this.httpClient; - } - - @Override - public Object getRequestHttpProxy() { - return this.httpProxy; - } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java index fa342f66dd..0c4bdf81f0 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java @@ -1,56 +1,35 @@ package me.chanjar.weixin.mp.api.impl.jodd; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; + import jodd.http.*; import jodd.http.net.SocketHttpConnectionProvider; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.StandardSessionManager; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.util.RandomUtils; -import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.http.*; import me.chanjar.weixin.mp.api.*; import me.chanjar.weixin.mp.api.impl.*; -import me.chanjar.weixin.mp.bean.*; -import me.chanjar.weixin.mp.bean.result.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.io.IOException; import java.util.concurrent.locks.Lock; -public class WxMpServiceImpl implements WxMpService,RequestHttp { - - private static final JsonParser JSON_PARSER = new JsonParser(); - - protected final Logger log = LoggerFactory.getLogger(this.getClass()); - protected WxSessionManager sessionManager = new StandardSessionManager(); - private WxMpConfigStorage wxMpConfigStorage; - private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); - private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); - private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); - private WxMpUserService userService = new WxMpUserServiceImpl(this); - private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this); - private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); - private WxMpCardService cardService = new WxMpCardServiceImpl(this); - private WxMpStoreService storeService = new WxMpStoreServiceImpl(this); - private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this); - private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this); - private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); - private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); - +/** + * jodd-http方式实现 + */ +public class WxMpServiceImpl extends AbstractWxMpService { private HttpConnectionProvider httpClient; private ProxyInfo httpProxy; - private int retrySleepMillis = 1000; - private int maxRetryTimes = 5; - private void initHttpClient() { + @Override + public HttpConnectionProvider getRequestHttpClient() { + return httpClient; + } + + @Override + public ProxyInfo getRequestHttpProxy() { + return httpProxy; + } + + @Override + public void initHttp() { WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { @@ -60,20 +39,7 @@ private void initHttpClient() { httpClient = JoddHttp.httpConnectionProvider; } - @Override - public boolean checkSignature(String timestamp, String nonce, String signature) { - try { - return SHA1.gen(this.getWxMpConfigStorage().getToken(), timestamp, nonce) - .equals(signature); - } catch (Exception e) { - return false; - } - } - @Override - public String getAccessToken() throws WxErrorException { - return getAccessToken(false); - } @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { @@ -91,9 +57,9 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { + this.getWxMpConfigStorage().getSecret(); HttpRequest request = HttpRequest.get(url); - if (this.httpProxy != null) { + if (this.getRequestHttpProxy() != null) { SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); - provider.useProxy(httpProxy); + provider.useProxy(getRequestHttpProxy()); request.withConnectionProvider(provider); } HttpResponse response = request.send(); @@ -111,406 +77,4 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } return this.getWxMpConfigStorage().getAccessToken(); } - - @Override - public String getJsapiTicket() throws WxErrorException { - return getJsapiTicket(false); - } - - @Override - public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { - Lock lock = this.getWxMpConfigStorage().getJsapiTicketLock(); - try { - lock.lock(); - - if (forceRefresh) { - this.getWxMpConfigStorage().expireJsapiTicket(); - } - - if (this.getWxMpConfigStorage().isJsapiTicketExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, null); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); - int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.getWxMpConfigStorage().updateJsapiTicket(jsapiTicket, expiresInSeconds); - } - } finally { - lock.unlock(); - } - return this.getWxMpConfigStorage().getJsapiTicket(); - } - - @Override - public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { - long timestamp = System.currentTimeMillis() / 1000; - String noncestr = RandomUtils.getRandomStr(); - String jsapiTicket = getJsapiTicket(false); - String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket, - "noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url); - WxJsapiSignature jsapiSignature = new WxJsapiSignature(); - jsapiSignature.setAppId(this.getWxMpConfigStorage().getAppId()); - jsapiSignature.setTimestamp(timestamp); - jsapiSignature.setNonceStr(noncestr); - jsapiSignature.setUrl(url); - jsapiSignature.setSignature(signature); - return jsapiSignature; - } - - @Override - public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; - String responseContent = this.post(url, news.toJson()); - return WxMpMassUploadResult.fromJson(responseContent); - } - - @Override - public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; - String responseContent = this.post(url, video.toJson()); - return WxMpMassUploadResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; - String responseContent = this.post(url, message.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; - String responseContent = this.post(url, message.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; - String responseContent = this.post(url, wxMpMassPreviewMessage.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public String shortUrl(String long_url) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/shorturl"; - JsonObject o = new JsonObject(); - o.addProperty("action", "long2short"); - o.addProperty("long_url", long_url); - String responseContent = this.post(url, o.toString()); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - return tmpJsonElement.getAsJsonObject().get("short_url").getAsString(); - } - - @Override - public WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/semantic/semproxy/search"; - String responseContent = this.post(url, semanticQuery.toJson()); - return WxMpSemanticQueryResult.fromJson(responseContent); - } - - @Override - public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { - StringBuilder url = new StringBuilder(); - url.append("https://open.weixin.qq.com/connect/oauth2/authorize?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); - url.append("&response_type=code"); - url.append("&scope=").append(scope); - if (state != null) { - url.append("&state=").append(state); - } - url.append("#wechat_redirect"); - return url.toString(); - } - - @Override - public String buildQrConnectUrl(String redirectURI, String scope, - String state) { - StringBuilder url = new StringBuilder(); - url.append("https://open.weixin.qq.com/connect/qrconnect?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); - url.append("&response_type=code"); - url.append("&scope=").append(scope); - if (state != null) { - url.append("&state=").append(state); - } - - url.append("#wechat_redirect"); - return url.toString(); - } - - private WxMpOAuth2AccessToken getOAuth2AccessToken(StringBuilder url) throws WxErrorException { - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(this, url.toString(), null); - return WxMpOAuth2AccessToken.fromJson(responseText); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/oauth2/access_token?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&secret=").append(this.getWxMpConfigStorage().getSecret()); - url.append("&code=").append(code); - url.append("&grant_type=authorization_code"); - - return this.getOAuth2AccessToken(url); - } - - @Override - public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/oauth2/refresh_token?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&grant_type=refresh_token"); - url.append("&refresh_token=").append(refreshToken); - - return this.getOAuth2AccessToken(url); - } - - @Override - public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/userinfo?"); - url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); - url.append("&openid=").append(oAuth2AccessToken.getOpenId()); - if (lang == null) { - url.append("&lang=zh_CN"); - } else { - url.append("&lang=").append(lang); - } - - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(this, url.toString(), null); - return WxMpUser.fromJson(responseText); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/auth?"); - url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); - url.append("&openid=").append(oAuth2AccessToken.getOpenId()); - - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - executor.execute(this, url.toString(), null); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (WxErrorException e) { - return false; - } - return true; - } - - @Override - public String[] getCallbackIP() throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/getcallbackip"; - String responseContent = get(url, null); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - JsonArray ipList = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); - String[] ipArray = new String[ipList.size()]; - for (int i = 0; i < ipList.size(); i++) { - ipArray[i] = ipList.get(i).getAsString(); - } - return ipArray; - } - - @Override - public String get(String url, String queryParam) throws WxErrorException { - return execute(new SimpleGetRequestExecutor(), url, queryParam); - } - - @Override - public String post(String url, String postData) throws WxErrorException { - return execute(new SimplePostRequestExecutor(), url, postData); - } - - //@Override - public HttpConnectionProvider getHttpclient() { - return this.httpClient; - } - - //@Override - public Object getHttpProxy() { - return null; - } - - /** - * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 - */ - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { - int retryTimes = 0; - do { - try { - T result = executeInternal(executor, uri, data); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, result); - return result; - } catch (WxErrorException e) { - if (retryTimes + 1 > this.maxRetryTimes) { - this.log.warn("重试达到最大次数【{}】", maxRetryTimes); - //最后一次重试失败后,直接抛出异常,不再等待 - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - WxError error = e.getError(); - // -1 系统繁忙, 1000ms后重试 - if (error.getErrorCode() == -1) { - int sleepMillis = this.retrySleepMillis * (1 << retryTimes); - try { - this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); - Thread.sleep(sleepMillis); - } catch (InterruptedException e1) { - throw new RuntimeException(e1); - } - } else { - throw e; - } - } - } while (retryTimes++ < this.maxRetryTimes); - - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { - if (uri.indexOf("access_token=") != -1) { - throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); - } - String accessToken = getAccessToken(false); - - String uriWithAccessToken = uri; - uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; - - try { - return executor.execute(this, uriWithAccessToken, data); - } catch (WxErrorException e) { - WxError error = e.getError(); - /* - * 发生以下情况时尝试刷新access_token - * 40001 获取access_token时AppSecret错误,或者access_token无效 - * 42001 access_token超时 - */ - if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { - // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token - this.getWxMpConfigStorage().expireAccessToken(); - if (this.getWxMpConfigStorage().autoRefreshToken()) { - return this.execute(executor, uri, data); - } - } - - if (error.getErrorCode() != 0) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); - throw new WxErrorException(error); - } - return null; - } catch (IOException e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); - throw new RuntimeException(e); - } - } - - @Override - public Object getRequestHttpClient() { - return this.httpClient; - } - - @Override - public Object getRequestHttpProxy() { - return this.httpProxy; - } - - - @Override - public WxMpConfigStorage getWxMpConfigStorage() { - return this.wxMpConfigStorage; - } - - @Override - public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { - this.wxMpConfigStorage = wxConfigProvider; - this.initHttpClient(); - } - - @Override - public void setRetrySleepMillis(int retrySleepMillis) { - this.retrySleepMillis = retrySleepMillis; - } - - @Override - public void setMaxRetryTimes(int maxRetryTimes) { - this.maxRetryTimes = maxRetryTimes; - } - - @Override - public WxMpKefuService getKefuService() { - return this.kefuService; - } - - @Override - public WxMpMaterialService getMaterialService() { - return this.materialService; - } - - @Override - public WxMpMenuService getMenuService() { - return this.menuService; - } - - @Override - public WxMpUserService getUserService() { - return this.userService; - } - - @Override - public WxMpUserTagService getUserTagService() { - return this.tagService; - } - - @Override - public WxMpQrcodeService getQrcodeService() { - return this.qrCodeService; - } - - @Override - public WxMpCardService getCardService() { - return this.cardService; - } - - @Override - public WxMpDataCubeService getDataCubeService() { - return this.dataCubeService; - } - - @Override - public WxMpUserBlacklistService getBlackListService() { - return this.blackListService; - } - - @Override - public WxMpStoreService getStoreService() { - return this.storeService; - } - - @Override - public WxMpTemplateMsgService getTemplateMsgService() { - return this.templateMsgService; - } - - @Override - public WxMpDeviceService getDeviceService() { - return this.deviceService; - } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java new file mode 100644 index 0000000000..2eebb5ff90 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java @@ -0,0 +1,96 @@ +package me.chanjar.weixin.mp.api.impl.okhttp; + +import java.io.IOException; +import java.util.concurrent.locks.Lock; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.mp.api.*; +import me.chanjar.weixin.mp.api.impl.*; +import okhttp3.*; + +public class WxMpServiceImpl extends AbstractWxMpService { + + + private ConnectionPool httpClient; + private OkhttpProxyInfo httpProxy; + + + @Override + public ConnectionPool getRequestHttpClient() { + return httpClient; + } + + @Override + public OkhttpProxyInfo getRequestHttpProxy() { + return httpProxy; + } + + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.getWxMpConfigStorage().expireAccessToken(); + } + + if (this.getWxMpConfigStorage().isAccessTokenExpired()) { + String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + + "&appid=" + this.getWxMpConfigStorage().getAppId() + "&secret=" + + this.getWxMpConfigStorage().getSecret(); + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(httpClient); + //设置代理 + if (httpProxy != null) { + clientBuilder.proxy(getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + Request request =new Request.Builder().url(url).get().build(); + Response response =client.newCall(request).execute(); + String resultContent = response.body().toString(); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), + accessToken.getExpiresIn()); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + return this.getWxMpConfigStorage().getAccessToken(); + } + + @Override + public void initHttp() { + WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + httpProxy = new OkhttpProxyInfo(OkhttpProxyInfo.ProxyType.SOCKS5, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + } + + httpClient = new ConnectionPool(); + } + + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java index ef3f31b6e2..473d11609e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java @@ -6,10 +6,14 @@ import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import okhttp3.*; + import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -21,7 +25,7 @@ import java.util.HashMap; import java.util.Map; -public class MaterialDeleteRequestExecutor implements RequestExecutor { +public class MaterialDeleteRequestExecutor extends AbstractRequestExecutor { public MaterialDeleteRequestExecutor() { @@ -29,25 +33,32 @@ public MaterialDeleteRequestExecutor() { } @Override - public Boolean execute(RequestHttp requestHttp, String uri, String materialId) throws WxErrorException, IOException { - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, materialId); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, materialId); - } else { - //这里需要抛出异常,需要优化 - return null; + public Boolean executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); + httpPost.setConfig(config); } - + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return true; + } + } finally { + httpPost.releaseConnection(); + } } - private Boolean executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { + @Override + public Boolean executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { HttpRequest request = HttpRequest.post(uri); if (proxyInfo != null) { provider.useProxy(proxyInfo); @@ -65,27 +76,35 @@ private Boolean executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo } } - private Boolean executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); + @Override + public Boolean executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); } - - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return true; + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); } - } finally { - httpPost.releaseConnection(); + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).post(requestBody).build(); + Response response = client.newCall(request).execute(); + String responseContent = response.body().toString(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return true; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java index 8718006724..8c36d16b12 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java @@ -6,12 +6,16 @@ import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import okhttp3.*; + import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -23,30 +27,13 @@ import java.util.HashMap; import java.util.Map; -public class MaterialNewsInfoRequestExecutor implements RequestExecutor { +public class MaterialNewsInfoRequestExecutor extends AbstractRequestExecutor { public MaterialNewsInfoRequestExecutor() { super(); } @Override - public WxMpMaterialNews execute(RequestHttp requestHttp, String uri, - String materialId) throws WxErrorException, IOException { - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, materialId); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, materialId); - } else { - //这里需要抛出异常,需要优化 - return null; - } - } - public WxMpMaterialNews executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String materialId) throws WxErrorException, IOException { HttpPost httpPost = new HttpPost(uri); if (httpProxy != null) { @@ -70,7 +57,7 @@ public WxMpMaterialNews executeApache(CloseableHttpClient httpclient, HttpHost h } } - + @Override public WxMpMaterialNews executeJodd(HttpConnectionProvider httpclient, ProxyInfo httpProxy, String uri, String materialId) throws WxErrorException, IOException { HttpRequest request = HttpRequest.post(uri); if (httpProxy != null) { @@ -81,7 +68,40 @@ public WxMpMaterialNews executeJodd(HttpConnectionProvider httpclient, ProxyInfo request.query("media_id", materialId); HttpResponse response = request.send(); - String responseContent = request.bodyText(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + } + } + + @Override + public WxMpMaterialNews executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).post(requestBody).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().toString(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java index a1e1a91bd3..25286a34ff 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java @@ -6,12 +6,16 @@ import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.bean.material.WxMpMaterial; import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import okhttp3.*; + import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -26,26 +30,10 @@ import java.io.IOException; import java.util.Map; -public class MaterialUploadRequestExecutor implements RequestExecutor { +public class MaterialUploadRequestExecutor extends AbstractRequestExecutor { @Override - public WxMpMaterialUploadResult execute(RequestHttp requestHttp, String uri, WxMpMaterial material) throws WxErrorException, IOException { - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, material); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, material); - } else { - //这里需要抛出异常,需要优化 - return null; - } - } - - private WxMpMaterialUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, WxMpMaterial material) throws WxErrorException, IOException { + public WxMpMaterialUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, WxMpMaterial material) throws WxErrorException, IOException { HttpRequest request = HttpRequest.post(uri); if (httpProxy != null) { provider.useProxy(httpProxy); @@ -76,8 +64,56 @@ private WxMpMaterialUploadResult executeJodd(HttpConnectionProvider provider, Pr } } - private WxMpMaterialUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - WxMpMaterial material) throws WxErrorException, IOException { + @Override + public WxMpMaterialUploadResult executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, WxMpMaterial material) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + + if (material == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); + } + + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); + MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().addFormDataPart("media", null, fileBody); + Map form = material.getForm(); + if (material.getForm() != null) { + bodyBuilder.addFormDataPart("description", WxGsonBuilder.create().toJson(form)); + } + RequestBody body =bodyBuilder.build(); + Request request = new Request.Builder().url(uri).post(body).build(); + Response response = client.newCall(request).execute(); + String responseContent = response.body().toString(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialUploadResult.fromJson(responseContent); + } + } + + @Override + public WxMpMaterialUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + WxMpMaterial material) throws WxErrorException, IOException { HttpPost httpPost = new HttpPost(uri); if (httpProxy != null) { RequestConfig response = RequestConfig.custom().setProxy(httpProxy).build(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java index fb5818926e..22020ce18a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java @@ -6,11 +6,16 @@ import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import okhttp3.*; + import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -22,31 +27,14 @@ import java.util.HashMap; import java.util.Map; -public class MaterialVideoInfoRequestExecutor implements RequestExecutor { +public class MaterialVideoInfoRequestExecutor extends AbstractRequestExecutor { public MaterialVideoInfoRequestExecutor() { super(); } @Override - public WxMpMaterialVideoInfoResult execute(RequestHttp requestHttp, String uri, String materialId) throws WxErrorException, IOException { - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, materialId); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, materialId); - } else { - //这里需要抛出异常,需要优化 - return null; - } - } - - - private WxMpMaterialVideoInfoResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { + public WxMpMaterialVideoInfoResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { HttpRequest request = HttpRequest.post(uri); if (proxyInfo != null) { provider.useProxy(proxyInfo); @@ -64,8 +52,41 @@ private WxMpMaterialVideoInfoResult executeJodd(HttpConnectionProvider provider, } } - private WxMpMaterialVideoInfoResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - String materialId) throws WxErrorException, IOException { + @Override + public WxMpMaterialVideoInfoResult executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody =new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).post(requestBody).build(); + Response response = client.newCall(request).execute(); + String responseContent = response.body().toString(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); + } + } + + @Override + public WxMpMaterialVideoInfoResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + String materialId) throws WxErrorException, IOException { HttpPost httpPost = new HttpPost(uri); if (httpProxy != null) { RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java index 913ca0862f..b97483590d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java @@ -6,10 +6,15 @@ import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import okhttp3.*; + import org.apache.commons.io.IOUtils; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -25,8 +30,7 @@ import java.util.HashMap; import java.util.Map; -public class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { - +public class MaterialVoiceAndImageDownloadRequestExecutor extends AbstractRequestExecutor { public MaterialVoiceAndImageDownloadRequestExecutor() { super(); @@ -36,24 +40,9 @@ public MaterialVoiceAndImageDownloadRequestExecutor(File tmpDirFile) { super(); } - @Override - public InputStream execute(RequestHttp requestHttp, String uri, String materialId) throws WxErrorException, IOException { - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, materialId); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, materialId); - } else { - //这里需要抛出异常,需要优化 - return null; - } - } - private InputStream executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { + @Override + public InputStream executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { HttpRequest request = HttpRequest.post(uri); if (proxyInfo != null) { provider.useProxy(proxyInfo); @@ -81,8 +70,51 @@ private InputStream executeJodd(HttpConnectionProvider provider, ProxyInfo proxy } - private InputStream executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - String materialId) throws WxErrorException, IOException { + @Override + public InputStream executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).get().post(requestBody).build(); + Response response = client.newCall(request).execute(); + + try (InputStream inputStream = new ByteArrayInputStream(response.body().bytes())) { + // 下载媒体文件出错 + byte[] responseContent = IOUtils.toByteArray(inputStream); + String responseContentString = new String(responseContent, "UTF-8"); + if (responseContentString.length() < 100) { + try { + WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); + if (wxError.getErrorCode() != 0) { + throw new WxErrorException(wxError); + } + } catch (com.google.gson.JsonSyntaxException ex) { + return new ByteArrayInputStream(responseContent); + } + } + return new ByteArrayInputStream(responseContent); + } + } + + @Override + public InputStream executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + String materialId) throws WxErrorException, IOException { HttpPost httpPost = new HttpPost(uri); if (httpProxy != null) { RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java index c22bc31098..51f283e61a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java @@ -4,12 +4,19 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; +import jodd.util.MimeTypes; import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import okhttp3.*; + import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -20,34 +27,20 @@ import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; /** * @author miller */ -public class MediaImgUploadRequestExecutor implements RequestExecutor { - - @Override - public WxMediaImgUploadResult execute(RequestHttp requestHttp, String uri, File data) throws WxErrorException, IOException { - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, data); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, data); - } else { - //这里需要抛出异常,需要优化 - return null; - } - - } +public class MediaImgUploadRequestExecutor extends AbstractRequestExecutor { - private WxMediaImgUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, File data) throws WxErrorException, IOException { + @Override + public WxMediaImgUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, File data) throws WxErrorException, IOException { if (data == null) { throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); } @@ -69,8 +62,43 @@ private WxMediaImgUploadResult executeJodd(HttpConnectionProvider provider, Prox return WxMediaImgUploadResult.fromJson(responseContent); } - private WxMediaImgUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - File data) throws WxErrorException, IOException { + @Override + public WxMediaImgUploadResult executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, File data) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), data); + RequestBody body = new MultipartBody.Builder().addFormDataPart("media", null, fileBody).build(); + Request request = new Request.Builder().url(uri).post(body).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().toString(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + + return WxMediaImgUploadResult.fromJson(responseContent); + } + + @Override + public WxMediaImgUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + File data) throws WxErrorException, IOException { if (data == null) { throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java index c9ae525c29..3a140637a1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java @@ -8,11 +8,14 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import okhttp3.*; + import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -33,27 +36,10 @@ * * @author chanjarster */ -public class QrCodeRequestExecutor implements RequestExecutor { - - @Override - public File execute(RequestHttp requestHttp, String uri, - WxMpQrCodeTicket ticket) throws WxErrorException, IOException { - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, ticket); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, ticket); - } else { - //这里需要抛出异常,需要优化 - return null; - } - } +public class QrCodeRequestExecutor extends AbstractRequestExecutor { - private File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, WxMpQrCodeTicket ticket) throws WxErrorException, IOException { +@Override + public File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, WxMpQrCodeTicket ticket) throws WxErrorException, IOException { if (ticket != null) { if (uri.indexOf('?') == -1) { uri += '?'; @@ -80,8 +66,41 @@ private File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, S } } - private File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - WxMpQrCodeTicket ticket) throws WxErrorException, IOException { + @Override + public File executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, WxMpQrCodeTicket data) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + Request request = new Request.Builder().url(uri).get().build(); + Response response = client.newCall(request).execute(); + String contentTypeHeader = response.header("Content-Type"); + if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { + String responseContent = response.body().toString(); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + try (InputStream inputStream = new ByteArrayInputStream(response.body().bytes())) { + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } + } + + @Override + public File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, + WxMpQrCodeTicket ticket) throws WxErrorException, IOException { if (ticket != null) { if (uri.indexOf('?') == -1) { uri += '?'; @@ -113,4 +132,5 @@ private File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, S } } + } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java index 74777caef0..39013f66d8 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java @@ -3,7 +3,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl; + import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -17,7 +17,7 @@ public class WxMpBusyRetryTest { @DataProvider(name = "getService") public Object[][] getService() { - WxMpService service = new WxMpServiceImpl() { + WxMpService service = new WxMpServiceImpl0() { @Override public synchronized T executeInternal( diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java index 2cfaec543c..b9ce06c6f7 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java @@ -6,7 +6,6 @@ import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl; import java.io.IOException; import java.io.InputStream; @@ -19,7 +18,7 @@ public void configure(Binder binder) { try (InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml")) { TestConfigStorage config = this.fromXml(TestConfigStorage.class, is1); config.setAccessTokenLock(new ReentrantLock()); - WxMpService wxService = new WxMpServiceImpl(); + WxMpService wxService = new WxMpServiceImpl0(); wxService.setWxMpConfigStorage(config); binder.bind(WxMpService.class).toInstance(wxService); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java index e2c75f83d6..4d3ce9dfec 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java @@ -5,7 +5,7 @@ import me.chanjar.weixin.mp.api.WxMpMessageHandler; import me.chanjar.weixin.mp.api.WxMpMessageRouter; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl; + import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; @@ -47,7 +47,7 @@ private static void initWeixin() { .fromXml(is1); wxMpConfigStorage = config; - wxMpService = new WxMpServiceImpl(); + wxMpService = new WxMpServiceImpl0(); wxMpService.setWxMpConfigStorage(config); WxMpMessageHandler logHandler = new DemoLogHandler(); diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index d0d50455f8..0b2b6c0bf1 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -19,13 +19,6 @@ weixin-java-common ${project.version} - - - org.jodd - jodd-http - 3.7 - - com.github.binarywang qrcode-utils From d01d372b654ff1714c1498d117ca7277a0f1cc05 Mon Sep 17 00:00:00 2001 From: ecoolper Date: Thu, 27 Apr 2017 20:14:52 +0800 Subject: [PATCH 016/179] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E5=86=B2?= =?UTF-8?q?=E7=AA=81=E5=92=8C=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/MediaDownloadRequestExecutor.java | 22 +++---------------- .../cp/api/impl/apache/WxCpServiceImpl.java | 4 +--- .../cp/api/impl/jodd/WxCpServiceImpl.java | 3 --- .../mp/api/impl/apache/WxMpServiceImpl.java | 4 ---- .../weixin/mp/api/WxMpBusyRetryTest.java | 2 +- .../weixin/mp/api/test/ApiTestModule.java | 2 +- .../weixin/mp/demo/WxMpDemoServer.java | 3 +-- 7 files changed, 7 insertions(+), 33 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java index 3cb1d5631e..e95f02de24 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java @@ -10,7 +10,6 @@ import me.chanjar.weixin.common.util.fs.FileUtils; import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; - import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import okhttp3.*; @@ -112,7 +111,7 @@ public File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, St } } - String fileName = getFileNameApache(response); + String fileName = getFileName(response); if (StringUtils.isBlank(fileName)) { return null; } @@ -129,6 +128,7 @@ public File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, St /** * jodd-http实现方式 + * * @param provider * @param proxyInfo * @param uri @@ -237,23 +237,7 @@ private String getFileName(Response response) throws WxErrorException { if (m.matches()) { return m.group(1); } - request.withConnectionProvider(provider); - HttpResponse response = request.send(); - String contentType = response.header("Content-Type"); - if (contentType != null && contentType.startsWith("application/json")) { - // application/json; encoding=utf-8 下载媒体文件出错 - throw new WxErrorException(WxError.fromJson(response.bodyText())); - } - - String fileName = getFileNameJodd(response); - if (StringUtils.isBlank(fileName)) { - return null; - } - - InputStream inputStream = new ByteArrayInputStream(response.bodyBytes()); - String[] nameAndExt = fileName.split("\\."); - return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); } - } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java index ca0ed4620d..8e4d57e39e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java @@ -1,5 +1,6 @@ package me.chanjar.weixin.cp.api.impl.apache; + import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; @@ -7,7 +8,6 @@ import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; import me.chanjar.weixin.cp.api.impl.AbstractWxCpService; - import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -73,7 +73,6 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } @Override - public void initHttp() { ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage .getApacheHttpClientBuilder(); @@ -92,5 +91,4 @@ public void initHttp() { this.httpClient = apacheHttpClientBuilder.build(); } - } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java index c2a2eb6e7e..f0af34746b 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java @@ -19,7 +19,6 @@ public HttpConnectionProvider getRequestHttpClient() { @Override public ProxyInfo getRequestHttpProxy() { return httpProxy; - } @Override @@ -57,12 +56,10 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { @Override public void initHttp() { - if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) { httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); } httpClient = JoddHttp.httpConnectionProvider; } - } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java index 37f7e5a441..8c8085da74 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java @@ -1,6 +1,5 @@ package me.chanjar.weixin.mp.api.impl.apache; - import java.io.IOException; import java.util.concurrent.locks.Lock; @@ -72,13 +71,11 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { + this.getWxMpConfigStorage().getSecret(); try { HttpGet httpGet = new HttpGet(url); - if (this.getRequestHttpProxy() != null) { RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); httpGet.setConfig(config); } try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) { - String resultContent = new BasicResponseHandler().handleResponse(response); WxError error = WxError.fromJson(resultContent); if (error.getErrorCode() != 0) { @@ -99,5 +96,4 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } return this.getWxMpConfigStorage().getAccessToken(); } - } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java index 3cdce4a74c..8a8c717043 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java @@ -19,7 +19,7 @@ public class WxMpBusyRetryTest { @DataProvider(name = "getService") public Object[][] getService() { - WxMpService service = new WxMpServiceImpl0() { + WxMpService service = new WxMpServiceImpl() { @Override public synchronized T executeInternal( diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java index 696c9416c4..03e01444f7 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java @@ -20,7 +20,7 @@ public void configure(Binder binder) { try (InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml")) { TestConfigStorage config = this.fromXml(TestConfigStorage.class, is1); config.setAccessTokenLock(new ReentrantLock()); - WxMpService wxService = new WxMpServiceImpl0(); + WxMpService wxService = new WxMpServiceImpl(); wxService.setWxMpConfigStorage(config); binder.bind(WxMpService.class).toInstance(wxService); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java index 7e6c585a0f..66b90d0f7f 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java @@ -5,7 +5,6 @@ import me.chanjar.weixin.mp.api.WxMpMessageHandler; import me.chanjar.weixin.mp.api.WxMpMessageRouter; import me.chanjar.weixin.mp.api.WxMpService; - import me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl; import org.eclipse.jetty.server.Server; @@ -49,7 +48,7 @@ private static void initWeixin() { .fromXml(is1); wxMpConfigStorage = config; - wxMpService = new WxMpServiceImpl0(); + wxMpService = new WxMpServiceImpl(); wxMpService.setWxMpConfigStorage(config); WxMpMessageHandler logHandler = new DemoLogHandler(); From f42b22f5c19fba66ffd8f726533d55758085538c Mon Sep 17 00:00:00 2001 From: ecoolper Date: Thu, 27 Apr 2017 20:24:42 +0800 Subject: [PATCH 017/179] =?UTF-8?q?WxCpService=E6=B7=BB=E5=8A=A0getWxMpCon?= =?UTF-8?q?figStorage=E6=96=B9=E6=B3=95=EF=BC=8C=E5=90=8C=E6=97=B6?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=9B=B8=E5=85=B3=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/me/chanjar/weixin/cp/api/WxCpService.java | 7 +++++++ .../chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java | 6 ++++++ .../chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java | 6 ++++++ .../chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java | 5 +++++ .../weixin/cp/api/impl/apache/WxCpMessageAPITest.java | 2 +- 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 4b15fdb153..3da42ea18b 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -556,4 +556,11 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * 初始化http请求对象 */ void initHttp(); + + /** + * 获取WxMpConfigStorage 对象 + * + * @return WxMpConfigStorage + */ + WxCpConfigStorage getWxMpConfigStorage(); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java index 8e4d57e39e..453e33bee3 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java @@ -6,6 +6,7 @@ import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; +import me.chanjar.weixin.cp.api.WxCpConfigStorage; import me.chanjar.weixin.cp.api.impl.AbstractWxCpService; import org.apache.http.HttpHost; @@ -91,4 +92,9 @@ public void initHttp() { this.httpClient = apacheHttpClientBuilder.build(); } + + @Override + public WxCpConfigStorage getWxMpConfigStorage() { + return this.configStorage; + } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java index f0af34746b..6c0994ad76 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java @@ -4,6 +4,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpConfigStorage; import me.chanjar.weixin.cp.api.impl.AbstractWxCpService; public class WxCpServiceImpl extends AbstractWxCpService { @@ -62,4 +63,9 @@ public void initHttp() { httpClient = JoddHttp.httpConnectionProvider; } + + @Override + public WxCpConfigStorage getWxMpConfigStorage() { + return this.configStorage; + } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java index 39db38166c..b371be9d17 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java @@ -87,4 +87,9 @@ public void initHttp() { httpClient = new ConnectionPool(); } + + @Override + public WxCpConfigStorage getWxMpConfigStorage() { + return this.configStorage; + } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java index 968cfea944..2d46f29f21 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java @@ -21,7 +21,7 @@ public class WxCpMessageAPITest { protected WxCpServiceImpl wxService; public void testSendCustomMessage() throws WxErrorException { - ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlCpInMemoryConfigStorage) this.wxService.configStorage; + ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlCpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage(); WxCpMessage message1 = new WxCpMessage(); message1.setAgentId(configStorage.getAgentId()); message1.setMsgType(WxConsts.CUSTOM_MSG_TEXT); From 57e1f0919b5f0c56e465b38baf3bf8625e78993a Mon Sep 17 00:00:00 2001 From: ecoolper Date: Thu, 27 Apr 2017 20:32:05 +0800 Subject: [PATCH 018/179] =?UTF-8?q?WxCpService=E7=9A=84getWxMpConfigStorag?= =?UTF-8?q?e=E6=96=B9=E6=B3=95=E4=BF=AE=E6=94=B9=E4=B8=BAgetWxCpConfigStor?= =?UTF-8?q?age?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/me/chanjar/weixin/cp/api/WxCpService.java | 2 +- .../me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java | 2 +- .../me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java | 2 +- .../me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java | 2 +- .../me/chanjar/weixin/cp/api/impl/apache/WxCpBaseAPITest.java | 2 +- .../chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 3da42ea18b..f02b758928 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -562,5 +562,5 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * * @return WxMpConfigStorage */ - WxCpConfigStorage getWxMpConfigStorage(); + WxCpConfigStorage getWxCpConfigStorage(); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java index 453e33bee3..cff7e13d1e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java @@ -94,7 +94,7 @@ public void initHttp() { } @Override - public WxCpConfigStorage getWxMpConfigStorage() { + public WxCpConfigStorage getWxCpConfigStorage() { return this.configStorage; } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java index 6c0994ad76..d569f2621b 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java @@ -65,7 +65,7 @@ public void initHttp() { } @Override - public WxCpConfigStorage getWxMpConfigStorage() { + public WxCpConfigStorage getWxCpConfigStorage() { return this.configStorage; } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java index b371be9d17..1a9c2ac814 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java @@ -89,7 +89,7 @@ public void initHttp() { } @Override - public WxCpConfigStorage getWxMpConfigStorage() { + public WxCpConfigStorage getWxCpConfigStorage() { return this.configStorage; } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBaseAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBaseAPITest.java index 6fecf6e7e2..7ed63b776a 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBaseAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBaseAPITest.java @@ -22,7 +22,7 @@ public class WxCpBaseAPITest { protected WxCpServiceImpl wxService; public void testRefreshAccessToken() throws WxErrorException { - WxCpConfigStorage configStorage = this.wxService.configStorage; + WxCpConfigStorage configStorage = this.wxService.getWxCpConfigStorage(); String before = configStorage.getAccessToken(); this.wxService.getAccessToken(false); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java index 2d46f29f21..470323f21c 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java @@ -21,7 +21,7 @@ public class WxCpMessageAPITest { protected WxCpServiceImpl wxService; public void testSendCustomMessage() throws WxErrorException { - ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlCpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage(); + ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlCpInMemoryConfigStorage) this.wxService.getWxCpConfigStorage(); WxCpMessage message1 = new WxCpMessage(); message1.setAgentId(configStorage.getAgentId()); message1.setMsgType(WxConsts.CUSTOM_MSG_TEXT); From 4f900f8b21c04958a3790cb937dafe70907c1b0a Mon Sep 17 00:00:00 2001 From: ecoolper Date: Sat, 29 Apr 2017 13:40:53 +0800 Subject: [PATCH 019/179] =?UTF-8?q?=E6=B7=BB=E5=8A=A0httpType=E6=9E=9A?= =?UTF-8?q?=E4=B8=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/me/chanjar/weixin/common/util/http/HttpType.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java new file mode 100644 index 0000000000..5e78a6f1d0 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java @@ -0,0 +1,8 @@ +package me.chanjar.weixin.common.util.http; + +/** + * Created by ecoolper on 2017/4/28. + */ +public enum HttpType { + joddHttp, apacheHttp, okHttp; +} From 2384b4b86335d1880c296f200679b5f4eb216c9c Mon Sep 17 00:00:00 2001 From: ecoolper Date: Wed, 3 May 2017 20:55:49 +0800 Subject: [PATCH 020/179] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9E=9A=E4=B8=BEHtt?= =?UTF-8?q?pType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/http/AbstractRequestExecutor.java | 43 ++++++++++--------- .../weixin/common/util/http/RequestHttp.java | 6 +++ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java index 23881e6635..731bec777e 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java @@ -17,26 +17,29 @@ public abstract class AbstractRequestExecutor implements RequestExecutor { @Override - public T execute(RequestHttp requestHttp, String uri, E data) throws WxErrorException, IOException{ - if (requestHttp.getRequestHttpClient() instanceof CloseableHttpClient) { - //apache-http请求 - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, data); - } - if (requestHttp.getRequestHttpClient() instanceof HttpConnectionProvider) { - //jodd-http请求 - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, data); - } else if (requestHttp.getRequestHttpClient() instanceof ConnectionPool) { - //okhttp请求 - ConnectionPool pool = (ConnectionPool) requestHttp.getRequestHttpClient(); - OkhttpProxyInfo proxyInfo = (OkhttpProxyInfo) requestHttp.getRequestHttpProxy(); - return executeOkhttp(pool, proxyInfo, uri, data); - } else { - //TODO 这里需要抛出异常,需要优化 - return null; + public T execute(RequestHttp requestHttp, String uri, E data) throws WxErrorException, IOException { + switch (requestHttp.getRequestType()) { + case apacheHttp: { + //apache-http请求 + CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); + HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); + return executeApache(httpClient, httpProxy, uri, data); + } + case joddHttp: { + //jodd-http请求 + HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); + return executeJodd(provider, proxyInfo, uri, data); + } + case okHttp: { + //okhttp请求 + ConnectionPool pool = (ConnectionPool) requestHttp.getRequestHttpClient(); + OkhttpProxyInfo proxyInfo = (OkhttpProxyInfo) requestHttp.getRequestHttpProxy(); + return executeOkhttp(pool, proxyInfo, uri, data); + } + default: + //TODO 这里需要抛出异常,需要优化 + return null; } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java index 5af68e0710..13eaf93989 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java @@ -17,4 +17,10 @@ public interface RequestHttp { */ P getRequestHttpProxy(); + /** + * + * @return + */ + HttpType getRequestType(); + } From 6b7c86da956be53180cdf633e8013eb04ca20633 Mon Sep 17 00:00:00 2001 From: ecoolper Date: Wed, 3 May 2017 21:11:56 +0800 Subject: [PATCH 021/179] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9E=9A=E4=B8=BEHtt?= =?UTF-8?q?pType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java | 6 ++++++ .../me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java | 6 ++++++ .../chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java | 6 ++++++ .../chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java | 5 +++++ .../me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java | 6 ++++++ .../chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java | 6 ++++++ 6 files changed, 35 insertions(+) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java index cff7e13d1e..7c1334b460 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java @@ -4,6 +4,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; import me.chanjar.weixin.cp.api.WxCpConfigStorage; @@ -32,6 +33,11 @@ public HttpHost getRequestHttpProxy() { return httpProxy; } + @Override + public HttpType getRequestType() { + return HttpType.apacheHttp; + } + @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { if (forceRefresh) { diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java index 2096ffd180..1dc2dd0efc 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java @@ -4,6 +4,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.cp.api.WxCpConfigStorage; import me.chanjar.weixin.cp.api.impl.AbstractWxCpServiceImpl; @@ -22,6 +23,11 @@ public ProxyInfo getRequestHttpProxy() { return httpProxy; } + @Override + public HttpType getRequestType() { + return HttpType.joddHttp; + } + @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { if (forceRefresh) { diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java index c33015d73b..5e53a172a2 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java @@ -5,6 +5,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.cp.api.WxCpConfigStorage; import me.chanjar.weixin.cp.api.impl.AbstractWxCpServiceImpl; @@ -25,6 +26,11 @@ public OkhttpProxyInfo getRequestHttpProxy() { return httpProxy; } + @Override + public HttpType getRequestType() { + return HttpType.okHttp; + } + @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { if (forceRefresh) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java index 0eaf200a06..835fbe1897 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java @@ -46,6 +46,11 @@ public HttpHost getRequestHttpProxy() { return httpProxy; } + @Override + public HttpType getRequestType() { + return HttpType.apacheHttp; + } + @Override public void initHttp() { WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java index 23f88b14ac..677e2e6b6d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java @@ -5,6 +5,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.mp.api.*; import me.chanjar.weixin.mp.api.impl.*; @@ -27,6 +28,11 @@ public ProxyInfo getRequestHttpProxy() { return httpProxy; } + @Override + public HttpType getRequestType() { + return HttpType.joddHttp; + } + @Override public void initHttp() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java index a8e0aeb99e..e89b103c6b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java @@ -3,6 +3,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; @@ -26,6 +27,11 @@ public OkhttpProxyInfo getRequestHttpProxy() { return httpProxy; } + @Override + public HttpType getRequestType() { + return HttpType.okHttp; + } + @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); From 59fc9134c84a563d5c974b22939554a61f3f14c8 Mon Sep 17 00:00:00 2001 From: ecoolper Date: Thu, 4 May 2017 11:02:24 +0800 Subject: [PATCH 022/179] =?UTF-8?q?okhttp=E4=BD=BF=E7=94=A8=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=E6=9C=89=E9=94=99=E8=AF=AF=EF=BC=8Cbody().toString()?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=BAbody().string()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/http/MediaDownloadRequestExecutor.java | 2 +- .../common/util/http/MediaUploadRequestExecutor.java | 2 +- .../weixin/common/util/http/SimpleGetRequestExecutor.java | 2 +- .../weixin/common/util/http/SimplePostRequestExecutor.java | 2 +- .../chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java | 7 ++++++- .../chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java | 2 +- .../weixin/mp/util/http/MaterialDeleteRequestExecutor.java | 2 +- .../mp/util/http/MaterialNewsInfoRequestExecutor.java | 2 +- .../weixin/mp/util/http/MaterialUploadRequestExecutor.java | 2 +- .../mp/util/http/MaterialVideoInfoRequestExecutor.java | 2 +- .../weixin/mp/util/http/MediaImgUploadRequestExecutor.java | 2 +- .../chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java | 2 +- 12 files changed, 17 insertions(+), 12 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java index e95f02de24..6da7c65c6c 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java @@ -213,7 +213,7 @@ public Request authenticate(Route route, Response response) throws IOException { String contentType = response.header("Content-Type"); if (contentType != null && contentType.startsWith("application/json")) { // application/json; encoding=utf-8 下载媒体文件出错 - throw new WxErrorException(WxError.fromJson(response.body().toString())); + throw new WxErrorException(WxError.fromJson(response.body().string())); } String fileName = getFileName(response); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java index 42040834ab..a6366f546f 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java @@ -136,7 +136,7 @@ public Request authenticate(Route route, Response response) throws IOException { Request request = new Request.Builder().url(uri).post(body).build(); Response response = client.newCall(request).execute(); - String responseContent = response.body().toString(); + String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java index 5edb70f3a0..f29739d675 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java @@ -141,7 +141,7 @@ public Request authenticate(Route route, Response response) throws IOException { Request request = new Request.Builder().url(uri).build(); Response response = client.newCall(request).execute(); - String responseContent = response.body().toString(); + String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java index 5517ab636b..c89309b7bd 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java @@ -156,7 +156,7 @@ public Request authenticate(Route route, Response response) throws IOException { Request request = new Request.Builder().url(uri).post(body).build(); Response response = client.newCall(request).execute(); - String responseContent = response.body().toString(); + String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java index 5e53a172a2..ae4eab2c35 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java @@ -68,7 +68,12 @@ public Request authenticate(Route route, Response response) throws IOException { } catch (IOException e) { e.printStackTrace(); } - String resultContent = response.body().toString(); + String resultContent = null; + try { + resultContent = response.body().string(); + } catch (IOException e) { + e.printStackTrace(); + } WxError error = WxError.fromJson(resultContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java index e89b103c6b..dc6d7d0051 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java @@ -66,7 +66,7 @@ public Request authenticate(Route route, Response response) throws IOException { Request request = new Request.Builder().url(url).get().build(); Response response = client.newCall(request).execute(); - String resultContent = response.body().toString(); + String resultContent = response.body().string(); WxError error = WxError.fromJson(resultContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java index 15e636bb6c..d6c68bf963 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java @@ -102,7 +102,7 @@ public Request authenticate(Route route, Response response) throws IOException { RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); Request request = new Request.Builder().url(uri).post(requestBody).build(); Response response = client.newCall(request).execute(); - String responseContent = response.body().toString(); + String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java index 58e63a92b0..de5f23429c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java @@ -104,7 +104,7 @@ public Request authenticate(Route route, Response response) throws IOException { Request request = new Request.Builder().url(uri).post(requestBody).build(); Response response = client.newCall(request).execute(); - String responseContent = response.body().toString(); + String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java index a23af2b544..772684ab7c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java @@ -104,7 +104,7 @@ public Request authenticate(Route route, Response response) throws IOException { RequestBody body =bodyBuilder.build(); Request request = new Request.Builder().url(uri).post(body).build(); Response response = client.newCall(request).execute(); - String responseContent = response.body().toString(); + String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java index a6af76eb14..3c481f7ca1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java @@ -77,7 +77,7 @@ public Request authenticate(Route route, Response response) throws IOException { RequestBody requestBody =new FormBody.Builder().add("media_id", materialId).build(); Request request = new Request.Builder().url(uri).post(requestBody).build(); Response response = client.newCall(request).execute(); - String responseContent = response.body().toString(); + String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java index b0db70dc9e..4232f33316 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java @@ -90,7 +90,7 @@ public Request authenticate(Route route, Response response) throws IOException { Request request = new Request.Builder().url(uri).post(body).build(); Response response = client.newCall(request).execute(); - String responseContent = response.body().toString(); + String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java index 91e38eb53b..d37d0bb96a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java @@ -92,7 +92,7 @@ public Request authenticate(Route route, Response response) throws IOException { Response response = client.newCall(request).execute(); String contentTypeHeader = response.header("Content-Type"); if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { - String responseContent = response.body().toString(); + String responseContent = response.body().string(); throw new WxErrorException(WxError.fromJson(responseContent)); } try (InputStream inputStream = new ByteArrayInputStream(response.body().bytes())) { From aa4c076d3627be4787f63b6fc5295226e371f412 Mon Sep 17 00:00:00 2001 From: ecoolper Date: Thu, 4 May 2017 13:57:48 +0800 Subject: [PATCH 023/179] =?UTF-8?q?1=E3=80=81=E5=88=A0=E9=99=A4AbstractWxM?= =?UTF-8?q?pService=E3=80=81AbstractWxCPService=E7=B1=BB=202=E3=80=81?= =?UTF-8?q?=E4=BF=AE=E6=94=B9apache.WxCpServiceImpl=E7=B1=BB=E7=9A=84?= =?UTF-8?q?=E7=88=B6=E7=B1=BB=E4=B8=BAAbstractWxCpServiceImpl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cp/api/impl/AbstractWxCpService.java | 632 ------------------ .../cp/api/impl/apache/WxCpServiceImpl.java | 4 +- .../mp/api/impl/AbstractWxMpService.java | 445 ------------ 3 files changed, 2 insertions(+), 1079 deletions(-) delete mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpService.java delete mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpService.java diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpService.java deleted file mode 100644 index 82fcdef9b3..0000000000 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpService.java +++ /dev/null @@ -1,632 +0,0 @@ -package me.chanjar.weixin.cp.api.impl; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.UUID; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.gson.*; -import com.google.gson.reflect.TypeToken; - -import me.chanjar.weixin.common.bean.WxJsapiSignature; -import me.chanjar.weixin.common.bean.menu.WxMenu; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.StandardSessionManager; -import me.chanjar.weixin.common.session.WxSession; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.util.RandomUtils; -import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.*; -import me.chanjar.weixin.common.util.json.GsonHelper; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.WxCpService; -import me.chanjar.weixin.cp.bean.WxCpDepart; -import me.chanjar.weixin.cp.bean.WxCpMessage; -import me.chanjar.weixin.cp.bean.WxCpTag; -import me.chanjar.weixin.cp.bean.WxCpUser; -import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; - -public abstract class AbstractWxCpService implements WxCpService, RequestHttp { - - protected final Logger log = LoggerFactory.getLogger(AbstractWxCpService.class); - - /** - * 全局的是否正在刷新access token的锁 - */ - protected final Object globalAccessTokenRefreshLock = new Object(); - - /** - * 全局的是否正在刷新jsapi_ticket的锁 - */ - protected final Object globalJsapiTicketRefreshLock = new Object(); - - protected WxCpConfigStorage configStorage; - - - protected WxSessionManager sessionManager = new StandardSessionManager(); - /** - * 临时文件目录 - */ - protected File tmpDirFile; - private int retrySleepMillis = 1000; - private int maxRetryTimes = 5; - - @Override - public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) { - try { - return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data) - .equals(msgSignature); - } catch (Exception e) { - return false; - } - } - - @Override - public void userAuthenticated(String userId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId; - get(url, null); - } - - @Override - public String getAccessToken() throws WxErrorException { - return getAccessToken(false); - } - - - @Override - public String getJsapiTicket() throws WxErrorException { - return getJsapiTicket(false); - } - - @Override - public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { - if (forceRefresh) { - this.configStorage.expireJsapiTicket(); - } - if (this.configStorage.isJsapiTicketExpired()) { - synchronized (this.globalJsapiTicketRefreshLock) { - if (this.configStorage.isJsapiTicketExpired()) { - String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); - int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.configStorage.updateJsapiTicket(jsapiTicket, - expiresInSeconds); - } - } - } - return this.configStorage.getJsapiTicket(); - } - - @Override - public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { - long timestamp = System.currentTimeMillis() / 1000; - String noncestr = RandomUtils.getRandomStr(); - String jsapiTicket = getJsapiTicket(false); - String signature = SHA1.genWithAmple( - "jsapi_ticket=" + jsapiTicket, - "noncestr=" + noncestr, - "timestamp=" + timestamp, - "url=" + url - ); - WxJsapiSignature jsapiSignature = new WxJsapiSignature(); - jsapiSignature.setTimestamp(timestamp); - jsapiSignature.setNonceStr(noncestr); - jsapiSignature.setUrl(url); - jsapiSignature.setSignature(signature); - - // Fixed bug - jsapiSignature.setAppId(this.configStorage.getCorpId()); - - return jsapiSignature; - } - - @Override - public void messageSend(WxCpMessage message) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"; - post(url, message.toJson()); - } - - @Override - public void menuCreate(WxMenu menu) throws WxErrorException { - menuCreate(this.configStorage.getAgentId(), menu); - } - - @Override - public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" - + this.configStorage.getAgentId(); - post(url, menu.toJson()); - } - - @Override - public void menuDelete() throws WxErrorException { - menuDelete(this.configStorage.getAgentId()); - } - - @Override - public void menuDelete(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId; - get(url, null); - } - - @Override - public WxMenu menuGet() throws WxErrorException { - return menuGet(this.configStorage.getAgentId()); - } - - @Override - public WxMenu menuGet(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId; - try { - String resultContent = get(url, null); - return WxMenu.fromJson(resultContent); - } catch (WxErrorException e) { - // 46003 不存在的菜单数据 - if (e.getError().getErrorCode() == 46003) { - return null; - } - throw e; - } - } - - @Override - public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) - throws WxErrorException, IOException { - return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); - } - - @Override - public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; - return execute(new MediaUploadRequestExecutor(), url, file); - } - - @Override - public File mediaDownload(String mediaId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; - return execute( - new MediaDownloadRequestExecutor( - this.configStorage.getTmpDirFile()), - url, "media_id=" + mediaId); - } - - - @Override - public Integer departCreate(WxCpDepart depart) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; - String responseContent = execute( - new SimplePostRequestExecutor(), - url, - depart.toJson()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id")); - } - - @Override - public void departUpdate(WxCpDepart group) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update"; - post(url, group.toJson()); - } - - @Override - public void departDelete(Integer departId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId; - get(url, null); - } - - @Override - public List departGet() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; - String responseContent = get(url, null); - /* - * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } - * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } - */ - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("department"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public void userCreate(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; - post(url, user.toJson()); - } - - @Override - public void userUpdate(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; - post(url, user.toJson()); - } - - @Override - public void userDelete(String userid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userid; - get(url, null); - } - - @Override - public void userDelete(String[] userids) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; - JsonObject jsonObject = new JsonObject(); - JsonArray jsonArray = new JsonArray(); - for (String userid : userids) { - jsonArray.add(new JsonPrimitive(userid)); - } - jsonObject.add("useridlist", jsonArray); - post(url, jsonObject.toString()); - } - - @Override - public WxCpUser userGet(String userid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid; - String responseContent = get(url, null); - return WxCpUser.fromJson(responseContent); - } - - @Override - public List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; - String params = ""; - if (fetchChild != null) { - params += "&fetch_child=" + (fetchChild ? "1" : "0"); - } - if (status != null) { - params += "&status=" + status; - } else { - params += "&status=0"; - } - - String responseContent = get(url, params); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; - String params = ""; - if (fetchChild != null) { - params += "&fetch_child=" + (fetchChild ? "1" : "0"); - } - if (status != null) { - params += "&status=" + status; - } else { - params += "&status=0"; - } - - String responseContent = get(url, params); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public String tagCreate(String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; - JsonObject o = new JsonObject(); - o.addProperty("tagname", tagName); - String responseContent = post(url, o.toString()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return tmpJsonElement.getAsJsonObject().get("tagid").getAsString(); - } - - @Override - public void tagUpdate(String tagId, String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; - JsonObject o = new JsonObject(); - o.addProperty("tagid", tagId); - o.addProperty("tagname", tagName); - post(url, o.toString()); - } - - @Override - public void tagDelete(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; - get(url, null); - } - - @Override - public List tagGet() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; - String responseContent = get(url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("taglist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public List tagGetUsers(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; - String responseContent = get(url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); - } - - @Override - public void tagAddUsers(String tagId, List userIds, List partyIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("tagid", tagId); - if (userIds != null) { - JsonArray jsonArray = new JsonArray(); - for (String userId : userIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("userlist", jsonArray); - } - if (partyIds != null) { - JsonArray jsonArray = new JsonArray(); - for (String userId : partyIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("partylist", jsonArray); - } - post(url, jsonObject.toString()); - } - - @Override - public void tagRemoveUsers(String tagId, List userIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("tagid", tagId); - JsonArray jsonArray = new JsonArray(); - for (String userId : userIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("userlist", jsonArray); - post(url, jsonObject.toString()); - } - - @Override - public String oauth2buildAuthorizationUrl(String state) { - return this.oauth2buildAuthorizationUrl( - this.configStorage.getOauth2redirectUri(), - state - ); - } - - @Override - public String oauth2buildAuthorizationUrl(String redirectUri, String state) { - String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"; - url += "appid=" + this.configStorage.getCorpId(); - url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri); - url += "&response_type=code"; - url += "&scope=snsapi_base"; - if (state != null) { - url += "&state=" + state; - } - url += "#wechat_redirect"; - return url; - } - - @Override - public String[] oauth2getUserInfo(String code) throws WxErrorException { - return oauth2getUserInfo(this.configStorage.getAgentId(), code); - } - - @Override - public String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?" - + "code=" + code - + "&agentid=" + agentId; - String responseText = get(url, null); - JsonElement je = new JsonParser().parse(responseText); - JsonObject jo = je.getAsJsonObject(); - return new String[]{GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId"), GsonHelper.getString(jo, "OpenId")}; - } - - @Override - public int invite(String userId, String inviteTips) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/invite/send"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("userid", userId); - if (StringUtils.isNotEmpty(inviteTips)) { - jsonObject.addProperty("invite_tips", inviteTips); - } - String responseContent = post(url, jsonObject.toString()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return tmpJsonElement.getAsJsonObject().get("type").getAsInt(); - } - - @Override - public String[] getCallbackIp() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip"; - String responseContent = get(url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); - String[] ips = new String[jsonArray.size()]; - for (int i = 0; i < jsonArray.size(); i++) { - ips[i] = jsonArray.get(i).getAsString(); - } - return ips; - } - - @Override - public String get(String url, String queryParam) throws WxErrorException { - return execute(new SimpleGetRequestExecutor(), url, queryParam); - } - - @Override - public String post(String url, String postData) throws WxErrorException { - return execute(new SimplePostRequestExecutor(), url, postData); - } - - /** - * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 - */ - @Override - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { - int retryTimes = 0; - do { - try { - T result = this.executeInternal(executor, uri, data); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",uri, data, result); - return result; - } catch (WxErrorException e) { - if (retryTimes + 1 > this.maxRetryTimes) { - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); - //最后一次重试失败后,直接抛出异常,不再等待 - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - WxError error = e.getError(); - /* - * -1 系统繁忙, 1000ms后重试 - */ - if (error.getErrorCode() == -1) { - int sleepMillis = this.retrySleepMillis * (1 << retryTimes); - try { - this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); - Thread.sleep(sleepMillis); - } catch (InterruptedException e1) { - throw new RuntimeException(e1); - } - } else { - throw e; - } - } - } while (retryTimes++ < this.maxRetryTimes); - - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { - if (uri.contains("access_token=")) { - throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); - } - String accessToken = getAccessToken(false); - - String uriWithAccessToken = uri; - uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; - - try { - return executor.execute(this, uriWithAccessToken, data); - } catch (WxErrorException e) { - WxError error = e.getError(); - /* - * 发生以下情况时尝试刷新access_token - * 40001 获取access_token时AppSecret错误,或者access_token无效 - * 42001 access_token超时 - */ - if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { - // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token - this.configStorage.expireAccessToken(); - return execute(executor, uri, data); - } - - if (error.getErrorCode() != 0) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); - throw new WxErrorException(error); - } - return null; - } catch (IOException e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); - throw new RuntimeException(e); - } - } - - @Override - public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) { - this.configStorage = wxConfigProvider; - this.initHttp(); - } - - @Override - public void setRetrySleepMillis(int retrySleepMillis) { - this.retrySleepMillis = retrySleepMillis; - } - - - @Override - public void setMaxRetryTimes(int maxRetryTimes) { - this.maxRetryTimes = maxRetryTimes; - } - - @Override - public WxSession getSession(String id) { - if (this.sessionManager == null) { - return null; - } - return this.sessionManager.getSession(id); - } - - @Override - public WxSession getSession(String id, boolean create) { - if (this.sessionManager == null) { - return null; - } - return this.sessionManager.getSession(id, create); - } - - - @Override - public void setSessionManager(WxSessionManager sessionManager) { - this.sessionManager = sessionManager; - } - - @Override - public String replaceParty(String mediaId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("media_id", mediaId); - return post(url, jsonObject.toString()); - } - - @Override - public String replaceUser(String mediaId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("media_id", mediaId); - return post(url, jsonObject.toString()); - } - - @Override - public String getTaskResult(String joinId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?jobid=" + joinId; - return get(url, null); - } - - public File getTmpDirFile() { - return this.tmpDirFile; - } - - public void setTmpDirFile(File tmpDirFile) { - this.tmpDirFile = tmpDirFile; - } - -} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java index 7c1334b460..61b75cb5d5 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java @@ -8,7 +8,7 @@ import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.impl.AbstractWxCpService; +import me.chanjar.weixin.cp.api.impl.AbstractWxCpServiceImpl; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -19,7 +19,7 @@ import java.io.IOException; -public class WxCpServiceImpl extends AbstractWxCpService { +public class WxCpServiceImpl extends AbstractWxCpServiceImpl { protected CloseableHttpClient httpClient; protected HttpHost httpProxy; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpService.java deleted file mode 100644 index 5c6b58eb04..0000000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpService.java +++ /dev/null @@ -1,445 +0,0 @@ -package me.chanjar.weixin.mp.api.impl; - -import java.io.IOException; -import java.util.concurrent.locks.Lock; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import me.chanjar.weixin.common.bean.WxJsapiSignature; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.StandardSessionManager; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.util.RandomUtils; -import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.http.*; -import me.chanjar.weixin.mp.api.*; -import me.chanjar.weixin.mp.bean.*; -import me.chanjar.weixin.mp.bean.result.*; - -public abstract class AbstractWxMpService implements WxMpService,RequestHttp { - - private static final JsonParser JSON_PARSER = new JsonParser(); - - protected final Logger log = LoggerFactory.getLogger(this.getClass()); - protected WxSessionManager sessionManager = new StandardSessionManager(); - private WxMpConfigStorage wxMpConfigStorage; - private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); - private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); - private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); - private WxMpUserService userService = new WxMpUserServiceImpl(this); - private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this); - private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); - private WxMpCardService cardService = new WxMpCardServiceImpl(this); - private WxMpStoreService storeService = new WxMpStoreServiceImpl(this); - private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this); - private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this); - private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); - private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); - - private int retrySleepMillis = 1000; - private int maxRetryTimes = 5; - - - @Override - public boolean checkSignature(String timestamp, String nonce, String signature) { - try { - return SHA1.gen(this.getWxMpConfigStorage().getToken(), timestamp, nonce) - .equals(signature); - } catch (Exception e) { - return false; - } - } - - @Override - public String getJsapiTicket() throws WxErrorException { - return getJsapiTicket(false); - } - - @Override - public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { - Lock lock = this.getWxMpConfigStorage().getJsapiTicketLock(); - try { - lock.lock(); - - if (forceRefresh) { - this.getWxMpConfigStorage().expireJsapiTicket(); - } - - if (this.getWxMpConfigStorage().isJsapiTicketExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, null); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); - int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.getWxMpConfigStorage().updateJsapiTicket(jsapiTicket, expiresInSeconds); - } - } finally { - lock.unlock(); - } - return this.getWxMpConfigStorage().getJsapiTicket(); - } - - @Override - public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { - long timestamp = System.currentTimeMillis() / 1000; - String noncestr = RandomUtils.getRandomStr(); - String jsapiTicket = getJsapiTicket(false); - String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket, - "noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url); - WxJsapiSignature jsapiSignature = new WxJsapiSignature(); - jsapiSignature.setAppId(this.getWxMpConfigStorage().getAppId()); - jsapiSignature.setTimestamp(timestamp); - jsapiSignature.setNonceStr(noncestr); - jsapiSignature.setUrl(url); - jsapiSignature.setSignature(signature); - return jsapiSignature; - } - - @Override - public String getAccessToken() throws WxErrorException { - return getAccessToken(false); - } - - @Override - public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; - String responseContent = this.post(url, news.toJson()); - return WxMpMassUploadResult.fromJson(responseContent); - } - - @Override - public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; - String responseContent = this.post(url, video.toJson()); - return WxMpMassUploadResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; - String responseContent = this.post(url, message.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; - String responseContent = this.post(url, message.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; - String responseContent = this.post(url, wxMpMassPreviewMessage.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public String shortUrl(String long_url) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/shorturl"; - JsonObject o = new JsonObject(); - o.addProperty("action", "long2short"); - o.addProperty("long_url", long_url); - String responseContent = this.post(url, o.toString()); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - return tmpJsonElement.getAsJsonObject().get("short_url").getAsString(); - } - - @Override - public WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/semantic/semproxy/search"; - String responseContent = this.post(url, semanticQuery.toJson()); - return WxMpSemanticQueryResult.fromJson(responseContent); - } - - @Override - public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { - StringBuilder url = new StringBuilder(); - url.append("https://open.weixin.qq.com/connect/oauth2/authorize?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); - url.append("&response_type=code"); - url.append("&scope=").append(scope); - if (state != null) { - url.append("&state=").append(state); - } - url.append("#wechat_redirect"); - return url.toString(); - } - - @Override - public String buildQrConnectUrl(String redirectURI, String scope, - String state) { - StringBuilder url = new StringBuilder(); - url.append("https://open.weixin.qq.com/connect/qrconnect?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); - url.append("&response_type=code"); - url.append("&scope=").append(scope); - if (state != null) { - url.append("&state=").append(state); - } - - url.append("#wechat_redirect"); - return url.toString(); - } - - private WxMpOAuth2AccessToken getOAuth2AccessToken(StringBuilder url) throws WxErrorException { - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(this, url.toString(), null); - return WxMpOAuth2AccessToken.fromJson(responseText); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/oauth2/access_token?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&secret=").append(this.getWxMpConfigStorage().getSecret()); - url.append("&code=").append(code); - url.append("&grant_type=authorization_code"); - - return this.getOAuth2AccessToken(url); - } - - @Override - public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/oauth2/refresh_token?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&grant_type=refresh_token"); - url.append("&refresh_token=").append(refreshToken); - - return this.getOAuth2AccessToken(url); - } - - @Override - public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/userinfo?"); - url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); - url.append("&openid=").append(oAuth2AccessToken.getOpenId()); - if (lang == null) { - url.append("&lang=zh_CN"); - } else { - url.append("&lang=").append(lang); - } - - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(this, url.toString(), null); - return WxMpUser.fromJson(responseText); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/auth?"); - url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); - url.append("&openid=").append(oAuth2AccessToken.getOpenId()); - - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - executor.execute(this, url.toString(), null); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (WxErrorException e) { - return false; - } - return true; - } - - @Override - public String[] getCallbackIP() throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/getcallbackip"; - String responseContent = get(url, null); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - JsonArray ipList = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); - String[] ipArray = new String[ipList.size()]; - for (int i = 0; i < ipList.size(); i++) { - ipArray[i] = ipList.get(i).getAsString(); - } - return ipArray; - } - - @Override - public String get(String url, String queryParam) throws WxErrorException { - return execute(new SimpleGetRequestExecutor(), url, queryParam); - } - - @Override - public String post(String url, String postData) throws WxErrorException { - return execute(new SimplePostRequestExecutor(), url, postData); - } - - /** - * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 - */ - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { - int retryTimes = 0; - do { - try { - T result = executeInternal(executor, uri, data); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, result); - return result; - } catch (WxErrorException e) { - if (retryTimes + 1 > this.maxRetryTimes) { - this.log.warn("重试达到最大次数【{}】", maxRetryTimes); - //最后一次重试失败后,直接抛出异常,不再等待 - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - WxError error = e.getError(); - // -1 系统繁忙, 1000ms后重试 - if (error.getErrorCode() == -1) { - int sleepMillis = this.retrySleepMillis * (1 << retryTimes); - try { - this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); - Thread.sleep(sleepMillis); - } catch (InterruptedException e1) { - throw new RuntimeException(e1); - } - } else { - throw e; - } - } - } while (retryTimes++ < this.maxRetryTimes); - - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { - if (uri.indexOf("access_token=") != -1) { - throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); - } - String accessToken = getAccessToken(false); - - String uriWithAccessToken = uri; - uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; - - try { - return executor.execute(this, uriWithAccessToken, data); - } catch (WxErrorException e) { - WxError error = e.getError(); - /* - * 发生以下情况时尝试刷新access_token - * 40001 获取access_token时AppSecret错误,或者access_token无效 - * 42001 access_token超时 - */ - if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { - // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token - this.getWxMpConfigStorage().expireAccessToken(); - if (this.getWxMpConfigStorage().autoRefreshToken()) { - return this.execute(executor, uri, data); - } - } - - if (error.getErrorCode() != 0) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); - throw new WxErrorException(error); - } - return null; - } catch (IOException e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); - throw new RuntimeException(e); - } - } - - @Override - public WxMpConfigStorage getWxMpConfigStorage() { - return this.wxMpConfigStorage; - } - - @Override - public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { - this.wxMpConfigStorage = wxConfigProvider; - this.initHttp(); - } - - @Override - public void setRetrySleepMillis(int retrySleepMillis) { - this.retrySleepMillis = retrySleepMillis; - } - - @Override - public void setMaxRetryTimes(int maxRetryTimes) { - this.maxRetryTimes = maxRetryTimes; - } - - @Override - public WxMpKefuService getKefuService() { - return this.kefuService; - } - - @Override - public WxMpMaterialService getMaterialService() { - return this.materialService; - } - - @Override - public WxMpMenuService getMenuService() { - return this.menuService; - } - - @Override - public WxMpUserService getUserService() { - return this.userService; - } - - @Override - public WxMpUserTagService getUserTagService() { - return this.tagService; - } - - @Override - public WxMpQrcodeService getQrcodeService() { - return this.qrCodeService; - } - - @Override - public WxMpCardService getCardService() { - return this.cardService; - } - - @Override - public WxMpDataCubeService getDataCubeService() { - return this.dataCubeService; - } - - @Override - public WxMpUserBlacklistService getBlackListService() { - return this.blackListService; - } - - @Override - public WxMpStoreService getStoreService() { - return this.storeService; - } - - @Override - public WxMpTemplateMsgService getTemplateMsgService() { - return this.templateMsgService; - } - - @Override - public WxMpDeviceService getDeviceService() { - return this.deviceService; - } -} From 26d68cd3e8262994856a60d1f2d9da1b61e32ae3 Mon Sep 17 00:00:00 2001 From: ecoolper Date: Sat, 6 May 2017 19:05:01 +0800 Subject: [PATCH 024/179] =?UTF-8?q?RequestExecutor=E5=AE=9E=E4=BE=8B?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=BA=E9=80=9A=E8=BF=87create=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E6=9E=84=E5=BB=BA=EF=BC=8C=E8=A7=A3=E5=86=B3=E4=BA=86?= =?UTF-8?q?=E5=BF=85=E9=A1=BB=E5=90=8C=E6=97=B6=E5=BC=95=E5=85=A5apache-ht?= =?UTF-8?q?tp=E3=80=81jodd-http=E3=80=81okhttp=20jar=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/http/AbstractRequestExecutor.java | 46 ---- .../http/MediaDownloadRequestExecutor.java | 214 ++---------------- .../util/http/MediaUploadRequestExecutor.java | 124 ++-------- .../common/util/http/RequestExecutor.java | 14 +- .../util/http/SimpleGetRequestExecutor.java | 132 ++--------- .../util/http/SimplePostRequestExecutor.java | 150 ++---------- .../ApacheMediaDownloadRequestExecutor.java | 90 ++++++++ .../ApacheMediaUploadRequestExecutor.java | 58 +++++ .../ApacheSimpleGetRequestExecutor.java | 52 +++++ .../ApacheSimplePostRequestExecutor.java | 63 ++++++ .../JoddMediaDownloadRequestExecutor.java | 79 +++++++ .../jodd/JoddMediaUploadRequestExecutor.java | 41 ++++ .../jodd/JoddSimpleGetRequestExecutor.java | 54 +++++ .../jodd/JoddSimplePostRequestExecutor.java | 58 +++++ .../OkMediaDownloadRequestExecutor.java | 92 ++++++++ .../okhttp/OkMediaUploadRequestExecutor.java | 56 +++++ .../okhttp/OkSimpleGetRequestExecutor.java | 63 ++++++ .../okhttp/OkSimplePostRequestExecutor.java | 59 +++++ .../cp/api/impl/AbstractWxCpServiceImpl.java | 14 +- .../weixin/mp/api/WxMpCardService.java | 2 +- .../me/chanjar/weixin/mp/api/WxMpService.java | 7 + .../mp/api/impl/AbstractWxMpServiceImpl.java | 21 +- .../mp/api/impl/WxMpCardServiceImpl.java | 6 +- .../mp/api/impl/WxMpKefuServiceImpl.java | 2 +- .../mp/api/impl/WxMpMaterialServiceImpl.java | 16 +- .../mp/api/impl/WxMpQrcodeServiceImpl.java | 2 +- .../impl/WxMpUserBlacklistServiceImpl.java | 6 +- .../mp/api/impl/apache/WxMpServiceImpl.java | 5 + .../mp/api/impl/jodd/WxMpServiceImpl.java | 6 + .../mp/api/impl/okhttp/WxMpServiceImpl.java | 6 + .../http/MaterialDeleteRequestExecutor.java | 96 ++------ .../http/MaterialNewsInfoRequestExecutor.java | 98 ++------ .../http/MaterialUploadRequestExecutor.java | 137 ++--------- .../MaterialVideoInfoRequestExecutor.java | 97 ++------ ...lVoiceAndImageDownloadRequestExecutor.java | 129 ++--------- .../http/MediaImgUploadRequestExecutor.java | 112 ++------- .../mp/util/http/QrCodeRequestExecutor.java | 112 ++------- .../ApacheMaterialDeleteRequestExecutor.java | 52 +++++ ...ApacheMaterialNewsInfoRequestExecutor.java | 54 +++++ .../ApacheMaterialUploadRequestExecutor.java | 75 ++++++ ...pacheMaterialVideoInfoRequestExecutor.java | 53 +++++ ...lVoiceAndImageDownloadRequestExecutor.java | 64 ++++++ .../ApacheMediaImgUploadRequestExecutor.java | 61 +++++ .../apache/ApacheQrCodeRequestExecutor.java | 66 ++++++ .../JoddMaterialDeleteRequestExecutor.java | 40 ++++ .../JoddMaterialNewsInfoRequestExecutor.java | 43 ++++ .../JoddMaterialUploadRequestExecutor.java | 59 +++++ .../JoddMaterialVideoInfoRequestExecutor.java | 41 ++++ ...lVoiceAndImageDownloadRequestExecutor.java | 56 +++++ .../JoddMediaImgUploadRequestExecutor.java | 46 ++++ .../http/jodd/JoddQrCodeRequestExecutor.java | 57 +++++ .../OkhttpMaterialDeleteRequestExecutor.java | 54 +++++ ...OkhttpMaterialNewsInfoRequestExecutor.java | 55 +++++ .../OkhttpMaterialUploadRequestExecutor.java | 80 +++++++ ...khttpMaterialVideoInfoRequestExecutor.java | 52 +++++ ...lVoiceAndImageDownloadRequestExecutor.java | 68 ++++++ .../OkhttpMediaImgUploadRequestExecutor.java | 56 +++++ .../okhttp/OkhttpQrCodeRequestExecutor.java | 58 +++++ 58 files changed, 2214 insertions(+), 1295 deletions(-) delete mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaDownloadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaUploadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimpleGetRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimplePostRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaDownloadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaUploadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimpleGetRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimplePostRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialDeleteRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialNewsInfoRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialUploadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVideoInfoRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVoiceAndImageDownloadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMediaImgUploadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheQrCodeRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialDeleteRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialUploadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVideoInfoRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMediaImgUploadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddQrCodeRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java deleted file mode 100644 index 731bec777e..0000000000 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/AbstractRequestExecutor.java +++ /dev/null @@ -1,46 +0,0 @@ -package me.chanjar.weixin.common.util.http; - -import java.io.IOException; - -import org.apache.http.HttpHost; -import org.apache.http.impl.client.CloseableHttpClient; - -import jodd.http.HttpConnectionProvider; -import jodd.http.ProxyInfo; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; -import okhttp3.ConnectionPool; - -/** - * Created by ecoolper on 2017/4/27. - */ -public abstract class AbstractRequestExecutor implements RequestExecutor { - - @Override - public T execute(RequestHttp requestHttp, String uri, E data) throws WxErrorException, IOException { - switch (requestHttp.getRequestType()) { - case apacheHttp: { - //apache-http请求 - CloseableHttpClient httpClient = (CloseableHttpClient) requestHttp.getRequestHttpClient(); - HttpHost httpProxy = (HttpHost) requestHttp.getRequestHttpProxy(); - return executeApache(httpClient, httpProxy, uri, data); - } - case joddHttp: { - //jodd-http请求 - HttpConnectionProvider provider = (HttpConnectionProvider) requestHttp.getRequestHttpClient(); - ProxyInfo proxyInfo = (ProxyInfo) requestHttp.getRequestHttpProxy(); - return executeJodd(provider, proxyInfo, uri, data); - } - case okHttp: { - //okhttp请求 - ConnectionPool pool = (ConnectionPool) requestHttp.getRequestHttpClient(); - OkhttpProxyInfo proxyInfo = (OkhttpProxyInfo) requestHttp.getRequestHttpProxy(); - return executeOkhttp(pool, proxyInfo, uri, data); - } - default: - //TODO 这里需要抛出异常,需要优化 - return null; - } - } - -} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java index 6da7c65c6c..8ea7658d95 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java @@ -8,8 +8,11 @@ import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.apache.ApacheMediaDownloadRequestExecutor; import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.jodd.JoddMediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.okhttp.OkMediaDownloadRequestExecutor; import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import okhttp3.*; @@ -37,207 +40,26 @@ * * @author Daniel Qian */ -public class MediaDownloadRequestExecutor extends AbstractRequestExecutor { - - private File tmpDirFile; - - public MediaDownloadRequestExecutor(File tmpDirFile) { - this.tmpDirFile = tmpDirFile; - } - - private String getFileName(HttpResponse response) throws WxErrorException { - String content = response.header("Content-disposition"); - if (content == null || content.length() == 0) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - - Pattern p = Pattern.compile(".*filename=\"(.*)\""); - Matcher m = p.matcher(content); - if (m.matches()) { - return m.group(1); - } - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - - private String getFileName(CloseableHttpResponse response) throws WxErrorException { - Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); - if (contentDispositionHeader == null || contentDispositionHeader.length == 0) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - - Pattern p = Pattern.compile(".*filename=\"(.*)\""); - Matcher m = p.matcher(contentDispositionHeader[0].getValue()); - if (m.matches()) { - return m.group(1); - } - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - - - /** - * apache-http实现方式 - * - * @param httpclient - * @param httpProxy - * @param uri - * @param queryParam - * @return - * @throws WxErrorException - * @throws IOException - */ - public File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - - HttpGet httpGet = new HttpGet(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpGet.setConfig(config); - } - - try (CloseableHttpResponse response = httpclient.execute(httpGet); - InputStream inputStream = InputStreamResponseHandler.INSTANCE - .handleResponse(response)) { - Header[] contentTypeHeader = response.getHeaders("Content-Type"); - if (contentTypeHeader != null && contentTypeHeader.length > 0) { - if (contentTypeHeader[0].getValue().startsWith(ContentType.APPLICATION_JSON.getMimeType())) { - // application/json; encoding=utf-8 下载媒体文件出错 - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - throw new WxErrorException(WxError.fromJson(responseContent)); - } - } - - String fileName = getFileName(response); - if (StringUtils.isBlank(fileName)) { +public abstract class MediaDownloadRequestExecutor implements RequestExecutor { + + public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile){ + switch (requestHttp.getRequestType()){ + case apacheHttp: + return new ApacheMediaDownloadRequestExecutor(requestHttp, tmpDirFile); + case joddHttp: + return new JoddMediaDownloadRequestExecutor(requestHttp, tmpDirFile); + case okHttp: + return new OkMediaDownloadRequestExecutor(requestHttp, tmpDirFile); + default: return null; - } - - String[] nameAndExt = fileName.split("\\."); - return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); - - } finally { - httpGet.releaseConnection(); } - } + protected RequestHttp requestHttp; + protected File tmpDirFile; - /** - * jodd-http实现方式 - * - * @param provider - * @param proxyInfo - * @param uri - * @param queryParam - * @return - * @throws WxErrorException - * @throws IOException - */ - public File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - - HttpRequest request = HttpRequest.get(uri); - if (proxyInfo != null) { - provider.useProxy(proxyInfo); - } - request.withConnectionProvider(provider); - - HttpResponse response = request.send(); - String contentType = response.header("Content-Type"); - if (contentType != null && contentType.startsWith("application/json")) { - // application/json; encoding=utf-8 下载媒体文件出错 - throw new WxErrorException(WxError.fromJson(response.bodyText())); - } - - String fileName = getFileName(response); - if (StringUtils.isBlank(fileName)) { - return null; - } - - InputStream inputStream = new ByteArrayInputStream(response.bodyBytes()); - String[] nameAndExt = fileName.split("\\."); - return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); - } - - - /** - * okhttp现实方式 - * - * @param pool - * @param proxyInfo - * @param uri - * @param queryParam - * @return - * @throws WxErrorException - * @throws IOException - */ - public File executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - - Request request = new Request.Builder().url(uri).get().build(); - - Response response = client.newCall(request).execute(); - - String contentType = response.header("Content-Type"); - if (contentType != null && contentType.startsWith("application/json")) { - // application/json; encoding=utf-8 下载媒体文件出错 - throw new WxErrorException(WxError.fromJson(response.body().string())); - } - - String fileName = getFileName(response); - if (StringUtils.isBlank(fileName)) { - return null; - } - - InputStream inputStream = new ByteArrayInputStream(response.body().bytes()); - String[] nameAndExt = fileName.split("\\."); - return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); - } - - private String getFileName(Response response) throws WxErrorException { - String content = response.header("Content-disposition"); - if (content == null || content.length() == 0) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - - Pattern p = Pattern.compile(".*filename=\"(.*)\""); - Matcher m = p.matcher(content); - if (m.matches()) { - return m.group(1); - } - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + public MediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + this.tmpDirFile = tmpDirFile; } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java index a6366f546f..abe3dbd69e 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java @@ -7,8 +7,11 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.apache.ApacheMediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.jodd.JoddMediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.okhttp.OkMediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import okhttp3.*; @@ -32,117 +35,24 @@ * * @author Daniel Qian */ -public class MediaUploadRequestExecutor extends AbstractRequestExecutor { +public abstract class MediaUploadRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; - /** - * apache-http实现方式 - * - * @param httpclient - * @param httpProxy - * @param uri - * @param file - * @return - * @throws WxErrorException - * @throws IOException - */ - public WxMediaUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File file) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - if (file != null) { - HttpEntity entity = MultipartEntityBuilder - .create() - .addBinaryBody("media", file) - .setMode(HttpMultipartMode.RFC6532) - .build(); - httpPost.setEntity(entity); - httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); - } - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return WxMediaUploadResult.fromJson(responseContent); - } finally { - httpPost.releaseConnection(); - } + public MediaUploadRequestExecutor(RequestHttp requestHttp){ + this.requestHttp =requestHttp; } - - /** - * jodd-http实现方式 - * - * @param provider - * @param proxyInfo - * @param uri - * @param file - * @return - * @throws WxErrorException - * @throws IOException - */ - public WxMediaUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, File file) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (proxyInfo != null) { - provider.useProxy(proxyInfo); + public static RequestExecutor create(RequestHttp requestHttp){ + switch (requestHttp.getRequestType()){ + case apacheHttp: + return new ApacheMediaUploadRequestExecutor(requestHttp); + case joddHttp: + return new JoddMediaUploadRequestExecutor(requestHttp); + case okHttp: + return new OkMediaUploadRequestExecutor(requestHttp); + default: + return null; } - request.withConnectionProvider(provider); - request.form("media", file); - HttpResponse response = request.send(); - String responseContent = response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return WxMediaUploadResult.fromJson(responseContent); } - - /** - * okhttp现实方式 - * - * @param pool - * @param proxyInfo - * @param uri - * @param file - * @return - * @throws WxErrorException - * @throws IOException - */ - public WxMediaUploadResult executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, File file) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - - RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); - RequestBody body = new MultipartBody.Builder().addFormDataPart("media", null, fileBody).build(); - Request request = new Request.Builder().url(uri).post(body).build(); - - Response response = client.newCall(request).execute(); - String responseContent = response.body().string(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return WxMediaUploadResult.fromJson(responseContent); - } - - } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java index 42fa76f958..b58249e920 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java @@ -26,7 +26,7 @@ public interface RequestExecutor { * @throws WxErrorException * @throws IOException */ - T execute(RequestHttp requestHttp, String uri, E data) throws WxErrorException, IOException; + T execute(String uri, E data) throws WxErrorException, IOException; /** * apache-http实现方式 @@ -37,10 +37,10 @@ public interface RequestExecutor { * @return * @throws WxErrorException * @throws IOException - */ + *//* T executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, E data) throws WxErrorException, IOException; - /** + *//** * jodd-http实现方式 * @param provider * @param proxyInfo @@ -49,11 +49,11 @@ public interface RequestExecutor { * @return * @throws WxErrorException * @throws IOException - */ + *//* T executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, E data) throws WxErrorException, IOException; - /** okhttp实现方式 + *//** okhttp实现方式 * @param pool * @param proxyInfo * @param uri @@ -61,7 +61,7 @@ public interface RequestExecutor { * @return * @throws WxErrorException * @throws IOException - */ + *//* T executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, E data) throws WxErrorException, IOException; - +*/ } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java index f29739d675..ec7a2e57fe 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java @@ -6,8 +6,11 @@ import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.apache.ApacheSimpleGetRequestExecutor; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.jodd.JoddSimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.okhttp.OkSimpleGetRequestExecutor; import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import okhttp3.*; @@ -27,126 +30,25 @@ * * @author Daniel Qian */ -public class SimpleGetRequestExecutor extends AbstractRequestExecutor { +public abstract class SimpleGetRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; - - /** - * apache-http实现方式 - * - * @param httpclient - * @param httpProxy - * @param uri - * @param queryParam - * @return - * @throws WxErrorException - * @throws IOException - */ - public String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - HttpGet httpGet = new HttpGet(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpGet.setConfig(config); - } - - try (CloseableHttpResponse response = httpclient.execute(httpGet)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return responseContent; - } finally { - httpGet.releaseConnection(); - } + public SimpleGetRequestExecutor(RequestHttp requestHttp){ + this.requestHttp =requestHttp; } - /** - * jodd-http实现方式 - * - * @param provider - * @param proxyInfo - * @param uri - * @param queryParam - * @return - * @throws WxErrorException - * @throws IOException - */ - public String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - - HttpRequest request = HttpRequest.get(uri); - if (proxyInfo != null) { - provider.useProxy(proxyInfo); - } - request.withConnectionProvider(provider); - HttpResponse response = request.send(); - String responseContent = response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return responseContent; - } - - - /** - * okHttp实现方式 - * - * @param pool - * @param proxyInfo - * @param uri - * @param queryParam - * @return - * @throws WxErrorException - * @throws IOException - */ - public String executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client =clientBuilder.build(); - - Request request = new Request.Builder().url(uri).build(); - - Response response = client.newCall(request).execute(); - String responseContent = response.body().string(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); + public static RequestExecutor create(RequestHttp requestHttp){ + switch(requestHttp.getRequestType()){ + case apacheHttp: + return new ApacheSimpleGetRequestExecutor(requestHttp); + case joddHttp: + return new JoddSimpleGetRequestExecutor(requestHttp); + case okHttp: + return new OkSimpleGetRequestExecutor(requestHttp); + default: + return null; } - return responseContent; } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java index c89309b7bd..c6f4e6a7fd 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java @@ -6,8 +6,12 @@ import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.apache.ApacheSimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.apache.ApacheSimplePostRequestExecutor; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.jodd.JoddSimplePostRequestExecutor; +import me.chanjar.weixin.common.util.http.okhttp.OkSimplePostRequestExecutor; import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import okhttp3.*; @@ -27,142 +31,24 @@ * * @author Daniel Qian */ -public class SimplePostRequestExecutor extends AbstractRequestExecutor { +public abstract class SimplePostRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; - /** - * apache-http实现方式 - * - * @param httpclient - * @param httpProxy - * @param uri - * @param postEntity - * @return - * @throws WxErrorException - * @throws IOException - */ - public String executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String postEntity) throws WxErrorException, IOException { - - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - if (postEntity != null) { - StringEntity entity = new StringEntity(postEntity, Consts.UTF_8); - httpPost.setEntity(entity); - } - - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - if (responseContent.isEmpty()) { - throw new WxErrorException( - WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") - .build()); - } - - if (responseContent.startsWith("")) { - //xml格式输出直接返回 - return responseContent; - } - - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return responseContent; - } finally { - httpPost.releaseConnection(); - } - } - - - /** - * jodd-http实现方式 - * - * @param provider - * @param proxyInfo - * @param uri - * @param postEntity - * @return - * @throws WxErrorException - * @throws IOException - */ - public String executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String postEntity) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (proxyInfo != null) { - provider.useProxy(proxyInfo); - } - request.withConnectionProvider(provider); - if (postEntity != null) { - request.bodyText(postEntity); - } - HttpResponse response = request.send(); - - String responseContent = response.bodyText(); - if (responseContent.isEmpty()) { - throw new WxErrorException( - WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") - .build()); - } - - if (responseContent.startsWith("")) { - //xml格式输出直接返回 - return responseContent; - } - - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return responseContent; + public SimplePostRequestExecutor(RequestHttp requestHttp){ + this.requestHttp =requestHttp; } - - /** - * okHttp实现方式 - * - * @param pool - * @param proxyInfo - * @param uri - * @param postEntity - * @return - * @throws WxErrorException - * @throws IOException - */ - public String executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String postEntity) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); + public static RequestExecutor create(RequestHttp requestHttp){ + switch (requestHttp.getRequestType()){ + case apacheHttp: + return new ApacheSimplePostRequestExecutor(requestHttp); + case joddHttp: + return new JoddSimplePostRequestExecutor(requestHttp); + case okHttp: + return new OkSimplePostRequestExecutor(requestHttp); + default: + return null; } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - - - MediaType mediaType = MediaType.parse("text/plain; charset=utf-8"); - RequestBody body = RequestBody.create(mediaType, postEntity); - - Request request = new Request.Builder().url(uri).post(body).build(); - - Response response = client.newCall(request).execute(); - String responseContent = response.body().string(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return responseContent; } - } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java new file mode 100644 index 0000000000..8546a79126 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java @@ -0,0 +1,90 @@ +package me.chanjar.weixin.common.util.http.apache; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor { + + + public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public File execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpGet httpGet = new HttpGet(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet); + InputStream inputStream = InputStreamResponseHandler.INSTANCE + .handleResponse(response)) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0) { + if (contentTypeHeader[0].getValue().startsWith(ContentType.APPLICATION_JSON.getMimeType())) { + // application/json; encoding=utf-8 下载媒体文件出错 + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + } + + String fileName = getFileName(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + + String[] nameAndExt = fileName.split("\\."); + return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], super.tmpDirFile); + + } finally { + httpGet.releaseConnection(); + } + } + + private String getFileName(CloseableHttpResponse response) throws WxErrorException { + Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); + if (contentDispositionHeader == null || contentDispositionHeader.length == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(contentDispositionHeader[0].getValue()); + if (m.matches()) { + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java new file mode 100644 index 0000000000..a9c10a58d9 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java @@ -0,0 +1,58 @@ +package me.chanjar.weixin.common.util.http.apache; + +import java.io.File; +import java.io.IOException; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMediaUploadRequestExecutor extends MediaUploadRequestExecutor { + public ApacheMediaUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaUploadResult execute(String uri, File file) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + if (file != null) { + HttpEntity entity = MultipartEntityBuilder + .create() + .addBinaryBody("media", file) + .setMode(HttpMultipartMode.RFC6532) + .build(); + httpPost.setEntity(entity); + httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); + } + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMediaUploadResult.fromJson(responseContent); + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java new file mode 100644 index 0000000000..9564fd3618 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.common.util.http.apache; + +import java.io.IOException; + +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class ApacheSimpleGetRequestExecutor extends SimpleGetRequestExecutor { + + public ApacheSimpleGetRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + HttpGet httpGet = new HttpGet(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } finally { + httpGet.releaseConnection(); + } + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java new file mode 100644 index 0000000000..4e092c435e --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java @@ -0,0 +1,63 @@ +package me.chanjar.weixin.common.util.http.apache; + +import java.io.IOException; + +import org.apache.http.Consts; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class ApacheSimplePostRequestExecutor extends SimplePostRequestExecutor { + + public ApacheSimplePostRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String postEntity) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + if (postEntity != null) { + StringEntity entity = new StringEntity(postEntity, Consts.UTF_8); + httpPost.setEntity(entity); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + if (responseContent.isEmpty()) { + throw new WxErrorException( + WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") + .build()); + } + + if (responseContent.startsWith("")) { + //xml格式输出直接返回 + return responseContent; + } + + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaDownloadRequestExecutor.java new file mode 100644 index 0000000000..f392f5accb --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaDownloadRequestExecutor.java @@ -0,0 +1,79 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor { + + + public JoddMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public File execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpRequest request = HttpRequest.get(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + HttpResponse response = request.send(); + String contentType = response.header("Content-Type"); + if (contentType != null && contentType.startsWith("application/json")) { + // application/json; encoding=utf-8 下载媒体文件出错 + throw new WxErrorException(WxError.fromJson(response.bodyText())); + } + + String fileName = getFileName(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + + InputStream inputStream = new ByteArrayInputStream(response.bodyBytes()); + String[] nameAndExt = fileName.split("\\."); + return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], super.tmpDirFile); + } + + private String getFileName(HttpResponse response) throws WxErrorException { + String content = response.header("Content-disposition"); + if (content == null || content.length() == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(content); + if (m.matches()) { + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaUploadRequestExecutor.java new file mode 100644 index 0000000000..91cae4fc0d --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaUploadRequestExecutor.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import java.io.File; +import java.io.IOException; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMediaUploadRequestExecutor extends MediaUploadRequestExecutor { + public JoddMediaUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaUploadResult execute(String uri, File file) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + request.form("media", file); + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMediaUploadResult.fromJson(responseContent); + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimpleGetRequestExecutor.java new file mode 100644 index 0000000000..ea44e5a658 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimpleGetRequestExecutor.java @@ -0,0 +1,54 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import java.io.IOException; + +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class JoddSimpleGetRequestExecutor extends SimpleGetRequestExecutor { + + public JoddSimpleGetRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpRequest request = HttpRequest.get(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimplePostRequestExecutor.java new file mode 100644 index 0000000000..59eea7b2fe --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimplePostRequestExecutor.java @@ -0,0 +1,58 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import java.io.IOException; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class JoddSimplePostRequestExecutor extends SimplePostRequestExecutor { + + public JoddSimplePostRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String postEntity) throws WxErrorException, IOException { + HttpConnectionProvider provider = requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = requestHttp.getRequestHttpProxy(); + + HttpRequest request = HttpRequest.post(uri); + if (proxyInfo != null) { + provider.useProxy(proxyInfo); + } + request.withConnectionProvider(provider); + if (postEntity != null) { + request.bodyText(postEntity); + } + HttpResponse response = request.send(); + + String responseContent = response.bodyText(); + if (responseContent.isEmpty()) { + throw new WxErrorException( + WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") + .build()); + } + + if (responseContent.startsWith("")) { + //xml格式输出直接返回 + return responseContent; + } + + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaDownloadRequestExecutor.java new file mode 100644 index 0000000000..a2f6f8edeb --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaDownloadRequestExecutor.java @@ -0,0 +1,92 @@ +package me.chanjar.weixin.common.util.http.okhttp; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import okhttp3.*; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor { + + + public OkMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public File execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + Request request = new Request.Builder().url(uri).get().build(); + + Response response = client.newCall(request).execute(); + + String contentType = response.header("Content-Type"); + if (contentType != null && contentType.startsWith("application/json")) { + // application/json; encoding=utf-8 下载媒体文件出错 + throw new WxErrorException(WxError.fromJson(response.body().string())); + } + + String fileName = getFileName(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + + InputStream inputStream = new ByteArrayInputStream(response.body().bytes()); + String[] nameAndExt = fileName.split("\\."); + return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], super.tmpDirFile); + } + + private String getFileName(Response response) throws WxErrorException { + String content = response.header("Content-disposition"); + if (content == null || content.length() == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(content); + if (m.matches()) { + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaUploadRequestExecutor.java new file mode 100644 index 0000000000..b380895679 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaUploadRequestExecutor.java @@ -0,0 +1,56 @@ +package me.chanjar.weixin.common.util.http.okhttp; + +import java.io.File; +import java.io.IOException; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import okhttp3.*; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkMediaUploadRequestExecutor extends MediaUploadRequestExecutor { + + public OkMediaUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaUploadResult execute(String uri, File file) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); + RequestBody body = new MultipartBody.Builder().addFormDataPart("media", null, fileBody).build(); + Request request = new Request.Builder().url(uri).post(body).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMediaUploadResult.fromJson(responseContent); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimpleGetRequestExecutor.java new file mode 100644 index 0000000000..5d77bf7dbe --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimpleGetRequestExecutor.java @@ -0,0 +1,63 @@ +package me.chanjar.weixin.common.util.http.okhttp; + +import java.io.IOException; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import okhttp3.*; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class OkSimpleGetRequestExecutor extends SimpleGetRequestExecutor { + + public OkSimpleGetRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client =clientBuilder.build(); + + Request request = new Request.Builder().url(uri).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimplePostRequestExecutor.java new file mode 100644 index 0000000000..1fddcb261c --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimplePostRequestExecutor.java @@ -0,0 +1,59 @@ +package me.chanjar.weixin.common.util.http.okhttp; + +import java.io.IOException; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import okhttp3.*; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class OkSimplePostRequestExecutor extends SimplePostRequestExecutor{ + + public OkSimplePostRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String postEntity) throws WxErrorException, IOException { + ConnectionPool pool = requestHttp.getRequestHttpClient(); + final OkhttpProxyInfo proxyInfo = requestHttp.getRequestHttpProxy(); + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + + MediaType mediaType = MediaType.parse("text/plain; charset=utf-8"); + RequestBody body = RequestBody.create(mediaType, postEntity); + + Request request = new Request.Builder().url(uri).post(body).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java index 27928d8bf6..85065a7138 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java @@ -93,7 +93,7 @@ public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { synchronized (this.globalJsapiTicketRefreshLock) { if (this.configStorage.isJsapiTicketExpired()) { String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, null); + String responseContent = execute(SimpleGetRequestExecutor.create(this), url, null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); @@ -187,14 +187,14 @@ public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputS @Override public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; - return execute(new MediaUploadRequestExecutor(), url, file); + return execute(MediaUploadRequestExecutor.create(this), url, file); } @Override public File mediaDownload(String mediaId) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; return execute( - new MediaDownloadRequestExecutor( + MediaDownloadRequestExecutor.create(this, this.configStorage.getTmpDirFile()), url, "media_id=" + mediaId); } @@ -204,7 +204,7 @@ public File mediaDownload(String mediaId) throws WxErrorException { public Integer departCreate(WxCpDepart depart) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; String responseContent = execute( - new SimplePostRequestExecutor(), + SimplePostRequestExecutor.create(this), url, depart.toJson()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); @@ -475,12 +475,12 @@ public String[] getCallbackIp() throws WxErrorException { @Override public String get(String url, String queryParam) throws WxErrorException { - return execute(new SimpleGetRequestExecutor(), url, queryParam); + return execute(SimpleGetRequestExecutor.create(this), url, queryParam); } @Override public String post(String url, String postData) throws WxErrorException { - return execute(new SimplePostRequestExecutor(), url, postData); + return execute(SimplePostRequestExecutor.create(this), url, postData); } /** @@ -530,7 +530,7 @@ protected synchronized T executeInternal(RequestExecutor executor, String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken; try { - T result = executor.execute(this, uriWithAccessToken, data); + T result = executor.execute(uriWithAccessToken, data); this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, result); return result; } catch (WxErrorException e) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java index 35a23f709d..34a80fc513 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java @@ -8,7 +8,7 @@ * 卡券相关接口 * @author YuJian(mgcnrx11@hotmail.com) on 01/11/2016 */ -public interface WxMpCardService { +public interface WxMpCardService { /** * 得到WxMpService diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index 8f03350b78..da51c00115 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -4,6 +4,7 @@ import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.mp.bean.*; import me.chanjar.weixin.mp.bean.result.*; @@ -414,5 +415,11 @@ public interface WxMpService { */ void initHttp(); + /** + * + * @return + */ + RequestHttp getRequestHttp(); + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java index 00880ffdfb..527f6fe2e1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java @@ -45,6 +45,7 @@ public abstract class AbstractWxMpServiceImpl implements WxMpService, Requ private int retrySleepMillis = 1000; private int maxRetryTimes = 5; + @Override public boolean checkSignature(String timestamp, String nonce, String signature) { try { @@ -71,7 +72,7 @@ public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { } if (this.getWxMpConfigStorage().isJsapiTicketExpired()) { - String responseContent = execute(new SimpleGetRequestExecutor(), WxMpService.GET_JSAPI_TICKET_URL, null); + String responseContent = execute(SimpleGetRequestExecutor.create(this), WxMpService.GET_JSAPI_TICKET_URL, null); JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); @@ -165,8 +166,8 @@ public String buildQrConnectUrl(String redirectURI, String scope, String state) private WxMpOAuth2AccessToken getOAuth2AccessToken(String url) throws WxErrorException { try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(this, url, null); + RequestExecutor executor = SimpleGetRequestExecutor.create(this); + String responseText = executor.execute(url, null); return WxMpOAuth2AccessToken.fromJson(responseText); } catch (IOException e) { throw new RuntimeException(e); @@ -194,8 +195,8 @@ public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, Strin String url = String.format(WxMpService.OAUTH2_USERINFO_URL, oAuth2AccessToken.getAccessToken(), oAuth2AccessToken.getOpenId(), lang); try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(this, url, null); + RequestExecutor executor = SimpleGetRequestExecutor.create(this); + String responseText = executor.execute(url, null); return WxMpUser.fromJson(responseText); } catch (IOException e) { throw new RuntimeException(e); @@ -207,8 +208,8 @@ public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken String url = String.format(WxMpService.OAUTH2_VALIDATE_TOKEN_URL, oAuth2AccessToken.getAccessToken(), oAuth2AccessToken.getOpenId()); try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - executor.execute(this, url, null); + RequestExecutor executor = SimpleGetRequestExecutor.create(this); + executor.execute(url, null); } catch (IOException e) { throw new RuntimeException(e); } catch (WxErrorException e) { @@ -231,12 +232,12 @@ public String[] getCallbackIP() throws WxErrorException { @Override public String get(String url, String queryParam) throws WxErrorException { - return execute(new SimpleGetRequestExecutor(), url, queryParam); + return execute(SimpleGetRequestExecutor.create(this), url, queryParam); } @Override public String post(String url, String postData) throws WxErrorException { - return execute(new SimplePostRequestExecutor(), url, postData); + return execute(SimplePostRequestExecutor.create(this), url, postData); } /** @@ -283,7 +284,7 @@ public synchronized T executeInternal(RequestExecutor executor, Str String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken; try { - T result = executor.execute(this, uriWithAccessToken, data); + T result = executor.execute(uriWithAccessToken, data); this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, result); return result; } catch (WxErrorException e) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java index 9e64d0431c..388bca5653 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java @@ -15,8 +15,6 @@ import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.result.WxMpCardResult; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.http.HttpHost; -import org.apache.http.impl.client.CloseableHttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,7 +24,7 @@ /** * Created by Binary Wang on 2016/7/27. */ -public class WxMpCardServiceImpl implements WxMpCardService { +public class WxMpCardServiceImpl implements WxMpCardService { private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class); @@ -81,7 +79,7 @@ public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { if (this.getWxMpService().getWxMpConfigStorage().isCardApiTicketExpired()) { String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; - String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); + String responseContent = this.wxMpService.execute(SimpleGetRequestExecutor.create(this.getWxMpService().getRequestHttp()), url, null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java index b5a6b39542..8d98a07a32 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java @@ -67,7 +67,7 @@ public boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErro @Override public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) throws WxErrorException { WxMediaUploadResult responseContent = this.wxMpService - .execute(new MediaUploadRequestExecutor(), String.format(KFACCOUNT_UPLOAD_HEAD_IMG, kfAccount), imgFile); + .execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), String.format(KFACCOUNT_UPLOAD_HEAD_IMG, kfAccount), imgFile); return responseContent != null; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java index 4242063bda..b24ea80d21 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java @@ -46,14 +46,14 @@ public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputS @Override public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { String url = MEDIA_API_URL_PREFIX + "/upload?type=" + mediaType; - return this.wxMpService.execute(new MediaUploadRequestExecutor(), url, file); + return this.wxMpService.execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, file); } @Override public File mediaDownload(String media_id) throws WxErrorException { String url = MEDIA_API_URL_PREFIX + "/get"; return this.wxMpService.execute( - new MediaDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), + MediaDownloadRequestExecutor.create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, "media_id=" + media_id); } @@ -61,13 +61,13 @@ public File mediaDownload(String media_id) throws WxErrorException { @Override public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException { String url = MEDIA_API_URL_PREFIX + "/uploadimg"; - return this.wxMpService.execute(new MediaImgUploadRequestExecutor(), url, file); + return this.wxMpService.execute(MediaImgUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, file); } @Override public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException { String url = MATERIAL_API_URL_PREFIX + "/add_material?type=" + mediaType; - return this.wxMpService.execute(new MaterialUploadRequestExecutor(), url, material); + return this.wxMpService.execute(MaterialUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, material); } @Override @@ -83,19 +83,19 @@ public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws @Override public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException { String url = MATERIAL_API_URL_PREFIX + "/get_material"; - return this.wxMpService.execute(new MaterialVoiceAndImageDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, media_id); + return this.wxMpService.execute(MaterialVoiceAndImageDownloadRequestExecutor.create(this.wxMpService.getRequestHttp(),this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, media_id); } @Override public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException { String url = MATERIAL_API_URL_PREFIX + "/get_material"; - return this.wxMpService.execute(new MaterialVideoInfoRequestExecutor(), url, media_id); + return this.wxMpService.execute(MaterialVideoInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), url, media_id); } @Override public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException { String url = MATERIAL_API_URL_PREFIX + "/get_material"; - return this.wxMpService.execute(new MaterialNewsInfoRequestExecutor(), url, media_id); + return this.wxMpService.execute(MaterialNewsInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), url, media_id); } @Override @@ -113,7 +113,7 @@ public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleU @Override public boolean materialDelete(String media_id) throws WxErrorException { String url = MATERIAL_API_URL_PREFIX + "/del_material"; - return this.wxMpService.execute(new MaterialDeleteRequestExecutor(), url, media_id); + return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()), url, media_id); } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java index 8659f2af9d..817a0b68f2 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java @@ -89,7 +89,7 @@ public WxMpQrCodeTicket qrCodeCreateLastTicket(String sceneStr) throws WxErrorEx @Override public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException { String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode"; - return this.wxMpService.execute(new QrCodeRequestExecutor(), url, ticket); + return this.wxMpService.execute(QrCodeRequestExecutor.create(this.wxMpService.getRequestHttp()), url, ticket); } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java index b0b35343e8..4e3f78140a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java @@ -28,7 +28,7 @@ public WxMpUserBlacklistGetResult getBlacklist(String nextOpenid) throws WxError JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("begin_openid", nextOpenid); String url = API_BLACKLIST_PREFIX + "/getblacklist"; - String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, jsonObject.toString()); + String responseContent = this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, jsonObject.toString()); return WxMpUserBlacklistGetResult.fromJson(responseContent); } @@ -37,7 +37,7 @@ public void pushToBlacklist(List openidList) throws WxErrorException { Map map = new HashMap<>(); map.put("openid_list", openidList); String url = API_BLACKLIST_PREFIX + "/batchblacklist"; - this.wxMpService.execute(new SimplePostRequestExecutor(), url, new Gson().toJson(map)); + this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, new Gson().toJson(map)); } @Override @@ -45,6 +45,6 @@ public void pullFromBlacklist(List openidList) throws WxErrorException { Map map = new HashMap<>(); map.put("openid_list", openidList); String url = API_BLACKLIST_PREFIX + "/batchunblacklist"; - this.wxMpService.execute(new SimplePostRequestExecutor(), url, new Gson().toJson(map)); + this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, new Gson().toJson(map)); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java index 835fbe1897..d0991a5bc8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java @@ -71,6 +71,11 @@ public void initHttp() { this.httpClient = apacheHttpClientBuilder.build(); } + @Override + public RequestHttp getRequestHttp() { + return this; + } + @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java index 677e2e6b6d..b32ea3eb13 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java @@ -6,6 +6,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; +import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.mp.api.*; import me.chanjar.weixin.mp.api.impl.*; @@ -45,6 +46,11 @@ public void initHttp() { httpClient = JoddHttp.httpConnectionProvider; } + @Override + public RequestHttp getRequestHttp() { + return this; + } + @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java index dc6d7d0051..afa0ed7148 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java @@ -4,6 +4,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; +import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; @@ -94,5 +95,10 @@ public void initHttp() { httpClient = new ConnectionPool(); } + @Override + public RequestHttp getRequestHttp() { + return this; + } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java index d6c68bf963..6bd467c0b5 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java @@ -6,7 +6,6 @@ import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; @@ -14,6 +13,9 @@ import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialDeleteRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialDeleteRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialDeleteRequestExecutor; import okhttp3.*; import org.apache.http.HttpHost; @@ -27,87 +29,23 @@ import java.util.HashMap; import java.util.Map; -public class MaterialDeleteRequestExecutor extends AbstractRequestExecutor { +public abstract class MaterialDeleteRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; - - public MaterialDeleteRequestExecutor() { - super(); - } - - @Override - public Boolean executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return true; - } - } finally { - httpPost.releaseConnection(); - } - } - - - @Override - public Boolean executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (proxyInfo != null) { - provider.useProxy(proxyInfo); - } - request.withConnectionProvider(provider); - - request.query("media_id", materialId); - HttpResponse response = request.send(); - String responseContent = response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return true; - } + public MaterialDeleteRequestExecutor(RequestHttp requestHttp){ + this.requestHttp =requestHttp; } - @Override - public Boolean executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - - RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); - Request request = new Request.Builder().url(uri).post(requestBody).build(); - Response response = client.newCall(request).execute(); - String responseContent = response.body().string(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return true; + public static RequestExecutor create(RequestHttp requestHttp){ + switch (requestHttp.getRequestType()){ + case apacheHttp: + return new ApacheMaterialDeleteRequestExecutor(requestHttp); + case joddHttp: + return new JoddMaterialDeleteRequestExecutor(requestHttp); + case okHttp: + return new OkhttpMaterialDeleteRequestExecutor(requestHttp); + default: + return null; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java index de5f23429c..92188b2a99 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java @@ -6,7 +6,6 @@ import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; @@ -15,6 +14,9 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialNewsInfoRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialNewsInfoRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialNewsInfoRequestExecutor; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import okhttp3.*; @@ -29,88 +31,24 @@ import java.util.HashMap; import java.util.Map; -public class MaterialNewsInfoRequestExecutor extends AbstractRequestExecutor { +public abstract class MaterialNewsInfoRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; - public MaterialNewsInfoRequestExecutor() { - super(); + public MaterialNewsInfoRequestExecutor(RequestHttp requestHttp){ + this.requestHttp =requestHttp; } - @Override - public WxMpMaterialNews executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); - } - } finally { - httpPost.releaseConnection(); - } - } - - - @Override - public WxMpMaterialNews executeJodd(HttpConnectionProvider httpclient, ProxyInfo httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (httpProxy != null) { - httpclient.useProxy(httpProxy); - } - request.withConnectionProvider(httpclient); - - request.query("media_id", materialId); - HttpResponse response = request.send(); - - String responseContent = response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); - } - } - - @Override - public WxMpMaterialNews executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - - RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); - Request request = new Request.Builder().url(uri).post(requestBody).build(); - - Response response = client.newCall(request).execute(); - String responseContent = response.body().string(); - - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + public static RequestExecutor create(RequestHttp requestHttp){ + switch (requestHttp.getRequestType()){ + case apacheHttp: + return new ApacheMaterialNewsInfoRequestExecutor(requestHttp); + case joddHttp: + return new JoddMaterialNewsInfoRequestExecutor(requestHttp); + case okHttp: + return new OkhttpMaterialNewsInfoRequestExecutor(requestHttp); + default: + //TODO 需要优化抛出异常 + return null; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java index 772684ab7c..54d1d0e7da 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java @@ -6,7 +6,6 @@ import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; @@ -16,6 +15,9 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.bean.material.WxMpMaterial; import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialUploadRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialUploadRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialUploadRequestExecutor; import okhttp3.*; import org.apache.http.HttpHost; @@ -32,127 +34,22 @@ import java.io.IOException; import java.util.Map; -public class MaterialUploadRequestExecutor extends AbstractRequestExecutor { - - @Override - public WxMpMaterialUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo httpProxy, String uri, WxMpMaterial material) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (httpProxy != null) { - provider.useProxy(httpProxy); - } - request.withConnectionProvider(provider); - - if (material == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); - } - - File file = material.getFile(); - if (file == null || !file.exists()) { - throw new FileNotFoundException(); - } - request.form("media", file); - Map form = material.getForm(); - if (material.getForm() != null) { - request.form("description", WxGsonBuilder.create().toJson(form)); - } - - HttpResponse response = request.send(); - String responseContent = response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialUploadResult.fromJson(responseContent); - } - } - - @Override - public WxMpMaterialUploadResult executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, WxMpMaterial material) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - - - if (material == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); - } - - File file = material.getFile(); - if (file == null || !file.exists()) { - throw new FileNotFoundException(); - } - RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); - MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().addFormDataPart("media", null, fileBody); - Map form = material.getForm(); - if (material.getForm() != null) { - bodyBuilder.addFormDataPart("description", WxGsonBuilder.create().toJson(form)); - } - RequestBody body =bodyBuilder.build(); - Request request = new Request.Builder().url(uri).post(body).build(); - Response response = client.newCall(request).execute(); - String responseContent = response.body().string(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialUploadResult.fromJson(responseContent); - } +public abstract class MaterialUploadRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; + public MaterialUploadRequestExecutor(RequestHttp requestHttp){ + this.requestHttp =requestHttp; } - @Override - public WxMpMaterialUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - WxMpMaterial material) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig response = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(response); - } - - if (material == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); - } - - File file = material.getFile(); - if (file == null || !file.exists()) { - throw new FileNotFoundException(); - } - - MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); - multipartEntityBuilder - .addBinaryBody("media", file) - .setMode(HttpMultipartMode.RFC6532); - Map form = material.getForm(); - if (material.getForm() != null) { - multipartEntityBuilder.addTextBody("description", WxGsonBuilder.create().toJson(form)); - } - - httpPost.setEntity(multipartEntityBuilder.build()); - httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); - - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialUploadResult.fromJson(responseContent); - } - } finally { - httpPost.releaseConnection(); + public static RequestExecutor create(RequestHttp requestHttp){ + switch (requestHttp.getRequestType()){ + case apacheHttp: + return new ApacheMaterialUploadRequestExecutor(requestHttp); + case joddHttp: + return new JoddMaterialUploadRequestExecutor(requestHttp); + case okHttp: + return new OkhttpMaterialUploadRequestExecutor(requestHttp); + default: + return null; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java index 3c481f7ca1..c042d261df 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java @@ -6,7 +6,6 @@ import jodd.http.ProxyInfo; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; @@ -14,8 +13,10 @@ import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialVideoInfoRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialVideoInfoRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialVideoInfoRequestExecutor; import okhttp3.*; import org.apache.http.HttpHost; @@ -29,87 +30,23 @@ import java.util.HashMap; import java.util.Map; -public class MaterialVideoInfoRequestExecutor extends AbstractRequestExecutor { - - public MaterialVideoInfoRequestExecutor() { - super(); - } - - @Override - public WxMpMaterialVideoInfoResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (proxyInfo != null) { - provider.useProxy(proxyInfo); - } - request.withConnectionProvider(provider); - - request.query("media_id", materialId); - HttpResponse response = request.send(); - String responseContent = response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialVideoInfoResult.fromJson(responseContent); - } - } - - @Override - public WxMpMaterialVideoInfoResult executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - - RequestBody requestBody =new FormBody.Builder().add("media_id", materialId).build(); - Request request = new Request.Builder().url(uri).post(requestBody).build(); - Response response = client.newCall(request).execute(); - String responseContent = response.body().string(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialVideoInfoResult.fromJson(responseContent); - } +public abstract class MaterialVideoInfoRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; + public MaterialVideoInfoRequestExecutor(RequestHttp requestHttp){ + this.requestHttp =requestHttp; } - @Override - public WxMpMaterialVideoInfoResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialVideoInfoResult.fromJson(responseContent); - } - } finally { - httpPost.releaseConnection(); + public static RequestExecutor create(RequestHttp requestHttp){ + switch (requestHttp.getRequestType()){ + case apacheHttp: + return new ApacheMaterialVideoInfoRequestExecutor(requestHttp); + case joddHttp: + return new JoddMaterialVideoInfoRequestExecutor(requestHttp); + case okHttp: + return new OkhttpMaterialVideoInfoRequestExecutor(requestHttp); + default: + return null; } } - } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java index d536223c9d..752553468c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java @@ -7,13 +7,14 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialVoiceAndImageDownloadRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialVoiceAndImageDownloadRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialVoiceAndImageDownloadRequestExecutor; import okhttp3.*; import org.apache.commons.io.IOUtils; @@ -31,119 +32,27 @@ import java.util.HashMap; import java.util.Map; -public class MaterialVoiceAndImageDownloadRequestExecutor extends AbstractRequestExecutor { +public abstract class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; + protected File tmpDirFile; - public MaterialVoiceAndImageDownloadRequestExecutor() { - super(); - } - - public MaterialVoiceAndImageDownloadRequestExecutor(File tmpDirFile) { - super(); - } - - - @Override - public InputStream executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (proxyInfo != null) { - provider.useProxy(proxyInfo); - } - request.withConnectionProvider(provider); - - request.query("media_id", materialId); - HttpResponse response = request.send(); - try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { - // 下载媒体文件出错 - byte[] responseContent = IOUtils.toByteArray(inputStream); - String responseContentString = new String(responseContent, "UTF-8"); - if (responseContentString.length() < 100) { - try { - WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); - if (wxError.getErrorCode() != 0) { - throw new WxErrorException(wxError); - } - } catch (com.google.gson.JsonSyntaxException ex) { - return new ByteArrayInputStream(responseContent); - } - } - return new ByteArrayInputStream(responseContent); - } + public MaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + this.requestHttp = requestHttp; + this.tmpDirFile = tmpDirFile; } - @Override - public InputStream executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - - RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); - Request request = new Request.Builder().url(uri).get().post(requestBody).build(); - Response response = client.newCall(request).execute(); - - try (InputStream inputStream = new ByteArrayInputStream(response.body().bytes())) { - - // 下载媒体文件出错 - byte[] responseContent = IOUtils.toByteArray(inputStream); - String responseContentString = new String(responseContent, "UTF-8"); - if (responseContentString.length() < 100) { - try { - WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); - if (wxError.getErrorCode() != 0) { - throw new WxErrorException(wxError); - } - } catch (com.google.gson.JsonSyntaxException ex) { - return new ByteArrayInputStream(responseContent); - } - } - return new ByteArrayInputStream(responseContent); - } - } - - @Override - public InputStream executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try (CloseableHttpResponse response = httpclient.execute(httpPost); - InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { - // 下载媒体文件出错 - byte[] responseContent = IOUtils.toByteArray(inputStream); - String responseContentString = new String(responseContent, "UTF-8"); - if (responseContentString.length() < 100) { - try { - WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); - if (wxError.getErrorCode() != 0) { - throw new WxErrorException(wxError); - } - } catch (com.google.gson.JsonSyntaxException ex) { - return new ByteArrayInputStream(responseContent); - } - } - return new ByteArrayInputStream(responseContent); - } finally { - httpPost.releaseConnection(); + public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile) { + switch (requestHttp.getRequestType()) { + case apacheHttp: + return new ApacheMaterialVoiceAndImageDownloadRequestExecutor(requestHttp, tmpDirFile); + case joddHttp: + return new JoddMaterialVoiceAndImageDownloadRequestExecutor(requestHttp, tmpDirFile); + case okHttp: + return new OkhttpMaterialVoiceAndImageDownloadRequestExecutor(requestHttp, tmpDirFile); + default: + return null; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java index 4232f33316..f4713afdbb 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java @@ -5,13 +5,8 @@ import jodd.http.HttpResponse; import jodd.http.ProxyInfo; -import jodd.util.MimeTypes; - import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; @@ -19,6 +14,9 @@ import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import me.chanjar.weixin.mp.util.http.apache.ApacheMediaImgUploadRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddMediaImgUploadRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMediaImgUploadRequestExecutor; import okhttp3.*; import org.apache.http.HttpEntity; @@ -31,104 +29,28 @@ import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.util.UUID; /** * @author miller */ -public class MediaImgUploadRequestExecutor extends AbstractRequestExecutor { - - @Override - public WxMediaImgUploadResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, File data) throws WxErrorException, IOException { - if (data == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); - } - - HttpRequest request = HttpRequest.post(uri); - if (proxyInfo != null) { - provider.useProxy(proxyInfo); - } - request.withConnectionProvider(provider); - - request.form("media", data); - HttpResponse response = request.send(); - String responseContent = response.bodyText(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - - return WxMediaImgUploadResult.fromJson(responseContent); - } - - @Override - public WxMediaImgUploadResult executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, File data) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - - RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), data); - RequestBody body = new MultipartBody.Builder().addFormDataPart("media", null, fileBody).build(); - Request request = new Request.Builder().url(uri).post(body).build(); - - Response response = client.newCall(request).execute(); - String responseContent = response.body().string(); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - - return WxMediaImgUploadResult.fromJson(responseContent); +public abstract class MediaImgUploadRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; + public MediaImgUploadRequestExecutor(RequestHttp requestHttp){ + this.requestHttp =requestHttp; } - @Override - public WxMediaImgUploadResult executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - File data) throws WxErrorException, IOException { - - if (data == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); - } - - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - HttpEntity entity = MultipartEntityBuilder - .create() - .addBinaryBody("media", data) - .setMode(HttpMultipartMode.RFC6532) - .build(); - httpPost.setEntity(entity); - httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); - - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - - return WxMediaImgUploadResult.fromJson(responseContent); + public static RequestExecutor create(RequestHttp requestHttp){ + switch (requestHttp.getRequestType()){ + case apacheHttp: + return new ApacheMediaImgUploadRequestExecutor(requestHttp); + case joddHttp: + return new JoddMediaImgUploadRequestExecutor(requestHttp); + case okHttp: + return new OkhttpMediaImgUploadRequestExecutor(requestHttp); + default: + return null; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java index d37d0bb96a..151a20e498 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java @@ -9,13 +9,16 @@ import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.AbstractRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import me.chanjar.weixin.mp.util.http.apache.ApacheQrCodeRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddQrCodeRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpQrCodeRequestExecutor; import okhttp3.*; import org.apache.http.Header; @@ -38,102 +41,25 @@ * * @author chanjarster */ -public class QrCodeRequestExecutor extends AbstractRequestExecutor { +public abstract class QrCodeRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; -@Override - public File executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, WxMpQrCodeTicket ticket) throws WxErrorException, IOException { - if (ticket != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") - ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") - : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); - } - - HttpRequest request = HttpRequest.get(uri); - if (proxyInfo != null) { - provider.useProxy(proxyInfo); - } - request.withConnectionProvider(provider); - - HttpResponse response = request.send(); - String contentTypeHeader = response.header("Content-Type"); - if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { - String responseContent = response.bodyText(); - throw new WxErrorException(WxError.fromJson(responseContent)); - } - try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { - return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); - } - } - - @Override - public File executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, WxMpQrCodeTicket data) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - - Request request = new Request.Builder().url(uri).get().build(); - Response response = client.newCall(request).execute(); - String contentTypeHeader = response.header("Content-Type"); - if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { - String responseContent = response.body().string(); - throw new WxErrorException(WxError.fromJson(responseContent)); - } - try (InputStream inputStream = new ByteArrayInputStream(response.body().bytes())) { - return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); - } + public QrCodeRequestExecutor(RequestHttp requestHttp){ + this.requestHttp =requestHttp; } - @Override - public File executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - WxMpQrCodeTicket ticket) throws WxErrorException, IOException { - - if (ticket != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") - ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") - : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); - } - - HttpGet httpGet = new HttpGet(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpGet.setConfig(config); - } - - try (CloseableHttpResponse response = httpclient.execute(httpGet); - InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { - Header[] contentTypeHeader = response.getHeaders("Content-Type"); - if (contentTypeHeader != null && contentTypeHeader.length > 0) { - // 出错 - if (ContentType.TEXT_PLAIN.getMimeType().equals(contentTypeHeader[0].getValue())) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - throw new WxErrorException(WxError.fromJson(responseContent)); - } - } - return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); - } finally { - httpGet.releaseConnection(); + public static RequestExecutor create(RequestHttp requestHttp){ + switch (requestHttp.getRequestType()){ + case apacheHttp: + return new ApacheQrCodeRequestExecutor(requestHttp); + case joddHttp: + return new JoddQrCodeRequestExecutor(requestHttp); + case okHttp: + return new OkhttpQrCodeRequestExecutor(requestHttp); + default: + //TODO 需要优化,最好抛出异常 + return null; } } - } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialDeleteRequestExecutor.java new file mode 100644 index 0000000000..5446483ff1 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialDeleteRequestExecutor.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.http.MaterialDeleteRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMaterialDeleteRequestExecutor extends MaterialDeleteRequestExecutor { + public ApacheMaterialDeleteRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public Boolean execute(String uri, String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return true; + } + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialNewsInfoRequestExecutor.java new file mode 100644 index 0000000000..81fb801974 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialNewsInfoRequestExecutor.java @@ -0,0 +1,54 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { + public ApacheMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialNews execute(String uri, String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + } + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialUploadRequestExecutor.java new file mode 100644 index 0000000000..af6ab10aa0 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialUploadRequestExecutor.java @@ -0,0 +1,75 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Map; + +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import me.chanjar.weixin.mp.util.http.MaterialUploadRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMaterialUploadRequestExecutor extends MaterialUploadRequestExecutor { + public ApacheMaterialUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig response = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(response); + } + + if (material == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); + } + + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + + MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); + multipartEntityBuilder + .addBinaryBody("media", file) + .setMode(HttpMultipartMode.RFC6532); + Map form = material.getForm(); + if (material.getForm() != null) { + multipartEntityBuilder.addTextBody("description", WxGsonBuilder.create().toJson(form)); + } + + httpPost.setEntity(multipartEntityBuilder.build()); + httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialUploadResult.fromJson(responseContent); + } + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVideoInfoRequestExecutor.java new file mode 100644 index 0000000000..1d1e2c5783 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVideoInfoRequestExecutor.java @@ -0,0 +1,53 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import me.chanjar.weixin.mp.util.http.MaterialVideoInfoRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMaterialVideoInfoRequestExecutor extends MaterialVideoInfoRequestExecutor { + public ApacheMaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialVideoInfoResult execute(String uri, String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); + } + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVoiceAndImageDownloadRequestExecutor.java new file mode 100644 index 0000000000..92cf1c5a8c --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVoiceAndImageDownloadRequestExecutor.java @@ -0,0 +1,64 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.http.MaterialVoiceAndImageDownloadRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMaterialVoiceAndImageDownloadRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { + public ApacheMaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public InputStream execute(String uri, String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + // 下载媒体文件出错 + byte[] responseContent = IOUtils.toByteArray(inputStream); + String responseContentString = new String(responseContent, "UTF-8"); + if (responseContentString.length() < 100) { + try { + WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); + if (wxError.getErrorCode() != 0) { + throw new WxErrorException(wxError); + } + } catch (com.google.gson.JsonSyntaxException ex) { + return new ByteArrayInputStream(responseContent); + } + } + return new ByteArrayInputStream(responseContent); + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMediaImgUploadRequestExecutor.java new file mode 100644 index 0000000000..4aaf2f1261 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMediaImgUploadRequestExecutor.java @@ -0,0 +1,61 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import java.io.File; +import java.io.IOException; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import me.chanjar.weixin.mp.util.http.MediaImgUploadRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMediaImgUploadRequestExecutor extends MediaImgUploadRequestExecutor { + public ApacheMediaImgUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaImgUploadResult execute(String uri, File data) throws WxErrorException, IOException { + if (data == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); + } + + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + HttpEntity entity = MultipartEntityBuilder + .create() + .addBinaryBody("media", data) + .setMode(HttpMultipartMode.RFC6532) + .build(); + httpPost.setEntity(entity); + httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + + return WxMediaImgUploadResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheQrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheQrCodeRequestExecutor.java new file mode 100644 index 0000000000..dd84f293c1 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheQrCodeRequestExecutor.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; + +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheQrCodeRequestExecutor extends QrCodeRequestExecutor { + public ApacheQrCodeRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public File execute(String uri, WxMpQrCodeTicket ticket) throws WxErrorException, IOException { + if (ticket != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") + ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") + : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); + } + + HttpGet httpGet = new HttpGet(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet); + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0) { + // 出错 + if (ContentType.TEXT_PLAIN.getMimeType().equals(contentTypeHeader[0].getValue())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + } + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } finally { + httpGet.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialDeleteRequestExecutor.java new file mode 100644 index 0000000000..082653b257 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialDeleteRequestExecutor.java @@ -0,0 +1,40 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import java.io.IOException; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.util.http.MaterialDeleteRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMaterialDeleteRequestExecutor extends MaterialDeleteRequestExecutor { + public JoddMaterialDeleteRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public Boolean execute(String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return true; + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java new file mode 100644 index 0000000000..083cfedc00 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java @@ -0,0 +1,43 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import java.io.IOException; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { + public JoddMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialNews execute(String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialUploadRequestExecutor.java new file mode 100644 index 0000000000..4c1fe48034 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialUploadRequestExecutor.java @@ -0,0 +1,59 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Map; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import me.chanjar.weixin.mp.util.http.MaterialUploadRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMaterialUploadRequestExecutor extends MaterialUploadRequestExecutor { + public JoddMaterialUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + if (material == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); + } + + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + request.form("media", file); + Map form = material.getForm(); + if (material.getForm() != null) { + request.form("description", WxGsonBuilder.create().toJson(form)); + } + + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialUploadResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVideoInfoRequestExecutor.java new file mode 100644 index 0000000000..ed7bfc04c6 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVideoInfoRequestExecutor.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import java.io.IOException; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import me.chanjar.weixin.mp.util.http.MaterialVideoInfoRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMaterialVideoInfoRequestExecutor extends MaterialVideoInfoRequestExecutor { + public JoddMaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialVideoInfoResult execute(String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java new file mode 100644 index 0000000000..b8da949e84 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java @@ -0,0 +1,56 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.http.MaterialVoiceAndImageDownloadRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialVoiceAndImageDownloadRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMaterialVoiceAndImageDownloadRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { + public JoddMaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public InputStream execute(String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { + // 下载媒体文件出错 + byte[] responseContent = IOUtils.toByteArray(inputStream); + String responseContentString = new String(responseContent, "UTF-8"); + if (responseContentString.length() < 100) { + try { + WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); + if (wxError.getErrorCode() != 0) { + throw new WxErrorException(wxError); + } + } catch (com.google.gson.JsonSyntaxException ex) { + return new ByteArrayInputStream(responseContent); + } + } + return new ByteArrayInputStream(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMediaImgUploadRequestExecutor.java new file mode 100644 index 0000000000..82bfbf8107 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMediaImgUploadRequestExecutor.java @@ -0,0 +1,46 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import java.io.File; +import java.io.IOException; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import me.chanjar.weixin.mp.util.http.MediaImgUploadRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMediaImgUploadRequestExecutor extends MediaImgUploadRequestExecutor { + public JoddMediaImgUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaImgUploadResult execute(String uri, File data) throws WxErrorException, IOException { + if (data == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); + } + + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + request.form("media", data); + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + + return WxMediaImgUploadResult.fromJson(responseContent); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddQrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddQrCodeRequestExecutor.java new file mode 100644 index 0000000000..1191751c0e --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddQrCodeRequestExecutor.java @@ -0,0 +1,57 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.MimeTypes; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddQrCodeRequestExecutor extends QrCodeRequestExecutor { + public JoddQrCodeRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public File execute(String uri, WxMpQrCodeTicket ticket) throws WxErrorException, IOException { + if (ticket != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") + ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") + : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); + } + + HttpRequest request = HttpRequest.get(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + HttpResponse response = request.send(); + String contentTypeHeader = response.header("Content-Type"); + if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { + String responseContent = response.bodyText(); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java new file mode 100644 index 0000000000..5da55877c1 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java @@ -0,0 +1,54 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import java.io.IOException; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.mp.util.http.MaterialDeleteRequestExecutor; +import okhttp3.*; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMaterialDeleteRequestExecutor extends MaterialDeleteRequestExecutor { + + + public OkhttpMaterialDeleteRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public Boolean execute(String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).post(requestBody).build(); + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return true; + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java new file mode 100644 index 0000000000..c7efbb893c --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java @@ -0,0 +1,55 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import java.io.IOException; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import okhttp3.*; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { + public OkhttpMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialNews execute(String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).post(requestBody).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java new file mode 100644 index 0000000000..4be74cdaae --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java @@ -0,0 +1,80 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Map; + +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import me.chanjar.weixin.mp.util.http.MaterialUploadRequestExecutor; +import okhttp3.*; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMaterialUploadRequestExecutor extends MaterialUploadRequestExecutor { + public OkhttpMaterialUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + + if (material == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); + } + + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); + MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().addFormDataPart("media", null, fileBody); + Map form = material.getForm(); + if (material.getForm() != null) { + bodyBuilder.addFormDataPart("description", WxGsonBuilder.create().toJson(form)); + } + RequestBody body =bodyBuilder.build(); + Request request = new Request.Builder().url(uri).post(body).build(); + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialUploadResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java new file mode 100644 index 0000000000..c431d70ae4 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import java.io.IOException; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import me.chanjar.weixin.mp.util.http.MaterialVideoInfoRequestExecutor; +import okhttp3.*; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMaterialVideoInfoRequestExecutor extends MaterialVideoInfoRequestExecutor { + public OkhttpMaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialVideoInfoResult execute(String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody =new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).post(requestBody).build(); + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java new file mode 100644 index 0000000000..3cd1eb980f --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java @@ -0,0 +1,68 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.http.MaterialVoiceAndImageDownloadRequestExecutor; +import okhttp3.*; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMaterialVoiceAndImageDownloadRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { + public OkhttpMaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public InputStream execute(String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).get().post(requestBody).build(); + Response response = client.newCall(request).execute(); + + try (InputStream inputStream = new ByteArrayInputStream(response.body().bytes())) { + + // 下载媒体文件出错 + byte[] responseContent = IOUtils.toByteArray(inputStream); + String responseContentString = new String(responseContent, "UTF-8"); + if (responseContentString.length() < 100) { + try { + WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); + if (wxError.getErrorCode() != 0) { + throw new WxErrorException(wxError); + } + } catch (com.google.gson.JsonSyntaxException ex) { + return new ByteArrayInputStream(responseContent); + } + } + return new ByteArrayInputStream(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java new file mode 100644 index 0000000000..790dd17eb1 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java @@ -0,0 +1,56 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import java.io.File; +import java.io.IOException; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import me.chanjar.weixin.mp.util.http.MediaImgUploadRequestExecutor; +import okhttp3.*; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMediaImgUploadRequestExecutor extends MediaImgUploadRequestExecutor { + + public OkhttpMediaImgUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaImgUploadResult execute(String uri, File data) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), data); + RequestBody body = new MultipartBody.Builder().addFormDataPart("media", null, fileBody).build(); + Request request = new Request.Builder().url(uri).post(body).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + + return WxMediaImgUploadResult.fromJson(responseContent); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java new file mode 100644 index 0000000000..b2cb372f0b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java @@ -0,0 +1,58 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +import jodd.util.MimeTypes; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; +import okhttp3.*; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpQrCodeRequestExecutor extends QrCodeRequestExecutor { + public OkhttpQrCodeRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public File execute(String uri, WxMpQrCodeTicket data) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + Request request = new Request.Builder().url(uri).get().build(); + Response response = client.newCall(request).execute(); + String contentTypeHeader = response.header("Content-Type"); + if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { + String responseContent = response.body().string(); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + try (InputStream inputStream = new ByteArrayInputStream(response.body().bytes())) { + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } + } +} From adcff4ec7af577ff533080f6ede35d575d66a2be Mon Sep 17 00:00:00 2001 From: ecoolper Date: Mon, 8 May 2017 18:35:54 +0800 Subject: [PATCH 025/179] =?UTF-8?q?pom=E6=B7=BBdeveloper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 5e219eb686..3e915cfc82 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,11 @@ aimilin@yeah.net https://github.com/aimilin6688 + + ecoolper + crskyp@gmail.com + https://github.com/crskyp + From 49d07fc51877743015d8a3b47395971b812aa63d Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 9 May 2017 13:51:22 +0800 Subject: [PATCH 026/179] Update contribution.md --- contribution.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contribution.md b/contribution.md index cbcbb7dbb3..abd07aa6f5 100644 --- a/contribution.md +++ b/contribution.md @@ -1,8 +1,9 @@ # 代码贡献指南 1. 非常欢迎和感谢对本项目发起Pull Request的同学,本项目代码风格为使用2个空格代表一个Tab,因此在提交代码时请注意一下,否则很容易在IDE格式化代码后与原代码产生大量diff,这样会给其他人阅读代码带来极大的困扰。为了便于设置,本项目引入editorconfig插件,请使用eclipse的同学在贡献代码前安装相关插件,IntelliJ IDEA新版本自带支持,如果没有可自行安装插件。 1. 本项目可以采用两种方式接受代码贡献: - * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择develop分支,详细步骤参考后文。 +  * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择develop分支,详细步骤参考后文,推荐使用此种方式贡献代码。 * 另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题,具体加入方式,请咨询QQ群管理员[![点击这里给我发消息](http://wpa.qq.com/pa?p=2:1211415707:51)](http://wpa.qq.com/msgrd?v=3&uin=1211415707&site=qq&menu=yes)。 +1. 提交代码前请检查代码是否已经格式化,并且保证新增加或者修改的方法都有完整的参数说明,而public方法必须拥有相应的单元测试并通过测试。 ### PR方式贡献代码步骤 From 16dea387f2f9a2941876f9f80c7bba6af8d2187d Mon Sep 17 00:00:00 2001 From: ecoolper Date: Fri, 19 May 2017 23:48:47 +0800 Subject: [PATCH 027/179] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=A4=E4=B8=AA?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MaterialVideoInfoRequestExecutor.java | 44 +++++++++++-------- .../okhttp/OkhttpQrCodeRequestExecutor.java | 3 +- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java index 4d18379cb8..49c984ddb5 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java @@ -1,25 +1,33 @@ package me.chanjar.weixin.mp.util.http; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; -import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialVideoInfoRequestExecutor; -import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialVideoInfoRequestExecutor; -import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialVideoInfoRequestExecutor; + + import me.chanjar.weixin.common.util.http.RequestExecutor; + import me.chanjar.weixin.common.util.http.RequestHttp; + + import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; + import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialVideoInfoRequestExecutor; + import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialVideoInfoRequestExecutor; + import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialVideoInfoRequestExecutor; + public abstract class MaterialVideoInfoRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; public MaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { - this.requestHttp = requestHttp; - } - - @Override - public WxMpMaterialVideoInfoResult executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, String materialId) throws WxErrorException, IOException { - HttpRequest request = HttpRequest.post(uri); - if (proxyInfo != null) { - provider.useProxy(proxyInfo); - } - } - -} + this.requestHttp = requestHttp; + } + + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case apacheHttp: + return new ApacheMaterialVideoInfoRequestExecutor(requestHttp); + case joddHttp: + return new JoddMaterialVideoInfoRequestExecutor(requestHttp); + case okHttp: + return new OkhttpMaterialVideoInfoRequestExecutor(requestHttp); + default: + return null; + } + } + + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java index 6bc83cd391..5d75c74d4d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java @@ -7,6 +7,7 @@ import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; + import okhttp3.*; import java.io.ByteArrayInputStream; @@ -46,7 +47,7 @@ public Request authenticate(Route route, Response response) throws IOException { Request request = new Request.Builder().url(uri).get().build(); Response response = client.newCall(request).execute(); String contentTypeHeader = response.header("Content-Type"); - if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { + if ("text/plain".equals(contentTypeHeader)) { String responseContent = response.body().string(); throw new WxErrorException(WxError.fromJson(responseContent)); } From 9d2fb9fe3d7bc0733ae433e722aaa86d69142f6c Mon Sep 17 00:00:00 2001 From: DDLeEHi <569198459@qq.com> Date: Wed, 24 May 2017 10:40:32 +0800 Subject: [PATCH 028/179] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=94=AF=E4=BB=98=20=E4=B8=8B=E8=BD=BD=E5=AF=B9=E8=B4=A6?= =?UTF-8?q?=E5=8D=95=20=E7=9A=84=E6=8E=A5=E5=8F=A3=20#65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wxpay/bean/result/WxPayBillBaseResult | 257 ++++++++++++++++++ .../wxpay/bean/result/WxPayBillResult | 86 ++++++ .../wxpay/service/WxPayService.java | 2 +- .../wxpay/service/impl/WxPayServiceImpl.java | 84 +++++- .../service/impl/WxPayServiceImplTest.java | 5 +- 5 files changed, 426 insertions(+), 8 deletions(-) create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult new file mode 100644 index 0000000000..530d9a2295 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult @@ -0,0 +1,257 @@ +package com.github.binarywang.wxpay.bean.result; +import java.io.Serializable; + +public class WxPayBillBaseResult implements Serializable +{ + /* + * 交易时间:2017-04-06 01:00:02 公众账号ID: 商户号: 子商户号:0 设备号:WEB 微信订单号: 商户订单号:2017040519091071873216 用户标识: 交易类型:NATIVE + * 交易状态:REFUND 付款银行:CFT 货币种类:CNY 总金额:0.00 企业红包金额:0.00 微信退款单号: 商户退款单号:20170406010000933 退款金额:0.01 企业红包退款金额:0.00 + * 退款类型:ORIGINAL 退款状态:SUCCESS 商品名称: 商户数据包: 手续费:0.00000 费率 :0.60% + */ + private static final long serialVersionUID = 1L; + /**交易时间*/ + private String tradeTime; + /**公众账号ID*/ + private String appId; + /**商户号*/ + private String mchId; + /**子商户号*/ + private String subMchId; + /**设备号*/ + private String deviceInfo; + /**微信订单号*/ + private String transationId; + /**商户订单号*/ + private String outTradeNo; + /**用户标识*/ + private String openId; + /**交易类型*/ + private String tradeType; + /**交易状态*/ + private String tradeState ; + /**付款银行*/ + private String bankType; + /**货币种类*/ + private String feeType; + /**总金额*/ + private String totalFee; + /**企业红包金额*/ + private String couponFee; + /**微信退款单号*/ + private String refundId; + /**商户退款单号*/ + private String outRefundNo; + /**退款金额*/ + private String settlementRefundFee; + /**企业红包退款金额*/ + private String couponRefundFee; + /**退款类型*/ + private String refundChannel; + /**退款状态*/ + private String refundState; + /**商品名称*/ + private String body; + /**商户数据包*/ + private String attach; + /**手续费*/ + private String poundage; + /**费率*/ + private String poundageRate; + public String getTradeTime() + { + return tradeTime; + } + public void setTradeTime(String tradeTime) + { + this.tradeTime = tradeTime; + } + public String getAppId() + { + return appId; + } + public void setAppId(String appId) + { + this.appId = appId; + } + public String getMchId() + { + return mchId; + } + public void setMchId(String mchId) + { + this.mchId = mchId; + } + public String getSubMchId() + { + return subMchId; + } + public void setSubMchId(String subMchId) + { + this.subMchId = subMchId; + } + public String getDeviceInfo() + { + return deviceInfo; + } + public void setDeviceInfo(String deviceInfo) + { + this.deviceInfo = deviceInfo; + } + public String getTransationId() + { + return transationId; + } + public void setTransationId(String transationId) + { + this.transationId = transationId; + } + public String getOutTradeNo() + { + return outTradeNo; + } + public void setOutTradeNo(String outTradeNo) + { + this.outTradeNo = outTradeNo; + } + public String getOpenId() + { + return openId; + } + public void setOpenId(String openId) + { + this.openId = openId; + } + public String getTradeType() + { + return tradeType; + } + public void setTradeType(String tradeType) + { + this.tradeType = tradeType; + } + public String getTradeState() + { + return tradeState; + } + public void setTradeState(String tradeState) + { + this.tradeState = tradeState; + } + public String getBankType() + { + return bankType; + } + public void setBankType(String bankType) + { + this.bankType = bankType; + } + public String getFeeType() + { + return feeType; + } + public void setFeeType(String feeType) + { + this.feeType = feeType; + } + public String getTotalFee() + { + return totalFee; + } + public void setTotalFee(String totalFee) + { + this.totalFee = totalFee; + } + public String getCouponFee() + { + return couponFee; + } + public void setCouponFee(String couponFee) + { + this.couponFee = couponFee; + } + public String getRefundId() + { + return refundId; + } + public void setRefundId(String refundId) + { + this.refundId = refundId; + } + public String getOutRefundNo() + { + return outRefundNo; + } + public void setOutRefundNo(String outRefundNo) + { + this.outRefundNo = outRefundNo; + } + public String getSettlementRefundFee() + { + return settlementRefundFee; + } + public void setSettlementRefundFee(String settlementRefundFee) + { + this.settlementRefundFee = settlementRefundFee; + } + public String getCouponRefundFee() + { + return couponRefundFee; + } + public void setCouponRefundFee(String couponRefundFee) + { + this.couponRefundFee = couponRefundFee; + } + public String getRefundChannel() + { + return refundChannel; + } + public void setRefundChannel(String refundChannel) + { + this.refundChannel = refundChannel; + } + public String getRefundState() + { + return refundState; + } + public void setRefundState(String refundState) + { + this.refundState = refundState; + } + public String getBody() + { + return body; + } + public void setBody(String body) + { + this.body = body; + } + public String getAttach() + { + return attach; + } + public void setAttach(String attach) + { + this.attach = attach; + } + public String getPoundage() + { + return poundage; + } + public void setPoundage(String poundage) + { + this.poundage = poundage; + } + public String getPoundageRate() + { + return poundageRate; + } + public void setPoundageRate(String poundageRate) + { + this.poundageRate = poundageRate; + } + public static long getSerialversionuid() + { + return serialVersionUID; + } + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult new file mode 100644 index 0000000000..d7b64dccd5 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult @@ -0,0 +1,86 @@ +package com.github.binarywang.wxpay.bean.result; + +import java.util.List; + +public class WxPayBillResult implements Serializable +{ + /** + * 对账返回对象 + */ + private static final long serialVersionUID = 1L; + + private List wxPayBillBaseResultLst; + /**总交易单数*/ + private String totalRecord; + /**总交易额*/ + private String totalFee; + /**总退款金额*/ + private String totalRefundFee; + /**总代金券或立减优惠退款金额*/ + private String totalCouponFee; + /**手续费总金额 */ + private String totalPoundageFee; + + public List getWxPayBillBaseResultLst() + { + return wxPayBillBaseResultLst; + } + + public void setWxPayBillBaseResultLst(List wxPayBillBaseResultLst) + { + this.wxPayBillBaseResultLst = wxPayBillBaseResultLst; + } + + public String getTotalRecord() + { + return totalRecord; + } + + public void setTotalRecord(String totalRecord) + { + this.totalRecord = totalRecord; + } + + public String getTotalFee() + { + return totalFee; + } + + public void setTotalFee(String totalFee) + { + this.totalFee = totalFee; + } + + public String getTotalRefundFee() + { + return totalRefundFee; + } + + public void setTotalRefundFee(String totalRefundFee) + { + this.totalRefundFee = totalRefundFee; + } + + public String getTotalCouponFee() + { + return totalCouponFee; + } + + public void setTotalCouponFee(String totalCouponFee) + { + this.totalCouponFee = totalCouponFee; + } + + public String getTotalPoundageFee() + { + return totalPoundageFee; + } + + public void setTotalPoundageFee(String totalPoundageFee) + { + this.totalPoundageFee = totalPoundageFee; + } + + + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index c04d77061f..999c733e36 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -246,7 +246,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri * @param deviceInfo 设备号 device_info 非必传参数,终端设备号 * @return 保存到本地的临时文件 */ - File downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException; + WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException; /** *
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
index 90778999ac..9de0790fa2 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
@@ -299,7 +299,7 @@ public void report(WxPayReportRequest request) throws WxErrorException {
   }
 
   @Override
-  public File downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException {
+  public WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException {
     WxPayDownloadBillRequest request = new WxPayDownloadBillRequest();
     request.setBillType(billType);
     request.setBillDate(billDate);
@@ -311,11 +311,85 @@ public File downloadBill(String billDate, String billType, String tarType, Strin
     String url = this.getPayBaseUrl() + "/pay/downloadbill";
     //TODO 返回的内容可能是文件流,也有可能是xml,需要区分对待
     String responseContent = this.post(url, request.toXML());
+    if (responseContent.startsWith("<")){
+      WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class);
+      result.checkResult(this);
+      return null;
+    }else{
+      WxPayBillResult wxPayBillResult = billInformationDeal(responseContent);
+      return wxPayBillResult;
+    }
+  }
+  
+    private WxPayBillResult billInformationDeal(String responseContent){
+    WxPayBillResult wxPayBillResult = new WxPayBillResult();
+
+    String listStr = "";
+    String objStr = "";
+    if (responseContent.indexOf("总交易单数") >= 0){
+      listStr = responseContent.substring(0, responseContent.indexOf("总交易单数"));
+      objStr = responseContent.substring(responseContent.indexOf("总交易单数"));
+    }
 
-    WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class);
-    result.checkResult(this);
-    //TODO 待实现,暂时无测试帐号,无法调试
-    return null;
+    /*
+     * 交易时间:2017-04-06 01:00:02 公众账号ID: 商户号: 子商户号:0 设备号:WEB 微信订单号: 商户订单号:2017040519091071873216 用户标识: 交易类型:NATIVE
+     * 交易状态:REFUND 付款银行:CFT 货币种类:CNY 总金额:0.00 企业红包金额:0.00 微信退款单号: 商户退款单号:20170406010000933 退款金额:0.01 企业红包退款金额:0.00
+     * 退款类型:ORIGINAL 退款状态:SUCCESS 商品名称: 商户数据包: 手续费:0.00000 费率 :0.60%
+     */
+
+    // 参考以上格式进行取值
+
+    List wxPayBillBaseResultLst = new LinkedList();
+    String newStr = listStr.replaceAll(",", " "); // 去空格
+    String[] tempStr = newStr.split("`"); // 数据分组
+    String[] t = tempStr[0].split(" ");// 分组标题
+    int j = tempStr.length / t.length; // 计算循环次数
+    int k = 1; // 纪录数组下标
+    for (int i = 0; i < j; i++){
+      WxPayBillBaseResult wxPayBillBaseResult = new WxPayBillBaseResult();
+
+      wxPayBillBaseResult.setTradeTime(tempStr[k]);
+      wxPayBillBaseResult.setAppId(tempStr[k + 1]);
+      wxPayBillBaseResult.setMchId(tempStr[k + 2]);
+      wxPayBillBaseResult.setSubMchId(tempStr[k + 3]);
+      wxPayBillBaseResult.setDeviceInfo(tempStr[k + 4]);
+      wxPayBillBaseResult.setTransationId(tempStr[k + 5]);
+      wxPayBillBaseResult.setOutTradeNo(tempStr[k + 6]);
+      wxPayBillBaseResult.setOpenId(tempStr[k + 7]);
+      wxPayBillBaseResult.setTradeType(tempStr[k + 8]);
+      wxPayBillBaseResult.setTradeState(tempStr[k + 9]);
+      wxPayBillBaseResult.setBankType(tempStr[k + 10]);
+      wxPayBillBaseResult.setFeeType(tempStr[k + 11]);
+      wxPayBillBaseResult.setTotalFee(tempStr[k + 12]);
+      wxPayBillBaseResult.setCouponFee(tempStr[k + 13]);
+      wxPayBillBaseResult.setRefundId(tempStr[k + 14]);
+      wxPayBillBaseResult.setOutRefundNo(tempStr[k + 15]);
+      wxPayBillBaseResult.setSettlementRefundFee(tempStr[k + 16]);
+      wxPayBillBaseResult.setCouponRefundFee(tempStr[k + 17]);
+      wxPayBillBaseResult.setRefundChannel(tempStr[k + 18]);
+      wxPayBillBaseResult.setRefundState(tempStr[k + 19]);
+      wxPayBillBaseResult.setBody(tempStr[k + 20]);
+      wxPayBillBaseResult.setAttach(tempStr[k + 21]);
+      wxPayBillBaseResult.setPoundage(tempStr[k + 22]);
+      wxPayBillBaseResult.setPoundageRate(tempStr[k + 23]);
+      wxPayBillBaseResultLst.add(wxPayBillBaseResult);
+      k += t.length;
+    }
+    /*
+     * 总交易单数,总交易额,总退款金额,总代金券或立减优惠退款金额,手续费总金额 `2,`0.02,`0.0,`0.0,`0
+     */
+
+    // 参考以上格式进行取值
+
+    String totalStr = objStr.replaceAll(",", " ");
+    String[] totalTempStr = totalStr.split("`");
+    wxPayBillResult.setTotalRecord(totalTempStr[1]);
+    wxPayBillResult.setTotalFee(totalTempStr[2]);
+    wxPayBillResult.setTotalRefundFee(totalTempStr[3]);
+    wxPayBillResult.setTotalCouponFee(totalTempStr[4]);
+    wxPayBillResult.setTotalPoundageFee(totalTempStr[5]);
+    
+    return wxPayBillResult;
   }
 
   @Override
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java
index 1ca8d2e6ff..685337c768 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java
@@ -49,8 +49,9 @@ public void testGetPayInfo() throws Exception {
 
   @Test
   public void testDownloadBill() throws Exception {
-    File file = this.payService.downloadBill("20170101", "ALL", "GZIP", "1111111");
-    assertNotNull(file);
+    WxPayBillResult wxPayBillResult = this.payService.downloadBill("20170101", "ALL", "GZIP", "1111111");
+    //前一天没有账单记录返回null
+    assertNotNull(wxPayBillResult);
     //必填字段为空时,抛出异常
     this.payService.downloadBill("", "", "", null);
   }

From d108366736ac0c4be9544d1149c57e9279231d16 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Wed, 24 May 2017 10:46:04 +0800
Subject: [PATCH 029/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../wxpay/bean/result/WxPayBillBaseResult     | 257 ---------------
 .../bean/result/WxPayBillBaseResult.java      | 305 ++++++++++++++++++
 .../{WxPayBillResult => WxPayBillResult.java} |  65 ++--
 3 files changed, 336 insertions(+), 291 deletions(-)
 delete mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java
 rename weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/{WxPayBillResult => WxPayBillResult.java} (52%)

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult
deleted file mode 100644
index 530d9a2295..0000000000
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult
+++ /dev/null
@@ -1,257 +0,0 @@
-package com.github.binarywang.wxpay.bean.result;
-import java.io.Serializable;
-
-public class WxPayBillBaseResult implements Serializable
-{
-    /*
-     * 交易时间:2017-04-06 01:00:02 公众账号ID: 商户号: 子商户号:0 设备号:WEB 微信订单号: 商户订单号:2017040519091071873216 用户标识: 交易类型:NATIVE
-     * 交易状态:REFUND 付款银行:CFT 货币种类:CNY 总金额:0.00 企业红包金额:0.00 微信退款单号: 商户退款单号:20170406010000933 退款金额:0.01 企业红包退款金额:0.00
-     * 退款类型:ORIGINAL 退款状态:SUCCESS 商品名称: 商户数据包: 手续费:0.00000 费率 :0.60%
-     */
-  private static final long serialVersionUID = 1L;
-  /**交易时间*/
-  private String tradeTime;
-  /**公众账号ID*/
-  private String appId;
-  /**商户号*/
-  private String mchId;
-  /**子商户号*/
-  private String subMchId;
-  /**设备号*/
-  private String deviceInfo;
-  /**微信订单号*/
-  private String transationId;
-  /**商户订单号*/
-  private String outTradeNo;
-  /**用户标识*/
-  private String openId;
-  /**交易类型*/
-  private String tradeType;
-  /**交易状态*/
-  private String tradeState ;
-  /**付款银行*/
-  private String bankType;
-  /**货币种类*/
-  private String feeType;
-  /**总金额*/
-  private String totalFee;
-  /**企业红包金额*/
-  private String couponFee;
-  /**微信退款单号*/
-  private String refundId;
-  /**商户退款单号*/
-  private String outRefundNo;
-  /**退款金额*/
-  private String settlementRefundFee;
-  /**企业红包退款金额*/
-  private String couponRefundFee;
-  /**退款类型*/
-  private String refundChannel;
-  /**退款状态*/
-  private String refundState;
-  /**商品名称*/
-  private String body;
-  /**商户数据包*/
-  private String attach;
-  /**手续费*/
-  private String poundage;
-  /**费率*/
-  private String poundageRate;
-  public String getTradeTime()
-  {
-    return tradeTime;
-  }
-  public void setTradeTime(String tradeTime)
-  {
-    this.tradeTime = tradeTime;
-  }
-  public String getAppId()
-  {
-    return appId;
-  }
-  public void setAppId(String appId)
-  {
-    this.appId = appId;
-  }
-  public String getMchId()
-  {
-    return mchId;
-  }
-  public void setMchId(String mchId)
-  {
-    this.mchId = mchId;
-  }
-  public String getSubMchId()
-  {
-    return subMchId;
-  }
-  public void setSubMchId(String subMchId)
-  {
-    this.subMchId = subMchId;
-  }
-  public String getDeviceInfo()
-  {
-    return deviceInfo;
-  }
-  public void setDeviceInfo(String deviceInfo)
-  {
-    this.deviceInfo = deviceInfo;
-  }
-  public String getTransationId()
-  {
-    return transationId;
-  }
-  public void setTransationId(String transationId)
-  {
-    this.transationId = transationId;
-  }
-  public String getOutTradeNo()
-  {
-    return outTradeNo;
-  }
-  public void setOutTradeNo(String outTradeNo)
-  {
-    this.outTradeNo = outTradeNo;
-  }
-  public String getOpenId()
-  {
-    return openId;
-  }
-  public void setOpenId(String openId)
-  {
-    this.openId = openId;
-  }
-  public String getTradeType()
-  {
-    return tradeType;
-  }
-  public void setTradeType(String tradeType)
-  {
-    this.tradeType = tradeType;
-  }
-  public String getTradeState()
-  {
-    return tradeState;
-  }
-  public void setTradeState(String tradeState)
-  {
-    this.tradeState = tradeState;
-  }
-  public String getBankType()
-  {
-    return bankType;
-  }
-  public void setBankType(String bankType)
-  {
-    this.bankType = bankType;
-  }
-  public String getFeeType()
-  {
-    return feeType;
-  }
-  public void setFeeType(String feeType)
-  {
-    this.feeType = feeType;
-  }
-  public String getTotalFee()
-  {
-    return totalFee;
-  }
-  public void setTotalFee(String totalFee)
-  {
-    this.totalFee = totalFee;
-  }
-  public String getCouponFee()
-  {
-    return couponFee;
-  }
-  public void setCouponFee(String couponFee)
-  {
-    this.couponFee = couponFee;
-  }
-  public String getRefundId()
-  {
-    return refundId;
-  }
-  public void setRefundId(String refundId)
-  {
-    this.refundId = refundId;
-  }
-  public String getOutRefundNo()
-  {
-    return outRefundNo;
-  }
-  public void setOutRefundNo(String outRefundNo)
-  {
-    this.outRefundNo = outRefundNo;
-  }
-  public String getSettlementRefundFee()
-  {
-    return settlementRefundFee;
-  }
-  public void setSettlementRefundFee(String settlementRefundFee)
-  {
-    this.settlementRefundFee = settlementRefundFee;
-  }
-  public String getCouponRefundFee()
-  {
-    return couponRefundFee;
-  }
-  public void setCouponRefundFee(String couponRefundFee)
-  {
-    this.couponRefundFee = couponRefundFee;
-  }
-  public String getRefundChannel()
-  {
-    return refundChannel;
-  }
-  public void setRefundChannel(String refundChannel)
-  {
-    this.refundChannel = refundChannel;
-  }
-  public String getRefundState()
-  {
-    return refundState;
-  }
-  public void setRefundState(String refundState)
-  {
-    this.refundState = refundState;
-  }
-  public String getBody()
-  {
-    return body;
-  }
-  public void setBody(String body)
-  {
-    this.body = body;
-  }
-  public String getAttach()
-  {
-    return attach;
-  }
-  public void setAttach(String attach)
-  {
-    this.attach = attach;
-  }
-  public String getPoundage()
-  {
-    return poundage;
-  }
-  public void setPoundage(String poundage)
-  {
-    this.poundage = poundage;
-  }
-  public String getPoundageRate()
-  {
-    return poundageRate;
-  }
-  public void setPoundageRate(String poundageRate)
-  {
-    this.poundageRate = poundageRate;
-  }
-  public static long getSerialversionuid()
-  {
-    return serialVersionUID;
-  }
-  
-}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java
new file mode 100644
index 0000000000..e469ff4538
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java
@@ -0,0 +1,305 @@
+package com.github.binarywang.wxpay.bean.result;
+
+import java.io.Serializable;
+
+public class WxPayBillBaseResult implements Serializable {
+  /*
+   * 交易时间:2017-04-06 01:00:02 公众账号ID: 商户号: 子商户号:0 设备号:WEB 微信订单号: 商户订单号:2017040519091071873216 用户标识: 交易类型:NATIVE
+   * 交易状态:REFUND 付款银行:CFT 货币种类:CNY 总金额:0.00 企业红包金额:0.00 微信退款单号: 商户退款单号:20170406010000933 退款金额:0.01 企业红包退款金额:0.00
+   * 退款类型:ORIGINAL 退款状态:SUCCESS 商品名称: 商户数据包: 手续费:0.00000 费率 :0.60%
+   */
+  private static final long serialVersionUID = 1L;
+  /**
+   * 交易时间
+   */
+  private String tradeTime;
+  /**
+   * 公众账号ID
+   */
+  private String appId;
+  /**
+   * 商户号
+   */
+  private String mchId;
+  /**
+   * 子商户号
+   */
+  private String subMchId;
+  /**
+   * 设备号
+   */
+  private String deviceInfo;
+  /**
+   * 微信订单号
+   */
+  private String transationId;
+  /**
+   * 商户订单号
+   */
+  private String outTradeNo;
+  /**
+   * 用户标识
+   */
+  private String openId;
+  /**
+   * 交易类型
+   */
+  private String tradeType;
+  /**
+   * 交易状态
+   */
+  private String tradeState;
+  /**
+   * 付款银行
+   */
+  private String bankType;
+  /**
+   * 货币种类
+   */
+  private String feeType;
+  /**
+   * 总金额
+   */
+  private String totalFee;
+  /**
+   * 企业红包金额
+   */
+  private String couponFee;
+  /**
+   * 微信退款单号
+   */
+  private String refundId;
+  /**
+   * 商户退款单号
+   */
+  private String outRefundNo;
+  /**
+   * 退款金额
+   */
+  private String settlementRefundFee;
+  /**
+   * 企业红包退款金额
+   */
+  private String couponRefundFee;
+  /**
+   * 退款类型
+   */
+  private String refundChannel;
+  /**
+   * 退款状态
+   */
+  private String refundState;
+  /**
+   * 商品名称
+   */
+  private String body;
+  /**
+   * 商户数据包
+   */
+  private String attach;
+  /**
+   * 手续费
+   */
+  private String poundage;
+  /**
+   * 费率
+   */
+  private String poundageRate;
+
+  public static long getSerialversionuid() {
+    return serialVersionUID;
+  }
+
+  public String getTradeTime() {
+    return tradeTime;
+  }
+
+  public void setTradeTime(String tradeTime) {
+    this.tradeTime = tradeTime;
+  }
+
+  public String getAppId() {
+    return appId;
+  }
+
+  public void setAppId(String appId) {
+    this.appId = appId;
+  }
+
+  public String getMchId() {
+    return mchId;
+  }
+
+  public void setMchId(String mchId) {
+    this.mchId = mchId;
+  }
+
+  public String getSubMchId() {
+    return subMchId;
+  }
+
+  public void setSubMchId(String subMchId) {
+    this.subMchId = subMchId;
+  }
+
+  public String getDeviceInfo() {
+    return deviceInfo;
+  }
+
+  public void setDeviceInfo(String deviceInfo) {
+    this.deviceInfo = deviceInfo;
+  }
+
+  public String getTransationId() {
+    return transationId;
+  }
+
+  public void setTransationId(String transationId) {
+    this.transationId = transationId;
+  }
+
+  public String getOutTradeNo() {
+    return outTradeNo;
+  }
+
+  public void setOutTradeNo(String outTradeNo) {
+    this.outTradeNo = outTradeNo;
+  }
+
+  public String getOpenId() {
+    return openId;
+  }
+
+  public void setOpenId(String openId) {
+    this.openId = openId;
+  }
+
+  public String getTradeType() {
+    return tradeType;
+  }
+
+  public void setTradeType(String tradeType) {
+    this.tradeType = tradeType;
+  }
+
+  public String getTradeState() {
+    return tradeState;
+  }
+
+  public void setTradeState(String tradeState) {
+    this.tradeState = tradeState;
+  }
+
+  public String getBankType() {
+    return bankType;
+  }
+
+  public void setBankType(String bankType) {
+    this.bankType = bankType;
+  }
+
+  public String getFeeType() {
+    return feeType;
+  }
+
+  public void setFeeType(String feeType) {
+    this.feeType = feeType;
+  }
+
+  public String getTotalFee() {
+    return totalFee;
+  }
+
+  public void setTotalFee(String totalFee) {
+    this.totalFee = totalFee;
+  }
+
+  public String getCouponFee() {
+    return couponFee;
+  }
+
+  public void setCouponFee(String couponFee) {
+    this.couponFee = couponFee;
+  }
+
+  public String getRefundId() {
+    return refundId;
+  }
+
+  public void setRefundId(String refundId) {
+    this.refundId = refundId;
+  }
+
+  public String getOutRefundNo() {
+    return outRefundNo;
+  }
+
+  public void setOutRefundNo(String outRefundNo) {
+    this.outRefundNo = outRefundNo;
+  }
+
+  public String getSettlementRefundFee() {
+    return settlementRefundFee;
+  }
+
+  public void setSettlementRefundFee(String settlementRefundFee) {
+    this.settlementRefundFee = settlementRefundFee;
+  }
+
+  public String getCouponRefundFee() {
+    return couponRefundFee;
+  }
+
+  public void setCouponRefundFee(String couponRefundFee) {
+    this.couponRefundFee = couponRefundFee;
+  }
+
+  public String getRefundChannel() {
+    return refundChannel;
+  }
+
+  public void setRefundChannel(String refundChannel) {
+    this.refundChannel = refundChannel;
+  }
+
+  public String getRefundState() {
+    return refundState;
+  }
+
+  public void setRefundState(String refundState) {
+    this.refundState = refundState;
+  }
+
+  public String getBody() {
+    return body;
+  }
+
+  public void setBody(String body) {
+    this.body = body;
+  }
+
+  public String getAttach() {
+    return attach;
+  }
+
+  public void setAttach(String attach) {
+    this.attach = attach;
+  }
+
+  public String getPoundage() {
+    return poundage;
+  }
+
+  public void setPoundage(String poundage) {
+    this.poundage = poundage;
+  }
+
+  public String getPoundageRate() {
+    return poundageRate;
+  }
+
+  public void setPoundageRate(String poundageRate) {
+    this.poundageRate = poundageRate;
+  }
+
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult.java
similarity index 52%
rename from weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult
rename to weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult.java
index d7b64dccd5..a7fb25bef2 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult.java
@@ -1,86 +1,83 @@
 package com.github.binarywang.wxpay.bean.result;
 
+import java.io.Serializable;
 import java.util.List;
 
-public class WxPayBillResult implements Serializable
-{
+public class WxPayBillResult implements Serializable {
   /**
    * 对账返回对象
    */
   private static final long serialVersionUID = 1L;
-  
+
   private List wxPayBillBaseResultLst;
-  /**总交易单数*/
+  /**
+   * 总交易单数
+   */
   private String totalRecord;
-  /**总交易额*/
+  /**
+   * 总交易额
+   */
   private String totalFee;
-  /**总退款金额*/
+  /**
+   * 总退款金额
+   */
   private String totalRefundFee;
-  /**总代金券或立减优惠退款金额*/
+  /**
+   * 总代金券或立减优惠退款金额
+   */
   private String totalCouponFee;
-  /**手续费总金额 */
+  /**
+   * 手续费总金额
+   */
   private String totalPoundageFee;
 
-  public List getWxPayBillBaseResultLst()
-  {
+  public List getWxPayBillBaseResultLst() {
     return wxPayBillBaseResultLst;
   }
 
-  public void setWxPayBillBaseResultLst(List wxPayBillBaseResultLst)
-  {
+  public void setWxPayBillBaseResultLst(List wxPayBillBaseResultLst) {
     this.wxPayBillBaseResultLst = wxPayBillBaseResultLst;
   }
 
-  public String getTotalRecord()
-  {
+  public String getTotalRecord() {
     return totalRecord;
   }
 
-  public void setTotalRecord(String totalRecord)
-  {
+  public void setTotalRecord(String totalRecord) {
     this.totalRecord = totalRecord;
   }
 
-  public String getTotalFee()
-  {
+  public String getTotalFee() {
     return totalFee;
   }
 
-  public void setTotalFee(String totalFee)
-  {
+  public void setTotalFee(String totalFee) {
     this.totalFee = totalFee;
   }
 
-  public String getTotalRefundFee()
-  {
+  public String getTotalRefundFee() {
     return totalRefundFee;
   }
 
-  public void setTotalRefundFee(String totalRefundFee)
-  {
+  public void setTotalRefundFee(String totalRefundFee) {
     this.totalRefundFee = totalRefundFee;
   }
 
-  public String getTotalCouponFee()
-  {
+  public String getTotalCouponFee() {
     return totalCouponFee;
   }
 
-  public void setTotalCouponFee(String totalCouponFee)
-  {
+  public void setTotalCouponFee(String totalCouponFee) {
     this.totalCouponFee = totalCouponFee;
   }
 
-  public String getTotalPoundageFee()
-  {
+  public String getTotalPoundageFee() {
     return totalPoundageFee;
   }
 
-  public void setTotalPoundageFee(String totalPoundageFee)
-  {
+  public void setTotalPoundageFee(String totalPoundageFee) {
     this.totalPoundageFee = totalPoundageFee;
   }
-  
-  
+
 
 }

From 3661018f4e44ec087a8623a54d9435ab84fe134c Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Wed, 24 May 2017 10:49:50 +0800
Subject: [PATCH 030/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../binarywang/wxpay/service/impl/WxPayServiceImpl.java     | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
index 9de0790fa2..e7c73fa621 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
@@ -21,6 +21,8 @@
 import java.io.File;
 import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -320,7 +322,7 @@ public WxPayBillResult downloadBill(String billDate, String billType, String tar
       return wxPayBillResult;
     }
   }
-  
+
     private WxPayBillResult billInformationDeal(String responseContent){
     WxPayBillResult wxPayBillResult = new WxPayBillResult();
 
@@ -388,7 +390,7 @@ private WxPayBillResult billInformationDeal(String responseContent){
     wxPayBillResult.setTotalRefundFee(totalTempStr[3]);
     wxPayBillResult.setTotalCouponFee(totalTempStr[4]);
     wxPayBillResult.setTotalPoundageFee(totalTempStr[5]);
-    
+
     return wxPayBillResult;
   }
 

From 655b2c3201cc945425495349e2f54de72087f998 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Fri, 26 May 2017 14:30:16 +0800
Subject: [PATCH 031/179] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E4=BB=A3?=
 =?UTF-8?q?=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../wxpay/service/impl/WxPayServiceImpl.java        | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
index e7c73fa621..cb49928502 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
@@ -311,24 +311,23 @@ public WxPayBillResult downloadBill(String billDate, String billType, String tar
     request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/pay/downloadbill";
-    //TODO 返回的内容可能是文件流,也有可能是xml,需要区分对待
     String responseContent = this.post(url, request.toXML());
-    if (responseContent.startsWith("<")){
+    if (responseContent.startsWith("<")) {
       WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class);
       result.checkResult(this);
       return null;
-    }else{
+    } else {
       WxPayBillResult wxPayBillResult = billInformationDeal(responseContent);
       return wxPayBillResult;
     }
   }
 
-    private WxPayBillResult billInformationDeal(String responseContent){
+  private WxPayBillResult billInformationDeal(String responseContent) {
     WxPayBillResult wxPayBillResult = new WxPayBillResult();
 
     String listStr = "";
     String objStr = "";
-    if (responseContent.indexOf("总交易单数") >= 0){
+    if (responseContent.contains("总交易单数")) {
       listStr = responseContent.substring(0, responseContent.indexOf("总交易单数"));
       objStr = responseContent.substring(responseContent.indexOf("总交易单数"));
     }
@@ -341,13 +340,13 @@ private WxPayBillResult billInformationDeal(String responseContent){
 
     // 参考以上格式进行取值
 
-    List wxPayBillBaseResultLst = new LinkedList();
+    List wxPayBillBaseResultLst = new LinkedList<>();
     String newStr = listStr.replaceAll(",", " "); // 去空格
     String[] tempStr = newStr.split("`"); // 数据分组
     String[] t = tempStr[0].split(" ");// 分组标题
     int j = tempStr.length / t.length; // 计算循环次数
     int k = 1; // 纪录数组下标
-    for (int i = 0; i < j; i++){
+    for (int i = 0; i < j; i++) {
       WxPayBillBaseResult wxPayBillBaseResult = new WxPayBillBaseResult();
 
       wxPayBillBaseResult.setTradeTime(tempStr[k]);

From d961047c24a7b8733bdb0d3ac27b2fee1abfb8cc Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sat, 27 May 2017 10:12:27 +0800
Subject: [PATCH 032/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BC=81=E4=B8=9A?=
 =?UTF-8?q?=E5=8F=B7=E8=8F=9C=E5=8D=95=E5=88=9B=E5=BB=BA=E6=8E=A5=E5=8F=A3?=
 =?UTF-8?q?=E6=96=B9=E6=B3=95=E7=9A=84bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java
index 85065a7138..52cbc0062b 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java
@@ -143,7 +143,7 @@ public void menuCreate(WxMenu menu) throws WxErrorException {
   @Override
   public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException {
     String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid="
-      + this.configStorage.getAgentId();
+      + agentId;
     post(url, menu.toJson());
   }
 

From c0172785a747ea26262a6c31eca3d6f5f56141ca Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sat, 27 May 2017 10:21:58 +0800
Subject: [PATCH 033/179] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=BB=98=E8=AE=A4?=
 =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=AE=9E=E7=8E=B0=E7=B1=BB=EF=BC=8C=E5=85=BC?=
 =?UTF-8?q?=E5=AE=B9=E4=B9=8B=E5=89=8D=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../chanjar/weixin/cp/api/impl/WxCpServiceImpl.java   | 11 +++++++++++
 .../chanjar/weixin/mp/api/impl/WxMpServiceImpl.java   | 11 +++++++++++
 2 files changed, 22 insertions(+)
 create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
 create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
new file mode 100644
index 0000000000..f37e5396dc
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
@@ -0,0 +1,11 @@
+package me.chanjar.weixin.cp.api.impl;
+
+/**
+ * 
+ *  默认接口实现类,使用apache httpclient实现
+ * Created by Binary Wang on 2017-5-27.
+ * @author binarywang(Binary Wang)
+ * 
+ */ +public class WxCpServiceImpl extends me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl{ +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java new file mode 100644 index 0000000000..4482f66467 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java @@ -0,0 +1,11 @@ +package me.chanjar.weixin.mp.api.impl; + +/** + *
+ * 默认接口实现类,使用apache httpclient实现
+ * Created by Binary Wang on 2017-5-27.
+ * @author binarywang(Binary Wang)
+ * 
+ */ +public class WxMpServiceImpl extends me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl{ +} From 7f08a9ef466b2a8b03cba19b52a81957677da368 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 27 May 2017 11:29:20 +0800 Subject: [PATCH 034/179] =?UTF-8?q?=E4=BC=98=E5=8C=96pom=EF=BC=8C=E5=B0=BD?= =?UTF-8?q?=E9=87=8F=E5=87=8F=E5=B0=91=E4=B8=8D=E5=BF=85=E8=A6=81=E7=9A=84?= =?UTF-8?q?=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 159 +++++++++++++++++++------------------ weixin-java-common/pom.xml | 61 ++++++++++++-- weixin-java-cp/pom.xml | 11 +++ weixin-java-mp/pom.xml | 13 ++- weixin-java-pay/pom.xml | 6 +- 5 files changed, 164 insertions(+), 86 deletions(-) diff --git a/pom.xml b/pom.xml index 5fc6455948..34b2db51e3 100644 --- a/pom.xml +++ b/pom.xml @@ -103,86 +103,90 @@ UTF-8 true true - 4.5 - 1.7.10 - 1.1.2 - 2.7 - 19.0 - 3.5 - 2.5 - 1.10 + 4.5.3 9.3.0.RC0 - 2.9.0 - - 3.7 - - - org.jodd - jodd-http - ${jodd-http.version} - - - com.squareup.okhttp3 - okhttp - 3.7.0 - - - org.slf4j - slf4j-api - ${slf4j.version} - - - com.thoughtworks.xstream - xstream - 1.4.9 - - - ch.qos.logback - logback-classic - ${logback.version} - test - - - org.apache.httpcomponents - httpclient - ${httpclient.version} - - - org.apache.httpcomponents - httpmime - ${httpclient.version} - - - com.google.code.gson - gson - ${gson.version} - - - commons-codec - commons-codec - ${commons-codec.version} - - - commons-io - commons-io - ${commons-io.version} - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - - com.google.guava - guava - ${guava.version} - - - + + com.github.binarywang + qrcode-utils + 1.1 + + + + org.jodd + jodd-http + 3.7.1 + provided + + + com.squareup.okhttp3 + okhttp + 3.7.0 + provided + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + org.apache.httpcomponents + httpmime + ${httpclient.version} + + + commons-codec + commons-codec + 1.10 + + + commons-io + commons-io + 2.5 + + + org.apache.commons + commons-lang3 + 3.5 + + + org.slf4j + slf4j-api + 1.7.24 + + + com.thoughtworks.xstream + xstream + 1.4.9 + + + com.google.guava + guava + 22.0 + + + com.google.code.gson + gson + 2.8.0 + + + + + joda-time + joda-time + 2.9.7 + test + + + ch.qos.logback + logback-classic + 1.1.11 + test + com.google.inject guice @@ -192,7 +196,7 @@ org.testng testng - 6.8.7 + 6.10 test @@ -216,7 +220,8 @@ redis.clients jedis - ${jedis.version} + 3.0 + provided diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index a0d5683f94..5414f8bc3d 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -1,7 +1,8 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0"> 4.0.0 com.github.binarywang @@ -14,6 +15,59 @@ 微信公众号、企业号Java SDK Common + + org.jodd + jodd-http + provided + + + com.squareup.okhttp3 + okhttp + provided + + + + org.slf4j + slf4j-api + + + com.thoughtworks.xstream + xstream + + + org.apache.httpcomponents + httpclient + + + org.apache.httpcomponents + httpmime + + + com.google.code.gson + gson + + + commons-codec + commons-codec + + + commons-io + commons-io + + + org.apache.commons + commons-lang3 + + + com.google.guava + guava + + + + ch.qos.logback + logback-classic + test + org.testng testng @@ -39,11 +93,6 @@ jetty-servlet test - - org.jodd - jodd-http - 3.7 - diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 68ad828313..3bbc65b7fa 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -20,10 +20,21 @@ weixin-java-common ${project.version} + + org.jodd + jodd-http + provided + + + com.squareup.okhttp3 + okhttp + provided + redis.clients jedis + org.testng testng diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 1b97c00853..570abca132 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -19,6 +19,18 @@ weixin-java-common ${project.version} + + + org.jodd + jodd-http + provided + + + com.squareup.okhttp3 + okhttp + provided + + org.testng testng @@ -42,7 +54,6 @@ joda-time joda-time - 2.9.4 test diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 989fd9fac3..11c6000510 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -22,9 +22,11 @@ com.github.binarywang qrcode-utils - 1.1 - + + org.jodd + jodd-http + org.testng testng From 4f41aa7b37a1c3c74849b716307a56f1f185b08c Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 27 May 2017 11:43:58 +0800 Subject: [PATCH 035/179] =?UTF-8?q?=E8=B0=83=E6=95=B4=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E7=89=88=E6=9C=AC=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 34b2db51e3..3740221c74 100644 --- a/pom.xml +++ b/pom.xml @@ -103,7 +103,7 @@ UTF-8 true true - 4.5.3 + 4.5 9.3.0.RC0 @@ -163,10 +163,11 @@ xstream 1.4.9 + com.google.guava guava - 22.0 + 20.0 com.google.code.gson From a96e6f35b0ff6e19c343b191b169bb15426afc88 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 27 May 2017 11:46:23 +0800 Subject: [PATCH 036/179] =?UTF-8?q?=E8=B0=83=E6=95=B4=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E7=89=88=E6=9C=AC=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3740221c74..5343df8c68 100644 --- a/pom.xml +++ b/pom.xml @@ -221,7 +221,7 @@ redis.clients jedis - 3.0 + 2.9.0 provided From 46d94db6dabb1f65da77916943c07adaaf95bf02 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 27 May 2017 11:54:35 +0800 Subject: [PATCH 037/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81=E4=B8=AD=E5=AF=B9junit?= =?UTF-8?q?=E7=9A=84=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/impl/WxMpMaterialServiceImplTest.java | 4 +++- .../chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java index 6bb1e58bff..b175114af1 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java @@ -16,7 +16,9 @@ import java.io.InputStream; import java.util.*; -import static org.junit.Assert.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; /** * 素材管理相关接口的测试 diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java index baa34443f2..ed5845088b 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java @@ -12,7 +12,7 @@ import java.math.BigDecimal; import java.util.List; -import static org.junit.Assert.assertNotNull; +import static org.testng.AssertJUnit.assertNotNull; /** * @author binarywang(Binary Wang) From 8d5b41ced0c316922adb4f6e1c04d6980ffe03f4 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 13:40:35 +0800 Subject: [PATCH 038/179] refactor code --- .../WxMessageInMemoryDuplicateCheckerTest.java | 18 ++++++++++-------- .../src/test/resources/testng.xml | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) rename weixin-java-common/src/test/java/me/chanjar/weixin/common/{util => api}/WxMessageInMemoryDuplicateCheckerTest.java (62%) diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateCheckerTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateCheckerTest.java similarity index 62% rename from weixin-java-common/src/test/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateCheckerTest.java rename to weixin-java-common/src/test/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateCheckerTest.java index c149584223..8599b29f89 100644 --- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateCheckerTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateCheckerTest.java @@ -1,34 +1,36 @@ -package me.chanjar.weixin.common.util; +package me.chanjar.weixin.common.api; -import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; -import org.testng.*; -import org.testng.annotations.*; +import org.testng.Assert; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; @Test public class WxMessageInMemoryDuplicateCheckerTest { + private WxMessageInMemoryDuplicateChecker checker = new WxMessageInMemoryDuplicateChecker(2000l, 1000l); public void test() throws InterruptedException { Long[] msgIds = new Long[]{1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l}; - WxMessageInMemoryDuplicateChecker checker = new WxMessageInMemoryDuplicateChecker(2000l, 1000l); // 第一次检查 for (Long msgId : msgIds) { boolean result = checker.isDuplicate(String.valueOf(msgId)); - Assert.assertFalse(result); + assertFalse(result); } // 过1秒再检查 Thread.sleep(1000l); for (Long msgId : msgIds) { boolean result = checker.isDuplicate(String.valueOf(msgId)); - Assert.assertTrue(result); + assertTrue(result); } // 过1.5秒再检查 Thread.sleep(1500l); for (Long msgId : msgIds) { boolean result = checker.isDuplicate(String.valueOf(msgId)); - Assert.assertFalse(result); + assertFalse(result); } } diff --git a/weixin-java-common/src/test/resources/testng.xml b/weixin-java-common/src/test/resources/testng.xml index 793ba0a650..9eeba0df4c 100644 --- a/weixin-java-common/src/test/resources/testng.xml +++ b/weixin-java-common/src/test/resources/testng.xml @@ -7,7 +7,7 @@ - + From ae8b2effb92f7c4bbf0f6e1300dd97c5adb4021e Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 13:43:22 +0800 Subject: [PATCH 039/179] refactor code --- .../weixin/mp/api/WxMpMessageRouter.java | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java index 958c302676..bdf1d6a3d3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java @@ -77,8 +77,6 @@ public WxMpMessageRouter(WxMpService wxMpService) { * 设置自定义的 {@link ExecutorService} * 如果不调用该方法,默认使用 Executors.newFixedThreadPool(100) *
- * - * @param executorService */ public void setExecutorService(ExecutorService executorService) { this.executorService = executorService; @@ -89,8 +87,6 @@ public void setExecutorService(ExecutorService executorService) { * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker} * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker} *
- * - * @param messageDuplicateChecker */ public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { this.messageDuplicateChecker = messageDuplicateChecker; @@ -101,8 +97,6 @@ public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicat * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager} * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager} * - * - * @param sessionManager */ public void setSessionManager(WxSessionManager sessionManager) { this.sessionManager = sessionManager; @@ -113,8 +107,6 @@ public void setSessionManager(WxSessionManager sessionManager) { * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler} * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler} * - * - * @param exceptionHandler */ public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { this.exceptionHandler = exceptionHandler; @@ -133,11 +125,9 @@ public WxMpMessageRouterRule rule() { /** * 处理微信消息 - * - * @param wxMessage */ public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) { - if (isDuplicateMessage(wxMessage)) { + if (isMsgDuplicated(wxMessage)) { // 如果是重复消息,那么就不做处理 return null; } @@ -188,9 +178,7 @@ public void run() { WxMpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUser()); // 异步操作结束,session访问结束 sessionEndAccess(wxMessage); - } catch (InterruptedException e) { - WxMpMessageRouter.this.log.error("Error happened when wait task finish", e); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { WxMpMessageRouter.this.log.error("Error happened when wait task finish", e); } } @@ -200,9 +188,9 @@ public void run() { return res; } - protected boolean isDuplicateMessage(WxMpXmlMessage wxMessage) { + protected boolean isMsgDuplicated(WxMpXmlMessage wxMessage) { - StringBuffer messageId = new StringBuffer(); + StringBuilder messageId = new StringBuilder(); if (wxMessage.getMsgId() == null) { messageId.append(wxMessage.getCreateTime()) .append("-").append(wxMessage.getFromUser()) @@ -219,8 +207,6 @@ protected boolean isDuplicateMessage(WxMpXmlMessage wxMessage) { /** * 对session的访问结束 - * - * @param wxMessage */ protected void sessionEndAccess(WxMpXmlMessage wxMessage) { From 0ba2684f47f948196a3469368317ca9964034076 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 14:03:06 +0800 Subject: [PATCH 040/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8DWxMpInRedisConfigStor?= =?UTF-8?q?age=E5=9C=A8=E6=9E=81=E7=AB=AF=E6=83=85=E5=86=B5=E4=B8=8B?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=20#229?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java index 706d59ecd1..d22214dfa1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java @@ -25,7 +25,7 @@ public String getAccessToken() { @Override public boolean isAccessTokenExpired() { - return getAccessToken() == null ? true : false; + return jedis.ttl(ACCESS_TOKEN_KEY.concat(appId)) < 2; } @Override @@ -46,7 +46,7 @@ public String getJsapiTicket() { @Override public boolean isJsapiTicketExpired() { - return getJsapiTicket() == null ? true : false; + return jedis.ttl(JSAPI_TICKET_KEY.concat(appId)) < 2; } @Override @@ -70,7 +70,7 @@ public String getCardApiTicket() { @Override public boolean isCardApiTicketExpired() { - return getCardApiTicket() == null ? true : false; + return jedis.ttl(CARDAPI_TICKET_KEY.concat(appId)) < 2; } @Override From c924e369fa6fb1ebff2d8272b3413a61da6992e4 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 14:04:22 +0800 Subject: [PATCH 041/179] Update readme.md --- readme.md | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/readme.md b/readme.md index b55333188b..a83977f8fa 100644 --- a/readme.md +++ b/readme.md @@ -50,11 +50,10 @@ * https://github.com/wechat-group/weixin-java-cp-demo (企业号demo,筹备中) --------------------------------- -## Maven & Gradle 最新正式版本 +## Maven 最新正式版本 * 微信支付: -maven: ```xml com.github.binarywang @@ -62,14 +61,9 @@ maven: 2.6.0 ``` -gradle: -```groovy -compile 'com.github.binarywang:weixin-java-pay:2.6.0' -``` * 公众号(订阅号及服务号): -maven: ```xml com.github.binarywang @@ -77,14 +71,9 @@ maven: 2.6.0 ``` -gradle: -```groovy -compile 'com.github.binarywang:weixin-java-mp:2.6.0' -``` * 企业号: -maven: ```xml com.github.binarywang @@ -92,7 +81,3 @@ maven: 2.6.0 ``` -gradle: -```groovy -compile 'com.github.binarywang:weixin-java-cp:2.6.0' -``` From 00825724f3dbd0af282efee03f4bf510ee00835f Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 14:09:28 +0800 Subject: [PATCH 042/179] =?UTF-8?q?WxMpXmlMessage=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E5=8D=A1=E5=88=B8=E5=BA=93=E5=AD=98=E6=8A=A5?= =?UTF-8?q?=E8=AD=A6=E4=BA=8B=E4=BB=B6=E5=A2=9E=E5=8A=A0=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E7=9A=84=E6=B6=88=E6=81=AF=E6=95=B0=E6=8D=AE=20#218?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/bean/message/WxMpXmlMessage.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java index fd5a1725ff..375caebe78 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java @@ -254,6 +254,15 @@ public class WxMpXmlMessage implements Serializable { @XStreamAlias("RemarkAmount") private String remarkAmount; + /** + *
+   * 官网文档中,微信卡券>>卡券事件推送>>2.10 库存报警事件card_sku_remind
+   * Detail:报警详细信息
+   * 
+ */ + @XStreamAlias("Detail") + private String detail; + @XStreamAlias("ScanCodeInfo") private ScanCodeInfo scanCodeInfo = new ScanCodeInfo(); @@ -468,6 +477,14 @@ public void setFailReason(String failReason) { this.failReason = failReason; } + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + public String getStoreUniqId() { return this.storeUniqId; } From 290bed1343255b1add4f110ea8811d873935720c Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 14:13:06 +0800 Subject: [PATCH 043/179] =?UTF-8?q?WxMpXmlMessage=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E4=BC=9A=E5=91=98=E5=8D=A1=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=8B=E4=BB=B6=E5=A2=9E=E5=8A=A0=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E7=9A=84=E6=B6=88=E6=81=AF=E6=95=B0=E6=8D=AE=20#216?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mp/bean/message/WxMpXmlMessage.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java index 375caebe78..5543696b46 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java @@ -263,6 +263,24 @@ public class WxMpXmlMessage implements Serializable { @XStreamAlias("Detail") private String detail; + /** + *
+   * 官网文档中,微信卡券>>卡券事件推送>>2.9 会员卡内容更新事件 update_member_card
+   * ModifyBonus:变动的积分值
+   * 
+ */ + @XStreamAlias("ModifyBonus") + private String modifyBonus; + + /** + *
+   * 官网文档中,微信卡券>>卡券事件推送>>2.9 会员卡内容更新事件 update_member_card
+   * ModifyBalance:变动的余额值
+   * 
+ */ + @XStreamAlias("ModifyBalance") + private String modifyBalance; + @XStreamAlias("ScanCodeInfo") private ScanCodeInfo scanCodeInfo = new ScanCodeInfo(); @@ -485,6 +503,22 @@ public void setDetail(String detail) { this.detail = detail; } + public String getModifyBonus() { + return modifyBonus; + } + + public void setModifyBonus(String modifyBonus) { + this.modifyBonus = modifyBonus; + } + + public String getModifyBalance() { + return modifyBalance; + } + + public void setModifyBalance(String modifyBalance) { + this.modifyBalance = modifyBalance; + } + public String getStoreUniqId() { return this.storeUniqId; } From e186cd9ea10643364f13d55d4528062d0892e083 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 14:15:57 +0800 Subject: [PATCH 044/179] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=E5=86=85=E5=AE=B9=20#215?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java index 5543696b46..e3df764c7e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java @@ -207,6 +207,9 @@ public class WxMpXmlMessage implements Serializable { *
    * 领取场景值,用于领取渠道数据统计。可在生成二维码接口及添加Addcard接口中自定义该字段的字符串值。
    * 核销卡券时:开发者发起核销时传入的自定义参数,用于进行核销渠道统计
+   * 另外:
+   * 官网文档中,微信卡券>>卡券事件推送>>2.7 进入会员卡事件推送 user_view_card
+   * OuterStr:商户自定义二维码渠道参数,用于标识本次扫码打开会员卡来源来自于某个渠道值的二维码
    * 
*/ @XStreamAlias("OuterStr") From c80621cf1683fb2f063ad03b4127750d81afcee3 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 14:19:34 +0800 Subject: [PATCH 045/179] =?UTF-8?q?WxMpXmlMessage=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E7=94=A8=E6=88=B7=E5=8D=A1=E5=88=B8=E4=B9=B0?= =?UTF-8?q?=E5=8D=95=E4=BA=8B=E4=BB=B6=E5=A2=9E=E5=8A=A0=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E7=9A=84=E6=B6=88=E6=81=AF=E6=95=B0=E6=8D=AE=20#214?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mp/bean/message/WxMpXmlMessage.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java index e3df764c7e..262399b8f4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java @@ -284,6 +284,42 @@ public class WxMpXmlMessage implements Serializable { @XStreamAlias("ModifyBalance") private String modifyBalance; + /** + *
+   * 官网文档中,微信卡券>>卡券事件推送>>2.6 买单事件推送 User_pay_from_pay_cell
+   * TransId:微信支付交易订单号(只有使用买单功能核销的卡券才会出现)
+   * 
+ */ + @XStreamAlias("TransId") + private String transId; + + /** + *
+   * 官网文档中,微信卡券>>卡券事件推送>>2.6 买单事件推送 User_pay_from_pay_cell
+   * LocationId:门店ID,当前卡券核销的门店ID(只有通过卡券商户助手和买单核销时才会出现)
+   * 
+ */ + @XStreamAlias("LocationId") + private String locationId; + + /** + *
+   * 官网文档中,微信卡券>>卡券事件推送>>2.6 买单事件推送 User_pay_from_pay_cell
+   * Fee:实付金额,单位为分
+   * 
+ */ + @XStreamAlias("Fee") + private String fee; + + /** + *
+   * 官网文档中,微信卡券>>卡券事件推送>>2.6 买单事件推送 User_pay_from_pay_cell
+   * OriginalFee:应付金额,单位为分
+   * 
+ */ + @XStreamAlias("OriginalFee") + private String originalFee; + @XStreamAlias("ScanCodeInfo") private ScanCodeInfo scanCodeInfo = new ScanCodeInfo(); @@ -522,6 +558,38 @@ public void setModifyBalance(String modifyBalance) { this.modifyBalance = modifyBalance; } + public String getTransId() { + return transId; + } + + public void setTransId(String transId) { + this.transId = transId; + } + + public String getLocationId() { + return locationId; + } + + public void setLocationId(String locationId) { + this.locationId = locationId; + } + + public String getFee() { + return fee; + } + + public void setFee(String fee) { + this.fee = fee; + } + + public String getOriginalFee() { + return originalFee; + } + + public void setOriginalFee(String originalFee) { + this.originalFee = originalFee; + } + public String getStoreUniqId() { return this.storeUniqId; } From ac257dd31c7ad87d06b0c047380e39c504e687f4 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 14:23:09 +0800 Subject: [PATCH 046/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E3=80=90=E4=B8=8A=E4=BC=A0=E4=B8=B4=E6=97=B6=E7=B4=A0=E6=9D=90?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E3=80=91=E6=8E=A5=E5=8F=A3=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=2044001=20=E5=A4=9A=E5=AA=92=E4=BD=93=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=BA=E7=A9=BA=E7=9A=84=E9=97=AE=E9=A2=98=20=20#209?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/http/apache/ApacheMediaUploadRequestExecutor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java index e250157bc8..bdddf0dfb9 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java @@ -40,7 +40,6 @@ public WxMediaUploadResult execute(String uri, File file) throws WxErrorExceptio .setMode(HttpMultipartMode.RFC6532) .build(); httpPost.setEntity(entity); - httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); } try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); From a436e621039e5d6344ceb2adbeee0e3f96d5ef80 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 14:39:25 +0800 Subject: [PATCH 047/179] =?UTF-8?q?=E6=8A=BD=E5=8F=96=E5=8D=A1=E5=88=B8?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3=E8=AF=B7=E6=B1=82URL?= =?UTF-8?q?=E5=88=B0=E5=85=B6=E6=8E=A5=E5=8F=A3=E7=B1=BB=E4=B8=AD=20#195?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/mp/api/WxMpCardService.java | 6 ++++++ .../mp/api/impl/WxMpCardServiceImpl.java | 18 ++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java index c1327776ef..08ea9a7007 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java @@ -10,6 +10,12 @@ * @author YuJian(mgcnrx11@hotmail.com) on 01/11/2016 */ public interface WxMpCardService { + String CARD_GET = "https://api.weixin.qq.com/card/get"; + String CARD_GET_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; + String CARD_CODE_DECRYPT = "https://api.weixin.qq.com/card/code/decrypt"; + String CARD_CODE_GET = "https://api.weixin.qq.com/card/code/get"; + String CARD_CODE_CONSUME = "https://api.weixin.qq.com/card/code/consume"; + String CARD_CODE_MARK = "https://api.weixin.qq.com/card/code/mark"; /** * 得到WxMpService diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java index 7bb9b9cca3..8ec5945f7b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java @@ -74,8 +74,7 @@ public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { } if (this.getWxMpService().getWxMpConfigStorage().isCardApiTicketExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; - String responseContent = this.wxMpService.execute(SimpleGetRequestExecutor.create(this.getWxMpService().getRequestHttp()), url, null); + String responseContent = this.wxMpService.execute(SimpleGetRequestExecutor.create(this.getWxMpService().getRequestHttp()), CARD_GET_TICKET, null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); @@ -129,10 +128,9 @@ public WxCardApiSignature createCardApiSignature(String... optionalSignParam) th */ @Override public String decryptCardCode(String encryptCode) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/code/decrypt"; JsonObject param = new JsonObject(); param.addProperty("encrypt_code", encryptCode); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(CARD_CODE_DECRYPT, param.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); JsonPrimitive jsonPrimitive = tmpJsonObject.getAsJsonPrimitive("code"); @@ -149,12 +147,11 @@ public String decryptCardCode(String encryptCode) throws WxErrorException { */ @Override public WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/code/get"; JsonObject param = new JsonObject(); param.addProperty("card_id", cardId); param.addProperty("code", code); param.addProperty("check_consume", checkConsume); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(CARD_CODE_GET, param.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, new TypeToken() { @@ -183,7 +180,6 @@ public String consumeCardCode(String code) throws WxErrorException { */ @Override public String consumeCardCode(String code, String cardId) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/code/consume"; JsonObject param = new JsonObject(); param.addProperty("code", code); @@ -191,7 +187,7 @@ public String consumeCardCode(String code, String cardId) throws WxErrorExceptio param.addProperty("card_id", cardId); } - return this.wxMpService.post(url, param.toString()); + return this.wxMpService.post(CARD_CODE_CONSUME, param.toString()); } /** @@ -207,13 +203,12 @@ public String consumeCardCode(String code, String cardId) throws WxErrorExceptio @Override public void markCardCode(String code, String cardId, String openId, boolean isMark) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/code/mark"; JsonObject param = new JsonObject(); param.addProperty("code", code); param.addProperty("card_id", cardId); param.addProperty("openid", openId); param.addProperty("is_mark", isMark); - String responseContent = this.getWxMpService().post(url, param.toString()); + String responseContent = this.getWxMpService().post(CARD_CODE_MARK, param.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); WxMpCardResult cardResult = WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, new TypeToken() { @@ -225,10 +220,9 @@ public void markCardCode(String code, String cardId, String openId, boolean isMa @Override public String getCardDetail(String cardId) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/get"; JsonObject param = new JsonObject(); param.addProperty("card_id", cardId); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(CARD_GET, param.toString()); // 判断返回值 JsonObject json = (new JsonParser()).parse(responseContent).getAsJsonObject(); From 931533c13a29df8f58344d0fd8987d1e1438aa5f Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 15:07:23 +0800 Subject: [PATCH 048/179] =?UTF-8?q?=E6=8A=BD=E5=8F=96=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3=E8=AF=B7?= =?UTF-8?q?=E6=B1=82URL=E5=88=B0=E5=85=B6=E6=8E=A5=E5=8F=A3=E7=B1=BB?= =?UTF-8?q?=E4=B8=AD=EF=BC=8C=E5=B9=B6=E9=87=8D=E6=9E=84=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=20#195?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/WxMpDataCubeService.java | 18 +++ .../mp/api/impl/WxMpDataCubeServiceImpl.java | 151 +++++------------- 2 files changed, 57 insertions(+), 112 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java index 644844338e..7610b03d3a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java @@ -13,6 +13,24 @@ * @author binarywang (https://github.com/binarywang) */ public interface WxMpDataCubeService { + String GET_USER_SUMMARY = "https://api.weixin.qq.com/datacube/getusersummary"; + String GET_USER_CUMULATE = "https://api.weixin.qq.com/datacube/getusercumulate"; + String GET_ARTICLE_SUMMARY = "https://api.weixin.qq.com/datacube/getarticlesummary"; + String GET_ARTICLE_TOTAL = "https://api.weixin.qq.com/datacube/getarticletotal"; + String GET_USER_READ = "https://api.weixin.qq.com/datacube/getuserread"; + String GET_USER_READ_HOUR = "https://api.weixin.qq.com/datacube/getuserreadhour"; + String GET_USER_SHARE = "https://api.weixin.qq.com/datacube/getusershare"; + String GET_USER_SHARE_HOUR = "https://api.weixin.qq.com/datacube/getusersharehour"; + String GET_UPSTREAM_MSG = "https://api.weixin.qq.com/datacube/getupstreammsg"; + String GET_UPSTREAM_MSG_HOUR = "https://api.weixin.qq.com/datacube/getupstreammsghour"; + String GET_UPSTREAM_MSG_WEEK = "https://api.weixin.qq.com/datacube/getupstreammsgweek"; + String GET_UPSTREAM_MSG_MONTH = "https://api.weixin.qq.com/datacube/getupstreammsgmonth"; + String GET_UPSTREAM_MSG_DIST = "https://api.weixin.qq.com/datacube/getupstreammsgdist"; + String GET_UPSTREAM_MSG_DIST_WEEK = "https://api.weixin.qq.com/datacube/getupstreammsgdistweek"; + String GET_UPSTREAM_MSG_DIST_MONTH = "https://api.weixin.qq.com/datacube/getupstreammsgdistmonth"; + String GET_INTERFACE_SUMMARY = "https://api.weixin.qq.com/datacube/getinterfacesummary"; + String GET_INTERFACE_SUMMARY_HOUR = "https://api.weixin.qq.com/datacube/getinterfacesummaryhour"; + //*******************用户分析数据接口***********************// /** diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java index a1a8d82b0e..25bd3cfaab 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java @@ -17,7 +17,6 @@ * @author binarywang (https://github.com/binarywang) */ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService { - private static final String API_URL_PREFIX = "https://api.weixin.qq.com/datacube"; private final Format dateFormat = FastDateFormat.getInstance("yyyy-MM-dd"); @@ -29,180 +28,108 @@ public WxMpDataCubeServiceImpl(WxMpService wxMpService) { @Override public List getUserSummary(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getusersummary"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(GET_USER_SUMMARY, buildParams(beginDate, endDate)); return WxDataCubeUserSummary.fromJson(responseContent); } @Override public List getUserCumulate(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getusercumulate"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(GET_USER_CUMULATE, buildParams(beginDate, endDate)); return WxDataCubeUserCumulate.fromJson(responseContent); } @Override public List getArticleSummary(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getarticlesummary"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeArticleResult.fromJson(responseContent); + return this.getArticleResults(GET_ARTICLE_SUMMARY, beginDate, endDate); } @Override public List getArticleTotal(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getarticletotal"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(GET_ARTICLE_TOTAL, buildParams(beginDate, endDate)); return WxDataCubeArticleTotal.fromJson(responseContent); } @Override public List getUserRead(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getuserread"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeArticleResult.fromJson(responseContent); + return this.getArticleResults(GET_USER_READ, beginDate, endDate); } @Override public List getUserReadHour(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getuserreadhour"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeArticleResult.fromJson(responseContent); + return this.getArticleResults(GET_USER_READ_HOUR, beginDate, endDate); } @Override public List getUserShare(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getusershare"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeArticleResult.fromJson(responseContent); + return this.getArticleResults(GET_USER_SHARE, beginDate, endDate); } @Override public List getUserShareHour(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getusersharehour"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + return this.getArticleResults(GET_USER_SHARE_HOUR, beginDate, endDate); + } + + private List getArticleResults(String url, Date beginDate, Date endDate) throws WxErrorException { + String responseContent = this.wxMpService.post(url, buildParams(beginDate, endDate)); return WxDataCubeArticleResult.fromJson(responseContent); } @Override - public List getUpstreamMsg(Date beginDate, Date endDate) - throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsg"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsg(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG, beginDate, endDate); } @Override - public List getUpstreamMsgHour(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsghour"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsgHour(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_HOUR, beginDate, endDate); } @Override - public List getUpstreamMsgWeek(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsgweek"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsgWeek(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_WEEK, beginDate, endDate); } @Override - public List getUpstreamMsgMonth(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsgmonth"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsgMonth(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_MONTH, beginDate, endDate); } @Override - public List getUpstreamMsgDist(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsgdist"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsgDist(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_DIST, beginDate, endDate); } @Override - public List getUpstreamMsgDistWeek(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsgdistweek"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsgDistWeek(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_DIST_WEEK, beginDate, endDate); } @Override - public List getUpstreamMsgDistMonth(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsgdistmonth"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + public List getUpstreamMsgDistMonth(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_DIST_MONTH, beginDate, endDate); + } + + private List getUpstreamMsg(String url, Date beginDate, Date endDate) throws WxErrorException { + String responseContent = this.wxMpService.post(url, buildParams(beginDate, endDate)); return WxDataCubeMsgResult.fromJson(responseContent); } @Override - public List getInterfaceSummary(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getinterfacesummary"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + public List getInterfaceSummary(Date beginDate, Date endDate) throws WxErrorException { + String responseContent = this.wxMpService.post(GET_INTERFACE_SUMMARY, buildParams(beginDate, endDate)); return WxDataCubeInterfaceResult.fromJson(responseContent); } - @Override - public List getInterfaceSummaryHour(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getinterfacesummaryhour"; + private String buildParams(Date beginDate, Date endDate) { JsonObject param = new JsonObject(); param.addProperty("begin_date", this.dateFormat.format(beginDate)); param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + return param.toString(); + } + + @Override + public List getInterfaceSummaryHour(Date beginDate, Date endDate) throws WxErrorException { + String responseContent = this.wxMpService.post(GET_INTERFACE_SUMMARY_HOUR, buildParams(beginDate, endDate)); return WxDataCubeInterfaceResult.fromJson(responseContent); } } From 355f64c2e5a6dc9b806a1617de54807114897ca4 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 15:13:33 +0800 Subject: [PATCH 049/179] =?UTF-8?q?=E5=8F=91=E5=B8=83=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC2.6.2.BETA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 5343df8c68..62b7e15735 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang weixin-java-parent - 2.6.1.BETA + 2.6.2.BETA pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 5414f8bc3d..9903d4d5f7 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.6.1.BETA + 2.6.2.BETA weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 3bbc65b7fa..3a867c9308 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.6.1.BETA + 2.6.2.BETA weixin-java-cp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 570abca132..912a585cb5 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.6.1.BETA + 2.6.2.BETA weixin-java-mp WeiXin Java Tools - MP diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 11c6000510..2ffacde424 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 2.6.1.BETA + 2.6.2.BETA 4.0.0 From 4cf3f5c36387c6790dce283c8b535e9489758471 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 15:27:57 +0800 Subject: [PATCH 050/179] remove useless gradle files --- build.gradle | 33 --------------------------------- settings.gradle | 10 ---------- weixin-java-common/build.gradle | 11 ----------- weixin-java-cp/build.gradle | 11 ----------- weixin-java-mp/build.gradle | 12 ------------ weixin-java-pay/build.gradle | 12 ------------ 6 files changed, 89 deletions(-) delete mode 100644 build.gradle delete mode 100644 settings.gradle delete mode 100644 weixin-java-common/build.gradle delete mode 100644 weixin-java-cp/build.gradle delete mode 100644 weixin-java-mp/build.gradle delete mode 100644 weixin-java-pay/build.gradle diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 6fa9a27ac2..0000000000 --- a/build.gradle +++ /dev/null @@ -1,33 +0,0 @@ -allprojects { - apply plugin: 'maven' - - group = 'com.github.binarywang' - version = '2.6.0' -} - -subprojects { - apply plugin: 'java' - sourceCompatibility = 1.7 - targetCompatibility = 1.7 - - - repositories { - mavenLocal() - maven { url "http://central.maven.org/maven2" } - //maven { url "http://maven.aliyun.com/nexus/content/groups/public" } - } - - - dependencies { - compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.10' - compile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.5' - compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5' - compile group: 'com.google.code.gson', name: 'gson', version: '2.7' - compile group: 'com.google.guava', name: 'guava', version: '19.0' - compile group: 'commons-codec', name: 'commons-codec', version: '1.10' - compile group: 'commons-io', name: 'commons-io', version: '2.5' - compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.4' - compile group: 'redis.clients', name: 'jedis', version: '2.9.0' - testCompile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.2' - } -} diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 0ff1d35b7c..0000000000 --- a/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -rootProject.name = 'weixin-java-parent' -include ':weixin-java-common' -include ':weixin-java-cp' -include ':weixin-java-mp' -include ':weixin-java-pay' - -project(':weixin-java-common').projectDir = "$rootDir/weixin-java-common" as File -project(':weixin-java-cp').projectDir = "$rootDir/weixin-java-cp" as File -project(':weixin-java-mp').projectDir = "$rootDir/weixin-java-mp" as File -project(':weixin-java-pay').projectDir = "$rootDir/weixin-java-pay" as File diff --git a/weixin-java-common/build.gradle b/weixin-java-common/build.gradle deleted file mode 100644 index f7f40ba01a..0000000000 --- a/weixin-java-common/build.gradle +++ /dev/null @@ -1,11 +0,0 @@ -description = 'WeiXin Java Tools - Common' -dependencies { - compile group: 'com.thoughtworks.xstream', name: 'xstream', version: '1.4.7' - testCompile group: 'junit', name: 'junit', version: '4.11' - testCompile group: 'org.testng', name: 'testng', version: '6.8.7' - testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5' - testCompile group: 'com.google.inject', name: 'guice', version: '3.0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.0.RC0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.3.0.RC0' -} -test.useTestNG() diff --git a/weixin-java-cp/build.gradle b/weixin-java-cp/build.gradle deleted file mode 100644 index 3e0c09ad0c..0000000000 --- a/weixin-java-cp/build.gradle +++ /dev/null @@ -1,11 +0,0 @@ -description = 'WeiXin Java Tools - CP' -dependencies { - compile project(':weixin-java-common') - testCompile group: 'junit', name: 'junit', version: '4.11' - testCompile group: 'org.testng', name: 'testng', version: '6.8.7' - testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5' - testCompile group: 'com.google.inject', name: 'guice', version: '3.0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.0.RC0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.3.0.RC0' -} -test.useTestNG() diff --git a/weixin-java-mp/build.gradle b/weixin-java-mp/build.gradle deleted file mode 100644 index bd91f2f88f..0000000000 --- a/weixin-java-mp/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -description = 'WeiXin Java Tools - MP' -dependencies { - compile project(':weixin-java-common') - testCompile group: 'junit', name: 'junit', version: '4.11' - testCompile group: 'org.testng', name: 'testng', version: '6.8.7' - testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5' - testCompile group: 'com.google.inject', name: 'guice', version: '3.0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.0.RC0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.3.0.RC0' - testCompile group: 'joda-time', name: 'joda-time', version: '2.9.4' -} -test.useTestNG() diff --git a/weixin-java-pay/build.gradle b/weixin-java-pay/build.gradle deleted file mode 100644 index 2f0c7e9a87..0000000000 --- a/weixin-java-pay/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -description = 'WeiXin Java Tools - PAY' -dependencies { - compile project(':weixin-java-common') - testCompile group: 'junit', name: 'junit', version: '4.11' - testCompile group: 'org.testng', name: 'testng', version: '6.8.7' - testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5' - testCompile group: 'com.google.inject', name: 'guice', version: '3.0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.0.RC0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.3.0.RC0' - testCompile group: 'joda-time', name: 'joda-time', version: '2.9.4' -} -test.useTestNG() From 4f93fde535bdc5476afbc4bc6679efaced6c05aa Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 15:39:15 +0800 Subject: [PATCH 051/179] Update pom.xml --- weixin-java-osgi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weixin-java-osgi/pom.xml b/weixin-java-osgi/pom.xml index b44ef85d7e..da00a739c3 100644 --- a/weixin-java-osgi/pom.xml +++ b/weixin-java-osgi/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang weixin-java-parent - 2.5.2.BETA + 2.6.0 weixin-java-osgi From f633a77785eeba2192a9f1d7a2b343d2fdceb2bb Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 15:43:33 +0800 Subject: [PATCH 052/179] Delete build.gradle --- build.gradle | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 build.gradle diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 23ec2c52c9..0000000000 --- a/build.gradle +++ /dev/null @@ -1,33 +0,0 @@ -allprojects { - apply plugin: 'maven' - - group = 'com.github.binarywang' - version = '2.6.0' -} - -subprojects { - apply plugin: 'java' - sourceCompatibility = 1.7 - targetCompatibility = 1.7 - - - repositories { - mavenLocal() - maven { url "http://central.maven.org/maven2" } - //maven { url "http://maven.aliyun.com/nexus/content/groups/public" } - } - - - dependencies { - compile group: 'org.slf4j', name: 'slf4j-api', version:'1.7.10' - compile group: 'org.apache.httpcomponents', name: 'httpmime', version:'4.5' - compile group: 'org.apache.httpcomponents', name: 'httpclient', version:'4.5' - compile group: 'com.google.code.gson', name: 'gson', version:'2.7' - compile group: 'com.google.guava', name: 'guava', version:'19.0' - compile group: 'commons-codec', name: 'commons-codec', version:'1.10' - compile group: 'commons-io', name: 'commons-io', version:'2.5' - compile group: 'org.apache.commons', name: 'commons-lang3', version:'3.4' - compile group: 'redis.clients', name: 'jedis', version:'2.9.0' - testCompile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2' - } -} From c8e4d0c38eedbe8d35bf6fd44e3a69b0f7a3e2ac Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 29 May 2017 15:43:46 +0800 Subject: [PATCH 053/179] Delete settings.gradle --- settings.gradle | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 settings.gradle diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 1c0e0214c4..0000000000 --- a/settings.gradle +++ /dev/null @@ -1,8 +0,0 @@ -rootProject.name = 'weixin-java-parent' -include ':weixin-java-common' -include ':weixin-java-cp' -include ':weixin-java-mp' - -project(':weixin-java-common').projectDir = "$rootDir/weixin-java-common" as File -project(':weixin-java-cp').projectDir = "$rootDir/weixin-java-cp" as File -project(':weixin-java-mp').projectDir = "$rootDir/weixin-java-mp" as File \ No newline at end of file From 69ca699829e8e792b5d4090241623ecb958e3b05 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 30 May 2017 10:35:42 +0800 Subject: [PATCH 054/179] =?UTF-8?q?=E5=8A=A0=E5=BC=BA=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../github/binarywang/wxpay/config/WxPayConfig.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java index 838b57914f..6b4ea379de 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java @@ -1,5 +1,6 @@ package com.github.binarywang.wxpay.config; +import org.apache.commons.lang3.StringUtils; import org.apache.http.ssl.SSLContexts; import javax.net.ssl.SSLContext; @@ -143,13 +144,17 @@ public void setUseSandboxEnv(boolean useSandboxEnv) { } public SSLContext initSSLContext() { - if (null == mchId) { - throw new IllegalArgumentException("请确保商户号mch_id已设置"); + if (StringUtils.isBlank(mchId)) { + throw new IllegalArgumentException("请确保商户号mchId已设置"); + } + + if (StringUtils.isBlank(this.keyPath)) { + throw new IllegalArgumentException("请确保证书文件地址keyPath已配置"); } File file = new File(this.keyPath); if (!file.exists()) { - throw new RuntimeException("证书文件:【" + file.getPath() + "】不存在!"); + throw new RuntimeException("证书文件【" + file.getPath() + "】不存在!"); } try { From 592af1cd7b886c0d704a56839da9cc422e4e1a83 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 30 May 2017 11:56:33 +0800 Subject: [PATCH 055/179] Update readme.md --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index a83977f8fa..af1d9c9d8c 100644 --- a/readme.md +++ b/readme.md @@ -43,9 +43,9 @@ ## 可参考的Demo项目 #### 欢迎提供更多的Demo供新手参考: * https://github.com/wechat-group/weixin-java-mp-demo (公众号Demo,使用Spring MVC实现) -* https://github.com/wechat-group/weixin-java-mp-multi-demo (支持多公众号) -* https://github.com/wechat-group/weixin-java-tools-springmvc (公众号Demo,内含部分微信支付代码) * https://github.com/wechat-group/weixin-java-mp-demo-springboot (公众号Demo,使用Spring Boot实现) +* https://github.com/wechat-group/weixin-java-tools-springmvc (公众号Demo,内含部分微信支付代码) +* https://github.com/wechat-group/weixin-java-mp-multi-demo (支持多公众号) * https://github.com/wechat-group/weixin-java-pay-demo (微信支付demo) * https://github.com/wechat-group/weixin-java-cp-demo (企业号demo,筹备中) From 7f91ba2372576f18cb7a7c28e8610819f6e61d3a Mon Sep 17 00:00:00 2001 From: ecoolper Date: Sat, 3 Jun 2017 23:10:30 +0800 Subject: [PATCH 056/179] =?UTF-8?q?jodd=20response=20=E7=BC=96=E7=A0=81?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E4=B8=BAUTF-8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/jodd/JoddMediaDownloadRequestExecutor.java | 4 ++++ .../util/http/jodd/JoddMediaUploadRequestExecutor.java | 4 ++++ .../util/http/jodd/JoddSimpleGetRequestExecutor.java | 10 ++++++---- .../util/http/jodd/JoddSimplePostRequestExecutor.java | 3 +++ .../http/jodd/JoddMaterialDeleteRequestExecutor.java | 3 +++ .../http/jodd/JoddMaterialNewsInfoRequestExecutor.java | 3 +++ .../http/jodd/JoddMaterialUploadRequestExecutor.java | 3 +++ .../jodd/JoddMaterialVideoInfoRequestExecutor.java | 3 +++ ...ddMaterialVoiceAndImageDownloadRequestExecutor.java | 3 +++ .../http/jodd/JoddMediaImgUploadRequestExecutor.java | 3 +++ .../mp/util/http/jodd/JoddQrCodeRequestExecutor.java | 3 +++ 11 files changed, 38 insertions(+), 4 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaDownloadRequestExecutor.java index 230b3ca69b..a15272bc07 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaDownloadRequestExecutor.java @@ -4,6 +4,8 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; +import jodd.util.StringPool; + import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; @@ -44,6 +46,8 @@ public File execute(String uri, String queryParam) throws WxErrorException, IOEx request.withConnectionProvider(requestHttp.getRequestHttpClient()); HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + String contentType = response.header("Content-Type"); if (contentType != null && contentType.startsWith("application/json")) { // application/json; encoding=utf-8 下载媒体文件出错 diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaUploadRequestExecutor.java index 43f17fbcf0..8466eead68 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaUploadRequestExecutor.java @@ -4,6 +4,8 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; +import jodd.util.StringPool; + import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; @@ -30,6 +32,8 @@ public WxMediaUploadResult execute(String uri, File file) throws WxErrorExceptio request.withConnectionProvider(requestHttp.getRequestHttpClient()); request.form("media", file); HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + String responseContent = response.bodyText(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimpleGetRequestExecutor.java index a43fe5f206..02f6aa3795 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimpleGetRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimpleGetRequestExecutor.java @@ -1,9 +1,8 @@ package me.chanjar.weixin.common.util.http.jodd; -import jodd.http.HttpConnectionProvider; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.ProxyInfo; +import jodd.http.*; +import jodd.util.StringPool; + import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; @@ -35,7 +34,10 @@ public String execute(String uri, String queryParam) throws WxErrorException, IO } request.withConnectionProvider(requestHttp.getRequestHttpClient()); HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimplePostRequestExecutor.java index 1db0f2af30..cca45350a6 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimplePostRequestExecutor.java @@ -4,6 +4,8 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; +import jodd.util.StringPool; + import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; @@ -34,6 +36,7 @@ public String execute(String uri, String postEntity) throws WxErrorException, IO request.bodyText(postEntity); } HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); String responseContent = response.bodyText(); if (responseContent.isEmpty()) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialDeleteRequestExecutor.java index 5349a0fafa..0344e1cddc 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialDeleteRequestExecutor.java @@ -4,6 +4,8 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; +import jodd.util.StringPool; + import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; @@ -29,6 +31,7 @@ public Boolean execute(String uri, String materialId) throws WxErrorException, I request.query("media_id", materialId); HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); String responseContent = response.bodyText(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java index 6d6b0120ce..a5d5ad1fd3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java @@ -4,6 +4,8 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; +import jodd.util.StringPool; + import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; @@ -31,6 +33,7 @@ public WxMpMaterialNews execute(String uri, String materialId) throws WxErrorExc request.query("media_id", materialId); HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); String responseContent = response.bodyText(); WxError error = WxError.fromJson(responseContent); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialUploadRequestExecutor.java index 8c9fdd0d64..ce30323695 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialUploadRequestExecutor.java @@ -4,6 +4,8 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; +import jodd.util.StringPool; + import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; @@ -48,6 +50,7 @@ public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material) throw } HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); String responseContent = response.bodyText(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVideoInfoRequestExecutor.java index 8d600bc607..ab4ce6682c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVideoInfoRequestExecutor.java @@ -4,6 +4,8 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; +import jodd.util.StringPool; + import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; @@ -30,6 +32,7 @@ public WxMpMaterialVideoInfoResult execute(String uri, String materialId) throws request.query("media_id", materialId); HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); String responseContent = response.bodyText(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java index bc8696009b..a6317d5a00 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java @@ -4,6 +4,8 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; +import jodd.util.StringPool; + import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; @@ -34,6 +36,7 @@ public InputStream execute(String uri, String materialId) throws WxErrorExceptio request.query("media_id", materialId); HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { // 下载媒体文件出错 byte[] responseContent = IOUtils.toByteArray(inputStream); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMediaImgUploadRequestExecutor.java index 09309890db..d0fdbfb856 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMediaImgUploadRequestExecutor.java @@ -4,6 +4,8 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; +import jodd.util.StringPool; + import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; @@ -35,6 +37,7 @@ public WxMediaImgUploadResult execute(String uri, File data) throws WxErrorExcep request.form("media", data); HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); String responseContent = response.bodyText(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddQrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddQrCodeRequestExecutor.java index 36ae7b4dbc..8b15dccf00 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddQrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddQrCodeRequestExecutor.java @@ -5,6 +5,8 @@ import jodd.http.HttpResponse; import jodd.http.ProxyInfo; import jodd.util.MimeTypes; +import jodd.util.StringPool; + import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; @@ -45,6 +47,7 @@ public File execute(String uri, WxMpQrCodeTicket ticket) throws WxErrorException request.withConnectionProvider(requestHttp.getRequestHttpClient()); HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); String contentTypeHeader = response.header("Content-Type"); if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { String responseContent = response.bodyText(); From 39a07f294c329878595a169ceda1d3d9996cf927 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 5 Jun 2017 10:34:41 +0800 Subject: [PATCH 057/179] Update contribution.md --- contribution.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contribution.md b/contribution.md index abd07aa6f5..a10729a81c 100644 --- a/contribution.md +++ b/contribution.md @@ -2,8 +2,8 @@ 1. 非常欢迎和感谢对本项目发起Pull Request的同学,本项目代码风格为使用2个空格代表一个Tab,因此在提交代码时请注意一下,否则很容易在IDE格式化代码后与原代码产生大量diff,这样会给其他人阅读代码带来极大的困扰。为了便于设置,本项目引入editorconfig插件,请使用eclipse的同学在贡献代码前安装相关插件,IntelliJ IDEA新版本自带支持,如果没有可自行安装插件。 1. 本项目可以采用两种方式接受代码贡献:  * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择develop分支,详细步骤参考后文,推荐使用此种方式贡献代码。 - * 另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题,具体加入方式,请咨询QQ群管理员[![点击这里给我发消息](http://wpa.qq.com/pa?p=2:1211415707:51)](http://wpa.qq.com/msgrd?v=3&uin=1211415707&site=qq&menu=yes)。 -1. 提交代码前请检查代码是否已经格式化,并且保证新增加或者修改的方法都有完整的参数说明,而public方法必须拥有相应的单元测试并通过测试。 +  * (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。 +1. 另外,提交代码前请检查代码是否已经格式化,并且保证新增加或者修改的方法都有完整的参数说明,而public方法必须拥有相应的单元测试并通过测试。 ### PR方式贡献代码步骤 From 5b0b32ad4d9ad4b9008fe6f66f01ba2c101d9147 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 5 Jun 2017 10:40:27 +0800 Subject: [PATCH 058/179] Update contribution.md --- contribution.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contribution.md b/contribution.md index a10729a81c..1b4f5a8fdc 100644 --- a/contribution.md +++ b/contribution.md @@ -1,8 +1,8 @@ # 代码贡献指南 1. 非常欢迎和感谢对本项目发起Pull Request的同学,本项目代码风格为使用2个空格代表一个Tab,因此在提交代码时请注意一下,否则很容易在IDE格式化代码后与原代码产生大量diff,这样会给其他人阅读代码带来极大的困扰。为了便于设置,本项目引入editorconfig插件,请使用eclipse的同学在贡献代码前安装相关插件,IntelliJ IDEA新版本自带支持,如果没有可自行安装插件。 1. 本项目可以采用两种方式接受代码贡献: -  * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择develop分支,详细步骤参考后文,推荐使用此种方式贡献代码。 -  * (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。 + * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择develop分支,详细步骤参考后文,推荐使用此种方式贡献代码。 + * (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。 1. 另外,提交代码前请检查代码是否已经格式化,并且保证新增加或者修改的方法都有完整的参数说明,而public方法必须拥有相应的单元测试并通过测试。 From ff2caf76db008529243f731b8d8418ca8e00beb1 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 5 Jun 2017 17:06:01 +0800 Subject: [PATCH 059/179] =?UTF-8?q?WxPayUnifiedOrderRequest=E9=87=8C?= =?UTF-8?q?=E7=9A=84builder=E7=B1=BB=E6=B7=BB=E5=8A=A0=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=9A=84=E4=B8=A4=E4=B8=AA=E5=AD=90=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=95=86=E7=9A=84=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/WxPayUnifiedOrderRequest.java | 146 +++++++++--------- .../service/impl/WxPayServiceImplTest.java | 5 +- 2 files changed, 72 insertions(+), 79 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java index 48b059d36a..16855d8e18 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java @@ -274,8 +274,33 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { @XStreamAlias("openid") private String openid; - public static WxUnifiedOrderRequestBuilder builder() { - return new WxUnifiedOrderRequestBuilder(); + private WxPayUnifiedOrderRequest(Builder builder) { + setAppid(builder.appid); + setDeviceInfo(builder.deviceInfo); + setMchId(builder.mchId); + setBody(builder.body); + setSubAppId(builder.subAppId); + setSubMchId(builder.subMchId); + setNonceStr(builder.nonceStr); + setSign(builder.sign); + setDetail(builder.detail); + setAttach(builder.attach); + setOutTradeNo(builder.outTradeNo); + setFeeType(builder.feeType); + setTotalFee(builder.totalFee); + setSpbillCreateIp(builder.spbillCreateIp); + setTimeStart(builder.timeStart); + setTimeExpire(builder.timeExpire); + setGoodsTag(builder.goodsTag); + setNotifyURL(builder.notifyURL); + setTradeType(builder.tradeType); + setProductId(builder.productId); + setLimitPay(builder.limitPay); + setOpenid(builder.openid); + } + + public static Builder newBuilder() { + return new Builder(); } public String getDeviceInfo() { @@ -445,13 +470,15 @@ public void checkAndSign(WxPayConfig config) throws WxErrorException { super.checkAndSign(config); } - public static class WxUnifiedOrderRequestBuilder { + public static final class Builder { private String appid; - private String mchId; private String deviceInfo; + private String mchId; + private String body; + private String subAppId; + private String subMchId; private String nonceStr; private String sign; - private String body; private String detail; private String attach; private String outTradeNo; @@ -467,154 +494,121 @@ public static class WxUnifiedOrderRequestBuilder { private String limitPay; private String openid; - public WxUnifiedOrderRequestBuilder appid(String appid) { + private Builder() { + } + + public Builder appid(String appid) { this.appid = appid; return this; } - public WxUnifiedOrderRequestBuilder mchId(String mchId) { + public Builder deviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + return this; + } + + public Builder mchId(String mchId) { this.mchId = mchId; return this; } - public WxUnifiedOrderRequestBuilder deviceInfo(String deviceInfo) { - this.deviceInfo = deviceInfo; + public Builder body(String body) { + this.body = body; return this; } - public WxUnifiedOrderRequestBuilder nonceStr(String nonceStr) { - this.nonceStr = nonceStr; + public Builder subAppId(String subAppId) { + this.subAppId = subAppId; return this; } - public WxUnifiedOrderRequestBuilder sign(String sign) { - this.sign = sign; + public Builder subMchId(String subMchId) { + this.subMchId = subMchId; return this; } - public WxUnifiedOrderRequestBuilder body(String body) { - this.body = body; + public Builder nonceStr(String nonceStr) { + this.nonceStr = nonceStr; + return this; + } + + public Builder sign(String sign) { + this.sign = sign; return this; } - public WxUnifiedOrderRequestBuilder detail(String detail) { + public Builder detail(String detail) { this.detail = detail; return this; } - public WxUnifiedOrderRequestBuilder attach(String attach) { + public Builder attach(String attach) { this.attach = attach; return this; } - public WxUnifiedOrderRequestBuilder outTradeNo(String outTradeNo) { + public Builder outTradeNo(String outTradeNo) { this.outTradeNo = outTradeNo; return this; } - public WxUnifiedOrderRequestBuilder feeType(String feeType) { + public Builder feeType(String feeType) { this.feeType = feeType; return this; } - public WxUnifiedOrderRequestBuilder totalFee(Integer totalFee) { + public Builder totalFee(Integer totalFee) { this.totalFee = totalFee; return this; } - public WxUnifiedOrderRequestBuilder spbillCreateIp(String spbillCreateIp) { + public Builder spbillCreateIp(String spbillCreateIp) { this.spbillCreateIp = spbillCreateIp; return this; } - public WxUnifiedOrderRequestBuilder timeStart(String timeStart) { + public Builder timeStart(String timeStart) { this.timeStart = timeStart; return this; } - public WxUnifiedOrderRequestBuilder timeExpire(String timeExpire) { + public Builder timeExpire(String timeExpire) { this.timeExpire = timeExpire; return this; } - public WxUnifiedOrderRequestBuilder goodsTag(String goodsTag) { + public Builder goodsTag(String goodsTag) { this.goodsTag = goodsTag; return this; } - public WxUnifiedOrderRequestBuilder notifyURL(String notifyURL) { + public Builder notifyURL(String notifyURL) { this.notifyURL = notifyURL; return this; } - public WxUnifiedOrderRequestBuilder tradeType(String tradeType) { + public Builder tradeType(String tradeType) { this.tradeType = tradeType; return this; } - public WxUnifiedOrderRequestBuilder productId(String productId) { + public Builder productId(String productId) { this.productId = productId; return this; } - public WxUnifiedOrderRequestBuilder limitPay(String limitPay) { + public Builder limitPay(String limitPay) { this.limitPay = limitPay; return this; } - public WxUnifiedOrderRequestBuilder openid(String openid) { + public Builder openid(String openid) { this.openid = openid; return this; } - public WxUnifiedOrderRequestBuilder from(WxPayUnifiedOrderRequest origin) { - this.appid(origin.appid); - this.mchId(origin.mchId); - this.deviceInfo(origin.deviceInfo); - this.nonceStr(origin.nonceStr); - this.sign(origin.sign); - this.body(origin.body); - this.detail(origin.detail); - this.attach(origin.attach); - this.outTradeNo(origin.outTradeNo); - this.feeType(origin.feeType); - this.totalFee(origin.totalFee); - this.spbillCreateIp(origin.spbillCreateIp); - this.timeStart(origin.timeStart); - this.timeExpire(origin.timeExpire); - this.goodsTag(origin.goodsTag); - this.notifyURL(origin.notifyURL); - this.tradeType(origin.tradeType); - this.productId(origin.productId); - this.limitPay(origin.limitPay); - this.openid(origin.openid); - return this; - } - public WxPayUnifiedOrderRequest build() { - WxPayUnifiedOrderRequest m = new WxPayUnifiedOrderRequest(); - m.appid = this.appid; - m.mchId = this.mchId; - m.deviceInfo = this.deviceInfo; - m.nonceStr = this.nonceStr; - m.sign = this.sign; - m.body = this.body; - m.detail = this.detail; - m.attach = this.attach; - m.outTradeNo = this.outTradeNo; - m.feeType = this.feeType; - m.totalFee = this.totalFee; - m.spbillCreateIp = this.spbillCreateIp; - m.timeStart = this.timeStart; - m.timeExpire = this.timeExpire; - m.goodsTag = this.goodsTag; - m.notifyURL = this.notifyURL; - m.tradeType = this.tradeType; - m.productId = this.productId; - m.limitPay = this.limitPay; - m.openid = this.openid; - return m; + return new WxPayUnifiedOrderRequest(this); } } - } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java index 685337c768..e40c6dc43c 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java @@ -12,7 +12,6 @@ import org.slf4j.LoggerFactory; import org.testng.annotations.*; -import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; @@ -35,7 +34,7 @@ public class WxPayServiceImplTest { @Test public void testGetPayInfo() throws Exception { - Map payInfo = this.payService.getPayInfo(WxPayUnifiedOrderRequest.builder() + Map payInfo = this.payService.getPayInfo(WxPayUnifiedOrderRequest.newBuilder() .body("我去") .totalFee(1) .spbillCreateIp("111111") @@ -136,7 +135,7 @@ public void testQueryRedpack() throws Exception { @Test public void testUnifiedOrder() throws WxErrorException { WxPayUnifiedOrderResult result = this.payService - .unifiedOrder(WxPayUnifiedOrderRequest.builder() + .unifiedOrder(WxPayUnifiedOrderRequest.newBuilder() .body("我去") .totalFee(1) .spbillCreateIp("111111") From ea131978449c1b13ac3a8aa0b7e514ba01cf76c9 Mon Sep 17 00:00:00 2001 From: Bob Date: Tue, 6 Jun 2017 16:36:18 +0800 Subject: [PATCH 060/179] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=9A=E6=91=87=E4=B8=80=E6=91=87=E5=91=A8=E8=BE=B9=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E8=AE=BE=E5=A4=87=E5=8F=8A=E7=94=A8=E6=88=B7=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=20(#243)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #240 --- .../me/chanjar/weixin/mp/api/WxMpService.java | 6 + .../weixin/mp/api/WxMpShakeService.java | 27 +++ .../mp/api/impl/AbstractWxMpServiceImpl.java | 6 + .../mp/api/impl/WxMpShakeServiceImpl.java | 39 +++++ .../weixin/mp/bean/WxMpShakeInfoResult.java | 164 ++++++++++++++++++ .../weixin/mp/bean/WxMpShakeQuery.java | 41 +++++ .../mp/api/impl/WxMpShakeServiceImplTest.java | 31 ++++ 7 files changed, 314 insertions(+) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeQuery.java create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImplTest.java diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index 33a4066b60..71a5413523 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -409,6 +409,12 @@ public interface WxMpService { */ WxMpDeviceService getDeviceService(); + /** + * 返回摇一摇周边相关接口方法的实现类对象,以方便调用其各个接口 + * + * @return WxMpShakeService + */ + WxMpShakeService getShakeService(); /** * 初始化http请求对象 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java new file mode 100644 index 0000000000..87a6747af5 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java @@ -0,0 +1,27 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.bean.WxMpShakeInfoResult; +import me.chanjar.weixin.mp.bean.WxMpShakeQuery; + +/** + * 摇一摇周边的相关接口 + * + * @author rememberber + */ +public interface WxMpShakeService { + + /** + *
+   * 获取设备及用户信息
+ * 获取设备信息,包括UUID、major、minor,以及距离、openID等信息。 + * 详情请见: https://mp.weixin.qq.com/wiki?action=doc&id=mp1443447963 + * http请求方式: POST(请使用https协议) + * 接口地址:https://api.weixin.qq.com/shakearound/user/getshakeinfo?access_token=ACCESS_TOKE + *
+ * + * @param wxMpShakeQuery 查询参数 + */ + WxMpShakeInfoResult getShakeInfo(WxMpShakeQuery wxMpShakeQuery) throws WxErrorException; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java index 527f6fe2e1..e1dfd83f44 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java @@ -41,6 +41,7 @@ public abstract class AbstractWxMpServiceImpl implements WxMpService, Requ private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this); private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); + private WxMpShakeService shakeService = new WxMpShakeServiceImpl(this); private int retrySleepMillis = 1000; private int maxRetryTimes = 5; @@ -394,4 +395,9 @@ public WxMpTemplateMsgService getTemplateMsgService() { public WxMpDeviceService getDeviceService() { return this.deviceService; } + + @Override + public WxMpShakeService getShakeService(){ + return this.shakeService; + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java new file mode 100644 index 0000000000..bee636fd54 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.mp.api.impl; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.WxMpShakeService; +import me.chanjar.weixin.mp.bean.WxMpShakeInfoResult; +import me.chanjar.weixin.mp.bean.WxMpShakeQuery; + +/** + * Created by rememberber on 2017/6/5. + * @author rememberber + */ +public class WxMpShakeServiceImpl implements WxMpShakeService { + + private WxMpService wxMpService; + + public WxMpShakeServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + /** + *
+   * 获取设备及用户信息
+ * 获取设备信息,包括UUID、major、minor,以及距离、openID等信息。 + * 详情请见: https://mp.weixin.qq.com/wiki?action=doc&id=mp1443447963 + * http请求方式: POST(请使用https协议) + * 接口地址:https://api.weixin.qq.com/shakearound/user/getshakeinfo?access_token=ACCESS_TOKE + *
+ * + * @param wxMpShakeQuery 查询参数 + */ + @Override + public WxMpShakeInfoResult getShakeInfo(WxMpShakeQuery wxMpShakeQuery) throws WxErrorException { + String url = "https://api.weixin.qq.com/shakearound/user/getshakeinfo"; + String postData = wxMpShakeQuery.toJsonString(); + String responseContent = this.wxMpService.post(url, postData); + return WxMpShakeInfoResult.fromJson(responseContent); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java new file mode 100644 index 0000000000..ac94b457b0 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java @@ -0,0 +1,164 @@ +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * 摇一摇周边:获取设备及用户信息接口返回JSON数据接收类 + * Created by rememberber on 2017/6/5. + * + * @author rememberber + */ +public class WxMpShakeInfoResult implements Serializable { + + private Integer errcode; + + private String errmsg; + + private Data data; + + public static WxMpShakeInfoResult fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpShakeInfoResult.class); + } + + public class Data { + + private String page_id; + + private String openid; + + private String poi_id; + + private String brand_userame; + + private BeaconInfo beacon_info; + + public class BeaconInfo { + + private double distance; + + private Integer major; + + private Integer measure_power; + + private Integer minor; + + private Integer rssi; + + private String uuid; + + public double getDistance() { + return distance; + } + + public void setDistance(double distance) { + this.distance = distance; + } + + public Integer getMajor() { + return major; + } + + public void setMajor(Integer major) { + this.major = major; + } + + public Integer getMeasure_power() { + return measure_power; + } + + public void setMeasure_power(Integer measure_power) { + this.measure_power = measure_power; + } + + public Integer getMinor() { + return minor; + } + + public void setMinor(Integer minor) { + this.minor = minor; + } + + public Integer getRssi() { + return rssi; + } + + public void setRssi(Integer rssi) { + this.rssi = rssi; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + } + + public String getPage_id() { + return page_id; + } + + public void setPage_id(String page_id) { + this.page_id = page_id; + } + + public String getOpenid() { + return openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public String getPoi_id() { + return poi_id; + } + + public void setPoi_id(String poi_id) { + this.poi_id = poi_id; + } + + public BeaconInfo getBeacon_info() { + return beacon_info; + } + + public void setBeacon_info(BeaconInfo beacon_info) { + this.beacon_info = beacon_info; + } + + public String getBrand_userame() { + return brand_userame; + } + + public void setBrand_userame(String brand_userame) { + this.brand_userame = brand_userame; + } + } + + public Integer getErrcode() { + return errcode; + } + + public void setErrcode(Integer errcode) { + this.errcode = errcode; + } + + public String getErrmsg() { + return errmsg; + } + + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } + + public Data getData() { + return data; + } + + public void setData(Data data) { + this.data = data; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeQuery.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeQuery.java new file mode 100644 index 0000000000..bb9d326fad --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeQuery.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.mp.bean; + +import com.google.gson.Gson; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by rememberber on 2017/6/5. + * + * @author rememberber + */ +public class WxMpShakeQuery { + + private String ticket; + + private int needPoi; + + public String toJsonString() { + Map map = new HashMap<>(); + map.put("ticket", this.ticket); + map.put("need_poi", this.needPoi); + return new Gson().toJson(map); + } + + public String getTicket() { + return ticket; + } + + public void setTicket(String ticket) { + this.ticket = ticket; + } + + public int getNeedPoi() { + return needPoi; + } + + public void setNeedPoi(int needPoi) { + this.needPoi = needPoi; + } +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImplTest.java new file mode 100644 index 0000000000..f608cd19b0 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImplTest.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.test.ApiTestModule; +import me.chanjar.weixin.mp.bean.WxMpShakeInfoResult; +import me.chanjar.weixin.mp.bean.WxMpShakeQuery; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +/** + * 测试摇一摇周边相关的接口 + * + * @author rememberber + */ +@Test(groups = "userAPI") +@Guice(modules = ApiTestModule.class) +public class WxMpShakeServiceImplTest { + @Inject + private WxMpService wxService; + + public void testGetShakeInfo() throws Exception { + WxMpShakeQuery wxMpShakeQuery = new WxMpShakeQuery(); + wxMpShakeQuery.setTicket("b87db7df490e5cbe4f598272f77f46be"); + wxMpShakeQuery.setNeedPoi(1); + WxMpShakeInfoResult wxMpShakeInfoResult = this.wxService.getShakeService().getShakeInfo(wxMpShakeQuery); + + System.out.println(); + } + +} From 92c8a861993f775292117790246eacf8d0093e89 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 6 Jun 2017 18:57:52 +0800 Subject: [PATCH 061/179] =?UTF-8?q?=E5=BC=95=E5=85=A5WxPayException?= =?UTF-8?q?=EF=BC=8C=E6=9B=BF=E4=BB=A3=E5=8E=9F=E6=9C=89=E7=9A=84=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E5=A4=84=E7=90=86=E7=B1=BB=EF=BC=8C=E5=B9=B6=E5=81=9A?= =?UTF-8?q?=E7=9B=B8=E5=BA=94=E7=9A=84=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weixin-java-pay/pom.xml | 6 + .../wxpay/bean/request/WxPayBaseRequest.java | 11 +- .../bean/request/WxPayRefundRequest.java | 4 +- .../request/WxPayUnifiedOrderRequest.java | 4 +- .../wxpay/bean/result/WxPayBaseResult.java | 16 +- .../wxpay/exception/WxPayException.java | 153 ++++++++++++++++++ .../wxpay/service/WxPayService.java | 40 ++--- .../wxpay/service/impl/WxPayServiceImpl.java | 51 +++--- .../service/impl/WxPayServiceImplTest.java | 12 +- 9 files changed, 228 insertions(+), 69 deletions(-) create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 2ffacde424..f055999d71 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -27,6 +27,12 @@ org.jodd jodd-http + + + ch.qos.logback + logback-classic + test + org.testng testng diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java index 65f10f5cd2..b44822483b 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java @@ -1,6 +1,7 @@ package com.github.binarywang.wxpay.bean.request; import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.util.SignUtils; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; @@ -113,9 +114,13 @@ public static Integer yuanToFee(String yuan) { /** * 检查请求参数内容,包括必填参数以及特殊约束 */ - protected void checkFields() throws WxErrorException { + protected void checkFields() throws WxPayException { //check required fields - BeanUtils.checkRequiredFields(this); + try { + BeanUtils.checkRequiredFields(this); + } catch (WxErrorException e) { + throw new WxPayException(e.getError().getErrorMsg()); + } //check other parameters this.checkConstraints(); @@ -210,7 +215,7 @@ public String toXML() { * * @param config 支付配置对象,用于读取相应系统配置信息 */ - public void checkAndSign(WxPayConfig config) throws WxErrorException { + public void checkAndSign(WxPayConfig config) throws WxPayException { this.checkFields(); if (StringUtils.isBlank(getAppid())) { diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java index 8d80148c41..59111da5f8 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java @@ -1,9 +1,9 @@ package com.github.binarywang.wxpay.bean.request; import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.annotation.Required; -import me.chanjar.weixin.common.exception.WxErrorException; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -169,7 +169,7 @@ public static Builder newBuilder() { } @Override - public void checkAndSign(WxPayConfig config) throws WxErrorException { + public void checkAndSign(WxPayConfig config) throws WxPayException { if (StringUtils.isBlank(this.getOpUserId())) { this.setOpUserId(config.getMchId()); } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java index 16855d8e18..669f597bdd 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java @@ -1,9 +1,9 @@ package com.github.binarywang.wxpay.bean.request; import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.annotation.Required; -import me.chanjar.weixin.common.exception.WxErrorException; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -458,7 +458,7 @@ protected void checkConstraints() { } @Override - public void checkAndSign(WxPayConfig config) throws WxErrorException { + public void checkAndSign(WxPayConfig config) throws WxPayException { if (StringUtils.isBlank(this.getNotifyURL())) { this.setNotifyURL(config.getNotifyUrl()); } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java index 899703c84d..3f07a58199 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java @@ -1,13 +1,12 @@ package com.github.binarywang.wxpay.bean.result; +import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; import com.github.binarywang.wxpay.util.SignUtils; import com.google.common.base.Joiner; import com.google.common.collect.Maps; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.xml.XStreamInitializer; import org.apache.commons.lang3.StringUtils; @@ -308,12 +307,12 @@ protected Integer getXmlValueAsInt(String... path) { /** * 校验返回结果签名 */ - public void checkResult(WxPayServiceImpl wxPayService) throws WxErrorException { + public void checkResult(WxPayServiceImpl wxPayService) throws WxPayException { //校验返回结果签名 Map map = toMap(); if (getSign() != null && !SignUtils.checkSign(map, wxPayService.getConfig().getMchKey())) { this.getLogger().debug("校验结果签名失败,参数:{}", map); - throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("参数格式校验错误!").build()); + throw new WxPayException("参数格式校验错误!"); } //校验结果是否成功 @@ -336,12 +335,9 @@ public void checkResult(WxPayServiceImpl wxPayService) throws WxErrorException { errorMsg.append(",错误详情:").append(getErrCodeDes()); } - WxError error = WxError.newBuilder() - .setErrorCode(-1) - .setErrorMsg(errorMsg.toString()) - .build(); - this.getLogger().error("\n结果业务代码异常,返回結果:{},\n{}", map, error); - throw new WxErrorException(error); + this.getLogger().error("\n结果业务代码异常,返回結果:{},\n{}", + map, errorMsg.toString()); + throw WxPayException.from(this); } } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java new file mode 100644 index 0000000000..eafd8b98d3 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java @@ -0,0 +1,153 @@ +package com.github.binarywang.wxpay.exception; + +import com.github.binarywang.wxpay.bean.result.WxPayBaseResult; +import com.google.common.base.Joiner; + +/** + *
+ * 微信支付异常结果类
+ * Created by Binary Wang on 2017-6-6.
+ * 
+ */ +public class WxPayException extends Exception { + private String customErrorMsg; + /** + * 返回状态码 + */ + private String returnCode; + /** + * 返回信息 + */ + private String returnMsg; + + /** + * 业务结果 + */ + private String resultCode; + + /** + * 错误代码 + */ + private String errCode; + + /** + * 错误代码描述 + */ + private String errCodeDes; + + /** + * 微信支付返回的结果xml字符串 + */ + private String xmlString; + + public WxPayException(String customErrorMsg) { + super(customErrorMsg); + this.customErrorMsg = customErrorMsg; + } + + private WxPayException(Builder builder) { + super(builder.buildErrorMsg()); + returnCode = builder.returnCode; + returnMsg = builder.returnMsg; + resultCode = builder.resultCode; + errCode = builder.errCode; + errCodeDes = builder.errCodeDes; + xmlString = builder.xmlString; + } + + public static WxPayException from(WxPayBaseResult payBaseResult) { + return WxPayException.newBuilder() + .xmlString(payBaseResult.getXmlString()) + .returnMsg(payBaseResult.getReturnMsg()) + .returnCode(payBaseResult.getReturnCode()) + .resultCode(payBaseResult.getResultCode()) + .errCode(payBaseResult.getErrCode()) + .errCodeDes(payBaseResult.getErrCodeDes()) + .build(); + } + + public String getXmlString() { + return this.xmlString; + } + + public String getReturnCode() { + return this.returnCode; + } + + public String getReturnMsg() { + return this.returnMsg; + } + + public String getResultCode() { + return this.resultCode; + } + + public String getErrCode() { + return this.errCode; + } + + public String getErrCodeDes() { + return this.errCodeDes; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder { + private String returnCode; + private String returnMsg; + private String resultCode; + private String errCode; + private String errCodeDes; + private String xmlString; + + private Builder() { + } + + public Builder returnCode(String returnCode) { + this.returnCode = returnCode; + return this; + } + + public Builder returnMsg(String returnMsg) { + this.returnMsg = returnMsg; + return this; + } + + public Builder resultCode(String resultCode) { + this.resultCode = resultCode; + return this; + } + + public Builder errCode(String errCode) { + this.errCode = errCode; + return this; + } + + public Builder errCodeDes(String errCodeDes) { + this.errCodeDes = errCodeDes; + return this; + } + + public Builder xmlString(String xmlString) { + this.xmlString = xmlString; + return this; + } + + public WxPayException build() { + return new WxPayException(this); + } + + public String buildErrorMsg() { + return Joiner.on(",").skipNulls().join(new String[]{ + returnCode == null ? null : String.format("返回代码:[%s]", returnCode), + returnMsg == null ? null : String.format("返回信息:[%s]", returnMsg), + resultCode == null ? null : String.format("结果代码:[%s]", resultCode), + errCode == null ? null : String.format("错误代码:[%s]", errCode), + errCodeDes == null ? null : String.format("错误详情:[%s]", errCodeDes), + xmlString == null ? null : "微信返回的原始报文:\n" + xmlString, + }); + } + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index 999c733e36..f3102a3a6c 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -3,7 +3,7 @@ import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.config.WxPayConfig; -import me.chanjar.weixin.common.exception.WxErrorException; +import com.github.binarywang.wxpay.exception.WxPayException; import java.io.File; import java.util.Map; @@ -33,7 +33,7 @@ public interface WxPayService { * @param transactionId 微信订单号 * @param outTradeNo 商户系统内部的订单号,当没提供transactionId时需要传这个。 */ - WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException; + WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxPayException; /** *
@@ -49,7 +49,7 @@ public interface WxPayService {
    *
    * @param outTradeNo 商户系统内部的订单号
    */
-  WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorException;
+  WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException;
 
   /**
    * 统一下单(详见http://com.github.binarywang.wechat.pay.bean.pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
@@ -58,7 +58,7 @@ public interface WxPayService {
    *
    * @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
    */
-  WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxErrorException;
+  WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException;
 
   /**
    * 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数
@@ -66,7 +66,7 @@ public interface WxPayService {
    *
    * @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
    */
-  Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException;
+  Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxPayException;
 
   /**
    * 获取配置
@@ -88,7 +88,7 @@ public interface WxPayService {
    * @param request 请求对象
    * @return 退款操作结果
    */
-  WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException;
+  WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayException;
 
   /**
    * 
@@ -108,13 +108,13 @@ public interface WxPayService {
    * @return 退款信息
    */
   WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId)
-    throws WxErrorException;
+    throws WxPayException;
 
   /**
    * 读取支付结果通知
    * 详见http://com.github.binarywang.wechat.pay.bean.pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
    */
-  WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException;
+  WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException;
 
   /**
    * 发送微信红包给个人用户
@@ -128,7 +128,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    *
    * @param request 请求对象
    */
-  WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxErrorException;
+  WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException;
 
   /**
    * 
@@ -141,7 +141,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    *
    * @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890
    */
-  WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException;
+  WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException;
 
   /**
    * 
@@ -155,7 +155,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    *
    * @param request 请求对象
    */
-  WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException;
+  WxEntPayResult entPay(WxEntPayRequest request) throws WxPayException;
 
   /**
    * 
@@ -167,7 +167,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    *
    * @param partnerTradeNo 商户订单号
    */
-  WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException;
+  WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException;
 
   /**
    * 
@@ -225,7 +225,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    * 是否需要证书:不需要
    * 
*/ - void report(WxPayReportRequest request) throws WxErrorException; + void report(WxPayReportRequest request) throws WxPayException; /** *
@@ -246,7 +246,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    * @param deviceInfo 设备号	device_info	非必传参数,终端设备号
    * @return 保存到本地的临时文件
    */
-  WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException;
+  WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException;
 
   /**
    * 
@@ -260,7 +260,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    * 是否需要证书:不需要。
    * 
*/ - WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxErrorException; + WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException; /** *
@@ -276,7 +276,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    *  是否需要证书:请求需要双向证书。
    * 
*/ - WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxErrorException; + WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxPayException; /** *
@@ -291,7 +291,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    *
    * @param request 请求对象
    */
-  String shorturl(WxPayShorturlRequest request) throws WxErrorException;
+  String shorturl(WxPayShorturlRequest request) throws WxPayException;
 
   /**
    * 
@@ -301,7 +301,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    * @param longUrl 需要被压缩的网址
    * @see WxPayService#shorturl(WxPayShorturlRequest)
    */
-  String shorturl(String longUrl) throws WxErrorException;
+  String shorturl(String longUrl) throws WxPayException;
 
   /**
    * 
@@ -316,7 +316,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    * @param request 请求对象
    * @return openid
    */
-  String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxErrorException;
+  String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayException;
 
   /**
    * 
@@ -327,5 +327,5 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    * @return openid
    * @see WxPayService#authcode2Openid(WxPayAuthcode2OpenidRequest)
    */
-  String authcode2Openid(String authCode) throws WxErrorException;
+  String authcode2Openid(String authCode) throws WxPayException;
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
index cb49928502..f9973f0fcc 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
@@ -4,14 +4,13 @@
 import com.github.binarywang.wxpay.bean.request.*;
 import com.github.binarywang.wxpay.bean.result.*;
 import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.util.SignUtils;
 import com.google.common.collect.Maps;
 import jodd.http.HttpRequest;
 import jodd.http.HttpResponse;
 import jodd.http.net.SSLSocketHttpConnectionProvider;
-import me.chanjar.weixin.common.bean.result.WxError;
-import me.chanjar.weixin.common.exception.WxErrorException;
 import org.apache.commons.lang3.CharEncoding;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
@@ -55,7 +54,7 @@ private String getPayBaseUrl() {
   }
 
   @Override
-  public WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException {
+  public WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/secapi/pay/refund";
@@ -67,7 +66,7 @@ public WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorExcept
 
   @Override
   public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId)
-    throws WxErrorException {
+    throws WxPayException {
     WxPayRefundQueryRequest request = new WxPayRefundQueryRequest();
     request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
     request.setTransactionId(StringUtils.trimToNull(transactionId));
@@ -85,24 +84,24 @@ public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeN
   }
 
   @Override
-  public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException {
+  public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException {
     try {
       log.debug("微信支付回调参数详细:{}", xmlData);
       WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData);
       log.debug("微信支付回调结果对象:{}", result);
       result.checkResult(this);
       return result;
-    } catch (WxErrorException e) {
+    } catch (WxPayException e) {
       log.error(e.getMessage(), e);
       throw e;
     } catch (Exception e) {
       log.error(e.getMessage(), e);
-      throw new WxErrorException(WxError.newBuilder().setErrorMsg("发生异常" + e.getMessage()).build());
+      throw new WxPayException("发生异常," + e.getMessage());
     }
   }
 
   @Override
-  public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxErrorException {
+  public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendredpack";
@@ -119,7 +118,7 @@ public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throw
   }
 
   @Override
-  public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException {
+  public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException {
     WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest();
     request.setMchBillNo(mchBillNo);
     request.setBillType("MCHT");
@@ -133,7 +132,7 @@ public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorExce
   }
 
   @Override
-  public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException {
+  public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxPayException {
     WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
     request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
     request.setTransactionId(StringUtils.trimToNull(transactionId));
@@ -142,7 +141,7 @@ public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo)
     String url = this.getPayBaseUrl() + "/pay/orderquery";
     String responseContent = this.post(url, request.toXML());
     if (StringUtils.isBlank(responseContent)) {
-      throw new WxErrorException(WxError.newBuilder().setErrorMsg("无响应结果").build());
+      throw new WxPayException("无响应结果");
     }
 
     WxPayOrderQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderQueryResult.class);
@@ -152,7 +151,7 @@ public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo)
   }
 
   @Override
-  public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorException {
+  public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException {
     if (StringUtils.isBlank(outTradeNo)) {
       throw new IllegalArgumentException("out_trade_no不能为空");
     }
@@ -170,7 +169,7 @@ public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorExcepti
   }
 
   @Override
-  public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxErrorException {
+  public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/pay/unifiedorder";
@@ -181,7 +180,7 @@ public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) th
   }
 
   @Override
-  public Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException {
+  public Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxPayException {
     WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request);
     String prepayId = unifiedOrderResult.getPrepayId();
     if (StringUtils.isBlank(prepayId)) {
@@ -225,7 +224,7 @@ public Map getPayInfo(WxPayUnifiedOrderRequest request) throws W
   }
 
   @Override
-  public WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException {
+  public WxEntPayResult entPay(WxEntPayRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
     String url = this.getPayBaseUrl() + "/mmpaymkttransfers/promotion/transfers";
 
@@ -236,7 +235,7 @@ public WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException {
   }
 
   @Override
-  public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException {
+  public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException {
     WxEntPayQueryRequest request = new WxEntPayQueryRequest();
     request.setPartnerTradeNo(partnerTradeNo);
     request.checkAndSign(this.getConfig());
@@ -291,7 +290,7 @@ private byte[] createQrcode(String content, File logoFile, Integer sideLength) {
     return QrcodeUtils.createQrcode(content, sideLength, logoFile);
   }
 
-  public void report(WxPayReportRequest request) throws WxErrorException {
+  public void report(WxPayReportRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/payitil/report";
@@ -301,7 +300,7 @@ public void report(WxPayReportRequest request) throws WxErrorException {
   }
 
   @Override
-  public WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException {
+  public WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException {
     WxPayDownloadBillRequest request = new WxPayDownloadBillRequest();
     request.setBillType(billType);
     request.setBillDate(billDate);
@@ -394,7 +393,7 @@ private WxPayBillResult billInformationDeal(String responseContent) {
   }
 
   @Override
-  public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxErrorException {
+  public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/pay/micropay";
@@ -405,7 +404,7 @@ public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxError
   }
 
   @Override
-  public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxErrorException {
+  public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/secapi/pay/reverse";
@@ -416,7 +415,7 @@ public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) th
   }
 
   @Override
-  public String shorturl(WxPayShorturlRequest request) throws WxErrorException {
+  public String shorturl(WxPayShorturlRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/tools/shorturl";
@@ -427,12 +426,12 @@ public String shorturl(WxPayShorturlRequest request) throws WxErrorException {
   }
 
   @Override
-  public String shorturl(String longUrl) throws WxErrorException {
+  public String shorturl(String longUrl) throws WxPayException {
     return this.shorturl(new WxPayShorturlRequest(longUrl));
   }
 
   @Override
-  public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxErrorException {
+  public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/tools/authcodetoopenid";
@@ -443,7 +442,7 @@ public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxErro
   }
 
   @Override
-  public String authcode2Openid(String authCode) throws WxErrorException {
+  public String authcode2Openid(String authCode) throws WxPayException {
     return this.authcode2Openid(new WxPayAuthcode2OpenidRequest(authCode));
   }
 
@@ -472,7 +471,7 @@ private String post(String url, String xmlParam) {
   /**
    * ecoolper(20170418),修改为jodd-http方式
    */
-  private String postWithKey(String url, String requestStr) throws WxErrorException {
+  private String postWithKey(String url, String requestStr) throws WxPayException {
     try {
       SSLContext sslContext = this.getConfig().getSslContext();
       if (null == sslContext) {
@@ -487,7 +486,7 @@ private String postWithKey(String url, String requestStr) throws WxErrorExceptio
       return result;
     } catch (Exception e) {
       this.log.error("\n[URL]:  {}\n[PARAMS]: {}\n[EXCEPTION]: {}", url, requestStr, e.getMessage());
-      throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg(e.getMessage()).build(), e);
+      throw new WxPayException(e.getMessage());
     }
   }
 
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java
index e40c6dc43c..ac599adcb3 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java
@@ -3,11 +3,11 @@
 import com.github.binarywang.utils.qrcode.QrcodeUtils;
 import com.github.binarywang.wxpay.bean.request.*;
 import com.github.binarywang.wxpay.bean.result.*;
+import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.testbase.ApiTestModule;
 import com.github.binarywang.wxpay.testbase.XmlWxPayConfig;
 import com.google.inject.Inject;
-import me.chanjar.weixin.common.exception.WxErrorException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.*;
@@ -133,7 +133,7 @@ public void testQueryRedpack() throws Exception {
    * Test method for {@link WxPayService#unifiedOrder(WxPayUnifiedOrderRequest)}.
    */
   @Test
-  public void testUnifiedOrder() throws WxErrorException {
+  public void testUnifiedOrder() throws WxPayException {
     WxPayUnifiedOrderResult result = this.payService
       .unifiedOrder(WxPayUnifiedOrderRequest.newBuilder()
         .body("我去")
@@ -151,7 +151,7 @@ public void testUnifiedOrder() throws WxErrorException {
    * Test method for {@link WxPayService#queryOrder(java.lang.String, java.lang.String)} .
    */
   @Test
-  public void testQueryOrder() throws WxErrorException {
+  public void testQueryOrder() throws WxPayException {
     this.logger.info(this.payService.queryOrder("11212121", null).toString());
     this.logger.info(this.payService.queryOrder(null, "11111").toString());
   }
@@ -160,7 +160,7 @@ public void testQueryOrder() throws WxErrorException {
    * Test method for {@link WxPayService#closeOrder(java.lang.String)} .
    */
   @Test
-  public void testCloseOrder() throws WxErrorException {
+  public void testCloseOrder() throws WxPayException {
     this.logger.info(this.payService.closeOrder("11212121").toString());
   }
 
@@ -168,7 +168,7 @@ public void testCloseOrder() throws WxErrorException {
    * Test method for {@link WxPayService#entPay(WxEntPayRequest)}.
    */
   @Test
-  public void testEntPay() throws WxErrorException {
+  public void testEntPay() throws WxPayException {
     WxEntPayRequest request = new WxEntPayRequest();
     this.logger.info(this.payService.entPay(request).toString());
   }
@@ -177,7 +177,7 @@ public void testEntPay() throws WxErrorException {
    * Test method for {@link WxPayService#queryEntPay(java.lang.String)}.
    */
   @Test
-  public void testQueryEntPay() throws WxErrorException {
+  public void testQueryEntPay() throws WxPayException {
     this.logger.info(this.payService.queryEntPay("11212121").toString());
   }
 

From cc33de3de9325018d0ce85c3e3835e13d9829722 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Tue, 6 Jun 2017 18:59:48 +0800
Subject: [PATCH 062/179] update some files

---
 contribution.md          |  5 +++--
 readme.md                | 21 +++------------------
 weixin-java-osgi/pom.xml |  2 +-
 3 files changed, 7 insertions(+), 21 deletions(-)

diff --git a/contribution.md b/contribution.md
index cbcbb7dbb3..1b4f5a8fdc 100644
--- a/contribution.md
+++ b/contribution.md
@@ -1,8 +1,9 @@
 # 代码贡献指南
 1. 非常欢迎和感谢对本项目发起Pull Request的同学,本项目代码风格为使用2个空格代表一个Tab,因此在提交代码时请注意一下,否则很容易在IDE格式化代码后与原代码产生大量diff,这样会给其他人阅读代码带来极大的困扰。为了便于设置,本项目引入editorconfig插件,请使用eclipse的同学在贡献代码前安装相关插件,IntelliJ IDEA新版本自带支持,如果没有可自行安装插件。
 1. 本项目可以采用两种方式接受代码贡献:
-  * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择develop分支,详细步骤参考后文。
-  * 另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题,具体加入方式,请咨询QQ群管理员[![点击这里给我发消息](http://wpa.qq.com/pa?p=2:1211415707:51)](http://wpa.qq.com/msgrd?v=3&uin=1211415707&site=qq&menu=yes)。
+    * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择develop分支,详细步骤参考后文,推荐使用此种方式贡献代码。
+    * (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。
+1. 另外,提交代码前请检查代码是否已经格式化,并且保证新增加或者修改的方法都有完整的参数说明,而public方法必须拥有相应的单元测试并通过测试。
 
 
 ### PR方式贡献代码步骤
diff --git a/readme.md b/readme.md
index b55333188b..af1d9c9d8c 100644
--- a/readme.md
+++ b/readme.md
@@ -43,18 +43,17 @@
 ## 可参考的Demo项目
 #### 欢迎提供更多的Demo供新手参考:
 * https://github.com/wechat-group/weixin-java-mp-demo (公众号Demo,使用Spring MVC实现)
-* https://github.com/wechat-group/weixin-java-mp-multi-demo (支持多公众号)
-* https://github.com/wechat-group/weixin-java-tools-springmvc (公众号Demo,内含部分微信支付代码)
 * https://github.com/wechat-group/weixin-java-mp-demo-springboot (公众号Demo,使用Spring Boot实现)
+* https://github.com/wechat-group/weixin-java-tools-springmvc (公众号Demo,内含部分微信支付代码)
+* https://github.com/wechat-group/weixin-java-mp-multi-demo (支持多公众号)
 * https://github.com/wechat-group/weixin-java-pay-demo (微信支付demo) 
 * https://github.com/wechat-group/weixin-java-cp-demo (企业号demo,筹备中)
 
 ---------------------------------
-## Maven & Gradle 最新正式版本
+## Maven 最新正式版本
 
 * 微信支付:
 
-maven:
 ```xml
 
   com.github.binarywang
@@ -62,14 +61,9 @@ maven:
   2.6.0
 
 ```
-gradle:
-```groovy
-compile 'com.github.binarywang:weixin-java-pay:2.6.0'
-```
 
 * 公众号(订阅号及服务号):
 
-maven:
 ```xml
 
   com.github.binarywang
@@ -77,14 +71,9 @@ maven:
   2.6.0
 
 ```
-gradle:
-```groovy
-compile 'com.github.binarywang:weixin-java-mp:2.6.0'
-```
 
 * 企业号:
 
-maven:
 ```xml
 
   com.github.binarywang
@@ -92,7 +81,3 @@ maven:
   2.6.0
 
 ```
-gradle:
-```groovy
-compile 'com.github.binarywang:weixin-java-cp:2.6.0'
-```
diff --git a/weixin-java-osgi/pom.xml b/weixin-java-osgi/pom.xml
index 43874695de..91c84d24f3 100644
--- a/weixin-java-osgi/pom.xml
+++ b/weixin-java-osgi/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     weixin-java-parent
-    2.5.2.BETA
+    2.6.0
   
 
   weixin-java-osgi

From 563302eef65063bc16c45c1de367e976373955e7 Mon Sep 17 00:00:00 2001
From: Hyseen 
Date: Thu, 8 Jun 2017 00:14:32 +0800
Subject: [PATCH 063/179] =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=B7=AF=E7=94=B1?=
 =?UTF-8?q?=E5=99=A8=E8=B7=AF=E7=94=B1=E6=97=B6=E5=8F=AF=E4=BB=A5=E4=BC=A0?=
 =?UTF-8?q?=E5=85=A5context=20(#245)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../weixin/cp/api/WxCpMessageRouter.java      | 19 ++++++++++++++++---
 .../weixin/cp/api/WxCpMessageRouterRule.java  |  7 +++++--
 .../weixin/mp/api/WxMpMessageRouter.java      | 12 +++++++++---
 .../weixin/mp/api/WxMpMessageRouterRule.java  |  7 +++++--
 4 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
index da18e28e4f..823280107c 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
@@ -14,7 +14,9 @@
 import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -135,8 +137,9 @@ public WxCpMessageRouterRule rule() {
    * 处理微信消息
    *
    * @param wxMessage
+   * @param context
    */
-  public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) {
+  public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage, final Map context) {
     if (isDuplicateMessage(wxMessage)) {
       // 如果是重复消息,那么就不做处理
       return null;
@@ -166,12 +169,12 @@ public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) {
           this.executorService.submit(new Runnable() {
             @Override
             public void run() {
-              rule.service(wxMessage, WxCpMessageRouter.this.wxCpService, WxCpMessageRouter.this.sessionManager, WxCpMessageRouter.this.exceptionHandler);
+              rule.service(wxMessage, context, WxCpMessageRouter.this.wxCpService, WxCpMessageRouter.this.sessionManager, WxCpMessageRouter.this.exceptionHandler);
             }
           })
         );
       } else {
-        res = rule.service(wxMessage, this.wxCpService, this.sessionManager, this.exceptionHandler);
+        res = rule.service(wxMessage, context, this.wxCpService, this.sessionManager, this.exceptionHandler);
         // 在同步操作结束,session访问结束
         this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUserName());
         sessionEndAccess(wxMessage);
@@ -200,6 +203,16 @@ public void run() {
     return res;
   }
 
+
+  /**
+   * 处理微信消息
+   *
+   * @param wxMessage
+   */
+  public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) {
+    return this.route(wxMessage, new HashMap());
+  }
+
   protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) {
 
     String messageId = "";
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java
index 7bd332ad9b..aa4fe504a0 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java
@@ -229,13 +229,16 @@ protected boolean test(WxCpXmlMessage wxMessage) {
    * @return true 代表继续执行别的router,false 代表停止执行别的router
    */
   protected WxCpXmlOutMessage service(WxCpXmlMessage wxMessage,
+                                      Map context,
                                       WxCpService wxCpService,
                                       WxSessionManager sessionManager,
                                       WxErrorExceptionHandler exceptionHandler) {
 
-    try {
+    if (context == null) {
+      context = new HashMap<>();
+    }
 
-      Map context = new HashMap<>();
+    try {
       // 如果拦截器不通过
       for (WxCpMessageInterceptor interceptor : this.interceptors) {
         if (!interceptor.intercept(wxMessage, context, wxCpService, sessionManager)) {
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
index bdf1d6a3d3..5acf0040aa 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
@@ -14,7 +14,9 @@
 import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -126,7 +128,7 @@ public WxMpMessageRouterRule rule() {
   /**
    * 处理微信消息
    */
-  public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) {
+  public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map context) {
     if (isMsgDuplicated(wxMessage)) {
       // 如果是重复消息,那么就不做处理
       return null;
@@ -156,12 +158,12 @@ public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) {
           this.executorService.submit(new Runnable() {
             @Override
             public void run() {
-              rule.service(wxMessage, WxMpMessageRouter.this.wxMpService, WxMpMessageRouter.this.sessionManager, WxMpMessageRouter.this.exceptionHandler);
+              rule.service(wxMessage, context, WxMpMessageRouter.this.wxMpService, WxMpMessageRouter.this.sessionManager, WxMpMessageRouter.this.exceptionHandler);
             }
           })
         );
       } else {
-        res = rule.service(wxMessage, this.wxMpService, this.sessionManager, this.exceptionHandler);
+        res = rule.service(wxMessage, context, this.wxMpService, this.sessionManager, this.exceptionHandler);
         // 在同步操作结束,session访问结束
         this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser());
         sessionEndAccess(wxMessage);
@@ -188,6 +190,10 @@ public void run() {
     return res;
   }
 
+  public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) {
+    return this.route(wxMessage, new HashMap());
+  }
+
   protected boolean isMsgDuplicated(WxMpXmlMessage wxMessage) {
 
     StringBuilder messageId = new StringBuilder();
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java
index eda32b71a9..e44406f4b1 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java
@@ -193,13 +193,16 @@ protected boolean test(WxMpXmlMessage wxMessage) {
    * @return true 代表继续执行别的router,false 代表停止执行别的router
    */
   protected WxMpXmlOutMessage service(WxMpXmlMessage wxMessage,
+                                      Map context,
                                       WxMpService wxMpService,
                                       WxSessionManager sessionManager,
                                       WxErrorExceptionHandler exceptionHandler) {
 
-    try {
+    if (context == null) {
+      context = new HashMap<>();
+    }
 
-      Map context = new HashMap<>();
+    try {
       // 如果拦截器不通过
       for (WxMpMessageInterceptor interceptor : this.interceptors) {
         if (!interceptor.intercept(wxMessage, context, wxMpService, sessionManager)) {

From 228b3791ae350fe535954a5c4855a08875aacdd8 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sat, 10 Jun 2017 13:08:44 +0800
Subject: [PATCH 064/179] =?UTF-8?q?#247=20=E7=BB=9F=E4=B8=80=E4=B8=8B?=
 =?UTF-8?q?=E5=8D=95=E6=8E=A5=E5=8F=A3=E6=94=AF=E6=8C=81H5=E6=94=AF?=
 =?UTF-8?q?=E4=BB=98=EF=BC=8C=E5=B9=B6=E5=8E=BB=E6=8E=89=E4=BA=A4=E6=98=93?=
 =?UTF-8?q?=E7=B1=BB=E5=9E=8Btrade=5Ftype=E7=9A=84=E6=A0=A1=E9=AA=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../bean/request/WxPayUnifiedOrderRequest.java     | 10 +++++-----
 .../wxpay/bean/result/WxPayUnifiedOrderResult.java | 14 ++++++++++++++
 2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
index 669f597bdd..a5560c20df 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
@@ -27,7 +27,7 @@
  */
 @XStreamAlias("xml")
 public class WxPayUnifiedOrderRequest extends WxPayBaseRequest {
-  private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP"};
+  private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP","MWEB"};
 
   /**
    * 
@@ -443,10 +443,10 @@ public void setOpenid(String openid) {
 
   @Override
   protected void checkConstraints() {
-    if (!ArrayUtils.contains(TRADE_TYPES, this.getTradeType())) {
-      throw new IllegalArgumentException(String.format("trade_type目前必须为%s其中之一,实际值:%s",
-        Arrays.toString(TRADE_TYPES), this.getTradeType()));
-    }
+//    if (!ArrayUtils.contains(TRADE_TYPES, this.getTradeType())) {
+//      throw new IllegalArgumentException(String.format("trade_type目前必须为%s其中之一,实际值:%s",
+//        Arrays.toString(TRADE_TYPES), this.getTradeType()));
+//    }
 
     if ("JSAPI".equals(this.getTradeType()) && this.getOpenid() == null) {
       throw new IllegalArgumentException("当 trade_type是'JSAPI'时未指定openid");
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java
index f6d82bd184..92c98bda48 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java
@@ -25,6 +25,12 @@ public class WxPayUnifiedOrderResult extends WxPayBaseResult {
   @XStreamAlias("trade_type")
   private String tradeType;
 
+  /**
+   * mweb_url 支付跳转链接
+   */
+  @XStreamAlias("mweb_url")
+  private String mwebUrl;
+
   /**
    * trade_type为NATIVE时有返回,用于生成二维码,展示给用户进行扫码支付
    */
@@ -54,4 +60,12 @@ public String getCodeURL() {
   public void setCodeURL(String codeURL) {
     this.codeURL = codeURL;
   }
+
+  public String getMwebUrl() {
+    return mwebUrl;
+  }
+
+  public void setMwebUrl(String mwebUrl) {
+    this.mwebUrl = mwebUrl;
+  }
 }

From 8ed0e786db82028c01d3a491c1e2df27ca3829a8 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sat, 10 Jun 2017 15:50:08 +0800
Subject: [PATCH 065/179] =?UTF-8?q?#246=20=E4=BF=AE=E5=A4=8D=E4=BC=81?=
 =?UTF-8?q?=E4=B8=9A=E5=8F=B7=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF=E7=9B=B8?=
 =?UTF-8?q?=E5=85=B3=E5=B1=9E=E6=80=A7=EF=BC=8C=E5=AF=B9=E6=AF=94=E5=AE=9E?=
 =?UTF-8?q?=E9=99=85=E6=8E=A5=E5=8F=A3=E8=BF=94=E5=9B=9E=E5=86=85=E5=AE=B9?=
 =?UTF-8?q?=EF=BC=8C=E7=A7=BB=E9=99=A4=E5=B7=B2=E5=A4=B1=E6=95=88=E5=B1=9E?=
 =?UTF-8?q?=E6=80=A7=EF=BC=88weixinid=E3=80=81tel=EF=BC=89=EF=BC=8C?=
 =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=BC=BA=E5=A4=B1=E7=9A=84=E5=B1=9E=E6=80=A7?=
 =?UTF-8?q?=EF=BC=88telephone,=20english=5Fname,=20hide=5Fmobile=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 weixin-java-cp/pom.xml                        |  9 ++++
 .../cp/api/impl/AbstractWxCpServiceImpl.java  |  5 +-
 .../me/chanjar/weixin/cp/bean/WxCpUser.java   | 48 +++++++++++++------
 .../cp/util/json/WxCpUserGsonAdapter.java     | 29 +++++++----
 .../chanjar/weixin/cp/api/ApiTestModule.java  |  2 +-
 .../{impl/apache => }/WxCpBaseAPITest.java    | 10 ++--
 .../{impl/apache => }/WxCpBusyRetryTest.java  |  7 +--
 .../weixin/cp/api/WxCpDepartAPITest.java      | 21 ++++----
 .../weixin/cp/api/WxCpMediaAPITest.java       |  8 ++--
 .../{impl/apache => }/WxCpMessageAPITest.java |  7 +--
 .../weixin/cp/api/WxCpMessageRouterTest.java  |  5 +-
 .../chanjar/weixin/cp/api/WxCpTagAPITest.java |  7 +--
 .../weixin/cp/api/WxCpUserAPITest.java        | 28 +++++++----
 .../chanjar/weixin/cp/api/WxMenuAPITest.java  |  8 ++--
 .../weixin/cp/bean/WxCpMessageTest.java       |  4 +-
 .../weixin/cp/bean/WxCpXmlMessageTest.java    |  4 +-
 .../cp/bean/WxCpXmlOutImageMessageTest.java   |  4 +-
 .../cp/bean/WxCpXmlOutNewsMessageTest.java    |  4 +-
 .../cp/bean/WxCpXmlOutTextMessageTest.java    |  4 +-
 .../cp/bean/WxCpXmlOutVideoMessageTest.java   |  4 +-
 .../cp/bean/WxCpXmlOutVoiceMessageTest.java   |  4 +-
 .../weixin/cp/demo/WxCpDemoServer.java        |  2 +-
 weixin-java-cp/src/test/resources/testng.xml  |  6 +--
 23 files changed, 144 insertions(+), 86 deletions(-)
 rename weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/{impl/apache => }/WxCpBaseAPITest.java (78%)
 rename weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/{impl/apache => }/WxCpBusyRetryTest.java (92%)
 rename weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/{impl/apache => }/WxCpMessageAPITest.java (89%)

diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml
index 3a867c9308..def682327a 100644
--- a/weixin-java-cp/pom.xml
+++ b/weixin-java-cp/pom.xml
@@ -34,6 +34,10 @@
       redis.clients
       jedis
     
+    
+      org.slf4j
+      slf4j-api
+    
 
     
       org.testng
@@ -60,6 +64,11 @@
       jetty-servlet
       test
     
+    
+      ch.qos.logback
+      logback-classic
+      test
+    
   
 
   
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java
index 52cbc0062b..b8eebe38e7 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java
@@ -34,7 +34,7 @@
 
 public abstract class AbstractWxCpServiceImpl implements WxCpService, RequestHttp {
 
-  protected final Logger log = LoggerFactory.getLogger(AbstractWxCpServiceImpl.class);
+  protected final Logger log = LoggerFactory.getLogger(this.getClass());
 
   /**
    * 全局的是否正在刷新access token的锁
@@ -293,8 +293,7 @@ public List userList(Integer departId, Boolean fetchChild, Integer sta
     String responseContent = get(url, params);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxCpGsonBuilder.INSTANCE.create()
-      .fromJson(
-        tmpJsonElement.getAsJsonObject().get("userlist"),
+      .fromJson(        tmpJsonElement.getAsJsonObject().get("userlist"),
         new TypeToken>() {
         }.getType()
       );
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java
index a3adca9894..fcf84de91e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java
@@ -14,19 +14,21 @@
 public class WxCpUser implements Serializable {
 
   private static final long serialVersionUID = -5696099236344075582L;
-  private final List extAttrs = new ArrayList<>();
   private String userId;
   private String name;
   private Integer[] departIds;
   private String position;
   private String mobile;
   private String gender;
-  private String tel;
   private String email;
-  private String weiXinId;
   private String avatar;
   private Integer status;
   private Integer enable;
+  private Integer isLeader;
+  private final List extAttrs = new ArrayList<>();
+  private Integer hideMobile;
+  private String englishName;
+  private String telephone;
 
   public static WxCpUser fromJson(String json) {
     return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpUser.class);
@@ -80,12 +82,12 @@ public void setMobile(String mobile) {
     this.mobile = mobile;
   }
 
-  public String getTel() {
-    return this.tel;
+  public String getTelephone() {
+    return this.telephone;
   }
 
-  public void setTel(String tel) {
-    this.tel = tel;
+  public void setTelephone(String telephone) {
+    this.telephone = telephone;
   }
 
   public String getEmail() {
@@ -96,14 +98,6 @@ public void setEmail(String email) {
     this.email = email;
   }
 
-  public String getWeiXinId() {
-    return this.weiXinId;
-  }
-
-  public void setWeiXinId(String weiXinId) {
-    this.weiXinId = weiXinId;
-  }
-
   public String getAvatar() {
     return this.avatar;
   }
@@ -136,6 +130,30 @@ public List getExtAttrs() {
     return this.extAttrs;
   }
 
+  public Integer getIsLeader() {
+    return isLeader;
+  }
+
+  public void setIsLeader(Integer isLeader) {
+    this.isLeader = isLeader;
+  }
+
+  public Integer getHideMobile() {
+    return hideMobile;
+  }
+
+  public void setHideMobile(Integer hideMobile) {
+    this.hideMobile = hideMobile;
+  }
+
+  public String getEnglishName() {
+    return englishName;
+  }
+
+  public void setEnglishName(String englishName) {
+    this.englishName = englishName;
+  }
+
   public String toJson() {
     return WxCpGsonBuilder.INSTANCE.create().toJson(this);
   }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java
index 4a8a9010e8..00cdea5752 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java
@@ -24,8 +24,6 @@ public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationC
     throws JsonParseException {
     JsonObject o = json.getAsJsonObject();
     WxCpUser user = new WxCpUser();
-    user.setUserId(GsonHelper.getString(o, "userid"));
-    user.setName(GsonHelper.getString(o, "name"));
 
     if (o.get("department") != null) {
       JsonArray departJsonArray = o.get("department").getAsJsonArray();
@@ -37,14 +35,19 @@ public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationC
       user.setDepartIds(departIds);
     }
 
+    user.setUserId(GsonHelper.getString(o, "userid"));
+    user.setName(GsonHelper.getString(o, "name"));
     user.setPosition(GsonHelper.getString(o, "position"));
     user.setMobile(GsonHelper.getString(o, "mobile"));
     user.setGender(GsonHelper.getString(o, "gender"));
-    user.setTel(GsonHelper.getString(o, "tel"));
     user.setEmail(GsonHelper.getString(o, "email"));
-    user.setWeiXinId(GsonHelper.getString(o, "weixinid"));
     user.setAvatar(GsonHelper.getString(o, "avatar"));
     user.setStatus(GsonHelper.getInteger(o, "status"));
+    user.setEnable(GsonHelper.getInteger(o, "enable"));
+    user.setIsLeader(GsonHelper.getInteger(o, "isleader"));
+    user.setHideMobile(GsonHelper.getInteger(o, "hide_mobile"));
+    user.setEnglishName(GsonHelper.getString(o, "english_name"));
+    user.setTelephone(GsonHelper.getString(o, "telephone"));
 
     if (GsonHelper.isNotNull(o.get("extattr"))) {
       JsonArray attrJsonElements = o.get("extattr").getAsJsonObject().get("attrs").getAsJsonArray();
@@ -84,15 +87,9 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon
     if (user.getGender() != null) {
       o.addProperty("gender", user.getGender());
     }
-    if (user.getTel() != null) {
-      o.addProperty("tel", user.getTel());
-    }
     if (user.getEmail() != null) {
       o.addProperty("email", user.getEmail());
     }
-    if (user.getWeiXinId() != null) {
-      o.addProperty("weixinid", user.getWeiXinId());
-    }
     if (user.getAvatar() != null) {
       o.addProperty("avatar", user.getAvatar());
     }
@@ -102,6 +99,18 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon
     if (user.getEnable() != null) {
       o.addProperty("enable", user.getEnable());
     }
+    if (user.getIsLeader() != null) {
+      o.addProperty("isleader", user.getIsLeader());
+    }
+    if (user.getHideMobile() != null) {
+      o.addProperty("hide_mobile", user.getHideMobile());
+    }
+    if (user.getEnglishName() != null) {
+      o.addProperty("english_name", user.getEnglishName());
+    }
+    if (user.getTelephone() != null) {
+      o.addProperty("telephone", user.getTelephone());
+    }
     if (user.getExtAttrs().size() > 0) {
       JsonArray attrsJsonArray = new JsonArray();
       for (WxCpUser.Attr attr : user.getExtAttrs()) {
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java
index d498cc5a92..1c3fd5e7ea 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java
@@ -5,7 +5,7 @@
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
-import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBaseAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java
similarity index 78%
rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBaseAPITest.java
rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java
index b3271dc8fe..a778046a9b 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBaseAPITest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java
@@ -1,12 +1,12 @@
-package me.chanjar.weixin.cp.api.impl.apache;
+package me.chanjar.weixin.cp.api;
 
 import com.google.inject.Inject;
 import me.chanjar.weixin.common.exception.WxErrorException;
-import me.chanjar.weixin.cp.api.ApiTestModule;
-import me.chanjar.weixin.cp.api.WxCpConfigStorage;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
 import org.apache.commons.lang3.StringUtils;
-import org.testng.*;
-import org.testng.annotations.*;
+import org.testng.Assert;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
 
 /**
  * 基础API测试
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBusyRetryTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java
similarity index 92%
rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBusyRetryTest.java
rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java
index 3b8e8fa3e4..2c964d309c 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpBusyRetryTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java
@@ -1,10 +1,11 @@
-package me.chanjar.weixin.cp.api.impl.apache;
+package me.chanjar.weixin.cp.api;
 
 import me.chanjar.weixin.common.bean.result.WxError;
 import me.chanjar.weixin.common.exception.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
-import me.chanjar.weixin.cp.api.WxCpService;
-import org.testng.annotations.*;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java
index 58c142ff39..66db0ff36a 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java
@@ -2,19 +2,23 @@
 
 import com.google.inject.Inject;
 import me.chanjar.weixin.common.exception.WxErrorException;
-import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
 import me.chanjar.weixin.cp.bean.WxCpDepart;
-import org.testng.*;
-import org.testng.annotations.*;
+import org.testng.Assert;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
 
 import java.util.List;
 
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
 /**
  * 测试部门接口
  *
  * @author Daniel Qian
  */
-@Test(groups = "departAPI", dependsOnGroups = "baseAPI")
+@Test(groups = "departAPI")
 @Guice(modules = ApiTestModule.class)
 public class WxCpDepartAPITest {
 
@@ -23,6 +27,7 @@ public class WxCpDepartAPITest {
 
   protected WxCpDepart depart;
 
+  @Test
   public void testDepartCreate() throws WxErrorException {
     WxCpDepart cpDepart = new WxCpDepart();
     cpDepart.setName("子部门" + System.currentTimeMillis());
@@ -32,16 +37,16 @@ public void testDepartCreate() throws WxErrorException {
     System.out.println(departId);
   }
 
-  @Test(dependsOnMethods = "testDepartCreate")
+  @Test//(dependsOnMethods = "testDepartCreate")
   public void testDepartGet() throws WxErrorException {
     System.out.println("=================获取部门");
     List departList = this.wxCpService.departGet();
-    Assert.assertNotNull(departList);
-    Assert.assertTrue(departList.size() > 0);
+    assertNotNull(departList);
+    assertTrue(departList.size() > 0);
     for (WxCpDepart g : departList) {
       this.depart = g;
       System.out.println(this.depart.getId() + ":" + this.depart.getName());
-      Assert.assertNotNull(g.getName());
+      assertNotNull(g.getName());
     }
   }
 
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java
index b289bdbbfb..f10a8b7d3f 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java
@@ -4,9 +4,11 @@
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.exception.WxErrorException;
-import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl;
-import org.testng.*;
-import org.testng.annotations.*;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java
similarity index 89%
rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java
rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java
index d6004dee75..8b52ca8261 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/apache/WxCpMessageAPITest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java
@@ -1,11 +1,12 @@
-package me.chanjar.weixin.cp.api.impl.apache;
+package me.chanjar.weixin.cp.api;
 
 import com.google.inject.Inject;
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.exception.WxErrorException;
-import me.chanjar.weixin.cp.api.ApiTestModule;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
 import me.chanjar.weixin.cp.bean.WxCpMessage;
-import org.testng.annotations.*;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
 
 /***
  * 测试发送消息
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java
index 136109827b..678893659c 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java
@@ -5,8 +5,9 @@
 import me.chanjar.weixin.common.session.WxSessionManager;
 import me.chanjar.weixin.cp.bean.WxCpXmlMessage;
 import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage;
-import org.testng.*;
-import org.testng.annotations.*;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
 
 import java.util.Map;
 
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java
index 170f386cdb..761b1a910f 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java
@@ -1,11 +1,12 @@
 package me.chanjar.weixin.cp.api;
 
 import com.google.inject.Inject;
-import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
 import me.chanjar.weixin.cp.bean.WxCpTag;
 import me.chanjar.weixin.cp.bean.WxCpUser;
-import org.testng.*;
-import org.testng.annotations.*;
+import org.testng.Assert;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java
index 1bfb7c6060..c93cb884c1 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java
@@ -2,28 +2,30 @@
 
 import com.google.inject.Inject;
 import me.chanjar.weixin.common.exception.WxErrorException;
-import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl;
-import me.chanjar.weixin.cp.bean.WxCpDepart;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
 import me.chanjar.weixin.cp.bean.WxCpUser;
-import org.testng.*;
-import org.testng.annotations.*;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.testng.Assert;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
 
 import java.util.List;
 
+import static org.testng.Assert.assertNotEquals;
+
 /**
  * 测试用户接口
  *
  * @author Daniel Qian
  */
-@Test(groups = "userAPI", dependsOnGroups = "baseAPI")
+@Test(groups = "userAPI")
 @Guice(modules = ApiTestModule.class)
 public class WxCpUserAPITest {
 
   @Inject
   protected WxCpServiceImpl wxCpService;
 
-  protected WxCpDepart depart;
-
   public void testUserCreate() throws WxErrorException {
     WxCpUser user = new WxCpUser();
     user.setUserId("some.woman");
@@ -33,7 +35,7 @@ public void testUserCreate() throws WxErrorException {
     user.setGender("女");
     user.setMobile("13560084979");
     user.setPosition("woman");
-    user.setTel("3300393");
+    user.setTelephone("3300393");
     user.addExtAttr("爱好", "table");
     this.wxCpService.userCreate(user);
   }
@@ -56,11 +58,19 @@ public void testUserGet() throws WxErrorException {
   @Test(dependsOnMethods = "testUserGet")
   public void testDepartGetUsers() throws WxErrorException {
     List users = this.wxCpService.departGetUsers(1, true, 0);
-    Assert.assertNotEquals(users.size(), 0);
+    assertNotEquals(users.size(), 0);
   }
 
   @Test(dependsOnMethods = "testDepartGetUsers")
   public void testUserDelete() throws WxErrorException {
     this.wxCpService.userDelete("some.woman");
   }
+
+  public void testUserList() throws WxErrorException {
+    List users = this.wxCpService.userList(1, true, 0);
+    assertNotEquals(users.size(), 0);
+    for (WxCpUser user : users) {
+      System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE));
+    }
+  }
 }
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java
index cdeeadf2c4..643ba3306b 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java
@@ -5,9 +5,11 @@
 import me.chanjar.weixin.common.bean.menu.WxMenu;
 import me.chanjar.weixin.common.bean.menu.WxMenuButton;
 import me.chanjar.weixin.common.exception.WxErrorException;
-import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl;
-import org.testng.*;
-import org.testng.annotations.*;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
 
 /**
  * 测试菜单
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java
index cb3d2cdd29..f41f3a55a7 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java
@@ -3,9 +3,9 @@
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
 import me.chanjar.weixin.cp.bean.article.NewArticle;
-import org.testng.annotations.*;
+import org.testng.annotations.Test;
 
-import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
 
 @Test
 public class WxCpMessageTest {
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java
index 9a6eedf1af..74b526160b 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java
@@ -1,8 +1,8 @@
 package me.chanjar.weixin.cp.bean;
 
 import me.chanjar.weixin.common.api.WxConsts;
-import org.testng.*;
-import org.testng.annotations.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
 
 @Test
 public class WxCpXmlMessageTest {
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java
index 2660243435..6f366988eb 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java
@@ -1,7 +1,7 @@
 package me.chanjar.weixin.cp.bean;
 
-import org.testng.*;
-import org.testng.annotations.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
 
 @Test
 public class WxCpXmlOutImageMessageTest {
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java
index 2013e7a3ea..71dbf4125d 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java
@@ -1,7 +1,7 @@
 package me.chanjar.weixin.cp.bean;
 
-import org.testng.*;
-import org.testng.annotations.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
 
 @Test
 public class WxCpXmlOutNewsMessageTest {
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java
index 975eb5d178..4d73b27f5b 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java
@@ -1,7 +1,7 @@
 package me.chanjar.weixin.cp.bean;
 
-import org.testng.*;
-import org.testng.annotations.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
 
 @Test
 public class WxCpXmlOutTextMessageTest {
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java
index 5ad42ba76f..b4124c6130 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java
@@ -1,7 +1,7 @@
 package me.chanjar.weixin.cp.bean;
 
-import org.testng.*;
-import org.testng.annotations.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
 
 @Test
 public class WxCpXmlOutVideoMessageTest {
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java
index 293796011d..f414256a5f 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java
@@ -1,7 +1,7 @@
 package me.chanjar.weixin.cp.bean;
 
-import org.testng.*;
-import org.testng.annotations.*;
+import org.testng.Assert;
+import org.testng.annotations.Test;
 
 @Test
 public class WxCpXmlOutVoiceMessageTest {
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java
index 6862347ba0..9c9b50c161 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java
@@ -5,7 +5,7 @@
 import me.chanjar.weixin.cp.api.WxCpMessageHandler;
 import me.chanjar.weixin.cp.api.WxCpMessageRouter;
 import me.chanjar.weixin.cp.api.WxCpService;
-import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
 import me.chanjar.weixin.cp.bean.WxCpXmlMessage;
 import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage;
 import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage;
diff --git a/weixin-java-cp/src/test/resources/testng.xml b/weixin-java-cp/src/test/resources/testng.xml
index 04f960ed63..ba92bc0c0c 100644
--- a/weixin-java-cp/src/test/resources/testng.xml
+++ b/weixin-java-cp/src/test/resources/testng.xml
@@ -3,9 +3,9 @@
 
   
     
-      
-      
-      
+      
+      
+      
       
       
       

From 707d9b0ec7111aa49252d21bbde1363930fd3768 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sat, 10 Jun 2017 16:08:30 +0800
Subject: [PATCH 066/179] =?UTF-8?q?=E5=8F=91=E5=B8=83=E4=B8=B4=E6=97=B6?=
 =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC2.6.3.BETA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                    | 2 +-
 weixin-java-common/pom.xml | 2 +-
 weixin-java-cp/pom.xml     | 2 +-
 weixin-java-mp/pom.xml     | 2 +-
 weixin-java-pay/pom.xml    | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/pom.xml b/pom.xml
index 62b7e15735..ac44c2fcb7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
   4.0.0
   com.github.binarywang
   weixin-java-parent
-  2.6.2.BETA
+  2.6.3.BETA
   pom
   WeiXin Java Tools - Parent
   微信公众号、企业号上级POM
diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml
index 9903d4d5f7..72f213bcfd 100644
--- a/weixin-java-common/pom.xml
+++ b/weixin-java-common/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     weixin-java-parent
-    2.6.2.BETA
+    2.6.3.BETA
   
 
   weixin-java-common
diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml
index def682327a..a9322b57ba 100644
--- a/weixin-java-cp/pom.xml
+++ b/weixin-java-cp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     weixin-java-parent
-    2.6.2.BETA
+    2.6.3.BETA
   
 
   weixin-java-cp
diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml
index 912a585cb5..4bad07879b 100644
--- a/weixin-java-mp/pom.xml
+++ b/weixin-java-mp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     weixin-java-parent
-    2.6.2.BETA
+    2.6.3.BETA
   
   weixin-java-mp
   WeiXin Java Tools - MP
diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
index f055999d71..5dcd243e1e 100644
--- a/weixin-java-pay/pom.xml
+++ b/weixin-java-pay/pom.xml
@@ -5,7 +5,7 @@
   
     weixin-java-parent
     com.github.binarywang
-    2.6.2.BETA
+    2.6.3.BETA
   
   4.0.0
 

From e3c5dd66d46a6c921aeea44607822eaf3ae6a7b8 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sat, 10 Jun 2017 16:09:07 +0800
Subject: [PATCH 067/179] Create readme.md

---
 readme.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/readme.md b/readme.md
index af1d9c9d8c..977d1ad479 100644
--- a/readme.md
+++ b/readme.md
@@ -46,8 +46,8 @@
 * https://github.com/wechat-group/weixin-java-mp-demo-springboot (公众号Demo,使用Spring Boot实现)
 * https://github.com/wechat-group/weixin-java-tools-springmvc (公众号Demo,内含部分微信支付代码)
 * https://github.com/wechat-group/weixin-java-mp-multi-demo (支持多公众号)
-* https://github.com/wechat-group/weixin-java-pay-demo (微信支付demo) 
-* https://github.com/wechat-group/weixin-java-cp-demo (企业号demo,筹备中)
+* https://github.com/wechat-group/weixin-java-pay-demo (微信支付Demo) 
+* https://github.com/wechat-group/weixin-java-cp-demo (企业号Demo)
 
 ---------------------------------
 ## Maven 最新正式版本

From 23a8afee7614c12a738f8f8fe5bdb2ac4fe2cadf Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sat, 10 Jun 2017 16:11:28 +0800
Subject: [PATCH 068/179] Create readme.md

---
 readme.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/readme.md b/readme.md
index 977d1ad479..504f2becd6 100644
--- a/readme.md
+++ b/readme.md
@@ -42,12 +42,12 @@
 ---------------------------------
 ## 可参考的Demo项目
 #### 欢迎提供更多的Demo供新手参考:
+* https://github.com/wechat-group/weixin-java-pay-demo (微信支付Demo) 
+* https://github.com/wechat-group/weixin-java-cp-demo (企业号Demo)
 * https://github.com/wechat-group/weixin-java-mp-demo (公众号Demo,使用Spring MVC实现)
 * https://github.com/wechat-group/weixin-java-mp-demo-springboot (公众号Demo,使用Spring Boot实现)
 * https://github.com/wechat-group/weixin-java-tools-springmvc (公众号Demo,内含部分微信支付代码)
 * https://github.com/wechat-group/weixin-java-mp-multi-demo (支持多公众号)
-* https://github.com/wechat-group/weixin-java-pay-demo (微信支付Demo) 
-* https://github.com/wechat-group/weixin-java-cp-demo (企业号Demo)
 
 ---------------------------------
 ## Maven 最新正式版本

From 26272bb7e5b06c999d4c9444c70a38d23ba1453f Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sat, 10 Jun 2017 17:02:14 +0800
Subject: [PATCH 069/179] refactor some packages and class files name

---
 .../weixin/common/util/http/HttpType.java     |  2 +-
 .../http/MediaDownloadRequestExecutor.java    | 14 ++++++-------
 .../util/http/MediaUploadRequestExecutor.java | 14 ++++++-------
 .../common/util/http/RequestExecutor.java     |  2 +-
 .../util/http/SimpleGetRequestExecutor.java   | 18 ++++++++---------
 .../util/http/SimplePostRequestExecutor.java  | 14 ++++++-------
 ...heHttpClientSimpleGetRequestExecutor.java} |  4 ++--
 ...JoddHttpMediaDownloadRequestExecutor.java} |  4 ++--
 ...> JoddHttpMediaUploadRequestExecutor.java} |  4 ++--
 ... => JoddHttpSimpleGetRequestExecutor.java} |  4 ++--
 ...=> JoddHttpSimplePostRequestExecutor.java} |  4 ++--
 ...> OkHttpMediaDownloadRequestExecutor.java} |  4 ++--
 ... => OkHttpMediaUploadRequestExecutor.java} |  4 ++--
 ...ttpProxyInfo.java => OkHttpProxyInfo.java} | 20 +++++++++----------
 ...va => OkHttpSimpleGetRequestExecutor.java} |  4 ++--
 ...a => OkHttpSimplePostRequestExecutor.java} |  6 +++---
 ...a => WxCpServiceApacheHttpClientImpl.java} |  6 +++---
 .../weixin/cp/api/impl/WxCpServiceImpl.java   |  2 +-
 ...Impl.java => WxCpServiceJoddHttpImpl.java} |  6 +++---
 ...ceImpl.java => WxCpServiceOkHttpImpl.java} | 14 ++++++-------
 ...a => WxMpServiceApacheHttpClientImpl.java} |  7 +++----
 .../weixin/mp/api/impl/WxMpServiceImpl.java   |  2 +-
 ...Impl.java => WxMpServiceJoddHttpImpl.java} |  7 +++----
 ...ceImpl.java => WxMpServiceOkHttpImpl.java} | 15 +++++++-------
 .../http/MaterialDeleteRequestExecutor.java   |  6 +++---
 .../http/MaterialNewsInfoRequestExecutor.java |  6 +++---
 .../http/MaterialUploadRequestExecutor.java   |  6 +++---
 .../MaterialVideoInfoRequestExecutor.java     |  6 +++---
 ...lVoiceAndImageDownloadRequestExecutor.java |  6 +++---
 .../http/MediaImgUploadRequestExecutor.java   |  6 +++---
 .../mp/util/http/QrCodeRequestExecutor.java   |  6 +++---
 .../OkhttpMaterialDeleteRequestExecutor.java  |  4 ++--
 ...OkhttpMaterialNewsInfoRequestExecutor.java |  4 ++--
 .../OkhttpMaterialUploadRequestExecutor.java  |  4 ++--
 ...khttpMaterialVideoInfoRequestExecutor.java |  4 ++--
 ...lVoiceAndImageDownloadRequestExecutor.java |  4 ++--
 .../OkhttpMediaImgUploadRequestExecutor.java  |  4 ++--
 .../okhttp/OkhttpQrCodeRequestExecutor.java   |  4 ++--
 .../weixin/mp/api/WxMpBusyRetryTest.java      |  4 ++--
 .../weixin/mp/api/test/ApiTestModule.java     |  4 ++--
 .../weixin/mp/demo/WxMpDemoServer.java        |  4 ++--
 41 files changed, 130 insertions(+), 133 deletions(-)
 rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/{ApacheSimpleGetRequestExecutor.java => ApacheHttpClientSimpleGetRequestExecutor.java} (88%)
 rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/{JoddMediaDownloadRequestExecutor.java => JoddHttpMediaDownloadRequestExecutor.java} (92%)
 rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/{JoddMediaUploadRequestExecutor.java => JoddHttpMediaUploadRequestExecutor.java} (87%)
 rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/{JoddSimpleGetRequestExecutor.java => JoddHttpSimpleGetRequestExecutor.java} (87%)
 rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/{JoddSimplePostRequestExecutor.java => JoddHttpSimplePostRequestExecutor.java} (89%)
 rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/{OkMediaDownloadRequestExecutor.java => OkHttpMediaDownloadRequestExecutor.java} (93%)
 rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/{OkMediaUploadRequestExecutor.java => OkHttpMediaUploadRequestExecutor.java} (91%)
 rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/{OkhttpProxyInfo.java => OkHttpProxyInfo.java} (81%)
 rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/{OkSimpleGetRequestExecutor.java => OkHttpSimpleGetRequestExecutor.java} (91%)
 rename weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/{OkSimplePostRequestExecutor.java => OkHttpSimplePostRequestExecutor.java} (87%)
 rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/{apache/WxCpServiceImpl.java => WxCpServiceApacheHttpClientImpl.java} (95%)
 rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/{jodd/WxCpServiceImpl.java => WxCpServiceJoddHttpImpl.java} (93%)
 rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/{okhttp/WxCpServiceImpl.java => WxCpServiceOkHttpImpl.java} (89%)
 rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{apache/WxMpServiceImpl.java => WxMpServiceApacheHttpClientImpl.java} (94%)
 rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{jodd/WxMpServiceImpl.java => WxMpServiceJoddHttpImpl.java} (92%)
 rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{okhttp/WxMpServiceImpl.java => WxMpServiceOkHttpImpl.java} (87%)

diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java
index 5e78a6f1d0..c692eb9100 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java
@@ -4,5 +4,5 @@
  * Created by ecoolper on 2017/4/28.
  */
 public enum HttpType {
-  joddHttp, apacheHttp, okHttp;
+  JODD_HTTP, APACHE_HTTP, OK_HTTP;
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java
index 72ceeb14b4..dbfb5f8f27 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java
@@ -1,8 +1,8 @@
 package me.chanjar.weixin.common.util.http;
 
 import me.chanjar.weixin.common.util.http.apache.ApacheMediaDownloadRequestExecutor;
-import me.chanjar.weixin.common.util.http.jodd.JoddMediaDownloadRequestExecutor;
-import me.chanjar.weixin.common.util.http.okhttp.OkMediaDownloadRequestExecutor;
+import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaDownloadRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaDownloadRequestExecutor;
 
 import java.io.File;
 
@@ -22,12 +22,12 @@ public MediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
 
   public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile) {
     switch (requestHttp.getRequestType()) {
-      case apacheHttp:
+      case APACHE_HTTP:
         return new ApacheMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
-      case joddHttp:
-        return new JoddMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
-      case okHttp:
-        return new OkMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
+      case JODD_HTTP:
+        return new JoddHttpMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
+      case OK_HTTP:
+        return new OkHttpMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
       default:
         return null;
     }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
index 1352954c2a..6b883ce7cd 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
@@ -2,8 +2,8 @@
 
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.util.http.apache.ApacheMediaUploadRequestExecutor;
-import me.chanjar.weixin.common.util.http.jodd.JoddMediaUploadRequestExecutor;
-import me.chanjar.weixin.common.util.http.okhttp.OkMediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaUploadRequestExecutor;
 
 import java.io.File;
 
@@ -21,12 +21,12 @@ public MediaUploadRequestExecutor(RequestHttp requestHttp) {
 
   public static RequestExecutor create(RequestHttp requestHttp) {
     switch (requestHttp.getRequestType()) {
-      case apacheHttp:
+      case APACHE_HTTP:
         return new ApacheMediaUploadRequestExecutor(requestHttp);
-      case joddHttp:
-        return new JoddMediaUploadRequestExecutor(requestHttp);
-      case okHttp:
-        return new OkMediaUploadRequestExecutor(requestHttp);
+      case JODD_HTTP:
+        return new JoddHttpMediaUploadRequestExecutor(requestHttp);
+      case OK_HTTP:
+        return new OkHttpMediaUploadRequestExecutor(requestHttp);
       default:
         return null;
     }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java
index a31796e668..583db4f5ae 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java
@@ -54,6 +54,6 @@ public interface RequestExecutor {
    * @throws WxErrorException
    * @throws IOException
    *//*
-  T executeOkhttp(ConnectionPool pool, final OkhttpProxyInfo proxyInfo, String uri, E data) throws WxErrorException, IOException;
+  T executeOkhttp(ConnectionPool pool, final OkHttpProxyInfo proxyInfo, String uri, E data) throws WxErrorException, IOException;
 */
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java
index c7d782f50c..a7871934a9 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java
@@ -1,8 +1,8 @@
 package me.chanjar.weixin.common.util.http;
 
-import me.chanjar.weixin.common.util.http.apache.ApacheSimpleGetRequestExecutor;
-import me.chanjar.weixin.common.util.http.jodd.JoddSimpleGetRequestExecutor;
-import me.chanjar.weixin.common.util.http.okhttp.OkSimpleGetRequestExecutor;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientSimpleGetRequestExecutor;
+import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimpleGetRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimpleGetRequestExecutor;
 
 /**
  * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String
@@ -19,12 +19,12 @@ public SimpleGetRequestExecutor(RequestHttp requestHttp) {
 
   public static RequestExecutor create(RequestHttp requestHttp) {
     switch (requestHttp.getRequestType()) {
-      case apacheHttp:
-        return new ApacheSimpleGetRequestExecutor(requestHttp);
-      case joddHttp:
-        return new JoddSimpleGetRequestExecutor(requestHttp);
-      case okHttp:
-        return new OkSimpleGetRequestExecutor(requestHttp);
+      case APACHE_HTTP:
+        return new ApacheHttpClientSimpleGetRequestExecutor(requestHttp);
+      case JODD_HTTP:
+        return new JoddHttpSimpleGetRequestExecutor(requestHttp);
+      case OK_HTTP:
+        return new OkHttpSimpleGetRequestExecutor(requestHttp);
       default:
         return null;
     }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java
index a8d4d7839d..2932f24728 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java
@@ -1,8 +1,8 @@
 package me.chanjar.weixin.common.util.http;
 
 import me.chanjar.weixin.common.util.http.apache.ApacheSimplePostRequestExecutor;
-import me.chanjar.weixin.common.util.http.jodd.JoddSimplePostRequestExecutor;
-import me.chanjar.weixin.common.util.http.okhttp.OkSimplePostRequestExecutor;
+import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimplePostRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimplePostRequestExecutor;
 
 /**
  * 用装饰模式实现
@@ -19,12 +19,12 @@ public SimplePostRequestExecutor(RequestHttp requestHttp) {
 
   public static RequestExecutor create(RequestHttp requestHttp) {
     switch (requestHttp.getRequestType()) {
-      case apacheHttp:
+      case APACHE_HTTP:
         return new ApacheSimplePostRequestExecutor(requestHttp);
-      case joddHttp:
-        return new JoddSimplePostRequestExecutor(requestHttp);
-      case okHttp:
-        return new OkSimplePostRequestExecutor(requestHttp);
+      case JODD_HTTP:
+        return new JoddHttpSimplePostRequestExecutor(requestHttp);
+      case OK_HTTP:
+        return new OkHttpSimplePostRequestExecutor(requestHttp);
       default:
         return null;
     }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientSimpleGetRequestExecutor.java
similarity index 88%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientSimpleGetRequestExecutor.java
index ebc7050e3d..e47216e6cd 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientSimpleGetRequestExecutor.java
@@ -15,9 +15,9 @@
 /**
  * Created by ecoolper on 2017/5/4.
  */
-public class ApacheSimpleGetRequestExecutor extends SimpleGetRequestExecutor {
+public class ApacheHttpClientSimpleGetRequestExecutor extends SimpleGetRequestExecutor {
 
-  public ApacheSimpleGetRequestExecutor(RequestHttp requestHttp) {
+  public ApacheHttpClientSimpleGetRequestExecutor(RequestHttp requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java
similarity index 92%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaDownloadRequestExecutor.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java
index a15272bc07..edbee76678 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaDownloadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java
@@ -23,10 +23,10 @@
 /**
  * Created by ecoolper on 2017/5/5.
  */
-public class JoddMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor {
+public class JoddHttpMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor {
 
 
-  public JoddMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+  public JoddHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
     super(requestHttp, tmpDirFile);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java
similarity index 87%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaUploadRequestExecutor.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java
index 8466eead68..b4eef26a79 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java
@@ -18,8 +18,8 @@
 /**
  * Created by ecoolper on 2017/5/5.
  */
-public class JoddMediaUploadRequestExecutor extends MediaUploadRequestExecutor {
-  public JoddMediaUploadRequestExecutor(RequestHttp requestHttp) {
+public class JoddHttpMediaUploadRequestExecutor extends MediaUploadRequestExecutor {
+  public JoddHttpMediaUploadRequestExecutor(RequestHttp requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java
similarity index 87%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimpleGetRequestExecutor.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java
index 02f6aa3795..63386e77a8 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java
@@ -13,9 +13,9 @@
 /**
  * Created by ecoolper on 2017/5/4.
  */
-public class JoddSimpleGetRequestExecutor extends SimpleGetRequestExecutor {
+public class JoddHttpSimpleGetRequestExecutor extends SimpleGetRequestExecutor {
 
-  public JoddSimpleGetRequestExecutor(RequestHttp requestHttp) {
+  public JoddHttpSimpleGetRequestExecutor(RequestHttp requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java
similarity index 89%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimplePostRequestExecutor.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java
index cca45350a6..8fa349c67a 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddSimplePostRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java
@@ -16,9 +16,9 @@
 /**
  * Created by ecoolper on 2017/5/4.
  */
-public class JoddSimplePostRequestExecutor extends SimplePostRequestExecutor {
+public class JoddHttpSimplePostRequestExecutor extends SimplePostRequestExecutor {
 
-  public JoddSimplePostRequestExecutor(RequestHttp requestHttp) {
+  public JoddHttpSimplePostRequestExecutor(RequestHttp requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java
similarity index 93%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaDownloadRequestExecutor.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java
index ea9a95a9d6..97f8cb02c5 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaDownloadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java
@@ -18,10 +18,10 @@
 /**
  * Created by ecoolper on 2017/5/5.
  */
-public class OkMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor {
+public class OkHttpMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor {
 
 
-  public OkMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+  public OkHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
     super(requestHttp, tmpDirFile);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java
similarity index 91%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaUploadRequestExecutor.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java
index 6dd1596d3f..c01b373808 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java
@@ -13,9 +13,9 @@
 /**
  * Created by ecoolper on 2017/5/5.
  */
-public class OkMediaUploadRequestExecutor extends MediaUploadRequestExecutor {
+public class OkHttpMediaUploadRequestExecutor extends MediaUploadRequestExecutor {
 
-  public OkMediaUploadRequestExecutor(RequestHttp requestHttp) {
+  public OkHttpMediaUploadRequestExecutor(RequestHttp requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkhttpProxyInfo.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpProxyInfo.java
similarity index 81%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkhttpProxyInfo.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpProxyInfo.java
index daaa92f2fb..5515b0f713 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkhttpProxyInfo.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpProxyInfo.java
@@ -7,13 +7,13 @@
  * Created by ecoolper on 2017/4/26.
  * Proxy information.
  */
-public class OkhttpProxyInfo {
+public class OkHttpProxyInfo {
   private final String proxyAddress;
   private final int proxyPort;
   private final String proxyUsername;
   private final String proxyPassword;
   private final ProxyType proxyType;
-  public OkhttpProxyInfo(ProxyType proxyType, String proxyHost, int proxyPort, String proxyUser, String proxyPassword) {
+  public OkHttpProxyInfo(ProxyType proxyType, String proxyHost, int proxyPort, String proxyUser, String proxyPassword) {
     this.proxyType = proxyType;
     this.proxyAddress = proxyHost;
     this.proxyPort = proxyPort;
@@ -24,8 +24,8 @@ public OkhttpProxyInfo(ProxyType proxyType, String proxyHost, int proxyPort, Str
   /**
    * Creates directProxy.
    */
-  public static OkhttpProxyInfo directProxy() {
-    return new OkhttpProxyInfo(ProxyType.NONE, null, 0, null, null);
+  public static OkHttpProxyInfo directProxy() {
+    return new OkHttpProxyInfo(ProxyType.NONE, null, 0, null, null);
   }
 
   // ---------------------------------------------------------------- factory
@@ -33,22 +33,22 @@ public static OkhttpProxyInfo directProxy() {
   /**
    * Creates SOCKS4 proxy.
    */
-  public static OkhttpProxyInfo socks4Proxy(String proxyAddress, int proxyPort, String proxyUser) {
-    return new OkhttpProxyInfo(ProxyType.SOCKS4, proxyAddress, proxyPort, proxyUser, null);
+  public static OkHttpProxyInfo socks4Proxy(String proxyAddress, int proxyPort, String proxyUser) {
+    return new OkHttpProxyInfo(ProxyType.SOCKS4, proxyAddress, proxyPort, proxyUser, null);
   }
 
   /**
    * Creates SOCKS5 proxy.
    */
-  public static OkhttpProxyInfo socks5Proxy(String proxyAddress, int proxyPort, String proxyUser, String proxyPassword) {
-    return new OkhttpProxyInfo(ProxyType.SOCKS5, proxyAddress, proxyPort, proxyUser, proxyPassword);
+  public static OkHttpProxyInfo socks5Proxy(String proxyAddress, int proxyPort, String proxyUser, String proxyPassword) {
+    return new OkHttpProxyInfo(ProxyType.SOCKS5, proxyAddress, proxyPort, proxyUser, proxyPassword);
   }
 
   /**
    * Creates HTTP proxy.
    */
-  public static OkhttpProxyInfo httpProxy(String proxyAddress, int proxyPort, String proxyUser, String proxyPassword) {
-    return new OkhttpProxyInfo(ProxyType.HTTP, proxyAddress, proxyPort, proxyUser, proxyPassword);
+  public static OkHttpProxyInfo httpProxy(String proxyAddress, int proxyPort, String proxyUser, String proxyPassword) {
+    return new OkHttpProxyInfo(ProxyType.HTTP, proxyAddress, proxyPort, proxyUser, proxyPassword);
   }
 
   /**
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java
similarity index 91%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimpleGetRequestExecutor.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java
index ba1ba999fd..bbb5d43754 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java
@@ -11,9 +11,9 @@
 /**
  * Created by ecoolper on 2017/5/4.
  */
-public class OkSimpleGetRequestExecutor extends SimpleGetRequestExecutor {
+public class OkHttpSimpleGetRequestExecutor extends SimpleGetRequestExecutor {
 
-  public OkSimpleGetRequestExecutor(RequestHttp requestHttp) {
+  public OkHttpSimpleGetRequestExecutor(RequestHttp requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java
similarity index 87%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimplePostRequestExecutor.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java
index eed6850172..9d153117c5 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkSimplePostRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java
@@ -11,16 +11,16 @@
 /**
  * Created by ecoolper on 2017/5/4.
  */
-public class OkSimplePostRequestExecutor extends SimplePostRequestExecutor {
+public class OkHttpSimplePostRequestExecutor extends SimplePostRequestExecutor {
 
-  public OkSimplePostRequestExecutor(RequestHttp requestHttp) {
+  public OkHttpSimplePostRequestExecutor(RequestHttp requestHttp) {
     super(requestHttp);
   }
 
   @Override
   public String execute(String uri, String postEntity) throws WxErrorException, IOException {
     ConnectionPool pool = requestHttp.getRequestHttpClient();
-    final OkhttpProxyInfo proxyInfo = requestHttp.getRequestHttpProxy();
+    final OkHttpProxyInfo proxyInfo = requestHttp.getRequestHttpProxy();
 
     OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool);
     //设置代理
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
similarity index 95%
rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java
rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
index 006bb52ee1..fecb26464f 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/apache/WxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
@@ -1,4 +1,4 @@
-package me.chanjar.weixin.cp.api.impl.apache;
+package me.chanjar.weixin.cp.api.impl;
 
 
 import me.chanjar.weixin.common.bean.WxAccessToken;
@@ -18,7 +18,7 @@
 
 import java.io.IOException;
 
-public class WxCpServiceImpl extends AbstractWxCpServiceImpl {
+public class WxCpServiceApacheHttpClientImpl extends AbstractWxCpServiceImpl {
   protected CloseableHttpClient httpClient;
   protected HttpHost httpProxy;
 
@@ -34,7 +34,7 @@ public HttpHost getRequestHttpProxy() {
 
   @Override
   public HttpType getRequestType() {
-    return HttpType.apacheHttp;
+    return HttpType.APACHE_HTTP;
   }
 
   @Override
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
index f37e5396dc..ff8e149c77 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
@@ -7,5 +7,5 @@
  * @author binarywang(Binary Wang)
  * 
*/ -public class WxCpServiceImpl extends me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl{ +public class WxCpServiceImpl extends WxCpServiceApacheHttpClientImpl { } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java similarity index 93% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java index 1dc2dd0efc..5ceabd0c64 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/jodd/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.cp.api.impl.jodd; +package me.chanjar.weixin.cp.api.impl; import jodd.http.*; import me.chanjar.weixin.common.bean.WxAccessToken; @@ -8,7 +8,7 @@ import me.chanjar.weixin.cp.api.WxCpConfigStorage; import me.chanjar.weixin.cp.api.impl.AbstractWxCpServiceImpl; -public class WxCpServiceImpl extends AbstractWxCpServiceImpl { +public class WxCpServiceJoddHttpImpl extends AbstractWxCpServiceImpl { protected HttpConnectionProvider httpClient; protected ProxyInfo httpProxy; @@ -25,7 +25,7 @@ public ProxyInfo getRequestHttpProxy() { @Override public HttpType getRequestType() { - return HttpType.joddHttp; + return HttpType.JODD_HTTP; } @Override diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java similarity index 89% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java index 48f4b6707c..11411cdafc 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/okhttp/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java @@ -1,19 +1,19 @@ -package me.chanjar.weixin.cp.api.impl.okhttp; +package me.chanjar.weixin.cp.api.impl; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; -import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.cp.api.WxCpConfigStorage; import me.chanjar.weixin.cp.api.impl.AbstractWxCpServiceImpl; import okhttp3.*; import java.io.IOException; -public class WxCpServiceImpl extends AbstractWxCpServiceImpl { +public class WxCpServiceOkHttpImpl extends AbstractWxCpServiceImpl { protected ConnectionPool httpClient; - protected OkhttpProxyInfo httpProxy; + protected OkHttpProxyInfo httpProxy; @Override @@ -22,13 +22,13 @@ public ConnectionPool getRequestHttpClient() { } @Override - public OkhttpProxyInfo getRequestHttpProxy() { + public OkHttpProxyInfo getRequestHttpProxy() { return httpProxy; } @Override public HttpType getRequestType() { - return HttpType.okHttp; + return HttpType.OK_HTTP; } @Override @@ -92,7 +92,7 @@ public void initHttp() { WxCpConfigStorage configStorage = this.configStorage; if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { - httpProxy = new OkhttpProxyInfo(OkhttpProxyInfo.ProxyType.SOCKS5, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + httpProxy = new OkHttpProxyInfo(OkHttpProxyInfo.ProxyType.SOCKS5, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); } httpClient = new ConnectionPool(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java similarity index 94% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java index fdce402ed8..8e7d6da779 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/apache/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.mp.api.impl.apache; +package me.chanjar.weixin.mp.api.impl; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.result.WxError; @@ -9,7 +9,6 @@ import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.impl.AbstractWxMpServiceImpl; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -23,7 +22,7 @@ /** * apache-http方式实现 */ -public class WxMpServiceImpl extends AbstractWxMpServiceImpl { +public class WxMpServiceApacheHttpClientImpl extends AbstractWxMpServiceImpl { private CloseableHttpClient httpClient; private HttpHost httpProxy; @@ -39,7 +38,7 @@ public HttpHost getRequestHttpProxy() { @Override public HttpType getRequestType() { - return HttpType.apacheHttp; + return HttpType.APACHE_HTTP; } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java index 4482f66467..4d2017dd63 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java @@ -7,5 +7,5 @@ * @author binarywang(Binary Wang) *
*/ -public class WxMpServiceImpl extends me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl{ +public class WxMpServiceImpl extends WxMpServiceApacheHttpClientImpl { } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java similarity index 92% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java index 6f02ff80c8..bd4a525b6d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/jodd/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.mp.api.impl.jodd; +package me.chanjar.weixin.mp.api.impl; import jodd.http.*; import jodd.http.net.SocketHttpConnectionProvider; @@ -9,14 +9,13 @@ import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.impl.AbstractWxMpServiceImpl; import java.util.concurrent.locks.Lock; /** * jodd-http方式实现 */ -public class WxMpServiceImpl extends AbstractWxMpServiceImpl { +public class WxMpServiceJoddHttpImpl extends AbstractWxMpServiceImpl { private HttpConnectionProvider httpClient; private ProxyInfo httpProxy; @@ -32,7 +31,7 @@ public ProxyInfo getRequestHttpProxy() { @Override public HttpType getRequestType() { - return HttpType.joddHttp; + return HttpType.JODD_HTTP; } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java similarity index 87% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java index afa0ed7148..fbf44cb87c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/okhttp/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java @@ -1,22 +1,21 @@ -package me.chanjar.weixin.mp.api.impl.okhttp; +package me.chanjar.weixin.mp.api.impl; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.impl.AbstractWxMpServiceImpl; import okhttp3.*; import java.io.IOException; import java.util.concurrent.locks.Lock; -public class WxMpServiceImpl extends AbstractWxMpServiceImpl { +public class WxMpServiceOkHttpImpl extends AbstractWxMpServiceImpl { private ConnectionPool httpClient; - private OkhttpProxyInfo httpProxy; + private OkHttpProxyInfo httpProxy; @Override public ConnectionPool getRequestHttpClient() { @@ -24,13 +23,13 @@ public ConnectionPool getRequestHttpClient() { } @Override - public OkhttpProxyInfo getRequestHttpProxy() { + public OkHttpProxyInfo getRequestHttpProxy() { return httpProxy; } @Override public HttpType getRequestType() { - return HttpType.okHttp; + return HttpType.OK_HTTP; } @Override @@ -89,7 +88,7 @@ public void initHttp() { WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { - httpProxy = new OkhttpProxyInfo(OkhttpProxyInfo.ProxyType.SOCKS5, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + httpProxy = new OkHttpProxyInfo(OkHttpProxyInfo.ProxyType.SOCKS5, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); } httpClient = new ConnectionPool(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java index 307f55ff32..51b7a67764 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java @@ -15,11 +15,11 @@ public MaterialDeleteRequestExecutor(RequestHttp requestHttp) { public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { - case apacheHttp: + case APACHE_HTTP: return new ApacheMaterialDeleteRequestExecutor(requestHttp); - case joddHttp: + case JODD_HTTP: return new JoddMaterialDeleteRequestExecutor(requestHttp); - case okHttp: + case OK_HTTP: return new OkhttpMaterialDeleteRequestExecutor(requestHttp); default: return null; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java index 0544fbe91b..24c00fe75a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java @@ -16,11 +16,11 @@ public MaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { - case apacheHttp: + case APACHE_HTTP: return new ApacheMaterialNewsInfoRequestExecutor(requestHttp); - case joddHttp: + case JODD_HTTP: return new JoddMaterialNewsInfoRequestExecutor(requestHttp); - case okHttp: + case OK_HTTP: return new OkhttpMaterialNewsInfoRequestExecutor(requestHttp); default: //TODO 需要优化抛出异常 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java index c44b5f1607..c850d28cf9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java @@ -17,11 +17,11 @@ public MaterialUploadRequestExecutor(RequestHttp requestHttp) { public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { - case apacheHttp: + case APACHE_HTTP: return new ApacheMaterialUploadRequestExecutor(requestHttp); - case joddHttp: + case JODD_HTTP: return new JoddMaterialUploadRequestExecutor(requestHttp); - case okHttp: + case OK_HTTP: return new OkhttpMaterialUploadRequestExecutor(requestHttp); default: return null; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java index 49c984ddb5..73948052ff 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java @@ -19,11 +19,11 @@ public MaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { - case apacheHttp: + case APACHE_HTTP: return new ApacheMaterialVideoInfoRequestExecutor(requestHttp); - case joddHttp: + case JODD_HTTP: return new JoddMaterialVideoInfoRequestExecutor(requestHttp); - case okHttp: + case OK_HTTP: return new OkhttpMaterialVideoInfoRequestExecutor(requestHttp); default: return null; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java index 7c47532a24..8bf55d03e0 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java @@ -22,11 +22,11 @@ public MaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, Fil public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile) { switch (requestHttp.getRequestType()) { - case apacheHttp: + case APACHE_HTTP: return new ApacheMaterialVoiceAndImageDownloadRequestExecutor(requestHttp, tmpDirFile); - case joddHttp: + case JODD_HTTP: return new JoddMaterialVoiceAndImageDownloadRequestExecutor(requestHttp, tmpDirFile); - case okHttp: + case OK_HTTP: return new OkhttpMaterialVoiceAndImageDownloadRequestExecutor(requestHttp, tmpDirFile); default: return null; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java index dc5e037b4d..e187561fc8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java @@ -21,11 +21,11 @@ public MediaImgUploadRequestExecutor(RequestHttp requestHttp) { public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { - case apacheHttp: + case APACHE_HTTP: return new ApacheMediaImgUploadRequestExecutor(requestHttp); - case joddHttp: + case JODD_HTTP: return new JoddMediaImgUploadRequestExecutor(requestHttp); - case okHttp: + case OK_HTTP: return new OkhttpMediaImgUploadRequestExecutor(requestHttp); default: return null; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java index 3fc34d87c7..87c1920cd8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java @@ -23,11 +23,11 @@ public QrCodeRequestExecutor(RequestHttp requestHttp) { public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { - case apacheHttp: + case APACHE_HTTP: return new ApacheQrCodeRequestExecutor(requestHttp); - case joddHttp: + case JODD_HTTP: return new JoddQrCodeRequestExecutor(requestHttp); - case okHttp: + case OK_HTTP: return new OkhttpQrCodeRequestExecutor(requestHttp); default: //TODO 需要优化,最好抛出异常 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java index 17e3ae5547..61d4d18b37 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java @@ -3,7 +3,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.util.http.MaterialDeleteRequestExecutor; import okhttp3.*; @@ -12,7 +12,7 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMaterialDeleteRequestExecutor extends MaterialDeleteRequestExecutor { +public class OkhttpMaterialDeleteRequestExecutor extends MaterialDeleteRequestExecutor { public OkhttpMaterialDeleteRequestExecutor(RequestHttp requestHttp) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java index 921915fff5..d51fbbe481 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java @@ -3,7 +3,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -14,7 +14,7 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { +public class OkhttpMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { public OkhttpMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java index a1e3f6189b..27a9b5bfc7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java @@ -3,7 +3,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.bean.material.WxMpMaterial; import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; @@ -18,7 +18,7 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMaterialUploadRequestExecutor extends MaterialUploadRequestExecutor { +public class OkhttpMaterialUploadRequestExecutor extends MaterialUploadRequestExecutor { public OkhttpMaterialUploadRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java index e296a84966..90c775bac6 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java @@ -3,7 +3,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; import me.chanjar.weixin.mp.util.http.MaterialVideoInfoRequestExecutor; import okhttp3.*; @@ -13,7 +13,7 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMaterialVideoInfoRequestExecutor extends MaterialVideoInfoRequestExecutor { +public class OkhttpMaterialVideoInfoRequestExecutor extends MaterialVideoInfoRequestExecutor { public OkhttpMaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java index e6393b8267..336b3a989e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java @@ -3,7 +3,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.util.http.MaterialVoiceAndImageDownloadRequestExecutor; import okhttp3.*; @@ -17,7 +17,7 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMaterialVoiceAndImageDownloadRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { +public class OkhttpMaterialVoiceAndImageDownloadRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { public OkhttpMaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { super(requestHttp, tmpDirFile); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java index af29e532d1..3d8abd394a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java @@ -3,7 +3,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; import me.chanjar.weixin.mp.util.http.MediaImgUploadRequestExecutor; import okhttp3.*; @@ -14,7 +14,7 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMediaImgUploadRequestExecutor extends MediaImgUploadRequestExecutor { +public class OkhttpMediaImgUploadRequestExecutor extends MediaImgUploadRequestExecutor { public OkhttpMediaImgUploadRequestExecutor(RequestHttp requestHttp) { super(requestHttp); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java index 5d75c74d4d..f401b021cc 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java @@ -4,7 +4,7 @@ import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; @@ -19,7 +19,7 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpQrCodeRequestExecutor extends QrCodeRequestExecutor { +public class OkhttpQrCodeRequestExecutor extends QrCodeRequestExecutor { public OkhttpQrCodeRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java index cc4dcf9619..fc0f70b776 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java @@ -3,7 +3,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl; +import me.chanjar.weixin.mp.api.impl.WxMpServiceApacheHttpClientImpl; import org.testng.annotations.*; import java.util.concurrent.ExecutionException; @@ -16,7 +16,7 @@ public class WxMpBusyRetryTest { @DataProvider(name = "getService") public Object[][] getService() { - WxMpService service = new WxMpServiceImpl() { + WxMpService service = new WxMpServiceApacheHttpClientImpl() { @Override public synchronized T executeInternal( diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java index 2cfaec543c..036c534adc 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java @@ -6,7 +6,7 @@ import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl; +import me.chanjar.weixin.mp.api.impl.WxMpServiceApacheHttpClientImpl; import java.io.IOException; import java.io.InputStream; @@ -19,7 +19,7 @@ public void configure(Binder binder) { try (InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml")) { TestConfigStorage config = this.fromXml(TestConfigStorage.class, is1); config.setAccessTokenLock(new ReentrantLock()); - WxMpService wxService = new WxMpServiceImpl(); + WxMpService wxService = new WxMpServiceApacheHttpClientImpl(); wxService.setWxMpConfigStorage(config); binder.bind(WxMpService.class).toInstance(wxService); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java index e2c75f83d6..3e16042d7f 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java @@ -5,7 +5,7 @@ import me.chanjar.weixin.mp.api.WxMpMessageHandler; import me.chanjar.weixin.mp.api.WxMpMessageRouter; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.impl.apache.WxMpServiceImpl; +import me.chanjar.weixin.mp.api.impl.WxMpServiceApacheHttpClientImpl; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; @@ -47,7 +47,7 @@ private static void initWeixin() { .fromXml(is1); wxMpConfigStorage = config; - wxMpService = new WxMpServiceImpl(); + wxMpService = new WxMpServiceApacheHttpClientImpl(); wxMpService.setWxMpConfigStorage(config); WxMpMessageHandler logHandler = new DemoLogHandler(); From 0fe431fc78926963f9dc641072f8d3ecdf5ff4f9 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Jun 2017 17:19:10 +0800 Subject: [PATCH 070/179] =?UTF-8?q?=E7=94=9F=E6=88=90sha1=E7=AD=BE?= =?UTF-8?q?=E5=90=8D=E6=97=B6=EF=BC=8C=E5=8A=A0=E5=85=A5=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/common/util/crypto/SHA1.java | 5 +++ .../weixin/common/util/crypto/SHA1Test.java | 36 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/SHA1Test.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java index 36aa1e7e03..f2e6bd1e8d 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java @@ -1,6 +1,7 @@ package me.chanjar.weixin.common.util.crypto; import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; import java.util.Arrays; @@ -13,6 +14,10 @@ public class SHA1 { * 串接arr参数,生成sha1 digest */ public static String gen(String... arr) { + if (StringUtils.isAnyEmpty(arr)) { + throw new IllegalArgumentException("非法请求参数,有部分参数为空 : " + Arrays.toString(arr)); + } + Arrays.sort(arr); StringBuilder sb = new StringBuilder(); for (String a : arr) { diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/SHA1Test.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/SHA1Test.java new file mode 100644 index 0000000000..323fc7060e --- /dev/null +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/SHA1Test.java @@ -0,0 +1,36 @@ +package me.chanjar.weixin.common.util.crypto; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +/** + *
+ *  Created by BinaryWang on 2017/6/10.
+ * 
+ * + * @author binarywang(Binary Wang) + */ +public class SHA1Test { + @Test + public void testGen() throws Exception { + final String result = SHA1.gen("123", "345"); + assertNotNull(result); + assertEquals(result,"9f537aeb751ec72605f57f94a2f6dc3e3958e1dd"); + } + + @Test(expectedExceptions = {IllegalArgumentException.class}) + public void testGen_illegalArguments() { + final String result = SHA1.gen(null, "", "345"); + assertNotNull(result); + } + + @Test + public void testGenWithAmple() throws Exception { + final String result = SHA1.genWithAmple("123", "345"); + assertNotNull(result); + assertEquals(result,"20b896ccbd5a72dde5dbe0878ff985e4069771c6"); + } + +} From 975cfdaf77123aed8f92441ee5f67574445b8363 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Jun 2017 17:22:38 +0800 Subject: [PATCH 071/179] =?UTF-8?q?=E7=94=9F=E6=88=90sha1=E7=AD=BE?= =?UTF-8?q?=E5=90=8D=E6=97=B6=EF=BC=8C=E5=8A=A0=E5=85=A5=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/me/chanjar/weixin/common/util/crypto/SHA1.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java index f2e6bd1e8d..732d1bb85a 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java @@ -30,6 +30,10 @@ public static String gen(String... arr) { * 用&串接arr参数,生成sha1 digest */ public static String genWithAmple(String... arr) { + if (StringUtils.isAnyEmpty(arr)) { + throw new IllegalArgumentException("非法请求参数,有部分参数为空 : " + Arrays.toString(arr)); + } + Arrays.sort(arr); StringBuilder sb = new StringBuilder(); for (int i = 0; i < arr.length; i++) { From 787a4ccaada64da6d7944cb27ebd075f0b081648 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Jun 2017 17:37:57 +0800 Subject: [PATCH 072/179] =?UTF-8?q?#244=20=E4=BF=AE=E5=A4=8D=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E5=A4=9A=E5=AA=92=E4=BD=93=E6=96=87=E4=BB=B6=E6=8A=A5?= =?UTF-8?q?=E9=94=99=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/common/util/http/MediaDownloadRequestExecutor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java index dbfb5f8f27..d948859748 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java @@ -17,6 +17,7 @@ public abstract class MediaDownloadRequestExecutor implements RequestExecu protected RequestHttp requestHttp; protected File tmpDirFile; public MediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + this.requestHttp = requestHttp; this.tmpDirFile = tmpDirFile; } From 9c0e9e44fb0327d1309b583fd9c228b9b98f4b4a Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Jun 2017 22:18:47 +0800 Subject: [PATCH 073/179] =?UTF-8?q?=E6=A3=80=E6=9F=A5=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=A6=82=E6=9E=9C=E6=9C=89=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E6=89=93=E5=8D=B0=E5=87=BA=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/me/chanjar/weixin/common/util/crypto/SHA1.java | 2 +- .../me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java | 3 ++- .../me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java index 732d1bb85a..3cdc572387 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java @@ -33,7 +33,7 @@ public static String genWithAmple(String... arr) { if (StringUtils.isAnyEmpty(arr)) { throw new IllegalArgumentException("非法请求参数,有部分参数为空 : " + Arrays.toString(arr)); } - + Arrays.sort(arr); StringBuilder sb = new StringBuilder(); for (int i = 0; i < arr.length; i++) { diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java index b8eebe38e7..463125b46b 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java @@ -63,6 +63,7 @@ public boolean checkSignature(String msgSignature, String timestamp, String nonc return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data) .equals(msgSignature); } catch (Exception e) { + this.log.error("Checking signature failed, and the reason is :" + e.getMessage()); return false; } } @@ -293,7 +294,7 @@ public List userList(Integer departId, Boolean fetchChild, Integer sta String responseContent = get(url, params); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.INSTANCE.create() - .fromJson( tmpJsonElement.getAsJsonObject().get("userlist"), + .fromJson(tmpJsonElement.getAsJsonObject().get("userlist"), new TypeToken>() { }.getType() ); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java index e1dfd83f44..85d3071885 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java @@ -53,6 +53,7 @@ public boolean checkSignature(String timestamp, String nonce, String signature) return SHA1.gen(this.getWxMpConfigStorage().getToken(), timestamp, nonce) .equals(signature); } catch (Exception e) { + this.log.error("Checking signature failed, and the reason is :" + e.getMessage()); return false; } } From 007e736f741e87c9f7a4c2602c01147e4139496e Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Jun 2017 23:06:40 +0800 Subject: [PATCH 074/179] fix some code --- .../java/me/chanjar/weixin/common/util/http/RequestHttp.java | 5 ----- .../weixin/common/util/http/SimpleGetRequestExecutor.java | 5 ++--- .../chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java | 3 +-- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java index df27d44e92..efd9f99b9d 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java @@ -8,20 +8,15 @@ public interface RequestHttp { /** * 返回httpClient * - * @return */ H getRequestHttpClient(); /** * 返回httpProxy * - * @return */ P getRequestHttpProxy(); - /** - * @return - */ HttpType getRequestType(); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java index a7871934a9..e72acc9084 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java @@ -12,11 +12,10 @@ public abstract class SimpleGetRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; - public SimpleGetRequestExecutor(RequestHttp requestHttp) { + public SimpleGetRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } - public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: @@ -26,7 +25,7 @@ public static RequestExecutor create(RequestHttp requestHttp) { case OK_HTTP: return new OkHttpSimpleGetRequestExecutor(requestHttp); default: - return null; + throw new IllegalArgumentException("非法请求参数"); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java index 85d3071885..f5e4a91f9c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java @@ -210,8 +210,7 @@ public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken String url = String.format(WxMpService.OAUTH2_VALIDATE_TOKEN_URL, oAuth2AccessToken.getAccessToken(), oAuth2AccessToken.getOpenId()); try { - RequestExecutor executor = SimpleGetRequestExecutor.create(this); - executor.execute(url, null); + SimpleGetRequestExecutor.create(this).execute(url, null); } catch (IOException e) { throw new RuntimeException(e); } catch (WxErrorException e) { From ee5115697a4197afd6979ebf744350ece9f2c8fe Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 11 Jun 2017 17:05:45 +0800 Subject: [PATCH 075/179] Create contribution.md --- contribution.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contribution.md b/contribution.md index 1b4f5a8fdc..edc9e79a0b 100644 --- a/contribution.md +++ b/contribution.md @@ -1,7 +1,7 @@ # 代码贡献指南 1. 非常欢迎和感谢对本项目发起Pull Request的同学,本项目代码风格为使用2个空格代表一个Tab,因此在提交代码时请注意一下,否则很容易在IDE格式化代码后与原代码产生大量diff,这样会给其他人阅读代码带来极大的困扰。为了便于设置,本项目引入editorconfig插件,请使用eclipse的同学在贡献代码前安装相关插件,IntelliJ IDEA新版本自带支持,如果没有可自行安装插件。 1. 本项目可以采用两种方式接受代码贡献: - * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择develop分支,详细步骤参考后文,推荐使用此种方式贡献代码。 +    * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择dev分支,详细步骤参考后文,推荐使用此种方式贡献代码。 * (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。 1. 另外,提交代码前请检查代码是否已经格式化,并且保证新增加或者修改的方法都有完整的参数说明,而public方法必须拥有相应的单元测试并通过测试。 @@ -28,7 +28,7 @@ $ git push ```bash $ git remote add upstream https://github.com/wechat-group/weixin-java-tools $ git fetch upstream -$ git checkout develop -$ git rebase upstream/develop -$ git push -f origin develop +$ git checkout dev +$ git rebase upstream/dev +$ git push -f origin dev ``` From b2f8ee14477d0f54c78289b66ee5eec02617f98b Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 13 Jun 2017 19:00:49 +0800 Subject: [PATCH 076/179] =?UTF-8?q?#248=20httpclient=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E6=97=B6=E5=BF=BD=E7=95=A5=E6=8E=89=E5=AF=B9=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=99=A8=E7=AB=AF=E8=AF=81=E4=B9=A6=E7=9A=84=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=EF=BC=8C=E4=BB=A5=E9=81=BF=E5=85=8D=E6=9F=90=E4=BA=9B=E6=83=85?= =?UTF-8?q?=E5=86=B5=E4=B8=8B=E5=BE=AE=E4=BF=A1=E8=AF=B7=E6=B1=82=E4=BC=9A?= =?UTF-8?q?=E5=87=BA=E7=8E=B040029=E6=88=96443=20failed=20to=20respond?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DefaultApacheHttpClientBuilder.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java index 875f2fccb8..b328ede9af 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java @@ -14,16 +14,24 @@ import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.protocol.HttpContext; +import org.apache.http.ssl.SSLContexts; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.net.ssl.SSLContext; import java.io.IOException; +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.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -214,6 +222,7 @@ private synchronized void prepare() { this.httpClientBuilder = HttpClients.custom() .setConnectionManager(connectionManager) .setConnectionManagerShared(true) + .setSSLSocketFactory(this.buildSSLConnectionSocketFactory()) .setDefaultRequestConfig( RequestConfig.custom() .setSocketTimeout(this.soTimeout) @@ -240,6 +249,29 @@ private synchronized void prepare() { prepared.set(true); } + private SSLConnectionSocketFactory buildSSLConnectionSocketFactory() { + try { + SSLContext sslcontext = SSLContexts.custom() + //忽略掉对服务器端证书的校验 + .loadTrustMaterial(new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return true; + } + }).build(); + + return new SSLConnectionSocketFactory( + sslcontext, + new String[]{"TLSv1"}, + null, + SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) { + this.log.error(e.getMessage(), e); + } + + return null; + } + @Override public CloseableHttpClient build() { if (!prepared.get()) { From 5986fbbd25e440957f335c3307920449848ce2de Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 13 Jun 2017 19:11:47 +0800 Subject: [PATCH 077/179] =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=BC=BA=E5=B0=91=E7=9A=84logback=E4=BE=9D?= =?UTF-8?q?=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weixin-java-mp/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 4bad07879b..caa607140a 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -60,6 +60,11 @@ redis.clients jedis + + ch.qos.logback + logback-classic + test + From 34670104741b2c03fada5d1a608e77d757258fbc Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Wed, 14 Jun 2017 16:21:18 +0800 Subject: [PATCH 078/179] Add files via upload --- alipay_qrcode.jpg | Bin 0 -> 56148 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 alipay_qrcode.jpg diff --git a/alipay_qrcode.jpg b/alipay_qrcode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..105f1d87531ded493be7a057ef9c39189ca401cc GIT binary patch literal 56148 zcmdqJ1z23mwjkWNySp_`;~w1I-GT;p2ofx~y9aj-E+GjC4k5waEjS69pviO-Ip^H> z?z!*H-1%qz+5LU1OIEE~yK2=kivB+LeGP!AAR{jWfPw-5puiu%_eFpt01XKl1sMws z1&@G?jD!M*l9?WxmY$wem`$9Ok%OI;5yZkJs35|{E5pYE64MozQBu*+)Zi2`Ff&jy zRZ!PZg%E*4M@Of}!lA=src>ns@u>c{pYPoOEJQc}j1mkKH2@k53I+@6doO?l%p^1n zgx%i{96Ssx0yLzP2;BbHJ^&On3>@tD1pq1xcpN4SCipd*f_@MEzrJ8=7P&gac*@b1 zr%VVO555Pw0d1e!n(DVtpL9`T=9visp-3uJf~1ophuC4rJep`q#Qxc9F?U?mp9?^- z!+-iDpi1A_ut_JX8%hUlZlc1f*)u8q&TP~swFr+QD*$^>yqGycMSGrK(TGn(`j*yS z0}K8`QK3VcD&4mwnwF#B`lbWC2S!RmIdcDGvfA|z5ru;{Agt`RWc!8{S!+cv3@xws zB3@_K)3&yWjyvh8F{#Jr3on(v)N-yxOs6rW$A50uW1d-s!}k@GT8wO%i1}#X3wvQx zy+CVnLbHu^f^RTH)ws${&s{>B`cGzsb4GU%MwgtKx#NjevKWyb z>WrlWfg8Bb;*A=={F8~H+i1wn7C)SA^n_=GUhp*Mg6_N>E`}perZ+MZt8WILhz@2^ zh}NyX5vg`jpq42|Nmy2X;S--&m(EW8k(o9VGmxijJw*uiwo~eGX5GzvnBfJ8K|@1_ z_n+-5;JImP%-7Rzhx=vEGF^%!&H+$g=pIQvwCI{fUcn%jw-KK!D7V^pV^*7P37o5$ zFBp2ORnnEo0JG(hY>W8JHkH~zg0A--u!K*vA=~}4 z0slwZbr*eVkT2_*H{RC8KzFkIUr^+cZOZ%Kv=lJb1`mbJ1N^W2y2V14%6xn2Jd4IR zjR01C0_kIpx%S)m6^pek0rLIQjT;$}QD~f&D<9%dM65R_3lhgWO{DiSwg+M_W{54p z{J~h5C}hiCechNs3i=Q1A{oCsAI(^-Z6b(Ks^OS7uXJsA^UTC>MM>CzoR4Rl$JOD$ zamW8^-yW357dZ53Z1P#i>Im^#?v&4+!An$kY(bmdbfti{Gv{6Fm4Wf{Z38BHI#e`Q z2m7t;;RBxf3+Kzpkpw|bj)je{O)dBd7ftbms~R&`2P2tBLp`6@_q*DNlI>rVx76ZP z2$QS*BYVDQ*&v!TO^Xlvv7Fa_&jdM>eD;YqmOd1wFA6RSPLjiC3HwM5`A?*tUAGjM zQGd?kXr*}U>E%AF>a2QH{j!*b%n&~7NqV?-ZG`4*KHqcN&jU?wKg6qKTZb?8D0BMW zv>5K%IociVplkzRSX7J;MTEZ9I;?V;N zXeR}$|6WkIElb*G`Q$1n=#MF(Xvk>tnrM2ah{G3^oVfcp{{ZkVU6D)X?*MjJe8d*6 z$Nsi){rSZ<002ADf`w~&y(N!wS>}@MQT{_7w0>|Q?oWWFm|V%GCO(4_{Gz`fphb!M zjHS14yyv*jc-0M1h8EU9O}Z2U+PH^lpI6#5rM;wec%jmz5~OBPLu_fFW`gwwnH?MJ zCPGqrn=cmL!(^yUyG1*CsNHt?AU#6zr_R1$tFmaX^?urSSv zbBwe3uNbMFxGGl^e$|sAr_LRQBR5YCo$pefu4t?=qs{zSVcspbQvOGmD*1@@hI<#P zB}Z8Umd5yl9kJlAgt`uCFM>botcFlM$Gw4amKY+zCArY5r3>YgFJDr91>s6mc883V zLmKCvzB1ZronF%nO6V=@p9KJkaF6sNi=4bT*Tcla-lNlYVw7~Th{tIt&rXW(*o_P*+%U>PMQ%nNchw5kx(T{!pJ;@DOzWK@L@bk{d^6MOBWT_)}1 zqIYOrE4#fDC|BGL4@ejh6et|MMi2!+_c&E7M!z;6)%&mSqma8(7POYmy1HSg@(Q(4 zQ27$$$K+Y9mQZf>cocV~SBkxgVa{3+Gp)Y#Y3jy?VbV@B%;2q*l@5-dq>j>HbiyME z9FlyTDK5Uz;y>e`&kUd;U!IM zLH}vdU}HVvecvZwsE>583G#G2^4( z{6V%yr;YXQ?TFNI4?s`=_h;1l_3t7TGO>JC_c4=5pUEle*6viOD5WDo0e zksNE*OY;sHE(n4Q1eK~6zicQP)AWw3y|D;pH9C9bS9)G?#kIq|*I;!|_)l}#jUF7L z`fwCA3K|88{fV)p_@q(&r1gCORCKrpfe0DgXoR>{Z6S)DAaa}KyCuj>vGw`Esu1+PYLW1gZ<-{cSTxtSbyJ;@!O#YBQKH;v@$ocb-K^y04EJ zUEWhw=m^5X(=2##yvyn*h)itxH#?^Wv-5!McG2yNd)RgGPgxIC>eU5#R_zHGwv3Rj zj}P!G^ucZVUDaQ^i;|JL$5nrNK}8{VX__AO#bbb=z0ZkM`LmiKI8E!u|s)<9t=K1+@HtDxx~w-byh zJ!7D|l9!;FsNMFeO5*lrnQu@&;i-kRrN;|E&>uqc+jgltOXlsJuh=}<6Iv|E^AvV( zDiqk=UF42=5drHc)Tq-vYgs#wTq7!h<@U64JD1dhUYLAEIF}uRd~?*vR}fcN3(zo& zAW=SiZ>`;W?Vd{8vi6 zfP$f|LFQHXYo==k#oa1{Zt@m?(gU4YEzo0yTOzL|4LN`0pR&_zdbhj$e=rhri`j}I$79a&-@^1x~b?$TqP|RrDA)| z(jq3nPVHH0?s#ZmO`tvbtA;FL(;Jq~`a2?a|I{2U%bJnUu=E0jnd0s{@i*8!%r>P; zBkme&r6^UYtW|1FGter13iuVbUp7)ZA}iJY=7_1oJs62$`3~URGlzG6hW|k>FH)Pg zZ5J#!NnSKmpl*B{D)Xc6rgTBX-IwavADwlUn3!G8O5c8DYGOi zyH-Pn^7!wSw_zi4+e zhOv*OI{0aN241$jgRyh3{X#8y(s?!bGtVa9$EP2ief^BCIg{g1THf0mslj?4Ox|OH zpO2RpE)Jruvq1}R9lv@D0LUv&hvn~73s6x0osMM25AaZO)E3l#INfw+-upbNT`cqE z1nYLJaik9W;WQHBF~o;Tjr56h8)%`Sb~iE<>;@Z~UVr~9o1O%|nAx3G6J`M}`;Q`9 zH#-j`-bueRa2QMRgqiVeS(?@hd+f!a?PxTWt1F#g*E0UD*1o{~%&iB*m$6<~(2Sm^ z+==P3aR%iu^}pc3D0N3=nvObFdq_0tbdJSE@r(0@;ydo%=p#NOekm>&kr}}@!7)KE zFf%{HYN$c1mT(oZ@gl(N{K-wi{N7jCRw17cXzy?GAH56fEYRKBgk8W?UKALRzHd%W`Bq%ng*0^q80UP*vi1P9pw7lA+;0Jy{x$Ja5PpWW@O8w5zg} zo0-o5>0<$SWS|(}>x%*w{Aa#qDdneenT!wx+K3K&jwzE^Su+igGX7u)NO$pc$d9^#U=QmlJx5`13DU*wQp$L3_ zUhRXX-Z~w1U~DqxceSfYxnmmhs#)uWczoIz+YKSFiuI<&P=vj%&2Gaf)<>kBv1gH) zpzi=z)Kw1D*nrVG$dRTg=7Nky9m^=0&Mvu##sU0FLQwLv+I)ZlxFbfvg64fc(X!*lLJW4AtzKh&Dwdb; z*1W0o=PaKc$(`^lx*w5QiA4zSNrQW(QnogU5jd#ANjbs(yKpKPm@bKw%AWNHu=$Lq zu-s3Yl^c_ac;wbX_M!}GQn>pG9R@=Coufo02#3YQwA?h>w%vBYVh5>!k-%3RBcNb4 ziri=HYQ1v8r%j%-Q!<4i%i=y%QCN9#mvf@jDno+5e;35vJe2-?>|e!DcAX=Mj3+b~cR7#Y>qXA<>>q)c-ZoW3TjbB#_tx&m_yX#*9H+6zt&4`zABX?1#h5>0@q0T0 zQHywfQZPF`<#w|iiJVwhBS|<|HIiUElfkr{EL33NCYQ{E;xAU0vIV_p#3Kfh)^^0B zEvtcI_AOcoVxA`Pl%oBZ;C^lRUp{OpAA$f7v$h2%vaZUK-cedprE{3p`0)Xppa#`8 z)$n;71qVTG3Zaom>Ka;;y4yIjd%b4qAT(}vh4(U3o1Xz(W5^3kGlZ3t508e6vOz{0 z0ZL`hC6F(S##j|DLhH1ANnNY0$5#OVT1P(Q-m{K(oU}k@I%lXJd%k?m_j}v)wQA3W zElj)~nwChOqtfENEPt1Fvhhah>{;4w6j?taJh>f zz`}i(Ykn`{$jt&{>d98{f-?MU4-iB=utr;-e+MYfU11<_rMFn}zO9{Swo+@rn-#CY zEO=P)030Np1a2?tY{X2Qx5eGNBd`#0qTI_6G&5_{a_lo{7(Y&$ymbFN&jhTHX2C%Y zy4!9~P6zuAYplR9q|*J;zAqK}8Qg>)G3PhoRKib5TMoC^5J$dto+D>s@TiUzw|n}tI-#l@sjXBCe)ayHn5g|if{NhHB59~@LSx)TniS&BfnqCuS>^PpM`>7A z*NvP+zr`x@hiy_(tH@Oak?t}9U#I!bMuhL#UNS9ce?fSdp)$(?DlOSg~+Vz2R|Hn zgwX~U_|#czy7Ucljsb%v3JL0bsd?t@)UWV8;ca& zuB!sp?}-j_DfZ_--`Yrj{bsw-0=zA@w-s%;;T&OpoW5_b?O=Z{AkOn=9-$u9%n5ya zUHI`U`}S=1{=v>g+p|D?p)BVR`cdBJ+hr>)Y!RZb9@pgujElH9nr5DC+LO+%=GHaO zYL58nl+7;b9r!2VpI|YbULH8_J4rX+I@l|_JM213H@9rn8{|Lk^egMg7v0tGv zWJNFn8Q3!a%rn{t9!J|77|_PRJTErhC zU;JzrW@pUrI%8l8QkC2pySj+Cpo?e7y?ujF*ZpV0;4=8n2mk3K_Mf)?|FscvRe=)| z0DyyrhlV@=g!^O|_^JXd94;mf9tS5E7A3YC6}y-zH4TuKTRbSSKmvS+0TFz?0SXTK zJ76(-iwgSCIP)dPWAnql`IshxN38FSGa1d$X-5wlb1%P5RZKY6ZJX46(6oDGx1?K= zr4NOZ+G2j&ZKeJ(WhW-$M5SOY@;aYw*Ev7Ucfc|SKN6V@;Q;YFfKZf!rCMEXN`u_Q zF3ZHA1vgHbDyz~{LNcqmoagF;!=qL%L!8*uk3vJtG^eEgt0}Tno4j;{4SsYiB?wrc z#&!=`{aT7KvX2KS2m-#{eacjlRE3FSsZtpLF#;8C|@{xaa-Ed%y*_6!@QwGK2O7OuUhAM^^}gv%ox*XJvP;mBdqu``C|#2;_hv{!+;4V(Q}UC>Zpt@1rmL(#0H5ASoIfmNMQbu%8FvmSLrnqm**g`qz^Nf_KgIx; z^jEE?Qwt=z??d~W)HM9KkZPI(#h)b3;YJ`Dwd3wjUz;;3u-K`1(`~V*?>+ZsudU2! zu>V#L6yjLgh({n)xrfTwVV|cN{7iY^oYC>y1RGVVRXG7o`@stvl-Lbp5yEVAw=_!j(5Rt4NWaSxu>ZwH?9Q76Ud!c_-PciFAAxEQp9jPReMfE$8} zSh(LAeg`Z$_7ts;yX>}m7zwhH5unFJNdG_9uzK6=n8q)Ad3R-ha%gGwv{3#+0?l-A z@^FC*&4zdMOY?X;?n9g#xrh_-Z~jSZqf7#@sh$YR3FP@H6nG^1=-2(SLmD$FT`M(? zO1uk1d_!+22)h@za8pz`dQr(8d1EuS#wCPWn~QH%Sqv|%p8*n=56X_PSfjvX@tZ6rkm~J<);&yRqpWF ze3I&?BND`v;rhq&@oWC6EeTyRoH<13F<#Oy3x@mA*vny*tRmFL$u*IHtv!WbqUsuL zf$2-S?|XJW)(|S-1|AQ>pUR^S^5MQf$Ey5_7X_Rmv7!@k@b*C~ zXJv(7VqIdqQc216E_szF2}{a5#B3Bu*t(E|bjgcZES{5r%GpxuruyzXK#`^LZ7KcQ zVzdKkhLVg%dO60s&ex^S9vzgObi}sy*t{2DyrjX;24YXy^S_#XQ$%dgZ|@L6sQA>e zmOOGF?g|4qv0A;WV<=-MUn>0+0SHVXV?r{U1TT1*e6c?T&K+8|+^SzJEi&CZt}o`CAo@A?c?SL8X=6vZ5%uTgS4!?{ngV+Gc8qJ(Yt~=OfSs8|a1T z5sc}vVw^ZOJ~kq-8&@zXr0UhbIc8+0){N0Ty1KIb$kv@+8mNDEbNd~z-TZi{r^Ugb z6=aBC8>7=#Z9d&#H}`+Mp}Uw@`rPG3ptQ-VEK0_?_7S*Z?xsiONop)hpx!s-`X34| z5r*z?uNKYs`6VOW$2Ew=m+uk%oQh*AHum|I!nFcE2|~I%;#rGBLClnus0E*X^sS;m zFd*&ssQ*w{N2hwP+cw_)F*a{>UUo@G09jUt>!v~G-6A2`%0=!;>3P)MTua}RfCW(# zl*Qe3w|-UA`eYVh3=(y>+@A{Mu?Ikgo9F>5x&3}4z9qLGox!=JPeUt zT1}#Nge!bwe2Mane0K= z6Ms@xy`e*-#d96OJ_=X8Ek-hv{ndr6C8lNbxb~V)jHDd-%P~f}^%nViHS2#GFgN;k zYBNrS|0f84)Oa0cQKSA9FJ1z+zqnX4o`-+)C%`PyhbbH6nzS?x%^p=sBn!Hc$IMk^ zwR7#giW7ONnz-aXwHY0ozGbGGKIO6R+QUYB9;HU^`GHex5{SkrChkppNVrX^&zt*u zHt@U&ph|dVe)a2P$Y!T=K7oGhl~Bvp{^Kn^ekQ4dbD(*QbSL^eWAgBI2x;$1oq;Ha zes{ub@Rw_TqlT0@oTgX)w*K7>GYmITW3#~Xa+%cKiCkjMVg(PO`Nl$$I+)uy#@Y2Tnz@N8Z6M9%vWOU<-3B5f@Ac2#-;dT z?R9570gL4q=*mt>twbJqn7;yOsR1Bn@h4`|P(o!nnGDhgR4%Goi6oIrjT4(;sy->x zKs1gpG>%~6lAsUr7Zs{|motUt5VtM4DVZ#RHo(aqlRLPgr$J~EQL3U$J|S;t ztAwnn%DXw4Lv$)u{Cq+lwD4H%jvlu5w^P8#{F5HlSlU`ORkdUq&Zwx#O@ytNM82Vk zQ!*wh`Gi>B;9l;_zXL>8sQCA~?i-#(I(KJ|wIo-OHaKhjRy(b;6x-x1eu&b;JZY)Z8;u&7U>L$XI4M@VAQh=9BD!_DC0lL zV7-LxBPM>C$aqTbI<{%!Vjzp3)K}uNsN50~%e~tiPuJdl@G=p%SU>cgKkZM_Kjy#! zc9wHgwzn?6Ok~|cc>(=N3``{+G-V2r5H@S?>xmnPdTYarH#zC(ZtLbV&7WY*T`j9z zzAk*csRKT;KZJ=*Tj+E8ipO-~VDhlk3U}vPNvQ=@k{0;>g!L=Nz)vjUGLke@NgDFB z<8WnDGm?~V2*J)h5fN&{f+NGIH_3ByB=r*OS6nMZpOF=2n((Y@5%P{ly}@Jm6l=FQ zA(&B8QfrRsodT$__p}m~x%IS^CT5;=XBT_E|3N-+aL|&LQHB{}SkBpN7q)0UEfhcX zH`EuO^p`JDdfdn#d z9=TG)-~jm3$NsA2giV{_wp4aY{s8kyCy>cfpa1GuL`LZ99K3hiKC3iXh>e}J*G$GV zW~Ur-Tvs>u3XHTDwZFTK$O*L#-Y^8zmA+O+CAC|PRY~Loqmc5HRssA?qk`L+ukDoE zoA;^>7MCR#kDALG^wvhhABjoroeQxtzb1aLJx>Gw;0l&t12}}HnJAKRv}#8~R>4if z*3O)RMAb-AH9sxxd*YAR_9V!nSUN{P$lmQQdylu`1q3t*)`L}8K#LRD82qrieV29F zM?lkA%1819u6;|cUZm8Ltc0$;ysVqi#UDB(5_+}fJO@BPWH;PJafpL306}vBs}m-5 z%IBLg?Hix?D@7*bHWhqY!)( ziAHvA#$oIFHd6yvhtoyn>v-6?x<9U5;#4RYN!q^%jk_(rUk)-pLeDjaIQFd10x0F# zUhyUxDEnCA&@v1-W?C@Bp2_JK5jh2(f<*w)NqQ!M>3+@~<+cPFi3l<@j}G##*pZG~H zC?(QVs}kq9^z8bD&Z!D*XHg2yHy3=64yD(ON6)1akNgrj;$bbwl?Q)QkndsL!L^L+ zGeLj>JLnP8lx3xXqE2l2l*~#Mq{5%Q|IkHj4`XuG;Cu**2OiTP$F*{R_&30z=R7lq z88q|Faiy|S1O0S5%In*A@13KEMY?L`UoG?waQ*u%5=%TSL|@__v3U0$vtXPBw^n>r z2g{ZB+r7S(hgAuq^Y`x5^RflJs%Df^+(7Kr_;E7zM@OJBJZkkcaeVpPd1&?wm z!su9Y4<318#<9gd72+m|2ff!)+3pE!KYWa_hfjgz*aYdib_D1srHNK&o+eOXM@)Hb zGxK{PIyU_CQ{kz*i9_{;FeL&SjxBbzaQTD7r`+Wdd-0U7cW-+uZDV;Jh3X?E>;2(E z^hzJ$TuZaPT&Y`N^cR^xxSI-q?F5=gqTM1(XgwNbqcUVh9@$8GtNkDpJ&COi_7lbW z=Rdm$tQsHeCY0<-k}6X|4n!w>QGf&0H175YHxXOso5lvm!IoR2}=L+^T6J!MCJ0~fb7#X z{skjuwRu0-WX+8S0;a+Bm0s$t{gunHDs{4#0oi<2_g>%QvSwy&7h4;(NzA$F9O9-B z9T!n`!y(+xbtVCM5N&-kcy(PAQr%oiJdw*?;#4FDCk)Zc*J_CNV1=*}U`2pJKyQkm zdWq6ynK|X`ig(jFNb#EYP7kr7S&3B%Q$=%L%^KLvQ8z4>cMw&Ul*7`epDk&n>r%2r zRF9V51BHDD48zx~g;8#m!$IN`3;KHcd+X9ra}-BYaliO9P4I$pfy*RW-f#oo0qF2+~CV8Wrd||llrqrZIgOXsRh6<_jCgI7`jZBQ`6Rpb}aw}16Bwlh}-m$X-K`k zkNPGb1@asA_p^E`KZmn7xdQfT2n8+ODAW8@H4{lIgf=8uE7R=UV9v-AC4|BTgjK|n zXom>@aL9$JzeGo<)=~r-{Fn^(h{1>BlwEcWJ7O>x7k>lc17+-MyW2Z+Pt(_L9Dlxr zc?DLguZLRgam)g#gb_%PVX`RhCwRoAo&v${w92y#htIE}5RLYb%L7>{|J-q0V&tuf_xBd8X&_7gb2 zwnqMCNv_r}U1{f-W+qK|PvMs>zDi~T#tc!P%DqZvbZXy2e&fWDdX0Q4$Himj zLun${6->)I!mgx)XVvqDe~ZP|c3Cu!8G*a8gl{wh)qK)E1rc83|)lxO08Up&<`$)S$K{ z8i{^*qe@$-BcW!-3ZfAh&)FUEkd(lmQIt^kcHtdBaT+VB8YLHpd@w#|ALHi}Vz1nnugRh!c)p_?9V~@}86-xER z6^HC91}xKZaMt8n=(ly!H?wQO_a4{e)<6omlExcWZ#Gp}AE5?PjO{lJ&XkGZA|Z;4?eDj+;HX!ieWG|oWRK(+;7&pm*=_x? zrVUO2gcm_q!FqwM-Oq&b3B*XSu+WgVEH51 zD;p2u4LT{?!$~?!X{Cw~XoCrqP|Bc78rEbvX_wjQ2CbBleUl@cGV$Q(Bp{?>bh{S~ zy){-Gn~m8qn`;^}7D$r2Xf^bXi9}I4OpWgeqm;pk+a`iB7hGR4sM1JmL7yXq-(vxpeO|`0;sW82?H> zgIMH^3UUgoP@IU`9mwV}Cs*n}mR}U{GwEJg(gRzoO%lswf`8+iYvl-N0O=GPBd+LU< zJML6*lAZdoK@?o240d__fjMON%_2X^5j!NQ#BK#DK(r&|K;*C4sR!F}Oqn~Yh41UT zYs3Ntv-Tz}qy2O(Dnx19H#K4j{jtHi>)vQIeNq2t$Z2#L~l zxZ{`X|CAqr(pcsw72+-rPd%QtNZ3s zA!;$#2-q1sDnZSzlD%SW8@pOG?LuM+%fu|Gf!R_aEDkIbZA+0xSF`8zSHzlK9Tt^p z&!z}%R&`R3!;l6Kur13t>}nALwHVR(5ar2*lDk$?=3i;O(&z9pX zf{K0Xeq}uvzR^~r>Dl$@5ZA|utef9wYEnQ6I#@uX672^exQAP|H1fo9qHoy-CuDLH zc})8h1_O;aw$Ej%~br8kXbOz=^%&}spfyjCfJ?_RH<6m{s^S!S_TjHd?s47owkN^E-6@^4iW$Y?(r! zjQ^1Rt~32Tvej zfc%nZ53#dL^#$@@(~aP)!VgE_w@1JRjG*vbVz}AV@Sn*6I|v7waY%PvkquKZ{M{q$ zO|dMS&@p8EjKIdGSS+&iQR0#A^kFA(U)ch&31c$Ejexipq0(m3wiNe!jTcZTyG?4< zCY@utXk(A}ho!wD+s2!11C690m&R#-lrLUWEXxmU@u_p zmOayhWEE84hZTrWgV`urp6@+<+X8v1KvqeC zK4NP8aP?!?nS4GX@q#>O9#$DEm|IlZ_XVqAa@g{3P-I*rzES1$sGi<)c>6-Nv@v>N zQIQ;Gv@JU$TL;ClRi|}kjT<;gny3=Jqo6oNwBA^AOy$KL?%!BQI{Ri0an;@w-7C0jrhlx2%M0B*8V#9q zKm3(np2z>m22ii}cfgiU=5~F0VtyxgNl$}ZS5o;tO-p7#o}5o_s%!!{_jh%Es^`Nt zqd;qMrdkN1-`i?96SE5!X_5A`VOesyu}v(c#CtQjzzK} z8O1~7v}mcvcSc#$gfy=J3^}xtlT(P25dTKP4NUrGNxl*O4e9byPrYPB6dt!xj<$U3 zO>mFB_;qJ~bY~Wc`FcrIGgh()Q2G*`KNWF{jBSwGm8$tWAc=DxJ`njKpJZ%FWLgfn zjGj;r#b*j^p21s!qT#KFu(YbJIru5;Md}0tr=%kkTg1*?uq1hk>{Iz76rxC~ANpwF z&d`B8nW+`2;tvFUo&xh3(TK9Ohe~hdnRzt_GcWxb z@TuwNr_mpmQkllQH3%^4mXud{cPfJ6bG8n8vBd~1u&m2!+TzP5XmTV1E>NTK+l#_5 zLQNivA_4JD6?8&t(c5tYkdU}g`HpG*7DZ*JPjx3{y;#1b4v(GzUmmknSY7a9pV{4P z8fcKEioGBG4oF-D-?(ALg8Uc=;{A;qnER_kkY5tP!o|j+;@}ihQ^z!;7Ki1cbfF0{ zHFv$gZ3F%(5mBgbTXEz=iMpST9=>b|_%wa<5?tgumHPlAB5<9M$=+qkDP^&Za6szb z#6%MLmhnv~h6+Q*d6Do$(h1B(yuf_wAaLV3*@BC^?j|Z-amVDX*queZ=~c>vhsG8) z)|Y~QHqPVEeS3mL&J$0s2S{hn9Rl%vT8`W!QG$$;iK zUvJH#xLrp~-OB8KeH<`X5B3YHf~$}#nErQs6@CZsg)XXO99urH=}OGG?TN6nX*D5U zlu@8@=ulv0$wv#aj`l;L=ibJ@Z2AViI?gXKSrY%Gf-MhQcY=vqo`{mpvaqM#n%n9z zhf2l-Qaq61ZS!D0W>{>%RM;~Obrbqz6omFH@W0;6P*Kaj*vOGyfr9xCkS3HrRW?oC zE?Jo!Sd9cKnMEVuoT%Qpr$2a_-Eu-{8I*_2i=Gjs=lresdLZ4e!7X;uE`Vw~qy$*B zv!2j&p7Y3RgG9WyT=}gWT}$6wMfT`1qF(?NPhD!Nnk4+kx(K-Z=)s5mJRAvz)T!wWRuzw=z}4W-tei?*NGCwc?7i~dMm3cvs*M#+=?NU&iY%mR z+mYl~Ljqsa{6-^q$C6!=(nn8J=zAJ9_Eaq3Qg9L-I#W9ty94FgFznvZu-96!VK^3L za?lEJ2DJ&hd3oQJFH8PgsH3B(|bh*eXqz)71JJC zy<=5(i%B&qVnlI{*vU$2!R+*TmU}dIOA{tqO0^ZUCnrbsP&ewu$}&bbW2G;f*_sNz z%8i5;cSP^fXQ!xdy^&TW{5ZEbwDVs#h&JLlo%}l(9K{%y;=K#p$)qu=u;i%I*B3u_ zbo1LWVBZF0E}JhFMh^uHe|gw=mvIs|^zW)*+MX|uaf~)6a)4r0azPbIQ6=f) z*J|3Wk{b*fmSy>yy#w~+x`x1Ze}AG+cnX+O8@NbuM!0H5Z(BmysR{=}dkHJhcumzw1n5qE+xtSX=+9@o*GN^5I}c)n(k9 zP;TWUejD+$fN;@(xg{VP|4M0(PJX0WW94?Vkc+#NU}3=cg1o<3(@i+erflm8@woEf7oMVL zNr(2*d^B@2(N3}rwf_q3n^y^#3dPwQ-ezX-sB!(Tg%GO2cp3v8_=LF;l;RkC)Q&b9r&>N z*p(K$g_YK`p}YI^+Qt+Y6hhRc40rkan9B+`ROSKiqP{8k)Ni2MjXoa8;Eeu zHZg;=jPjEyVgv4cLZ$@y)3gyw+aDvjyu&Kn^!8+q`^NC1ko(55X?VXM0=5Bf1bc3> z%zD@vMFwo~907h{yH(Q2sTN|&B~23{R#wl55Vn?vBbFHI=Leo~mCoSD)}7gk)tsBG4J zrLY(c)LXdOI6OS8RK(<>BJ7wV1N_oTEv7I|)3I8Fg6+HtrJivTu{_#J)o4<&T15?e zQ7F$%hD;o2w+Hl?bP6g$#arzih_8hOI@N4VA{SuYjnzrl4E%Jprx7sT8hf8=LmqKO znnwJzj~nf11TeN6rKcfMCiw_%DrVpTIO_)LH>UDrI%%aY3E%;$^t94KBk#n&$f%)~ z$(C=O%gmz{IAyPei9&nMVrh`?S5@ap(!RI!@b;~Q;~G-ww9oJO_(5?UeynTn1n`_P zu0Sdc3p)a}qi9I{O;E?aPnmz?sg_EVk5RaZ8A2oht`)hNtx+fgeqwW22?(-0MsJ`z z$IX*sGq5x@c3-giCroA-^ro(}StbenBGrqiCC&1+d;}JuKyEVVcnWQi@?&}vp0Fo4LLq4WY`{bQd#sqO zZ_@5=>zJqy<-Dm!5s!VoAq*@GL8ZjTD@2-eixr6tx(ce$r8sR)b${_}`)D-FJDm!Y z=Y)#c+3U$WC`cMy9(@H5A1+dcd_a_*HqT?0YnHg`C0K>bXP~CWyv<4>cu&WmBWa_Ztkq$Xoz>Z ztSdR^saAZpGz#V${x;TQHmyWD{mHitfv|MFf(J2C9ctIwZ8jekPTIF%POhO z;poKkWzx)0%&Q)SiRN17A7H~JoVGB+hHRev7(cDlR%1i<)8If_r3(x?JxDG*)6BQq z5k&!fgQ&MtMxR6suGH25e0uKzIu(L*Ozl#9tCI0H^l}WJy?I z)cd&YXZ0ZPtT0z?Vm|5303Quya=8VICTx9w2i~BNwmyi2 z(6OFDS>8Ot4*@UUJU^|7q5@&!V|whV&I~jGWn0bg)NPmZ5LY4mRQ5}=0oG~-o77SS zx15=@3tQSse}1zC^guj?si0Gtv7RNW7>ChCR5rZ_e#TB)o{i?8+3{6d&1@iRo#+_i zDV?GgybCDy z`(*-vs9f_AdAHGf5)CA-n}lYH+Px(*5bv>aqqyF|VA-MsJ=NpKZo#XlmBvpX^p{YW z(!F(|XRVeqkeI*}x!*d{QAn>HGnhInLdjpY&#(b958>m%#Y}S(!Y5K_V?!|xbLod1 zY)R>mH+#VH=eOGJV2vsI0Ya3jQ57Z8$Jn^4_B%ruw>zlf_ufCRSVxj$jrNxCUz)9|M5hoN182= zf|x2SM6PlH+M@MvW*$a$zJUS6z>8Yva@#_`qo`>7rXQ zF-rVFB|17LtO0V0zmbzQ^6t?6;N&Iyatgr&>LQdkc+CuDPsqTV-qd~tva)B^H+VOr zX6sr)Y+&^jWM%G3bQ(_9=n{cfQ)^|?Lwl;8O9Y z777p2buPg?d$}**Q4_-H4Br6^d`Gy)KWa&bV9Fv`2$*0zgHM5u7(DmW*pd(5<0oQ4 z7WchVmbdw#09>Ql3Sq|J0ixMX@8TR-DotL%otl4Qw`%$y{*l%hyeL<9sx3{9#uQLzIeA~pn6K*4W<`Y-;U z=e^He>#py<@Aq+L4U?I3_SvWH{o8xaIn&N~$eZ58`OnoF_-@qksHcv`Nlbb@V_kV0 zJDqsU>wsYLlFq@S^l_BKRLc89v@jvuaSx+HOWnHF8T7fI%&F?}o^fF6QrZy{o5OU` zN|#g{EU;c3n-DP_+u&2_z$d`PG>2RJ4g}KWPv|d6D|gE`J`8P61BY=Kf9WL4L&Zqk zotC<$gfpO&9a8oCDcriXByC*Ke8)Jp6hv@5(xO1#%WJVU7&u zL?UrkB3sb_0XD7tA|rd3&HzM2Y4MLwqT=`c5a;&4S_!6#7BtFZmP?JYw$RSTmeXZ0KTIj9{HqK4SbsVeI{U z@tjayxBupr8e$c_uDuslM`sI2P@_vi zXbg7D#>R%;KK8~3Ew(%BgtJfy@6hhI(M?Bb??8@!)Y=j8O~_$g%5m7)nbwjg+R0_| z-Jp)aLl;{`x)7>oc^tIOlh@n+fMWJzUY2T+JO;tfZClGePNOw-KX6pf$EYv4gNXRB zyOaGKlBf8cJIPO&E>SoOKfI?m;`P1BbzN+tKh@=yqAra0WVc#zZcq1nl7FP{>*qs{ z&(alwXn|An_p8=x|5#BK>8E3edN!~FHM7DaLjrrVh zjmyPMK}hi@GNA3&9_@UFPxNO#0t?~~J6oxL4~Q4*lH%p{I??g9BnThx@BLnpCr;w- zq|Tpux9`|eEr;$ovJ;^cwX)`eqBMdH%BWp*ywPWOx1Oda;G zdVGATqaiOWYdkQv)DUr*e&HuU5;$HuE&e)vda>&D^e2~1_Mlh8h)$NS>9Vn<_FLHI zmj3;#E}PiZO?+a*XV&nFe*ZO($J-sQOmkaBY>C_ar%G#JmUOL4$1|gc<07^@yhh2C zP|g{jkn^yJ>yqFe%i|1qdo@yNOaGr#GZtxx)fQ=9JuObR4p5V!O4ejHkcq50oC6 z(V`-@O*jdxcifRIn{awOyx+vI`|z*f3#B82ET&iZr;N^^!svdoH}*|BP0uE(tY;-= zC(T3og8&^D#NbqQ{|+ex*#$~&A8R>meXK~W6I6K#jT>4#U^jDv-Da(e6D&<^raA10 zk;|_CSa81UKKd~$M4aB~gia)I-q}Xeyc2F1M`B|xn^L-j3Y?F}{um-4U@U5O?N(Iw zc2&MaZ(9%-SoT}>p9%9iz`pa{*{yN(koiK@l1&=-M`&l&l7qHcMZf);OtCn}So)5N zb%#^X7vbPgvb+r)1-VLct6#AblMFs*b_?P(CGyS6?}+`H)YW#(-oCl2C6a$)lM!LH zIwHq9^RJ|osk%Q@X8toZ*Ixgfvt12}s=UmiS*&Y_w!1A-Gb#Em^Urm+A)bw}9Wg#Zd>1FU zq;tf={BzLTr$0fJu)m9ugu68%`^-^s<*XVHq=Qj z2Jw%xtq@_B4yGzEswEb4U68ZcBprGrb@~xLzF8jc&BvtY6(~iCs@T%+AWEmXDu^*$ z^LpIa^)#Q}sbk-q`H3+6z20Mbn)I*#EhZiGHt9C8w8V)KJ}2<^veCibyLXC5d6Q>* z8u&BL)c*wy#)6<0H6?7Q7p>JILmgG$7>M<@2=Ck3ah=euBopiPE_&7hP57eEJ(^i+ zaL!{(1%Zx&L2ybm6IPvzRE%C~t*dFK8 zHB`RW`#AZM=guq-i*JBw5xe=fw3JWJ%D^A-59ek!U*3_-L zWXhubWu@#b0 zx#h3SR+Rdarsk61pDK}2{LPZtcy%^kUe$^J^PaN+Bk zbaPGb8K|4K6x6Si!A`XNqC5NkHZPi!{g)I<%_ZhM`_D+#`>=3i;CyjU`Y&v&U(NCg z?W%i4wt8Le(p;+~&oN?%LS;+)FZBU}xVz!VTQfb$~9+^^b-O4W$Pk!w9#r zKe3;0h`2btc%PBof6Yxm=_OjT<#Xpk7oavNl zh*b+f4NYU|R$_XZK*^Dgl0tby4Wl~0Nwn!@Lru0WoR(2CXmy1(rz$Cns_NcVaY>S6 zyz~zv5j4o($NW$Ty9yo`oblXpA)HTam<9Qd+kVmMmxY-1F5d+WTG*f}(=2&|M4%KB zTA`H>M0uU;L*P?KW_?;~lNWRZff4b%ja)9?8NVSh@#-KHS0v#|+@-fAyqO4)RfTA#hO zXTO89VnvUQCg1t|h3YuwwbKlS-D8O0>e6nn&hhHzA>Jj>6U!N2$dot&%V(;tuJpW> zzi98_#FkN59USr+5u9WHO7l;lcHJA4uGhU1BUVqACi|;CkP!Te*7S)SZByJ?ltO;W z_%80R{W|c6kyPK9L${A)td!%#>w&x58~018t#)xNdQD?pprhQNk)_QJ9dBUh=FehX z?4IE)8|BnDXz^iTr6&g+yPZ-E3El_P`5>)qk0IR>4Ga>ATO%EG6g--7#XUwm0f}`z z(sa}8qFaBHN@LxRLjN4+ri-V2%i9OdBXe`V%FBOtaedox{b9hN`tj#~z3oQklOW2P zM`lwcT)1<;N*`&Xfxq%_@U6T5NE(#+2c3L>YC<7MtPiqJ{3;Of9Vnzr|8K(_X_9;PqrL-Ej{F*2c(&>npOYBW z%?ob_A6oaYithwYW1W2-XFtKseZ@M1OZxMc1?kiar29j1I;P|D$3HlT?3*jGU#!i>VU9Z(1CsvgcE zL~xIk<^WswN6hRlyJxUSM-;g9X>&gv*iQ}9t&SLaZl}=n0~qrKOqp*36;VUdM-7%T(oetOeIRyiP;B(AB+9RN&pe-m-9UG+&O~&~P%244JdDH5 zP(3Luv)YTg=_oK7eCb8kQv2NzsM^+zTt6BOxX{w0qd7aZ=Nd6*F3*xd#JVeJAl7MpA)n7a)<#2z89i@ItP543<21|H^_@P8?Vxj zx*=Byr09&X4$o;KxCPCx9cXm$-+^~M>t)4v++|)nnYB8M*XD%Rl)Fns9xb)<5PoGb zTpnqI*XyBx8g>>{B#Lj&c*v%&e2ytP#|B;H1ThGg@}zR;Od}nei)P0HbIM0bpyA1c6QUw}OM{uIMgVT^9HRad zP5z-oGEZRRpxYVmrD}rGcr~|yOzOldai`PKI(+LDi*^qmUs=^or!?}*TMgRPN5WJD zIt>GlxSUO&LKFpjNIc?w;xhLe!_N+-7Ts!HC05aKNs%?JwZ8VeaGCgkznq9<1Bx!fH0PJJ^?TI=q>SR%svA z8UCbTzhn7+$3`gm1Qaq*b7Pq4EVP8IaI(a&Z7l_8Z&kqsQ zqjSe8-dqDOyRARbvDDk*Ebc7M2qC}TWUB~(i@RNhyQ7dy(GE&>k#HeKUCOy{a<@;- z_s1}nmD{OnJ8O9`uTFt9-1zHv#5X2uVmCU{5&)g4e0Kn+!Ap(|%s-4jqCsOoS~w^z z-DWyD6Eq&G5a-YSq0Wv|u)yYSUqyX}@vRfu#92C}?gXQ~Wr`R2nCmo)k|rvmFEAmK z)U3npmZhU8d$Zppe&Z`eC0){x4HS#5T5;%nU-==qisOWg8X?USD@??-G1!Dv=j>QZ zBpWzJBfXFu)&U{R32u5bJecNKaX_a-xij&+fM>Wu!z?+|P(s{rv7GX#w3fL$ItcgL z)+lJy$ehj=e*&{Oq|%#(!B%Xp~Uh2 zz(5sv>(TE3;wWr+A)V%BfY5U+er*=?!fKHbkuWO#*$NizE@G6FmDs9mBcpG+0L}w6 zIcDV@ypy`A(~*wO*yn0^`L$T4DV_^&SsnE?br0nKa{-(umTz#!F##p)raQJHB*S|f zEIM%?wV=;ffS-NR_sysmR4hsV_4}J$#|%tn0E$;3qy@H=Vqt0qL!tl?zAT?CXN!F$ zh2BADJ)`!(rk-CImA1@b#~0YYGUeVzk+{qIc3@5NiuHxWH!Td2aCsRP6Z6!uzsitg&i5Kb@z*K7BVIsWbk`s_~(Lj=j zo?_HH{Cq1ja{rQkK*4$U@OrG-T9PIPKLKJF&?CJ@2t3G zUSdGoyL*;qRY1g)FqzB&BvwxY78#JlxJ+p?ldE>N`ZEZKsBszmg^NNN6B9cL^)bB4 z;Im(-b(s+lAC8jcz`w0NvX(qp#c*H5?o6>qDEnDYDWSy14?Lxk@I}6xV`}$tfCOK4 z!eOiFNgte}J<%?tOvof-)S%!psSKi(?TK{*TvAexPy0x}rYOL>823}+#vHfXw+&%b z4afwut5F4T;Rj*IqL%k`Ja_-}|Hfh0qrX|H+O0DYw;F#fdVDW#?155C&QPsym~4UD zz?{>MA3AXs$sLz8{C0;)>3g0?oKk@s8*e?O&ZS)3iq6O(d43)J_J+CwJ*9<@kvAhb zVg3!B1_=j2<`(`U^*6dGJZ!>Bb4F;G`^koTEB}P54vgV`{!ZVUp7nP}C&At1RGSa% zAq2H^zkIXXU$hXBVVT~(gme;4)X>V(SXfSfguWtk9iwtjwvryTc|MGgAAqo!Iwkxb>^&FjM~x%& zA9g-2jPYH(F6D7;r8?TTBn_<0 z*y}1X+)t?D^IVHpVk2ayJ&@kVTN9k;y+B5(^VUkNKkhQE5_chw2`T#}bZC=M3+A#t zro4#Yqep9{4G2kauWd6p*_2<0Td4FWRB3ED>=yhFh(8KOTZ;ReWacPrFXC=1_@mu8F`3*%oS6vy?_scuh=U80wN;j3d&Lh-(qivsXGNFk2P0bI{oV zI;bo7k!>IIL4SMsmV@nzhX_|kyAG}>G{k1fX->$g^xV)7+t6Ef%2M3KFeB@kf_wXvEay^V^dvaT z4ykBg#eG2eya%tOO*_tXP<&Yop7}deo@hhB#t-{E^Z)czqB;sY|0=ym^$J0yZQ9Rj zreTQtCG+P~aS!)1mHg^@cbHrM)EG;WYhZtl`5fFd7pwO;w=y=6tJ1O5B{mRKAWdqJ1N%`43q!AiH>nON zrONTqxCw}Bj^)ewn3XBq&W&@Jpsx*|! z3!gfOtV{O|WS{DgZNHc3DDIY1Jw>l%a#F6Z!;k#Hi0STGe`n_=zaV<&{2^yKzRou$ zyOrX;T|dtd*W7eS|6g@uH3X!+;!{AR^}_gi@xAg-IyL4CQI2^No0qp&ZMb;Ytv7&= znVT5R_`_8zd3nsmFMknExKoB-ucki`uDyVgKh*q9U-u0oW5obSVgicTH*rej-O_>% zH%O&SMJ1thBQ~xs!V!13{{Gj~-8d(6wV+WcJnkMn(|`vo*^tM)_FQ1jmCJ_@$a7zR zatgOC7DFGj2rd#sKqT9L#TlJO-%ir6VO(7ELr~~-WbeE+xz&6Z`NQQJ*!tH@)m7OxE>vbmjE(_8nkw1B(I&D(gcIQ0{Q z5*8L8V_3L2-p*S9< zHJN`Cr0US9W8i?Tqc`Ey&z#=6`mv0BV!q>b6KqE2CXY4M?p>8=%5Y21utG>!a*+|7 zHJgpl8t>iGtsx7odse4{@!5LDpH9twfr;MDIl%oCM(cK1YUw5s$0LZ$o+kwO3d9r! z;DFdY*%ZU6$z1ayV`}IL8ZVJ)i=^AkD;~9^ZWc9Ueu3g-Ej<_T7W)Fv?zf<{ey7{I z+SAtAs~>&lL8;FG|HP5X-TPT?#cviKd@wb$)gX_6(URq`i3AB(N!b`2`=cSHjy9Sy zFt1;WCbPR0Z!%}$81AArlVcRn%}R`9Ca62k4AbZ=R1<>(U<(4rgMB;F+mY%3a~6I! zK`9J+5Carz z8X0wm%Iw9^-Q8Mik($U85nZ@-AAH;=3MpX$#gso2)3e;cmud#`(lN)AsZl5RZG(#> znNFf4WcP2-rq$v;aZ9JMw5YiXzd(FqM0GMNR3$x(*!zr)@a!9PT6@PKEnwl2 znXkH(Z;OEt9jjc*1G8a6>&3DLI3Sm4Vxq>*hGhYYJRn|%F+AAr3?Vg|i950^Kp5@_ zaaS3#H|Hj-sKyLIROD?_!Y5zQWeYxc(eV5n^9fQ>9@gn+uu;^>1-I#g-C|S;W8DeOa$QDOioqo5YgG&agIRJ!0 z12kqSnB;z)1o!%memI-_G}($xaeGb=R=RHozGOdchk5lJWflx)F}o^$2=b7J5$i>d zN*mV*b^DS}xsJ^r$X6Af*uJCZ$be?{_J=c%A_N?NC>iECL|9<6y}oHsyCer^S18b;_|O6_B|*}vKOU?cX* zSJY)i6W(3GJUu>xnr5ZmWdfzja*)$MZ0Db$=T67#!tF2&?al>L_Kcl!c-I# z_i2u!h;xTyl7a-{qS>e;rGcyDGK0TlOz2bGSGnnPW}^<7lH0}oYYbha^NU*T=IL@I zI(&e?c#e5XXOW(KL-V+JKF%|?O?ldvmP|aCj6-r4N|Z@HiOp$TbS+-sDV%!NHuW@O z{fNufAlWGic{%1rwb;g;5bKR8OCaRF5f3Gib;lj?%oKUsQ7M}8tA}pcyBKH}7)l5W zwPuJh5x=ISZu}xfppS;YNMt#IdNq`EO&6&n?h${( zB9ErJ@6EUrA%=8)8B54}NWtB%o2dME>B z$v+X$p?18_Fpo=D$jTO~`1nb)ObC!vQJljbCHo|;qb!e)!AxVCi5<|tHXOZg-ei{d zvS*fuAMM^%B(CxLfN`t$k;q!wb;IoWNDpSyg9`ycxns*Lr$6%#F}U&$54`$@&p~Rm zF_PkfYNI+!`ql+5i{B`*%u-)(aMGD}`wqm0ZE}sQ{3JiGK1ra`?h^@Cf(xbE&)K zJI~szcs6HbRhP6`;bMN&=rY@pgBhUs`Z4f=gQDtwpg5KV{^Dq6g!30|6ZKJQhERj6 zN{wY}8C47@6HO^A6yxsgI2d(BFE6O>dHqUd=OGZVI!wjCwHsfO4}Y6ny1-vQ%R~=& zxY{MveD0EcYHk40&syCklz|`M4F|0QQ0XK0vPv}rF*)hSo(F>SmXoOqR!JZA-3fvN zo(m-JT}d2GLd;<06kzB?vNKNg0HznyG0x7A{{@7)8P25QW)>G zwg&(PSCFm3LQ~EI*ax)TDqEoO!OE^Pf5)kj@Pnt|a(sGkoZXdEn<^!23XbSmcc_U1 zsX6$p(;?4XablN31SEEWEZ` zf)qi(k1Ey1hRc>>*Ikojwj8Ovt#_@s(WQqkDHPB;vUV6veImk3_7LOmacV%JjTFvm zASv=ZG}t?>BCV=vL6-TBr@GvRUMtt=l~`w5zOcNpisxVvTBd}l6?>WLi{K2drD}?+ zP>8jEtF5D;H*=@QPPfed)CI> z0EhI{x#rr3#-X1s{XoP@uf(#Hl5m6_saa|ad5mQf=WSEXc1TT>Jccb;A*vDFo?+2w zlUEvBbrtu7T3CuW(G{0cN_%jie}v8 zE{8&5#GSR@#=6ZlN}XRs!;i{g;VSZU`aiQNixFJU`Y~imSeTxj_ZgX({8sd%052P* z2W9fSyME{Y#O%ZXmu4@Xx9S@f3PK zYCCaK|Ha*3ro}jJ9s~c3fYeoUI05`gseZj56z)jLl$NC@*MK&@| zK!&Sd;{fj&Uu3bJfd)ckz)zuHW%M4*mj#2={sal#^;#Sre!d*WJi5XsFCs*NA}<~8 zhKnOVHL$7m?ij-Q!Lu(|pjD)qeelTIqaNdTNCGgSPSc zEz6y5K6!!i%d4%^RYlf@Z&w47!5*Tuwf5Y z%=vYJg8#1|JqCMptoC8Y+B>XvkOtQsIu?T9PbbYJ$!2mWAHZvivE->>h8T5ErPnex zJiwBCkPj68W}$k5LmJ=E*=v)$cgf3hL};SxAZY76Ue!O?bNr%gQ!r@7EbzSj7<7u2 ziEw7i6GFFaIgrC!%iFl5(04-nXhxZq!F{_Mu8uG8$hG(mN-in%@v5Wq-#eknkQZ8c za?vR-)Y!!q=ilVI)yoOWO&OEm59AWamTZ?;`ydxr-Rh;dE)~+3%=tW9zD5?G6&lR7 zl4H;BI5G?s%B$8A6ul1>H!GF}Q@_lUYw^*8>GiM3#_2~#jzatII1J+9xDyF~_y;DB z=uFb>^{Gd7&Ps6)zA|4tb#5(Y?>En9b?(yLkSzwp^h^H$Up>H!IQ67cup- zNwSP9`GJC}2-Xt(9sFnw0yznQ6HL!v~wu9%7T z4PQo`LiY~-jM}jQ(kPT*bi%MP&z99inbcV;M>`9HiMgUz4YaSHdcUw01tiQQD^{3# zQWmzDG??e?evM4vLXZD?Ru^U3UV_TQ2s0Pu#H<_RDyH6EV(UC}pi}3yvrf6^CU{d9 zk{D*P0-Eq&JfD@etnw-}bX@nUyU!nm1d*-IeVIdhyp9a>Z%;YdppCz}N~nJzME9T# zyCLnwFR!>fH~e=e1FzXQO9YT{*th(%<%JLGwEUNk!4&osNdQ0J4^0<-4LwJeKU79A z>>HqGmaaCge zd*eEPE-^;whaXDE36#)-LM!?wI<7CqJ!CmEdhyd7PtbJzsw*9tKOO1o_yr;4TWEy& zPmaF3bNn0%e*QD6JYvRwL>A$Er>FWFk{#~MS$$1rs75Ib2Pg@a>?ES^I{I>&8hc-7 zdLkPfXM^siu|TLv*QD}OZME;^6D^rs__tH#Mjd_mL#dxe5a-CK1&0D-16X%EP8tHp4XpJWsL3+0@)sWe3Rud!(9H(E4({Bc)$2Zc-D_&y+G3zl#r#Q zrk59e&g`2xP@LFwO5))vcEY8JnfR(>_jZH$ zq6$X72mX3r-?9x%h%>3J>9p5mmjNl9Rc1UI_YPq^9v=Qxhx8i5|C6}1*ziS2xZ2_G zz#lmsC{9qiVl&;KP1qg4`dFj>Kyh+~zRT5Lg86ao*B9I`{s65=XQkNt&8jbNVxE=y zUQpd6J;(p>ad~*q%XIf&JGOp8B2w#p>=DeuB_>HhlOon?T6Ht;GPzH1!jXZGB3Qw) z1T|p{cZ9G&`RK|#l(!(W4k@9qFjXC_Pez%Es(KH;p5JL=IkeEQS=|&5gJkdBVt?-yundf5ot zb8+B~f&6ozdzbmnE)9=s9XEx%TGoXA;*J$-jg83p8M3$a&CSt$d7~;*&zaVw@+}0X z9Ovg=dWf^+0(SvsHcX=L3|<#1vnHLdmj!xmFsiyIq<2K*$U`6I3z-(3by(#5bi2X? zLx9gRwL^nzUFuFg6sZk!>Zb=i_R(}Gi^GzgdmpZ4{tB5Ml4WaGWM@kj)q1a-8(2lH zk$wH`MBA%Zk&Ei+!9TsmPv<8=H}MG`m%Wcmy)NzC{Ahq}M)EKUKc%o+V*g3N?TMEKFHc$2cbS%`X3UqQ+7 zjen4O9MFAkN-e#1Slzc5l~HE^WPMJ&s@>~oWYisFugjjEVG4wiDl_0agtir%UcKsf zXue8S#e8J*&PTQ=MBeU9A$%y4FLdMJON$lvm@-C{YdAk>Wms_Yxq?J|C>dUPaK2-nZ#=z>p@kg6 zS*-z)l)~N()A6s_VYHf=xeH+&(6xP;@iMIZYd=O;HE=x~8H7@!!12x${pI#M&XtUMOTqQ~)eDNnMx*g5Pc=lh(Zaz=GuI>Z zH%tyCL{+hTWc!5wQIWe+nuvj!bCmxsK`e3~DgHZ<>?fUO`hO+tc{n;%<@FR`Y@Z;y zv#5(wYu<6jA~4>wy#_#cK8uC{70B1^!H*t;9;U56CXaS=CCied!+R~@g5JG%GJ!qt zc&-Vbdk(-kNo2Z29HDubQ`skx6Pz+BH2Pp{kvSy&w33OhC@|-qK!o5xv-y)pHz^Qo zM4!*d{RhozW_hXbW)7eJ*H7#H$3HEmo^CGG!a$(JlxW>*KA9d&OyZ<+A&=oTSVF33 zYrejqvf2SX_%v~*Kna)FU&wVYX0#pg8|xX)hw$c3+*J$lt|O0sRCdx#`Y^iq|JoU%wp zfQZt1!Nj=QQ434G8H&hN6kpjz%X{~-hzXxD)>T$|WQKDwmG}LeYI~8Fxw_|D9mX!Em|#nmko({j}$JMw+-AzMs6qp&;!OAk-a<2N>F_1 zRK_ZafD5&8@_I|ex2{AA?0w0_QHc_wN{M4ZO!W~1-f(HjhU&9>)!H;F=BcZuT1|Gh z641hS-}DsH5_BK3SR0J`S0kZ!0OD0mAY$_?JymR9_KT%z=<4T)2-)lRBhZ<{ z>OPXy!%AIGKI}{1hLzMpKVL&Kax%Su$KUgEgTuC4S=K!AOPsZT9*e6;uB=Gnmty#Gm^q2!+qt|zl#Q2R=EEZd{YuhzNA-46HEAa@$|x!>$4$xaw5AU-^7D5Zaj9MBr8CnSOB5``8TmZG?0L!FysF1 zS z24jD0QaBG8%6Xmk1gX3GA1o2CoORgdX8SJOR^MJP5tDOVF66dKoXl$1}z#Zp$n~2 z>I?ZR=Kvd=K*K^z(Kr^h7rk0ao!CVh0CWMivDtr(1_!j3N2Ev$TFW%-6r0wI5h*ZB z*oaoC88_)~>;cQ*O(H-@L*s_gkP&nz6%MdzEyYUx&fYMglL26-!KcxL=@CK)5{&~0 zT}bTj?6IK1ii23eX{Jb6iWY{DclT4gB~Z8xH#KZ2aElwAGL=BI^kL+D6Nhd_Tjk$)>`j< zCCpFmzofHrYX4A3?zN>UwYz6>6g1z7$?9~Cl-4UeSh?X)90E+T2u(G-jbH!{ z8zzjhflO+Zu&99vOOt+MZ)-TyfZ$XxIsi(o94gZ6$TTAF;;~&T9?B5HU2Dr+^s$U68;3dOz6Qs^|d2>*1;qs^u)ZcU; z1Ci@92S@rVj_EEyFs1G*(Iy$3J8Bgh4hZ~B_wl|k#nmHm6z~9W^@%`ck{AUAFH4d# z?*4ne)ZZHG*U#Ug{f+qFDg2Lk1g<2J19v5aKpEf=`dX47#e}dcdf`c>V~ZGFo9Pf@ z^i>=oIHQB?xwVdjzPBo7)8|m=hOH^@Q4#2Vg@83a4*hKw2A0u$X#=!H}u!EahnQqSTlG=C+H5w@8_#bc2+RQTbXZ!G%rMe0HX&&oC1ko#;Gr5|oGUiI&Zb@WI}%C6bF7~u6nw=&p7 ziR0bVEM8gmNw?6`na9pW>6x3PTqT5VKBeNaZB) zt$KM2w?0>>MW+YMe|{}zK3y#HE6em{`4N-!BE4wv|H9Wy%C&EREo*Fs&u(tR|LA1u zdFOD@1IPdR)UUF^5|pJTJ^vjz)udnSq&B=u^2-|^_0$f7)EwgC#`;4c3LddXz3{193SF(_8`9^}6+v087Y2x9z@OYI%bH^5sN>lOU zr~C3N*xriU_gQ7QpE4cxojU0=vBrDj8VfVe^K)qCyN|2pilMkrxM@?(W@@r|icgEz zQjbAee-7sYwJ$@VKj4eFHOBPOE3y3yT8L%UH8J-wT@hb7!jk2)z|Nj8twY;a4w~I# zl4a|C(3F`gZkG3IlfDPymT-cDJ3s$r%T#u}qSqoR8ly|J3BeIcgUMGtGdjkmw}caY zzf{a-y>U*81Sg8xNvJZ~!K(Hqief5c8!kjS4%xRTRcy^?d#tY1K{(VkojZylz()By zz;Ka~WaurcMGn<}f|qZ@?`Iq>QrDhv-5r+ZEwX_0Pwy!=FyZE?8nvq~4R(uAW)I!K z9l_kb+`FS(XQKK--0KbPq3h?Bo}~<)P?n$n?{RtM(~WW`uC~i%eBoNdyS;V{q~EyG`T8ytr~=eeRVpXl=W+Va}$3${~I8Qy%fI5VI?{uBzLL zBWrc}Il^m=@*d3l+nT9Vmmbl2*|j%1qKLRdMoYJfBNm#xdXgpC*(5}}Z%lsE;20i% zEMxFM;;C5M>|@D(6Mab>8}_TAE>0_ua{nP^bQj@2Ix#5KLYkJMsFA8u?CTfmP z;iWY5DYs@k9AixTUuW?zc-S5*h5KLraY*V+zV3D}G`;Yj9|@d?y6fFn6HA^lSs_SC z3eImneM>x0C7F_`_GQ{m+fSD$!zsjJ>tj%$guEm)L;AAr`qngn#ZU5fly8Bvnt9g@ zyD&OihrKX~RruDrJgg=+^9o$zBe+&h(V3&1(0-a$S$;@K{JkLm1~$I9GkH1D5h^Y5xjD<@8Sgr*-%0+l#1)PJ0S5?7 zelBsvE7~k#aJpV08KoU#A4$O6pKtt^!o_nI>ZpFasyHggEFJf02ijyO%*s*T?j{ zuH28!C*zqy;_=G{a))J7Yr4>s)0%V^um}hETW){)E^{;ylJH4|W5!NXt;f ziN__6OJ2~siF<`(+1Y!3(_1Trw`hO;mv)(zw?&~=ftyI)sgt)T63cb$Pwj&>dUh!n z?I{<^d^(~tBsu-wkanAhez^mAHyDM}1*Y~h7{SIEaN1=z3;8W5%A*N`hm(YfEZ%kx z!9|+xjD67Q?&4LUYl-fVm>&0>BQ`w@ovxl*JMC)A-Ls$VMx86r(3#T%6n)SWQxs>Z z2=_fm6DU%||0)0^N}V)+a%vQw@+z#vf?e!{E(!-MBK_?azu+BF%?Z?f+pynEKjXdw z!8<7DVRbVw+I5mV4<~FsnZrzzm7N?3eQLBIygNbdfa@mXr5Te<0}I`gId7eA?)ijN z$b^q|g4LaWff7COPt#D)jmZ@eH(|G;V6^g58Rj<$d}Wc1#wY<>0p_o==3(E ziR6KdFi+)#OerMd=FvzJu2<;BB3N?I{yMO*;+aX_Z*-y=p`yV$tn){&u>yFw5{?Jl zFnd9YW_8@Y3`ZFaZ_l`XY*N>#_aPQsRPC~yE*28p&3Yl~^&bzrTUL=CCOj(-OT(p^(losb57 z*9cgA}cCNMc=0>Q^9WEjucqo_r!R9f^l7XQ~mW@-Q+VSfNns(mTU+8BZ= zpG%;k3HHXQivTPY<{JaWS!E3)z3Qp1Wa7+Z^LDKi831dK?Uo$c%keUmPg#9i!UnRh zS$SKGel*UIy$)@4r<~;@1PbV{b@?d4)t_+b@nL!{#$MM4yWf@T)f6n8m^dW*fd-v_ zd=4U)-#4iQH-;oZ!ysfItV+{jS&DSL0TiWUm0;P0cdd>Pxs=cNc<2+->L7Xs)A`Zx zSXKX#i*k&rt*8kDRsWr@J6zSK9_BJCe+yq^&Rh>@<&x+qg5&mJiltNA9QzJ*39v9c z*hHQ$tRtXxw)FSc2G4p5CIRNKWn_~n(5*M4_HYI)!qc(JqFWW1hQ6!Q- zmnTWK$I84>ksz8AzE4WMFeQIN@TeN<8Jm#Kw5geJwE?Gu0xRQ2Poa>rT z-h7iQ3jBz%!*_t`*0j?%8E}G~$70R@&u?~p2Zp5g@y-EgFR;x}XK((zrRj1ajY{g43?#u83S34UaQdQQXGz`3>Rcj-Gku2uoWQZ+q4 z%C36%F;h8S1$3~Q62|Y;=bDfuu|B8bSDRT8$ZzC;)Xv0@MxmRfoWa61!IlpYYobCZ z|C{*>d^@|wyhRtsmllIDQxX9qjz+glKo7GDM?wfA@{pXFCmAOs#xB6jku3TSYT>?4 zy`Gw%Fc}Q2;-sZZ;GR$-?R_JDdNzeyEH5Gr;-y(5uFJ~F!YyDEP|Fa- zse904p2`WJF-Hx(o1r!q7mzwOEl3VHmR&8lxr6UM8VH#3H{caGJC;O5pgZwdmAl@F z?By`%WIR5+kCi5=vm;B>{VKpz@{J7L7mgzPZ~_@)eYc+&ChO<*wI`Hcn&z=Ksqh3m=cVIj z^Om+Ja^l5YUylV$_RYAD8Icjgv#I(F^685J0mj63TSN}%d5gNhxk|jl!&^bYunVyp z^!cE-N!av>c-fw6D(9UUB^?Dsy2T96vQWZS`zW+UA6FzS;V}X0ljui!+(eldi_xAQ zt)FDa!D>ycxL=Iv`+wo!CyK-*7*ZfZ6u<4z3*=H6Nk}A`hxgp6I>Kywe$!CQxf$c> zF(rWkh3vARvS9X*MbU9niz2?u?I~CKBM*0&w%|l0Sc4376AViL zb++wGh)b5xNL=(|-Pw|8G#=)aD10m1&w_iZFZA%ivNk7CIExbulYCH$k&owC>Z!Zk z)P1R&vq(4&0puN^AX*anFXAXnfQfx@m|&(HSMp` z7qB-xOZV=5xpUs0{GI-qrh~f`FQ=PSvMQCFF{D02GW1+ye+5j<=0f02&=B=@TQV%G zOd5uPtdzwoSnVDWp(BLJd6$p(rgh#ekYXC@LU`6r~st5d{^L zrl{#lXzx4yOZ znq=?UGxO}(Gf(+FGtYLTlqSK8gzAD>am4sU_p4--STp)uZBh;#A;WO;btvgw58U5X zLC-Ne@Wq>#S9CUjhd6?a%FDi>?&g+3z)Y$G*}7X1R){0?1cfUa6bV~`wm>9tx?0wR zWUZOqM0Sw=AcF+>zUi(a=Lhc)q*{{3q;IIVSJ=1(k-YHGZsdL+*P_N+yakat$xaOblx*`{fLLs;9@#aAcNWWE7k9$Fqi zGp-eF`7I>Q|NRqgXHz*N;V7;n{2L&3sOY2Z@v%kad7GIuwRY=RfJ)|Z#11{4zd9ZA z@KIHbx8JqKJwH!-`$%YDr>f)`IDqrJ#%q?0LG+PrBOGBG8-Co%0+2i?5=|*`sa$%c zfV57umP1G(;tx3G{-`Udz*MOnDc?&&hD-b?V~=eDxFAvhVpCmMJxQvI{iC`6q(C+*su$%$n;QIZUL(QljfqdC zFWYl{oO*oXcY3ysk}4Aq3{^INwMo2H4mIKTs_SqGzB)qBmT<}=KQ5O!lookj>jrkhSG33N$5$5zY8I;Eu7-TA5S9jFj*Rq#)y!M?R3>a)&tS+8LCbA- zKl=Nh`_72vS!t`u(V89K&DcAVWTTo&x5PK^e)h>tG2p)Gt`#4x4{99`U@*Uzl4Yxb zmLrnFrhF_^JpTE#x#>!M?dJ%F(EWS1*)j~V1+%gN*Fq}0^X!ucv^4kj;^v3&wak;n zynB^S78a%9!6!q$R&IO!i-y#zef7IXdZPRXF23Eo7IX1wV1vhXVRg0#{j%?_WM=d2 z{*nDPGgn=YozL@{PTu$>ZiCu^$GYivpjeW=-H-}Rj8Myq{I9oNU90zp{QV0LxBCBh zX7RbOfc^<#r%y? z%n}9aWb&g$NP%kG_7N&7XVL}Y{;Wnx8!`e0##?s8jb>EyBE4O&!EB_+vJIY#!535T zj_)*`F~tseB;Ei6l`*4*!3WZNl|w|elmeaIIGpv#Lm`##Nta*hyvV1+MzhKP{jK{FG1BWCwB|rLQS@NU0mp{@dW#$D&oQlQV~kv~JuMyDs!jeX`%6Y45%!E72o` zuzumz3cCkzorSt+QCWj*DfYx3P@)Z!&&jZDxQ#Sxl{OYW3B_4(1rM%GM;{fpzce=R zm%O*-tZimcV%f69xl%W~sdWW6oc8Q%v-4zsK`f2Xu<3^D+s1J5mvL1YOKe8#&eexv z5yck=@~0i?IQhl$PnbXFJrvjLxtnhJKF;$$1Su@{KU`_>|NOw1Q*4(nHb(12jXK=- zg%W?pK!4LfBvrEo_kHRJ-4A5>77fKpQ=KY^$FTI-E`dJ}Zpb(H>+3=cBJjch_E_ZP zO~NKIRP$%@W(JXk`&{Hcc~h};#_vQE#>;`!#c`TZ6QM0xgmU>;R(u%&#q7{*Q+J_Q z=KheTLmR~=t)P3En_5kdm5I5)$gu10|H9<&$yjy7Ny@W!&ab5_HiK&IpCa|o`$q)A zxyrxOo6!-YC$?a2T7AV1y>v(l)_%oQyA9q^$-6vj8D4 z&rH}P??8c5q<}Jo&jr#w<5y0Zni6~@QQ>TVWyCoPxl+e*;xV33=mt0tF-kBr!(7-h zbP=1v-m1Gqy_>Izx}ZL8objDdh+YoQuA36Mf7id**|z!b^S;_&8JZ4?=WDOKZatTH zyaadlV{^Bk;*_cZ#LcF;KSzs%t;15iaW((&Lw;3?e*m??`}E5H*Mrq>4NEZ@OT1GL z<2a>DZjg#GICfflKbS(3#YpA6=VTtuBoX+aqGTS~a5-Y7 z5J4|3p1Ll~e$y&$r zjH3OwS1aD3U2**eWGxBz{rpxrb>PLrt5s{xy)`7!jPayQ!B|8KqsbTvt#iK9fJh2# z_Od%@UZs)>uA(MWM~eJG2D*rWUBNmlp=O7CWt@a$CLN2sxuX@64u#_OUwl;MclA)e z70h_>{-0lk?%M&4X(`Ngnw}~zr^W8C2xkaelmi?={)4KJtvxsKvW7V8TkwNLnu2cV z0-nzxh{hrjAVFkA;A*M_U+)yS^}MMwz!3eDNdrmc_w*FbTW0%e-GZiA>8D7(i71)NAo zaJ=Amr|lJ#Y#v~&iAS_2z3@*BObl3Hf)LOfABsYbpJ;=GMZf}7IQ$Hk!Qdb<@&O-M z-P%EDo({nDxM=9_)i{tg4AmIu5J<>0IRF;*itLR~o&0_c%24RXLRz?5n^)t>v>}Kr zC4h~9DFIwfo}*_(=s(T3z2fE(0iK89k&4ed2Y)t4#{aBk}@n}Gqy1IiQQC~v34N11q;~wz6Sm!5#t|H z23RTdvXld9Mx!1xED6PeG_^2NeBw<)%9BCsOi#M$U%^75-99AH`Ep5*$Q3M~-AtB$ zovMvgsCcQBlc$d1?GTF%I1Q7Q`M3s-6U)7(_XNro6O|*%%P;`YoOkkJ&+hB_$6P$F zv;EQ1$wP3EfYst_7T>->ngN_y=6g7^asnM^&bDEG z(7SuN)0#s`q59)hZ#oCfcEP@~H@}~eiuU*rK?S_vpP^ZkLbCN9?j@n9wHlNBGF}t9 zr}|ANZOejW4Y`+ZETWcp58o4ak;ie zvt6Rk@+x;56gEj;{(7=jA+O2rP221h*JD4#oNl21*_Xc<*S!(I71>EPRxiS*I4bF# zAxd0?J4+(F`~;26LtH$&E7%$NhKT7cx1GZD>?EBL&>Gxeg>e6tPCpTs*_7AX0>3+v z2Un~xa`6)+DBG=k42cgL{on#%sRklxC#CU0vzOHKG-^&s697nwui@~Uf{_KHR@BdZ=f>0 zmt+ZILxuL?97Qu3jQy+1j_WESVjfLKbc0(PO9_&+V+sKWevtUh*m6gjfYpwC%!EsA zyAnx5e!c0!XGjUfQ%LZevBhx74T9;!7wKt-pf9Zb(?j2Yqyc8)owF?)+=;%+c??9p zk(cKMy@zs67&=wCR+gjfa{T19IE^2If1I967c~wgrsi#1-rT!M{H0xNx01sA?T60) z=vE&aLO3OWYSr`8ilJ)xYu5R~G8A+!J@bjh6bY3td50wS$Qi?@kA%tMNWFmiN5rEJ z1qZX7$4?R$^tagyvm2xsJ8sq{G*j1ElqA#-O2L_Dj0H1iwvStBI~v+Fqcq2@G)Fha zON+}P#^r+N)Mc5`_Yb%^1iAW zKTHz8`I85tw=jy4>o{?VD|DQQ*J!)dIRCchNbK~pE%d`3fjkRaTToWUH|O(HD3E`? z#*RHTdtyVPPo9%Z{4(>J|(nJaZu5xD;`wOMt;!$RKn! zQwX!#NJ4-u=30-m!WEOlD*x8LDJt!@GNv7wZK(UBEq(UFRHBwtR_%b+Ua)khA-^Rnn7I2 zfzc`}zQ!Nhb#VpZzxdR5Ytd_}dCXZ&b2jne*^jJX%8KNR5{bJ03mHOu8V$Cv*(><3 zW%ZmG3`>L~S?V;lAFwcLDMvs;2i%3=G-vC_h#}>h>mdfo*620@` zJKC1!2d!7eS8Crhu|!)D((^ab;kUs7(5 z+h2SXX1uGmc-JcVpwR;768%avt01SABa>j2lXi5@g6!Q{@vil?eUvuG zoK%y?A&b8DQQk{X1`-amI{HZW?)8{}qbRuU^SbL`C_drT^*|CA-i{}&3%&*I!(Yks zLKI0of+GvZs9H{_F;2#2HcaMC^gT`MrgR5jD>aIVhi5UG2d}L@l>QZ|y%(T|iyxl= z(}*idX*%y+Brscb;WHx@jBvR#ci_a*zN918^_wo32^Fnesk`k8Xe7rZF0AP3ID|kl zfy7Fb(2WLr#td~J)idx}4g}sy4(cPG3#>uSMi)Ong~vI)b0gqV?cy1i!UE<>-wAG#7?=pLp)F|kEG0#9DiwbCSPSF_68=58bthBb!*?ry6(Aa z4Y%A}S1H3fW7y8>*6jX9e6bIv%NbL4J#aNM?AoV7mxwqqp2kyhYnnwk{w_qKjXo9w z+D129wBOb6gvi!CH#L-hYvI>Sgg`Tc_5x_GnJ<=q-1Ts+m*4s3Nfu7$BB7pYCGid5 z378tisfH94?kTNL@^sa6cQf0cqeKQ3%jSsQuhq!T$e3kl$$im5OFGLp!0#WaL*88yweF+U9H095=4Uc7n$DnhuHQ*Y%ymH~bPgIcp4Jg3 z!JDW^l-l;%jg~2l$XYW_~!zJ9dSOy1N#K6U08X{NtO`>>N#6x-&A^G3QVMXODdE zFh*OgNgr7p4xupxjF96JyeawF;caRI|4vj9D?X!ko%m&g=9Vs>g&qb9XG?gr)M2)} zi-)Zqj^#f+V4rYe?KC+}?56GBRVA2pU9p!XPSS3<=ghK#!Y6OH2wwl{`A%6ONf{u* z*L5ECBVe+-^3`z|hf(WWYh3UQFouBN$)9gu@y5MpraCz>!b-1b#8(=V$$-&qXrNn# z1QR-IZ$S1t*Q05&$|iYL#$Kwsq4zVPATg%K11GD7kusMp z;0C>p`kT+7RvCbiwudj z_g1hr#+)z@iDHNVBF4e~1 z;>P2SEh(9~%O82k|9R@rcL`*iv=Xv8QBGM<(3V6oF|7kj2*atvl}q5lEQ_`NJK*?W zPF!5c=-)8q-JUoiWQb+Kg57VvC@|SrFk%K&l~duc+T;nb6$N|%P$nLst-z0jdONS5 z^a+h563}vs3S;?y9q_&%+-Z!pqbFV&F9jvFLHR4=*9vm_vL5gEc82yi(5|>AjpY{< zIQ0ZGyNng~w^WNr3CVLgEm>&*N)k&k`ty4gAqTthT`|8yr_k1RpwBZpGCJBbIwJO| z7o6rG79F+8?yTnWlhM(3k{GO>Ft5cnI?AqG`)Pm37i6#oSpiO8;Tavc1CB}ZFOp;4 zoNpr7{hg#hPp9u2gN>$w8yS%Ob1qLs(-^({&70~sQ$Ldgy!|QZ_7Gby05sn=$0{ai z?h9i$9a%^L$lAccTGiI9P}som5az3yjR#Cc+Qfd+cepp0A&^?no&`=zkN6H}wr7Cq zAu9hhhJFCJXFTTA*DVXbCUxQY>$^`f*T#TC2Jhr#X9gDbw0TEvohHcw&#HgwrM{srx7^6jS`2JG zaSgUIp{3n=VSFueygI-~!S7~reK7(bM(Dy&@k599zaJ;ioh8fAhvC#Ksqe?7ss8X8 z_9}xheaePD{w|*QGSGP6Rj4(n_7-(hrN=Q!**=)ZiZvwriuUlV-c6XRSQt4QqaD$_ zgK&y90~i|sXua>vJNp$hu0qgBZ`kmynW~TKNX02^=2=WjdqZJJA72F}W3}tiZ{1?@ zep|Z&1Z?m3TprX{y;$4e{^j+6l3`@$#YbAjHB)s}i zAxuWvRMINa%X)-B0`HsXTahj?yp+y7sfKE3nZtoC!hF?zKW1Ir*iX+-M48{|pI~4P zJ<#i1;@kxTc~W)6j_LZXyE`xcv1s~J37sh>-dmS3`r+hTy}vwf)*SSkYkVGi=jUmO zfW^9124jPX^WyVzbTA)52BL()#VA}}xcpn)ds)WFq#kS_^(kDZSlx$;ojITwc!jNa zv&! zE^-uckD&EdH!q6}3jvrJc)#LgJc!tgMu?ayE=C7!Nd>Bo!Vkasy5g#H&I_s{x_-0; zA+8U zKoTt*&gFM-yc2MCs=k0?lzdl7$Su>yRHp@RWGJE5?g{>=#9<+QkmPXl(5W+`I!ui2 zy4Uc)C;sIhGhE?uAz|P;>p@IHVpv@d`(Pd_?`?hYAZ2?!sW;!uJK=kK$48Dm1~yJ> zw&h4)G5JY=1%k8s*6AfmVSr<((t=UiB3upGtgYP1Z!5fV+Mt<=# zCqZSPXXN*X`){N*&wIYB+Z@z5oOrzchd+b(IHYS=rH=Pk|NiJ5zZt0ia%@59bVBex zel1ldXx^{u`O5f9i2WbcjqoOJTq%D-R)L8sMH|-uN7$p23WV-ShDfN9TiYj28je;^MPQJtzdUe;2d-j=qv@e z?Jv>?YgjXlvd!-|Vv>~sIi#ZxV5T=@RrDSqB-N9BXI4;DETojvp!%#s4MjWVZ~e5> z4BdY^As_v8Li$vGN!S%peAP|opBK8}yEnJFZR6Oka;=4o7uS|Bi47-1E{IRER0{Bf zw!LqL|9z+vnFQIbuik&ty!xc@ch$8mzZg{Ion$_i3=^SaOE%3uDZETv}lwdhy*SCJ@| zD40f})d?NC%`e{$oDYXLqs>NtgDBiSzK1O6jWd&H(--I?eUPSA*|krwsCeh%@{Uc{ z-LYc3YM@b=M*mMQ;}x1@H<+ zjhDzl*aY*di^z4n~KJk!JmQp*l2T~o-PTarJtD3+8>&8Fk67Q!^s_rG&=@ECpP zn1s8=!)MII?^f$h2+v#jy`YW!nO_K%H7S#txlTJU$MeCC!wdh*#I6&`x;g95SGurM z2Tk6#n*ZdgE}G1lNXb{HCLUg3KzrQ*nhNZz9l#`ML(2VvQ-@uc&XqH@;@Ys}z5w}m zL)%uL{C9$d15oUFViLea%B0;&{F%#lSZ`M#6k^At5N)ZqVm1G;Cgu(cehOI#$XuGZ z|GA)~W3i>kZ>P;999Y$j9$l8_Wf>6oM9o!O&l)!o)Ckc1RVqLf&Y44xg{#Xl7%~li zk?c>8r*xqQDO92)md+1M2lab$7w`Vi4mJLku!$UOc}={@3h<(;Z?ZqJV1OTXSZ`!P z5NL5=MBKaD1E15NP4U@E*nyetv@=dz>59aOC}0ZMXxHqBVK_~7);C+Gp5P_HKmvm} z>q7I9m4}(8;8zoL!DXF7K?1ma?Y^(MKbB*xUBGe(mPP0H#^%e7%g*V#}JP>cv_w~QJem>BjLlzYMXKvkRs^SNR-a$hB&if9=qF%#ab7Ll2F z3$Rc~AdqBazFd!c{m;YvzP702i}?>>o$)aQdYPy|Q-1&Q3vZ_Gzxn@3G7&(gt+4oF z+*j^=h8{8bfAF*M8!%$Yp7XBW5ZSf2!QheB_3=8NoawCL{r?|cqPFgu_2(?>pJ6h_ z2v+?7>Qirmd@CGOT8W+ED8YF>bz(*d8+Md3Xh1232 zax5?vM)63C)ijhox+LM1fFuq71Q6F8V5YD+Wnxk=7~81I1Q;E6!H4U@V3)_vV>EhI z0OoeQnb3a&KylF{1(+;HCWI@^wDkx%@q&bVK)xI?pGH9^qnWLscph1mYay^Xl3g^@ zChcK(q)l>5kNS=^mMj=fh@F({Oa}2dq4nC`UagW6$Af2ZUO*&ej7WW)xOvlaVt{A5SFjjCHqcIV15y5`Dq;{XOV7IcG8;W2S;2Z8qz!1=<1rW}hx}P*Ed{uh zIlzo4x)fu9PO;%(0LGgDj4aCm*@yCq*bO6T*k@23O(@!uqa&kWr>pkZ3d(1tL;_fl zg?s4;tGtYQF6OFZQpyMqR7I_048B!Gnb<{23fG$18)ILn`LxLtA|(2Q&4pvcaI!p# ziUv^3Hb4kIMC~6Sb|P^*a-QT)A;aO5Xagi_q>l*z607uEHbpT2*C6D`Fwi??hoXC; z*5lt8i;^$k+t!hoAl_Da^>z>nbj=78*+=YG*9hD%ctJv_W3<_T>Z|nr*kYNmXV(=S z54=L@kLwb8(X00-n588@JxVNV%Jr9I)M}nLvKyvNp@}rW{t4+^JXdrA=+T;N?5C+tXuaOb>31sq1{NEfxXH|IzpzUQqwsys#l37%WTv0+!C^!83Fex79^=+ z>72tAfXq?RaYq~?3qRO|U&R{^xVKC$$(1C_vGA(@fcJBPi?r`^^GHweq#;UTZ4Ei9Ft|%;Rcz-MN?26om^$c``zZAIQbbnN9&=>>3m zHgY6o4}oU~Pk^?;P;>`waJQ5jrt|}&V;JM76b`8XR%v{_=rypV2_2KDnu)AmC#Qn~ zM8G*6HMo}Lw&_e8rjhx~At0_5X|~#>HsP4a3W3_3V}l@Sn>bSm zrjM_wxwZmq?v9IrTb~AKDbf$AFZ&yKkZ%#lL>inNObEr@-qk5f7@*!0td%EB!jo`5 z*mKrL)2qpRZ=R}@lq*g46uWQ-zZ>kc;F^osjKha;15^Qkh3VsV5o)BEa;&pF5evTC z7r*S@i9hfMnSJB}_ly2S{+nuD|L}A3^xX5>7Q&=)mG=kPih^iMxZ?&=P9Y`XeJUFT z0BtTVXS>+Al)vr4B$-i}-VZo}BM+HOnZZpYMTlL*1pgh_nedn)X?CP}4M?iL7wv8) z2Ux*K_kGcI+F_;pRX8M8uVk6(sNEopd`b5+Dr=a)_g~W-%}h`<5LlgJDOr}(D+nrp z^GqozOqlhaB&wRT>L3d^H(uayR7{Z}cV_vh3*Ow?9;GoANFh_~CrX%E=1wC#E}Uq;;_ZXg086l154=zw2e8^=86UWK$pe5)=Oc`+ zHZh)pbb0A-)l0_pwSr!~09DoP6Ijma^c>wH_7I0n0e3U2F;;6L!YSdpSj2h0$lM;8 ZWo(r8V-v>Dy%_)7KTh9((cEuC{{!C=NBRH& literal 0 HcmV?d00001 From f6623b6a69d2954885bb31ca976c5fabd2b45cec Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Wed, 14 Jun 2017 16:24:37 +0800 Subject: [PATCH 079/179] update --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 504f2becd6..45b37b9c7e 100644 --- a/readme.md +++ b/readme.md @@ -15,7 +15,7 @@ 1. 本SDK要求的最低JDK版本是7,还在使用JDK6的用户请参考[【此项目】]( https://github.com/binarywang/weixin-java-tools-for-jdk6) ,而其他更早的JDK版本则需要自己改造实现。 1. 如有新功能需求,发现BUG,或者由于微信官方接口调整导致的代码问题,可以直接在[【Issues】](https://github.com/Wechat-Group/weixin-java-tools/issues)页提出issue,便于讨论追踪问题; 1. 如果想贡献代码,请阅读[【代码贡献指南】](contribution.md); -1. 捐助渠道已开通,如有意向请前往托管于码云的项目首页(具体地址见下文)的页面评论区上方,可以找到“捐助”按钮,非常感谢各位捐助的同学! +1. **捐助渠道已开通,如有意向请点击[支付宝二维码](alipay_qrcode.jpg)捐赠,或者直接前往[托管于码云的项目首页](http://git.oschina.net/binary/weixin-java-tools)的页面,在评论区上方可以找到“捐助”按钮。非常感谢各位捐助的同学!** --------------------------------- ## SDK使用交流方式说明: From e241de6a30ba36dd4462f59b3184e7e5ceb49809 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Wed, 14 Jun 2017 16:26:20 +0800 Subject: [PATCH 080/179] update --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 45b37b9c7e..cfc090b3cd 100644 --- a/readme.md +++ b/readme.md @@ -15,7 +15,7 @@ 1. 本SDK要求的最低JDK版本是7,还在使用JDK6的用户请参考[【此项目】]( https://github.com/binarywang/weixin-java-tools-for-jdk6) ,而其他更早的JDK版本则需要自己改造实现。 1. 如有新功能需求,发现BUG,或者由于微信官方接口调整导致的代码问题,可以直接在[【Issues】](https://github.com/Wechat-Group/weixin-java-tools/issues)页提出issue,便于讨论追踪问题; 1. 如果想贡献代码,请阅读[【代码贡献指南】](contribution.md); -1. **捐助渠道已开通,如有意向请点击[支付宝二维码](alipay_qrcode.jpg)捐赠,或者直接前往[托管于码云的项目首页](http://git.oschina.net/binary/weixin-java-tools)的页面,在评论区上方可以找到“捐助”按钮。非常感谢各位捐助的同学!** +1. **捐助渠道已开通,如有意向请点击[【支付宝二维码】](alipay_qrcode.jpg)捐赠,或者直接前往[【托管于码云的项目首页】](http://git.oschina.net/binary/weixin-java-tools),在评论区上方可以找到“捐助”按钮。非常感谢各位捐助的同学!** --------------------------------- ## SDK使用交流方式说明: From 02793bda6ce0ffab0adddebc3ccd1b1c7eb38519 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Wed, 14 Jun 2017 16:29:20 +0800 Subject: [PATCH 081/179] update --- contribution.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contribution.md b/contribution.md index edc9e79a0b..8c38553cc5 100644 --- a/contribution.md +++ b/contribution.md @@ -28,7 +28,7 @@ $ git push ```bash $ git remote add upstream https://github.com/wechat-group/weixin-java-tools $ git fetch upstream -$ git checkout dev -$ git rebase upstream/dev -$ git push -f origin dev +$ git checkout develop +$ git rebase upstream/develop +$ git push -f origin develop ``` From a8fbf3c4c7b28fa8a00688739dae6363f2e2f097 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Wed, 14 Jun 2017 16:29:56 +0800 Subject: [PATCH 082/179] update --- contribution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribution.md b/contribution.md index 8c38553cc5..91be80a478 100644 --- a/contribution.md +++ b/contribution.md @@ -1,7 +1,7 @@ # 代码贡献指南 1. 非常欢迎和感谢对本项目发起Pull Request的同学,本项目代码风格为使用2个空格代表一个Tab,因此在提交代码时请注意一下,否则很容易在IDE格式化代码后与原代码产生大量diff,这样会给其他人阅读代码带来极大的困扰。为了便于设置,本项目引入editorconfig插件,请使用eclipse的同学在贡献代码前安装相关插件,IntelliJ IDEA新版本自带支持,如果没有可自行安装插件。 1. 本项目可以采用两种方式接受代码贡献: -    * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择dev分支,详细步骤参考后文,推荐使用此种方式贡献代码。 +    * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择develop分支,详细步骤参考后文,推荐使用此种方式贡献代码。 * (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。 1. 另外,提交代码前请检查代码是否已经格式化,并且保证新增加或者修改的方法都有完整的参数说明,而public方法必须拥有相应的单元测试并通过测试。 From 4c0337353c4151414ae21f100c69a5bb50cf10b2 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 15 Jun 2017 19:32:30 +0800 Subject: [PATCH 083/179] =?UTF-8?q?=E6=94=AF=E4=BB=98=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E7=B1=BB=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wxpay/bean/WxPayOrderNotifyCoupon.java | 7 --- .../result/WxPayOrderNotifyResultTest.java | 58 +++++++++++++++++++ 2 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResultTest.java diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyCoupon.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyCoupon.java index c72ddcb222..c2b4e22e74 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyCoupon.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyCoupon.java @@ -1,6 +1,5 @@ package com.github.binarywang.wxpay.bean; -import com.thoughtworks.xstream.annotations.XStreamAlias; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -12,16 +11,10 @@ * 支付异步通知代金券详细 */ public class WxPayOrderNotifyCoupon implements Serializable { - /** - * @fields serialVersionUID - */ private static final long serialVersionUID = -4165343733538156097L; - @XStreamAlias("coupon_id") private String couponId; - @XStreamAlias("coupon_type") private String couponType; - @XStreamAlias("coupon_fee") private Integer couponFee; public String getCouponId() { diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResultTest.java new file mode 100644 index 0000000000..389b374d9e --- /dev/null +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResultTest.java @@ -0,0 +1,58 @@ +package com.github.binarywang.wxpay.bean.result; + +import org.testng.*; +import org.testng.annotations.*; + +/** + *
+ * Created by Binary Wang on 2017-6-15.
+ * @author Binary Wang
+ * 
+ */ +public class WxPayOrderNotifyResultTest { + @Test + public void testFromXML() throws Exception { + String xmlString = "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " 2\n" + + " \n" + + " 10000\n" + + " 100\n" + + " \n" + + " 10001\n" + + " 200\n" + + ""; + + WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlString); + + Assert.assertEquals(result.getCouponCount().intValue(), 2); + Assert.assertNotNull(result.getCouponList()); + Assert.assertEquals(result.getCouponList().size(), 2); + + Assert.assertEquals(result.getCouponList().get(0).getCouponFee().intValue(), 100); + Assert.assertEquals(result.getCouponList().get(1).getCouponFee().intValue(), 200); + + Assert.assertEquals(result.getCouponList().get(0).getCouponType(), "CASH"); + Assert.assertEquals(result.getCouponList().get(1).getCouponType(), "NO_CASH"); + + Assert.assertEquals(result.getCouponList().get(0).getCouponId(), "10000"); + Assert.assertEquals(result.getCouponList().get(1).getCouponId(), "10001"); + } + +} From 0546e001f65b6ad17fb76cbad5c820d37b1a932d Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 15 Jun 2017 23:58:06 +0800 Subject: [PATCH 084/179] fix logback-test.xml --- weixin-java-common/src/test/resources/logback-test.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/weixin-java-common/src/test/resources/logback-test.xml b/weixin-java-common/src/test/resources/logback-test.xml index e69034238e..984cd3ce69 100644 --- a/weixin-java-common/src/test/resources/logback-test.xml +++ b/weixin-java-common/src/test/resources/logback-test.xml @@ -1,5 +1,3 @@ - - diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml new file mode 100644 index 0000000000..1dbf7835ed --- /dev/null +++ b/weixin-java-miniapp/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + com.github.binarywang + weixin-java-parent + 2.6.3.BETA + + weixin-java-miniapp + WeiXin Java Tools - MiniApp + 微信小程序Java SDK + + + + com.github.binarywang + weixin-java-common + ${project.version} + + + + org.jodd + jodd-http + provided + + + com.squareup.okhttp3 + okhttp + provided + + + + org.testng + testng + test + + + ch.qos.logback + logback-classic + test + + + com.google.inject + guice + test + + + org.eclipse.jetty + jetty-server + test + + + org.eclipse.jetty + jetty-servlet + test + + + joda-time + joda-time + test + + + redis.clients + jedis + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + src/test/resources/testng.xml + + + + + + + diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMediaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMediaService.java new file mode 100644 index 0000000000..09c8aa5b9d --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMediaService.java @@ -0,0 +1,65 @@ +package cn.binarywang.wx.miniapp.api; + +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.File; +import java.io.InputStream; + +/** + *
+ * 临时素材接口
+ * Created by Binary Wang on 2016/7/21.
+ * 
+ * + * @author Binary Wang + */ +public interface WxMaMediaService { + String MEDIA_UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?type=%s"; + String MEDIA_GET_URL = "https://api.weixin.qq.com/cgi-bin/media/get"; + + /** + *
+   * 新增临时素材
+   * 小程序可以使用本接口把媒体文件(目前仅支持图片)上传到微信服务器,用户发送客服消息或被动回复用户消息。
+   * 详情请见: 新增临时素材
+   * 接口url格式:https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
+   * 
+ * + * @param mediaType 媒体类型, + * @param file 文件对象 + * @see #uploadMedia(String, String, InputStream) + */ + WxMediaUploadResult uploadMedia(String mediaType, File file) throws WxErrorException; + + /** + *
+   * 新增临时素材
+   * 小程序可以使用本接口把媒体文件(目前仅支持图片)上传到微信服务器,用户发送客服消息或被动回复用户消息。
+   *
+   * 详情请见: 新增临时素材
+   * 接口url格式:https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
+   * 
+ * + * @param mediaType 媒体类型 + * @param fileType 文件类型 + * @param inputStream 输入流 + * @see #uploadMedia(java.lang.String, java.io.File) + */ + WxMediaUploadResult uploadMedia(String mediaType, String fileType, InputStream inputStream) throws WxErrorException; + + /** + *
+   * 获取临时素材
+   * 小程序可以使用本接口获取客服消息内的临时素材(即下载临时的多媒体文件)。目前小程序仅支持下载图片文件。
+   *
+   * 详情请见: 获取临时素材
+   * 接口url格式:https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
+   * 
+ * + * @param mediaId 媒体Id + * @return 保存到本地的临时文件 + */ + File getMedia(String mediaId) throws WxErrorException; + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java new file mode 100644 index 0000000000..040e81e530 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java @@ -0,0 +1,36 @@ +package cn.binarywang.wx.miniapp.api; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + *
+ * 消息发送接口
+ * 
+ * + * @author Binary Wang + */ +public interface WxMaMsgService { + String KEFU_MESSAGE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; + String TEMPLATE_MSG_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send"; + + /** + *
+   * 发送客服消息
+   * 详情请见: 发送客服消息
+   * 接口url格式:https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
+   * 
+ */ + boolean sendKefuMsg(WxMaKefuMessage message) throws WxErrorException; + + /** + *
+   * 发送模板消息
+   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN
+   * 
+ * + * @return 消息Id + */ + String sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException; +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java new file mode 100644 index 0000000000..822f5de8a4 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java @@ -0,0 +1,30 @@ +package cn.binarywang.wx.miniapp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.File; + +/** + *
+ * 二维码相关操作接口
+ * 文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html
+ * 
+ * + * @author Binary Wang + */ +public interface WxMaQrcodeService { + + /** + *
+   * 获取小程序页面二维码
+   * 适用于需要的码数量较少的业务场景
+   * 通过该接口,仅能生成已发布的小程序的二维码。
+   * 可以在开发者工具预览时生成开发版的带参二维码。
+   * 带参二维码只有 100000 个,请谨慎调用。
+   * 
+ * + * @param path 不能为空,最大长度 128 字节 + * @param width 默认430 二维码的宽度 + */ + File createQrcode(String path, int width) throws WxErrorException; +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java new file mode 100644 index 0000000000..9098d4ac48 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java @@ -0,0 +1,135 @@ +package cn.binarywang.wx.miniapp.api; + +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; + +/** + * @author Binary Wang + */ +public interface WxMaService { + /** + * 获取access_token + */ + String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; + + /** + *
+   * 验证消息的确来自微信服务器
+   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
+   * 
+ */ + boolean checkSignature(String timestamp, String nonce, String signature); + + /** + * 获取access_token, 不强制刷新access_token + * + * @see #getAccessToken(boolean) + */ + String getAccessToken() throws WxErrorException; + + /** + *
+   * 获取access_token,本方法线程安全
+   * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
+   *
+   * 另:本service的所有方法都会在access_token过期是调用此方法
+   *
+   * 程序员在非必要情况下尽量不要主动调用此方法
+   *
+   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN
+   * 
+ * + * @param forceRefresh 强制刷新 + */ + String getAccessToken(boolean forceRefresh) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 + */ + String get(String url, String queryParam) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 + */ + String post(String url, String postData) throws WxErrorException; + + /** + *
+   * Service没有实现某个API的时候,可以用这个,
+   * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
+   * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
+   * 
+ */ + T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + + /** + *
+   * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试
+   * 默认:1000ms
+   * 
+ */ + void setRetrySleepMillis(int retrySleepMillis); + + /** + *
+   * 设置当微信系统响应系统繁忙时,最大重试次数
+   * 默认:5次
+   * 
+ */ + void setMaxRetryTimes(int maxRetryTimes); + + /** + * 获取WxMaConfig 对象 + * + * @return WxMaConfig + */ + WxMaConfig getWxMaConfig(); + + /** + * 注入 {@link WxMaConfig} 的实现 + */ + void setWxMaConfig(WxMaConfig wxConfigProvider); + + /** + * 返回消息(客服消息和模版消息)发送接口方法实现类,以方便调用其各个接口 + * + * @return WxMaMsgService + */ + WxMaMsgService getMsgService(); + + /** + * 返回素材相关接口方法的实现类对象,以方便调用其各个接口 + * + * @return WxMaMediaService + */ + WxMaMediaService getMediaService(); + + /** + * 返回用户相关接口方法的实现类对象,以方便调用其各个接口 + * + * @return WxMaUserService + */ + WxMaUserService getUserService(); + + /** + * 返回二维码相关接口方法的实现类对象,以方便调用其各个接口 + * + * @return WxMaQrcodeService + */ + WxMaQrcodeService getQrcodeService(); + + /** + * 初始化http请求对象 + */ + void initHttp(); + + /** + * 请求http请求相关信息 + */ + RequestHttp getRequestHttp(); + + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java new file mode 100644 index 0000000000..84b17378ca --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java @@ -0,0 +1,39 @@ +package cn.binarywang.wx.miniapp.api; + +import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; +import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + * 用户信息相关操作接口 + * + * @author Binary Wang + */ +public interface WxMaUserService { + String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session"; + + /** + * 获取登录后的session信息 + * + * @param jsCode 登录时获取的 code + */ + WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException; + + /** + * 解密用户敏感数据 + * + * @param sessionKey 会话密钥 + * @param encryptedData 消息密文 + * @param ivStr 加密算法的初始向量 + */ + WxMaUserInfo getUserInfo(String sessionKey, String encryptedData, String ivStr); + + /** + * 验证用户信息完整性 + * + * @param sessionKey 会话密钥 + * @param rawData 微信用户基本信息 + * @param signature 数据签名 + */ + boolean checkUserInfo(String sessionKey, String rawData, String signature); +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImpl.java new file mode 100644 index 0000000000..66ad3c2a91 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImpl.java @@ -0,0 +1,61 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaMediaService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.UUID; + +/** + * @author Binary Wang + */ +public class WxMaMediaServiceImpl implements WxMaMediaService { + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private WxMaService wxMaService; + + public WxMaMediaServiceImpl(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + @Override + public WxMediaUploadResult uploadMedia(String mediaType, String fileType, InputStream inputStream) throws WxErrorException { + try { + return this.uploadMedia(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); + } catch (IOException e) { + e.printStackTrace(); + throw new WxErrorException(WxError.newBuilder().setErrorMsg(e.getMessage()).build()); + } + } + + @Override + public WxMediaUploadResult uploadMedia(String mediaType, File file) throws WxErrorException { + String url = String.format(MEDIA_UPLOAD_URL, mediaType); + return this.wxMaService.execute(MediaUploadRequestExecutor.create(this.wxMaService.getRequestHttp()), url, file); + } + + @Override + public File getMedia(String mediaId) throws WxErrorException { + try { + RequestExecutor executor = MediaDownloadRequestExecutor + .create(this.wxMaService.getRequestHttp(), Files.createTempDirectory("wxma").toFile()); + return this.wxMaService.execute(executor, MEDIA_GET_URL, "media_id=" + mediaId); + } catch (IOException e) { + this.log.error(e.getMessage(), e); + throw new WxErrorException(WxError.newBuilder().setErrorMsg(e.getMessage()).build()); + } + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java new file mode 100644 index 0000000000..238bbe0e7f --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java @@ -0,0 +1,40 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaMsgService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + * @author Binary Wang + */ +public class WxMaMsgServiceImpl implements WxMaMsgService { + private static final JsonParser JSON_PARSER = new JsonParser(); + private WxMaService wxMaService; + + public WxMaMsgServiceImpl(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + @Override + public boolean sendKefuMsg(WxMaKefuMessage message) throws WxErrorException { + String responseContent = this.wxMaService.post(KEFU_MESSAGE_SEND_URL, message.toJson()); + return responseContent != null; + } + + @Override + public String sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException { + String responseContent = this.wxMaService.post(TEMPLATE_MSG_SEND_URL, templateMessage.toJson()); + JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); + if (jsonObject.get("errcode").getAsInt() == 0) { + return jsonObject.get("msgid").getAsString(); + } + + throw new WxErrorException(WxError.fromJson(responseContent)); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java new file mode 100644 index 0000000000..f0fc36af16 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java @@ -0,0 +1,28 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaQrcode; +import cn.binarywang.wx.miniapp.util.http.QrCodeRequestExecutor; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.File; + +/** + * @author Binary Wang + */ +public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { + private WxMaService wxMaService; + + public WxMaQrcodeServiceImpl(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + @Override + public File createQrcode(String path, int width) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode"; + return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), + url, new WxMaQrcode(path, width)); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java new file mode 100644 index 0000000000..167341265a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java @@ -0,0 +1,265 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.*; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import com.google.gson.JsonParser; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.crypto.SHA1; +import me.chanjar.weixin.common.util.http.*; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.concurrent.locks.Lock; + +/** + * @author Binary Wang + */ +public class WxMaServiceImpl implements WxMaService, RequestHttp { + private static final JsonParser JSON_PARSER = new JsonParser(); + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private CloseableHttpClient httpClient; + private HttpHost httpProxy; + private WxMaConfig wxMaConfig; + + private WxMaMsgService kefuService = new WxMaMsgServiceImpl(this); + private WxMaMediaService materialService = new WxMaMediaServiceImpl(this); + private WxMaUserService userService = new WxMaUserServiceImpl(this); + private WxMaQrcodeService qrCodeService = new WxMaQrcodeServiceImpl(this); + + private int retrySleepMillis = 1000; + private int maxRetryTimes = 5; + + @Override + public CloseableHttpClient getRequestHttpClient() { + return httpClient; + } + + @Override + public HttpHost getRequestHttpProxy() { + return httpProxy; + } + + @Override + public HttpType getRequestType() { + return HttpType.APACHE_HTTP; + } + + @Override + public void initHttp() { + WxMaConfig configStorage = this.getWxMaConfig(); + ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder(); + if (null == apacheHttpClientBuilder) { + apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); + } + + apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost()) + .httpProxyPort(configStorage.getHttpProxyPort()) + .httpProxyUsername(configStorage.getHttpProxyUsername()) + .httpProxyPassword(configStorage.getHttpProxyPassword()); + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort()); + } + + this.httpClient = apacheHttpClientBuilder.build(); + } + + @Override + public RequestHttp getRequestHttp() { + return this; + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMaConfig().getAccessTokenLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.getWxMaConfig().expireAccessToken(); + } + + if (this.getWxMaConfig().isAccessTokenExpired()) { + String url = String.format(WxMaService.GET_ACCESS_TOKEN_URL, this.getWxMaConfig().getAppid(), + this.getWxMaConfig().getSecret()); + try { + HttpGet httpGet = new HttpGet(url); + if (this.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) { + String resultContent = new BasicResponseHandler().handleResponse(response); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.getWxMaConfig().updateAccessToken(accessToken.getAccessToken(), + accessToken.getExpiresIn()); + } finally { + httpGet.releaseConnection(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } finally { + lock.unlock(); + } + + return this.getWxMaConfig().getAccessToken(); + } + + @Override + public boolean checkSignature(String timestamp, String nonce, String signature) { + try { + return SHA1.gen(this.getWxMaConfig().getToken(), timestamp, nonce).equals(signature); + } catch (Exception e) { + this.log.error("Checking signature failed, and the reason is :" + e.getMessage()); + return false; + } + } + + @Override + public String getAccessToken() throws WxErrorException { + return getAccessToken(false); + } + + @Override + public String get(String url, String queryParam) throws WxErrorException { + return execute(SimpleGetRequestExecutor.create(this), url, queryParam); + } + + @Override + public String post(String url, String postData) throws WxErrorException { + return execute(SimplePostRequestExecutor.create(this), url, postData); + } + + /** + * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 + */ + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + int retryTimes = 0; + do { + try { + return this.executeInternal(executor, uri, data); + } catch (WxErrorException e) { + if (retryTimes + 1 > this.maxRetryTimes) { + this.log.warn("重试达到最大次数【{}】", maxRetryTimes); + //最后一次重试失败后,直接抛出异常,不再等待 + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + WxError error = e.getError(); + // -1 系统繁忙, 1000ms后重试 + if (error.getErrorCode() == -1) { + int sleepMillis = this.retrySleepMillis * (1 << retryTimes); + try { + this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + Thread.sleep(sleepMillis); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + } else { + throw e; + } + } + } while (retryTimes++ < this.maxRetryTimes); + + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + if (uri.contains("access_token=")) { + throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); + } + String accessToken = getAccessToken(false); + + String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken; + + try { + T result = executor.execute(uriWithAccessToken, data); + this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, result); + return result; + } catch (WxErrorException e) { + WxError error = e.getError(); + /* + * 发生以下情况时尝试刷新access_token + * 40001 获取access_token时AppSecret错误,或者access_token无效 + * 42001 access_token超时 + * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期) + */ + if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001 || error.getErrorCode() == 40014) { + // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token + this.getWxMaConfig().expireAccessToken(); + if (this.getWxMaConfig().autoRefreshToken()) { + return this.execute(executor, uri, data); + } + } + + if (error.getErrorCode() != 0) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, error); + throw new WxErrorException(error); + } + return null; + } catch (IOException e) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uriWithAccessToken, data, e.getMessage()); + throw new RuntimeException(e); + } + } + + @Override + public WxMaConfig getWxMaConfig() { + return this.wxMaConfig; + } + + @Override + public void setWxMaConfig(WxMaConfig wxConfigProvider) { + this.wxMaConfig = wxConfigProvider; + this.initHttp(); + } + + @Override + public void setRetrySleepMillis(int retrySleepMillis) { + this.retrySleepMillis = retrySleepMillis; + } + + @Override + public void setMaxRetryTimes(int maxRetryTimes) { + this.maxRetryTimes = maxRetryTimes; + } + + @Override + public WxMaMsgService getMsgService() { + return this.kefuService; + } + + @Override + public WxMaMediaService getMediaService() { + return this.materialService; + } + + @Override + public WxMaUserService getUserService() { + return this.userService; + } + + @Override + public WxMaQrcodeService getQrcodeService() { + return this.qrCodeService; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java new file mode 100644 index 0000000000..e2fdb9dc2b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java @@ -0,0 +1,51 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.WxMaUserService; +import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; +import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; +import com.google.common.base.Joiner; +import me.chanjar.weixin.common.exception.WxErrorException; +import org.apache.commons.codec.digest.DigestUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Binary Wang + */ +public class WxMaUserServiceImpl implements WxMaUserService { + private WxMaService service; + + WxMaUserServiceImpl(WxMaService service) { + this.service = service; + } + + @Override + public WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException { + final WxMaConfig config = service.getWxMaConfig(); + Map params = new HashMap<>(); + params.put("appid", config.getAppid()); + params.put("secret", config.getSecret()); + params.put("js_code", jsCode); + params.put("grant_type", "authorization_code"); + + String result = this.service.get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params)); + return WxMaJscode2SessionResult.fromJson(result); + } + + @Override + public WxMaUserInfo getUserInfo(String sessionKey, String encryptedData, String ivStr) { + return WxMaUserInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)); + } + + @Override + public boolean checkUserInfo(String sessionKey, String rawData, String signature) { + final String generatedSignature = DigestUtils.sha1Hex(rawData + sessionKey); + System.out.println(generatedSignature); + return generatedSignature.equals(signature); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaJscode2SessionResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaJscode2SessionResult.java new file mode 100644 index 0000000000..4b9cc93d6b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaJscode2SessionResult.java @@ -0,0 +1,49 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; + +/** + * {"session_key":"nzoqhc3OnwHzeTxJs+inbQ==","expires_in":2592000,"openid":"oVBkZ0aYgDMDIywRdgPW8-joxXc4"} + * + * @author Binary Wang + */ +public class WxMaJscode2SessionResult { + @SerializedName("session_key") + private String sessionKey; + + @SerializedName("expires_in") + private Integer expiresin; + + @SerializedName("openid") + private String openid; + + public String getSessionKey() { + return sessionKey; + } + + public void setSessionKey(String sessionKey) { + this.sessionKey = sessionKey; + } + + public Integer getExpiresin() { + return expiresin; + } + + public void setExpiresin(Integer expiresin) { + this.expiresin = expiresin; + } + + public String getOpenid() { + return openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public static WxMaJscode2SessionResult fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaJscode2SessionResult.class); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessage.java new file mode 100644 index 0000000000..d75fbf12ae --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessage.java @@ -0,0 +1,99 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.builder.ImageBuilder; +import cn.binarywang.wx.miniapp.builder.TextBuilder; +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; + +import java.io.Serializable; + +/** + * 客服消息 + * + * @author Binary Wang + */ +public class WxMaKefuMessage implements Serializable { + private static final long serialVersionUID = -9196732086954365246L; + + private String toUser; + private String msgType; + private String content; + private String mediaId; + private String thumbMediaId; + private String title; + private String description; + + /** + * 获得文本消息builder + */ + public static TextBuilder TEXT() { + return new TextBuilder(); + } + + /** + * 获得图片消息builder + */ + public static ImageBuilder IMAGE() { + return new ImageBuilder(); + } + + public String getToUser() { + return this.toUser; + } + + public void setToUser(String toUser) { + this.toUser = toUser; + } + + public String getMsgType() { + return this.msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMediaId() { + return this.mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public String getThumbMediaId() { + return this.thumbMediaId; + } + + public void setThumbMediaId(String thumbMediaId) { + this.thumbMediaId = thumbMediaId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java new file mode 100644 index 0000000000..4b201da1cd --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java @@ -0,0 +1,236 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import cn.binarywang.wx.miniapp.util.xml.XStreamTransformer; +import com.google.gson.annotations.SerializedName; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.nio.charset.StandardCharsets; + +/** + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxMaMessage implements Serializable { + private static final long serialVersionUID = -3586245291677274914L; + + @SerializedName("Encrypt") + @XStreamAlias("Encrypt") + @XStreamConverter(value = XStreamCDataConverter.class) + private String encrypt; + + @SerializedName("ToUserName") + @XStreamAlias("ToUserName") + @XStreamConverter(value = XStreamCDataConverter.class) + private String toUser; + + @SerializedName("FromUserName") + @XStreamAlias("FromUserName") + @XStreamConverter(value = XStreamCDataConverter.class) + private String fromUser; + + @SerializedName("CreateTime") + @XStreamAlias("CreateTime") + @XStreamConverter(value = XStreamCDataConverter.class) + private Integer createTime; + + @SerializedName("MsgDataFormat") + @XStreamAlias("MsgDataFormat") + @XStreamConverter(value = XStreamCDataConverter.class) + private String msgType; + + // 文本消息 + @SerializedName("Content") + @XStreamAlias("Content") + @XStreamConverter(value = XStreamCDataConverter.class) + private String content; + + @SerializedName("MsgId") + @XStreamAlias("MsgId") + @XStreamConverter(value = XStreamCDataConverter.class) + private Long msgId; + + // 图片消息 + @SerializedName("PicUrl") + @XStreamAlias("PicUrl") + @XStreamConverter(value = XStreamCDataConverter.class) + private String picUrl; + + @SerializedName("MediaId") + @XStreamAlias("MediaId") + @XStreamConverter(value = XStreamCDataConverter.class) + private String mediaId; + + // 事件消息 + @SerializedName("Event") + @XStreamAlias("Event") + @XStreamConverter(value = XStreamCDataConverter.class) + private String event; + + @SerializedName("SessionFrom") + @XStreamAlias("SessionFrom") + @XStreamConverter(value = XStreamCDataConverter.class) + private String sessionFrom; + + public static WxMaMessage fromXml(String xml) { + return XStreamTransformer.fromXml(WxMaMessage.class, xml); + } + + public static WxMaMessage fromXml(InputStream is) { + return XStreamTransformer.fromXml(WxMaMessage.class, is); + } + + /** + * 从加密字符串转换 + * + * @param encryptedXml 密文 + * @param wxMaConfig 配置存储器对象 + * @param timestamp 时间戳 + * @param nonce 随机串 + * @param msgSignature 签名串 + */ + public static WxMaMessage fromEncryptedXml(String encryptedXml, + WxMaConfig wxMaConfig, String timestamp, String nonce, + String msgSignature) { + String plainText = new WxMaCryptUtils(wxMaConfig).decrypt(msgSignature, timestamp, nonce, encryptedXml); + return fromXml(plainText); + } + + public static WxMaMessage fromEncryptedXml(InputStream is, WxMaConfig wxMaConfig, String timestamp, + String nonce, String msgSignature) { + try { + return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), wxMaConfig, + timestamp, nonce, msgSignature); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static WxMaMessage fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaMessage.class); + } + + public static WxMaMessage fromEncryptedJson(String encryptedJson, WxMaConfig config) { + try { + WxMaMessage encryptedMessage = fromJson(encryptedJson); + String plainText = new WxMaCryptUtils(config).decrypt(encryptedMessage.getEncrypt()); + return fromJson(plainText); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static WxMaMessage fromEncryptedJson(InputStream inputStream, WxMaConfig config) { + try { + return fromEncryptedJson(IOUtils.toString(inputStream, StandardCharsets.UTF_8), config); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } + + public String getToUser() { + return toUser; + } + + public void setToUser(String toUser) { + this.toUser = toUser; + } + + public String getFromUser() { + return fromUser; + } + + public void setFromUser(String fromUser) { + this.fromUser = fromUser; + } + + public Integer getCreateTime() { + return createTime; + } + + public void setCreateTime(Integer createTime) { + this.createTime = createTime; + } + + public String getMsgType() { + return msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Long getMsgId() { + return msgId; + } + + public void setMsgId(Long msgId) { + this.msgId = msgId; + } + + public String getPicUrl() { + return picUrl; + } + + public void setPicUrl(String picUrl) { + this.picUrl = picUrl; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public String getEvent() { + return event; + } + + public void setEvent(String event) { + this.event = event; + } + + public String getSessionFrom() { + return sessionFrom; + } + + public void setSessionFrom(String sessionFrom) { + this.sessionFrom = sessionFrom; + } + + public String getEncrypt() { + return encrypt; + } + + public void setEncrypt(String encrypt) { + this.encrypt = encrypt; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcode.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcode.java new file mode 100644 index 0000000000..83050f0619 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcode.java @@ -0,0 +1,44 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; + +import java.io.Serializable; + +/** + * @author Binary Wang + */ +public class WxMaQrcode implements Serializable { + private static final long serialVersionUID = 5777119669111011584L; + private String path; + private int width = 430; + + public WxMaQrcode(String path, int width) { + this.path = path; + this.width = width; + } + + public static WxMaQrcode fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaQrcode.class); + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + @Override + public String toString() { + return WxMaGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java new file mode 100644 index 0000000000..7a89dfa8a5 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java @@ -0,0 +1,214 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html#接口说明 模板消息部分 + * + * @author Binary Wang + */ +public class WxMaTemplateMessage implements Serializable { + private static final long serialVersionUID = 5063374783759519418L; + /** + * touser 是 接收者(用户)的 openid + */ + private String toUser; + /** + * template_id 是 所需下发的模板消息的id + */ + private String templateId; + /** + *
+   * page	否	点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
+   * 
+ */ + private String page; + /** + * form_id 是 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id + */ + private String formId; + /** + * data 是 模板内容,不填则下发空模板 + */ + private List data = new ArrayList<>(); + /** + * color 否 模板内容字体的颜色,不填默认黑色 + */ + private String color; + /** + * emphasis_keyword 否 模板需要放大的关键词,不填则默认无放大 + */ + private String emphasisKeyword; + + private WxMaTemplateMessage(Builder builder) { + setToUser(builder.toUser); + setTemplateId(builder.templateId); + setPage(builder.page); + setFormId(builder.formId); + setData(builder.data); + setColor(builder.color); + setEmphasisKeyword(builder.emphasisKeyword); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } + + public String getToUser() { + return toUser; + } + + public void setToUser(String toUser) { + this.toUser = toUser; + } + + public String getTemplateId() { + return templateId; + } + + public void setTemplateId(String templateId) { + this.templateId = templateId; + } + + public String getPage() { + return page; + } + + public void setPage(String page) { + this.page = page; + } + + public String getFormId() { + return formId; + } + + public void setFormId(String formId) { + this.formId = formId; + } + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + public String getEmphasisKeyword() { + return emphasisKeyword; + } + + public void setEmphasisKeyword(String emphasisKeyword) { + this.emphasisKeyword = emphasisKeyword; + } + + public static class Data { + private String name; + private String value; + private String color; + + public Data(String name, String value) { + this.name = name; + this.value = value; + } + + public Data(String name, String value, String color) { + this.name = name; + this.value = value; + this.color = color; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return this.value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getColor() { + return this.color; + } + + public void setColor(String color) { + this.color = color; + } + + } + + public static final class Builder { + private String toUser; + private String templateId; + private String page; + private String formId; + private List data; + private String color; + private String emphasisKeyword; + + private Builder() { + } + + public Builder toUser(String toUser) { + this.toUser = toUser; + return this; + } + + public Builder templateId(String templateId) { + this.templateId = templateId; + return this; + } + + public Builder page(String page) { + this.page = page; + return this; + } + + public Builder formId(String formId) { + this.formId = formId; + return this; + } + + public Builder data(List data) { + this.data = data; + return this; + } + + public Builder color(String color) { + this.color = color; + return this; + } + + public Builder emphasisKeyword(String emphasisKeyword) { + this.emphasisKeyword = emphasisKeyword; + return this; + } + + public WxMaTemplateMessage build() { + return new WxMaTemplateMessage(this); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaUserInfo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaUserInfo.java new file mode 100644 index 0000000000..e3cc69d913 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaUserInfo.java @@ -0,0 +1,131 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * @author Binary Wang + */ +public class WxMaUserInfo { + private String openId; + private String nickName; + private String gender; + private String language; + private String city; + private String province; + private String country; + private String avatarUrl; + private String unionId; + private Watermark watermark; + + public static WxMaUserInfo fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaUserInfo.class); + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getProvince() { + return province; + } + + public void setProvince(String province) { + this.province = province; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getAvatarUrl() { + return avatarUrl; + } + + public void setAvatarUrl(String avatarUrl) { + this.avatarUrl = avatarUrl; + } + + public String getUnionId() { + return unionId; + } + + public void setUnionId(String unionId) { + this.unionId = unionId; + } + + public Watermark getWatermark() { + return watermark; + } + + public void setWatermark(Watermark watermark) { + this.watermark = watermark; + } + + public static class Watermark { + private String timestamp; + private String appid; + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/BaseBuilder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/BaseBuilder.java new file mode 100644 index 0000000000..70d7cf4b7c --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/BaseBuilder.java @@ -0,0 +1,24 @@ +package cn.binarywang.wx.miniapp.builder; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; + +/** + * @author Binary Wang + */ +public class BaseBuilder { + protected String msgType; + protected String toUser; + + @SuppressWarnings("unchecked") + public T toUser(String toUser) { + this.toUser = toUser; + return (T) this; + } + + public WxMaKefuMessage build() { + WxMaKefuMessage m = new WxMaKefuMessage(); + m.setMsgType(this.msgType); + m.setToUser(this.toUser); + return m; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/ImageBuilder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/ImageBuilder.java new file mode 100644 index 0000000000..219e3fd43b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/ImageBuilder.java @@ -0,0 +1,27 @@ +package cn.binarywang.wx.miniapp.builder; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; + +/** + * @author Binary Wang + */ +public final class ImageBuilder extends BaseBuilder { + private String mediaId; + + public ImageBuilder() { + this.msgType = WxMaConstants.KefuMsgType.IMAGE; + } + + public ImageBuilder mediaId(String media_id) { + this.mediaId = media_id; + return this; + } + + @Override + public WxMaKefuMessage build() { + WxMaKefuMessage m = super.build(); + m.setMediaId(this.mediaId); + return m; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/TextBuilder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/TextBuilder.java new file mode 100644 index 0000000000..35c58a67df --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/TextBuilder.java @@ -0,0 +1,27 @@ +package cn.binarywang.wx.miniapp.builder; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; + +/** + * @author Binary Wang + */ +public final class TextBuilder extends BaseBuilder { + private String content; + + public TextBuilder() { + this.msgType = WxMaConstants.KefuMsgType.TEXT; + } + + public TextBuilder content(String content) { + this.content = content; + return this; + } + + @Override + public WxMaKefuMessage build() { + WxMaKefuMessage m = super.build(); + m.setContent(this.content); + return m; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java new file mode 100644 index 0000000000..df72bb2c7d --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java @@ -0,0 +1,73 @@ +package cn.binarywang.wx.miniapp.config; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + +import java.util.concurrent.locks.Lock; + +/** + * 小程序配置 + * + * @author Binary Wang + */ +public interface WxMaConfig { + + String getAccessToken(); + + Lock getAccessTokenLock(); + + boolean isAccessTokenExpired(); + + /** + * 强制将access token过期掉 + */ + void expireAccessToken(); + + /** + * 应该是线程安全的 + * + * @param accessToken 要更新的WxAccessToken对象 + */ + void updateAccessToken(WxAccessToken accessToken); + + /** + * 应该是线程安全的 + * + * @param accessToken 新的accessToken值 + * @param expiresInSeconds 过期时间,以秒为单位 + */ + void updateAccessToken(String accessToken, int expiresInSeconds); + + String getAppid(); + + String getSecret(); + + String getToken(); + + String getAesKey(); + + String getMsgDataFormat(); + + long getExpiresTime(); + + String getHttpProxyHost(); + + int getHttpProxyPort(); + + String getHttpProxyUsername(); + + String getHttpProxyPassword(); + + /** + * http client builder + * + * @return ApacheHttpClientBuilder + */ + ApacheHttpClientBuilder getApacheHttpClientBuilder(); + + /** + * 是否自动刷新token + */ + boolean autoRefreshToken(); + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java new file mode 100644 index 0000000000..735a52b56a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java @@ -0,0 +1,185 @@ +package cn.binarywang.wx.miniapp.config; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + +import java.io.File; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 + * + * @author Binary Wang + */ +public class WxMaInMemoryConfig implements WxMaConfig { + protected volatile String msgDataFormat; + protected volatile String appid; + protected volatile String secret; + protected volatile String token; + protected volatile String accessToken; + protected volatile String aesKey; + protected volatile long expiresTime; + + protected volatile String httpProxyHost; + protected volatile int httpProxyPort; + protected volatile String httpProxyUsername; + protected volatile String httpProxyPassword; + + protected Lock accessTokenLock = new ReentrantLock(); + + /** + * 临时文件目录 + */ + protected volatile File tmpDirFile; + + protected volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + + @Override + public String getAccessToken() { + return this.accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + @Override + public Lock getAccessTokenLock() { + return this.accessTokenLock; + } + + public void setAccessTokenLock(Lock accessTokenLock) { + this.accessTokenLock = accessTokenLock; + } + + @Override + public boolean isAccessTokenExpired() { + return System.currentTimeMillis() > this.expiresTime; + } + + @Override + public synchronized void updateAccessToken(WxAccessToken accessToken) { + updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + } + + @Override + public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { + this.accessToken = accessToken; + this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + } + + @Override + public void expireAccessToken() { + this.expiresTime = 0; + } + + @Override + public String getSecret() { + return this.secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } + + @Override + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public long getExpiresTime() { + return this.expiresTime; + } + + public void setExpiresTime(long expiresTime) { + this.expiresTime = expiresTime; + } + + @Override + public String getAesKey() { + return this.aesKey; + } + + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } + + @Override + public String getMsgDataFormat() { + return this.msgDataFormat; + } + + public void setMsgDataFormat(String msgDataFormat) { + this.msgDataFormat = msgDataFormat; + } + + @Override + public String getHttpProxyHost() { + return this.httpProxyHost; + } + + public void setHttpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + } + + @Override + public int getHttpProxyPort() { + return this.httpProxyPort; + } + + public void setHttpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + } + + @Override + public String getHttpProxyUsername() { + return this.httpProxyUsername; + } + + public void setHttpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + } + + @Override + public String getHttpProxyPassword() { + return this.httpProxyPassword; + } + + public void setHttpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + } + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + @Override + public ApacheHttpClientBuilder getApacheHttpClientBuilder() { + return this.apacheHttpClientBuilder; + } + + public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { + this.apacheHttpClientBuilder = apacheHttpClientBuilder; + } + + @Override + public boolean autoRefreshToken() { + return true; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaConstants.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaConstants.java new file mode 100644 index 0000000000..2ec718694a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaConstants.java @@ -0,0 +1,26 @@ +package cn.binarywang.wx.miniapp.constant; + +/** + *
+ *  小程序常量
+ * 
+ * + * @author Binary Wang + */ +public class WxMaConstants { + /** + * 消息格式 + */ + public static class MsgDataFormat { + public static final String XML = "XML"; + public static final String JSON = "JSON"; + } + + /** + * 客服消息的消息类型 + */ + public static class KefuMsgType { + public static final String TEXT = "text";//文本消息 + public static final String IMAGE = "image";//图片消息 + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java new file mode 100644 index 0000000000..794d60e98a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java @@ -0,0 +1,20 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; + +import java.util.Map; + +/** + * 处理小程序推送消息的处理器接口 + * + * @author Binary Wang + */ +public interface WxMaMessageHandler { + + void handle(WxMaMessage message, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException; + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java new file mode 100644 index 0000000000..1b220a0baa --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java @@ -0,0 +1,28 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; + +import java.util.Map; + +/** + * 微信消息拦截器,可以用来做验证 + * + * @author Binary Wang + */ +public interface WxMaMessageInterceptor { + + /** + * 拦截微信消息 + * + * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @return true代表OK,false代表不OK + */ + boolean intercept(WxMaMessage wxMessage, + Map context, + WxMaService wxMaService, + WxSessionManager sessionManager) throws WxErrorException; + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageMatcher.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageMatcher.java new file mode 100644 index 0000000000..9d4e54f89b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageMatcher.java @@ -0,0 +1,17 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.bean.WxMaMessage; + +/** + * 消息匹配器,用在消息路由的时候 + * + * @author Binary Wang + */ +public interface WxMaMessageMatcher { + + /** + * 消息是否匹配某种模式 + */ + boolean match(WxMaMessage message); + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java new file mode 100644 index 0000000000..cbe42b1f26 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java @@ -0,0 +1,176 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; +import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; +import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; +import me.chanjar.weixin.common.session.InternalSession; +import me.chanjar.weixin.common.session.InternalSessionManager; +import me.chanjar.weixin.common.session.StandardSessionManager; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.LogExceptionHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + * @author Binary Wang + */ +public class WxMaMessageRouter { + private static final int DEFAULT_THREAD_POOL_SIZE = 100; + private final Logger log = LoggerFactory.getLogger(WxMaMessageRouter.class); + private final List rules = new ArrayList<>(); + + private final WxMaService wxMaService; + + private ExecutorService executorService; + + private WxMessageDuplicateChecker messageDuplicateChecker; + + private WxSessionManager sessionManager; + + private WxErrorExceptionHandler exceptionHandler; + + public WxMaMessageRouter(WxMaService wxMaService) { + this.wxMaService = wxMaService; + this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); + this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); + this.sessionManager = new StandardSessionManager(); + this.exceptionHandler = new LogExceptionHandler(); + } + + /** + *
+   * 设置自定义的 {@link ExecutorService}
+   * 如果不调用该方法,默认使用 Executors.newFixedThreadPool(100)
+   * 
+ */ + public void setExecutorService(ExecutorService executorService) { + this.executorService = executorService; + } + + /** + *
+   * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker}
+   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker}
+   * 
+ */ + public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { + this.messageDuplicateChecker = messageDuplicateChecker; + } + + /** + *
+   * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager}
+   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager}
+   * 
+ */ + public void setSessionManager(WxSessionManager sessionManager) { + this.sessionManager = sessionManager; + } + + /** + *
+   * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler}
+   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler}
+   * 
+ */ + public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + + List getRules() { + return this.rules; + } + + /** + * 开始一个新的Route规则 + */ + public WxMaMessageRouterRule rule() { + return new WxMaMessageRouterRule(this); + } + + /** + * 处理微信消息 + */ + public void route(final WxMaMessage wxMessage, final Map context) { + final List matchRules = new ArrayList<>(); + // 收集匹配的规则 + for (final WxMaMessageRouterRule rule : this.rules) { + if (rule.test(wxMessage)) { + matchRules.add(rule); + if (!rule.isReEnter()) { + break; + } + } + } + + if (matchRules.size() == 0) { + return; + } + + final List> futures = new ArrayList<>(); + for (final WxMaMessageRouterRule rule : matchRules) { + // 返回最后一个非异步的rule的执行结果 + if (rule.isAsync()) { + futures.add( + this.executorService.submit(new Runnable() { + @Override + public void run() { + rule.service(wxMessage, context, WxMaMessageRouter.this.wxMaService, WxMaMessageRouter.this.sessionManager, WxMaMessageRouter.this.exceptionHandler); + } + }) + ); + } else { + rule.service(wxMessage, context, this.wxMaService, this.sessionManager, this.exceptionHandler); + // 在同步操作结束,session访问结束 + this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser()); + sessionEndAccess(wxMessage); + } + } + + if (futures.size() > 0) { + this.executorService.submit(new Runnable() { + @Override + public void run() { + for (Future future : futures) { + try { + future.get(); + WxMaMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUser()); + // 异步操作结束,session访问结束 + sessionEndAccess(wxMessage); + } catch (InterruptedException | ExecutionException e) { + WxMaMessageRouter.this.log.error("Error happened when wait task finish", e); + } + } + } + }); + } + + } + + public void route(final WxMaMessage wxMessage) { + this.route(wxMessage, new HashMap()); + } + + /** + * 对session的访问结束 + */ + protected void sessionEndAccess(WxMaMessage wxMessage) { + + InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUser()); + if (session != null) { + session.endAccess(); + } + + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java new file mode 100644 index 0000000000..9fce8b1a04 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java @@ -0,0 +1,316 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +/** + * @author Binary Wang + */ +public class WxMaMessageRouterRule { + + private final WxMaMessageRouter routerBuilder; + + private boolean async = true; + + private String fromUser; + + private String msgType; + + private String event; + + private String eventKey; + + private String content; + + private String rContent; + + private WxMaMessageMatcher matcher; + + private boolean reEnter = false; + + private List handlers = new ArrayList<>(); + + private List interceptors = new ArrayList<>(); + + public WxMaMessageRouterRule(WxMaMessageRouter routerBuilder) { + this.routerBuilder = routerBuilder; + } + + /** + * 设置是否异步执行,默认是true + */ + public WxMaMessageRouterRule async(boolean async) { + this.async = async; + return this; + } + + /** + * 如果msgType等于某值 + */ + public WxMaMessageRouterRule msgType(String msgType) { + this.msgType = msgType; + return this; + } + + /** + * 如果event等于某值 + */ + public WxMaMessageRouterRule event(String event) { + this.event = event; + return this; + } + + /** + * 如果eventKey等于某值 + */ + public WxMaMessageRouterRule eventKey(String eventKey) { + this.eventKey = eventKey; + return this; + } + + /** + * 如果content等于某值 + */ + public WxMaMessageRouterRule content(String content) { + this.content = content; + return this; + } + + /** + * 如果content匹配该正则表达式 + */ + public WxMaMessageRouterRule rContent(String regex) { + this.rContent = regex; + return this; + } + + /** + * 如果fromUser等于某值 + */ + public WxMaMessageRouterRule fromUser(String fromUser) { + this.fromUser = fromUser; + return this; + } + + /** + * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 + */ + public WxMaMessageRouterRule matcher(WxMaMessageMatcher matcher) { + this.matcher = matcher; + return this; + } + + /** + * 设置微信消息拦截器 + */ + public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor) { + return interceptor(interceptor, (WxMaMessageInterceptor[]) null); + } + + /** + * 设置微信消息拦截器 + */ + public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor, WxMaMessageInterceptor... otherInterceptors) { + this.interceptors.add(interceptor); + if (otherInterceptors != null && otherInterceptors.length > 0) { + for (WxMaMessageInterceptor i : otherInterceptors) { + this.interceptors.add(i); + } + } + return this; + } + + /** + * 设置微信消息处理器 + */ + public WxMaMessageRouterRule handler(WxMaMessageHandler handler) { + return handler(handler, (WxMaMessageHandler[]) null); + } + + /** + * 设置微信消息处理器 + */ + public WxMaMessageRouterRule handler(WxMaMessageHandler handler, WxMaMessageHandler... otherHandlers) { + this.handlers.add(handler); + if (otherHandlers != null && otherHandlers.length > 0) { + for (WxMaMessageHandler i : otherHandlers) { + this.handlers.add(i); + } + } + return this; + } + + /** + * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 + */ + public WxMaMessageRouter end() { + this.routerBuilder.getRules().add(this); + return this.routerBuilder; + } + + /** + * 规则结束,但是消息还会进入其他规则 + */ + public WxMaMessageRouter next() { + this.reEnter = true; + return end(); + } + + /** + * 将微信自定义的事件修正为不区分大小写, + * 比如框架定义的事件常量为click,但微信传递过来的却是CLICK + */ + protected boolean test(WxMaMessage wxMessage) { + return + (this.fromUser == null || this.fromUser.equals(wxMessage.getFromUser())) + && + (this.msgType == null || this.msgType.toLowerCase().equals((wxMessage.getMsgType() == null ? null : wxMessage.getMsgType().toLowerCase()))) + && + (this.event == null || this.event.toLowerCase().equals((wxMessage.getEvent() == null ? null : wxMessage.getEvent().toLowerCase()))) + && + (this.content == null || this.content + .equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) + && + (this.rContent == null || Pattern + .matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) + && + (this.matcher == null || this.matcher.match(wxMessage)) + ; + } + + /** + * 处理微信推送过来的消息 + * + * @return true 代表继续执行别的router,false 代表停止执行别的router + */ + protected void service(WxMaMessage wxMessage, + Map context, + WxMaService wxMaService, + WxSessionManager sessionManager, + WxErrorExceptionHandler exceptionHandler) { + if (context == null) { + context = new HashMap<>(); + } + + try { + // 如果拦截器不通过 + for (WxMaMessageInterceptor interceptor : this.interceptors) { + if (!interceptor.intercept(wxMessage, context, wxMaService, sessionManager)) { + return; + } + } + + // 交给handler处理 + for (WxMaMessageHandler handler : this.handlers) { + // 返回最后handler的结果 + if (handler == null) { + continue; + } + handler.handle(wxMessage, context, wxMaService, sessionManager); + } + } catch (WxErrorException e) { + exceptionHandler.handle(e); + } + } + + public WxMaMessageRouter getRouterBuilder() { + return this.routerBuilder; + } + + public boolean isAsync() { + return this.async; + } + + public void setAsync(boolean async) { + this.async = async; + } + + public String getFromUser() { + return this.fromUser; + } + + public void setFromUser(String fromUser) { + this.fromUser = fromUser; + } + + public String getMsgType() { + return this.msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public String getEvent() { + return this.event; + } + + public void setEvent(String event) { + this.event = event; + } + + public String getEventKey() { + return this.eventKey; + } + + public void setEventKey(String eventKey) { + this.eventKey = eventKey; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getrContent() { + return this.rContent; + } + + public void setrContent(String rContent) { + this.rContent = rContent; + } + + public WxMaMessageMatcher getMatcher() { + return this.matcher; + } + + public void setMatcher(WxMaMessageMatcher matcher) { + this.matcher = matcher; + } + + public boolean isReEnter() { + return this.reEnter; + } + + public void setReEnter(boolean reEnter) { + this.reEnter = reEnter; + } + + public List getHandlers() { + return this.handlers; + } + + public void setHandlers(List handlers) { + this.handlers = handlers; + } + + public List getInterceptors() { + return this.interceptors; + } + + public void setInterceptors(List interceptors) { + this.interceptors = interceptors; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java new file mode 100644 index 0000000000..e05bac5fb7 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java @@ -0,0 +1,43 @@ +package cn.binarywang.wx.miniapp.util.crypt; + +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import me.chanjar.weixin.common.util.crypto.PKCS7Encoder; +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.AlgorithmParameters; + +/** + * @author Binary Wang + */ +public class WxMaCryptUtils extends me.chanjar.weixin.common.util.crypto.WxCryptUtil { + public WxMaCryptUtils(WxMaConfig config) { + this.appidOrCorpid = config.getAppid(); + this.token = config.getToken(); + this.aesKey = Base64.decodeBase64(config.getAesKey() + "="); + } + + /** + * AES解密 + * + * @param encryptedData 消息密文 + * @param ivStr iv字符串 + */ + public static String decrypt(String sessionKey, String encryptedData, String ivStr) { + try { + AlgorithmParameters params = AlgorithmParameters.getInstance("AES"); + params.init(new IvParameterSpec(Base64.decodeBase64(ivStr))); + + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(sessionKey), "AES"), params); + + return new String(PKCS7Encoder.decode(cipher.doFinal(Base64.decodeBase64(encryptedData))), StandardCharsets.UTF_8); + } catch (Exception e) { + throw new RuntimeException("AES解密失败", e); + } + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java new file mode 100644 index 0000000000..7883ffda9b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java @@ -0,0 +1,61 @@ +package cn.binarywang.wx.miniapp.util.http; + +import cn.binarywang.wx.miniapp.bean.WxMaQrcode; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +/** + * @author Binary Wang + */ +public class QrCodeRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; + + public QrCodeRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } + + @Override + public File execute(String uri, WxMaQrcode ticket) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + httpPost + .setConfig(RequestConfig.custom() + .setProxy(requestHttp.getRequestHttpProxy()) + .build() + ); + } + httpPost.setEntity(new StringEntity(ticket.toString())); + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0 + && ContentType.TEXT_PLAIN.getMimeType().equals(contentTypeHeader[0].getValue())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaGsonBuilder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaGsonBuilder.java new file mode 100644 index 0000000000..4eb3a8adf0 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaGsonBuilder.java @@ -0,0 +1,24 @@ +package cn.binarywang.wx.miniapp.util.json; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +/** + * @author Binary Wang + */ +public class WxMaGsonBuilder { + private static final GsonBuilder INSTANCE = new GsonBuilder(); + + static { + INSTANCE.disableHtmlEscaping(); + INSTANCE.registerTypeAdapter(WxMaKefuMessage.class, new WxMaKefuMessageGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMaTemplateMessage.class, new WxMaTemplateMessageGsonAdapter()); + } + + public static Gson create() { + return INSTANCE.create(); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaKefuMessageGsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaKefuMessageGsonAdapter.java new file mode 100644 index 0000000000..33c46d63cd --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaKefuMessageGsonAdapter.java @@ -0,0 +1,47 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package cn.binarywang.wx.miniapp.util.json; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Type; + +/** + * @author Binary Wang + */ +public class WxMaKefuMessageGsonAdapter implements JsonSerializer { + + @Override + public JsonElement serialize(WxMaKefuMessage message, Type typeOfSrc, JsonSerializationContext context) { + JsonObject messageJson = new JsonObject(); + messageJson.addProperty("touser", message.getToUser()); + messageJson.addProperty("msgtype", message.getMsgType()); + + if (WxMaConstants.KefuMsgType.TEXT.equals(message.getMsgType())) { + JsonObject text = new JsonObject(); + text.addProperty("content", message.getContent()); + messageJson.add("text", text); + } + + if (WxMaConstants.KefuMsgType.IMAGE.equals(message.getMsgType())) { + JsonObject image = new JsonObject(); + image.addProperty("media_id", message.getMediaId()); + messageJson.add("image", image); + } + + return messageJson; + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaTemplateMessageGsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaTemplateMessageGsonAdapter.java new file mode 100644 index 0000000000..0b4edee286 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaTemplateMessageGsonAdapter.java @@ -0,0 +1,60 @@ +package cn.binarywang.wx.miniapp.util.json; + +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import java.lang.reflect.Type; + +/** + * @author Binary Wang + */ +public class WxMaTemplateMessageGsonAdapter implements JsonSerializer { + + @Override + public JsonElement serialize(WxMaTemplateMessage message, Type typeOfSrc, JsonSerializationContext context) { + JsonObject messageJson = new JsonObject(); + messageJson.addProperty("touser", message.getToUser()); + messageJson.addProperty("template_id", message.getTemplateId()); + if (message.getPage() != null) { + messageJson.addProperty("page", message.getPage()); + } + + if (message.getFormId() != null) { + messageJson.addProperty("form_id", message.getFormId()); + } + + if (message.getPage() != null) { + messageJson.addProperty("page", message.getPage()); + } + + if (message.getColor() != null) { + messageJson.addProperty("color", message.getColor()); + } + + if (message.getEmphasisKeyword() != null) { + messageJson.addProperty("emphasis_keyword", message.getEmphasisKeyword()); + } + + JsonObject data = new JsonObject(); + messageJson.add("data", data); + + if (message.getData() == null) { + return messageJson; + } + + for (WxMaTemplateMessage.Data datum : message.getData()) { + JsonObject dataJson = new JsonObject(); + dataJson.addProperty("value", datum.getValue()); + if (datum.getColor() != null) { + dataJson.addProperty("color", datum.getColor()); + } + data.add(datum.getName(), dataJson); + } + + return messageJson; + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/xml/XStreamTransformer.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/xml/XStreamTransformer.java new file mode 100644 index 0000000000..f85c716acb --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/xml/XStreamTransformer.java @@ -0,0 +1,88 @@ +package cn.binarywang.wx.miniapp.util.xml; + +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import com.thoughtworks.xstream.XStream; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; + +import java.io.InputStream; +import java.util.*; + +/** + * @author Binary Wang + */ +public class XStreamTransformer { + private static final Map, XStream> CLASS_2_XSTREAM_INSTANCE = new HashMap<>(); + + static { + registerClass(WxMaMessage.class); + } + + /** + * xml -> pojo + */ + @SuppressWarnings("unchecked") + public static T fromXml(Class clazz, String xml) { + T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(xml); + return object; + } + + @SuppressWarnings("unchecked") + public static T fromXml(Class clazz, InputStream is) { + T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(is); + return object; + } + + /** + * pojo -> xml + */ + public static String toXml(Class clazz, T object) { + return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); + } + + /** + * 注册扩展消息的解析器 + * + * @param clz 类型 + * @param xStream xml解析器 + */ + private static void register(Class clz, XStream xStream) { + CLASS_2_XSTREAM_INSTANCE.put(clz, xStream); + } + + /** + * 会自动注册该类及其子类 + * + * @param clz 要注册的类 + */ + private static void registerClass(Class clz) { + XStream xstream = XStreamInitializer.getInstance(); + xstream.processAnnotations(clz); + xstream.processAnnotations(getInnerClasses(clz)); + if (clz.equals(WxMaMessage.class)) { + // 操蛋的微信,模板消息推送成功的消息是MsgID,其他消息推送过来是MsgId + xstream.aliasField("MsgID", WxMaMessage.class, "msgId"); + } + + register(clz, xstream); + } + + private static Class[] getInnerClasses(Class clz) { + Class[] innerClasses = clz.getClasses(); + if (innerClasses == null) { + return null; + } + + List> result = new ArrayList<>(); + result.addAll(Arrays.asList(innerClasses)); + for (Class inner : innerClasses) { + Class[] innerClz = getInnerClasses(inner); + if (innerClz == null) { + continue; + } + + result.addAll(Arrays.asList(innerClz)); + } + + return result.toArray(new Class[0]); + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImplTest.java new file mode 100644 index 0000000000..825ad05f76 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImplTest.java @@ -0,0 +1,52 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +/** + * 临时素材接口的测试 + * + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaMediaServiceImplTest { + @Inject + protected WxMaService wxService; + + private String mediaId; + + @Test + public void testUploadMedia() throws WxErrorException, IOException { + String mediaType = "image"; + String fileType = "png"; + String fileName = "tmp.png"; + try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)) { + WxMediaUploadResult res = this.wxService.getMediaService().uploadMedia(mediaType, fileType, inputStream); + assertNotNull(res.getType()); + assertNotNull(res.getCreatedAt()); + assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null); + this.mediaId = res.getMediaId(); + System.out.println(res); + } + } + + @Test(dependsOnMethods = {"testUploadMedia"}) + public void testGetMedia() throws WxErrorException { + File file = this.wxService.getMediaService().getMedia(this.mediaId); + assertNotNull(file); + System.out.println(file.getAbsolutePath()); + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java new file mode 100644 index 0000000000..c5d8f1e86a --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java @@ -0,0 +1,76 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import cn.binarywang.wx.miniapp.test.TestConfig; +import com.google.common.collect.Lists; +import com.google.inject.Inject; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.exception.WxErrorException; +import org.testng.Assert; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 测试客服相关接口 + * + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaMsgServiceImplTest { + + @Inject + protected WxMaService wxService; + + public void testSendKefuMpNewsMessage() throws WxErrorException { + TestConfig configStorage = (TestConfig) this.wxService + .getWxMaConfig(); + WxMaKefuMessage message = new WxMaKefuMessage(); + message.setMsgType(WxConsts.CUSTOM_MSG_MPNEWS); + message.setToUser(configStorage.getOpenid()); + + this.wxService.getMsgService().sendKefuMsg(message); + } + + public void testSendKefuMessage() throws WxErrorException { + TestConfig config = (TestConfig) this.wxService + .getWxMaConfig(); + WxMaKefuMessage message = new WxMaKefuMessage(); + message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); + message.setToUser(config.getOpenid()); + message.setContent( + "欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); + + this.wxService.getMsgService().sendKefuMsg(message); + } + + @Test(invocationCount = 5, threadPoolSize = 3) + public void testSendTemplateMsg() throws WxErrorException { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + TestConfig config = (TestConfig) this.wxService.getWxMaConfig(); + + WxMaTemplateMessage templateMessage = WxMaTemplateMessage.newBuilder() + .toUser(config.getOpenid()) + .formId("FORMID") + .page("index") + .data(Lists.newArrayList( + new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177"), + new WxMaTemplateMessage.Data("keyword2", dateFormat.format(new Date()), "#173177"), + new WxMaTemplateMessage.Data("keyword3", "粤海喜来登酒店", "#173177"), + new WxMaTemplateMessage.Data("keyword4", "广州市天河区天河路208号", "#173177"))) + .templateId(config.getTemplateId()) + .emphasisKeyword("keyword1.DATA") + .build(); + + String msgId = this.wxService.getMsgService().sendTemplateMsg(templateMessage); + Assert.assertNotNull(msgId); + System.out.println(msgId); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java new file mode 100644 index 0000000000..48dad9362a --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java @@ -0,0 +1,26 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.io.File; + +/** + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaQrcodeServiceImplTest { + @Inject + protected WxMaService wxService; + + @Test + public void testCreateQrCode() throws Exception { + final File qrCode = this.wxService.getQrcodeService().createQrcode("111", 122); + System.out.println(qrCode); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java new file mode 100644 index 0000000000..1c99530d36 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java @@ -0,0 +1,35 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import me.chanjar.weixin.common.exception.WxErrorException; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertTrue; + +/** + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaServiceImplTest { + + @Inject + private WxMaService wxService; + + public void testRefreshAccessToken() throws WxErrorException { + WxMaConfig configStorage = this.wxService.getWxMaConfig(); + String before = configStorage.getAccessToken(); + this.wxService.getAccessToken(false); + + String after = configStorage.getAccessToken(); + assertNotEquals(before, after); + assertTrue(StringUtils.isNotBlank(after)); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplTest.java new file mode 100644 index 0000000000..a19692763b --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplTest.java @@ -0,0 +1,46 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +/** + * 测试用户相关的接口 + * + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaUserServiceImplTest { + + @Inject + private WxMaService wxService; + + @Test + public void testGetSessionKey() throws Exception { + assertNotNull(this.wxService.getUserService().getSessionInfo("aaa")); + } + + @Test + public void testGetUserInfo() throws Exception { + WxMaUserInfo userInfo = this.wxService.getUserService().getUserInfo("tiihtNczf5v6AKRyjwEUhQ==", + "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew==", + "r7BXXKkLb8qrSNn05n0qiA=="); + assertNotNull(userInfo); + System.out.println(userInfo.toString()); + } + + @Test + public void testCheckUserInfo() throws Exception { + assertTrue(this.wxService.getUserService().checkUserInfo("HyVFkGl5F5OQWJZZaNzBBg==", + "{\"nickName\":\"Band\",\"gender\":1,\"language\":\"zh_CN\",\"city\":\"Guangzhou\",\"province\":\"Guangdong\",\"country\":\"CN\",\"avatarUrl\":\"http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0\"}", + "75e81ceda165f4ffa64f4068af58c64b8f54b88c")); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessageTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessageTest.java new file mode 100644 index 0000000000..f2ef8bfac5 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessageTest.java @@ -0,0 +1,40 @@ +package cn.binarywang.wx.miniapp.bean; + +import me.chanjar.weixin.common.api.WxConsts; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author Binary Wang + */ +@Test +public class WxMaKefuMessageTest { + + public void testTextReply() { + WxMaKefuMessage reply = new WxMaKefuMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxConsts.CUSTOM_MSG_TEXT); + reply.setContent("sfsfdsdf"); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); + } + + public void testTextBuild() { + WxMaKefuMessage reply = WxMaKefuMessage.TEXT().toUser("OPENID").content("sfsfdsdf").build(); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); + } + + public void testImageReply() { + WxMaKefuMessage reply = new WxMaKefuMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxConsts.CUSTOM_MSG_IMAGE); + reply.setMediaId("MEDIA_ID"); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); + } + + public void testImageBuild() { + WxMaKefuMessage reply = WxMaKefuMessage.IMAGE().toUser("OPENID").mediaId("MEDIA_ID").build(); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); + } + + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaMessageTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaMessageTest.java new file mode 100644 index 0000000000..881091a1df --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaMessageTest.java @@ -0,0 +1,130 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import me.chanjar.weixin.common.api.WxConsts; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +/** + * @author Binary Wang + */ +@Test +public class WxMaMessageTest { + + public void testFromXml() { + String xml = "" + + "" + + " " + + "1348831860" + + "" + + "" + + "1234567890123456" + + "" + + "" + + "" + + "" + + "23.134521" + + "113.358803" + + "20" + + "" + + "" + + "" + + "<![CDATA[公众平台官网链接]]>" + + "" + + "" + + "" + + "23.137466" + + "113.352425" + + "119.385040" + + "" + + " " + + " " + + "" + + "" + + " 1\n" + + " " + + " " + + " " + + " " + + " " + + "" + + "" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "" + + ""; + WxMaMessage wxMessage = WxMaMessage.fromXml(xml); + assertEquals(wxMessage.getToUser(), "toUser"); + assertEquals(wxMessage.getFromUser(), "fromUser"); + assertEquals(wxMessage.getCreateTime(), new Long(1348831860L)); + assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); + assertEquals(wxMessage.getContent(), "this is a test"); + assertEquals(wxMessage.getMsgId(), new Long(1234567890123456L)); + assertEquals(wxMessage.getPicUrl(), "this is a url"); + assertEquals(wxMessage.getMediaId(), "media_id"); + assertEquals(wxMessage.getEvent(), "subscribe"); + } + + public void testFromXml2() { + + String xml = "" + + "" + + " " + + "1348831860" + + "" + + "" + + "1234567890123456" + + "" + + "" + + "" + + "" + + "23.134521" + + "113.358803" + + "20" + + "" + + "" + + "" + + "<![CDATA[公众平台官网链接]]>" + + "" + + "" + + "" + + "23.137466" + + "113.352425" + + "119.385040" + + "" + + " " + + " " + + "" + + "" + + " 1\n" + + " " + + " " + + " " + + " " + + " " + + "" + + "" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "" + + ""; + WxMaMessage wxMessage = WxMaMessage.fromXml(xml); + assertEquals(wxMessage.getToUser(), "toUser"); + assertEquals(wxMessage.getFromUser(), "fromUser"); + assertEquals(wxMessage.getCreateTime(), new Integer(1348831860)); + assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); + assertEquals(wxMessage.getContent(), "this is a test"); + assertEquals(wxMessage.getMsgId(), new Long(1234567890123456L)); + assertEquals(wxMessage.getPicUrl(), "this is a url"); + assertEquals(wxMessage.getMediaId(), "media_id"); + assertEquals(wxMessage.getEvent(), "subscribe"); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessageTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessageTest.java new file mode 100644 index 0000000000..ad6e62c2ca --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessageTest.java @@ -0,0 +1,31 @@ +package cn.binarywang.wx.miniapp.bean; + +import com.google.common.collect.Lists; +import org.testng.annotations.Test; + +import static org.testng.AssertJUnit.assertEquals; + +/** + * @author Binary Wang + */ +public class WxMaTemplateMessageTest { + @Test + public void testToJson() throws Exception { + WxMaTemplateMessage tm = WxMaTemplateMessage.newBuilder() + .toUser("OPENID") + //.color("aaaaa") + .formId("FORMID") + .page("index") + .data(Lists.newArrayList( + new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177"), + new WxMaTemplateMessage.Data("keyword2", "2015年01月05日12:30", "#173177"), + new WxMaTemplateMessage.Data("keyword3", "粤海喜来登酒店", "#173177"), + new WxMaTemplateMessage.Data("keyword4", "广州市天河区天河路208号", "#173177"))) + .templateId("TEMPLATE_ID") + .emphasisKeyword("keyword1.DATA") + .build(); + + assertEquals(tm.toJson(), "{\"touser\":\"OPENID\",\"template_id\":\"TEMPLATE_ID\",\"page\":\"index\",\"form_id\":\"FORMID\",\"emphasis_keyword\":\"keyword1.DATA\",\"data\":{\"keyword1\":{\"value\":\"339208499\",\"color\":\"#173177\"},\"keyword2\":{\"value\":\"2015年01月05日12:30\",\"color\":\"#173177\"},\"keyword3\":{\"value\":\"粤海喜来登酒店\",\"color\":\"#173177\"},\"keyword4\":{\"value\":\"广州市天河区天河路208号\",\"color\":\"#173177\"}}}"); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java new file mode 100644 index 0000000000..62847ab7d1 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java @@ -0,0 +1,144 @@ +package cn.binarywang.wx.miniapp.demo; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.message.WxMaMessageHandler; +import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; +import cn.binarywang.wx.miniapp.test.TestConfig; +import com.google.common.collect.Lists; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @author Binary Wang + */ +public class WxMaDemoServer { + + private static final WxMaMessageHandler logHandler = new WxMaMessageHandler() { + @Override + public void handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + System.out.println("收到消息:" + wxMessage.toString()); + service.getMsgService().sendKefuMsg(WxMaKefuMessage.TEXT().content("收到信息为:" + wxMessage.toJson()) + .toUser(wxMessage.getFromUser()).build()); + } + }; + private static final WxMaMessageHandler textHandler = new WxMaMessageHandler() { + @Override + public void handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) + throws WxErrorException { + service.getMsgService().sendKefuMsg(WxMaKefuMessage.TEXT().content("回复文本消息") + .toUser(wxMessage.getFromUser()).build()); + } + + }; + private static final WxMaMessageHandler picHandler = new WxMaMessageHandler() { + @Override + public void handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + try { + WxMediaUploadResult uploadResult = service.getMediaService() + .uploadMedia("image", "png", + ClassLoader.getSystemResourceAsStream("tmp.png")); + service.getMsgService().sendKefuMsg( + WxMaKefuMessage + .IMAGE() + .mediaId(uploadResult.getMediaId()) + .toUser(wxMessage.getFromUser()) + .build()); + } catch (WxErrorException e) { + e.printStackTrace(); + } + } + }; + private static final WxMaMessageHandler qrcodeHandler = new WxMaMessageHandler() { + @Override + public void handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + try { + final File file = service.getQrcodeService().createQrcode("123", 430); + WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file); + service.getMsgService().sendKefuMsg( + WxMaKefuMessage + .IMAGE() + .mediaId(uploadResult.getMediaId()) + .toUser(wxMessage.getFromUser()) + .build()); + } catch (WxErrorException e) { + e.printStackTrace(); + } + } + }; + + private static final WxMaMessageHandler templateMsgHandler = new WxMaMessageHandler() { + @Override + public void handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) + throws WxErrorException { + service.getMsgService().sendTemplateMsg(WxMaTemplateMessage.newBuilder() + .templateId(templateId).data(Lists.newArrayList( + new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177"))) + .toUser(wxMessage.getFromUser()) + .formId("自己替换可用的formid") + .build()); + } + + }; + + private static WxMaConfig config; + private static WxMaService service; + private static WxMaMessageRouter router; + private static String templateId; + + public static void main(String[] args) throws Exception { + init(); + + Server server = new Server(8080); + + ServletHandler servletHandler = new ServletHandler(); + server.setHandler(servletHandler); + + ServletHolder endpointServletHolder = new ServletHolder(new WxMaPortalServlet(config, service, router)); + servletHandler.addServletWithMapping(endpointServletHolder, "/*"); + + server.start(); + server.join(); + } + + private static void init() { + try (InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml")) { + TestConfig config = TestConfig.fromXml(is1); + config.setAccessTokenLock(new ReentrantLock()); + templateId = config.getTemplateId(); + + WxMaDemoServer.config = config; + service = new WxMaServiceImpl(); + service.setWxMaConfig(config); + + router = new WxMaMessageRouter(service); + + router.rule().handler(logHandler).next() + .rule().async(false).content("模板").handler(templateMsgHandler).end() + .rule().async(false).content("文本").handler(textHandler).end() + .rule().async(false).content("图片").handler(picHandler).end() + .rule().async(false).content("二维码").handler(qrcodeHandler).end(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java new file mode 100644 index 0000000000..5cadb68925 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java @@ -0,0 +1,92 @@ +package cn.binarywang.wx.miniapp.demo; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; +import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +/** + * @author Binary Wang + */ +public class WxMaPortalServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + private WxMaConfig wxMaConfig; + private WxMaService wxMaService; + private WxMaMessageRouter wxMaMessageRouter; + + WxMaPortalServlet(WxMaConfig wxMaConfig, WxMaService wxMaService, + WxMaMessageRouter wxMaMessageRouter) { + this.wxMaConfig = wxMaConfig; + this.wxMaService = wxMaService; + this.wxMaMessageRouter = wxMaMessageRouter; + } + + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) + throws IOException { + response.setContentType("text/html;charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + + String signature = request.getParameter("signature"); + String nonce = request.getParameter("nonce"); + String timestamp = request.getParameter("timestamp"); + + if (!this.wxMaService.checkSignature(timestamp, nonce, signature)) { + // 消息签名不正确,说明不是公众平台发过来的消息 + response.getWriter().println("非法请求"); + return; + } + + String echoStr = request.getParameter("echostr"); + if (StringUtils.isNotBlank(echoStr)) { + // 说明是一个仅仅用来验证的请求,回显echostr + response.getWriter().println(echoStr); + return; + } + + String encryptType = request.getParameter("encrypt_type"); + final boolean isJson = Objects.equals(this.wxMaConfig.getMsgDataFormat(), WxMaConstants.MsgDataFormat.JSON); + if (StringUtils.isBlank(encryptType)) { + // 明文传输的消息 + WxMaMessage inMessage; + if (isJson) { + inMessage = WxMaMessage.fromJson(IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8)); + } else {//xml + inMessage = WxMaMessage.fromXml(request.getInputStream()); + } + + this.wxMaMessageRouter.route(inMessage); + response.getWriter().write("success"); + return; + } + + if ("aes".equals(encryptType)) { + // 是aes加密的消息 + String msgSignature = request.getParameter("msg_signature"); + WxMaMessage inMessage; + if (isJson) { + inMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(), this.wxMaConfig); + } else {//xml + inMessage = WxMaMessage.fromEncryptedXml(request.getInputStream(), this.wxMaConfig, timestamp, nonce, msgSignature); + } + + this.wxMaMessageRouter.route(inMessage); + response.getWriter().write("success"); + return; + } + + response.getWriter().println("不可识别的加密类型"); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java new file mode 100644 index 0000000000..3b569e1b89 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java @@ -0,0 +1,33 @@ +package cn.binarywang.wx.miniapp.test; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import com.google.inject.Binder; +import com.google.inject.Module; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @author Binary Wang + */ +public class ApiTestModule implements Module { + + @Override + public void configure(Binder binder) { + try (InputStream inputStream = ClassLoader.getSystemResourceAsStream("test-config.xml")) { + TestConfig config = TestConfig.fromXml(inputStream); + config.setAccessTokenLock(new ReentrantLock()); + + WxMaService wxService = new cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl(); + wxService.setWxMaConfig(config); + + binder.bind(WxMaService.class).toInstance(wxService); + binder.bind(WxMaConfig.class).toInstance(config); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java new file mode 100644 index 0000000000..ee941ef349 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java @@ -0,0 +1,61 @@ +package cn.binarywang.wx.miniapp.test; + +import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import org.apache.commons.lang3.builder.ToStringBuilder; + +import java.io.InputStream; +import java.util.concurrent.locks.Lock; + +/** + * @author Binary Wang + */ +@XStreamAlias("xml") +public class TestConfig extends WxMaInMemoryConfig { + + private String openid; + private String kfAccount; + private String templateId; + + public static TestConfig fromXml(InputStream is) { + XStream xstream = XStreamInitializer.getInstance(); + xstream.processAnnotations(TestConfig.class); + return (TestConfig) xstream.fromXML(is); + } + + public String getOpenid() { + return this.openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + public String getKfAccount() { + return this.kfAccount; + } + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + + public String getTemplateId() { + return this.templateId; + } + + public void setTemplateId(String templateId) { + this.templateId = templateId; + } + + public void setAccessTokenLock(Lock lock) { + super.accessTokenLock = lock; + } + +} diff --git a/weixin-java-miniapp/src/test/resources/logback-test.xml b/weixin-java-miniapp/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..14d6a9a79b --- /dev/null +++ b/weixin-java-miniapp/src/test/resources/logback-test.xml @@ -0,0 +1,14 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %replace(%caller{1}){'Caller', ''} - %msg%n + + + + + + + + + diff --git a/weixin-java-miniapp/src/test/resources/test-config.sample.xml b/weixin-java-miniapp/src/test/resources/test-config.sample.xml new file mode 100644 index 0000000000..1f6cc38887 --- /dev/null +++ b/weixin-java-miniapp/src/test/resources/test-config.sample.xml @@ -0,0 +1,11 @@ + + JSON或者XML + appid + secret + Token + EncodingAESKey + 可以不填写 + 可以不填写 + 某个用户的openId + 模版消息的模版ID + diff --git a/weixin-java-miniapp/src/test/resources/tmp.png b/weixin-java-miniapp/src/test/resources/tmp.png new file mode 100644 index 0000000000000000000000000000000000000000..5cb4a406051bc91872c0767883ccf1b4b03ed16d GIT binary patch literal 5264 zcmd5=`8yPB)E?zcLdcdxBFPr7eQT`QLzJztW=VD<48~HH5M%5jim^;;tR=go$Tm!t ztb@jkDQh!~8Dr-2e*eRFUEdG)IoEy8`Qcp8bv^gpF0Mz(p;t65(Gq_^_05rik=$`+aaQ09$XD|S8e&9c_6v&+y zISC3!+;)nv5AltN@(lL@74BmmJ zA&G^RlclqUrlBsl3%?bW8U|!psT7~eI0zG=E7XW z>dlT&_4`CYK?92%mq)CROA+T}BQrvS7QbD*(0B3FzuR$?F{l`f&>e+t_w(J>A{-$m zM`O7Idt-N^7)&~$m$3aw)AyRhbfY>%2yS5;10VkXjGtj)qd2hQ@(~p|nZmvNDo#p5 zrX5dPFwtq4SEIhY@);vZDQ#dhLK33rv=zEYUd8hv<)2W}n@QB3c%ObBp*{+$Nj2Bd zHfJ()8endEjP6Oa8?|Q=ltB#`*d|D|p zo!7A?=o(C~n)Rwp_im76rnJZA3 zDv9BYa%#4ZhST5lG5)GxAO8+(0bRcZj!F@dIbDO7F4qbF$`3V)F=5S!l(0L$b4;I} zED1XRj-`@~qcbBV*24}CDKC3o7MjFVc8!EftQ)>ZRl}DdU1oD#PiUrjHhe_qJRx{9 z6)nv`K-^;qAAXIm-i?hBh&b{^&2XtcT^i%*kmjoR*2^wsQ|3bu&^5uPhWj0NsHv>%URdw zN))Y#c4pm7#Y836Ed!N@$k0zbR5*5{SIwgLANl$Z%>*;-_$N@20JR&sy@tPWeA#6( zEoQP!x$S*J96q+O4%J57?mPIz`CckoFxiyeGT0OFTQ3D;leBTP9p|AWqq`I^v>4gw zdbmPAjBT)v*Ot!_qiRKVwQUU;33KLDEO`{T6Gc+Rb;2dJ!i%PAty3pH3Ty1hjhE;5 zh7%oSbaExt8|LS2cq?XQ7vKSfy%t1ADV=GbYYAX_@JmSg$2$;#u{&zR?geDyf(Jm- z3Z^pi&b8HdmBe(CaT6>ffoqx}iy#=zCr}&lrb|`#w`YOSb84Y zyDJ+m2O$cLzV!gC=-zyIPTydk?8LCkK(_G9-IAdPQR1Gw5jy)-^BQ6OG87^XbQTfr zlUOxx&|Pb9&F|GDrf&@O4BacQ%igHjsZZH}9d-$-eUhXj2{6GYsLb5*JZAl`_9F>9 zY9uQ7*`U(uA~s?pN>H65J*}rz*qaP?PbQniA3Fv`BW z#o(jbpxdjsN!K~j8REi}o|^G7A6o4DLC25-?e^GGLAQJ{<;q32lqq;cfaGj@d?BXg z*7R0I!ZrUrlerP!yZ#B;0*pocyE5k@??haw7+BP)^M=??N$De=)1KSZ3}^h9xcGvMFiPv8?_UGU z;kV0l_Zxafw z^;*Y(_05P!VmyVG@ybB+@g*rK)*SxnXqRvHAcBk&k}Ok*(-eM}_1EGqRG=h^Zh0+Aa|7-+fm3{c?Py`RdY6 zY`|8>Aq-_jueOA3LT6WysG4HG^Z|Vi4dLr0zVe8}`U?q2jAR@(^&kB9yQ++L7nDc$ ztyJQjL+-CB-ih(vk&M%+4QJdmN(#vJ=?2bv%K@|eN4#V(6ovWs9L(rkL38+24)lOX zH>N+M+-h!p%jmD(k<%sejYtV@dJieBZ-O6eDHo9hWufO*6@HrEBzITDJFh8P#bofw zkA1D&&6RwA*fguKM%k<3;DC#*9+5F55B8KIkU`vI+ostNEGI-K*Alj|X?#IWmu+(Z zoKU-)t2XtTmQfKd*WjOP*}Lp@F)CJ`w+CHj=50n6s8Fq7>p)ybk`dRM`c={#qh+`T zYJ)Tc%UAL{Akrmdgk+aj<0EM)qXhFn{f93{gC}IaEk)6jM9z~TO z?1+HWA;)f89c5RDX$*+=@N7&?rNX+fXomiHF(N}t&_ z$q-#Pwn*|13cOVxQXia8=HK?h@2O%xv7`=Z|5?)mQe`=t12ba(W!3A;?Unb<5AzSE zDk-67K`nWp}BzuMH*W0?$`c%Askc1-VPV zDEB5~@8$^bKrXYcZRDA^blxjc?QJ19F)tGKR(ZxkG^2MOp*3GNXy;N=NKAY*PxK!$ z_p9>}$t=K{F9lW|mTm5SL}CZWdwz)y(qXVt-Ezbs1E2iE&sAdTwA&RwDCa3(zyl)_ z(I2Oc5|@HWKdmu?4ua;yqfH(cZSOm}Q#pC1vBumf9C<_Dul#@@kzQaqHtkH}&FMG< zHvCn2udc5c+Wh_@m1kP3=09<8JL1N1I!pE*z3QcCR6(PF6PNkgSux@67B@IAXhaV2 ze9Vu>`iZ@el`V^7Y~bYlJyGK+3}Vx!F=gVHi^Sz;55CP_987*#MKAJjxlC%b$|gh( zhS?L_%^ull8$D4zl@onhtr@2rkBN}03nmO~H*n)CTDAv;w6$v-=oJ|t$p`+^1OAH3?s zy&6qAQdyal=o&rW@6s|{OqM)F%v67*t>C+~vj~i4q4@XM{=L`nV9*=9@CitF< znHLiHYX4bW{|oQkbjt01fEm2Lrq0GQPuuit%cK}FiZN+KiF>A~>De2(bLGWMq}w#T zk%Ml)BpvsL;9sbHUKwgW+tzgR6l=m(b*-uN;NZbn9&-k?BBV!O$JKsGNqCr-^@2Ip zy2x1Ds!+!=hn8U)J2KRQfP?H{`c#O<>@routt753&;>p3Vkxvs{lal2&^wiNpNkm6 zAQzclIX-+f#@+FEJ^|`SjvRbIvq((Z<8wcpH=J4Ue}k~FoFRW3VPb~zRDPTW%!#u+ zeRpGD|GSzcbaj#0UHrB0r%*O=@Y^$2v(V)yUy>$8n8)a`y}2Bq`Y>PmW6cSDZ6*?X z+%jnjj2Xe{_A zo`whw!ga3c+nB~8LS~4>+1qrUPqqsXL!xb6)$o@VIH zddgDUftF|!qtXpcLC~yDeAxEp*BmB1lTuyF2>*M(1i@c^8j2sZiK!1WbrLSIzI~)W zndxtgTvI8Sd%F~=5(&DjLS0P9ROvV=|*P+ie$5d1J2*R=1GfRGFU-{R`O) zsmM%}(u@>;zZZ%2`O<{P^Wry}@^1k9)2upm%&%zY;sDa!JI$8|t8v4-JgZLN(W9wC zO~Sw2`4^SF*IbF$j^}h6x%lklOOOO-;)t` z)zzqo`2BWlC+_}>ve%*Wek(rh0nQ??<)5KuaUU^74rRY%D+S`6LT{e@X#i%Etg5UV z9B=BnL>DaFG0LKr;5QUutE$~Eh=#+_9m~1k&XN80YBHUrnjd*%ao@T2{-Ng&(>N5n zLzu10&VVlqi+z>siUP)P~L7J)BTGaIv9+4y$ku=p0TxD zHDljTkMI2R#GYu$Ti$+2BWOUM*M61sY`gm>>6^0Kc9zb9&qk>Qv&E6|&7B}T$qt3 zhvLfdAq7ZuK~M5j`G%N%v1dMR`H!80!sAqM^jf=QUPJ%TtugLwvedmTULYRPM7^C} zsxWm_E&i_I!3|5OdAQmcVC>BX%zaPa)x=r1{h z;??0aAdI_suqCNFpIz-`v5ZK{3TV}{mh{PxwpbMxxR;%FRU4*Q=SFR{# z^B95b5k!TCEY8p>pOA=i`;rrC zwr7OanRUpXEH?;_wD~+zjdn^bh9BZcrqUG%b+6#z?`mHw##S^CXbA8M-@5QtP(M=W z6zI`i#aRnR;F;d5$DJxN`qs(WeN7~7natux6~D@3T7>DT^baR=h+b`Wx#8>uJ?!d7dOB2D?*GlU3+@?a z${IuD4wN|zlV@7PGY=dQ6w=GTY3IM@Pb>u)nMNSfil4e!mj)_T2i1PaB5OHpH*l1V zs5C+vx&qH&(q>`||Cra;WF5?z&?d;kHxw6mW77PCNwmmIShI=+-PtKOL4%DSCE!f* ze^Yl?!@5&D_GH+`*=rn%Dy)2uYz!2AxsT`HTJWd4WCzT=VVl39=*s^72q(DZsW7*KKdqFP5Xf Date: Fri, 16 Jun 2017 00:08:01 +0800 Subject: [PATCH 087/179] =?UTF-8?q?=E5=8F=91=E5=B8=83=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC2.6.5.BETA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 86e9c096e0..575265314b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang weixin-java-parent - 2.6.3.BETA + 2.6.5.BETA pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 72f213bcfd..ce2e379a51 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.6.3.BETA + 2.6.5.BETA weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index a9322b57ba..29f53f89f0 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.6.3.BETA + 2.6.5.BETA weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index 1dbf7835ed..5aa2ebd485 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.6.3.BETA + 2.6.5.BETA weixin-java-miniapp WeiXin Java Tools - MiniApp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index caa607140a..3be0615ed7 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.6.3.BETA + 2.6.5.BETA weixin-java-mp WeiXin Java Tools - MP diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 5dcd243e1e..ca66794ac4 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 2.6.3.BETA + 2.6.5.BETA 4.0.0 From b81f74fb340d4c354779823f0ba8f17fc2105fdb Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 16 Jun 2017 00:15:20 +0800 Subject: [PATCH 088/179] update --- readme.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index cfc090b3cd..5c988a184b 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -微信支付、公众号&企业号开发Java SDK +微信支付、小程序、公众号&企业号开发Java SDK --------------------------------- [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent) [![Build Status](https://travis-ci.org/Wechat-Group/weixin-java-tools.svg?branch=develop)](https://travis-ci.org/Wechat-Group/weixin-java-tools) @@ -42,6 +42,7 @@ --------------------------------- ## 可参考的Demo项目 #### 欢迎提供更多的Demo供新手参考: +* https://github.com/wechat-group/weixin-java-miniapp-demo (微信小程序Demo) * https://github.com/wechat-group/weixin-java-pay-demo (微信支付Demo) * https://github.com/wechat-group/weixin-java-cp-demo (企业号Demo) * https://github.com/wechat-group/weixin-java-mp-demo (公众号Demo,使用Spring MVC实现) @@ -52,6 +53,16 @@ --------------------------------- ## Maven 最新正式版本 +* 微信小程序(暂时为测试版本): + +```xml + + com.github.binarywang +  weixin-java-miniapp +  2.6.5.BETA + +``` + * 微信支付: ```xml From 9eb4ccf4a46b7307ec5fc57cf35dee0f0c7d288b Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 17 Jun 2017 00:12:04 +0800 Subject: [PATCH 089/179] =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=B4=A0=E6=9D=90=E7=B1=BB=E5=9E=8B=E5=B8=B8=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/binarywang/wx/miniapp/constant/WxMaConstants.java | 7 +++++++ .../cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java | 8 ++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaConstants.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaConstants.java index 2ec718694a..14016fa578 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaConstants.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaConstants.java @@ -8,6 +8,13 @@ * @author Binary Wang */ public class WxMaConstants { + /** + * 素材类型 + */ + public static class MediaType { + public static final String IMAGE = "image";//图片 + } + /** * 消息格式 */ diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java index 62847ab7d1..fe986c8e71 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java @@ -6,6 +6,7 @@ import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; import cn.binarywang.wx.miniapp.message.WxMaMessageHandler; import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; import cn.binarywang.wx.miniapp.test.TestConfig; @@ -37,6 +38,7 @@ public void handle(WxMaMessage wxMessage, Map context, .toUser(wxMessage.getFromUser()).build()); } }; + private static final WxMaMessageHandler textHandler = new WxMaMessageHandler() { @Override public void handle(WxMaMessage wxMessage, Map context, @@ -47,13 +49,14 @@ public void handle(WxMaMessage wxMessage, Map context, } }; + private static final WxMaMessageHandler picHandler = new WxMaMessageHandler() { @Override public void handle(WxMaMessage wxMessage, Map context, WxMaService service, WxSessionManager sessionManager) throws WxErrorException { try { WxMediaUploadResult uploadResult = service.getMediaService() - .uploadMedia("image", "png", + .uploadMedia(WxMaConstants.MediaType.IMAGE, "png", ClassLoader.getSystemResourceAsStream("tmp.png")); service.getMsgService().sendKefuMsg( WxMaKefuMessage @@ -66,13 +69,14 @@ public void handle(WxMaMessage wxMessage, Map context, } } }; + private static final WxMaMessageHandler qrcodeHandler = new WxMaMessageHandler() { @Override public void handle(WxMaMessage wxMessage, Map context, WxMaService service, WxSessionManager sessionManager) throws WxErrorException { try { final File file = service.getQrcodeService().createQrcode("123", 430); - WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file); + WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia(WxMaConstants.MediaType.IMAGE, file); service.getMsgService().sendKefuMsg( WxMaKefuMessage .IMAGE() From 166f842ecf09afc6b828e92c791d73420573a287 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 17 Jun 2017 12:31:24 +0800 Subject: [PATCH 090/179] update --- contribution.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/contribution.md b/contribution.md index 91be80a478..093614d37c 100644 --- a/contribution.md +++ b/contribution.md @@ -1,10 +1,11 @@ # 代码贡献指南 -1. 非常欢迎和感谢对本项目发起Pull Request的同学,本项目代码风格为使用2个空格代表一个Tab,因此在提交代码时请注意一下,否则很容易在IDE格式化代码后与原代码产生大量diff,这样会给其他人阅读代码带来极大的困扰。为了便于设置,本项目引入editorconfig插件,请使用eclipse的同学在贡献代码前安装相关插件,IntelliJ IDEA新版本自带支持,如果没有可自行安装插件。 +1. 首先非常欢迎和感谢对本项目发起Pull Request的同学。 +1. 本项目代码风格为使用2个空格代表一个Tab,因此在提交代码时请注意一下,否则很容易在IDE格式化代码后与原代码产生大量diff,这样会给其他人阅读代码带来极大的困扰。 +1. 为了便于设置,本项目引入editorconfig支持,请使用Eclipse的同学在贡献代码前安装相关插件,而IntelliJ IDEA新版本自带支持,如果没有可自行安装插件。 +1. **提交代码前,请检查代码是否已经格式化,并且保证新增加或者修改的方法都有完整的参数说明,而public方法必须拥有相应的单元测试并通过测试。** 1. 本项目可以采用两种方式接受代码贡献: -    * 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择develop分支,详细步骤参考后文,推荐使用此种方式贡献代码。 - * (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。 -1. 另外,提交代码前请检查代码是否已经格式化,并且保证新增加或者修改的方法都有完整的参数说明,而public方法必须拥有相应的单元测试并通过测试。 - + - 第一种就是基于[Git Flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow)开发流程,因此在发起Pull Request的时候请选择develop分支,详细步骤参考后文,推荐使用此种方式贡献代码。 + - (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。 ### PR方式贡献代码步骤 * 在 GitHub 上 `fork` 到自己的仓库,如 `my_user/weixin-java-tools`,然后 `clone` 到本地,并设置用户信息。 From 87687b336917e5d90e7e593a7bb218c75f31529f Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 18 Jun 2017 12:19:51 +0800 Subject: [PATCH 091/179] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E4=BB=BF=E7=9C=9F=E6=B5=8B=E8=AF=95=E7=B3=BB=E7=BB=9F=E7=9A=84?= =?UTF-8?q?=E9=AA=8C=E7=AD=BE=E5=AF=86=E9=92=A5=E7=9A=84API=20#206?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bean/request/WxPayDefaultRequest.java | 19 +++++++ .../result/WxPaySandboxSignKeyResult.java | 35 +++++++++++++ .../wxpay/service/WxPayService.java | 11 ++++ .../wxpay/service/impl/WxPayServiceImpl.java | 51 +++++++++++++------ .../service/impl/WxPayServiceImplTest.java | 6 +++ 5 files changed, 107 insertions(+), 15 deletions(-) create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDefaultRequest.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPaySandboxSignKeyResult.java diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDefaultRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDefaultRequest.java new file mode 100644 index 0000000000..ff36bfaad7 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDefaultRequest.java @@ -0,0 +1,19 @@ +package com.github.binarywang.wxpay.bean.request; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + *
+ *  支付请求默认对象类
+ *  Created by BinaryWang on 2017/6/18.
+ * 
+ * + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxPayDefaultRequest extends WxPayBaseRequest { + @Override + protected void checkConstraints() { + //do nothing + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPaySandboxSignKeyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPaySandboxSignKeyResult.java new file mode 100644 index 0000000000..6326f694d3 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPaySandboxSignKeyResult.java @@ -0,0 +1,35 @@ +package com.github.binarywang.wxpay.bean.result; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + *
+ *  Created by BinaryWang on 2017/6/18.
+ * 
+ * + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxPaySandboxSignKeyResult extends WxPayBaseResult { + + /** + *
+   * 沙箱密钥
+   * sandbox_signkey
+   * 否
+   * 013467007045764
+   * String(32)
+   * 返回的沙箱密钥
+   * 
+ */ + @XStreamAlias("sandbox_signkey") + private String sandboxSignKey; + + public String getSandboxSignKey() { + return sandboxSignKey; + } + + public void setSandboxSignKey(String sandboxSignKey) { + this.sandboxSignKey = sandboxSignKey; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index f3102a3a6c..495ecb5eb9 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -328,4 +328,15 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri * @see WxPayService#authcode2Openid(WxPayAuthcode2OpenidRequest) */ String authcode2Openid(String authCode) throws WxPayException; + + /** + *
+   * 获取仿真测试系统的验签密钥
+   * 请求Url: https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey
+   * 是否需要证书: 否
+   * 请求方式: POST
+   * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_1
+   * 
+ */ + String getSandboxSignKey() throws WxPayException; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java index f9973f0fcc..a7228774e1 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java @@ -76,7 +76,7 @@ public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeN request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/refundquery"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayRefundQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundQueryResult.class); result.composeRefundRecords(); result.checkResult(this); @@ -139,7 +139,7 @@ public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/orderquery"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); if (StringUtils.isBlank(responseContent)) { throw new WxPayException("无响应结果"); } @@ -161,7 +161,7 @@ public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/closeorder"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayOrderCloseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderCloseResult.class); result.checkResult(this); @@ -173,7 +173,7 @@ public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) th request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/unifiedorder"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayUnifiedOrderResult result = WxPayBaseResult.fromXML(responseContent, WxPayUnifiedOrderResult.class); result.checkResult(this); return result; @@ -294,7 +294,7 @@ public void report(WxPayReportRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/payitil/report"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); result.checkResult(this); } @@ -310,7 +310,7 @@ public WxPayBillResult downloadBill(String billDate, String billType, String tar request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/downloadbill"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); if (responseContent.startsWith("<")) { WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); result.checkResult(this); @@ -397,7 +397,7 @@ public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayEx request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/micropay"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayMicropayResult result = WxPayBaseResult.fromXML(responseContent, WxPayMicropayResult.class); result.checkResult(this); return result; @@ -419,7 +419,7 @@ public String shorturl(WxPayShorturlRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/tools/shorturl"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayShorturlResult result = WxPayBaseResult.fromXML(responseContent, WxPayShorturlResult.class); result.checkResult(this); return result.getShortUrl(); @@ -435,7 +435,7 @@ public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayE request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/tools/authcodetoopenid"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayAuthcode2OpenidResult result = WxPayBaseResult.fromXML(responseContent, WxPayAuthcode2OpenidResult.class); result.checkResult(this); return result.getOpenid(); @@ -446,7 +446,25 @@ public String authcode2Openid(String authCode) throws WxPayException { return this.authcode2Openid(new WxPayAuthcode2OpenidRequest(authCode)); } - private String post(String url, String xmlParam) { + @Override + public String getSandboxSignKey() throws WxPayException { + WxPayDefaultRequest request = new WxPayDefaultRequest(); + request.checkAndSign(this.getConfig()); + + String url = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey"; + String responseContent = this.post(url, request.toXML(), false); + WxPaySandboxSignKeyResult result = WxPayBaseResult.fromXML(responseContent, WxPaySandboxSignKeyResult.class); + result.checkResult(this); + return result.getSandboxSignKey(); + } + + /** + * @param url 请求地址 + * @param xmlParam 请求字符串 + * @param needTransferEncoding 是否需要对结果进行重编码 + * @return 返回请求结果 + */ + private String post(String url, String xmlParam, boolean needTransferEncoding) { String requestString = xmlParam; try { requestString = new String(xmlParam.getBytes(CharEncoding.UTF_8), CharEncoding.ISO_8859_1); @@ -457,11 +475,14 @@ private String post(String url, String xmlParam) { HttpRequest request = HttpRequest.post(url).body(requestString); HttpResponse response = request.send(); - String responseString = null; - try { - responseString = new String(response.bodyText().getBytes(CharEncoding.ISO_8859_1), CharEncoding.UTF_8); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); + String responseString = response.bodyText(); + + if (needTransferEncoding) { + try { + responseString = new String(response.bodyText().getBytes(CharEncoding.ISO_8859_1), CharEncoding.UTF_8); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } } this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, xmlParam, responseString); diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java index ac599adcb3..995aa8275b 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java @@ -264,5 +264,11 @@ public void testAuthcode2Openid() throws Exception { this.logger.info(result); } + @Test + public void testGetSandboxSignKey() throws Exception { + final String signKey = this.payService.getSandboxSignKey(); + assertNotNull(signKey); + this.logger.info(signKey); + } } From ec4bf2687c1d51ea13836beaac7d01a8955ed2b2 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 18 Jun 2017 12:52:31 +0800 Subject: [PATCH 092/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E8=AF=B7=E6=B1=82=E6=9F=90=E4=BA=9B=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=9C=A8=E6=9F=90=E4=BA=9B=E6=83=85=E5=86=B5=E4=B8=8B?= =?UTF-8?q?=E4=BC=9A=E5=87=BA=E7=8E=B0=E4=B9=B1=E7=A0=81=E7=9A=84=E6=83=85?= =?UTF-8?q?=E5=86=B5=20#225?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wxpay/service/impl/WxPayServiceImpl.java | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java index a7228774e1..c28697a8fd 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java @@ -474,18 +474,9 @@ private String post(String url, String xmlParam, boolean needTransferEncoding) { } HttpRequest request = HttpRequest.post(url).body(requestString); - HttpResponse response = request.send(); - String responseString = response.bodyText(); - - if (needTransferEncoding) { - try { - responseString = new String(response.bodyText().getBytes(CharEncoding.ISO_8859_1), CharEncoding.UTF_8); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - } + String responseString = this.getResponseString(request.send()); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, xmlParam, responseString); + this.log.info("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", url, xmlParam, responseString); return responseString; } @@ -499,16 +490,35 @@ private String postWithKey(String url, String requestStr) throws WxPayException sslContext = this.getConfig().initSSLContext(); } - HttpRequest request = HttpRequest.post(url).withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext)); - request.bodyText(requestStr); - HttpResponse response = request.send(); - String result = response.bodyText(); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result); - return result; + HttpRequest request = HttpRequest + .post(url) + .withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext)) + .bodyText(requestStr); + + String responseString = this.getResponseString(request.send()); + + this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", url, requestStr, responseString); + return responseString; } catch (Exception e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", url, requestStr, e.getMessage()); + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", url, requestStr, e.getMessage()); throw new WxPayException(e.getMessage()); } } + private String getResponseString(HttpResponse response) { + this.log.debug("【微信服务器响应头信息】:\n{}", response.toString(false)); + + String responseString = response.bodyText(); + + if (StringUtils.isBlank(response.charset())) { + try { + responseString = new String(response.bodyText().getBytes(CharEncoding.ISO_8859_1), CharEncoding.UTF_8); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + return responseString; + } + + } From c7ffff0a9cd5b435a86eb0a78a03a81736ab187a Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 18 Jun 2017 14:48:32 +0800 Subject: [PATCH 093/179] =?UTF-8?q?#251=20=E5=BE=AE=E4=BF=A1=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E8=AF=81=E4=B9=A6=E6=96=87=E4=BB=B6=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=94=AF=E6=8C=81classpath=E5=BC=80=E5=A4=B4?= =?UTF-8?q?=E7=9A=84=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binarywang/wxpay/config/WxPayConfig.java | 29 +++++++++++++++---- .../wxpay/exception/WxPayException.java | 5 ++++ .../wxpay/service/impl/WxPayServiceImpl.java | 2 +- .../wxpay/config/WxPayConfigTest.java | 24 +++++++++++++++ weixin-java-pay/src/test/resources/.gitignore | 1 + 5 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java create mode 100644 weixin-java-pay/src/test/resources/.gitignore diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java index 6b4ea379de..e6c587a13b 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java @@ -1,11 +1,15 @@ package com.github.binarywang.wxpay.config; +import com.github.binarywang.wxpay.exception.WxPayException; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.ssl.SSLContexts; import javax.net.ssl.SSLContext; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; import java.security.KeyStore; /** @@ -143,7 +147,7 @@ public void setUseSandboxEnv(boolean useSandboxEnv) { this.useSandboxEnv = useSandboxEnv; } - public SSLContext initSSLContext() { + public SSLContext initSSLContext() throws WxPayException { if (StringUtils.isBlank(mchId)) { throw new IllegalArgumentException("请确保商户号mchId已设置"); } @@ -152,20 +156,33 @@ public SSLContext initSSLContext() { throw new IllegalArgumentException("请确保证书文件地址keyPath已配置"); } - File file = new File(this.keyPath); - if (!file.exists()) { - throw new RuntimeException("证书文件【" + file.getPath() + "】不存在!"); + InputStream inputStream; + final String prefix = "classpath:"; + if (this.keyPath.startsWith(prefix)) { + inputStream = WxPayConfig.class.getResourceAsStream(this.keyPath.replace(prefix, "")); + } else { + try { + File file = new File(this.keyPath); + if (!file.exists()) { + throw new WxPayException("证书文件【" + file.getPath() + "】不存在!"); + } + + inputStream = new FileInputStream(file); + } catch (IOException e) { + throw new WxPayException("证书文件有问题,请核实!", e); + } } try { - FileInputStream inputStream = new FileInputStream(file); KeyStore keystore = KeyStore.getInstance("PKCS12"); char[] partnerId2charArray = mchId.toCharArray(); keystore.load(inputStream, partnerId2charArray); this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build(); return this.sslContext; } catch (Exception e) { - throw new RuntimeException("证书文件有问题,请核实!", e); + throw new WxPayException("证书文件有问题,请核实!", e); + } finally { + IOUtils.closeQuietly(inputStream); } } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java index eafd8b98d3..948c7a4995 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java @@ -45,6 +45,11 @@ public WxPayException(String customErrorMsg) { this.customErrorMsg = customErrorMsg; } + public WxPayException(String customErrorMsg, Throwable tr) { + super(customErrorMsg, tr); + this.customErrorMsg = customErrorMsg; + } + private WxPayException(Builder builder) { super(builder.buildErrorMsg()); returnCode = builder.returnCode; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java index c28697a8fd..14c34d0360 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java @@ -497,7 +497,7 @@ private String postWithKey(String url, String requestStr) throws WxPayException String responseString = this.getResponseString(request.send()); - this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", url, requestStr, responseString); + this.log.info("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", url, requestStr, responseString); return responseString; } catch (Exception e) { this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", url, requestStr, e.getMessage()); diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java new file mode 100644 index 0000000000..83bcbf2c17 --- /dev/null +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java @@ -0,0 +1,24 @@ +package com.github.binarywang.wxpay.config; + +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +/** + *
+ *  Created by BinaryWang on 2017/6/18.
+ * 
+ * + * @author Binary Wang + */ +public class WxPayConfigTest { + private WxPayConfig payConfig = new WxPayConfig(); + + @Test + public void testInitSSLContext() throws Exception { + payConfig.setMchId("123"); + payConfig.setKeyPath("classpath:/abc.p12"); + payConfig.initSSLContext(); + } + +} diff --git a/weixin-java-pay/src/test/resources/.gitignore b/weixin-java-pay/src/test/resources/.gitignore new file mode 100644 index 0000000000..edd25bc776 --- /dev/null +++ b/weixin-java-pay/src/test/resources/.gitignore @@ -0,0 +1 @@ +*.p12 From babfc90258e3ab7612e145d54a90fb069b8db160 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 20 Jun 2017 10:42:44 +0800 Subject: [PATCH 094/179] update --- readme.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/readme.md b/readme.md index 5c988a184b..fc465112a7 100644 --- a/readme.md +++ b/readme.md @@ -3,14 +3,26 @@ [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent) [![Build Status](https://travis-ci.org/Wechat-Group/weixin-java-tools.svg?branch=develop)](https://travis-ci.org/Wechat-Group/weixin-java-tools) -### 注意事项: -1. 声明: ***本项目Fork自chanjarster/weixin-java-tools,但由于原项目已停止维护,故单独维护和发布,且发布到maven上的groupId也会不同,详细信息见下文。*** -1. **新手请注意,本项目仅是一个开发工具包(即SDK),未提供Web实现,建议使用maven或gradle引用本项目即可使用本SDK提供的各种功能,详情可参考下文中提到的Demo项目或本项目中的部分单元测试代码;如果没有贡献代码的意愿,不建议下载项目的源码自行编译,因为如果想看源码使用maven也是可以下载源码的**; +#### 声明: ***本项目Fork自chanjarster/weixin-java-tools,但由于原项目已停止维护,故单独维护和发布,且发布到maven上的groupId也会不同,详细信息见下文。*** + +** 新人提示:本项目仅是一个开发工具包(即SDK),未提供Web实现,建议使用maven或gradle引用本项目即可使用本SDK提供的各种功能,详情可参考下文中提到的Demo项目或本项目中的部分单元测试代码;另外微信开发新手请务必阅读wiki首页的常见问题部分,可以少走很多弯路,节省不少时间。** + +## Demo项目列表 +* https://github.com/wechat-group/weixin-java-miniapp-demo (微信小程序Demo) +* https://github.com/wechat-group/weixin-java-pay-demo (微信支付Demo) +* https://github.com/wechat-group/weixin-java-cp-demo (企业号Demo) +* https://github.com/wechat-group/weixin-java-mp-demo (公众号Demo,使用Spring MVC实现) +* https://github.com/wechat-group/weixin-java-mp-demo-springboot (公众号Demo,使用Spring Boot实现) +* https://github.com/wechat-group/weixin-java-tools-springmvc (公众号Demo,内含部分微信支付代码) +* https://github.com/wechat-group/weixin-java-mp-multi-demo (支持多公众号) + +--------------------------------- +### 其他信息: 1. 最新更新:**2017-4-13 发布[【2.6.0正式版】](https://github.com/Wechat-Group/weixin-java-tools/releases)**! 1. 开源中国网站的本项目介绍的首页链接地址:https://www.oschina.net/p/weixin-java-tools-new 1. 自2.0.0版本以来,公众号的接口调整比较大,主要是为了解决主接口类过于庞大不方便管理的问题,将接口实现代码按模块进行拆分。 1. 自2.6.0版本开始,微信支付相关功能抽出独立为一个模块,详细使用方式请参考相关demo; -1. SDK详细开发文档请查阅 [【Wiki】](https://github.com/wechat-group/weixin-java-tools/wiki),部分文档可能未能及时更新,如有发现,可以及时上报或者自行修改。***另外微信开发新手请务必阅读wiki首页的常见问题部分,可以少走很多弯路,节省不少时间。*** +1. SDK详细开发文档请查阅 [【Wiki】](https://github.com/wechat-group/weixin-java-tools/wiki),部分文档可能未能及时更新,如有发现,可以及时上报或者自行修改。 1. 各个模块的Javadoc可以在线查看(有可能是最新的测试版本的,请注意观察版本号):[weixin-java-pay](https://binarywang.github.io/weixin-java-pay-javadoc/)、[weixin-java-mp](https://binarywang.github.io/weixin-java-mp-javadoc/)、[weixin-java-common](https://binarywang.github.io/weixin-java-common-javadoc/)、[weixin-java-cp](https://binarywang.github.io/weixin-java-cp-javadoc/) 1. 本SDK要求的最低JDK版本是7,还在使用JDK6的用户请参考[【此项目】]( https://github.com/binarywang/weixin-java-tools-for-jdk6) ,而其他更早的JDK版本则需要自己改造实现。 1. 如有新功能需求,发现BUG,或者由于微信官方接口调整导致的代码问题,可以直接在[【Issues】](https://github.com/Wechat-Group/weixin-java-tools/issues)页提出issue,便于讨论追踪问题; @@ -39,17 +51,6 @@ * Bitbucket:https://bitbucket.org/binarywang/weixin-java-tools * Coding: https://git.coding.net/binarywang/weixin-java-tools.git ---------------------------------- -## 可参考的Demo项目 -#### 欢迎提供更多的Demo供新手参考: -* https://github.com/wechat-group/weixin-java-miniapp-demo (微信小程序Demo) -* https://github.com/wechat-group/weixin-java-pay-demo (微信支付Demo) -* https://github.com/wechat-group/weixin-java-cp-demo (企业号Demo) -* https://github.com/wechat-group/weixin-java-mp-demo (公众号Demo,使用Spring MVC实现) -* https://github.com/wechat-group/weixin-java-mp-demo-springboot (公众号Demo,使用Spring Boot实现) -* https://github.com/wechat-group/weixin-java-tools-springmvc (公众号Demo,内含部分微信支付代码) -* https://github.com/wechat-group/weixin-java-mp-multi-demo (支持多公众号) - --------------------------------- ## Maven 最新正式版本 From e2659b394ec6d19ee60ae947954bd45b6d39daa8 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 20 Jun 2017 10:45:42 +0800 Subject: [PATCH 095/179] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index fc465112a7..3961e33fd8 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,7 @@ #### 声明: ***本项目Fork自chanjarster/weixin-java-tools,但由于原项目已停止维护,故单独维护和发布,且发布到maven上的groupId也会不同,详细信息见下文。*** -** 新人提示:本项目仅是一个开发工具包(即SDK),未提供Web实现,建议使用maven或gradle引用本项目即可使用本SDK提供的各种功能,详情可参考下文中提到的Demo项目或本项目中的部分单元测试代码;另外微信开发新手请务必阅读wiki首页的常见问题部分,可以少走很多弯路,节省不少时间。** +***新人提示:本项目仅是一个开发工具包(即SDK),未提供Web实现,建议使用maven或gradle引用本项目即可使用本SDK提供的各种功能,详情可参考下文中提到的Demo项目或本项目中的部分单元测试代码;另外微信开发新手请务必阅读wiki首页的常见问题部分,可以少走很多弯路,节省不少时间。*** ## Demo项目列表 * https://github.com/wechat-group/weixin-java-miniapp-demo (微信小程序Demo) From aded340ac52a0d7405c28face4db9d215e4c644f Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 22 Jun 2017 15:23:19 +0800 Subject: [PATCH 096/179] =?UTF-8?q?#253=20=E4=BF=AE=E6=94=B9=E4=BC=81?= =?UTF-8?q?=E4=B8=9A=E5=8F=B7=E5=8F=91=E9=80=81=E6=B6=88=E6=81=AF=E7=9A=84?= =?UTF-8?q?messageSend=E6=96=B9=E6=B3=95=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E5=80=BC=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E8=BF=9B=E8=A1=8C=E8=87=AA=E8=A1=8C=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../me/chanjar/weixin/cp/api/WxCpService.java | 7 +- .../cp/api/impl/AbstractWxCpServiceImpl.java | 9 +- .../weixin/cp/bean/WxCpMessageSendResult.java | 103 ++++++++++++++++++ .../weixin/cp/api/WxCpMessageAPITest.java | 48 +++++--- 4 files changed, 142 insertions(+), 25 deletions(-) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 6e30ce55e0..444fa98dea 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -8,10 +8,7 @@ import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.cp.bean.WxCpDepart; -import me.chanjar.weixin.cp.bean.WxCpMessage; -import me.chanjar.weixin.cp.bean.WxCpTag; -import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.bean.*; import java.io.File; import java.io.IOException; @@ -141,7 +138,7 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * * @param message 要发送的消息对象 */ - void messageSend(WxCpMessage message) throws WxErrorException; + WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorException; /** *
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java
index 463125b46b..497832b36e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java
@@ -17,10 +17,7 @@
 import me.chanjar.weixin.common.util.json.GsonHelper;
 import me.chanjar.weixin.cp.api.WxCpConfigStorage;
 import me.chanjar.weixin.cp.api.WxCpService;
-import me.chanjar.weixin.cp.bean.WxCpDepart;
-import me.chanjar.weixin.cp.bean.WxCpMessage;
-import me.chanjar.weixin.cp.bean.WxCpTag;
-import me.chanjar.weixin.cp.bean.WxCpUser;
+import me.chanjar.weixin.cp.bean.*;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
@@ -131,9 +128,9 @@ public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException
   }
 
   @Override
-  public void messageSend(WxCpMessage message) throws WxErrorException {
+  public WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorException {
     String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send";
-    post(url, message.toJson());
+    return WxCpMessageSendResult.fromJson(this.post(url, message.toJson()));
   }
 
   @Override
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java
new file mode 100644
index 0000000000..6989c4988f
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java
@@ -0,0 +1,103 @@
+package me.chanjar.weixin.cp.bean;
+
+import com.google.common.base.Splitter;
+import com.google.gson.annotations.SerializedName;
+import me.chanjar.weixin.common.util.ToStringUtils;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 
+ * 消息发送结果对象类
+ * Created by Binary Wang on 2017-6-22.
+ * @author Binary Wang
+ * 
+ */ +public class WxCpMessageSendResult { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public static WxCpMessageSendResult fromJson(String json) { + return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpMessageSendResult.class); + } + + @SerializedName("errcode") + private Integer errCode; + + @SerializedName("errmsg") + private String errMsg; + + @SerializedName("invaliduser") + private String invalidUser; + + @SerializedName("invalidparty") + private String invalidParty; + + @SerializedName("invalidtag") + private String invalidTag; + + public Integer getErrCode() { + return this.errCode; + } + + public void setErrCode(Integer errCode) { + this.errCode = errCode; + } + + public String getErrMsg() { + return this.errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } + + public String getInvalidUser() { + return this.invalidUser; + } + + public void setInvalidUser(String invalidUser) { + this.invalidUser = invalidUser; + } + + public String getInvalidParty() { + return this.invalidParty; + } + + public void setInvalidParty(String invalidParty) { + this.invalidParty = invalidParty; + } + + public String getInvalidTag() { + return this.invalidTag; + } + + public void setInvalidTag(String invalidTag) { + this.invalidTag = invalidTag; + } + + public List getInvalidUserList() { + return this.content2List(this.invalidUser); + } + + private List content2List(String content) { + if(StringUtils.isBlank(content)){ + return Collections.emptyList(); + } + + return Splitter.on("|").splitToList(content); + } + + public List getInvalidPartyList() { + return this.content2List(this.invalidParty); + } + + public List getInvalidTagList() { + return this.content2List(this.invalidTag); + } +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java index 8b52ca8261..ece6d5348b 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java @@ -5,38 +5,58 @@ import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; import me.chanjar.weixin.cp.bean.WxCpMessage; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; +import me.chanjar.weixin.cp.bean.WxCpMessageSendResult; +import org.testng.annotations.*; + +import static org.testng.Assert.*; /*** * 测试发送消息 * @author Daniel Qian * */ -@Test(groups = "customMessageAPI", dependsOnGroups = "baseAPI") +@Test(groups = "customMessageAPI") @Guice(modules = ApiTestModule.class) public class WxCpMessageAPITest { @Inject protected WxCpServiceImpl wxService; + private ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage; + + @BeforeTest + public void setup() { + configStorage = (ApiTestModule.WxXmlCpInMemoryConfigStorage) this.wxService.getWxCpConfigStorage(); + } - public void testSendCustomMessage() throws WxErrorException { - ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlCpInMemoryConfigStorage) this.wxService.getWxCpConfigStorage(); - WxCpMessage message1 = new WxCpMessage(); - message1.setAgentId(configStorage.getAgentId()); - message1.setMsgType(WxConsts.CUSTOM_MSG_TEXT); - message1.setToUser(configStorage.getUserId()); - message1.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); - this.wxService.messageSend(message1); + public void testSendMessage() throws WxErrorException { + WxCpMessage message = new WxCpMessage(); + message.setAgentId(configStorage.getAgentId()); + message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); + message.setToUser(configStorage.getUserId()); + message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); - WxCpMessage message2 = WxCpMessage + WxCpMessageSendResult messageSendResult = this.wxService.messageSend(message); + assertNotNull(messageSendResult); + System.out.println(messageSendResult); + System.out.println(messageSendResult.getInvalidPartyList()); + System.out.println(messageSendResult.getInvalidUserList()); + System.out.println(messageSendResult.getInvalidTagList()); + } + + public void testSendMessage1() throws WxErrorException { + WxCpMessage message = WxCpMessage .TEXT() .agentId(configStorage.getAgentId()) .toUser(configStorage.getUserId()) .content("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World") .build(); - this.wxService.messageSend(message2); - } + WxCpMessageSendResult messageSendResult = this.wxService.messageSend(message); + assertNotNull(messageSendResult); + System.out.println(messageSendResult); + System.out.println(messageSendResult.getInvalidPartyList()); + System.out.println(messageSendResult.getInvalidUserList()); + System.out.println(messageSendResult.getInvalidTagList()); + } } From 239b8c505c128893451b551153f20925025d166e Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 24 Jun 2017 22:07:12 +0800 Subject: [PATCH 097/179] =?UTF-8?q?=E4=BF=AE=E6=94=B9logback=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weixin-java-common/src/test/resources/logback-test.xml | 4 +--- weixin-java-cp/src/test/resources/logback-test.xml | 4 +--- weixin-java-mp/src/test/resources/logback-test.xml | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/weixin-java-common/src/test/resources/logback-test.xml b/weixin-java-common/src/test/resources/logback-test.xml index 984cd3ce69..e206e178ec 100644 --- a/weixin-java-common/src/test/resources/logback-test.xml +++ b/weixin-java-common/src/test/resources/logback-test.xml @@ -1,9 +1,7 @@ - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %-5level %replace(%caller{1}){'Caller', ''} - %msg%n diff --git a/weixin-java-cp/src/test/resources/logback-test.xml b/weixin-java-cp/src/test/resources/logback-test.xml index 998a68962d..ec3deca97f 100644 --- a/weixin-java-cp/src/test/resources/logback-test.xml +++ b/weixin-java-cp/src/test/resources/logback-test.xml @@ -1,10 +1,8 @@ - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %-5level %replace(%caller{1}){'Caller', ''} - %msg%n diff --git a/weixin-java-mp/src/test/resources/logback-test.xml b/weixin-java-mp/src/test/resources/logback-test.xml index 9be51c9a5d..8e87c71af2 100644 --- a/weixin-java-mp/src/test/resources/logback-test.xml +++ b/weixin-java-mp/src/test/resources/logback-test.xml @@ -1,10 +1,8 @@ - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %-5level %replace(%caller{1}){'Caller', ''} - %msg%n From 49cf402a4e06fedc8ac056c17cab977508ee825e Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 24 Jun 2017 22:08:01 +0800 Subject: [PATCH 098/179] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=8F=B7message=E7=9B=B8=E5=85=B3=E7=B1=BB=E7=9A=84=E5=8C=85?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cp/{api => config}/WxCpConfigStorage.java | 148 ++-- .../WxCpInMemoryConfigStorage.java | 448 ++++++------ .../WxCpJedisConfigStorage.java | 538 +++++++-------- .../{api => message}/WxCpMessageHandler.java | 58 +- .../WxCpMessageInterceptor.java | 60 +- .../{api => message}/WxCpMessageMatcher.java | 30 +- .../{api => message}/WxCpMessageRouter.java | 498 +++++++------- .../WxCpMessageRouterRule.java | 642 +++++++++--------- .../weixin/cp/api/WxCpDepartAPITest.java | 67 -- 9 files changed, 1211 insertions(+), 1278 deletions(-) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/{api => config}/WxCpConfigStorage.java (94%) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/{api => config}/WxCpInMemoryConfigStorage.java (95%) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/{api => config}/WxCpJedisConfigStorage.java (96%) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/{api => message}/WxCpMessageHandler.java (96%) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/{api => message}/WxCpMessageInterceptor.java (96%) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/{api => message}/WxCpMessageMatcher.java (94%) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/{api => message}/WxCpMessageRouter.java (96%) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/{api => message}/WxCpMessageRouterRule.java (95%) delete mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java similarity index 94% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java index 3484db3b88..4434e697b5 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java @@ -1,74 +1,74 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; - -import java.io.File; - -/** - * 微信客户端配置存储 - * - * @author Daniel Qian - */ -public interface WxCpConfigStorage { - - String getAccessToken(); - - boolean isAccessTokenExpired(); - - /** - * 强制将access token过期掉 - */ - void expireAccessToken(); - - void updateAccessToken(WxAccessToken accessToken); - - void updateAccessToken(String accessToken, int expiresIn); - - String getJsapiTicket(); - - boolean isJsapiTicketExpired(); - - /** - * 强制将jsapi ticket过期掉 - */ - void expireJsapiTicket(); - - /** - * 应该是线程安全的 - * - * @param jsapiTicket - */ - void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); - - String getCorpId(); - - String getCorpSecret(); - - Integer getAgentId(); - - String getToken(); - - String getAesKey(); - - long getExpiresTime(); - - String getOauth2redirectUri(); - - String getHttpProxyHost(); - - int getHttpProxyPort(); - - String getHttpProxyUsername(); - - String getHttpProxyPassword(); - - File getTmpDirFile(); - - /** - * http client builder - * - * @return ApacheHttpClientBuilder - */ - ApacheHttpClientBuilder getApacheHttpClientBuilder(); -} +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + +import java.io.File; + +/** + * 微信客户端配置存储 + * + * @author Daniel Qian + */ +public interface WxCpConfigStorage { + + String getAccessToken(); + + boolean isAccessTokenExpired(); + + /** + * 强制将access token过期掉 + */ + void expireAccessToken(); + + void updateAccessToken(WxAccessToken accessToken); + + void updateAccessToken(String accessToken, int expiresIn); + + String getJsapiTicket(); + + boolean isJsapiTicketExpired(); + + /** + * 强制将jsapi ticket过期掉 + */ + void expireJsapiTicket(); + + /** + * 应该是线程安全的 + * + * @param jsapiTicket + */ + void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); + + String getCorpId(); + + String getCorpSecret(); + + Integer getAgentId(); + + String getToken(); + + String getAesKey(); + + long getExpiresTime(); + + String getOauth2redirectUri(); + + String getHttpProxyHost(); + + int getHttpProxyPort(); + + String getHttpProxyUsername(); + + String getHttpProxyPassword(); + + File getTmpDirFile(); + + /** + * http client builder + * + * @return ApacheHttpClientBuilder + */ + ApacheHttpClientBuilder getApacheHttpClientBuilder(); +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java similarity index 95% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java index b1eeb8274a..7ba06417c8 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java @@ -1,224 +1,224 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.ToStringUtils; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; - -import java.io.File; - -/** - * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 - * - * @author Daniel Qian - */ -public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { - - protected volatile String corpId; - protected volatile String corpSecret; - - protected volatile String token; - protected volatile String accessToken; - protected volatile String aesKey; - protected volatile Integer agentId; - protected volatile long expiresTime; - - protected volatile String oauth2redirectUri; - - protected volatile String httpProxyHost; - protected volatile int httpProxyPort; - protected volatile String httpProxyUsername; - protected volatile String httpProxyPassword; - - protected volatile String jsapiTicket; - protected volatile long jsapiTicketExpiresTime; - - protected volatile File tmpDirFile; - - private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; - - @Override - public String getAccessToken() { - return this.accessToken; - } - - public void setAccessToken(String accessToken) { - this.accessToken = accessToken; - } - - @Override - public boolean isAccessTokenExpired() { - return System.currentTimeMillis() > this.expiresTime; - } - - @Override - public void expireAccessToken() { - this.expiresTime = 0; - } - - @Override - public synchronized void updateAccessToken(WxAccessToken accessToken) { - updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - } - - @Override - public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { - this.accessToken = accessToken; - this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; - } - - @Override - public String getJsapiTicket() { - return this.jsapiTicket; - } - - public void setJsapiTicket(String jsapiTicket) { - this.jsapiTicket = jsapiTicket; - } - - public long getJsapiTicketExpiresTime() { - return this.jsapiTicketExpiresTime; - } - - public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) { - this.jsapiTicketExpiresTime = jsapiTicketExpiresTime; - } - - @Override - public boolean isJsapiTicketExpired() { - return System.currentTimeMillis() > this.jsapiTicketExpiresTime; - } - - @Override - public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { - this.jsapiTicket = jsapiTicket; - // 预留200秒的时间 - this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; - } - - @Override - public void expireJsapiTicket() { - this.jsapiTicketExpiresTime = 0; - } - - @Override - public String getCorpId() { - return this.corpId; - } - - public void setCorpId(String corpId) { - this.corpId = corpId; - } - - @Override - public String getCorpSecret() { - return this.corpSecret; - } - - public void setCorpSecret(String corpSecret) { - this.corpSecret = corpSecret; - } - - @Override - public String getToken() { - return this.token; - } - - public void setToken(String token) { - this.token = token; - } - - @Override - public long getExpiresTime() { - return this.expiresTime; - } - - public void setExpiresTime(long expiresTime) { - this.expiresTime = expiresTime; - } - - @Override - public String getAesKey() { - return this.aesKey; - } - - public void setAesKey(String aesKey) { - this.aesKey = aesKey; - } - - @Override - public Integer getAgentId() { - return this.agentId; - } - - public void setAgentId(Integer agentId) { - this.agentId = agentId; - } - - @Override - public String getOauth2redirectUri() { - return this.oauth2redirectUri; - } - - public void setOauth2redirectUri(String oauth2redirectUri) { - this.oauth2redirectUri = oauth2redirectUri; - } - - @Override - public String getHttpProxyHost() { - return this.httpProxyHost; - } - - public void setHttpProxyHost(String httpProxyHost) { - this.httpProxyHost = httpProxyHost; - } - - @Override - public int getHttpProxyPort() { - return this.httpProxyPort; - } - - public void setHttpProxyPort(int httpProxyPort) { - this.httpProxyPort = httpProxyPort; - } - - @Override - public String getHttpProxyUsername() { - return this.httpProxyUsername; - } - - public void setHttpProxyUsername(String httpProxyUsername) { - this.httpProxyUsername = httpProxyUsername; - } - - @Override - public String getHttpProxyPassword() { - return this.httpProxyPassword; - } - - public void setHttpProxyPassword(String httpProxyPassword) { - this.httpProxyPassword = httpProxyPassword; - } - - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - - @Override - public File getTmpDirFile() { - return this.tmpDirFile; - } - - public void setTmpDirFile(File tmpDirFile) { - this.tmpDirFile = tmpDirFile; - } - - @Override - public ApacheHttpClientBuilder getApacheHttpClientBuilder() { - return this.apacheHttpClientBuilder; - } - - public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { - this.apacheHttpClientBuilder = apacheHttpClientBuilder; - } -} +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + +import java.io.File; + +/** + * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 + * + * @author Daniel Qian + */ +public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { + + protected volatile String corpId; + protected volatile String corpSecret; + + protected volatile String token; + protected volatile String accessToken; + protected volatile String aesKey; + protected volatile Integer agentId; + protected volatile long expiresTime; + + protected volatile String oauth2redirectUri; + + protected volatile String httpProxyHost; + protected volatile int httpProxyPort; + protected volatile String httpProxyUsername; + protected volatile String httpProxyPassword; + + protected volatile String jsapiTicket; + protected volatile long jsapiTicketExpiresTime; + + protected volatile File tmpDirFile; + + private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + + @Override + public String getAccessToken() { + return this.accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + @Override + public boolean isAccessTokenExpired() { + return System.currentTimeMillis() > this.expiresTime; + } + + @Override + public void expireAccessToken() { + this.expiresTime = 0; + } + + @Override + public synchronized void updateAccessToken(WxAccessToken accessToken) { + updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + } + + @Override + public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { + this.accessToken = accessToken; + this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; + } + + @Override + public String getJsapiTicket() { + return this.jsapiTicket; + } + + public void setJsapiTicket(String jsapiTicket) { + this.jsapiTicket = jsapiTicket; + } + + public long getJsapiTicketExpiresTime() { + return this.jsapiTicketExpiresTime; + } + + public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) { + this.jsapiTicketExpiresTime = jsapiTicketExpiresTime; + } + + @Override + public boolean isJsapiTicketExpired() { + return System.currentTimeMillis() > this.jsapiTicketExpiresTime; + } + + @Override + public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { + this.jsapiTicket = jsapiTicket; + // 预留200秒的时间 + this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; + } + + @Override + public void expireJsapiTicket() { + this.jsapiTicketExpiresTime = 0; + } + + @Override + public String getCorpId() { + return this.corpId; + } + + public void setCorpId(String corpId) { + this.corpId = corpId; + } + + @Override + public String getCorpSecret() { + return this.corpSecret; + } + + public void setCorpSecret(String corpSecret) { + this.corpSecret = corpSecret; + } + + @Override + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public long getExpiresTime() { + return this.expiresTime; + } + + public void setExpiresTime(long expiresTime) { + this.expiresTime = expiresTime; + } + + @Override + public String getAesKey() { + return this.aesKey; + } + + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } + + @Override + public Integer getAgentId() { + return this.agentId; + } + + public void setAgentId(Integer agentId) { + this.agentId = agentId; + } + + @Override + public String getOauth2redirectUri() { + return this.oauth2redirectUri; + } + + public void setOauth2redirectUri(String oauth2redirectUri) { + this.oauth2redirectUri = oauth2redirectUri; + } + + @Override + public String getHttpProxyHost() { + return this.httpProxyHost; + } + + public void setHttpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + } + + @Override + public int getHttpProxyPort() { + return this.httpProxyPort; + } + + public void setHttpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + } + + @Override + public String getHttpProxyUsername() { + return this.httpProxyUsername; + } + + public void setHttpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + } + + @Override + public String getHttpProxyPassword() { + return this.httpProxyPassword; + } + + public void setHttpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + } + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + @Override + public File getTmpDirFile() { + return this.tmpDirFile; + } + + public void setTmpDirFile(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public ApacheHttpClientBuilder getApacheHttpClientBuilder() { + return this.apacheHttpClientBuilder; + } + + public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { + this.apacheHttpClientBuilder = apacheHttpClientBuilder; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java similarity index 96% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java index 25f5e2887b..f75188fece 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java @@ -1,269 +1,269 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.JedisPoolConfig; - -import java.io.File; - -/** - * Jedis client implementor for wechat config storage - * - * @author gaigeshen - */ -public class WxCpJedisConfigStorage implements WxCpConfigStorage { - - /* Redis keys here */ - private static final String ACCESS_TOKEN_KEY = "WX_CP_ACCESS_TOKEN"; - private static final String ACCESS_TOKEN_EXPIRES_TIME_KEY = "WX_CP_ACCESS_TOKEN_EXPIRES_TIME"; - private static final String JS_API_TICKET_KEY = "WX_CP_JS_API_TICKET"; - private static final String JS_API_TICKET_EXPIRES_TIME_KEY = "WX_CP_JS_API_TICKET_EXPIRES_TIME"; - /* Redis clients pool */ - private final JedisPool jedisPool; - private volatile String corpId; - private volatile String corpSecret; - private volatile String token; - private volatile String aesKey; - private volatile Integer agentId; - private volatile String oauth2redirectUri; - private volatile String httpProxyHost; - private volatile int httpProxyPort; - private volatile String httpProxyUsername; - private volatile String httpProxyPassword; - private volatile File tmpDirFile; - private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; - - public WxCpJedisConfigStorage(String host, int port) { - this.jedisPool = new JedisPool(host, port); - } - - - public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port) { - this.jedisPool = new JedisPool(poolConfig, host, port); - } - - public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, final String password) { - this.jedisPool = new JedisPool(poolConfig, host, port, timeout, password); - } - - /** - * This method will be destroy jedis pool - */ - public void destroy() { - this.jedisPool.destroy(); - } - - @Override - public String getAccessToken() { - try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.get(ACCESS_TOKEN_KEY); - } - } - - @Override - public boolean isAccessTokenExpired() { - try (Jedis jedis = this.jedisPool.getResource()) { - String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY); - - if (expiresTimeStr != null) { - Long expiresTime = Long.parseLong(expiresTimeStr); - return System.currentTimeMillis() > expiresTime; - } - - return true; - - } - } - - @Override - public void expireAccessToken() { - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY, "0"); - } - } - - @Override - public synchronized void updateAccessToken(WxAccessToken accessToken) { - this.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - } - - @Override - public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.set(ACCESS_TOKEN_KEY, accessToken); - - jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY, - (System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L) + ""); - } - } - - @Override - public String getJsapiTicket() { - try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.get(JS_API_TICKET_KEY); - } - } - - @Override - public boolean isJsapiTicketExpired() { - - try (Jedis jedis = this.jedisPool.getResource()) { - String expiresTimeStr = jedis.get(JS_API_TICKET_EXPIRES_TIME_KEY); - - if (expiresTimeStr != null) { - Long expiresTime = Long.parseLong(expiresTimeStr); - return System.currentTimeMillis() > expiresTime; - } - - return true; - - } - } - - @Override - public void expireJsapiTicket() { - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY, "0"); - } - } - - @Override - public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { - - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.set(JS_API_TICKET_KEY, jsapiTicket); - - jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY, - (System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L + "")); - } - - } - - @Override - public String getCorpId() { - return this.corpId; - } - - public void setCorpId(String corpId) { - this.corpId = corpId; - } - - @Override - public String getCorpSecret() { - return this.corpSecret; - } - - public void setCorpSecret(String corpSecret) { - this.corpSecret = corpSecret; - } - - @Override - public Integer getAgentId() { - return this.agentId; - } - - public void setAgentId(Integer agentId) { - this.agentId = agentId; - } - - @Override - public String getToken() { - return this.token; - } - - public void setToken(String token) { - this.token = token; - } - - @Override - public String getAesKey() { - return this.aesKey; - } - - public void setAesKey(String aesKey) { - this.aesKey = aesKey; - } - - @Override - public long getExpiresTime() { - try (Jedis jedis = this.jedisPool.getResource()) { - String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY); - - if (expiresTimeStr != null) { - Long expiresTime = Long.parseLong(expiresTimeStr); - return expiresTime; - } - - return 0L; - - } - } - - @Override - public String getOauth2redirectUri() { - return this.oauth2redirectUri; - } - - public void setOauth2redirectUri(String oauth2redirectUri) { - this.oauth2redirectUri = oauth2redirectUri; - } - - @Override - public String getHttpProxyHost() { - return this.httpProxyHost; - } - - public void setHttpProxyHost(String httpProxyHost) { - this.httpProxyHost = httpProxyHost; - } - - @Override - public int getHttpProxyPort() { - return this.httpProxyPort; - } - - public void setHttpProxyPort(int httpProxyPort) { - this.httpProxyPort = httpProxyPort; - } - - @Override - public String getHttpProxyUsername() { - return this.httpProxyUsername; - } - - // ============================ Setters below - - public void setHttpProxyUsername(String httpProxyUsername) { - this.httpProxyUsername = httpProxyUsername; - } - - @Override - public String getHttpProxyPassword() { - return this.httpProxyPassword; - } - - public void setHttpProxyPassword(String httpProxyPassword) { - this.httpProxyPassword = httpProxyPassword; - } - - @Override - public File getTmpDirFile() { - return this.tmpDirFile; - } - - public void setTmpDirFile(File tmpDirFile) { - this.tmpDirFile = tmpDirFile; - } - - @Override - public ApacheHttpClientBuilder getApacheHttpClientBuilder() { - return this.apacheHttpClientBuilder; - } - - public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { - this.apacheHttpClientBuilder = apacheHttpClientBuilder; - } - -} +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; + +import java.io.File; + +/** + * Jedis client implementor for wechat config storage + * + * @author gaigeshen + */ +public class WxCpJedisConfigStorage implements WxCpConfigStorage { + + /* Redis keys here */ + private static final String ACCESS_TOKEN_KEY = "WX_CP_ACCESS_TOKEN"; + private static final String ACCESS_TOKEN_EXPIRES_TIME_KEY = "WX_CP_ACCESS_TOKEN_EXPIRES_TIME"; + private static final String JS_API_TICKET_KEY = "WX_CP_JS_API_TICKET"; + private static final String JS_API_TICKET_EXPIRES_TIME_KEY = "WX_CP_JS_API_TICKET_EXPIRES_TIME"; + /* Redis clients pool */ + private final JedisPool jedisPool; + private volatile String corpId; + private volatile String corpSecret; + private volatile String token; + private volatile String aesKey; + private volatile Integer agentId; + private volatile String oauth2redirectUri; + private volatile String httpProxyHost; + private volatile int httpProxyPort; + private volatile String httpProxyUsername; + private volatile String httpProxyPassword; + private volatile File tmpDirFile; + private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + + public WxCpJedisConfigStorage(String host, int port) { + this.jedisPool = new JedisPool(host, port); + } + + + public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port) { + this.jedisPool = new JedisPool(poolConfig, host, port); + } + + public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, final String password) { + this.jedisPool = new JedisPool(poolConfig, host, port, timeout, password); + } + + /** + * This method will be destroy jedis pool + */ + public void destroy() { + this.jedisPool.destroy(); + } + + @Override + public String getAccessToken() { + try (Jedis jedis = this.jedisPool.getResource()) { + return jedis.get(ACCESS_TOKEN_KEY); + } + } + + @Override + public boolean isAccessTokenExpired() { + try (Jedis jedis = this.jedisPool.getResource()) { + String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY); + + if (expiresTimeStr != null) { + Long expiresTime = Long.parseLong(expiresTimeStr); + return System.currentTimeMillis() > expiresTime; + } + + return true; + + } + } + + @Override + public void expireAccessToken() { + try (Jedis jedis = this.jedisPool.getResource()) { + jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY, "0"); + } + } + + @Override + public synchronized void updateAccessToken(WxAccessToken accessToken) { + this.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + } + + @Override + public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { + try (Jedis jedis = this.jedisPool.getResource()) { + jedis.set(ACCESS_TOKEN_KEY, accessToken); + + jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY, + (System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L) + ""); + } + } + + @Override + public String getJsapiTicket() { + try (Jedis jedis = this.jedisPool.getResource()) { + return jedis.get(JS_API_TICKET_KEY); + } + } + + @Override + public boolean isJsapiTicketExpired() { + + try (Jedis jedis = this.jedisPool.getResource()) { + String expiresTimeStr = jedis.get(JS_API_TICKET_EXPIRES_TIME_KEY); + + if (expiresTimeStr != null) { + Long expiresTime = Long.parseLong(expiresTimeStr); + return System.currentTimeMillis() > expiresTime; + } + + return true; + + } + } + + @Override + public void expireJsapiTicket() { + try (Jedis jedis = this.jedisPool.getResource()) { + jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY, "0"); + } + } + + @Override + public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { + + try (Jedis jedis = this.jedisPool.getResource()) { + jedis.set(JS_API_TICKET_KEY, jsapiTicket); + + jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY, + (System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L + "")); + } + + } + + @Override + public String getCorpId() { + return this.corpId; + } + + public void setCorpId(String corpId) { + this.corpId = corpId; + } + + @Override + public String getCorpSecret() { + return this.corpSecret; + } + + public void setCorpSecret(String corpSecret) { + this.corpSecret = corpSecret; + } + + @Override + public Integer getAgentId() { + return this.agentId; + } + + public void setAgentId(Integer agentId) { + this.agentId = agentId; + } + + @Override + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public String getAesKey() { + return this.aesKey; + } + + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } + + @Override + public long getExpiresTime() { + try (Jedis jedis = this.jedisPool.getResource()) { + String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY); + + if (expiresTimeStr != null) { + Long expiresTime = Long.parseLong(expiresTimeStr); + return expiresTime; + } + + return 0L; + + } + } + + @Override + public String getOauth2redirectUri() { + return this.oauth2redirectUri; + } + + public void setOauth2redirectUri(String oauth2redirectUri) { + this.oauth2redirectUri = oauth2redirectUri; + } + + @Override + public String getHttpProxyHost() { + return this.httpProxyHost; + } + + public void setHttpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + } + + @Override + public int getHttpProxyPort() { + return this.httpProxyPort; + } + + public void setHttpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + } + + @Override + public String getHttpProxyUsername() { + return this.httpProxyUsername; + } + + // ============================ Setters below + + public void setHttpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + } + + @Override + public String getHttpProxyPassword() { + return this.httpProxyPassword; + } + + public void setHttpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + } + + @Override + public File getTmpDirFile() { + return this.tmpDirFile; + } + + public void setTmpDirFile(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public ApacheHttpClientBuilder getApacheHttpClientBuilder() { + return this.apacheHttpClientBuilder; + } + + public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { + this.apacheHttpClientBuilder = apacheHttpClientBuilder; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageHandler.java similarity index 96% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageHandler.java index 9a3920a285..907557f5cc 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageHandler.java @@ -1,29 +1,29 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; - -import java.util.Map; - -/** - * 处理微信推送消息的处理器接口 - * - * @author Daniel Qian - */ -public interface WxCpMessageHandler { - - /** - * @param wxMessage - * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 - * @param wxCpService - * @param sessionManager - * @return xml格式的消息,如果在异步规则里处理的话,可以返回null - */ - WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, - Map context, - WxCpService wxCpService, - WxSessionManager sessionManager) throws WxErrorException; - -} +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; + +import java.util.Map; + +/** + * 处理微信推送消息的处理器接口 + * + * @author Daniel Qian + */ +public interface WxCpMessageHandler { + + /** + * @param wxMessage + * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @param wxCpService + * @param sessionManager + * @return xml格式的消息,如果在异步规则里处理的话,可以返回null + */ + WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, + Map context, + WxCpService wxCpService, + WxSessionManager sessionManager) throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageInterceptor.java similarity index 96% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageInterceptor.java index e6de0e69f4..3c673523f4 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageInterceptor.java @@ -1,30 +1,30 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; - -import java.util.Map; - -/** - * 微信消息拦截器,可以用来做验证 - * - * @author Daniel Qian - */ -public interface WxCpMessageInterceptor { - - /** - * 拦截微信消息 - * - * @param wxMessage - * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 - * @param wxCpService - * @param sessionManager - * @return true代表OK,false代表不OK - */ - boolean intercept(WxCpXmlMessage wxMessage, - Map context, - WxCpService wxCpService, - WxSessionManager sessionManager) throws WxErrorException; - -} +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; + +import java.util.Map; + +/** + * 微信消息拦截器,可以用来做验证 + * + * @author Daniel Qian + */ +public interface WxCpMessageInterceptor { + + /** + * 拦截微信消息 + * + * @param wxMessage + * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @param wxCpService + * @param sessionManager + * @return true代表OK,false代表不OK + */ + boolean intercept(WxCpXmlMessage wxMessage, + Map context, + WxCpService wxCpService, + WxSessionManager sessionManager) throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageMatcher.java similarity index 94% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageMatcher.java index c2c62b9361..666e689b92 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageMatcher.java @@ -1,15 +1,15 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; - -/** - * 消息匹配器,用在消息路由的时候 - */ -public interface WxCpMessageMatcher { - - /** - * 消息是否匹配某种模式 - */ - boolean match(WxCpXmlMessage message); - -} +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; + +/** + * 消息匹配器,用在消息路由的时候 + */ +public interface WxCpMessageMatcher { + + /** + * 消息是否匹配某种模式 + */ + boolean match(WxCpXmlMessage message); + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java similarity index 96% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java index 823280107c..2a3785c24a 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java @@ -1,249 +1,249 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.api.WxErrorExceptionHandler; -import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; -import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; -import me.chanjar.weixin.common.session.InternalSession; -import me.chanjar.weixin.common.session.InternalSessionManager; -import me.chanjar.weixin.common.session.StandardSessionManager; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.util.LogExceptionHandler; -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -/** - *
- * 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理
- *
- * 说明:
- * 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理
- * 2. 默认情况下消息只会被处理一次,除非使用 {@link WxCpMessageRouterRule#next()}
- * 3. 规则的结束必须用{@link WxCpMessageRouterRule#end()}或者{@link WxCpMessageRouterRule#next()},否则不会生效
- *
- * 使用方法:
- * WxCpMessageRouter router = new WxCpMessageRouter();
- * router
- *   .rule()
- *       .msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT")
- *       .interceptor(interceptor, ...).handler(handler, ...)
- *   .end()
- *   .rule()
- *       // 另外一个匹配规则
- *   .end()
- * ;
- *
- * // 将WxXmlMessage交给消息路由器
- * router.route(message);
- *
- * 
- * - * @author Daniel Qian - */ -public class WxCpMessageRouter { - - private static final int DEFAULT_THREAD_POOL_SIZE = 100; - protected final Logger log = LoggerFactory.getLogger(WxCpMessageRouter.class); - private final List rules = new ArrayList<>(); - - private final WxCpService wxCpService; - - private ExecutorService executorService; - - private WxMessageDuplicateChecker messageDuplicateChecker; - - private WxSessionManager sessionManager; - - private WxErrorExceptionHandler exceptionHandler; - - public WxCpMessageRouter(WxCpService wxCpService) { - this.wxCpService = wxCpService; - this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); - this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); - this.sessionManager = new StandardSessionManager(); - this.exceptionHandler = new LogExceptionHandler(); - } - - /** - *
-   * 设置自定义的 {@link ExecutorService}
-   * 如果不调用该方法,默认使用 Executors.newFixedThreadPool(100)
-   * 
- * - * @param executorService - */ - public void setExecutorService(ExecutorService executorService) { - this.executorService = executorService; - } - - /** - *
-   * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker}
-   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker}
-   * 
- * - * @param messageDuplicateChecker - */ - public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { - this.messageDuplicateChecker = messageDuplicateChecker; - } - - /** - *
-   * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager}
-   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager}
-   * 
- * - * @param sessionManager - */ - public void setSessionManager(WxSessionManager sessionManager) { - this.sessionManager = sessionManager; - } - - /** - *
-   * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler}
-   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler}
-   * 
- * - * @param exceptionHandler - */ - public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { - this.exceptionHandler = exceptionHandler; - } - - List getRules() { - return this.rules; - } - - /** - * 开始一个新的Route规则 - */ - public WxCpMessageRouterRule rule() { - return new WxCpMessageRouterRule(this); - } - - /** - * 处理微信消息 - * - * @param wxMessage - * @param context - */ - public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage, final Map context) { - if (isDuplicateMessage(wxMessage)) { - // 如果是重复消息,那么就不做处理 - return null; - } - - final List matchRules = new ArrayList<>(); - // 收集匹配的规则 - for (final WxCpMessageRouterRule rule : this.rules) { - if (rule.test(wxMessage)) { - matchRules.add(rule); - if (!rule.isReEnter()) { - break; - } - } - } - - if (matchRules.size() == 0) { - return null; - } - - WxCpXmlOutMessage res = null; - final List futures = new ArrayList<>(); - for (final WxCpMessageRouterRule rule : matchRules) { - // 返回最后一个非异步的rule的执行结果 - if (rule.isAsync()) { - futures.add( - this.executorService.submit(new Runnable() { - @Override - public void run() { - rule.service(wxMessage, context, WxCpMessageRouter.this.wxCpService, WxCpMessageRouter.this.sessionManager, WxCpMessageRouter.this.exceptionHandler); - } - }) - ); - } else { - res = rule.service(wxMessage, context, this.wxCpService, this.sessionManager, this.exceptionHandler); - // 在同步操作结束,session访问结束 - this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUserName()); - sessionEndAccess(wxMessage); - } - } - - if (futures.size() > 0) { - this.executorService.submit(new Runnable() { - @Override - public void run() { - for (Future future : futures) { - try { - future.get(); - WxCpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUserName()); - // 异步操作结束,session访问结束 - sessionEndAccess(wxMessage); - } catch (InterruptedException e) { - WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); - } catch (ExecutionException e) { - WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); - } - } - } - }); - } - return res; - } - - - /** - * 处理微信消息 - * - * @param wxMessage - */ - public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) { - return this.route(wxMessage, new HashMap()); - } - - protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) { - - String messageId = ""; - if (wxMessage.getMsgId() == null) { - messageId = String.valueOf(wxMessage.getCreateTime()) - + "-" + String.valueOf(wxMessage.getAgentId() == null ? "" : wxMessage.getAgentId()) - + "-" + wxMessage.getFromUserName() - + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey()) - + "-" + String.valueOf(wxMessage.getEvent() == null ? "" : wxMessage.getEvent()) - ; - } else { - messageId = String.valueOf(wxMessage.getMsgId()); - } - - return this.messageDuplicateChecker.isDuplicate(messageId); - - } - - /** - * 对session的访问结束 - * - * @param wxMessage - */ - protected void sessionEndAccess(WxCpXmlMessage wxMessage) { - - InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUserName()); - if (session != null) { - session.endAccess(); - } - - } - - -} +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; +import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; +import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; +import me.chanjar.weixin.common.session.InternalSession; +import me.chanjar.weixin.common.session.InternalSessionManager; +import me.chanjar.weixin.common.session.StandardSessionManager; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.LogExceptionHandler; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + *
+ * 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理
+ *
+ * 说明:
+ * 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理
+ * 2. 默认情况下消息只会被处理一次,除非使用 {@link WxCpMessageRouterRule#next()}
+ * 3. 规则的结束必须用{@link WxCpMessageRouterRule#end()}或者{@link WxCpMessageRouterRule#next()},否则不会生效
+ *
+ * 使用方法:
+ * WxCpMessageRouter router = new WxCpMessageRouter();
+ * router
+ *   .rule()
+ *       .msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT")
+ *       .interceptor(interceptor, ...).handler(handler, ...)
+ *   .end()
+ *   .rule()
+ *       // 另外一个匹配规则
+ *   .end()
+ * ;
+ *
+ * // 将WxXmlMessage交给消息路由器
+ * router.route(message);
+ *
+ * 
+ * + * @author Daniel Qian + */ +public class WxCpMessageRouter { + + private static final int DEFAULT_THREAD_POOL_SIZE = 100; + protected final Logger log = LoggerFactory.getLogger(WxCpMessageRouter.class); + private final List rules = new ArrayList<>(); + + private final WxCpService wxCpService; + + private ExecutorService executorService; + + private WxMessageDuplicateChecker messageDuplicateChecker; + + private WxSessionManager sessionManager; + + private WxErrorExceptionHandler exceptionHandler; + + public WxCpMessageRouter(WxCpService wxCpService) { + this.wxCpService = wxCpService; + this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); + this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); + this.sessionManager = new StandardSessionManager(); + this.exceptionHandler = new LogExceptionHandler(); + } + + /** + *
+   * 设置自定义的 {@link ExecutorService}
+   * 如果不调用该方法,默认使用 Executors.newFixedThreadPool(100)
+   * 
+ * + * @param executorService + */ + public void setExecutorService(ExecutorService executorService) { + this.executorService = executorService; + } + + /** + *
+   * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker}
+   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker}
+   * 
+ * + * @param messageDuplicateChecker + */ + public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { + this.messageDuplicateChecker = messageDuplicateChecker; + } + + /** + *
+   * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager}
+   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager}
+   * 
+ * + * @param sessionManager + */ + public void setSessionManager(WxSessionManager sessionManager) { + this.sessionManager = sessionManager; + } + + /** + *
+   * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler}
+   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler}
+   * 
+ * + * @param exceptionHandler + */ + public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + + List getRules() { + return this.rules; + } + + /** + * 开始一个新的Route规则 + */ + public WxCpMessageRouterRule rule() { + return new WxCpMessageRouterRule(this); + } + + /** + * 处理微信消息 + * + * @param wxMessage + * @param context + */ + public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage, final Map context) { + if (isDuplicateMessage(wxMessage)) { + // 如果是重复消息,那么就不做处理 + return null; + } + + final List matchRules = new ArrayList<>(); + // 收集匹配的规则 + for (final WxCpMessageRouterRule rule : this.rules) { + if (rule.test(wxMessage)) { + matchRules.add(rule); + if (!rule.isReEnter()) { + break; + } + } + } + + if (matchRules.size() == 0) { + return null; + } + + WxCpXmlOutMessage res = null; + final List futures = new ArrayList<>(); + for (final WxCpMessageRouterRule rule : matchRules) { + // 返回最后一个非异步的rule的执行结果 + if (rule.isAsync()) { + futures.add( + this.executorService.submit(new Runnable() { + @Override + public void run() { + rule.service(wxMessage, context, WxCpMessageRouter.this.wxCpService, WxCpMessageRouter.this.sessionManager, WxCpMessageRouter.this.exceptionHandler); + } + }) + ); + } else { + res = rule.service(wxMessage, context, this.wxCpService, this.sessionManager, this.exceptionHandler); + // 在同步操作结束,session访问结束 + this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUserName()); + sessionEndAccess(wxMessage); + } + } + + if (futures.size() > 0) { + this.executorService.submit(new Runnable() { + @Override + public void run() { + for (Future future : futures) { + try { + future.get(); + WxCpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUserName()); + // 异步操作结束,session访问结束 + sessionEndAccess(wxMessage); + } catch (InterruptedException e) { + WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); + } catch (ExecutionException e) { + WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); + } + } + } + }); + } + return res; + } + + + /** + * 处理微信消息 + * + * @param wxMessage + */ + public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) { + return this.route(wxMessage, new HashMap()); + } + + protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) { + + String messageId = ""; + if (wxMessage.getMsgId() == null) { + messageId = String.valueOf(wxMessage.getCreateTime()) + + "-" + String.valueOf(wxMessage.getAgentId() == null ? "" : wxMessage.getAgentId()) + + "-" + wxMessage.getFromUserName() + + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey()) + + "-" + String.valueOf(wxMessage.getEvent() == null ? "" : wxMessage.getEvent()) + ; + } else { + messageId = String.valueOf(wxMessage.getMsgId()); + } + + return this.messageDuplicateChecker.isDuplicate(messageId); + + } + + /** + * 对session的访问结束 + * + * @param wxMessage + */ + protected void sessionEndAccess(WxCpXmlMessage wxMessage) { + + InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUserName()); + if (session != null) { + session.endAccess(); + } + + } + + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java similarity index 95% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java index aa4fe504a0..3c0921132c 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java @@ -1,321 +1,321 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.api.WxErrorExceptionHandler; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -public class WxCpMessageRouterRule { - - private final WxCpMessageRouter routerBuilder; - - private boolean async = true; - - private String fromUser; - - private String msgType; - - private String event; - - private String eventKey; - - private String content; - - private String rContent; - - private WxCpMessageMatcher matcher; - - private boolean reEnter = false; - - private Integer agentId; - - private List handlers = new ArrayList<>(); - - private List interceptors = new ArrayList<>(); - - protected WxCpMessageRouterRule(WxCpMessageRouter routerBuilder) { - this.routerBuilder = routerBuilder; - } - - /** - * 设置是否异步执行,默认是true - * - * @param async - */ - public WxCpMessageRouterRule async(boolean async) { - this.async = async; - return this; - } - - /** - * 如果agentId匹配 - * - * @param agentId - */ - public WxCpMessageRouterRule agentId(Integer agentId) { - this.agentId = agentId; - return this; - } - - /** - * 如果msgType等于某值 - * - * @param msgType - */ - public WxCpMessageRouterRule msgType(String msgType) { - this.msgType = msgType; - return this; - } - - /** - * 如果event等于某值 - * - * @param event - */ - public WxCpMessageRouterRule event(String event) { - this.event = event; - return this; - } - - /** - * 如果eventKey等于某值 - * - * @param eventKey - */ - public WxCpMessageRouterRule eventKey(String eventKey) { - this.eventKey = eventKey; - return this; - } - - /** - * 如果content等于某值 - * - * @param content - */ - public WxCpMessageRouterRule content(String content) { - this.content = content; - return this; - } - - /** - * 如果content匹配该正则表达式 - * - * @param regex - */ - public WxCpMessageRouterRule rContent(String regex) { - this.rContent = regex; - return this; - } - - /** - * 如果fromUser等于某值 - * - * @param fromUser - */ - public WxCpMessageRouterRule fromUser(String fromUser) { - this.fromUser = fromUser; - return this; - } - - /** - * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 - * - * @param matcher - */ - public WxCpMessageRouterRule matcher(WxCpMessageMatcher matcher) { - this.matcher = matcher; - return this; - } - - /** - * 设置微信消息拦截器 - * - * @param interceptor - */ - public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor) { - return interceptor(interceptor, (WxCpMessageInterceptor[]) null); - } - - /** - * 设置微信消息拦截器 - * - * @param interceptor - * @param otherInterceptors - */ - public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) { - this.interceptors.add(interceptor); - if (otherInterceptors != null && otherInterceptors.length > 0) { - for (WxCpMessageInterceptor i : otherInterceptors) { - this.interceptors.add(i); - } - } - return this; - } - - /** - * 设置微信消息处理器 - * - * @param handler - */ - public WxCpMessageRouterRule handler(WxCpMessageHandler handler) { - return handler(handler, (WxCpMessageHandler[]) null); - } - - /** - * 设置微信消息处理器 - * - * @param handler - * @param otherHandlers - */ - public WxCpMessageRouterRule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) { - this.handlers.add(handler); - if (otherHandlers != null && otherHandlers.length > 0) { - for (WxCpMessageHandler i : otherHandlers) { - this.handlers.add(i); - } - } - return this; - } - - /** - * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 - */ - public WxCpMessageRouter end() { - this.routerBuilder.getRules().add(this); - return this.routerBuilder; - } - - /** - * 规则结束,但是消息还会进入其他规则 - */ - public WxCpMessageRouter next() { - this.reEnter = true; - return end(); - } - - protected boolean test(WxCpXmlMessage wxMessage) { - return - (this.fromUser == null || this.fromUser.equals(wxMessage.getFromUserName())) - && - (this.agentId == null || this.agentId.equals(wxMessage.getAgentId())) - && - (this.msgType == null || this.msgType.equals(wxMessage.getMsgType())) - && - (this.event == null || this.event.equals(wxMessage.getEvent())) - && - (this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey())) - && - (this.content == null || this.content - .equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) - && - (this.rContent == null || Pattern - .matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) - && - (this.matcher == null || this.matcher.match(wxMessage)) - ; - } - - /** - * 处理微信推送过来的消息 - * - * @param wxMessage - * @return true 代表继续执行别的router,false 代表停止执行别的router - */ - protected WxCpXmlOutMessage service(WxCpXmlMessage wxMessage, - Map context, - WxCpService wxCpService, - WxSessionManager sessionManager, - WxErrorExceptionHandler exceptionHandler) { - - if (context == null) { - context = new HashMap<>(); - } - - try { - // 如果拦截器不通过 - for (WxCpMessageInterceptor interceptor : this.interceptors) { - if (!interceptor.intercept(wxMessage, context, wxCpService, sessionManager)) { - return null; - } - } - - // 交给handler处理 - WxCpXmlOutMessage res = null; - for (WxCpMessageHandler handler : this.handlers) { - // 返回最后handler的结果 - res = handler.handle(wxMessage, context, wxCpService, sessionManager); - } - return res; - - } catch (WxErrorException e) { - exceptionHandler.handle(e); - } - - return null; - - } - - public void setFromUser(String fromUser) { - this.fromUser = fromUser; - } - - public void setMsgType(String msgType) { - this.msgType = msgType; - } - - public void setEvent(String event) { - this.event = event; - } - - public void setEventKey(String eventKey) { - this.eventKey = eventKey; - } - - public void setContent(String content) { - this.content = content; - } - - public void setrContent(String rContent) { - this.rContent = rContent; - } - - public void setMatcher(WxCpMessageMatcher matcher) { - this.matcher = matcher; - } - - public void setAgentId(Integer agentId) { - this.agentId = agentId; - } - - public void setHandlers(List handlers) { - this.handlers = handlers; - } - - public void setInterceptors(List interceptors) { - this.interceptors = interceptors; - } - - public boolean isAsync() { - return this.async; - } - - public void setAsync(boolean async) { - this.async = async; - } - - public boolean isReEnter() { - return this.reEnter; - } - - public void setReEnter(boolean reEnter) { - this.reEnter = reEnter; - } - -} +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +public class WxCpMessageRouterRule { + + private final WxCpMessageRouter routerBuilder; + + private boolean async = true; + + private String fromUser; + + private String msgType; + + private String event; + + private String eventKey; + + private String content; + + private String rContent; + + private WxCpMessageMatcher matcher; + + private boolean reEnter = false; + + private Integer agentId; + + private List handlers = new ArrayList<>(); + + private List interceptors = new ArrayList<>(); + + protected WxCpMessageRouterRule(WxCpMessageRouter routerBuilder) { + this.routerBuilder = routerBuilder; + } + + /** + * 设置是否异步执行,默认是true + * + * @param async + */ + public WxCpMessageRouterRule async(boolean async) { + this.async = async; + return this; + } + + /** + * 如果agentId匹配 + * + * @param agentId + */ + public WxCpMessageRouterRule agentId(Integer agentId) { + this.agentId = agentId; + return this; + } + + /** + * 如果msgType等于某值 + * + * @param msgType + */ + public WxCpMessageRouterRule msgType(String msgType) { + this.msgType = msgType; + return this; + } + + /** + * 如果event等于某值 + * + * @param event + */ + public WxCpMessageRouterRule event(String event) { + this.event = event; + return this; + } + + /** + * 如果eventKey等于某值 + * + * @param eventKey + */ + public WxCpMessageRouterRule eventKey(String eventKey) { + this.eventKey = eventKey; + return this; + } + + /** + * 如果content等于某值 + * + * @param content + */ + public WxCpMessageRouterRule content(String content) { + this.content = content; + return this; + } + + /** + * 如果content匹配该正则表达式 + * + * @param regex + */ + public WxCpMessageRouterRule rContent(String regex) { + this.rContent = regex; + return this; + } + + /** + * 如果fromUser等于某值 + * + * @param fromUser + */ + public WxCpMessageRouterRule fromUser(String fromUser) { + this.fromUser = fromUser; + return this; + } + + /** + * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 + * + * @param matcher + */ + public WxCpMessageRouterRule matcher(WxCpMessageMatcher matcher) { + this.matcher = matcher; + return this; + } + + /** + * 设置微信消息拦截器 + * + * @param interceptor + */ + public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor) { + return interceptor(interceptor, (WxCpMessageInterceptor[]) null); + } + + /** + * 设置微信消息拦截器 + * + * @param interceptor + * @param otherInterceptors + */ + public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) { + this.interceptors.add(interceptor); + if (otherInterceptors != null && otherInterceptors.length > 0) { + for (WxCpMessageInterceptor i : otherInterceptors) { + this.interceptors.add(i); + } + } + return this; + } + + /** + * 设置微信消息处理器 + * + * @param handler + */ + public WxCpMessageRouterRule handler(WxCpMessageHandler handler) { + return handler(handler, (WxCpMessageHandler[]) null); + } + + /** + * 设置微信消息处理器 + * + * @param handler + * @param otherHandlers + */ + public WxCpMessageRouterRule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) { + this.handlers.add(handler); + if (otherHandlers != null && otherHandlers.length > 0) { + for (WxCpMessageHandler i : otherHandlers) { + this.handlers.add(i); + } + } + return this; + } + + /** + * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 + */ + public WxCpMessageRouter end() { + this.routerBuilder.getRules().add(this); + return this.routerBuilder; + } + + /** + * 规则结束,但是消息还会进入其他规则 + */ + public WxCpMessageRouter next() { + this.reEnter = true; + return end(); + } + + protected boolean test(WxCpXmlMessage wxMessage) { + return + (this.fromUser == null || this.fromUser.equals(wxMessage.getFromUserName())) + && + (this.agentId == null || this.agentId.equals(wxMessage.getAgentId())) + && + (this.msgType == null || this.msgType.equals(wxMessage.getMsgType())) + && + (this.event == null || this.event.equals(wxMessage.getEvent())) + && + (this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey())) + && + (this.content == null || this.content + .equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) + && + (this.rContent == null || Pattern + .matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) + && + (this.matcher == null || this.matcher.match(wxMessage)) + ; + } + + /** + * 处理微信推送过来的消息 + * + * @param wxMessage + * @return true 代表继续执行别的router,false 代表停止执行别的router + */ + protected WxCpXmlOutMessage service(WxCpXmlMessage wxMessage, + Map context, + WxCpService wxCpService, + WxSessionManager sessionManager, + WxErrorExceptionHandler exceptionHandler) { + + if (context == null) { + context = new HashMap<>(); + } + + try { + // 如果拦截器不通过 + for (WxCpMessageInterceptor interceptor : this.interceptors) { + if (!interceptor.intercept(wxMessage, context, wxCpService, sessionManager)) { + return null; + } + } + + // 交给handler处理 + WxCpXmlOutMessage res = null; + for (WxCpMessageHandler handler : this.handlers) { + // 返回最后handler的结果 + res = handler.handle(wxMessage, context, wxCpService, sessionManager); + } + return res; + + } catch (WxErrorException e) { + exceptionHandler.handle(e); + } + + return null; + + } + + public void setFromUser(String fromUser) { + this.fromUser = fromUser; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public void setEvent(String event) { + this.event = event; + } + + public void setEventKey(String eventKey) { + this.eventKey = eventKey; + } + + public void setContent(String content) { + this.content = content; + } + + public void setrContent(String rContent) { + this.rContent = rContent; + } + + public void setMatcher(WxCpMessageMatcher matcher) { + this.matcher = matcher; + } + + public void setAgentId(Integer agentId) { + this.agentId = agentId; + } + + public void setHandlers(List handlers) { + this.handlers = handlers; + } + + public void setInterceptors(List interceptors) { + this.interceptors = interceptors; + } + + public boolean isAsync() { + return this.async; + } + + public void setAsync(boolean async) { + this.async = async; + } + + public boolean isReEnter() { + return this.reEnter; + } + + public void setReEnter(boolean reEnter) { + this.reEnter = reEnter; + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java deleted file mode 100644 index 66db0ff36a..0000000000 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java +++ /dev/null @@ -1,67 +0,0 @@ -package me.chanjar.weixin.cp.api; - -import com.google.inject.Inject; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; -import me.chanjar.weixin.cp.bean.WxCpDepart; -import org.testng.Assert; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import java.util.List; - -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - -/** - * 测试部门接口 - * - * @author Daniel Qian - */ -@Test(groups = "departAPI") -@Guice(modules = ApiTestModule.class) -public class WxCpDepartAPITest { - - @Inject - protected WxCpServiceImpl wxCpService; - - protected WxCpDepart depart; - - @Test - public void testDepartCreate() throws WxErrorException { - WxCpDepart cpDepart = new WxCpDepart(); - cpDepart.setName("子部门" + System.currentTimeMillis()); - cpDepart.setParentId(1); - cpDepart.setOrder(1); - Integer departId = this.wxCpService.departCreate(cpDepart); - System.out.println(departId); - } - - @Test//(dependsOnMethods = "testDepartCreate") - public void testDepartGet() throws WxErrorException { - System.out.println("=================获取部门"); - List departList = this.wxCpService.departGet(); - assertNotNull(departList); - assertTrue(departList.size() > 0); - for (WxCpDepart g : departList) { - this.depart = g; - System.out.println(this.depart.getId() + ":" + this.depart.getName()); - assertNotNull(g.getName()); - } - } - - @Test(dependsOnMethods = {"testDepartGet", "testDepartCreate"}) - public void testDepartUpdate() throws WxErrorException { - System.out.println("=================更新部门"); - this.depart.setName("子部门改名" + System.currentTimeMillis()); - this.wxCpService.departUpdate(this.depart); - } - - @Test(dependsOnMethods = "testDepartUpdate") - public void testDepartDelete() throws WxErrorException { - System.out.println("=================删除部门"); - System.out.println(this.depart.getId() + ":" + this.depart.getName()); - this.wxCpService.departDelete(this.depart.getId()); - } - -} From 899d03786c49c742e79842ba6d36414c9bac31c9 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 24 Jun 2017 22:08:08 +0800 Subject: [PATCH 099/179] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=8F=B7message=E7=9B=B8=E5=85=B3=E7=B1=BB=E7=9A=84=E5=8C=85?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/message/WxCpMessageHandler.java | 59 +- .../cp/message/WxCpMessageInterceptor.java | 61 +- .../weixin/cp/message/WxCpMessageMatcher.java | 30 +- .../weixin/cp/message/WxCpMessageRouter.java | 499 +++++++------- .../cp/message/WxCpMessageRouterRule.java | 643 +++++++++--------- 5 files changed, 648 insertions(+), 644 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageHandler.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageHandler.java index 907557f5cc..615fa8f220 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageHandler.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageHandler.java @@ -1,29 +1,30 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; - -import java.util.Map; - -/** - * 处理微信推送消息的处理器接口 - * - * @author Daniel Qian - */ -public interface WxCpMessageHandler { - - /** - * @param wxMessage - * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 - * @param wxCpService - * @param sessionManager - * @return xml格式的消息,如果在异步规则里处理的话,可以返回null - */ - WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, - Map context, - WxCpService wxCpService, - WxSessionManager sessionManager) throws WxErrorException; - -} +package me.chanjar.weixin.cp.message; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; + +import java.util.Map; + +/** + * 处理微信推送消息的处理器接口 + * + * @author Daniel Qian + */ +public interface WxCpMessageHandler { + + /** + * @param wxMessage + * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @param wxCpService + * @param sessionManager + * @return xml格式的消息,如果在异步规则里处理的话,可以返回null + */ + WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, + Map context, + WxCpService wxCpService, + WxSessionManager sessionManager) throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageInterceptor.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageInterceptor.java index 3c673523f4..21abb5cdb4 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageInterceptor.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageInterceptor.java @@ -1,30 +1,31 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; - -import java.util.Map; - -/** - * 微信消息拦截器,可以用来做验证 - * - * @author Daniel Qian - */ -public interface WxCpMessageInterceptor { - - /** - * 拦截微信消息 - * - * @param wxMessage - * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 - * @param wxCpService - * @param sessionManager - * @return true代表OK,false代表不OK - */ - boolean intercept(WxCpXmlMessage wxMessage, - Map context, - WxCpService wxCpService, - WxSessionManager sessionManager) throws WxErrorException; - -} +package me.chanjar.weixin.cp.message; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; + +import java.util.Map; + +/** + * 微信消息拦截器,可以用来做验证 + * + * @author Daniel Qian + */ +public interface WxCpMessageInterceptor { + + /** + * 拦截微信消息 + * + * @param wxMessage + * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @param wxCpService + * @param sessionManager + * @return true代表OK,false代表不OK + */ + boolean intercept(WxCpXmlMessage wxMessage, + Map context, + WxCpService wxCpService, + WxSessionManager sessionManager) throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageMatcher.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageMatcher.java index 666e689b92..1bf36705b7 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageMatcher.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageMatcher.java @@ -1,15 +1,15 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; - -/** - * 消息匹配器,用在消息路由的时候 - */ -public interface WxCpMessageMatcher { - - /** - * 消息是否匹配某种模式 - */ - boolean match(WxCpXmlMessage message); - -} +package me.chanjar.weixin.cp.message; + +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; + +/** + * 消息匹配器,用在消息路由的时候 + */ +public interface WxCpMessageMatcher { + + /** + * 消息是否匹配某种模式 + */ + boolean match(WxCpXmlMessage message); + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java index 2a3785c24a..3c53d26106 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java @@ -1,249 +1,250 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.api.WxErrorExceptionHandler; -import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; -import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; -import me.chanjar.weixin.common.session.InternalSession; -import me.chanjar.weixin.common.session.InternalSessionManager; -import me.chanjar.weixin.common.session.StandardSessionManager; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.util.LogExceptionHandler; -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -/** - *
- * 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理
- *
- * 说明:
- * 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理
- * 2. 默认情况下消息只会被处理一次,除非使用 {@link WxCpMessageRouterRule#next()}
- * 3. 规则的结束必须用{@link WxCpMessageRouterRule#end()}或者{@link WxCpMessageRouterRule#next()},否则不会生效
- *
- * 使用方法:
- * WxCpMessageRouter router = new WxCpMessageRouter();
- * router
- *   .rule()
- *       .msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT")
- *       .interceptor(interceptor, ...).handler(handler, ...)
- *   .end()
- *   .rule()
- *       // 另外一个匹配规则
- *   .end()
- * ;
- *
- * // 将WxXmlMessage交给消息路由器
- * router.route(message);
- *
- * 
- * - * @author Daniel Qian - */ -public class WxCpMessageRouter { - - private static final int DEFAULT_THREAD_POOL_SIZE = 100; - protected final Logger log = LoggerFactory.getLogger(WxCpMessageRouter.class); - private final List rules = new ArrayList<>(); - - private final WxCpService wxCpService; - - private ExecutorService executorService; - - private WxMessageDuplicateChecker messageDuplicateChecker; - - private WxSessionManager sessionManager; - - private WxErrorExceptionHandler exceptionHandler; - - public WxCpMessageRouter(WxCpService wxCpService) { - this.wxCpService = wxCpService; - this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); - this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); - this.sessionManager = new StandardSessionManager(); - this.exceptionHandler = new LogExceptionHandler(); - } - - /** - *
-   * 设置自定义的 {@link ExecutorService}
-   * 如果不调用该方法,默认使用 Executors.newFixedThreadPool(100)
-   * 
- * - * @param executorService - */ - public void setExecutorService(ExecutorService executorService) { - this.executorService = executorService; - } - - /** - *
-   * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker}
-   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker}
-   * 
- * - * @param messageDuplicateChecker - */ - public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { - this.messageDuplicateChecker = messageDuplicateChecker; - } - - /** - *
-   * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager}
-   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager}
-   * 
- * - * @param sessionManager - */ - public void setSessionManager(WxSessionManager sessionManager) { - this.sessionManager = sessionManager; - } - - /** - *
-   * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler}
-   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler}
-   * 
- * - * @param exceptionHandler - */ - public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { - this.exceptionHandler = exceptionHandler; - } - - List getRules() { - return this.rules; - } - - /** - * 开始一个新的Route规则 - */ - public WxCpMessageRouterRule rule() { - return new WxCpMessageRouterRule(this); - } - - /** - * 处理微信消息 - * - * @param wxMessage - * @param context - */ - public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage, final Map context) { - if (isDuplicateMessage(wxMessage)) { - // 如果是重复消息,那么就不做处理 - return null; - } - - final List matchRules = new ArrayList<>(); - // 收集匹配的规则 - for (final WxCpMessageRouterRule rule : this.rules) { - if (rule.test(wxMessage)) { - matchRules.add(rule); - if (!rule.isReEnter()) { - break; - } - } - } - - if (matchRules.size() == 0) { - return null; - } - - WxCpXmlOutMessage res = null; - final List futures = new ArrayList<>(); - for (final WxCpMessageRouterRule rule : matchRules) { - // 返回最后一个非异步的rule的执行结果 - if (rule.isAsync()) { - futures.add( - this.executorService.submit(new Runnable() { - @Override - public void run() { - rule.service(wxMessage, context, WxCpMessageRouter.this.wxCpService, WxCpMessageRouter.this.sessionManager, WxCpMessageRouter.this.exceptionHandler); - } - }) - ); - } else { - res = rule.service(wxMessage, context, this.wxCpService, this.sessionManager, this.exceptionHandler); - // 在同步操作结束,session访问结束 - this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUserName()); - sessionEndAccess(wxMessage); - } - } - - if (futures.size() > 0) { - this.executorService.submit(new Runnable() { - @Override - public void run() { - for (Future future : futures) { - try { - future.get(); - WxCpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUserName()); - // 异步操作结束,session访问结束 - sessionEndAccess(wxMessage); - } catch (InterruptedException e) { - WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); - } catch (ExecutionException e) { - WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); - } - } - } - }); - } - return res; - } - - - /** - * 处理微信消息 - * - * @param wxMessage - */ - public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) { - return this.route(wxMessage, new HashMap()); - } - - protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) { - - String messageId = ""; - if (wxMessage.getMsgId() == null) { - messageId = String.valueOf(wxMessage.getCreateTime()) - + "-" + String.valueOf(wxMessage.getAgentId() == null ? "" : wxMessage.getAgentId()) - + "-" + wxMessage.getFromUserName() - + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey()) - + "-" + String.valueOf(wxMessage.getEvent() == null ? "" : wxMessage.getEvent()) - ; - } else { - messageId = String.valueOf(wxMessage.getMsgId()); - } - - return this.messageDuplicateChecker.isDuplicate(messageId); - - } - - /** - * 对session的访问结束 - * - * @param wxMessage - */ - protected void sessionEndAccess(WxCpXmlMessage wxMessage) { - - InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUserName()); - if (session != null) { - session.endAccess(); - } - - } - - -} +package me.chanjar.weixin.cp.message; + +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; +import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; +import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; +import me.chanjar.weixin.common.session.InternalSession; +import me.chanjar.weixin.common.session.InternalSessionManager; +import me.chanjar.weixin.common.session.StandardSessionManager; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.LogExceptionHandler; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + *
+ * 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理
+ *
+ * 说明:
+ * 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理
+ * 2. 默认情况下消息只会被处理一次,除非使用 {@link WxCpMessageRouterRule#next()}
+ * 3. 规则的结束必须用{@link WxCpMessageRouterRule#end()}或者{@link WxCpMessageRouterRule#next()},否则不会生效
+ *
+ * 使用方法:
+ * WxCpMessageRouter router = new WxCpMessageRouter();
+ * router
+ *   .rule()
+ *       .msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT")
+ *       .interceptor(interceptor, ...).handler(handler, ...)
+ *   .end()
+ *   .rule()
+ *       // 另外一个匹配规则
+ *   .end()
+ * ;
+ *
+ * // 将WxXmlMessage交给消息路由器
+ * router.route(message);
+ *
+ * 
+ * + * @author Daniel Qian + */ +public class WxCpMessageRouter { + + private static final int DEFAULT_THREAD_POOL_SIZE = 100; + protected final Logger log = LoggerFactory.getLogger(WxCpMessageRouter.class); + private final List rules = new ArrayList<>(); + + private final WxCpService wxCpService; + + private ExecutorService executorService; + + private WxMessageDuplicateChecker messageDuplicateChecker; + + private WxSessionManager sessionManager; + + private WxErrorExceptionHandler exceptionHandler; + + public WxCpMessageRouter(WxCpService wxCpService) { + this.wxCpService = wxCpService; + this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); + this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); + this.sessionManager = new StandardSessionManager(); + this.exceptionHandler = new LogExceptionHandler(); + } + + /** + *
+   * 设置自定义的 {@link ExecutorService}
+   * 如果不调用该方法,默认使用 Executors.newFixedThreadPool(100)
+   * 
+ * + * @param executorService + */ + public void setExecutorService(ExecutorService executorService) { + this.executorService = executorService; + } + + /** + *
+   * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker}
+   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker}
+   * 
+ * + * @param messageDuplicateChecker + */ + public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { + this.messageDuplicateChecker = messageDuplicateChecker; + } + + /** + *
+   * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager}
+   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager}
+   * 
+ * + * @param sessionManager + */ + public void setSessionManager(WxSessionManager sessionManager) { + this.sessionManager = sessionManager; + } + + /** + *
+   * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler}
+   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler}
+   * 
+ * + * @param exceptionHandler + */ + public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + + List getRules() { + return this.rules; + } + + /** + * 开始一个新的Route规则 + */ + public WxCpMessageRouterRule rule() { + return new WxCpMessageRouterRule(this); + } + + /** + * 处理微信消息 + * + * @param wxMessage + * @param context + */ + public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage, final Map context) { + if (isDuplicateMessage(wxMessage)) { + // 如果是重复消息,那么就不做处理 + return null; + } + + final List matchRules = new ArrayList<>(); + // 收集匹配的规则 + for (final WxCpMessageRouterRule rule : this.rules) { + if (rule.test(wxMessage)) { + matchRules.add(rule); + if (!rule.isReEnter()) { + break; + } + } + } + + if (matchRules.size() == 0) { + return null; + } + + WxCpXmlOutMessage res = null; + final List futures = new ArrayList<>(); + for (final WxCpMessageRouterRule rule : matchRules) { + // 返回最后一个非异步的rule的执行结果 + if (rule.isAsync()) { + futures.add( + this.executorService.submit(new Runnable() { + @Override + public void run() { + rule.service(wxMessage, context, WxCpMessageRouter.this.wxCpService, WxCpMessageRouter.this.sessionManager, WxCpMessageRouter.this.exceptionHandler); + } + }) + ); + } else { + res = rule.service(wxMessage, context, this.wxCpService, this.sessionManager, this.exceptionHandler); + // 在同步操作结束,session访问结束 + this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUserName()); + sessionEndAccess(wxMessage); + } + } + + if (futures.size() > 0) { + this.executorService.submit(new Runnable() { + @Override + public void run() { + for (Future future : futures) { + try { + future.get(); + WxCpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUserName()); + // 异步操作结束,session访问结束 + sessionEndAccess(wxMessage); + } catch (InterruptedException e) { + WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); + } catch (ExecutionException e) { + WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); + } + } + } + }); + } + return res; + } + + + /** + * 处理微信消息 + * + * @param wxMessage + */ + public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) { + return this.route(wxMessage, new HashMap()); + } + + protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) { + + String messageId = ""; + if (wxMessage.getMsgId() == null) { + messageId = String.valueOf(wxMessage.getCreateTime()) + + "-" + String.valueOf(wxMessage.getAgentId() == null ? "" : wxMessage.getAgentId()) + + "-" + wxMessage.getFromUserName() + + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey()) + + "-" + String.valueOf(wxMessage.getEvent() == null ? "" : wxMessage.getEvent()) + ; + } else { + messageId = String.valueOf(wxMessage.getMsgId()); + } + + return this.messageDuplicateChecker.isDuplicate(messageId); + + } + + /** + * 对session的访问结束 + * + * @param wxMessage + */ + protected void sessionEndAccess(WxCpXmlMessage wxMessage) { + + InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUserName()); + if (session != null) { + session.endAccess(); + } + + } + + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java index 3c0921132c..5f41f61783 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java @@ -1,321 +1,322 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.api.WxErrorExceptionHandler; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -public class WxCpMessageRouterRule { - - private final WxCpMessageRouter routerBuilder; - - private boolean async = true; - - private String fromUser; - - private String msgType; - - private String event; - - private String eventKey; - - private String content; - - private String rContent; - - private WxCpMessageMatcher matcher; - - private boolean reEnter = false; - - private Integer agentId; - - private List handlers = new ArrayList<>(); - - private List interceptors = new ArrayList<>(); - - protected WxCpMessageRouterRule(WxCpMessageRouter routerBuilder) { - this.routerBuilder = routerBuilder; - } - - /** - * 设置是否异步执行,默认是true - * - * @param async - */ - public WxCpMessageRouterRule async(boolean async) { - this.async = async; - return this; - } - - /** - * 如果agentId匹配 - * - * @param agentId - */ - public WxCpMessageRouterRule agentId(Integer agentId) { - this.agentId = agentId; - return this; - } - - /** - * 如果msgType等于某值 - * - * @param msgType - */ - public WxCpMessageRouterRule msgType(String msgType) { - this.msgType = msgType; - return this; - } - - /** - * 如果event等于某值 - * - * @param event - */ - public WxCpMessageRouterRule event(String event) { - this.event = event; - return this; - } - - /** - * 如果eventKey等于某值 - * - * @param eventKey - */ - public WxCpMessageRouterRule eventKey(String eventKey) { - this.eventKey = eventKey; - return this; - } - - /** - * 如果content等于某值 - * - * @param content - */ - public WxCpMessageRouterRule content(String content) { - this.content = content; - return this; - } - - /** - * 如果content匹配该正则表达式 - * - * @param regex - */ - public WxCpMessageRouterRule rContent(String regex) { - this.rContent = regex; - return this; - } - - /** - * 如果fromUser等于某值 - * - * @param fromUser - */ - public WxCpMessageRouterRule fromUser(String fromUser) { - this.fromUser = fromUser; - return this; - } - - /** - * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 - * - * @param matcher - */ - public WxCpMessageRouterRule matcher(WxCpMessageMatcher matcher) { - this.matcher = matcher; - return this; - } - - /** - * 设置微信消息拦截器 - * - * @param interceptor - */ - public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor) { - return interceptor(interceptor, (WxCpMessageInterceptor[]) null); - } - - /** - * 设置微信消息拦截器 - * - * @param interceptor - * @param otherInterceptors - */ - public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) { - this.interceptors.add(interceptor); - if (otherInterceptors != null && otherInterceptors.length > 0) { - for (WxCpMessageInterceptor i : otherInterceptors) { - this.interceptors.add(i); - } - } - return this; - } - - /** - * 设置微信消息处理器 - * - * @param handler - */ - public WxCpMessageRouterRule handler(WxCpMessageHandler handler) { - return handler(handler, (WxCpMessageHandler[]) null); - } - - /** - * 设置微信消息处理器 - * - * @param handler - * @param otherHandlers - */ - public WxCpMessageRouterRule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) { - this.handlers.add(handler); - if (otherHandlers != null && otherHandlers.length > 0) { - for (WxCpMessageHandler i : otherHandlers) { - this.handlers.add(i); - } - } - return this; - } - - /** - * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 - */ - public WxCpMessageRouter end() { - this.routerBuilder.getRules().add(this); - return this.routerBuilder; - } - - /** - * 规则结束,但是消息还会进入其他规则 - */ - public WxCpMessageRouter next() { - this.reEnter = true; - return end(); - } - - protected boolean test(WxCpXmlMessage wxMessage) { - return - (this.fromUser == null || this.fromUser.equals(wxMessage.getFromUserName())) - && - (this.agentId == null || this.agentId.equals(wxMessage.getAgentId())) - && - (this.msgType == null || this.msgType.equals(wxMessage.getMsgType())) - && - (this.event == null || this.event.equals(wxMessage.getEvent())) - && - (this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey())) - && - (this.content == null || this.content - .equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) - && - (this.rContent == null || Pattern - .matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) - && - (this.matcher == null || this.matcher.match(wxMessage)) - ; - } - - /** - * 处理微信推送过来的消息 - * - * @param wxMessage - * @return true 代表继续执行别的router,false 代表停止执行别的router - */ - protected WxCpXmlOutMessage service(WxCpXmlMessage wxMessage, - Map context, - WxCpService wxCpService, - WxSessionManager sessionManager, - WxErrorExceptionHandler exceptionHandler) { - - if (context == null) { - context = new HashMap<>(); - } - - try { - // 如果拦截器不通过 - for (WxCpMessageInterceptor interceptor : this.interceptors) { - if (!interceptor.intercept(wxMessage, context, wxCpService, sessionManager)) { - return null; - } - } - - // 交给handler处理 - WxCpXmlOutMessage res = null; - for (WxCpMessageHandler handler : this.handlers) { - // 返回最后handler的结果 - res = handler.handle(wxMessage, context, wxCpService, sessionManager); - } - return res; - - } catch (WxErrorException e) { - exceptionHandler.handle(e); - } - - return null; - - } - - public void setFromUser(String fromUser) { - this.fromUser = fromUser; - } - - public void setMsgType(String msgType) { - this.msgType = msgType; - } - - public void setEvent(String event) { - this.event = event; - } - - public void setEventKey(String eventKey) { - this.eventKey = eventKey; - } - - public void setContent(String content) { - this.content = content; - } - - public void setrContent(String rContent) { - this.rContent = rContent; - } - - public void setMatcher(WxCpMessageMatcher matcher) { - this.matcher = matcher; - } - - public void setAgentId(Integer agentId) { - this.agentId = agentId; - } - - public void setHandlers(List handlers) { - this.handlers = handlers; - } - - public void setInterceptors(List interceptors) { - this.interceptors = interceptors; - } - - public boolean isAsync() { - return this.async; - } - - public void setAsync(boolean async) { - this.async = async; - } - - public boolean isReEnter() { - return this.reEnter; - } - - public void setReEnter(boolean reEnter) { - this.reEnter = reEnter; - } - -} +package me.chanjar.weixin.cp.message; + +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +public class WxCpMessageRouterRule { + + private final WxCpMessageRouter routerBuilder; + + private boolean async = true; + + private String fromUser; + + private String msgType; + + private String event; + + private String eventKey; + + private String content; + + private String rContent; + + private WxCpMessageMatcher matcher; + + private boolean reEnter = false; + + private Integer agentId; + + private List handlers = new ArrayList<>(); + + private List interceptors = new ArrayList<>(); + + protected WxCpMessageRouterRule(WxCpMessageRouter routerBuilder) { + this.routerBuilder = routerBuilder; + } + + /** + * 设置是否异步执行,默认是true + * + * @param async + */ + public WxCpMessageRouterRule async(boolean async) { + this.async = async; + return this; + } + + /** + * 如果agentId匹配 + * + * @param agentId + */ + public WxCpMessageRouterRule agentId(Integer agentId) { + this.agentId = agentId; + return this; + } + + /** + * 如果msgType等于某值 + * + * @param msgType + */ + public WxCpMessageRouterRule msgType(String msgType) { + this.msgType = msgType; + return this; + } + + /** + * 如果event等于某值 + * + * @param event + */ + public WxCpMessageRouterRule event(String event) { + this.event = event; + return this; + } + + /** + * 如果eventKey等于某值 + * + * @param eventKey + */ + public WxCpMessageRouterRule eventKey(String eventKey) { + this.eventKey = eventKey; + return this; + } + + /** + * 如果content等于某值 + * + * @param content + */ + public WxCpMessageRouterRule content(String content) { + this.content = content; + return this; + } + + /** + * 如果content匹配该正则表达式 + * + * @param regex + */ + public WxCpMessageRouterRule rContent(String regex) { + this.rContent = regex; + return this; + } + + /** + * 如果fromUser等于某值 + * + * @param fromUser + */ + public WxCpMessageRouterRule fromUser(String fromUser) { + this.fromUser = fromUser; + return this; + } + + /** + * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 + * + * @param matcher + */ + public WxCpMessageRouterRule matcher(WxCpMessageMatcher matcher) { + this.matcher = matcher; + return this; + } + + /** + * 设置微信消息拦截器 + * + * @param interceptor + */ + public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor) { + return interceptor(interceptor, (WxCpMessageInterceptor[]) null); + } + + /** + * 设置微信消息拦截器 + * + * @param interceptor + * @param otherInterceptors + */ + public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) { + this.interceptors.add(interceptor); + if (otherInterceptors != null && otherInterceptors.length > 0) { + for (WxCpMessageInterceptor i : otherInterceptors) { + this.interceptors.add(i); + } + } + return this; + } + + /** + * 设置微信消息处理器 + * + * @param handler + */ + public WxCpMessageRouterRule handler(WxCpMessageHandler handler) { + return handler(handler, (WxCpMessageHandler[]) null); + } + + /** + * 设置微信消息处理器 + * + * @param handler + * @param otherHandlers + */ + public WxCpMessageRouterRule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) { + this.handlers.add(handler); + if (otherHandlers != null && otherHandlers.length > 0) { + for (WxCpMessageHandler i : otherHandlers) { + this.handlers.add(i); + } + } + return this; + } + + /** + * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 + */ + public WxCpMessageRouter end() { + this.routerBuilder.getRules().add(this); + return this.routerBuilder; + } + + /** + * 规则结束,但是消息还会进入其他规则 + */ + public WxCpMessageRouter next() { + this.reEnter = true; + return end(); + } + + protected boolean test(WxCpXmlMessage wxMessage) { + return + (this.fromUser == null || this.fromUser.equals(wxMessage.getFromUserName())) + && + (this.agentId == null || this.agentId.equals(wxMessage.getAgentId())) + && + (this.msgType == null || this.msgType.equals(wxMessage.getMsgType())) + && + (this.event == null || this.event.equals(wxMessage.getEvent())) + && + (this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey())) + && + (this.content == null || this.content + .equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) + && + (this.rContent == null || Pattern + .matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) + && + (this.matcher == null || this.matcher.match(wxMessage)) + ; + } + + /** + * 处理微信推送过来的消息 + * + * @param wxMessage + * @return true 代表继续执行别的router,false 代表停止执行别的router + */ + protected WxCpXmlOutMessage service(WxCpXmlMessage wxMessage, + Map context, + WxCpService wxCpService, + WxSessionManager sessionManager, + WxErrorExceptionHandler exceptionHandler) { + + if (context == null) { + context = new HashMap<>(); + } + + try { + // 如果拦截器不通过 + for (WxCpMessageInterceptor interceptor : this.interceptors) { + if (!interceptor.intercept(wxMessage, context, wxCpService, sessionManager)) { + return null; + } + } + + // 交给handler处理 + WxCpXmlOutMessage res = null; + for (WxCpMessageHandler handler : this.handlers) { + // 返回最后handler的结果 + res = handler.handle(wxMessage, context, wxCpService, sessionManager); + } + return res; + + } catch (WxErrorException e) { + exceptionHandler.handle(e); + } + + return null; + + } + + public void setFromUser(String fromUser) { + this.fromUser = fromUser; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public void setEvent(String event) { + this.event = event; + } + + public void setEventKey(String eventKey) { + this.eventKey = eventKey; + } + + public void setContent(String content) { + this.content = content; + } + + public void setrContent(String rContent) { + this.rContent = rContent; + } + + public void setMatcher(WxCpMessageMatcher matcher) { + this.matcher = matcher; + } + + public void setAgentId(Integer agentId) { + this.agentId = agentId; + } + + public void setHandlers(List handlers) { + this.handlers = handlers; + } + + public void setInterceptors(List interceptors) { + this.interceptors = interceptors; + } + + public boolean isAsync() { + return this.async; + } + + public void setAsync(boolean async) { + this.async = async; + } + + public boolean isReEnter() { + return this.reEnter; + } + + public void setReEnter(boolean reEnter) { + this.reEnter = reEnter; + } + +} From a90628c3b8c5b52f5709a341779985fc45a2cd42 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 24 Jun 2017 22:42:40 +0800 Subject: [PATCH 100/179] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=8F=B7config=E7=9B=B8=E5=85=B3=E7=B1=BB=E7=9A=84=E5=8C=85?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/config/WxCpConfigStorage.java | 148 ++--- .../cp/config/WxCpInMemoryConfigStorage.java | 448 +++++++-------- .../cp/config/WxCpJedisConfigStorage.java | 538 +++++++++--------- 3 files changed, 567 insertions(+), 567 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java index 4434e697b5..65dd3affff 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java @@ -1,74 +1,74 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; - -import java.io.File; - -/** - * 微信客户端配置存储 - * - * @author Daniel Qian - */ -public interface WxCpConfigStorage { - - String getAccessToken(); - - boolean isAccessTokenExpired(); - - /** - * 强制将access token过期掉 - */ - void expireAccessToken(); - - void updateAccessToken(WxAccessToken accessToken); - - void updateAccessToken(String accessToken, int expiresIn); - - String getJsapiTicket(); - - boolean isJsapiTicketExpired(); - - /** - * 强制将jsapi ticket过期掉 - */ - void expireJsapiTicket(); - - /** - * 应该是线程安全的 - * - * @param jsapiTicket - */ - void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); - - String getCorpId(); - - String getCorpSecret(); - - Integer getAgentId(); - - String getToken(); - - String getAesKey(); - - long getExpiresTime(); - - String getOauth2redirectUri(); - - String getHttpProxyHost(); - - int getHttpProxyPort(); - - String getHttpProxyUsername(); - - String getHttpProxyPassword(); - - File getTmpDirFile(); - - /** - * http client builder - * - * @return ApacheHttpClientBuilder - */ - ApacheHttpClientBuilder getApacheHttpClientBuilder(); -} +package me.chanjar.weixin.cp.config; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + +import java.io.File; + +/** + * 微信客户端配置存储 + * + * @author Daniel Qian + */ +public interface WxCpConfigStorage { + + String getAccessToken(); + + boolean isAccessTokenExpired(); + + /** + * 强制将access token过期掉 + */ + void expireAccessToken(); + + void updateAccessToken(WxAccessToken accessToken); + + void updateAccessToken(String accessToken, int expiresIn); + + String getJsapiTicket(); + + boolean isJsapiTicketExpired(); + + /** + * 强制将jsapi ticket过期掉 + */ + void expireJsapiTicket(); + + /** + * 应该是线程安全的 + * + * @param jsapiTicket + */ + void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); + + String getCorpId(); + + String getCorpSecret(); + + Integer getAgentId(); + + String getToken(); + + String getAesKey(); + + long getExpiresTime(); + + String getOauth2redirectUri(); + + String getHttpProxyHost(); + + int getHttpProxyPort(); + + String getHttpProxyUsername(); + + String getHttpProxyPassword(); + + File getTmpDirFile(); + + /** + * http client builder + * + * @return ApacheHttpClientBuilder + */ + ApacheHttpClientBuilder getApacheHttpClientBuilder(); +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java index 7ba06417c8..1b57f83bf8 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java @@ -1,224 +1,224 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.ToStringUtils; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; - -import java.io.File; - -/** - * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 - * - * @author Daniel Qian - */ -public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { - - protected volatile String corpId; - protected volatile String corpSecret; - - protected volatile String token; - protected volatile String accessToken; - protected volatile String aesKey; - protected volatile Integer agentId; - protected volatile long expiresTime; - - protected volatile String oauth2redirectUri; - - protected volatile String httpProxyHost; - protected volatile int httpProxyPort; - protected volatile String httpProxyUsername; - protected volatile String httpProxyPassword; - - protected volatile String jsapiTicket; - protected volatile long jsapiTicketExpiresTime; - - protected volatile File tmpDirFile; - - private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; - - @Override - public String getAccessToken() { - return this.accessToken; - } - - public void setAccessToken(String accessToken) { - this.accessToken = accessToken; - } - - @Override - public boolean isAccessTokenExpired() { - return System.currentTimeMillis() > this.expiresTime; - } - - @Override - public void expireAccessToken() { - this.expiresTime = 0; - } - - @Override - public synchronized void updateAccessToken(WxAccessToken accessToken) { - updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - } - - @Override - public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { - this.accessToken = accessToken; - this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; - } - - @Override - public String getJsapiTicket() { - return this.jsapiTicket; - } - - public void setJsapiTicket(String jsapiTicket) { - this.jsapiTicket = jsapiTicket; - } - - public long getJsapiTicketExpiresTime() { - return this.jsapiTicketExpiresTime; - } - - public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) { - this.jsapiTicketExpiresTime = jsapiTicketExpiresTime; - } - - @Override - public boolean isJsapiTicketExpired() { - return System.currentTimeMillis() > this.jsapiTicketExpiresTime; - } - - @Override - public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { - this.jsapiTicket = jsapiTicket; - // 预留200秒的时间 - this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; - } - - @Override - public void expireJsapiTicket() { - this.jsapiTicketExpiresTime = 0; - } - - @Override - public String getCorpId() { - return this.corpId; - } - - public void setCorpId(String corpId) { - this.corpId = corpId; - } - - @Override - public String getCorpSecret() { - return this.corpSecret; - } - - public void setCorpSecret(String corpSecret) { - this.corpSecret = corpSecret; - } - - @Override - public String getToken() { - return this.token; - } - - public void setToken(String token) { - this.token = token; - } - - @Override - public long getExpiresTime() { - return this.expiresTime; - } - - public void setExpiresTime(long expiresTime) { - this.expiresTime = expiresTime; - } - - @Override - public String getAesKey() { - return this.aesKey; - } - - public void setAesKey(String aesKey) { - this.aesKey = aesKey; - } - - @Override - public Integer getAgentId() { - return this.agentId; - } - - public void setAgentId(Integer agentId) { - this.agentId = agentId; - } - - @Override - public String getOauth2redirectUri() { - return this.oauth2redirectUri; - } - - public void setOauth2redirectUri(String oauth2redirectUri) { - this.oauth2redirectUri = oauth2redirectUri; - } - - @Override - public String getHttpProxyHost() { - return this.httpProxyHost; - } - - public void setHttpProxyHost(String httpProxyHost) { - this.httpProxyHost = httpProxyHost; - } - - @Override - public int getHttpProxyPort() { - return this.httpProxyPort; - } - - public void setHttpProxyPort(int httpProxyPort) { - this.httpProxyPort = httpProxyPort; - } - - @Override - public String getHttpProxyUsername() { - return this.httpProxyUsername; - } - - public void setHttpProxyUsername(String httpProxyUsername) { - this.httpProxyUsername = httpProxyUsername; - } - - @Override - public String getHttpProxyPassword() { - return this.httpProxyPassword; - } - - public void setHttpProxyPassword(String httpProxyPassword) { - this.httpProxyPassword = httpProxyPassword; - } - - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - - @Override - public File getTmpDirFile() { - return this.tmpDirFile; - } - - public void setTmpDirFile(File tmpDirFile) { - this.tmpDirFile = tmpDirFile; - } - - @Override - public ApacheHttpClientBuilder getApacheHttpClientBuilder() { - return this.apacheHttpClientBuilder; - } - - public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { - this.apacheHttpClientBuilder = apacheHttpClientBuilder; - } -} +package me.chanjar.weixin.cp.config; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + +import java.io.File; + +/** + * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 + * + * @author Daniel Qian + */ +public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { + + protected volatile String corpId; + protected volatile String corpSecret; + + protected volatile String token; + protected volatile String accessToken; + protected volatile String aesKey; + protected volatile Integer agentId; + protected volatile long expiresTime; + + protected volatile String oauth2redirectUri; + + protected volatile String httpProxyHost; + protected volatile int httpProxyPort; + protected volatile String httpProxyUsername; + protected volatile String httpProxyPassword; + + protected volatile String jsapiTicket; + protected volatile long jsapiTicketExpiresTime; + + protected volatile File tmpDirFile; + + private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + + @Override + public String getAccessToken() { + return this.accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + @Override + public boolean isAccessTokenExpired() { + return System.currentTimeMillis() > this.expiresTime; + } + + @Override + public void expireAccessToken() { + this.expiresTime = 0; + } + + @Override + public synchronized void updateAccessToken(WxAccessToken accessToken) { + updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + } + + @Override + public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { + this.accessToken = accessToken; + this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; + } + + @Override + public String getJsapiTicket() { + return this.jsapiTicket; + } + + public void setJsapiTicket(String jsapiTicket) { + this.jsapiTicket = jsapiTicket; + } + + public long getJsapiTicketExpiresTime() { + return this.jsapiTicketExpiresTime; + } + + public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) { + this.jsapiTicketExpiresTime = jsapiTicketExpiresTime; + } + + @Override + public boolean isJsapiTicketExpired() { + return System.currentTimeMillis() > this.jsapiTicketExpiresTime; + } + + @Override + public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { + this.jsapiTicket = jsapiTicket; + // 预留200秒的时间 + this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; + } + + @Override + public void expireJsapiTicket() { + this.jsapiTicketExpiresTime = 0; + } + + @Override + public String getCorpId() { + return this.corpId; + } + + public void setCorpId(String corpId) { + this.corpId = corpId; + } + + @Override + public String getCorpSecret() { + return this.corpSecret; + } + + public void setCorpSecret(String corpSecret) { + this.corpSecret = corpSecret; + } + + @Override + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public long getExpiresTime() { + return this.expiresTime; + } + + public void setExpiresTime(long expiresTime) { + this.expiresTime = expiresTime; + } + + @Override + public String getAesKey() { + return this.aesKey; + } + + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } + + @Override + public Integer getAgentId() { + return this.agentId; + } + + public void setAgentId(Integer agentId) { + this.agentId = agentId; + } + + @Override + public String getOauth2redirectUri() { + return this.oauth2redirectUri; + } + + public void setOauth2redirectUri(String oauth2redirectUri) { + this.oauth2redirectUri = oauth2redirectUri; + } + + @Override + public String getHttpProxyHost() { + return this.httpProxyHost; + } + + public void setHttpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + } + + @Override + public int getHttpProxyPort() { + return this.httpProxyPort; + } + + public void setHttpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + } + + @Override + public String getHttpProxyUsername() { + return this.httpProxyUsername; + } + + public void setHttpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + } + + @Override + public String getHttpProxyPassword() { + return this.httpProxyPassword; + } + + public void setHttpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + } + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + @Override + public File getTmpDirFile() { + return this.tmpDirFile; + } + + public void setTmpDirFile(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public ApacheHttpClientBuilder getApacheHttpClientBuilder() { + return this.apacheHttpClientBuilder; + } + + public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { + this.apacheHttpClientBuilder = apacheHttpClientBuilder; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java index f75188fece..39b2ae5023 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java @@ -1,269 +1,269 @@ -package me.chanjar.weixin.cp.api; - -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.JedisPoolConfig; - -import java.io.File; - -/** - * Jedis client implementor for wechat config storage - * - * @author gaigeshen - */ -public class WxCpJedisConfigStorage implements WxCpConfigStorage { - - /* Redis keys here */ - private static final String ACCESS_TOKEN_KEY = "WX_CP_ACCESS_TOKEN"; - private static final String ACCESS_TOKEN_EXPIRES_TIME_KEY = "WX_CP_ACCESS_TOKEN_EXPIRES_TIME"; - private static final String JS_API_TICKET_KEY = "WX_CP_JS_API_TICKET"; - private static final String JS_API_TICKET_EXPIRES_TIME_KEY = "WX_CP_JS_API_TICKET_EXPIRES_TIME"; - /* Redis clients pool */ - private final JedisPool jedisPool; - private volatile String corpId; - private volatile String corpSecret; - private volatile String token; - private volatile String aesKey; - private volatile Integer agentId; - private volatile String oauth2redirectUri; - private volatile String httpProxyHost; - private volatile int httpProxyPort; - private volatile String httpProxyUsername; - private volatile String httpProxyPassword; - private volatile File tmpDirFile; - private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; - - public WxCpJedisConfigStorage(String host, int port) { - this.jedisPool = new JedisPool(host, port); - } - - - public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port) { - this.jedisPool = new JedisPool(poolConfig, host, port); - } - - public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, final String password) { - this.jedisPool = new JedisPool(poolConfig, host, port, timeout, password); - } - - /** - * This method will be destroy jedis pool - */ - public void destroy() { - this.jedisPool.destroy(); - } - - @Override - public String getAccessToken() { - try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.get(ACCESS_TOKEN_KEY); - } - } - - @Override - public boolean isAccessTokenExpired() { - try (Jedis jedis = this.jedisPool.getResource()) { - String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY); - - if (expiresTimeStr != null) { - Long expiresTime = Long.parseLong(expiresTimeStr); - return System.currentTimeMillis() > expiresTime; - } - - return true; - - } - } - - @Override - public void expireAccessToken() { - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY, "0"); - } - } - - @Override - public synchronized void updateAccessToken(WxAccessToken accessToken) { - this.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - } - - @Override - public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.set(ACCESS_TOKEN_KEY, accessToken); - - jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY, - (System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L) + ""); - } - } - - @Override - public String getJsapiTicket() { - try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.get(JS_API_TICKET_KEY); - } - } - - @Override - public boolean isJsapiTicketExpired() { - - try (Jedis jedis = this.jedisPool.getResource()) { - String expiresTimeStr = jedis.get(JS_API_TICKET_EXPIRES_TIME_KEY); - - if (expiresTimeStr != null) { - Long expiresTime = Long.parseLong(expiresTimeStr); - return System.currentTimeMillis() > expiresTime; - } - - return true; - - } - } - - @Override - public void expireJsapiTicket() { - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY, "0"); - } - } - - @Override - public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { - - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.set(JS_API_TICKET_KEY, jsapiTicket); - - jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY, - (System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L + "")); - } - - } - - @Override - public String getCorpId() { - return this.corpId; - } - - public void setCorpId(String corpId) { - this.corpId = corpId; - } - - @Override - public String getCorpSecret() { - return this.corpSecret; - } - - public void setCorpSecret(String corpSecret) { - this.corpSecret = corpSecret; - } - - @Override - public Integer getAgentId() { - return this.agentId; - } - - public void setAgentId(Integer agentId) { - this.agentId = agentId; - } - - @Override - public String getToken() { - return this.token; - } - - public void setToken(String token) { - this.token = token; - } - - @Override - public String getAesKey() { - return this.aesKey; - } - - public void setAesKey(String aesKey) { - this.aesKey = aesKey; - } - - @Override - public long getExpiresTime() { - try (Jedis jedis = this.jedisPool.getResource()) { - String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY); - - if (expiresTimeStr != null) { - Long expiresTime = Long.parseLong(expiresTimeStr); - return expiresTime; - } - - return 0L; - - } - } - - @Override - public String getOauth2redirectUri() { - return this.oauth2redirectUri; - } - - public void setOauth2redirectUri(String oauth2redirectUri) { - this.oauth2redirectUri = oauth2redirectUri; - } - - @Override - public String getHttpProxyHost() { - return this.httpProxyHost; - } - - public void setHttpProxyHost(String httpProxyHost) { - this.httpProxyHost = httpProxyHost; - } - - @Override - public int getHttpProxyPort() { - return this.httpProxyPort; - } - - public void setHttpProxyPort(int httpProxyPort) { - this.httpProxyPort = httpProxyPort; - } - - @Override - public String getHttpProxyUsername() { - return this.httpProxyUsername; - } - - // ============================ Setters below - - public void setHttpProxyUsername(String httpProxyUsername) { - this.httpProxyUsername = httpProxyUsername; - } - - @Override - public String getHttpProxyPassword() { - return this.httpProxyPassword; - } - - public void setHttpProxyPassword(String httpProxyPassword) { - this.httpProxyPassword = httpProxyPassword; - } - - @Override - public File getTmpDirFile() { - return this.tmpDirFile; - } - - public void setTmpDirFile(File tmpDirFile) { - this.tmpDirFile = tmpDirFile; - } - - @Override - public ApacheHttpClientBuilder getApacheHttpClientBuilder() { - return this.apacheHttpClientBuilder; - } - - public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { - this.apacheHttpClientBuilder = apacheHttpClientBuilder; - } - -} +package me.chanjar.weixin.cp.config; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; + +import java.io.File; + +/** + * Jedis client implementor for wechat config storage + * + * @author gaigeshen + */ +public class WxCpJedisConfigStorage implements WxCpConfigStorage { + + /* Redis keys here */ + private static final String ACCESS_TOKEN_KEY = "WX_CP_ACCESS_TOKEN"; + private static final String ACCESS_TOKEN_EXPIRES_TIME_KEY = "WX_CP_ACCESS_TOKEN_EXPIRES_TIME"; + private static final String JS_API_TICKET_KEY = "WX_CP_JS_API_TICKET"; + private static final String JS_API_TICKET_EXPIRES_TIME_KEY = "WX_CP_JS_API_TICKET_EXPIRES_TIME"; + /* Redis clients pool */ + private final JedisPool jedisPool; + private volatile String corpId; + private volatile String corpSecret; + private volatile String token; + private volatile String aesKey; + private volatile Integer agentId; + private volatile String oauth2redirectUri; + private volatile String httpProxyHost; + private volatile int httpProxyPort; + private volatile String httpProxyUsername; + private volatile String httpProxyPassword; + private volatile File tmpDirFile; + private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + + public WxCpJedisConfigStorage(String host, int port) { + this.jedisPool = new JedisPool(host, port); + } + + + public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port) { + this.jedisPool = new JedisPool(poolConfig, host, port); + } + + public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, final String password) { + this.jedisPool = new JedisPool(poolConfig, host, port, timeout, password); + } + + /** + * This method will be destroy jedis pool + */ + public void destroy() { + this.jedisPool.destroy(); + } + + @Override + public String getAccessToken() { + try (Jedis jedis = this.jedisPool.getResource()) { + return jedis.get(ACCESS_TOKEN_KEY); + } + } + + @Override + public boolean isAccessTokenExpired() { + try (Jedis jedis = this.jedisPool.getResource()) { + String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY); + + if (expiresTimeStr != null) { + Long expiresTime = Long.parseLong(expiresTimeStr); + return System.currentTimeMillis() > expiresTime; + } + + return true; + + } + } + + @Override + public void expireAccessToken() { + try (Jedis jedis = this.jedisPool.getResource()) { + jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY, "0"); + } + } + + @Override + public synchronized void updateAccessToken(WxAccessToken accessToken) { + this.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + } + + @Override + public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { + try (Jedis jedis = this.jedisPool.getResource()) { + jedis.set(ACCESS_TOKEN_KEY, accessToken); + + jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY, + (System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L) + ""); + } + } + + @Override + public String getJsapiTicket() { + try (Jedis jedis = this.jedisPool.getResource()) { + return jedis.get(JS_API_TICKET_KEY); + } + } + + @Override + public boolean isJsapiTicketExpired() { + + try (Jedis jedis = this.jedisPool.getResource()) { + String expiresTimeStr = jedis.get(JS_API_TICKET_EXPIRES_TIME_KEY); + + if (expiresTimeStr != null) { + Long expiresTime = Long.parseLong(expiresTimeStr); + return System.currentTimeMillis() > expiresTime; + } + + return true; + + } + } + + @Override + public void expireJsapiTicket() { + try (Jedis jedis = this.jedisPool.getResource()) { + jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY, "0"); + } + } + + @Override + public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { + + try (Jedis jedis = this.jedisPool.getResource()) { + jedis.set(JS_API_TICKET_KEY, jsapiTicket); + + jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY, + (System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L + "")); + } + + } + + @Override + public String getCorpId() { + return this.corpId; + } + + public void setCorpId(String corpId) { + this.corpId = corpId; + } + + @Override + public String getCorpSecret() { + return this.corpSecret; + } + + public void setCorpSecret(String corpSecret) { + this.corpSecret = corpSecret; + } + + @Override + public Integer getAgentId() { + return this.agentId; + } + + public void setAgentId(Integer agentId) { + this.agentId = agentId; + } + + @Override + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public String getAesKey() { + return this.aesKey; + } + + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } + + @Override + public long getExpiresTime() { + try (Jedis jedis = this.jedisPool.getResource()) { + String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY); + + if (expiresTimeStr != null) { + Long expiresTime = Long.parseLong(expiresTimeStr); + return expiresTime; + } + + return 0L; + + } + } + + @Override + public String getOauth2redirectUri() { + return this.oauth2redirectUri; + } + + public void setOauth2redirectUri(String oauth2redirectUri) { + this.oauth2redirectUri = oauth2redirectUri; + } + + @Override + public String getHttpProxyHost() { + return this.httpProxyHost; + } + + public void setHttpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + } + + @Override + public int getHttpProxyPort() { + return this.httpProxyPort; + } + + public void setHttpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + } + + @Override + public String getHttpProxyUsername() { + return this.httpProxyUsername; + } + + // ============================ Setters below + + public void setHttpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + } + + @Override + public String getHttpProxyPassword() { + return this.httpProxyPassword; + } + + public void setHttpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + } + + @Override + public File getTmpDirFile() { + return this.tmpDirFile; + } + + public void setTmpDirFile(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public ApacheHttpClientBuilder getApacheHttpClientBuilder() { + return this.apacheHttpClientBuilder; + } + + public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { + this.apacheHttpClientBuilder = apacheHttpClientBuilder; + } + +} From 6b1b7f1a818cf8c4aa3131870c953b0a62a19d65 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 24 Jun 2017 22:45:49 +0800 Subject: [PATCH 101/179] =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=8F=B7=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/api/WxCpDepartmentService.java | 57 +++++ .../weixin/cp/api/WxCpMediaService.java | 11 + .../weixin/cp/api/WxCpMenuService.java | 11 + .../weixin/cp/api/WxCpOauth2Service.java | 11 + .../me/chanjar/weixin/cp/api/WxCpService.java | 141 ++++++------ .../chanjar/weixin/cp/api/WxCpTagService.java | 11 + .../weixin/cp/api/WxCpUserService.java | 83 ++++++++ .../cp/api/impl/AbstractWxCpServiceImpl.java | 201 +++++++++--------- .../api/impl/WxCpDepartmentServiceImpl.java | 65 ++++++ .../impl/WxCpServiceApacheHttpClientImpl.java | 5 +- .../cp/api/impl/WxCpServiceJoddHttpImpl.java | 3 +- .../cp/api/impl/WxCpServiceOkHttpImpl.java | 3 +- .../cp/api/impl/WxCpUserServiceImpl.java | 118 ++++++++++ .../weixin/cp/bean/WxCpXmlMessage.java | 2 +- .../weixin/cp/bean/WxCpXmlOutMessage.java | 2 +- .../weixin/cp/util/crypto/WxCpCryptUtil.java | 2 +- .../chanjar/weixin/cp/api/ApiTestModule.java | 6 +- .../weixin/cp/api/WxCpBaseAPITest.java | 1 + .../weixin/cp/api/WxCpMessageRouterTest.java | 3 + .../chanjar/weixin/cp/api/WxCpTagAPITest.java | 1 + .../weixin/cp/api/WxCpUserAPITest.java | 76 ------- .../impl/WxCpDepartmentServiceImplTest.java | 66 ++++++ .../cp/api/impl/WxCpUserServiceImplTest.java | 86 ++++++++ .../demo/WxCpDemoInMemoryConfigStorage.java | 2 +- .../weixin/cp/demo/WxCpDemoServer.java | 6 +- .../weixin/cp/demo/WxCpEndpointServlet.java | 4 +- 26 files changed, 706 insertions(+), 271 deletions(-) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOauth2Service.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java delete mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java create mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java create mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java new file mode 100644 index 0000000000..7ca1ade3e5 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java @@ -0,0 +1,57 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.bean.WxCpDepart; + +import java.util.List; + +/** + *
+ *  部门管理接口
+ *  Created by BinaryWang on 2017/6/24.
+ * 
+ * + * @author Binary Wang + */ +public interface WxCpDepartmentService { + + /** + *
+   * 部门管理接口 - 创建部门
+   * 最多支持创建500个部门
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
+   * 
+ * + * @param depart 部门 + * @return 部门id + */ + Integer create(WxCpDepart depart) throws WxErrorException; + + /** + *
+   * 部门管理接口 - 查询所有部门
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
+   * 
+ */ + List listAll() throws WxErrorException; + + /** + *
+   * 部门管理接口 - 修改部门名
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
+   * 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
+   * 
+ * + * @param group 要更新的group,group的id,name必须设置 + */ + void update(WxCpDepart group) throws WxErrorException; + + /** + *
+   * 部门管理接口 - 删除部门
+   * 
+ * + * @param departId 部门id + */ + void delete(Integer departId) throws WxErrorException; +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java new file mode 100644 index 0000000000..ba0241a629 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java @@ -0,0 +1,11 @@ +package me.chanjar.weixin.cp.api; + +/** + *
+ *  Created by BinaryWang on 2017/6/24.
+ * 
+ * + * @author Binary Wang + */ +public interface WxCpMediaService { +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java new file mode 100644 index 0000000000..f6a45e4352 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java @@ -0,0 +1,11 @@ +package me.chanjar.weixin.cp.api; + +/** + *
+ *  Created by BinaryWang on 2017/6/24.
+ * 
+ * + * @author Binary Wang + */ +public interface WxCpMenuService { +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOauth2Service.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOauth2Service.java new file mode 100644 index 0000000000..af86f1ed4d --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOauth2Service.java @@ -0,0 +1,11 @@ +package me.chanjar.weixin.cp.api; + +/** + *
+ *  Created by BinaryWang on 2017/6/24.
+ * 
+ * + * @author Binary Wang + */ +public interface WxCpOauth2Service { +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 444fa98dea..52692090e1 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -9,6 +9,7 @@ import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.cp.bean.*; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import java.io.File; import java.io.IOException; @@ -33,16 +34,6 @@ public interface WxCpService { */ boolean checkSignature(String msgSignature, String timestamp, String nonce, String data); - /** - *
-   *   用在二次验证的时候
-   *   企业在员工验证成功后,调用本方法告诉企业号平台该员工关注成功。
-   * 
- * - * @param userId 用户id - */ - void userAuthenticated(String userId) throws WxErrorException; - /** * 获取access_token, 不强制刷新access_token * @@ -218,109 +209,77 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i WxMenu menuGet(Integer agentId) throws WxErrorException; /** - *
-   * 部门管理接口 - 创建部门
-   * 最多支持创建500个部门
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
-   * 
- * - * @param depart 部门 - * @return 部门id + * @deprecated 请使用 {@link WxCpDepartmentService#create(WxCpDepart depart) } */ + @Deprecated Integer departCreate(WxCpDepart depart) throws WxErrorException; /** - *
-   * 部门管理接口 - 查询所有部门
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
-   * 
- */ - List departGet() throws WxErrorException; - - /** - *
-   * 部门管理接口 - 修改部门名
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
-   * 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
-   * 
- * - * @param group 要更新的group,group的id,name必须设置 + * @deprecated 请使用 {@link WxCpDepartmentService#update(WxCpDepart group) } */ + @Deprecated void departUpdate(WxCpDepart group) throws WxErrorException; /** - *
-   * 部门管理接口 - 删除部门
-   * 
- * - * @param departId 部门id + * @deprecated 请使用 {@link WxCpDepartmentService#delete(Integer departId) } */ + @Deprecated void departDelete(Integer departId) throws WxErrorException; /** - *
-   * 获取部门成员(详情)
-   *
-   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98.28.E8.AF.A6.E6.83.85.29
-   * 
- * - * @param departId 必填。部门id - * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 - * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 + * @deprecated 请使用 {@link WxCpDepartmentService#listAll() } */ - List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + @Deprecated + List departGet() throws WxErrorException; /** - *
-   * 获取部门成员
-   *
-   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98
-   * 
- * - * @param departId 必填。部门id - * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 - * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 + * @deprecated 请使用 {@link WxCpUserService#authenticate(String userId) } */ - List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + @Deprecated + void userAuthenticated(String userId) throws WxErrorException; /** - * 新建用户 - * - * @param user 用户对象 + * @deprecated 请使用 {@link WxCpUserService#create(WxCpUser user) } */ + @Deprecated void userCreate(WxCpUser user) throws WxErrorException; /** - * 更新用户 - * - * @param user 用户对象 + * @deprecated 请使用 {@link WxCpUserService#update(WxCpUser user)} */ + @Deprecated void userUpdate(WxCpUser user) throws WxErrorException; /** - * 删除用户 - * - * @param userid 用户id + * @deprecated 请使用 {@link WxCpUserService#delete(String... userids) } */ + @Deprecated void userDelete(String userid) throws WxErrorException; /** - *
-   * 批量删除成员
-   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E6.89.B9.E9.87.8F.E5.88.A0.E9.99.A4.E6.88.90.E5.91.98
-   * 
- * - * @param userids 员工UserID列表。对应管理端的帐号 + * @deprecated 请使用 {@link WxCpUserService#delete(String[] userids) } */ + @Deprecated void userDelete(String[] userids) throws WxErrorException; /** - * 获取用户 - * - * @param userid 用户id + * @deprecated 请使用 {@link WxCpUserService#getById(String userid) } */ + @Deprecated WxCpUser userGet(String userid) throws WxErrorException; + /** + * @deprecated 请使用 {@link WxCpUserService#listByDepartment(Integer departId, Boolean fetchChild, Integer status) } + */ + @Deprecated + List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + + /** + * @deprecated 请使用 {@link WxCpUserService#listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) } + */ + @Deprecated + List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + /** * 创建标签 * @@ -560,4 +519,34 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i * @param wxConfigProvider 配置对象 */ void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider); + + /** + * 获取部门相关接口的服务类对象 + */ + WxCpDepartmentService getDepartmentService(); + + /** + * 获取媒体相关接口的服务类对象 + */ + WxCpMediaService getMediaService(); + + /** + * 获取菜单相关接口的服务类对象 + */ + WxCpMenuService getMenuService(); + + /** + * 获取Oauth2相关接口的服务类对象 + */ + WxCpOauth2Service getOauth2Service(); + + /** + * 获取标签相关接口的服务类对象 + */ + WxCpTagService getTagService(); + + /** + * 获取用户相关接口的服务类对象 + */ + WxCpUserService getUserService(); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java new file mode 100644 index 0000000000..d84f4c95aa --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java @@ -0,0 +1,11 @@ +package me.chanjar.weixin.cp.api; + +/** + *
+ *  Created by BinaryWang on 2017/6/24.
+ * 
+ * + * @author Binary Wang + */ +public interface WxCpTagService { +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java new file mode 100644 index 0000000000..49ef9134f5 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java @@ -0,0 +1,83 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.bean.WxCpUser; + +import java.util.List; + +/** + *
+ * 用户管理接口
+ *  Created by BinaryWang on 2017/6/24.
+ * 
+ * + * @author Binary Wang + */ +public interface WxCpUserService { + /** + *
+   *   用在二次验证的时候
+   *   企业在员工验证成功后,调用本方法告诉企业号平台该员工关注成功。
+   * 
+ * + * @param userId 用户id + */ + void authenticate(String userId) throws WxErrorException; + + /** + *
+   * 获取部门成员(详情)
+   *
+   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98.28.E8.AF.A6.E6.83.85.29
+   * 
+ * + * @param departId 必填。部门id + * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 + * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 + */ + List listByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + + /** + *
+   * 获取部门成员
+   *
+   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98
+   * 
+ * + * @param departId 必填。部门id + * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 + * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 + */ + List listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + + /** + * 新建用户 + * + * @param user 用户对象 + */ + void create(WxCpUser user) throws WxErrorException; + + /** + * 更新用户 + * + * @param user 用户对象 + */ + void update(WxCpUser user) throws WxErrorException; + + /** + *
+   * 删除用户/批量删除成员
+   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E6.89.B9.E9.87.8F.E5.88.A0.E9.99.A4.E6.88.90.E5.91.98
+   * 
+ * + * @param userIds 员工UserID列表。对应管理端的帐号 + */ + void delete(String... userIds) throws WxErrorException; + + /** + * 获取用户 + * + * @param userid 用户id + */ + WxCpUser getById(String userid) throws WxErrorException; +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java index 497832b36e..ac6fe8b2ed 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java @@ -15,9 +15,9 @@ import me.chanjar.weixin.common.util.fs.FileUtils; import me.chanjar.weixin.common.util.http.*; import me.chanjar.weixin.common.util.json.GsonHelper; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.api.*; import me.chanjar.weixin.cp.bean.*; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -30,9 +30,15 @@ import java.util.UUID; public abstract class AbstractWxCpServiceImpl implements WxCpService, RequestHttp { - protected final Logger log = LoggerFactory.getLogger(this.getClass()); + private WxCpUserService userService = new WxCpUserServiceImpl(this); + private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this); + private WxCpMediaService mediaService; + private WxCpMenuService menuService; + private WxCpOauth2Service oauth2Service; + private WxCpTagService tagService; + /** * 全局的是否正在刷新access token的锁 */ @@ -65,12 +71,6 @@ public boolean checkSignature(String msgSignature, String timestamp, String nonc } } - @Override - public void userAuthenticated(String userId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId; - get(url, null); - } - @Override public String getAccessToken() throws WxErrorException { return getAccessToken(false); @@ -134,11 +134,13 @@ public WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorExce } @Override + @Deprecated public void menuCreate(WxMenu menu) throws WxErrorException { menuCreate(this.configStorage.getAgentId(), menu); } @Override + @Deprecated public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" + agentId; @@ -146,22 +148,26 @@ public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException { } @Override + @Deprecated public void menuDelete() throws WxErrorException { menuDelete(this.configStorage.getAgentId()); } @Override + @Deprecated public void menuDelete(Integer agentId) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId; get(url, null); } @Override + @Deprecated public WxMenu menuGet() throws WxErrorException { return menuGet(this.configStorage.getAgentId()); } @Override + @Deprecated public WxMenu menuGet(Integer agentId) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId; try { @@ -177,18 +183,21 @@ public WxMenu menuGet(Integer agentId) throws WxErrorException { } @Override + @Deprecated public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException { return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); } @Override + @Deprecated public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; return execute(MediaUploadRequestExecutor.create(this), url, file); } @Override + @Deprecated public File mediaDownload(String mediaId) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; return execute( @@ -197,130 +206,56 @@ public File mediaDownload(String mediaId) throws WxErrorException { url, "media_id=" + mediaId); } - - @Override - public Integer departCreate(WxCpDepart depart) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; - String responseContent = execute( - SimplePostRequestExecutor.create(this), - url, - depart.toJson()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id")); - } - - @Override - public void departUpdate(WxCpDepart group) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update"; - post(url, group.toJson()); - } - @Override - public void departDelete(Integer departId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId; - get(url, null); - } - - @Override - public List departGet() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; - String responseContent = get(url, null); - /* - * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } - * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } - */ - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("department"), - new TypeToken>() { - }.getType() - ); + @Deprecated + public void userAuthenticated(String userId) throws WxErrorException { + this.getUserService().authenticate(userId); } @Override + @Deprecated public void userCreate(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; - post(url, user.toJson()); + this.getUserService().create(user); } @Override + @Deprecated public void userUpdate(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; - post(url, user.toJson()); + this.getUserService().update(user); } @Override + @Deprecated public void userDelete(String userid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userid; - get(url, null); + this.getUserService().delete(userid); } @Override + @Deprecated public void userDelete(String[] userids) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; - JsonObject jsonObject = new JsonObject(); - JsonArray jsonArray = new JsonArray(); - for (String userid : userids) { - jsonArray.add(new JsonPrimitive(userid)); - } - jsonObject.add("useridlist", jsonArray); - post(url, jsonObject.toString()); + this.getUserService().delete(userids); } @Override + @Deprecated public WxCpUser userGet(String userid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid; - String responseContent = get(url, null); - return WxCpUser.fromJson(responseContent); + return this.getUserService().getById(userid); } @Override + @Deprecated public List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; - String params = ""; - if (fetchChild != null) { - params += "&fetch_child=" + (fetchChild ? "1" : "0"); - } - if (status != null) { - params += "&status=" + status; - } else { - params += "&status=0"; - } - - String responseContent = get(url, params); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson(tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); + return this.getUserService().listByDepartment(departId, fetchChild, status); } @Override + @Deprecated public List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; - String params = ""; - if (fetchChild != null) { - params += "&fetch_child=" + (fetchChild ? "1" : "0"); - } - if (status != null) { - params += "&status=" + status; - } else { - params += "&status=0"; - } - - String responseContent = get(url, params); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); + return this.getUserService().listSimpleByDepartment(departId, fetchChild, status); } @Override + @Deprecated public String tagCreate(String tagName) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; JsonObject o = new JsonObject(); @@ -331,6 +266,7 @@ public String tagCreate(String tagName) throws WxErrorException { } @Override + @Deprecated public void tagUpdate(String tagId, String tagName) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; JsonObject o = new JsonObject(); @@ -340,12 +276,14 @@ public void tagUpdate(String tagId, String tagName) throws WxErrorException { } @Override + @Deprecated public void tagDelete(String tagId) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; get(url, null); } @Override + @Deprecated public List tagGet() throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; String responseContent = get(url, null); @@ -359,6 +297,7 @@ public List tagGet() throws WxErrorException { } @Override + @Deprecated public List tagGetUsers(String tagId) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; String responseContent = get(url, null); @@ -372,6 +311,7 @@ public List tagGetUsers(String tagId) throws WxErrorException { } @Override + @Deprecated public void tagAddUsers(String tagId, List userIds, List partyIds) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; JsonObject jsonObject = new JsonObject(); @@ -394,6 +334,7 @@ public void tagAddUsers(String tagId, List userIds, List partyId } @Override + @Deprecated public void tagRemoveUsers(String tagId, List userIds) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; JsonObject jsonObject = new JsonObject(); @@ -407,6 +348,7 @@ public void tagRemoveUsers(String tagId, List userIds) throws WxErrorExc } @Override + @Deprecated public String oauth2buildAuthorizationUrl(String state) { return this.oauth2buildAuthorizationUrl( this.configStorage.getOauth2redirectUri(), @@ -415,6 +357,7 @@ public String oauth2buildAuthorizationUrl(String state) { } @Override + @Deprecated public String oauth2buildAuthorizationUrl(String redirectUri, String state) { String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"; url += "appid=" + this.configStorage.getCorpId(); @@ -429,11 +372,13 @@ public String oauth2buildAuthorizationUrl(String redirectUri, String state) { } @Override + @Deprecated public String[] oauth2getUserInfo(String code) throws WxErrorException { return oauth2getUserInfo(this.configStorage.getAgentId(), code); } @Override + @Deprecated public String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?" + "code=" + code @@ -588,7 +533,6 @@ public WxSession getSession(String id, boolean create) { return this.sessionManager.getSession(id, create); } - @Override public void setSessionManager(WxSessionManager sessionManager) { this.sessionManager = sessionManager; @@ -624,4 +568,57 @@ public void setTmpDirFile(File tmpDirFile) { this.tmpDirFile = tmpDirFile; } + @Override + public WxCpDepartmentService getDepartmentService() { + return departmentService; + } + + @Override + public WxCpMediaService getMediaService() { + return mediaService; + } + + @Override + public WxCpMenuService getMenuService() { + return menuService; + } + + @Override + public WxCpOauth2Service getOauth2Service() { + return oauth2Service; + } + + @Override + public WxCpTagService getTagService() { + return tagService; + } + + @Override + public WxCpUserService getUserService() { + return userService; + } + + @Override + @Deprecated + public Integer departCreate(WxCpDepart depart) throws WxErrorException { + return this.getDepartmentService().create(depart); + } + + @Override + @Deprecated + public void departUpdate(WxCpDepart depart) throws WxErrorException { + this.getDepartmentService().update(depart); + } + + @Override + @Deprecated + public void departDelete(Integer departId) throws WxErrorException { + this.getDepartmentService().delete(departId); + } + + @Override + @Deprecated + public List departGet() throws WxErrorException { + return this.getDepartmentService().listAll(); + } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java new file mode 100644 index 0000000000..82cd8c345c --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java @@ -0,0 +1,65 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.api.WxCpDepartmentService; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpDepart; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; + +/** + *
+ *  部门管理接口
+ *  Created by BinaryWang on 2017/6/24.
+ * 
+ * + * @author Binary Wang + */ +public class WxCpDepartmentServiceImpl implements WxCpDepartmentService { + private WxCpService mainService; + + public WxCpDepartmentServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public Integer create(WxCpDepart depart) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; + String responseContent = this.mainService.post(url, depart.toJson()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id")); + } + + @Override + public void update(WxCpDepart group) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update"; + this.mainService.post(url, group.toJson()); + } + + @Override + public void delete(Integer departId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId; + this.mainService.get(url, null); + } + + @Override + public List listAll() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; + String responseContent = this.mainService.get(url, null); + /* + * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } + * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } + */ + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson(tmpJsonElement.getAsJsonObject().get("department"), + new TypeToken>() { + }.getType() + ); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java index fecb26464f..9c87ccbd41 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java @@ -7,8 +7,8 @@ import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.impl.AbstractWxCpServiceImpl; +import me.chanjar.weixin.cp.bean.WxCpDepart; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -17,6 +17,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import java.io.IOException; +import java.util.List; public class WxCpServiceApacheHttpClientImpl extends AbstractWxCpServiceImpl { protected CloseableHttpClient httpClient; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java index 5ceabd0c64..3000916fac 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java @@ -5,8 +5,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.impl.AbstractWxCpServiceImpl; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; public class WxCpServiceJoddHttpImpl extends AbstractWxCpServiceImpl { protected HttpConnectionProvider httpClient; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java index 11411cdafc..4dd66d9d86 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java @@ -5,8 +5,7 @@ import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.impl.AbstractWxCpServiceImpl; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import okhttp3.*; import java.io.IOException; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java new file mode 100644 index 0000000000..c49c1ffd69 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java @@ -0,0 +1,118 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.api.WxCpUserService; +import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; + +/** + *
+ *  Created by BinaryWang on 2017/6/24.
+ * 
+ * + * @author Binary Wang + */ +public class WxCpUserServiceImpl implements WxCpUserService { + private WxCpService mainService; + + public WxCpUserServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public void authenticate(String userId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId; + this.mainService.get(url, null); + } + + @Override + public void create(WxCpUser user) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; + this.mainService.post(url, user.toJson()); + } + + @Override + public void update(WxCpUser user) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; + this.mainService.post(url, user.toJson()); + } + + public void deleteOne(String userId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userId; + this.mainService.get(url, null); + } + + @Override + public void delete(String... userIds) throws WxErrorException { + if (userIds.length == 1) { + this.deleteOne(userIds[0]); + } + + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; + JsonObject jsonObject = new JsonObject(); + JsonArray jsonArray = new JsonArray(); + for (String userid : userIds) { + jsonArray.add(new JsonPrimitive(userid)); + } + jsonObject.add("useridlist", jsonArray); + this.mainService.post(url, jsonObject.toString()); + } + + @Override + public WxCpUser getById(String userid) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid; + String responseContent = this.mainService.get(url, null); + return WxCpUser.fromJson(responseContent); + } + + @Override + public List listByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; + String params = ""; + if (fetchChild != null) { + params += "&fetch_child=" + (fetchChild ? "1" : "0"); + } + if (status != null) { + params += "&status=" + status; + } else { + params += "&status=0"; + } + + String responseContent = this.mainService.get(url, params); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson(tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public List listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; + String params = ""; + if (fetchChild != null) { + params += "&fetch_child=" + (fetchChild ? "1" : "0"); + } + if (status != null) { + params += "&status=" + status; + } else { + params += "&status=0"; + } + + String responseContent = this.mainService.get(url, params); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java index 3c0f50b883..8b7ee5f166 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java @@ -3,7 +3,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamConverter; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; import me.chanjar.weixin.cp.util.xml.XStreamTransformer; import org.apache.commons.io.IOUtils; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java index 0d90a012c7..d69703502f 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java @@ -3,7 +3,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamConverter; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import me.chanjar.weixin.cp.bean.outxmlbuilder.*; import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; import me.chanjar.weixin.cp.util.xml.XStreamTransformer; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java index 2b2dfe4715..770ef82797 100755 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java @@ -22,7 +22,7 @@ package me.chanjar.weixin.cp.util.crypto; import me.chanjar.weixin.common.util.crypto.WxCryptUtil; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import org.apache.commons.codec.binary.Base64; public class WxCpCryptUtil extends WxCryptUtil { diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java index 1c3fd5e7ea..ca4bc636fa 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java @@ -6,6 +6,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.config.WxCpInMemoryConfigStorage; import java.io.IOException; import java.io.InputStream; @@ -25,10 +27,10 @@ public void configure(Binder binder) { .getSystemResourceAsStream("test-config.xml")) { WxXmlCpInMemoryConfigStorage config = fromXml( WxXmlCpInMemoryConfigStorage.class, is1); - WxCpServiceImpl wxService = new WxCpServiceImpl(); + WxCpService wxService = new WxCpServiceImpl(); wxService.setWxCpConfigStorage(config); - binder.bind(WxCpServiceImpl.class).toInstance(wxService); + binder.bind(WxCpService.class).toInstance(wxService); binder.bind(WxCpConfigStorage.class).toInstance(config); } catch (IOException e) { e.printStackTrace(); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java index a778046a9b..b535634a45 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java @@ -3,6 +3,7 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import org.apache.commons.lang3.StringUtils; import org.testng.Assert; import org.testng.annotations.Guice; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java index 678893659c..e52101f508 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java @@ -3,6 +3,9 @@ import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.session.StandardSessionManager; import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.message.WxCpMessageHandler; +import me.chanjar.weixin.cp.message.WxCpMessageMatcher; +import me.chanjar.weixin.cp.message.WxCpMessageRouter; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; import org.testng.Assert; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java index 761b1a910f..cb743f3d94 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java @@ -4,6 +4,7 @@ import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; import me.chanjar.weixin.cp.bean.WxCpTag; import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java deleted file mode 100644 index c93cb884c1..0000000000 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java +++ /dev/null @@ -1,76 +0,0 @@ -package me.chanjar.weixin.cp.api; - -import com.google.inject.Inject; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; -import me.chanjar.weixin.cp.bean.WxCpUser; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import org.testng.Assert; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import java.util.List; - -import static org.testng.Assert.assertNotEquals; - -/** - * 测试用户接口 - * - * @author Daniel Qian - */ -@Test(groups = "userAPI") -@Guice(modules = ApiTestModule.class) -public class WxCpUserAPITest { - - @Inject - protected WxCpServiceImpl wxCpService; - - public void testUserCreate() throws WxErrorException { - WxCpUser user = new WxCpUser(); - user.setUserId("some.woman"); - user.setName("Some Woman"); - user.setDepartIds(new Integer[]{9, 8}); - user.setEmail("none@none.com"); - user.setGender("女"); - user.setMobile("13560084979"); - user.setPosition("woman"); - user.setTelephone("3300393"); - user.addExtAttr("爱好", "table"); - this.wxCpService.userCreate(user); - } - - @Test(dependsOnMethods = "testUserCreate") - public void testUserUpdate() throws WxErrorException { - WxCpUser user = new WxCpUser(); - user.setUserId("some.woman"); - user.setName("Some Woman"); - user.addExtAttr("爱好", "table2"); - this.wxCpService.userUpdate(user); - } - - @Test(dependsOnMethods = "testUserUpdate") - public void testUserGet() throws WxErrorException { - WxCpUser user = this.wxCpService.userGet("some.woman"); - Assert.assertNotNull(user); - } - - @Test(dependsOnMethods = "testUserGet") - public void testDepartGetUsers() throws WxErrorException { - List users = this.wxCpService.departGetUsers(1, true, 0); - assertNotEquals(users.size(), 0); - } - - @Test(dependsOnMethods = "testDepartGetUsers") - public void testUserDelete() throws WxErrorException { - this.wxCpService.userDelete("some.woman"); - } - - public void testUserList() throws WxErrorException { - List users = this.wxCpService.userList(1, true, 0); - assertNotEquals(users.size(), 0); - for (WxCpUser user : users) { - System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); - } - } -} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java new file mode 100644 index 0000000000..685f37444f --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpDepart; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.List; + +import static org.testng.Assert.*; + +/** + *
+ *  Created by BinaryWang on 2017/6/24.
+ * 
+ * + * @author Binary Wang + */ +@Guice(modules = ApiTestModule.class) +public class WxCpDepartmentServiceImplTest { + @Inject + private WxCpService wxCpService; + + private WxCpDepart depart; + + @Test + public void testCreate() throws Exception { + WxCpDepart cpDepart = new WxCpDepart(); + cpDepart.setName("子部门" + System.currentTimeMillis()); + cpDepart.setParentId(1); + cpDepart.setOrder(1); + Integer departId = this.wxCpService.getDepartmentService().create(cpDepart); + System.out.println(departId); + } + + @Test + public void testListAll() throws Exception { + System.out.println("=================获取部门"); + List departList = this.wxCpService.getDepartmentService().listAll(); + assertNotNull(departList); + assertTrue(departList.size() > 0); + for (WxCpDepart g : departList) { + this.depart = g; + System.out.println(this.depart.getId() + ":" + this.depart.getName()); + assertNotNull(g.getName()); + } + } + + @Test(dependsOnMethods = {"testListAll", "testCreate"}) + public void testUpdate() throws Exception { + System.out.println("=================更新部门"); + this.depart.setName("子部门改名" + System.currentTimeMillis()); + this.wxCpService.getDepartmentService().update(this.depart); + } + + @Test(dependsOnMethods = "testUpdate") + public void testDelete() throws Exception { + System.out.println("=================删除部门"); + System.out.println(this.depart.getId() + ":" + this.depart.getName()); + this.wxCpService.getDepartmentService().delete(this.depart.getId()); + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java new file mode 100644 index 0000000000..d576b866f5 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java @@ -0,0 +1,86 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpUser; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.testng.Assert; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.List; + +import static org.testng.Assert.*; + +/** + *
+ *  Created by BinaryWang on 2017/6/24.
+ * 
+ * + * @author Binary Wang + */ +@Guice(modules = ApiTestModule.class) +public class WxCpUserServiceImplTest { + @Inject + private WxCpService wxCpService; + + @Test + public void testAuthenticate() throws Exception { + } + + @Test + public void testCreate() throws Exception { + WxCpUser user = new WxCpUser(); + user.setUserId("some.woman"); + user.setName("Some Woman"); + user.setDepartIds(new Integer[]{9, 8}); + user.setEmail("none@none.com"); + user.setGender("女"); + user.setMobile("13560084979"); + user.setPosition("woman"); + user.setTelephone("3300393"); + user.addExtAttr("爱好", "table"); + this.wxCpService.getUserService().create(user); + } + + @Test(dependsOnMethods = "testCreate") + public void testUpdate() throws Exception { + WxCpUser user = new WxCpUser(); + user.setUserId("some.woman"); + user.setName("Some Woman"); + user.addExtAttr("爱好", "table2"); + this.wxCpService.getUserService().update(user); + } + + @Test + public void testDelete() throws Exception { + this.wxCpService.getUserService().delete("some.woman"); + } + + @Test(dependsOnMethods = "testUpdate") + public void testGetById() throws Exception { + WxCpUser user = this.wxCpService.getUserService().getById("some.woman"); + assertNotNull(user); + } + + @Test + public void testListByDepartment() throws Exception { + List users = this.wxCpService.getUserService().listByDepartment(1, true, 0); + assertNotEquals(users.size(), 0); + for (WxCpUser user : users) { + System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); + } + } + + @Test + public void testListSimpleByDepartment() throws Exception { + List users = this.wxCpService.getUserService().listSimpleByDepartment(1, true, 0); + assertNotEquals(users.size(), 0); + for (WxCpUser user : users) { + System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); + } + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java index 4171119be1..93ff1bbc0a 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java @@ -3,7 +3,7 @@ import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.util.xml.XStreamInitializer; -import me.chanjar.weixin.cp.api.WxCpInMemoryConfigStorage; +import me.chanjar.weixin.cp.config.WxCpInMemoryConfigStorage; import java.io.InputStream; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java index 9c9b50c161..e9d78768f2 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java @@ -1,9 +1,9 @@ package me.chanjar.weixin.cp.demo; import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.WxCpMessageHandler; -import me.chanjar.weixin.cp.api.WxCpMessageRouter; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.message.WxCpMessageHandler; +import me.chanjar.weixin.cp.message.WxCpMessageRouter; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java index dec6faee6a..291cef403d 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.cp.demo; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.WxCpMessageRouter; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.message.WxCpMessageRouter; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; From e6c80100c358e0f93c452b17458f180c373ef460 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 25 Jun 2017 17:35:52 +0800 Subject: [PATCH 102/179] =?UTF-8?q?=E6=B8=85=E7=90=86=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/impl/AbstractWxMpServiceImpl.java | 5 +++++ .../mp/api/impl/WxMpServiceApacheHttpClientImpl.java | 6 ------ .../weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java | 7 ------- .../chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java | 7 ------- 4 files changed, 5 insertions(+), 20 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java index f5e4a91f9c..750ec44e0d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java @@ -400,4 +400,9 @@ public WxMpDeviceService getDeviceService() { public WxMpShakeService getShakeService(){ return this.shakeService; } + + @Override + public RequestHttp getRequestHttp() { + return this; + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java index 8e7d6da779..d929b0974c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java @@ -4,7 +4,6 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; -import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; import me.chanjar.weixin.mp.api.WxMpConfigStorage; @@ -61,11 +60,6 @@ public void initHttp() { this.httpClient = apacheHttpClientBuilder.build(); } - @Override - public RequestHttp getRequestHttp() { - return this; - } - @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java index bd4a525b6d..5c0fb75300 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java @@ -6,7 +6,6 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; -import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; @@ -46,12 +45,6 @@ public void initHttp() { httpClient = JoddHttp.httpConnectionProvider; } - @Override - public RequestHttp getRequestHttp() { - return this; - } - - @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java index fbf44cb87c..81fb848909 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java @@ -4,7 +4,6 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; -import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; @@ -94,10 +93,4 @@ public void initHttp() { httpClient = new ConnectionPool(); } - @Override - public RequestHttp getRequestHttp() { - return this; - } - - } From 17d65ee3a0eef51ec310115bf72b99093ab1413d Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 25 Jun 2017 17:50:53 +0800 Subject: [PATCH 103/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mp/api/impl/WxMpMenuServiceImplTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java index dac37f266f..8846809001 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java @@ -138,7 +138,7 @@ public void testMenuGet() throws WxErrorException { System.out.println(wxMenu.toJson()); } - @Test(dependsOnMethods = {"testMenuGet"}) + @Test(dependsOnMethods = {"testMenuGet","testMenuCreate"}) public void testMenuDelete() throws WxErrorException { this.wxService.getMenuService().menuDelete(); } @@ -151,18 +151,18 @@ public Object[][] getMenu() { button1.setName("今日歌曲"); button1.setKey("V1001_TODAY_MUSIC"); - WxMenuButton button2 = new WxMenuButton(); - button2.setType(WxConsts.BUTTON_MINIPROGRAM); - button2.setName("小程序"); - button2.setAppId("wx286b93c14bbf93aa"); - button2.setPagePath("pages/lunar/index.html"); - button2.setUrl("http://mp.weixin.qq.com"); +// WxMenuButton button2 = new WxMenuButton(); +// button2.setType(WxConsts.BUTTON_MINIPROGRAM); +// button2.setName("小程序"); +// button2.setAppId("wx286b93c14bbf93aa"); +// button2.setPagePath("pages/lunar/index.html"); +// button2.setUrl("http://mp.weixin.qq.com"); WxMenuButton button3 = new WxMenuButton(); button3.setName("菜单"); menu.getButtons().add(button1); - menu.getButtons().add(button2); +// menu.getButtons().add(button2); menu.getButtons().add(button3); WxMenuButton button31 = new WxMenuButton(); From 0f0f7bb0a309fd6140966cb08b62c19ecb205a47 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 25 Jun 2017 17:51:35 +0800 Subject: [PATCH 104/179] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java index 750ec44e0d..9dc1d755dd 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java @@ -286,7 +286,7 @@ public synchronized T executeInternal(RequestExecutor executor, Str try { T result = executor.execute(uriWithAccessToken, data); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, result); + this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, data, result); return result; } catch (WxErrorException e) { WxError error = e.getError(); @@ -305,12 +305,12 @@ public synchronized T executeInternal(RequestExecutor executor, Str } if (error.getErrorCode() != 0) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, error); + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, data, error); throw new WxErrorException(error); } return null; } catch (IOException e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uriWithAccessToken, data, e.getMessage()); + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, data, e.getMessage()); throw new RuntimeException(e); } } From 9f4a7a779669fee630c1f1d8a9fe7664df196e5f Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 25 Jun 2017 18:35:21 +0800 Subject: [PATCH 105/179] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=8F=B7=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=E4=BA=86=E5=8D=87=E7=BA=A7=E4=BC=81?= =?UTF-8?q?=E4=B8=9A=E5=BE=AE=E4=BF=A1=E5=90=8E=E5=87=BA=E7=8E=B0=E7=9A=84?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E9=97=AE=E9=A2=98=E5=92=8C=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/json/WxMenuGsonAdapter.java | 7 +- .../weixin/cp/api/WxCpMediaService.java | 46 ++++ .../weixin/cp/api/WxCpMenuService.java | 80 ++++++ .../weixin/cp/api/WxCpOAuth2Service.java | 67 +++++ .../weixin/cp/api/WxCpOauth2Service.java | 11 - .../me/chanjar/weixin/cp/api/WxCpService.java | 253 ++++++------------ .../chanjar/weixin/cp/api/WxCpTagService.java | 55 ++++ .../cp/api/impl/AbstractWxCpServiceImpl.java | 167 +++--------- .../cp/api/impl/WxCpMediaServiceImpl.java | 50 ++++ .../cp/api/impl/WxCpMenuServiceImpl.java | 64 +++++ .../cp/api/impl/WxCpOAuth2ServiceImpl.java | 66 +++++ .../impl/WxCpServiceApacheHttpClientImpl.java | 3 +- .../cp/api/impl/WxCpTagServiceImpl.java | 116 ++++++++ .../bean/WxCpTagAddOrRemoveUsersResult.java | 85 ++++++ .../me/chanjar/weixin/cp/bean/WxCpUser.java | 39 ++- .../weixin/cp/util/json/WxCpGsonBuilder.java | 2 + .../cp/util/json/WxCpMenuGsonAdapter.java | 24 ++ .../cp/util/json/WxCpUserGsonAdapter.java | 4 +- .../chanjar/weixin/cp/api/ApiTestModule.java | 2 +- .../weixin/cp/api/WxCpMediaAPITest.java | 77 ------ .../chanjar/weixin/cp/api/WxCpTagAPITest.java | 68 ----- .../cp/api/impl/WxCpMediaServiceImplTest.java | 78 ++++++ .../WxCpMenuServiceImplTest.java} | 60 ++--- .../cp/api/impl/WxCpTagServiceImplTest.java | 75 ++++++ .../cp/api/impl/WxCpUserServiceImplTest.java | 20 +- .../weixin/cp/demo/WxCpDemoServer.java | 9 +- .../weixin/cp/demo/WxCpOAuth2Servlet.java | 2 +- weixin-java-cp/src/test/resources/mm.amr | Bin 0 -> 38982 bytes weixin-java-cp/src/test/resources/testng.xml | 5 - 29 files changed, 1022 insertions(+), 513 deletions(-) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java delete mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOauth2Service.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMenuGsonAdapter.java delete mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java delete mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java create mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java rename weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/{WxMenuAPITest.java => impl/WxCpMenuServiceImplTest.java} (62%) create mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java create mode 100644 weixin-java-cp/src/test/resources/mm.amr diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java index 526b5f29c9..c506c1ed75 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java @@ -90,9 +90,14 @@ public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon * 操蛋的微信 * 创建菜单时是 { button : ... } * 查询菜单时是 { menu : { button : ... } } + * 现在企业号升级为企业微信后,没有此问题,因此需要单独处理 */ - WxMenu menu = new WxMenu(); JsonArray buttonsJson = json.getAsJsonObject().get("menu").getAsJsonObject().get("button").getAsJsonArray(); + return this.buildMenuFromJson(buttonsJson); + } + + protected WxMenu buildMenuFromJson(JsonArray buttonsJson) { + WxMenu menu = new WxMenu(); for (int i = 0; i < buttonsJson.size(); i++) { JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject(); WxMenuButton button = convertFromJson(buttonJson); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java index ba0241a629..f813f1bf3f 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java @@ -1,11 +1,57 @@ package me.chanjar.weixin.cp.api; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + /** *
+ *  媒体管理接口
  *  Created by BinaryWang on 2017/6/24.
  * 
* * @author Binary Wang */ public interface WxCpMediaService { + + /** + *
+   * 上传多媒体文件
+   * 上传的多媒体文件有格式和大小限制,如下:
+   *   图片(image): 1M,支持JPG格式
+   *   语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
+   *   视频(video):10MB,支持MP4格式
+   *   缩略图(thumb):64KB,支持JPG格式
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
+   * 
+ * + * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} + * @param fileType 文件类型,请看{@link me.chanjar.weixin.common.api.WxConsts} + * @param inputStream 输入流 + */ + WxMediaUploadResult upload(String mediaType, String fileType, InputStream inputStream) + throws WxErrorException, IOException; + + /** + * @param mediaType 媒体类型 + * @param file 文件对象 + * @see #upload(String, String, InputStream) + */ + WxMediaUploadResult upload(String mediaType, File file) throws WxErrorException; + + /** + *
+   * 下载多媒体文件
+   * 根据微信文档,视频文件下载不了,会返回null
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
+   * 
+ * + * @param mediaId 媒体id + * @return 保存到本地的临时文件 + */ + File download(String mediaId) throws WxErrorException; + } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java index f6a45e4352..012efefb7f 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java @@ -1,11 +1,91 @@ package me.chanjar.weixin.cp.api; +import me.chanjar.weixin.common.bean.menu.WxMenu; +import me.chanjar.weixin.common.exception.WxErrorException; + /** *
+ *  菜单管理相关接口
  *  Created by BinaryWang on 2017/6/24.
  * 
* * @author Binary Wang */ public interface WxCpMenuService { + /** + *
+   * 自定义菜单创建接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
+   *
+   * 注意: 这个方法使用WxCpConfigStorage里的agentId
+   * 
+ * + * @param menu 菜单对象 + * @see #create(Integer, WxMenu) + */ + void create(WxMenu menu) throws WxErrorException; + + /** + *
+   * 自定义菜单创建接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
+   *
+   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
+   * 
+ * + * @param agentId 企业号应用的id + * @param menu 菜单对象 + * @see #create(me.chanjar.weixin.common.bean.menu.WxMenu) + */ + void create(Integer agentId, WxMenu menu) throws WxErrorException; + + /** + *
+   * 自定义菜单删除接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
+   *
+   * 注意: 这个方法使用WxCpConfigStorage里的agentId
+   * 
+ * + * @see #delete(Integer) + */ + void delete() throws WxErrorException; + + /** + *
+   * 自定义菜单删除接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
+   *
+   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
+   * 
+ * + * @param agentId 企业号应用的id + * @see #delete() + */ + void delete(Integer agentId) throws WxErrorException; + + /** + *
+   * 自定义菜单查询接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
+   *
+   * 注意: 这个方法使用WxCpConfigStorage里的agentId
+   * 
+ * + * @see #get(Integer) + */ + WxMenu get() throws WxErrorException; + + /** + *
+   * 自定义菜单查询接口
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
+   *
+   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
+   * 
+ * + * @param agentId 企业号应用的id + * @see #get() + */ + WxMenu get(Integer agentId) throws WxErrorException; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java new file mode 100644 index 0000000000..3312489538 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java @@ -0,0 +1,67 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + *
+ * OAuth2相关管理接口
+ *  Created by BinaryWang on 2017/6/24.
+ * 
+ * + * @author Binary Wang + */ +public interface WxCpOAuth2Service { + /** + *
+   * 构造oauth2授权的url连接
+   * 
+ * + * @param state 状态码 + * @return url + */ + String buildAuthorizationUrl(String state); + + /** + *
+   * 构造oauth2授权的url连接
+   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=企业获取code
+   * 
+ * + * @param redirectUri 跳转链接地址 + * @param state 状态码 + * @return url + */ + String buildAuthorizationUrl(String redirectUri, String state); + + /** + *
+   * 用oauth2获取用户信息
+   * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息
+   * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。
+   *
+   * 注意: 这个方法使用WxCpConfigStorage里的agentId
+   * 
+ * + * @param code 微信oauth授权返回的代码 + * @return [userid, deviceid] + * @see #getUserInfo(Integer, String) + */ + String[] getUserInfo(String code) throws WxErrorException; + + /** + *
+   * 用oauth2获取用户信息
+   * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息
+   * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。
+   *
+   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
+   * 
+ * + * @param agentId 企业号应用的id + * @param code 微信oauth授权返回的代码 + * @return [userid, deviceid] + * @see #getUserInfo(String) + */ + String[] getUserInfo(Integer agentId, String code) throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOauth2Service.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOauth2Service.java deleted file mode 100644 index af86f1ed4d..0000000000 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOauth2Service.java +++ /dev/null @@ -1,11 +0,0 @@ -package me.chanjar.weixin.cp.api; - -/** - *
- *  Created by BinaryWang on 2017/6/24.
- * 
- * - * @author Binary Wang - */ -public interface WxCpOauth2Service { -} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 52692090e1..880a92b06e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -8,6 +8,7 @@ import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.cp.bean.*; import me.chanjar.weixin.cp.config.WxCpConfigStorage; @@ -85,305 +86,208 @@ public interface WxCpService { WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; /** - *
-   * 上传多媒体文件
-   * 上传的多媒体文件有格式和大小限制,如下:
-   *   图片(image): 1M,支持JPG格式
-   *   语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
-   *   视频(video):10MB,支持MP4格式
-   *   缩略图(thumb):64KB,支持JPG格式
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
-   * 
- * - * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} - * @param fileType 文件类型,请看{@link me.chanjar.weixin.common.api.WxConsts} - * @param inputStream 输入流 + * @deprecated 请使用 {@link WxCpMenuService#create(WxMenu)} */ - WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) - throws WxErrorException, IOException; + @Deprecated + void menuCreate(WxMenu menu) throws WxErrorException; /** - * @param mediaType 媒体类型 - * @param file 文件对象 - * @see #mediaUpload(String, String, InputStream) + * @deprecated 请使用 {@link WxCpMenuService#create(Integer, WxMenu)} */ - WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException; + @Deprecated + void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException; /** - *
-   * 下载多媒体文件
-   * 根据微信文档,视频文件下载不了,会返回null
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
-   * 
- * - * @param mediaId 媒体id - * @return 保存到本地的临时文件 + * @deprecated 请使用 {@link WxCpMenuService#delete()} } */ - File mediaDownload(String mediaId) throws WxErrorException; + @Deprecated + void menuDelete() throws WxErrorException; /** - *
-   * 发送消息
-   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E
-   * 
- * - * @param message 要发送的消息对象 + * @deprecated 请使用 {@link WxCpMenuService#delete(Integer)} */ - WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorException; + @Deprecated + void menuDelete(Integer agentId) throws WxErrorException; /** - *
-   * 自定义菜单创建接口
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
-   *
-   * 注意: 这个方法使用WxCpConfigStorage里的agentId
-   * 
- * - * @param menu 菜单对象 - * @see #menuCreate(Integer, WxMenu) + * @deprecated 请使用 {@link WxCpMenuService#get() } */ - void menuCreate(WxMenu menu) throws WxErrorException; + @Deprecated + WxMenu menuGet() throws WxErrorException; /** - *
-   * 自定义菜单创建接口
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
-   *
-   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
-   * 
- * - * @param agentId 企业号应用的id - * @param menu 菜单对象 - * @see #menuCreate(me.chanjar.weixin.common.bean.menu.WxMenu) + * @deprecated 请使用 {@link WxCpMenuService#get(Integer)} */ - void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException; + @Deprecated + WxMenu menuGet(Integer agentId) throws WxErrorException; /** *
-   * 自定义菜单删除接口
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
-   *
-   * 注意: 这个方法使用WxCpConfigStorage里的agentId
+   * 发送消息
+   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E
    * 
* - * @see #menuDelete(Integer) + * @param message 要发送的消息对象 */ - void menuDelete() throws WxErrorException; + WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorException; /** - *
-   * 自定义菜单删除接口
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
-   *
-   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
-   * 
- * - * @param agentId 企业号应用的id - * @see #menuDelete() + * @deprecated 请使用 {@link WxCpDepartmentService#create(WxCpDepart)} */ - void menuDelete(Integer agentId) throws WxErrorException; + @Deprecated + Integer departCreate(WxCpDepart depart) throws WxErrorException; /** - *
-   * 自定义菜单查询接口
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
-   *
-   * 注意: 这个方法使用WxCpConfigStorage里的agentId
-   * 
- * - * @see #menuGet(Integer) + * @deprecated 请使用 {@link WxCpDepartmentService#update(WxCpDepart)} */ - WxMenu menuGet() throws WxErrorException; + @Deprecated + void departUpdate(WxCpDepart group) throws WxErrorException; /** - *
-   * 自定义菜单查询接口
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
-   *
-   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
-   * 
- * - * @param agentId 企业号应用的id - * @see #menuGet() + * @deprecated 请使用 {@link WxCpDepartmentService#delete(Integer)} */ - WxMenu menuGet(Integer agentId) throws WxErrorException; + @Deprecated + void departDelete(Integer departId) throws WxErrorException; /** - * @deprecated 请使用 {@link WxCpDepartmentService#create(WxCpDepart depart) } + * @deprecated 请使用 {@link WxCpDepartmentService#listAll() } */ @Deprecated - Integer departCreate(WxCpDepart depart) throws WxErrorException; + List departGet() throws WxErrorException; /** - * @deprecated 请使用 {@link WxCpDepartmentService#update(WxCpDepart group) } + * @deprecated 请使用 {@link WxCpMediaService#upload(String, String, InputStream)} */ @Deprecated - void departUpdate(WxCpDepart group) throws WxErrorException; + WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) + throws WxErrorException, IOException; /** - * @deprecated 请使用 {@link WxCpDepartmentService#delete(Integer departId) } + * @deprecated 请使用 {@link WxCpMediaService#upload(String, File)} */ @Deprecated - void departDelete(Integer departId) throws WxErrorException; + WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException; /** - * @deprecated 请使用 {@link WxCpDepartmentService#listAll() } + * @deprecated 请使用 {@link WxCpMediaService#download(String)} */ @Deprecated - List departGet() throws WxErrorException; + File mediaDownload(String mediaId) throws WxErrorException; /** - * @deprecated 请使用 {@link WxCpUserService#authenticate(String userId) } + * @deprecated 请使用 {@link WxCpUserService#authenticate(String)} */ @Deprecated void userAuthenticated(String userId) throws WxErrorException; /** - * @deprecated 请使用 {@link WxCpUserService#create(WxCpUser user) } + * @deprecated 请使用 {@link WxCpUserService#create(WxCpUser)} */ @Deprecated void userCreate(WxCpUser user) throws WxErrorException; /** - * @deprecated 请使用 {@link WxCpUserService#update(WxCpUser user)} + * @deprecated 请使用 {@link WxCpUserService#update(WxCpUser)} */ @Deprecated void userUpdate(WxCpUser user) throws WxErrorException; /** - * @deprecated 请使用 {@link WxCpUserService#delete(String... userids) } + * @deprecated 请使用 {@link WxCpUserService#delete(String...)} */ @Deprecated void userDelete(String userid) throws WxErrorException; /** - * @deprecated 请使用 {@link WxCpUserService#delete(String[] userids) } + * @deprecated 请使用 {@link WxCpUserService#delete(String...)} */ @Deprecated void userDelete(String[] userids) throws WxErrorException; /** - * @deprecated 请使用 {@link WxCpUserService#getById(String userid) } + * @deprecated 请使用 {@link WxCpUserService#getById(String)} */ @Deprecated WxCpUser userGet(String userid) throws WxErrorException; /** - * @deprecated 请使用 {@link WxCpUserService#listByDepartment(Integer departId, Boolean fetchChild, Integer status) } + * @deprecated 请使用 {@link WxCpUserService#listByDepartment(Integer, Boolean, Integer)} */ @Deprecated List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; /** - * @deprecated 请使用 {@link WxCpUserService#listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) } + * @deprecated 请使用 {@link WxCpUserService#listSimpleByDepartment(Integer, Boolean, Integer)} */ @Deprecated List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; /** - * 创建标签 - * - * @param tagName 标签名 + * @deprecated 请使用 {@link WxCpTagService#create(String)} */ + @Deprecated String tagCreate(String tagName) throws WxErrorException; /** - * 更新标签 - * - * @param tagId 标签id - * @param tagName 标签名 + * @deprecated 请使用 {@link WxCpTagService#update(String, String)} */ + @Deprecated void tagUpdate(String tagId, String tagName) throws WxErrorException; /** - * 删除标签 - * - * @param tagId 标签id + * @deprecated 请使用 {@link WxCpTagService#delete(String)} */ + @Deprecated void tagDelete(String tagId) throws WxErrorException; /** - * 获得标签列表 + * @deprecated 请使用 {@link WxCpTagService#listAll()} */ + @Deprecated List tagGet() throws WxErrorException; /** - * 获取标签成员 - * - * @param tagId 标签ID + * @deprecated 请使用 {@link WxCpTagService#listUsersByTagId(String)} */ + @Deprecated List tagGetUsers(String tagId) throws WxErrorException; /** - * 增加标签成员 - * - * @param tagId 标签id - * @param userIds 用户ID 列表 + * @deprecated 请使用 {@link WxCpTagService#addUsers2Tag(String, List, List)} */ + @Deprecated void tagAddUsers(String tagId, List userIds, List partyIds) throws WxErrorException; /** - *
-   * 构造oauth2授权的url连接
-   * 
- * - * @param state 状态码 - * @return url + * @deprecated 请使用 {@link WxCpTagService#removeUsersFromTag(String, List)} + */ + @Deprecated + void tagRemoveUsers(String tagId, List userIds) throws WxErrorException; + + /** + * @deprecated 请使用 {@link WxCpOAuth2Service#buildAuthorizationUrl(String)} */ + @Deprecated String oauth2buildAuthorizationUrl(String state); /** - *
-   * 构造oauth2授权的url连接
-   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=企业获取code
-   * 
- * - * @param redirectUri 跳转链接地址 - * @param state 状态码 - * @return url + * @deprecated 请使用 {@link WxCpOAuth2Service#buildAuthorizationUrl(String, String)} */ + @Deprecated String oauth2buildAuthorizationUrl(String redirectUri, String state); /** - *
-   * 用oauth2获取用户信息
-   * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息
-   * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。
-   *
-   * 注意: 这个方法使用WxCpConfigStorage里的agentId
-   * 
- * - * @param code 微信oauth授权返回的代码 - * @return [userid, deviceid] - * @see #oauth2getUserInfo(Integer, String) + * @deprecated 请使用 {@link WxCpOAuth2Service#getUserInfo(String)} */ + @Deprecated String[] oauth2getUserInfo(String code) throws WxErrorException; /** - *
-   * 用oauth2获取用户信息
-   * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息
-   * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。
-   *
-   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
-   * 
- * - * @param agentId 企业号应用的id - * @param code 微信oauth授权返回的代码 - * @return [userid, deviceid] - * @see #oauth2getUserInfo(String) + * @deprecated 请使用 {@link WxCpOAuth2Service#getUserInfo(Integer, String)} */ + @Deprecated String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException; - - /** - * 移除标签成员 - * - * @param tagId 标签id - * @param userIds 用户id列表 - */ - void tagRemoveUsers(String tagId, List userIds) throws WxErrorException; - /** *
    * 邀请成员关注
@@ -538,7 +442,7 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i
   /**
    * 获取Oauth2相关接口的服务类对象
    */
-  WxCpOauth2Service getOauth2Service();
+  WxCpOAuth2Service getOauth2Service();
 
   /**
    * 获取标签相关接口的服务类对象
@@ -549,4 +453,9 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i
    * 获取用户相关接口的服务类对象
    */
   WxCpUserService getUserService();
+
+  /**
+   * http请求对象
+   */
+  RequestHttp getRequestHttp();
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
index d84f4c95aa..c96318b80b 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
@@ -1,11 +1,66 @@
 package me.chanjar.weixin.cp.api;
 
+import me.chanjar.weixin.common.exception.WxErrorException;
+import me.chanjar.weixin.cp.bean.WxCpTag;
+import me.chanjar.weixin.cp.bean.WxCpTagAddOrRemoveUsersResult;
+import me.chanjar.weixin.cp.bean.WxCpUser;
+
+import java.util.List;
+
 /**
  * 
+ *  标签管理接口
  *  Created by BinaryWang on 2017/6/24.
  * 
* * @author Binary Wang */ public interface WxCpTagService { + /** + * 创建标签 + * + * @param tagName 标签名 + */ + String create(String tagName) throws WxErrorException; + + /** + * 更新标签 + * + * @param tagId 标签id + * @param tagName 标签名 + */ + void update(String tagId, String tagName) throws WxErrorException; + + /** + * 删除标签 + * + * @param tagId 标签id + */ + void delete(String tagId) throws WxErrorException; + + /** + * 获得标签列表 + */ + List listAll() throws WxErrorException; + + /** + * 获取标签成员 + * + * @param tagId 标签ID + */ + List listUsersByTagId(String tagId) throws WxErrorException; + + /** + * 增加标签成员 + * @param tagId 标签id + * @param userIds 用户ID 列表 + */ + WxCpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List userIds, List partyIds) throws WxErrorException; + + /** + * 移除标签成员 + * @param tagId 标签id + * @param userIds 用户id列表 + */ + WxCpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds) throws WxErrorException; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java index ac6fe8b2ed..6cff26485e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java @@ -1,7 +1,9 @@ package me.chanjar.weixin.cp.api.impl; -import com.google.gson.*; -import com.google.gson.reflect.TypeToken; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.result.WxError; @@ -12,13 +14,13 @@ import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.*; -import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; import me.chanjar.weixin.cp.api.*; import me.chanjar.weixin.cp.bean.*; import me.chanjar.weixin.cp.config.WxCpConfigStorage; -import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,17 +29,16 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; -import java.util.UUID; public abstract class AbstractWxCpServiceImpl implements WxCpService, RequestHttp { protected final Logger log = LoggerFactory.getLogger(this.getClass()); private WxCpUserService userService = new WxCpUserServiceImpl(this); private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this); - private WxCpMediaService mediaService; - private WxCpMenuService menuService; - private WxCpOauth2Service oauth2Service; - private WxCpTagService tagService; + private WxCpMediaService mediaService = new WxCpMediaServiceImpl(this); + private WxCpMenuService menuService = new WxCpMenuServiceImpl(this); + private WxCpOAuth2Service oauth2Service = new WxCpOAuth2ServiceImpl(this); + private WxCpTagService tagService = new WxCpTagServiceImpl(this); /** * 全局的是否正在刷新access token的锁 @@ -136,74 +137,56 @@ public WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorExce @Override @Deprecated public void menuCreate(WxMenu menu) throws WxErrorException { - menuCreate(this.configStorage.getAgentId(), menu); + this.getMenuService().create(menu); } @Override @Deprecated public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" - + agentId; - post(url, menu.toJson()); + this.getMenuService().create(agentId, menu); } @Override @Deprecated public void menuDelete() throws WxErrorException { - menuDelete(this.configStorage.getAgentId()); + this.getMenuService().delete(); } @Override @Deprecated public void menuDelete(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId; - get(url, null); + this.getMenuService().delete(agentId); } @Override @Deprecated public WxMenu menuGet() throws WxErrorException { - return menuGet(this.configStorage.getAgentId()); + return this.getMenuService().get(); } @Override @Deprecated public WxMenu menuGet(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId; - try { - String resultContent = get(url, null); - return WxMenu.fromJson(resultContent); - } catch (WxErrorException e) { - // 46003 不存在的菜单数据 - if (e.getError().getErrorCode() == 46003) { - return null; - } - throw e; - } + return this.getMenuService().get(agentId); } @Override @Deprecated public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException { - return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); + return this.getMediaService().upload(mediaType, fileType, inputStream); } @Override @Deprecated public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; - return execute(MediaUploadRequestExecutor.create(this), url, file); + return this.getMediaService().upload(mediaType, file); } @Override @Deprecated public File mediaDownload(String mediaId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; - return execute( - MediaDownloadRequestExecutor.create(this, - this.configStorage.getTmpDirFile()), - url, "media_id=" + mediaId); + return this.getMediaService().download(mediaId); } @Override @@ -245,148 +228,79 @@ public WxCpUser userGet(String userid) throws WxErrorException { @Override @Deprecated public List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { - return this.getUserService().listByDepartment(departId, fetchChild, status); + return this.getUserService().listByDepartment(departId, fetchChild, status); } @Override @Deprecated public List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { - return this.getUserService().listSimpleByDepartment(departId, fetchChild, status); + return this.getUserService().listSimpleByDepartment(departId, fetchChild, status); } @Override @Deprecated public String tagCreate(String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; - JsonObject o = new JsonObject(); - o.addProperty("tagname", tagName); - String responseContent = post(url, o.toString()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return tmpJsonElement.getAsJsonObject().get("tagid").getAsString(); + return this.getTagService().create(tagName); } @Override @Deprecated public void tagUpdate(String tagId, String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; - JsonObject o = new JsonObject(); - o.addProperty("tagid", tagId); - o.addProperty("tagname", tagName); - post(url, o.toString()); + this.getTagService().update(tagId, tagName); } @Override @Deprecated public void tagDelete(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; - get(url, null); + this.getTagService().delete(tagId); } @Override @Deprecated public List tagGet() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; - String responseContent = get(url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("taglist"), - new TypeToken>() { - }.getType() - ); + return this.getTagService().listAll(); } @Override @Deprecated public List tagGetUsers(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; - String responseContent = get(url, null); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxCpGsonBuilder.INSTANCE.create() - .fromJson( - tmpJsonElement.getAsJsonObject().get("userlist"), - new TypeToken>() { - }.getType() - ); + return this.getTagService().listUsersByTagId(tagId); } @Override @Deprecated public void tagAddUsers(String tagId, List userIds, List partyIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("tagid", tagId); - if (userIds != null) { - JsonArray jsonArray = new JsonArray(); - for (String userId : userIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("userlist", jsonArray); - } - if (partyIds != null) { - JsonArray jsonArray = new JsonArray(); - for (String userId : partyIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("partylist", jsonArray); - } - post(url, jsonObject.toString()); + this.getTagService().addUsers2Tag(tagId, userIds, partyIds); } @Override @Deprecated public void tagRemoveUsers(String tagId, List userIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("tagid", tagId); - JsonArray jsonArray = new JsonArray(); - for (String userId : userIds) { - jsonArray.add(new JsonPrimitive(userId)); - } - jsonObject.add("userlist", jsonArray); - post(url, jsonObject.toString()); + this.getTagService().removeUsersFromTag(tagId, userIds); } @Override @Deprecated public String oauth2buildAuthorizationUrl(String state) { - return this.oauth2buildAuthorizationUrl( - this.configStorage.getOauth2redirectUri(), - state - ); + return this.getOauth2Service().buildAuthorizationUrl(state); } @Override @Deprecated public String oauth2buildAuthorizationUrl(String redirectUri, String state) { - String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"; - url += "appid=" + this.configStorage.getCorpId(); - url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri); - url += "&response_type=code"; - url += "&scope=snsapi_base"; - if (state != null) { - url += "&state=" + state; - } - url += "#wechat_redirect"; - return url; + return this.getOauth2Service().buildAuthorizationUrl(redirectUri, state); } @Override @Deprecated public String[] oauth2getUserInfo(String code) throws WxErrorException { - return oauth2getUserInfo(this.configStorage.getAgentId(), code); + return this.getOauth2Service().getUserInfo(code); } @Override @Deprecated public String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?" - + "code=" + code - + "&agentid=" + agentId; - String responseText = get(url, null); - JsonElement je = new JsonParser().parse(responseText); - JsonObject jo = je.getAsJsonObject(); - return new String[]{GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId"), GsonHelper.getString(jo, "OpenId")}; + return this.getOauth2Service().getUserInfo(agentId, code); } @Override @@ -473,7 +387,7 @@ protected synchronized T executeInternal(RequestExecutor executor, try { T result = executor.execute(uriWithAccessToken, data); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, result); + this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, data, result); return result; } catch (WxErrorException e) { WxError error = e.getError(); @@ -490,12 +404,12 @@ protected synchronized T executeInternal(RequestExecutor executor, } if (error.getErrorCode() != 0) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, error); + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, data, error); throw new WxErrorException(error); } return null; } catch (IOException e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uriWithAccessToken, data, e.getMessage()); + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, data, e.getMessage()); throw new RuntimeException(e); } } @@ -584,7 +498,7 @@ public WxCpMenuService getMenuService() { } @Override - public WxCpOauth2Service getOauth2Service() { + public WxCpOAuth2Service getOauth2Service() { return oauth2Service; } @@ -621,4 +535,9 @@ public void departDelete(Integer departId) throws WxErrorException { public List departGet() throws WxErrorException { return this.getDepartmentService().listAll(); } + + @Override + public RequestHttp getRequestHttp() { + return this; + } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java new file mode 100644 index 0000000000..1364550aac --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java @@ -0,0 +1,50 @@ +package me.chanjar.weixin.cp.api.impl; + +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.cp.api.WxCpMediaService; +import me.chanjar.weixin.cp.api.WxCpService; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +/** + *
+ * 媒体管理接口
+ * Created by Binary Wang on 2017-6-25.
+ * @author Binary Wang
+ * 
+ */ +public class WxCpMediaServiceImpl implements WxCpMediaService { + private WxCpService mainService; + + public WxCpMediaServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public WxMediaUploadResult upload(String mediaType, String fileType, InputStream inputStream) + throws WxErrorException, IOException { + return this.upload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); + } + + @Override + public WxMediaUploadResult upload(String mediaType, File file) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; + return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), url, file); + } + + @Override + public File download(String mediaId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; + return this.mainService.execute( + MediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(), + this.mainService.getWxCpConfigStorage().getTmpDirFile()), + url, "media_id=" + mediaId); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java new file mode 100644 index 0000000000..7c3937d83e --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java @@ -0,0 +1,64 @@ +package me.chanjar.weixin.cp.api.impl; + +import me.chanjar.weixin.common.bean.menu.WxMenu; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpMenuService; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +/** + *
+ * 菜单管理相关接口
+ * Created by Binary Wang on 2017-6-25.
+ * @author Binary Wang
+ * 
+ */ +public class WxCpMenuServiceImpl implements WxCpMenuService { + private WxCpService mainService; + + public WxCpMenuServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public void create(WxMenu menu) throws WxErrorException { + this.create(this.mainService.getWxCpConfigStorage().getAgentId(), menu); + } + + @Override + public void create(Integer agentId, WxMenu menu) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" + agentId; + this.mainService.post(url, menu.toJson()); + } + + @Override + public void delete() throws WxErrorException { + this.delete(this.mainService.getWxCpConfigStorage().getAgentId()); + } + + @Override + public void delete(Integer agentId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId; + this.mainService.get(url, null); + } + + @Override + public WxMenu get() throws WxErrorException { + return this.get(this.mainService.getWxCpConfigStorage().getAgentId()); + } + + @Override + public WxMenu get(Integer agentId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId; + try { + String resultContent = this.mainService.get(url, null); + return WxCpGsonBuilder.create().fromJson(resultContent, WxMenu.class); + } catch (WxErrorException e) { + // 46003 不存在的菜单数据 + if (e.getError().getErrorCode() == 46003) { + return null; + } + throw e; + } + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java new file mode 100644 index 0000000000..a317bfb4e6 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.URIUtil; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.api.WxCpOAuth2Service; +import me.chanjar.weixin.cp.api.WxCpService; + +/** + *
+ *
+ * Created by Binary Wang on 2017-6-25.
+ * @author Binary Wang
+ * 
+ */ +public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { + private WxCpService mainService; + + public WxCpOAuth2ServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public String buildAuthorizationUrl(String state) { + return this.buildAuthorizationUrl( + this.mainService.getWxCpConfigStorage().getOauth2redirectUri(), + state + ); + } + + @Override + public String buildAuthorizationUrl(String redirectUri, String state) { + String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"; + url += "appid=" + this.mainService.getWxCpConfigStorage().getCorpId(); + url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri); + url += "&response_type=code"; + url += "&scope=snsapi_base"; + if (state != null) { + url += "&state=" + state; + } + url += "#wechat_redirect"; + return url; + } + + @Override + public String[] getUserInfo(String code) throws WxErrorException { + return getUserInfo(this.mainService.getWxCpConfigStorage().getAgentId(), code); + } + + @Override + public String[] getUserInfo(Integer agentId, String code) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?" + + "code=" + code + + "&agentid=" + agentId; + String responseText = this.mainService.get(url, null); + JsonElement je = new JsonParser().parse(responseText); + JsonObject jo = je.getAsJsonObject(); + return new String[]{GsonHelper.getString(jo, "UserId"), + GsonHelper.getString(jo, "DeviceId"), + GsonHelper.getString(jo, "OpenId")}; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java index 9c87ccbd41..d9388f0345 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java @@ -7,7 +7,6 @@ import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; -import me.chanjar.weixin.cp.bean.WxCpDepart; import me.chanjar.weixin.cp.config.WxCpConfigStorage; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -17,7 +16,6 @@ import org.apache.http.impl.client.CloseableHttpClient; import java.io.IOException; -import java.util.List; public class WxCpServiceApacheHttpClientImpl extends AbstractWxCpServiceImpl { protected CloseableHttpClient httpClient; @@ -103,4 +101,5 @@ public void initHttp() { public WxCpConfigStorage getWxCpConfigStorage() { return this.configStorage; } + } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java new file mode 100644 index 0000000000..ff995d9724 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java @@ -0,0 +1,116 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.api.WxCpTagService; +import me.chanjar.weixin.cp.bean.WxCpTag; +import me.chanjar.weixin.cp.bean.WxCpTagAddOrRemoveUsersResult; +import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; + +/** + *
+ *  标签管理接口
+ * Created by Binary Wang on 2017-6-25.
+ * @author Binary Wang
+ * 
+ */ +public class WxCpTagServiceImpl implements WxCpTagService { + private WxCpService mainService; + + public WxCpTagServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public String create(String tagName) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; + JsonObject o = new JsonObject(); + o.addProperty("tagname", tagName); + String responseContent = this.mainService.post(url, o.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("tagid").getAsString(); + } + + @Override + public void update(String tagId, String tagName) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; + JsonObject o = new JsonObject(); + o.addProperty("tagid", tagId); + o.addProperty("tagname", tagName); + this.mainService.post(url, o.toString()); + } + + @Override + public void delete(String tagId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; + this.mainService.get(url, null); + } + + @Override + public List listAll() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; + String responseContent = this.mainService.get(url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("taglist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public List listUsersByTagId(String tagId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; + String responseContent = this.mainService.get(url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public WxCpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List userIds, List partyIds) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + if (userIds != null) { + JsonArray jsonArray = new JsonArray(); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("userlist", jsonArray); + } + if (partyIds != null) { + JsonArray jsonArray = new JsonArray(); + for (String userId : partyIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("partylist", jsonArray); + } + + return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(url, jsonObject.toString())); + } + + @Override + public WxCpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + JsonArray jsonArray = new JsonArray(); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("userlist", jsonArray); + + return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(url, jsonObject.toString())); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java new file mode 100644 index 0000000000..c216ae46a6 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java @@ -0,0 +1,85 @@ +package me.chanjar.weixin.cp.bean; + +import com.google.common.base.Splitter; +import com.google.gson.annotations.SerializedName; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.List; + +/** + *
+ * 为标签添加或移除用户结果对象类
+ * Created by Binary Wang on 2017-6-22.
+ * @author Binary Wang
+ * 
+ */ +public class WxCpTagAddOrRemoveUsersResult { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public static WxCpTagAddOrRemoveUsersResult fromJson(String json) { + return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpTagAddOrRemoveUsersResult.class); + } + + @SerializedName("errcode") + private Integer errCode; + + @SerializedName("errmsg") + private String errMsg; + + @SerializedName("invalidlist") + private String invalidUsers; + + @SerializedName("invalidparty") + private String[] invalidParty; + + public Integer getErrCode() { + return this.errCode; + } + + public void setErrCode(Integer errCode) { + this.errCode = errCode; + } + + public String getErrMsg() { + return this.errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } + + public String getInvalidUser() { + return this.invalidUsers; + } + + public void setInvalidUser(String invalidUser) { + this.invalidUsers = invalidUser; + } + + public String[] getInvalidParty() { + return this.invalidParty; + } + + public void setInvalidParty(String[] invalidParty) { + this.invalidParty = invalidParty; + } + + public List getInvalidUserList() { + return this.content2List(this.invalidUsers); + } + + private List content2List(String content) { + if(StringUtils.isBlank(content)){ + return Collections.emptyList(); + } + + return Splitter.on("|").splitToList(content); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java index fcf84de91e..647a4e6ba2 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java @@ -13,13 +13,45 @@ */ public class WxCpUser implements Serializable { + public enum Gender { + MALE("男", "1"), + FEMAIL("女", "2"); + + private String genderName; + private String code; + + Gender(String genderName, String code) { + this.genderName = genderName; + this.code = code; + } + + public String getGenderName() { + return this.genderName; + } + + public String getCode() { + return this.code; + } + + public static Gender fromCode(String code) { + if ("1".equals(code)) { + return Gender.MALE; + } + if ("2".equals(code)) { + return Gender.FEMAIL; + } + + return null; + } + } + private static final long serialVersionUID = -5696099236344075582L; private String userId; private String name; private Integer[] departIds; private String position; private String mobile; - private String gender; + private Gender gender; private String email; private String avatar; private Integer status; @@ -58,11 +90,11 @@ public void setDepartIds(Integer[] departIds) { this.departIds = departIds; } - public String getGender() { + public Gender getGender() { return this.gender; } - public void setGender(String gender) { + public void setGender(Gender gender) { this.gender = gender; } @@ -159,7 +191,6 @@ public String toJson() { } public static class Attr { - private String name; private String value; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java index 3235864811..5efee45ce5 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java @@ -2,6 +2,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.util.json.WxErrorAdapter; import me.chanjar.weixin.cp.bean.WxCpDepart; @@ -19,6 +20,7 @@ public class WxCpGsonBuilder { INSTANCE.registerTypeAdapter(WxCpDepart.class, new WxCpDepartGsonAdapter()); INSTANCE.registerTypeAdapter(WxCpUser.class, new WxCpUserGsonAdapter()); INSTANCE.registerTypeAdapter(WxError.class, new WxErrorAdapter()); + INSTANCE.registerTypeAdapter(WxMenu.class, new WxCpMenuGsonAdapter()); INSTANCE.registerTypeAdapter(WxCpTag.class, new WxCpTagGsonAdapter()); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMenuGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMenuGsonAdapter.java new file mode 100644 index 0000000000..c7cb05cc62 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMenuGsonAdapter.java @@ -0,0 +1,24 @@ +package me.chanjar.weixin.cp.util.json; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import me.chanjar.weixin.common.bean.menu.WxMenu; +import me.chanjar.weixin.common.util.json.WxMenuGsonAdapter; + +import java.lang.reflect.Type; + +/** + *
+ * 企业号菜单json转换适配器
+ * Created by Binary Wang on 2017-6-25.
+ * @author Binary Wang
+ * 
+ */ +public class WxCpMenuGsonAdapter extends WxMenuGsonAdapter { + + @Override + public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + return this.buildMenuFromJson(json.getAsJsonObject().get("button").getAsJsonArray()); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java index 00cdea5752..6531d07ba9 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java @@ -39,7 +39,7 @@ public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationC user.setName(GsonHelper.getString(o, "name")); user.setPosition(GsonHelper.getString(o, "position")); user.setMobile(GsonHelper.getString(o, "mobile")); - user.setGender(GsonHelper.getString(o, "gender")); + user.setGender(WxCpUser.Gender.fromCode(GsonHelper.getString(o, "gender"))); user.setEmail(GsonHelper.getString(o, "email")); user.setAvatar(GsonHelper.getString(o, "avatar")); user.setStatus(GsonHelper.getInteger(o, "status")); @@ -85,7 +85,7 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon o.addProperty("mobile", user.getMobile()); } if (user.getGender() != null) { - o.addProperty("gender", user.getGender()); + o.addProperty("gender", user.getGender().getCode()); } if (user.getEmail() != null) { o.addProperty("email", user.getEmail()); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java index ca4bc636fa..179086f739 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java @@ -31,7 +31,7 @@ public void configure(Binder binder) { wxService.setWxCpConfigStorage(config); binder.bind(WxCpService.class).toInstance(wxService); - binder.bind(WxCpConfigStorage.class).toInstance(config); + binder.bind(WxXmlCpInMemoryConfigStorage.class).toInstance(config); } catch (IOException e) { e.printStackTrace(); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java deleted file mode 100644 index f10a8b7d3f..0000000000 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java +++ /dev/null @@ -1,77 +0,0 @@ -package me.chanjar.weixin.cp.api; - -import com.google.inject.Inject; -import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * 测试多媒体文件上传下载 - * - * @author Daniel Qian - */ -//@Test(groups="mediaAPI", dependsOnGroups="baseAPI") -@Test -@Guice(modules = ApiTestModule.class) -public class WxCpMediaAPITest { - - @Inject - protected WxCpServiceImpl wxService; - - private List media_ids = new ArrayList<>(); - - @Test(dataProvider = "uploadMedia") - public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { - try (InputStream inputStream = ClassLoader - .getSystemResourceAsStream(fileName);) { - WxMediaUploadResult res = this.wxService.mediaUpload(mediaType, fileType, - inputStream); - Assert.assertNotNull(res.getType()); - Assert.assertNotNull(res.getCreatedAt()); - Assert.assertTrue( - res.getMediaId() != null || res.getThumbMediaId() != null); - - if (res.getMediaId() != null) { - this.media_ids.add(res.getMediaId()); - } - if (res.getThumbMediaId() != null) { - this.media_ids.add(res.getThumbMediaId()); - } - } - } - - @DataProvider - public Object[][] uploadMedia() { - return new Object[][]{ - new Object[]{WxConsts.MEDIA_IMAGE, TestConstants.FILE_JPG, "mm.jpeg"}, - new Object[]{WxConsts.MEDIA_VOICE, TestConstants.FILE_MP3, "mm.mp3"}, - new Object[]{WxConsts.MEDIA_VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, - new Object[]{WxConsts.MEDIA_FILE, TestConstants.FILE_JPG, "mm.jpeg"} - }; - } - - @Test(dependsOnMethods = {"testUploadMedia"}, dataProvider = "downloadMedia") - public void testDownloadMedia(String media_id) throws WxErrorException { - this.wxService.mediaDownload(media_id); - } - - @DataProvider - public Object[][] downloadMedia() { - Object[][] params = new Object[this.media_ids.size()][]; - for (int i = 0; i < this.media_ids.size(); i++) { - params[i] = new Object[]{this.media_ids.get(i)}; - } - return params; - } - -} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java deleted file mode 100644 index cb743f3d94..0000000000 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java +++ /dev/null @@ -1,68 +0,0 @@ -package me.chanjar.weixin.cp.api; - -import com.google.inject.Inject; -import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; -import me.chanjar.weixin.cp.bean.WxCpTag; -import me.chanjar.weixin.cp.bean.WxCpUser; -import me.chanjar.weixin.cp.config.WxCpConfigStorage; -import org.testng.Assert; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import java.util.ArrayList; -import java.util.List; - -@Test(groups = "departAPI", dependsOnGroups = "baseAPI") -@Guice(modules = ApiTestModule.class) -public class WxCpTagAPITest { - - @Inject - protected WxCpServiceImpl wxService; - - @Inject - protected WxCpConfigStorage configStorage; - - protected String tagId; - - public void testTagCreate() throws Exception { - this.tagId = this.wxService.tagCreate("测试标签4"); - System.out.println(this.tagId); - } - - @Test(dependsOnMethods = "testTagCreate") - public void testTagUpdate() throws Exception { - this.wxService.tagUpdate(this.tagId, "测试标签-改名"); - } - - @Test(dependsOnMethods = "testTagUpdate") - public void testTagGet() throws Exception { - List tags = this.wxService.tagGet(); - Assert.assertNotEquals(tags.size(), 0); - } - - @Test(dependsOnMethods = "testTagGet") - public void testTagAddUsers() throws Exception { - List userIds = new ArrayList<>(); - userIds.add(((ApiTestModule.WxXmlCpInMemoryConfigStorage) this.configStorage).getUserId()); - this.wxService.tagAddUsers(this.tagId, userIds, null); - } - - @Test(dependsOnMethods = "testTagAddUsers") - public void testTagGetUsers() throws Exception { - List users = this.wxService.tagGetUsers(this.tagId); - Assert.assertNotEquals(users.size(), 0); - } - - @Test(dependsOnMethods = "testTagGetUsers") - public void testTagRemoveUsers() throws Exception { - List userIds = new ArrayList<>(); - userIds.add(((ApiTestModule.WxXmlCpInMemoryConfigStorage) this.configStorage).getUserId()); - this.wxService.tagRemoveUsers(this.tagId, userIds); - } - - @Test(dependsOnMethods = "testTagRemoveUsers") - public void testTagDelete() throws Exception { - this.wxService.tagDelete(this.tagId); - } - -} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java new file mode 100644 index 0000000000..4bdb73413d --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java @@ -0,0 +1,78 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.TestConstants; +import me.chanjar.weixin.cp.api.WxCpService; +import org.testng.annotations.*; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import static org.testng.Assert.*; + +/** + *
+ *
+ * Created by Binary Wang on 2017-6-25.
+ * @author Binary Wang
+ * 
+ */ +@Guice(modules = ApiTestModule.class) +public class WxCpMediaServiceImplTest { + @Inject + private WxCpService wxService; + + private List mediaIds = new ArrayList<>(); + + @DataProvider + public Object[][] mediaData() { + return new Object[][]{ + new Object[]{WxConsts.MEDIA_IMAGE, TestConstants.FILE_JPG, "mm.jpeg"}, + new Object[]{WxConsts.MEDIA_VOICE, TestConstants.FILE_MP3, "mm.mp3"}, + new Object[]{WxConsts.MEDIA_VOICE, TestConstants.FILE_AMR, "mm.amr"},//{"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"} + new Object[]{WxConsts.MEDIA_VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, + new Object[]{WxConsts.MEDIA_FILE, TestConstants.FILE_JPG, "mm.jpeg"} + }; + } + + @Test(dataProvider = "mediaData") + public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { + try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)) { + WxMediaUploadResult res = this.wxService.getMediaService().upload(mediaType, fileType, inputStream); + assertNotNull(res.getType()); + assertNotNull(res.getCreatedAt()); + assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null); + + if (res.getMediaId() != null) { + this.mediaIds.add(res.getMediaId()); + } + if (res.getThumbMediaId() != null) { + this.mediaIds.add(res.getThumbMediaId()); + } + } + } + + @DataProvider + public Object[][] downloadMedia() { + Object[][] params = new Object[this.mediaIds.size()][]; + for (int i = 0; i < this.mediaIds.size(); i++) { + params[i] = new Object[]{this.mediaIds.get(i)}; + } + return params; + } + + @Test(dependsOnMethods = {"testUploadMedia"}, dataProvider = "downloadMedia") + public void testDownloadMedia(String media_id) throws WxErrorException { + File file = this.wxService.getMediaService().download(media_id); + assertNotNull(file); + System.out.println(file); + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImplTest.java similarity index 62% rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImplTest.java index 643ba3306b..def6419820 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImplTest.java @@ -1,45 +1,29 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.api.impl; import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.menu.WxMenuButton; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.WxCpService; +import org.testng.annotations.*; + +import static org.testng.Assert.*; /** - * 测试菜单 + *
  *
- * @author Daniel Qian
+ * Created by Binary Wang on 2017-6-25.
+ * @author Binary Wang
+ * 
*/ -@Test(groups = "menuAPI", dependsOnGroups = "baseAPI") @Guice(modules = ApiTestModule.class) -public class WxMenuAPITest { - +public class WxCpMenuServiceImplTest { @Inject - protected WxCpServiceImpl wxService; - - @Test(dataProvider = "menu") - public void testCreateMenu(WxMenu wxMenu) throws WxErrorException { - this.wxService.menuCreate(wxMenu); - } + protected WxCpService wxService; - @Test(dependsOnMethods = {"testCreateMenu"}) - public void testGetMenu() throws WxErrorException { - Assert.assertNotNull(this.wxService.menuGet()); - } - - @Test(dependsOnMethods = {"testGetMenu"}) - public void testDeleteMenu() throws WxErrorException { - this.wxService.menuDelete(); - } - - @DataProvider(name = "menu") - public Object[][] getMenu() { + @DataProvider + public Object[][] menuData() { WxMenu menu = new WxMenu(); WxMenuButton button1 = new WxMenuButton(); button1.setType(WxConsts.BUTTON_CLICK); @@ -85,5 +69,21 @@ public Object[][] getMenu() { } + @Test(dataProvider = "menuData") + public void testCreate(WxMenu wxMenu) throws Exception { + this.wxService.getMenuService().create(wxMenu); + } + + @Test(dependsOnMethods = "testCreate") + public void testGet() throws Exception { + WxMenu menu = this.wxService.getMenuService().get(); + assertNotNull(menu); + System.out.println(menu.toJson()); + } + + @Test(dependsOnMethods = {"testGet", "testCreate"}) + public void testDelete() throws Exception { + this.wxService.getMenuService().delete(); + } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java new file mode 100644 index 0000000000..94ac3b09db --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java @@ -0,0 +1,75 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.common.base.Splitter; +import com.google.inject.Inject; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpTag; +import me.chanjar.weixin.cp.bean.WxCpTagAddOrRemoveUsersResult; +import me.chanjar.weixin.cp.bean.WxCpUser; +import org.testng.annotations.*; + +import java.util.List; + +import static org.testng.Assert.*; + +/** + *
+ *
+ * Created by Binary Wang on 2017-6-25.
+ * @author Binary Wang
+ * 
+ */ +@Guice(modules = ApiTestModule.class) +public class WxCpTagServiceImplTest { + @Inject + protected WxCpService wxService; + + @Inject + protected ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage; + + protected String tagId; + + @Test + public void testCreate() throws Exception { + this.tagId = this.wxService.getTagService().create("测试标签" + System.currentTimeMillis()); + System.out.println(this.tagId); + } + + @Test(dependsOnMethods = "testCreate") + public void testUpdate() throws Exception { + this.wxService.getTagService().update(this.tagId, "测试标签-改名" + System.currentTimeMillis()); + } + + @Test(dependsOnMethods = {"testUpdate", "testCreate"}) + public void testListAll() throws Exception { + List tags = this.wxService.getTagService().listAll(); + assertNotEquals(tags.size(), 0); + } + + @Test(dependsOnMethods = {"testListAll", "testUpdate", "testCreate"}) + public void testAddUsers2Tag() throws Exception { + List userIds = Splitter.on("|").splitToList(this.configStorage.getUserId()); + WxCpTagAddOrRemoveUsersResult result = this.wxService.getTagService().addUsers2Tag(this.tagId, userIds, null); + assertEquals(result.getErrCode(), Integer.valueOf(0)); + } + + @Test(dependsOnMethods = {"testAddUsers2Tag", "testListAll", "testUpdate", "testCreate"}) + public void testListUsersByTagId() throws Exception { + List users = this.wxService.getTagService().listUsersByTagId(this.tagId); + assertNotEquals(users.size(), 0); + } + + @Test(dependsOnMethods = {"testListUsersByTagId", "testAddUsers2Tag", "testListAll", "testUpdate", "testCreate"}) + public void testRemoveUsersFromTag() throws Exception { + List userIds = Splitter.on("|").splitToList(this.configStorage.getUserId()); + WxCpTagAddOrRemoveUsersResult result = this.wxService.getTagService().removeUsersFromTag(this.tagId, userIds); + assertEquals(result.getErrCode(), Integer.valueOf(0)); + } + + @Test(dependsOnMethods = {"testRemoveUsersFromTag", "testListUsersByTagId", "testAddUsers2Tag", "testListAll", "testUpdate", "testCreate"}) + public void testDelete() throws Exception { + this.wxService.getTagService().delete(this.tagId); + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java index d576b866f5..a01f03436e 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java @@ -6,9 +6,7 @@ import me.chanjar.weixin.cp.bean.WxCpUser; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; -import org.testng.Assert; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; +import org.testng.annotations.*; import java.util.List; @@ -25,19 +23,21 @@ public class WxCpUserServiceImplTest { @Inject private WxCpService wxCpService; + private String userId = "someone" + System.currentTimeMillis(); @Test public void testAuthenticate() throws Exception { + this.wxCpService.getUserService().authenticate("abc"); } @Test public void testCreate() throws Exception { WxCpUser user = new WxCpUser(); - user.setUserId("some.woman"); + user.setUserId(userId); user.setName("Some Woman"); - user.setDepartIds(new Integer[]{9, 8}); + user.setDepartIds(new Integer[]{2}); user.setEmail("none@none.com"); - user.setGender("女"); + user.setGender(WxCpUser.Gender.FEMAIL); user.setMobile("13560084979"); user.setPosition("woman"); user.setTelephone("3300393"); @@ -48,20 +48,20 @@ public void testCreate() throws Exception { @Test(dependsOnMethods = "testCreate") public void testUpdate() throws Exception { WxCpUser user = new WxCpUser(); - user.setUserId("some.woman"); + user.setUserId(userId); user.setName("Some Woman"); user.addExtAttr("爱好", "table2"); this.wxCpService.getUserService().update(user); } - @Test + @Test(dependsOnMethods = {"testCreate", "testUpdate"}) public void testDelete() throws Exception { - this.wxCpService.getUserService().delete("some.woman"); + this.wxCpService.getUserService().delete(userId); } @Test(dependsOnMethods = "testUpdate") public void testGetById() throws Exception { - WxCpUser user = this.wxCpService.getUserService().getById("some.woman"); + WxCpUser user = this.wxCpService.getUserService().getById(userId); assertNotNull(user); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java index e9d78768f2..a9ab309c37 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java @@ -1,14 +1,14 @@ package me.chanjar.weixin.cp.demo; import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.cp.config.WxCpConfigStorage; -import me.chanjar.weixin.cp.message.WxCpMessageHandler; -import me.chanjar.weixin.cp.message.WxCpMessageRouter; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.message.WxCpMessageHandler; +import me.chanjar.weixin.cp.message.WxCpMessageRouter; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; @@ -69,8 +69,7 @@ public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context, WxCpService wxService, WxSessionManager sessionManager) { String href = "测试oauth2"; return WxCpXmlOutMessage.TEXT().content(href) .fromUser(wxMessage.getToUserName()) diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java index d65e242702..37c2b7a12f 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java @@ -30,7 +30,7 @@ protected void service(HttpServletRequest request, HttpServletResponse response) response.getWriter().println("

code

"); response.getWriter().println(code); - String[] res = this.wxCpService.oauth2getUserInfo(code); + String[] res = this.wxCpService.getOauth2Service().getUserInfo(code); response.getWriter().println("

result

"); response.getWriter().println(Arrays.toString(res)); } catch (WxErrorException e) { diff --git a/weixin-java-cp/src/test/resources/mm.amr b/weixin-java-cp/src/test/resources/mm.amr new file mode 100644 index 0000000000000000000000000000000000000000..a4df01a0d9e7a0cdbe3e3fb6dd059767d60fedff GIT binary patch literal 38982 zcmb@tXEdB&)Hh6`*D=bBF&K@K2cz@LH|KcC~U-71w?El~RzyJT? z9SB^y2o$b=x`2$69-m61K>iUOf$zu5;*!Z-i}q-}@s&lE!z+{qKYdz*9@tmi?gFrX zh4f@(Q7F3AGC{bJKNtpM#LI z3xu^41x0`#l%bNQSm36oipEPkCtB3#FLOzWl+i&;R_CjYj|uN3m3}@E!vYJ&sfIU- z1RX<1SYT>Sf6Yj#L#^(=By6TGA1F@?@dJp6D0xVIKgGO{ZC@8q_$=R&)|P5`S0=Fc z>b9uk3lu;b#%4%u)VX*Rc^=wvmU`FR)tyONSmA_1azK$RWe*@BturM3H_fq~fT-zC zf3zC7vx?F@9FK@CAwT)nvIkJn!1Q^y@s8W5$LAVBcHW|_IOyly;g}J<>sO!Xn*b6L zIuy?3b@$Ggd=sppc*bg|s(kjBS>@LQ+_J{w|G{g!RpxT+`UrSd-sDA0ot#D@zWypJ7=j7iuR*;G@AK1`to1ukEd;aCeZZ(ACXaI3dne}#ahVs?#N6&R;X)EBT13w|)I+L#Y zlZeIEs9GK^oXgC@>ah!f9u=L$-(N@6m3V-JOkLNKHZ=326C%I%ZP{@{IcyU<-J?Gg zy?8C4;s@e+bWNVDXJ+87R^2QZzTM}0@#pn<`fs_Q5Jfj7P<{;PdfuF&<&F*t7wMJ; z0kpx*v$$B{?}j3Ey6Hj$01=5X@44kKE24W+PZ9)0G2A)RN*b-3Hl$B=pnNGH|11x* zu1J4Bol819VM{7o3>V#`-k(_$oSl!K@V;mQh;AHaTruksUdEVh8}seCIFPHXJYf1T zLif&()+_+zk49L%9XUX5;`=r9{f8p}B}Wu^KH5^=E9OPj0lY%E*gsp7H;kA?dPfPqFb`s&v1!nNpm*b6MBh~*a#&Hioq)}9nGsoSqW`H=_GMPC1mxg_(9dgW^T z<6Yw&?yC{qFV52W-!~il027i`dC5)#R6U zT{K%Iiq*dCu zl}OdkqhX@ztf(I)l+@(!blDTA+)-minvnm_r{Z?izt|cRHgu(d{F`G{;bQYW*qSCz zJUdzh4^Vx=%ewU!J`aBId^VX!vR)_ByL0liPA%p1k(17w^8fswwrkP5n5&WSRf5UC z?tG=fp;X(|j9kvFGkogy; zc4nLGzJ3+xt-eiRQ2FPTvc;`s_}HG};#Ub3fQkp9;`H%Oik6kU)xulH8$&#kXXy_5 zwua;c&v+LWK)jN+dvCVbCS!P=mk-qI`(()|2@nVwr0P5W0oo6ZaGlwGXaL7*se zqpXwo;NoBY8E2BvM>cd4SAz9W742P0ho>CYpnS=cRCE)VRU767c7tURJ)W$mn}NQS zZg-OOo8P5ng8EfsY1DCE@%E62RNIK@kgq$Ye(^{(?Z?;D(#Pck1 z^GNT=1?=2TFj%ab=nr6|SH+7rb9C~2-Nd-b5> zK3~x|oiN8KS=5J?PpqhA(<2nG!(J0W1>Ua|?3nN>qG-h5BJ+>QnX*^Lhrjiv8ms3D z+G60kx(a($$KoPB><@MNVYhLs_e4Fr8OqC3==5^GpJAXb<;sOgO3cMu%mE8fkru14JDV-; zck8}*!Dc-8B>3Kk`FSG^RO-5zfvO+4{{wBkN6HloibaRQ72hXV= ztymE~f}JerHo~wsPymuo5)M};>poX577l#da?^FBsybYFEkE{nHVpd^+@CmF1zwf1 z9@sUnslI^j<-KWHt=h*iO=a#Hks_K2Ksn|7;9;{Bm+>~MQYLSOC}K?v+6gXbde1x= z6!b>`D1?U(9zEYZj4uj|ef8&yc}=#@9oM^`+X}wi)lvfS5G6Q#T%qDJ!P=ZpOZ)y= zTgAvd!8V<}m$YvST|xTfk5$;%pLAb%dor-bMC`s$%cO{D5z}WSSIr!JgaV*+rEum~ zGlUzHUWHG0qO}8ndH5BuKrTa&{zse455zy?gGYT>Tzi8EMVpRJRTmO@3z&6PW-V0+ zs$`S{P%>T=+=8>Bbw^K{x(=!q$((oTeecL!3&)QvAjbcvKiUX0_U?7j>7x#w-hC(h zQhYqLzVE*{LHW`>gCi*SV$P+#GSTB5rt#z1?)%>HRqof*J~?1~2PG|)MVJm( z{28_KrejGu?OgE)WaMq{|F_P}HZddy;>)z*(VE?Ti6Q$h$Sg?TdEOa}Z$4bGxJp_> zoOJJ;kM?Ez8xa(`0HFEHw5g+B`R#V-=J`y^*;dJE@XYx*mlmbHPDw?U14#B4DCm5= ztlN9*za-Vm8sek;Wgk2kpA{}r3gBt>0Hi*G^-hcM{o0w?1XI4p?88slXCf@hc_#)r ze|v3}13WVMh&%+Fms$2U$w{5&qxGj7WM}P(K4OKdHyxL-08}{((efH{RF_>`HKuh3 zj(JqNO0Kg%s(r17pi|fb(6aP!n%4qh#y#(x*tuWy1Z7S3*7bcZW-zAM_6q~~Q=w<1 zD6n8uB4&YdE@yxwvV!Knn}7SJQiB5(i+WGGz7c>uJQ>Aa6^fE?SOD1gW+ChYnFAJtdUb%m>e~b>3FumQ z;sw_M4Z7B@91zl!6FsODCT`D9gJ$l0wmSF`&N|pzJMHlJ$M}R73gA;gnyqeyiVtP} ziMp$QTS|UWKgw@Xx?Rk=x!8*}6Ap%D!JBNJVRRf%|jPGdUi%=mbqrY8zFsnLPRW zKp{B16m@iw$S@HG>ZforljGw=k9#rJ=R)9=1tO4&-zwjS3arFp0qzhkHpkUr z{$PPfVe?Bejc zFFJTfKs?Ec)#Eb0$iog$_3$atn!R}7X(w6{6)W*7mmz}jqN zLqmCnxqH5E74_2V=;!-;*MrJ$oQD0?bs5F}dw-eWSbJQ-2#i2deE?;u-&E{t*BQg;9yeD)wb1Rq^C* z9DBabC_nk|u|B}TIey>^7X(0P(wi7yymjuytUP)xz4H84!Vu)1{Kb1tPD$Y#&@KQL z!eK{x8Ob$=54f1_3X7-tATX;syzNo|B$!onHvtGto+0V451VF!mAWKD@*ZmY8yPwe zEZr)SXI?zj@&llX`81?|_8_}4*#osU7W3;ChFasI(zd~dHQK+{`X(b*eF z|FB+MxGamvO&M8xGX1=w`R)l-jv@-65ua7Qf<~=J^_Y(NQ!Eg_zp_lUO~k>EK9zTQ zcsBuLa1c+uz}+FbJb5-dtHaW6KtOp+&FcKzXZ)5D3ZO#H8ePGyQ_Td=5s3sd>SIOb zN}0;`v9@Z3pQkY@01bPd*<|y#0W$%YFn@2&=boRhLv*3sy#-V;!(onMV0>3@JIPW> z9-REnixRI$;-3@RT0WG2G3SylvE>cQN3q`i3Vtd+6eIC$P*7E~&9IePqn@mxkmNxT z!3{rvHiQ)h=8vHKT@rkjp0X@acni4QfptV4{TmJqC&BJ8V&UqCGYV>Z z02Od8vew}#|zx2J>mgGSnsDo-aBjMGJMCR>vXt|FCHZY4x##5R)j@n!<_Q9_2$htmn| z5gl`T=1?^t+~fsa$~9_njWimn(F8CdLHwhZy`6C++T$_y!f!_ZlsNvuOnC^Cs_;wTg_w#b;X~)L?4>+i4B4JtA9SDHbM6)V0A1M*yUoPC!z4c73 zNQ$V$v^GgLV)He2K?M-eOMpbd!a4~ijSdJD#OvQq3E!o73qc}C)jy~@l>=z4VC``8 zeJe~138y3fr$(=jXM>~UOEpYAf7a~cLHb%%+EMh+rZM=&@^I8~_)Tt;!YG|N!?r=O ztU#y=z#1YhU(*&iauqv$kLAR(CA1JyJm|Z}GWfx2mHY-6-?2Vm-X@wqxjRZ`qa+mZ zL+PHEJ6%lHf-bWhWH1z9Z##AFbR+Cx_AIYGwZ|cVa`1;fAFPS zJ&Ek?NZch4^XRqL>D%=E;wfZzYp?|6NZbS<0T0K6`mqpPT-yQ7Z7)g99Lg-uKVu)- z4(|tOo~it|9&=E4om(4?blu8M99E6FmF^&iNqI+;cc-Tu3-T{Xw|eOQJQ$BydVaC= zu-JU~Gw-PHu4f5>M-+a9Lm&wie(W;22p_Z8xaj09Y(t)3`6*J zMuS<8Lrr3eef-;pv0Ln?V|fvN092s}A-M-_a}$`fzl`c?kPmQ6sg?Wc5l%qYO!936 z5K_6v=( z3dYYCu}qF}LdPkY45KdFQGJWIL?uSGn#h?ytiIr<1LJ3fP^7BV6t2Md+Asjq{-BGv zpIrVsir+}eB6oGj0T9ylpm$C3uQUB|V{1g8CK6bxE<7ft3W9k4<*Bs?=_AG19C?LO z&0^22&J@!~#o;UOinx!Y3(kG_ZfP|ELNb<6l-P5RpdvlrA3XS*7H^&G&2a;`)ZS&r zqN+^r{CFnE573c~(XWZm1J$ppdQvAyP|^u}Q4{YJ+?xO%RZDYav8JiJwU%`uRqEs| zEw6Fkyd!@<#nLtLAqW7drj%7fD@3w3Lw{W?O?b}_ZDS2E=B>QY96x*rzVAZnmTTl{ zVs&Qb+IsG7VZRaaWDNDJS{kNV-|Lv%A)x<}CnM^Lk*vjCIQlH@p_+#_z48Y`EF+Na zHFL!%0Bx3F2{p92UuVQ5vGC#K%`&2nV1qS6`j2&fCe_sffX1@>5q4l0YFV5E2hEbX zbd1L&ar24=Lazu; zIGr9h-+?}BBoQVdJ$9W4WUPE~uKx9O9n7zV)N>$&d$+JVY&OC2(R0k1)UCHuLd)Bi zV{=5l)`0YFP!ZVSj>!~CjgN72g8N+;w>b1#h1u`a>=y(`f_UW|OTt$P>Eg`Nw-c0( zOT-oM%{yf`q=kO>^$-+d0rV6aq(2^%%wo~K|DI;AN4;B7Z$X7y=Qfdx!6cZ!;e8>5 z1ucT6Y)mYc2{-m~6aLX4`8rz0=ONl@J>dP9bAjt3yU?zqANE@xAjq zL@D+*h;IV%?=@z5wJjH~O60>b3Yz*=+kA%cTxA_xu?ql?5-S;D4hvHN(9M%3Ct!r=Mgti~F< zl#|H@uJJa#e6@#>ElAJ8ODEFdqhYlLF@VPkW`!E0-!x77Q!{t?hfp=5_9VS}*uNy< zOs&}-)DLkcOM(!-mxDR2Ewz7+NU8pK@7ITX@nnC*^M2fsebP%c(q39#CIxZ)L5dm;v)+3RQ=-*R_fC!F)XoDJ-yd8c`>kn-m0 zThqwve_bj7o7$v}j-ZhZSLRuaWZEcKZ6bQPJ0vUMJJ(4|!Ak-FO_$2%_;j&pH(pU4 z59USn9Qj0vm<0kA=ck)bXs`fME0xKy$(p+(!L|GDPbS;@%<4revII0vw=+U)Y)}B2 ztDMcT^-{ba4=hJIy*ssP=U+GeVL!lDvV7@2P3z)6kn+TM7+(0-TApy9cf{UujaQ!S}u~QZts;XzaYiE_j2Cjp-hYs2x=S7a0*98=|BnARd6@L=6NDWSQjs zpPAK}$<_W8Q#s;r@Ab2nHv;)%ZMMYC#d~4!o3oh6L+e6&%hhCMm%E-_8mB&&djJAS z4Z(dJBM**CB5}E60T7&*uwZ5Wc8`BqHlzdN4;myL#i~(Rfe(N6#_r!`f+gL^H}%`w z!);CJ-t%frV4_1w#XCxcA z4o0;wj-?f+j-nxqa@V&&ep z;=lHq(2w+bojiS|<1U$FBNLb+<8rY7M@{B7hB?C|3qaByl(95;lOOTvWkM+HpY)DK zhye^xDTv#WYSS*Bg(Y3!fx+EZTszGBjcRJ!nKT9t;Qq7?5Vtwl_rbZ%FKuDl9*Q~b z)cVP1Yy3>Tbuac700#O}D)G3I=iXy{mk-;5mFq@*+0!pQDEXse#V`(Fe)Qk|f!0&F z#I2Y2irz9@EqO;rd>5{MTS@?7*aPp6jgHLCf%!P)0n>e}?ux!hqHT&7&-A#y#S{Gc z%K+jf`OOIcxU)i z8&mX$d=M{DM;-Ja&u=%0(IUsl*nVQAidtZ%h;pk@3CHE`0MPK4&|Z<0CbUn4d*n_3 z#3c~_aXm1HgwoR3ZZ2q*0|@?R*PytEG1p12^{#t^m3}=c{AazsWy=t=Fi8I}6JS6} zQ3oX@>IBFB<4;fhn{i+L^o!r+AEWa&id{$0|1&^12;98bGKW9uD$GFU5a9=znMr{1P@hiS8_UhCO%um>QISgq6 z`^(hWdoT7OJ0p4@j74dk=Lcvkl%l07wO29&x?!0B3MxhBqfs=4OX;W>jDG5~9<`g* z9K#%n44F+=2je3m2#sY3dq#h-K$~bC(KIW++&`T~Vo`Orn5@gnUeNw|%gI6n8{To1 zc5rm&$7=usspH=0i|B{JQA*~NdjJvZV@M=z5*xvLOEE3Jk3tTqbULLUBIh{1<>s83 zih=b5YDnbGC#JO?GtERy2(x_SLIa2+tt7Kx(S-{bU(>Knkm3I2L;FRZDFFXy@SY|Z zK@Htwc0MWX)StCr{fmToFW`x_Ye&3b#5g|I6!9ax?vj<~L_765YX$vZ{#p+SXcbPm zCxDP<91~%VR7XNb4L>nd{Wi8i<~0Enq@aAyb@w&}S(2)~=XE__6q-juXZUeYo(^d^Dkak32E0n+T<=-$K8L{`tIRRc4=Y=z{K^KEI_i= zBVcSZT1jifAWWfz-e<kq6x9&1LP4;{fzCt9l9{1b1K-?*ll3dizNe%2jv&lkmkJsXU;Vopy6A^Ts zzEnDl5Vo3R*9FcTJm`Prm9V(SZr!_ro5Hsos8uhVce-ycbG@R*v0~JT!2T~?2^sF8 zebcJoBiJ^tw=&Y~t$TLitz;?xCvl5sD6l?D3&9l}>lr7`yu1*o_Pl!OI8|>}m<*@Q z+P|R<`LBNr!3~DSjsGZe`S{QZ)|%frKEy6)9TCelbzlVEKaDIFm%2k97^7D)!rr46 zMy>qmrdbQUJFmVxJb4eCFDW9!4J<5;M^B^e$tr(6JbthA;91tc;$)qQR^0^T$hyvx*!d?|L8iL93qAC z@oFO!5Cf>V%R=0uhrA_X_(JREEq|A{57Mt+5M6F|lK80$Q?@UlPOlZZL6uV3iZ{*J2~#)9UwR64$O0YI@n z2J1tg#J2I~5^-U>$NvUKDdn{DZ!L@8g|5kf`6qoH)@|UK7>iq^=vr~(%;jsH+H%>LTU<^5 z#V-)I*=UaSOlw|`mO3-$rM}BaX2EqSItI6i0kA&x-}^Q3Q1u*dQRSl=&T;n!QAHEL zi9(c!86`G={0YFwaA^${f5HC8vk~_D>zU21nm5LEIJf7t%`hOIzE0cip@Qmwe0aEg zsIl!UonCV#J4&P9Pj(ji&A|GK3X`QqE7 z6v5r}O&2d?JJcSfJad|j#)ZYq_1t|J^fX-a2oLbd!1#(&3gU2&hCD#N zgVKsW_ns8;;q5dKr7ZeUXpR6#NqQ7}V)O|vDWdzBE`^Qnj|}U_8`h3wjylcOd3dnD4TG@ftnddW z>RW(ac!?QZ$_4q@yMbLFj=o!eTL7Sv^l{&aGkYJ!2$5_8B$43xN|wlj6C=9JHdkg`QZ< zsvQ8aHW-S%*gjw=rg*Z^(`|>lb6X6?Mn^&RgT`YP4gsj-VQ^TRAGN|WLI1 zX^NobFY93?rkDE}T{(&ib#MBAm`pi=@{y#2(_D#tAL5CeBo=YZjkwJWA&McjAYeBT zDKr7|D?WM%d=lHVo1@G0G1TwJTT89(`uCKA=Vb(Wi5Xo0vYigXoEuPaHEs}CdeWHO zOw0kr#|4UK{`$7N`QLm29|N4(SBN}l-0IT-fvUj2q#hH7VZRGfjb_D$1kis=g7}iE z#j77a3Pz-=Wv3c*Bx%*zy}Sptj9rsp{Ya`A!kiU!RF~q_6L3E&q&k;VR?j!bzhZ!tU-d6o102IlAf_ED>Z6_25vtH*A z0rBqJocx~|?yotSweyPsNGKzg84Q>@_&4{amT+qQHiwgciN(B?kQ45c>wW-hXfld9 zFYM;*r1wVm*1e6Mx|E$&86b&I9VQkn3d#owgTv<<*MsA&EnU?e?UK4B@0Lv@N|kWk z@#86jfcQKVbGlwYKmKDc+xAkmmS-0?@sZDcbp=?kOza*2g(LWi`XbF!(hx^ZG;5cW z-uZ9#9yEsh!@Ex7e}VBE8-uzOlV)$b|6n7cX6RFvZ;H#v@6DqAx7BAKD6s$ycQQ=B z5>|xC^1K0)Sp7MNRZIAUi~Lb1S4*Y74fYqp=nWxVue>bU_0Nbo)yPLuL;1()W0Q%583InDOo2F3{CWM_UK9xb`>Uxj*XW)UoCXQuTu)hhj zUqM)Nw+9y&?tf?( z+&?AC+!dTJP=T3Ko4y|~!~gj@w5&kAC;F2);l332G8Z;1pbYd6GWir*1K$eVCe7v; zSa{Smet1wN?VOUa-0qv}@m2x-D;>#{`BP8JalgH{HI1HK=oh$lFC|GR(|W| zdscJw)+)zqI@Mg6obC8P-v$u>HcJbPzw=Yl^eV}=zS<8hM>;Zk2lNa4Aa&yW~viB;;$JN0D5b`-m4F3+;-wb{1nAGal?<+vGzRoF1DQFSx*ZPaho$hn1s*PDD zfKbh(Z$uu64<*RV*9DpKGQIwhy2W3*$-(wSyuvvXK(@@@ZZx2wGz}eOa(GJV1N+ur z&nJI<67`YZVXz+pFg3)Hljaw+WB9n8vMQ`CJ8wR(2h@7zq(0Z>|736gxWmByD9QeK zUCb;|=}*`vb-k0BfnT(QMK%@xO!t}qD62iVZpj}ss&iGJ5VJLgP;;Z*eQH;^&-}cf z0rbzcu>fekY3v>y3R97uUw3r-{>giKXVl~Vfbns3q#bGga)bD2k6?S>9pk_1 zFvSCZoJNW{(|d_nF@TAafrm7UV=^V7{dcL_5P3n;&~;ou%eR!{8%nGJpnRfWOzmVQ zLtL@TU$3B=!1@tP#ceKTo-jslq>7RWBNg^-HPU_`aH9nJY+VO8BEwg}oTF z9@>{BY|35fAN7f!r8wiXeha$X=VSr>Pq?!Z zY5b>IuGoA>i&r}tqn4}$|N2Lid&LqQI1|D6Q5I%zo>43;A#gE@=FJ~_RpWR*ymm%@ ze%m7b(|6E5YS9lHwkal)kH+U(>8MVF?s6Tkql zutp%6wF)_Z-2YTW4PCwbc;`(-o0i-sRu3{oF>t=28-?3fQlB056ulpF`TlJQDYn#r zUku;bQ1;&&&K3AvfN${@RYJo`|~zsg0k80MNQ_6BsvRON!kp zUtWV{oEZ{k36*D_RMi!UA7*}~vum`|ZlNckOFlHmp8maX+kq5bct{q z>69u5L@>cBe7pN8QHfu!bx2*PFu0JBQ-_B^_N>w`^lpRw7Y%VfQwe=x1%k3$)zxWH z={ApK?9`|QRhVDQP3rwOzkotL=@@RiD=!0W%k+c!e!nD+7hfr0tKpaNLqNd(T{!az zaafT?v?nxpy_D_Gus+GeZpplQaRhh!adPi-$lg!+i4zy2#&Uol zz*))UZYDV2-Np zX!6y6KJ6Ogxl^WmhLYm`b$QVDP^stIh7naSMgShbOLg^d@%vCrk-6Ag-S(u-zq1qX zG+i4;BOV^`mV@UyWVFXG#-s(rsjnGx8#_fRJ(Oor9{DHe6!vtE$Z;rp*v@GNsE&E31(bxfh+8 z0Gqz8{|WIYN;83Tnmd?QBj=yCY>y51%v3hD*Us9&`n|62`s%3yIKQAt_8O-9W$}Jt z^cR>gjADf2se3a4IR9tIv3jYsX+B;X($QeTIUu#jgp&RJYwG@$X~KW}8wW!VD-SNX zGTUPB*f>pfI^?li`jgq@VHJwH74QI$o*gsBtu=~}pw4gW6_2ya#QqYta30FAq4KHN z5Uk&0@bs=<6~7OOxLlcsZhk#DuP^X5ZMHba(0;#Rj|Ka`UfeBRW}Sp-2n;V?_X2h& zMXcKB^z5@?XAT8F1mH2o(`{R*XVCFYQ^^#W$Zd~5i{0H+aIN3{3Mr%*0g$@h;nOVW z{N$h2CJ`#{tKL4KkEVNOq$W8QXZk9~0bKWB(Ay#xG!qQ}N+#=M^Evxzy*?BpbMdsl z;GH}8zDavvDYmFYA$4Y7{tYuVumo>h?fP`rtn}S0_a+1NAIpm}C5@+LzIh>5C__Wx zmw}f7hz}U+-cj7p#ew#xBF5lxWj`c7;c?RVL#*Xng8<}${{~krnOu8@Rwf{#DTw@i zl`owf8DSMaEC)Zlp&YZTyy0gSWdCUv3+k_Gu*v-gr|lR)=_ST*jmrIT27ybTjSb3| zZfkd6)^EPjpj;P0Q-Yz z`e#pMO$J5X^V5DE@3<}bu)Q~3=pEc5G+0P22Y9U0;R0GB$H{477qry3H}h<>&IdJb zslD~K6h8y!&)9U)OfO97bL&JruRrx$WE}M=e28O_>O;%W*R@%K`lIBLtVF3F!6|_J zNyW&!Z^9%eAVt@+f#;!O5@L^p7HERgNF!1Yv&Nj}2H{)CE1oc<6E-MUuPI_2C zz$_X|n4N6|>2#_2(`iAEyn}h(`^U?d9VP1(^4S59)^*_{EYOtKV9N-w9uQNT@+$H( z^LPAUd#lT;=A<0pw3~!OW*yp1XwRQCbIu3KLgW5Cv619L5bTtv%9aBs>Z#gN+!<}v+GsC`9pMg5`^$;Y9|46-%)C;B7TI8 z#$vgKk*q2`YuzR`?BP?0HVgK3qV&S!3pzk zP9_)fGSUyRv`tbzc5GK(@%-nl!$C(+00?!YVhQurnUXuTd>YhWUf)u!B(r;tl`{08 zI@h�MOIEaNAs-cbrg*(Q8XdaV%U(_meJ?P~{>se3{7)U~5Rlgq2&f5$wwH%PM z{>KWFZ}Y@akDuK4B!SyS(xy~PldUS zIy&Fmq&))bCvB4|^weZ_bh9oaX!nOa(p!SjM2p)rZOglhO|_tXxCo<|V>PTW`0F#f zO|&ERcE!dYe0^uD@+Bcd+W;Y)8a)rLm?==-@P>~D zazBvVpg~V@aQguaH5`an#Aq9?xQ;i03;sSLvBxk=LA5UlXJONPn|J`thf-BUu-g%4 zPWLd_!j)qPQ}2u%l7pfe!+n-Rf zqQLoM4lHi!J9IAj>8gj*+EK}EwXcp2pGsvr8f#C%_m@YW1BHtl$WKX<7ph(G{yb)B z_k2*X1^SDMsRu>i00{8k*A7rpvLoo#1B8$zcPO^9AEdqRmv9B;w z1f}4)n+u$(n~MLLFP%vEm0u%+ z56vNRP3>GgBD6@2lAuooK=CnQho3nXVTAU}a(!D0tP}5AvcyUIS(H7etR4dA=j+jM zTq4r$X57~{H(l$VMY7oI@<1U5*R+>26+S3{H%v}dCM~}m6N~x$Q7S84FK+ALOuk2+ zkFhr#01i-HgwN3Ib#ka^05aDFz!!JNbY$vx6`+vSTQ6f6*eBGc#V)zdfPOu7Oer=Yv; z`gei9ABd)t_U=|9PIP^q-MHw958FE}(N%akbEXn|gQ5!%*77nH!|ctZL%P? z_IGj$IT5T&l-uwhR{_}c*zc6#Wl9MX>3>1 zFi(gt8YMC?nQg3rA4T!Sld>mBF7mEB0B9A{^|Gvxpp>|Hy}QenYu>r0?)NrgEj|5D zYT8FK0iJet^0K6Q1O{&vfH~XP4LWR~le(Wl^MSu|tuO-g-x_kNWf{8d7?DZ8*ZVwg zdv6s}!b+MrP&%WE%toO7isMwv1|muc@p{@cY`s?9Vsew`>{|&m)UA2Jj1T~AP-0v* z&^AvH-79Wc9Q<5enzYGeIaon-?6-&j5(V0STt(TpF-&Jv>*d_E3t8jCCtYa~SE!Ka zCf_w=6M$6by;GLH58fZ*HF3@wGx_WgWP|ib#K(iR57K}FkhhC&F$KiU6Q+@}glo!< zRJ3h3Cc!yxkv+9d=~*ZT*Mm`ybD{GDqs5lhfHvEqTtUsZ9}Er_-Ji00aZLbPUsA42 zz73o&{b`t*MxQ|XBh4f8ngcFw)ijha4$99uoTIG!<7Dy#l80Z#=j_z_Gx=d%2_)%> zmsDJtAAnA_)hTQKphPJ8HFvahdUrbq(at7-uX(NR6l|{m`Ui^`jX7aK6bdtE|u?>Sml)L3QKMLsAm@oXlyS^543C9Un;k!{_mr zb%jbN&k02mA#B-ARGq8HFonRb!1vXY+7SS)%#~6$XkDZ+-ZzaGuN%nD_#oAL@-;12 zaa$T{3dXnn(V=BRrbmr&y4y#0h?c)!`rD?w*dozUKJI=w1lqr|k6c-X#1)}n&`Ib+ zue;xWjrL8olHI!y@!Nc-1nReeE#_PLUMXG7W78I5;^-j8g%6wkx)|m>&ra-A;9Nd@{YtA*Mb- zjY)qDP1foH;}>T+8IeM}oAEN`)eS>mtJ*_W8C}`QMlWnS4xo5IT8$U(#))7f%$7eB zY2M&gkhY>-2{AZ7+!4+<{8hA*U>sxJnHZQ9{yVJyNtw$j{`M`v1OW95 z6O_Oy7$1}pYn{jtcBq4{HK1OP7M4t5c^&-yC+Ocg>=4^9RV9M&llr0WIypl!PG9E< zW1ASCsfaR^mIHhyVwJ%Uv&~C{f!eawFmot4|fcIze6tSb0c112S zqhd1a8Wqo#@2b})`Y%n(HWc+-4B)d4#7rjx;QVn)MEDNb{_}u*1{rcZCIZj4Xbtwi zL?na7{%9bhAdyL$@A#dEls|du(5!t^A)z-MOlAT3dmD*$vE^bTd|tR-d@lYwCCR64 z%*@L=KCR8YEg=(>k7MR=1%Tud>EkUrOlq4`&ZG_qb#$_<9_S(y1@Eun|DoureiZkeqoseG-8@jzQ3gp90Qmb|gLNm%7&IZ!FbvG543p~KdArBkN+S364L*6~k zqPCg^OPPXVJKDc{qe1?et3csd&GpKA?iM0QNHr)SrM6B8Lze6ccYl;yN+rjQcSBVE z{_o;ioUPa_r0Ru}sx3vR7i4B_49w}*aCLexaWeZ}6%6~8n#2z5V}Re^>HCx+j zQaLm1qmoI#2bx3V`6a%Gu}^~f&4fSylTyA!QDlr{8G81|7h~4$^zWv0lzr9~AMJqt zjCpR=?#Lk6)8m!l9J2G`MbZl88*gvjCNm8Zh#`Ye6PLAWZ)Xz7GqY_ar?iuv2k<`? zInz?tQqWbc$=ifP^y1WJvJpLbC3)7*!($Dy>FvS~Tq{O)Lp+4@yxAZ{kEp|5Gg<=K zBHc1d!C>r4{__f%vvZdh`@Xl$nZW*P5lUP7tOzpbYOaNwNW95BYskc98Jb2T%S3*g zVF(oxQ1ppT07I^IyWOlC`AjbRf-%huKcoKqhYA1_h zvg4ZcNaNSrHI+2jAafp*~$A6RW2zu(|C{4P}C zD-VdT;}fc%G4P|Q9`0~u@dcK@xa+_B@04d}{P}c=*c8w&FPweeq#d5?TAt5KM$4-e z#ZoQynY(q5Wp!$!13`Qpdbz+_o^yyHda7@>U05Tb`=1G-Gos$H-l(|n`6lo`vdV`N z)I)SR>->gdu7>EVPf70%xZ3;jHXg$OK1UdMLieg1F;uwNRn%OsN07o>`l`Lda`Wk- ztEN)JkaB31m@+mM!4{ivA}!=D;!R!j3< zPi>u*UI^N2H`--fb6yT^hB%ieAh^2jEc0KU+RlJ5QPfo5A=rIDVsI3p+=&c;ZEZj15J%_#UD1N)a- zwEHQ1h#9B0B3^2F^*||AGs;Nri@MjYAJ<#({hkqUvk^KBBbj#YLm#1$uz_Qe@W(@E zA49vMF-d(0<;Gdo+s%j}!&-J#qF*6S&HlI)Fj$*3n6iIxtONPqi3o{%%^U=3xt80Z zmA`yKOyBmUZhWb8w4*wsiX($0E{gY86|ad9rhcF3GGVp`weQmA;H`r4dQEB0@FMbxn0;f;<~OT zS2g#)OP_6%RONvDBL>9K+xqk*s(0$ua&I2vww=HAAsHGhr_T$8s`=_5vG_on?+$Dv zs>Pq7>p4LkKReqG^lTU(9qYGhDOTekL`#_7Ckg>9qs)EHnViRn5bZYBAQlH^Htu54 zXW78Nv?dFEBI5?})h~2+xfP+A;>rB`lIWjgHp@SBX2AWb2WWhvH6pPk?0%xUi{^FG zbL%ytVxp^pkab(rN8X<{-aUh? z%?4@V(59i6=?H-l!;aabj!F{w@FeX@#v^Zm^cR8b0*CLx{ix)Lv_m`?I+$2#uJ7yE zXZFt@`mq|nx$*XfV`LEESrRAX0);ke4+iuQkaz;fAh_3GqL?1e|4Ot~{>A^El- zN#z4h0_DQmpxeiG>a?7`UqXl1V-?H?94z(qAv&uYyOqtXcsjk9$p}rG7c?43rli#9 zPt?CqPbhsAA!oSG4J+c zNYz0x^HaCl5Z(L=W3w9y%Uyokr)L47%C$;9^fK`nlF%14_5RL>rIww;g0x=$Jrj|dUO%^PY&2yMxAw#vcpEaS{?<4 z9Oa%o|7Q`W>PmU|hE&vu*m?b0*n`?5T7Wb<|}4+}|lo-XD7+ z+>C^f7{LomnFtK`@Fe$=1BLYIi2ljvr;pUhpDPOS8r4AvsW|JaJ(5FQ>IcgG`kTw- zjZWM{s)70H8V|@e=Di^a53vvHYo!=|^acnGy#1HY{5yDNg-vKf^dFCyg7s<%d`@C~ zBz`gmmHzKVlhj6S$)=pGnv>(*la&{dAis&*ONc}u1Y~J1j-rZXotaod4Gp-ef9*+# z&x(TouZ7Dry4BU-Kck~$nDm4w5sD1eLo_Mz8mzXT(&)TWk@KoL*xF}zdtpQZ*KT2DS z$s5{qz&=93<*!VsvGn8zqwP77W4srCb050l6saY9Qm6&xRL zQT7R*tP}Sn^obCj{Jwja7)^=M@w1~H=c1<R;)rn7(RtWZ_mp}X531{GQ^~I&vssV z#GRiS*AMK!`W5}TYYGHjkF{56940@59x7eLuaM&D2(21hQ8Hd^$M{(P_i&0&=@C%(IiZnAHzs$O22u+*;?x^E-Ep z>;V3e?#CI&ko1T27eYD?4Wl*7WMU*c6{LfAKOZAiKz|7mCCL`BtwvxVSXNIpyBvH+ z2E0r65M)F$ONiLZ0{<;q|2Wivkw6`|;Q!7(T2$p7q-#udmRS_ce%o867(ytEVmfSX z5uB*W#}7ZQZ}_v64A>>v>2xkA78Zl^6)}h@h_xv~FoYaxFK8!6&n5ig*P;01dvd+I z|8Wx%l2^mQ?br|qTDD$o^^uyfx4TC)-iUVY%$-ZGGe3d)HOfan?25w>Z;Uk+O+nT4 zydWfJIPJNydI&wi$^(44CTKGIfp&;jc=GhO#r51op*@(-RGS?KkKD7oJ3zk;uk8Kv zU?1Yb<|(C~`B|N;g z!VZsNgAo16<^j#^7*_e8;}BD+i9lLnuvH(H$MD$+iq+Q}LMnSA12QMj%z5S(&C}(A z^QpJLl^HPVJ7S+6&3*vCPgPL!ZJyzpb5@PI+BrGHVsTQ^+(z>!>groTPp>IL$ktGi zU8^*bfL4$Cph#dT`?|&>pCG=SyYKcb6F&p|3i0Z%XIf!+Ru7CNs9hPZ2~n$v|ErT> z+0NIAZvyiv)S|>gsxk-+z9!no`oDwrYQ0_LpG|jf>vP8Hzb1p!FT@`{C(~098q9#u z8UHG*s?g>nH9VyyOQHBg8t6~D6p+?#N{ikPoA%JftT-0{+TNm7Q_3RQ<~C7&^oC;VkCfV$p{>2&o!iw!p!O7rw$Nz;z((i2y41oPLZHkCC83>NqCiVJ#yBKQ8dW1X( zeW{1DTTRVz;Qm6*h?WQhXV7}Hzf+-my@^xAVod6%cA6GOR#$L8M$xussxS<5WBcXr z`H9{R@Yb(9%CcIVdYFqRL9-Cgg*?+P4=zX@Yc*QQ5$b)Xh(X7?;BKs?%uKB9Ejtju zqVz~~H!<{5zY4i;_h%GTd{EfNekk|b=HGVd?*{ywpxjSUm5CbCGNTGF)b;g}ETclj zx8XOnvUAR|k3s!PNQ5K?;RRqCc3;04eG|A7=43-ZlI5GPaNw&P4#CV)a?eaDNlcmo z!YsKZkzXk)gzsWGs8R=RYurZ+Lx_obUJ^w)g1yF4qx$nPtsY&^!Ct>VfpM5P6>mCRx{8fS)&O2TfH-hM;F1I8nTzU%tWU}+RC^w zWwF2K^hz1V2=vFK%8bN;K=Ulga7_uv8(-+Ga>+er7tnhes*DlS>p9EIF zw$BOOD;2!{t(vZ2Si2Z9h9@Mxe9rVodQnHAkX9*njdYunqsmomg7wJF_ZaZA;)R^N zcSrE-IR40j0B@;c%Zg{uvjzS2j!A)(-5|f9n`Pru^_IjAwf748(ItK>*{fNUqkbc^2TGXqYDhLe>Q~OaHd@(k2&pM%<5O>rWt95mVqqaG zRBlOX%ndiuWBayLxDkK^{1dp7&)wG`zo7ASvm=aRCeYG{ghaDCt)7V8iamzZ9TN~f zBM1<`ny4paT881`Ors{97@Qs~58;J?e@Cg+Bll)yFpPNvYrI7Mx#`EQU8LcV3FpHr ztyjYJAw|&uQ=ixBAir#V?vXu2-sGI1t@v}P;N`T{tHYgH2&pb;x1}0-QcpkPnj%%Ghv%7Lnk@;HPmL=~MQ9dC5fLG0LMoGyTJj3Tkg95s zd89n~5Zn7e-UboTu%xo$+T$O+t(1weNV9;%pR%Y!_dnP4%|_BGr@{~H95VE zs#Wyme6PC)&R?oTh{Vi+;g%wPBfCODcB6VLgwt_4vfa0Xs^M}sgvx|DNXkCOFc+6` zG&V0OGAoNse@VZ%+wA8SOONt~5E>;4PK|0qhup^p z%(QnJ)?Au;h5~3 zB81deuwA$%fM--V@LPpEUYW5?tUlz836Y(<`tB>RA1IWdtp`k#L@q5>>G+AtEa9G( zWpk&~=J0K|zvX|9A%tGNM7y;dntx#+rSjs?Q@xYtLQAZ-xE_b_;n&jvKCrqg&+K7G zqPkvD(}2cdN7|A%Qk}zvD^6UP^aH#hm`1D(&Biw@Wkx%?wT;Wovt>`%;VUfsTivZ{ z%7J6hUk>A;*@O`EdP4KR3xalzqSqG_zBC8&NZ;LiIf;ajl76PN%q$pz!q4RJCgiam z_1h15%6>MXmxsR=GymT{u$$686d;hN^V`Nm!4}?X9(GZ-9;Re7`;*O8K@GuD?#Q zDc+MvTe|FbUOQaAxn@9rEG>0o)GZ)MT*X&I-8H`l1@_rJJ^eLodSBQ`Apb9h4l!5m zZp8>t=QccYqdKW+`^SvCwD;i|`yGISLH@~38Qn!=HbgC7eY+#`mSyQ=9#d#&bf+oa zL{{{NA|$4kA+9V&foJp5&P;kZ)OY2>z-PPg-st9Qelm^V{$UnZ4R_^vNCNeT>={1I ziO{Qmuk*fbc_Y;xjWoOm^|=<9$X6$F5@)u~2LZ+jvmc$O?$2j8g_()DK9(N<|3c79 z(eEb*PfoVmQ8lq^ptqso?BBIT3Pq}S1^no42$9Xj7l2B^(x><3Bz_DtgYet?D4b{$wfjlZhdE^wD~T ze7aH2ml=@>YEpbDd28^T5b*D4_}6m=V1E**oviNPjq)-KQXOwBY%V+Ba0#OZ{f~xH zO1p1a+&su8?@snTF{MXc(9}Ps2Z(CryJq#J^FTr>Ju%ek(mib}%{ncNdU3mD` z>*4CakNQ5lK!9J+!UjaLZ~_DNYSsM4+_=W76CDomZ}Y9v+2`vIk0C=dz@O|CCD6=C z6{?!71#D+;_~vAM5!}(-vt9eH4;j0`G(VkElbAE+*Bix0nXtNp<(9G+*Tcq7cL{R9 zzUZT1yFKh!0fqQ)mUq*AUdQn;2HOhCV`*4(U_ic54wCw2$JABM(1Y4f7Y8m^R2a#R z8qXg0G#7Xy8iD_MjWmDN<&ELV&vjY){VA>Fz%6%ZwAEDXc1Vs{x;KOj%@!YvXT-2v zuWyhnpJI>Pvb3O^+gr@44m`IZD+cr3#Ox~B@;qcRV0sGtmkxf`-qbdwe?yZgx9m$_p_ z&hxgCC;r^Yuu5}H=!TRngCuu9Yh!5T2b(n*GTlr)Qa*f$S1pE(z@>;r;r+d@y+-)A+;nt_ z{5OS-i^2UXOYeSUMN{4q`1)2$i$%VatRaJ3m_JQJaHZjfJ>lHA?a#ZZ?CgjNJIaH5YG)vjT5#2t(SYl?M%eVIss zkG+OrIB|UvVjm64hkiVnFbj(>7!=>en;CgS0&$lWE?nFqF};>cg&XcIzpDuJ4^wbD$%AJfw&JxMxNV*__p|n6 zN^1o&jGb zydg_%$(&4aITEAR+O>ao3_SvOW_5ZV$tB^&n(h#;1Nk%N6}a$@5koCot!#Bl@V(1q zxcEuo68T`?k(11A5T9rySl!!ZLUZCKrO87-2-H6hnOtXhtY5>CF6x8^^9wLRruR0f zh6Lx`=lH98Y$N^)q;Bx?b}S6^FIh0whm`elg-8ON2wwT@k2?3pMulYH;tX+&FU@1G z!=$AF|3}wr^AnyC%Tc}|(R}_0Sp0qryyRK===sDs!|E}l7$Pa`hT|h}EM0M`d=!rF zW{M9_l-p0cBtU=N@huWsF{(B1g*dRB`MD14$z-SF=P4uvWlL+7&->3sbtexCS^Y0T-& zZZc$o43ffn?(R-A4$(hIsMgP=hb2*_A}+K2n7~}zE;D2X_(7kSoAx^&iM>mwS8FOP zStsL>7=o&eF+MC^>=_u( z%Rvgo@z2atd%Z5(FwDXM`BX(o3oXUd)<~>e+X-3|neS-xM9+A0E}>U;4sTX~^U+8t z97|n7aF=SR^(=?b2dbALe@@)|LB~EJ9l^Q@DXQhd#geSi)U5H$4G)7&UEZ5@5xB;A zIfKk9S)#}wO?4i4_+!BTW?5oo)s`5{|Ed4}%Z<~b=?(9Ew9mK zG>4VavB|?W$~23AFg_(VI>#&M9AWr z^8P30O$FC(Xp;ja;ho`*CR>&YyP4&7>|*wlw}*YC#G2S68h(U?P^#<_J_=)hG|Du% zldR}ouP7J4xJDP{Vuc*{WB+RhZAw+i`}}&0V8C=Vo9d<$tLh82z12*!9(f(pcDpu6VC+jWXx9wFleG~B7N{%f* zbIlMXQ#_Ps1obs#5fybGdA%X>l*GHON4Nj}$Wqn6b9n#FUqOW+%KOETS{w%Bb1(7# z@oA+#MZoWi49Lt~#V9A!e`3$&lj=bH4QuwPu8gUcsTd5s92fhrrQ?Tr974*(qa#Ge zy&K?vPs~0uuuo}x`%3CNB-X%Ae`q3zn4~fpBm5cY_fvenAL=HWQs$Pr_o|2}^>fOl zk7jW{C3U#YBHFy6O$d2$52K8sTZ}iGRQQVeI$;NYNac6t$^!S^M+5yuY3mWa6$wnr z2j+(ie4_KT%w91Wbks3QF{%nLz%Lq@E|Sz^iE-_l?GZT)oJv5x zweH#ytzMEimLx{H%{(`@A||7Cu0Hq%vthq7$>|OBUzL~WgFw*ZE<}hpSEOj}2)r|% zi>y)+!?pD69En7xnFZmGc)d2q>rOGax@yH=K73lEI@}{ZhMs;nY;GX`tiwpeFxVe*kJ4d5lf6g1Z8dCuc`!^{;_Yc!hJ77oa`i93 zmm-%$|0wyA=%pVU&wWW`4K=*}(KoP1#xa&Uq0WvCLP5N6;xh}ZK$&J~g{ivF&W#uF zY5)H|^I5rP+A9Nm4Nr9@3Na5+<310%mpkr>ruwpeohm`zBk0n!h_oQY}(z>lb~x_Rb*Z7*WD z@)o*a)L5rZlW2U6r-m9wX7B=m1X^4G>I zU_DHP$Cjw^9ZipH`Hj-cHIvqr*R}pglVu;a+0eX zzuF8h4|?8CA9(U{7To`m5D`&}Wlvqcyz1`f_g?uKOMZU!AK53TI(P3KgY!+&BMM~> zkxOrArTla==GJCE z>5!-Vm+BC4IjnV%qN7N9*_f5}?H3@v(Mq)?T0R+K#}PFo-`-~I6O@0t&+c|z=0cyt zVz(XeUqbLRp)5SL%t=S1!hB&p&x7vW`s+75I-hJ^CDVsceLl`a#K{GXbouAb%a>1{ z(nVc7fmC|WCRjIEVPHKxL59T0PU4iU`RUmqVt69qt?hBO=nazNRnxKkERg?zoU9U! zA+kkRt4$?^2k!4$&Wb~WKepABLk=h4`yu#+4W=42bwLr3YJAd%x=B7sB6#hZ`uG{s$hHcl|o5_Iveru7n_Z!QV)b%3Uy@cof=}$E;7d1qbKE_Op%s=(25DntBzD|6V`}hG#9-rDO@lymx)a|G z#8*@|M0~AjKw`1NbK=xghlSC;mgx=+p=X}_gxHvgoytwHf1GgEj24D#OmC&+%jqp^ z<^Rf|*J+N8oN|MXR-2IKL|%%xEQsHwH)iD58s;1y)2;O*=~&cYKl#@IKL81jFj#0e z#B&$Ab%?T+N`K(6EO;Gzq=YK*{Cl#@2G$p3g!7c5nU-~0+|{G|PPYf1nN^H-i0LaB zl4+BH{7ka;!Pg2j-QV_{QQt+U_&dGS#5Tc1(Y8;rta)JmkNRZ;c|r$*D*03P--U|) z=R*Dg{Y#NCLY$Kd5rx3M=!=R<3o{b98MLEAt*$J{%jDraL`|p{#pkN-LZCj%fy({s zMT@7HJC`+SYWsMPYH(gjKxJq;L#yCgKaf8WPp!U#QUcq{>Z~`;nua3X?j9AiAho^8!SfVH*L!)C-`uQ!QII6>)-As6%6Gql7>P3Dae^< z<%MC+npmm6xYPJc`PK?!T4MRaW9Nc!qLM3e_2L4^hO)E>m zYKXJNMP2vLcb^mLHOtQsgAN5eY8K+EA zqOlzZ`UgufC}2`1@yhOPyST#s4Hqt?k`9a*O5PZ}9ds zw)jr|*@QNgoVAu4%t&-$UT5{HpMBJlRGuDY{rHhC>$6EHWdrdk%mDT&Wr*%Szo)S2 z3!1Be0l{?zTDOTo0n-i1WFWqeRLZP`Fzo5Utd$aR^?H`0M`wM1H&+xq1>OwLLMpKc z`>b0Kf?6gkp!^98CEsD_uSssLDc(IOn$ZiqCn}^Q)07XxrSt0Xe@f9%Z&Tg)kVew& z-%Tucxk-v({$Yghe1IdC3)k25L`QZ;%dd%J;XheA7rE8kcZcBpjQHi0-=7f}$`ps` zvEobAuDDEZSytPn4|YvaGJv15A{8gx{HYYp-hc|IHYBXS`F*xBk$TmwzjQ z_$E-M0I7$dmM$CIdZMl*v5nxkr!@)%!#bXSO!S6UW<}G6_SlB#wx;@BZ}Z&1=wG5? zKxGu_DO^1}DXN3$H2s9LCHP4KBIAZV#+`NMH6{o;xC(9l8G(kz4$3CcM)2K?3nGs;q4cM}IVHMLl3%#FIfJ(t4Q z0Dp+6xpwJOqxo^X7HbTt%<`0EHy=ueO+~Az#^C{fA1Qd%;P-4fmOqL$p4p?K{^5+n$`(jks9Ow|jaYd;x&cB2EY)ZVaSt|5bj69S5dKUsqQnVFr$rpm2Q zCtoM4XAxw!Y60VO(`*pk3!EfTKnTsAJ7}bT*=&|n@#~{U#_{LxYX=6L>UCg#p_f|x zp&*uQPJW2%y5sK_r@nJ_(Mh>^iP*)-mjJ(`WljGg_wmfQkAa>-X>r|-WF|Y9Wb>KJ zzw4ioA;J3=8B&>+4H)`7i*>HWi+RC&MPo8ybnK!Td(@x*gai8{szJ2rMN^DkR}gya zz&4n`=58)Ga3}WHt3!(?K)(b7a?xw@+@^^>Q1LXezb7# zce<8NccdDf<>n8HxJ}I7EmxoBF^VYdXQ~_n|6Nc^6ku7(OTR*5*uCGhu<$v3(XcKu zBhoW?8{iKZCs?n{jHMVe6T{!!D`d{A5oFP6*a+Zc70AgAhm1wSG>Acgc#0SS5&6}& z%hs|sd{1%?kx?Fxm+mFAf&M{d4WiJ=5Os=+t9ELxZ?2q?rO-(rhhxd{OKvRqKB;dC zL~nNlyDaZm`^ZQp>BI&TD_Yi1_oN{HY9Yu!YdR?qVLf>2Ebhm91I;F!&mW|}y=Pw% z#aEC7|8E$`2T1Q&en+q^x!glVsQ2g%AG561ez0%Jx}l))4cK21FUiQj#|UPW1Nnb5 z7eDBnO?&XFB4O0zI^l&obs#??2=EOjiEVMx$nlx#)Qy4uUJ)Ocq*}z=&63nQ$XN6$ zV$TMSrI-0t)|OQLZndCmpWU7BF?zm--$5Jve$5TbJ?~fyt#q4*2#-Il|JZ3Ovo%AA zxvm(tY|a}Z2r8Qqg~WRD(n3u6El|R@7(gR`e0LJP?xjj>M=`ixm=IB^3B!mQ>UPf; zSlKOi;v@ zDEI_Hww8C}Gw!JaO}1YS?YC9SRax&Zca_2+leknfqSaRndq&0$1fN+2&28ul<0C(A4X-9jQmgW5;NHy3bBzq|U!u#STn@VTTWr<)0eRW zr33T5qW;)Yy4~9wnhU^`RBf+Y;Xu?FdwltGRBKvxjTutaKD9 zKDo)!ma%j-5BLXd6{{FcCOliD%rCX53Vn2D=d4>^V2!VTx!5f?B*cdfJM;ZVi6JMi zd@C?&u%Siub3%sd=xyN3#|mFs^+EihVG~zGkEJkd%iEGu<;Zd%G^1j51nEHAIk44Wqha^Dg_JPHGa}V&L|5`N7STTm6G8 zUY^Y%CSy2Lkbg(&W}1982l1iQ=mWc;?+>rgo4n*nt&mpwQrDs_TMYOc*)Dqrj7~L+ z1HHrt`>RriN+P0zePPl`Qk(tO0INW7m8e2Fn9U+Zd?s4i&TKUgw)}6wc)9v5`@k1P z@V-;LiyB8hiCqtt#b6~e@dL44h!Zl-sidcWZtrPcCtXt=ZPo|#Kj9^qe1>?Z z~s*1kjotOIH zzCMKF2&?~n%1ENjPn1_lHJ9(MY}a!y(4Ur~ah`qUrngFE zmgPj%p+M?J3*W98@DFhj^}ly*-|}b4e&J3{e%CidS6isv@KDos)>B0ae4kpTJ&9Hi z&w_p3jkmNeSv!&`N{p@T5;5nA$KLM-_$f?@L~{vGmGtwcgH!#`36xlCnUF28H@uOf ze_s*!FB_vjVmGn$DefNyR2{xId}|gUB6x_>MmNEH*KZm`?{8Rk>C7=yM$*vO zyP0m|S&Q?9wI|N+MHC@p$f=0v9fxI1cVUR-u8WS6I6guTqT?em9BX`l|Ay!-5F!d? zkf^hG`?sg#FV=CUd{@58>tJa~9n3)s{3~azE^!~^Kh_hUYbS>z!xFYW4T?SBU-@#O z)*-4JTozO>vr~6T@b8~g`1D$-vj-Vf7EDBOPM^CU=!Xe3=(4K zr*FUC2L6k~FC{C(5<#9y5FkT({DNX1m_7RL6hbh0QI`hdOO&RBMb? z%!u9)o-VO}-Jzwf+gR-^*NOE;fTr)&#Sw3S59I14_89oEfb?!g^T!{x#w*-z|ZqTj;v7O>2d9k zuB|<~qEo@N+?iclRh8s!bo13Qq!GJxn?#qdz@No0-B!~+XUfCCO0XlFp^6chsajwI z^Vi*sL_z-(+oJ3#OzAfH2fa&Izw3yW*BB%l%`^ghZYXMUW)1RJ@xjX1%(Z70?N4yT zl7m;bEsslXE(84$bh7w8Er8`Oz4t=kc`)D1X#D)@zez8?GL`w(8GTTH_@>m+Z-nPg z`Q?{$>2KO}0mB-c;SZtI;JDz!HV#r&x3M5m@sk*FG7TDEmSf}(-vqp}Z&AxuNn$P! zK?3{wO_GSP8=_1bw=pdVj~2Q!QsmyZ*8Shkh~Sk+n-EIrhCvrc8i7`Z3H2&{@%^)5 z%V$|XOC~QRCp>7_0shJ0|K%lH(7!ZMd9Em>oiNF&sG)Q#*1dH3j_d)@&pscJzXJKk zn!#T2+NWC$bghIEct3XL->g%pEfV-=SYC$}4S{{?TGpE|(_smdWe$efL#p2N-3x{L z;gG3n(1kNA7LcEfmL{l}cwDrDvW~S*v|hDF_ZQCt{2`hK@G;;=XEu__hg35LZD7L- zPT1*jeb)m2|GwgiNEr9K!#zB=^!U;~-PL%W>D92+&*s#%f8#V>OOQd*BK&)MJtpz~ znfb{PHsY*M@T;ZKZO{5D7bH9jRtLS06&21(3c|2$^wCfYy|AQLP_Yh$9wv@-%JRN$ zI)+faIR5#SAUv-^#;tp!i#JH0B6IeZpERA46-G?ubpO9Tn$uClh@nqISxr64iqta3 zM@em|8#$gA>bs=?`4SXk&-@DdPo#Dw8XYCn7il(wYfHmjewhu5o&M|w_#d8g?p%jq zl!cAJ!d-Yso^OdoiGe{R;KU|nNcDNDI-ga&a(27mB?}u zKL+vNW#J{0{6U4BDPhT^J5K+Kgk;uqhoO;#JKM1V#n7hmQqGx&0pMQ*J>PnC>!k}i@`a94@0Ri7V3&(g|S0UywJ+zNZO19ZS7f181SmnyIzF-67{#{K+E>joZ4 zqMnEhHOFO2Hyq!SO$POmxU08G*{K*l4YT34WK6t@iRX4!QJ>P=f7}u?g}{D5LG~oJ zQZ(P<#=RB`70tPK0kos9W~b@5UVL{d#6haMsahQ*9s=LkrAtY*%`oLwf6~1pw_-SB ztJBUEpnveHv~wGFEERSoQFuaQ>hrRl#*3Dj%YOHoaT`y`K>bNZcooZv;FL1`dF>73 z`O>MrZhy4wF&>S1-})BBPZ#nk#IJMW>5H?1I4heN*zG$H5ti9(q~Fa`BGcXwonuVW z12IM{*@lErri$&&WvbCT_b+JBkm#QY-#!NYeH{gPXKXZh@+ZB&E_~q43#4DuDdjb{ z52pJVYd^*Y__ue3Nu2Z~wrgta$CiJib?&Hq+T%FUyenEF_@6~Mw5jJ=PjYF+(o4H& z%HL&nw(QzSm1TV@;WGTxM%-5sqVco0Co~&v$mAwmHh%Q_;*meAu+?LcOUCXm8b7w! zL7Nxjrv9*$4w0v}?%wEgrA(S&ti06pPqc0!fYxJ}4PsHd%igg~6Yn^?aaql?O~U%9 zlI>NKc7x9K@0ZAY0KU`pk^9r)#*;_Qw;?n7GKVg0%9 zHHqvsV@s^vZuEV#=oeLgHqPkNO;YLKg+nVkmxW1ET5gUwQ%cbrOzBumI@^kJ*)5^S zUuXk>-?&6J_Rmcy-u;)Bz1(!om4!HE2O~SDX+5Z{%QZV-`+t5W?)Q(ZHyY`&En^Ra zY;M*icG2>$imqZtbs?u=NCd@e@%!W^%p|1+ZG2TikqviUnqY3*^k+cMN5q5;@Mm3= z&TrUOnaMkgT;2+t=#r*<>YR1J%w2UkXT%)vr%|f>e;V@~I{yo(KnYo-w0KbLaaS6g z_PuX}d~eSJewcrrNL$dM!=y9o`o7FWecJsS6o*S#+s+raUKc8Y^>XS&FY2D`J7XTK z^4<5I>oljRs&3%=QBiJyp9Zfzzt4c69$?6Zd&D^0pxoI&9cu`&%(bYRGA;oA zst87QZbL37CbHt`Qlf*m*RPdUyQi~l#jbbg7ox-eKfe>iZ(UL`v9}|i_ms8~avu2H zeD-$t!cGU3zW*%5!WW^^dW~bDjce5BszX^_@O)k|*=hbPy@P&lowOZzAD~VAo&I2f zh_F@=?6_qp?an`1;Kawaa3#y)?cjXHUG#{S%uNFcO~pMlb=yaQ$9OhA5Qkv zRRr%7$QvdkGrI&hfj9fKe)D646vm4Dhr`p8TEw?^$siteQBf5AH%9y0%?HmOT)Mi? z{;YO%9WQcTR1&Uutqy_-C7aBunT|efWk4<~`i>SpyDoU|r*7IzcP`H?=x<;#h1-1b zfd}2F9Me4hk^J{5`HSxugKwnL3d2Z-%x(zA=PA=_?P+&ZS*>x6vNbxA{{!XdE2+U1 zvaJ;`?Hoed!9ji*W%6{Qm-@|=_{8?fmR2ea`LhgLsfyrTZ%|)CnVfM_Z~v#cd-7;U zlj_maVB6Tgaol^3RlmNWkBK zgZN2E>bmrm+&xX6dv`bm(!K>4WpV#vWLO^t{2Ws!AtIbf_)GRrtJWIX%N3cA_zKr# zO8qViYrV$}1OHp5K~!Dv`6m%%@!(#NaPR1%Tkzf;gO#|KQ9u$P8qrWt-!+r+*VYLN z;n#I?`DOnW4!`VldYr){P+bfmlnTs<>JBe{X==uqEc9O7`l7H)TcB-h^*Dm_l|0Db z>)sFw?`7Zmm3B70s9`5i;aDeUhJDM_Y@&+tSKUvjeqOc zt-go%Mrq8Vi_vA&Hk#K0b1+|3V?cgOH^DSc#QnuznVzT*6;P^ItM`!;n?PYgY^0bP z$WICisv-g!rzj^L>}3~E8SCoDu;NTYc(Y7d4BDPp&w}~0*@dz2{`wU&`HvQ(L|#~aLlR*s6Fku}&&U7tK69siJKxIc4A@i=x*Yt!-i0^qlZRvkt5 zrM);Rp=H}kr93T-XzIi_bUdn1DOPeCwm!yPqOycwv39V2ap#MNprDnGsd5*6&MAR>$%_ zmB@t#KT?>POK6Qw{4BGW1@VcT0?`~I@0{nmVid*2_2Mb%gHP{h$Mc6=8g|md5Phtg zEm4RyWjpnrOO%fP*Poj;9KWvybP`1z6YuMQ^OMRpBdWa=-p+zCaOwnV9VV6Ny{H^V zp8s!sYyNt~CIHue8L9se3jhpgAa zmuIDIx&?~LR=9PYox5;VaYBgqZ;x{ifa8brZ7;o$V|;S$NBqTkekBRhE{fcmf9GoP zk~iDfS%BvYfb>gACq938MP>PsrOYzNe{oI>`T0~}%j@$K_5<_3nJIAolTY!f?rw(% zGd4~v5Itk+Epcda!1~(_YDYGJ@^4tK2hYP7$3$PvU^WxJA0zzoc$7%RAK-Gh&-K9k zXTL`Mhsid@HTApA%|#^E-&_63s?%v_!$Ld87P~Ic`PC)B{I%oZp-gvO4Yjx*{nLKF zow#=2i}(Bs4L`6t0Ovn!fb#1fzQ}zwBV9sKIqPp+yqHM;D>eP%^gmNC0L$08`ats+ zeAHN8dEM6N9;X3wr0A0~#T#l@RXcPB0Phzv2F{=Eakx~!qw{RCm+8hiD~~B{u~?UI z>~frR0fP;PlBNES#EgbZ)oo|zeKzf=m{ckD>5A#Er~}f4d`~6-%YT#pA0~B;-ukn3 z6{Qx%KYMq7#?1vB{}z;{eR%o`wEh_w|MFgrOJ{a;G)L*4-v4cqW{)ysikb!EmLAGZ3%xL&{=?0JW+Du`^ z7KxzDtW#fpu*=1;JUU>*URmZ;v!i=Kd`8w2=UzFMutn@wzvn+?tI_I^+C1|CuzfLi zQfZI17O>7YtjjdvLTbJS%^5e@T1k zo|{RR3=Tb<_!JmF&U2^#Fg?A{+iu3C#1pH{zaFW{w_i4U;&thDJ?qW^)2D!@J+S}a z$X7qBoppBCk=<(QMZuN5S#w{{iT>yhwBODQSbuyyFs=TU;KjYm?g`J8U(ge!9ki@z z=Hgs70UJK^`Tai<+Z_2dqz#w;baI*aO89PtsX}kfJigw`g~0Wx_GRWjOkXnc>vcul z47GT0`el}S^W5z0BX8z$F-sk=;j=99|6#IqLA2iSRo7TU6L-CP*JSZwegDts*%e#F zf$~Zz^M81mERd?Y74M^X`MOMg3eRC~p2@vSm+f_&0?a=SI`3YZaXa!0a){m$ef-|Q z|4L%nu}06^A!;j=;~Q-FLaTc(iAWugXW6wc(z@ViwQ=z0+0)Li5V-kKf6B}P8#W&U z;P|mvgGtq`7}s}O8OsmPXiL}}FS*VC$bo`00XBRwI+Ir#oIW5`_0n%y0>ee-w!&R1 zOTOPZT)}x#M#RB}Ewl>gf35_Z@Ao}aR;*w8t--X*y61!IyFSsdUIt+O5L?>+Lw0F{ z=@PFs(f4$|Y}@F=9gP$I{9LHhjklJ9UZ#8YB)|sU}tM9N8Pc-ENXX#V@aK z`uq4-IoNC#7vGj_k&wXn{JcQ}1H+_dAi==Es9XS|7#M6^%BrWORX%*c_`K@_kbeLq zhy-l989KH> - - - - - From 3af4c5ca762999d7a23314f4cdbccc0bc3791037 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 26 Jun 2017 09:59:01 +0800 Subject: [PATCH 106/179] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7=E4=B8=BA2.7.0=E6=AD=A3=E5=BC=8F=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 575265314b..a167cd8f48 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang weixin-java-parent - 2.6.5.BETA + 2.7.0 pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index ce2e379a51..66e32664ca 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.6.5.BETA + 2.7.0 weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 29f53f89f0..bcc4e73bb3 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.6.5.BETA + 2.7.0 weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index 5aa2ebd485..71601ef3a4 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.6.5.BETA + 2.7.0 weixin-java-miniapp WeiXin Java Tools - MiniApp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 3be0615ed7..bd8f147cb0 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.6.5.BETA + 2.7.0 weixin-java-mp WeiXin Java Tools - MP diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index ca66794ac4..4f24b0a9c3 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 2.6.5.BETA + 2.7.0 4.0.0 From b401be5ad399dcd2592f4094a75040dc9742dbc9 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 26 Jun 2017 10:56:58 +0800 Subject: [PATCH 107/179] update versions --- readme.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index 3961e33fd8..acb0ba84eb 100644 --- a/readme.md +++ b/readme.md @@ -18,10 +18,10 @@ --------------------------------- ### 其他信息: -1. 最新更新:**2017-4-13 发布[【2.6.0正式版】](https://github.com/Wechat-Group/weixin-java-tools/releases)**! +1. 最新更新:**2017-6-25 发布[【2.7.0正式版】](https://github.com/Wechat-Group/weixin-java-tools/releases)**! 1. 开源中国网站的本项目介绍的首页链接地址:https://www.oschina.net/p/weixin-java-tools-new -1. 自2.0.0版本以来,公众号的接口调整比较大,主要是为了解决主接口类过于庞大不方便管理的问题,将接口实现代码按模块进行拆分。 1. 自2.6.0版本开始,微信支付相关功能抽出独立为一个模块,详细使用方式请参考相关demo; +1. 自2.7.0版本开始支持微信支付,具体可以参考相关demo; 1. SDK详细开发文档请查阅 [【Wiki】](https://github.com/wechat-group/weixin-java-tools/wiki),部分文档可能未能及时更新,如有发现,可以及时上报或者自行修改。 1. 各个模块的Javadoc可以在线查看(有可能是最新的测试版本的,请注意观察版本号):[weixin-java-pay](https://binarywang.github.io/weixin-java-pay-javadoc/)、[weixin-java-mp](https://binarywang.github.io/weixin-java-mp-javadoc/)、[weixin-java-common](https://binarywang.github.io/weixin-java-common-javadoc/)、[weixin-java-cp](https://binarywang.github.io/weixin-java-cp-javadoc/) 1. 本SDK要求的最低JDK版本是7,还在使用JDK6的用户请参考[【此项目】]( https://github.com/binarywang/weixin-java-tools-for-jdk6) ,而其他更早的JDK版本则需要自己改造实现。 @@ -54,13 +54,13 @@ --------------------------------- ## Maven 最新正式版本 -* 微信小程序(暂时为测试版本): +* 微信小程序: ```xml com.github.binarywang  weixin-java-miniapp -  2.6.5.BETA +  2.7.0 ``` @@ -70,7 +70,7 @@ com.github.binarywang weixin-java-pay - 2.6.0 + 2.7.0 ``` @@ -80,7 +80,7 @@ com.github.binarywang weixin-java-mp - 2.6.0 + 2.7.0 ``` @@ -90,6 +90,6 @@ com.github.binarywang weixin-java-cp - 2.6.0 + 2.7.0 ``` From f72e60f49a508df6e5210d85006d2d6f0486f067 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 26 Jun 2017 11:02:15 +0800 Subject: [PATCH 108/179] Update readme.md --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index acb0ba84eb..5d0c6e764d 100644 --- a/readme.md +++ b/readme.md @@ -23,7 +23,7 @@ 1. 自2.6.0版本开始,微信支付相关功能抽出独立为一个模块,详细使用方式请参考相关demo; 1. 自2.7.0版本开始支持微信支付,具体可以参考相关demo; 1. SDK详细开发文档请查阅 [【Wiki】](https://github.com/wechat-group/weixin-java-tools/wiki),部分文档可能未能及时更新,如有发现,可以及时上报或者自行修改。 -1. 各个模块的Javadoc可以在线查看(有可能是最新的测试版本的,请注意观察版本号):[weixin-java-pay](https://binarywang.github.io/weixin-java-pay-javadoc/)、[weixin-java-mp](https://binarywang.github.io/weixin-java-mp-javadoc/)、[weixin-java-common](https://binarywang.github.io/weixin-java-common-javadoc/)、[weixin-java-cp](https://binarywang.github.io/weixin-java-cp-javadoc/) +1. 各个模块的Javadoc可以在线查看(有可能是最新的测试版本的,请注意观察版本号):[weixin-java-miniapp](https://binarywang.github.io/weixin-java-miniapp-javadoc/)、[weixin-java-pay](https://binarywang.github.io/weixin-java-pay-javadoc/)、[weixin-java-mp](https://binarywang.github.io/weixin-java-mp-javadoc/)、[weixin-java-common](https://binarywang.github.io/weixin-java-common-javadoc/)、[weixin-java-cp](https://binarywang.github.io/weixin-java-cp-javadoc/) 1. 本SDK要求的最低JDK版本是7,还在使用JDK6的用户请参考[【此项目】]( https://github.com/binarywang/weixin-java-tools-for-jdk6) ,而其他更早的JDK版本则需要自己改造实现。 1. 如有新功能需求,发现BUG,或者由于微信官方接口调整导致的代码问题,可以直接在[【Issues】](https://github.com/Wechat-Group/weixin-java-tools/issues)页提出issue,便于讨论追踪问题; 1. 如果想贡献代码,请阅读[【代码贡献指南】](contribution.md); @@ -41,7 +41,7 @@ ## 版本说明 1. 本项目定为大约每两个月发布一次正式版,版本号格式为X.X.0(如2.1.0,2.2.0等),遇到重大问题需修复会及时提交新版本,欢迎大家随时提交Pull Request; 1. BUG修复和新特性一般会先发布成小版本作为临时测试版本(如2.4.5.BETA,2.4.6.BETA等,即尾号不为0,并添加BETA字样,以区别于正式版); -1. 目前最新版本号为 [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent) ,也可以通过访问链接 [【微信支付】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-pay%22) 、[【公众号】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-mp%22) 、[【企业号】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-cp%22) +1. 目前最新版本号为 [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.binarywang/weixin-java-parent) ,也可以通过访问链接 [【微信支付】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-pay%22) 、[【微信小程序】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-miniapp%22) 、[【公众号】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-mp%22) 、[【企业号】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-cp%22) 分别查看所有最新的版本。 --------------------------------- From 754384f5f67c5defb4c9829fd5207bcd51c4f244 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 26 Jun 2017 12:11:51 +0800 Subject: [PATCH 109/179] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 5d0c6e764d..7d4413d621 100644 --- a/readme.md +++ b/readme.md @@ -21,7 +21,7 @@ 1. 最新更新:**2017-6-25 发布[【2.7.0正式版】](https://github.com/Wechat-Group/weixin-java-tools/releases)**! 1. 开源中国网站的本项目介绍的首页链接地址:https://www.oschina.net/p/weixin-java-tools-new 1. 自2.6.0版本开始,微信支付相关功能抽出独立为一个模块,详细使用方式请参考相关demo; -1. 自2.7.0版本开始支持微信支付,具体可以参考相关demo; +1. 自2.7.0版本开始,支持微信小程序,具体可以参考相关demo; 1. SDK详细开发文档请查阅 [【Wiki】](https://github.com/wechat-group/weixin-java-tools/wiki),部分文档可能未能及时更新,如有发现,可以及时上报或者自行修改。 1. 各个模块的Javadoc可以在线查看(有可能是最新的测试版本的,请注意观察版本号):[weixin-java-miniapp](https://binarywang.github.io/weixin-java-miniapp-javadoc/)、[weixin-java-pay](https://binarywang.github.io/weixin-java-pay-javadoc/)、[weixin-java-mp](https://binarywang.github.io/weixin-java-mp-javadoc/)、[weixin-java-common](https://binarywang.github.io/weixin-java-common-javadoc/)、[weixin-java-cp](https://binarywang.github.io/weixin-java-cp-javadoc/) 1. 本SDK要求的最低JDK版本是7,还在使用JDK6的用户请参考[【此项目】]( https://github.com/binarywang/weixin-java-tools-for-jdk6) ,而其他更早的JDK版本则需要自己改造实现。 From 73114635647cbdc462604665a43a2ebc1a0d8dcd Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 27 Jun 2017 11:04:21 +0800 Subject: [PATCH 110/179] =?UTF-8?q?jodd-http=E5=AF=B9=E4=BA=8E=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E6=94=AF=E4=BB=98=E6=9D=A5=E8=AF=B4=E6=98=AF=E5=BF=85?= =?UTF-8?q?=E9=A1=BB=E4=BE=9D=E8=B5=96=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weixin-java-pay/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 4f24b0a9c3..859d982248 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -26,6 +26,7 @@ org.jodd jodd-http + compile From 9771977d7a742e346f5f715ef75100bea4e4fbdd Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 27 Jun 2017 18:10:36 +0800 Subject: [PATCH 111/179] =?UTF-8?q?WxPayUnifiedOrderRequest=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=BB=98=E8=AE=A4=E6=9E=84=E9=80=A0=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wxpay/bean/request/WxPayUnifiedOrderRequest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java index a5560c20df..fb4b5e09c4 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java @@ -4,11 +4,8 @@ import com.github.binarywang.wxpay.exception.WxPayException; import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.annotation.Required; -import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; -import java.util.Arrays; - /** *
  * 统一下单请求参数对象
@@ -274,6 +271,9 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest {
   @XStreamAlias("openid")
   private String openid;
 
+  public WxPayUnifiedOrderRequest() {
+  }
+
   private WxPayUnifiedOrderRequest(Builder builder) {
     setAppid(builder.appid);
     setDeviceInfo(builder.deviceInfo);

From 0de1c7245b314d4ea524ffd67e9955a98031e2ce Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Tue, 27 Jun 2017 18:22:35 +0800
Subject: [PATCH 112/179] =?UTF-8?q?#257=20=E5=BE=AE=E4=BF=A1=E6=94=AF?=
 =?UTF-8?q?=E4=BB=98=E7=94=B3=E8=AF=B7=E9=80=80=E6=AC=BE=E6=8E=A5=E5=8F=A3?=
 =?UTF-8?q?=E5=A2=9E=E5=8A=A0refund=5Fdesc=E5=B1=9E=E6=80=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../bean/request/WxPayRefundRequest.java      | 63 +++++++++++++------
 1 file changed, 45 insertions(+), 18 deletions(-)

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java
index 59111da5f8..7fae6fa0f5 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java
@@ -142,17 +142,26 @@ public class WxPayRefundRequest extends WxPayBaseRequest {
    */
   @XStreamAlias("refund_account")
   private String refundAccount;
-
-  public WxPayRefundRequest() {
-  }
+  /**
+   * 
+   * 退款原因
+   * refund_account
+   * 否
+   * String(80)
+   * 商品已售完
+   * 若商户传入,会在下发给用户的退款消息中体现退款原因
+   * 
+ */ + @XStreamAlias("refund_desc") + private String refundDesc; private WxPayRefundRequest(Builder builder) { setDeviceInfo(builder.deviceInfo); setAppid(builder.appid); setTransactionId(builder.transactionId); setMchId(builder.mchId); - setOutTradeNo(builder.outTradeNo); setSubAppId(builder.subAppId); + setOutTradeNo(builder.outTradeNo); setSubMchId(builder.subMchId); setOutRefundNo(builder.outRefundNo); setNonceStr(builder.nonceStr); @@ -162,21 +171,13 @@ private WxPayRefundRequest(Builder builder) { setRefundFeeType(builder.refundFeeType); setOpUserId(builder.opUserId); setRefundAccount(builder.refundAccount); + setRefundDesc(builder.refundDesc); } public static Builder newBuilder() { return new Builder(); } - @Override - public void checkAndSign(WxPayConfig config) throws WxPayException { - if (StringUtils.isBlank(this.getOpUserId())) { - this.setOpUserId(config.getMchId()); - } - - super.checkAndSign(config); - } - public String getDeviceInfo() { return this.deviceInfo; } @@ -249,6 +250,26 @@ public void setRefundAccount(String refundAccount) { this.refundAccount = refundAccount; } + public String getRefundDesc() { + return this.refundDesc; + } + + public void setRefundDesc(String refundDesc) { + this.refundDesc = refundDesc; + } + + public WxPayRefundRequest() { + } + + @Override + public void checkAndSign(WxPayConfig config) throws WxPayException { + if (StringUtils.isBlank(this.getOpUserId())) { + this.setOpUserId(config.getMchId()); + } + + super.checkAndSign(config); + } + @Override protected void checkConstraints() { if (StringUtils.isNotBlank(this.getRefundAccount())) { @@ -268,8 +289,8 @@ public static final class Builder { private String appid; private String transactionId; private String mchId; - private String outTradeNo; private String subAppId; + private String outTradeNo; private String subMchId; private String outRefundNo; private String nonceStr; @@ -279,6 +300,7 @@ public static final class Builder { private String refundFeeType; private String opUserId; private String refundAccount; + private String refundDesc; private Builder() { } @@ -303,13 +325,13 @@ public Builder mchId(String mchId) { return this; } - public Builder outTradeNo(String outTradeNo) { - this.outTradeNo = outTradeNo; + public Builder subAppId(String subAppId) { + this.subAppId = subAppId; return this; } - public Builder subAppId(String subAppId) { - this.subAppId = subAppId; + public Builder outTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; return this; } @@ -358,6 +380,11 @@ public Builder refundAccount(String refundAccount) { return this; } + public Builder refundDesc(String refundDesc) { + this.refundDesc = refundDesc; + return this; + } + public WxPayRefundRequest build() { return new WxPayRefundRequest(this); } From 12eaa5b71ada375c3ec9a0e8995b1aa63d288739 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 27 Jun 2017 18:27:37 +0800 Subject: [PATCH 113/179] =?UTF-8?q?#255=20=E6=9C=8D=E5=8A=A1=E5=95=86?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E4=B8=8B=E7=BB=9F=E4=B8=80=E4=B8=8B=E5=8D=95?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=A2=9E=E5=8A=A0sub=5Fopenid=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/WxPayUnifiedOrderRequest.java | 52 +++++++++++++++---- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java index fb4b5e09c4..f5b58245d9 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java @@ -271,14 +271,29 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { @XStreamAlias("openid") private String openid; + /** + *
+   * 用户子标识
+   * sub_openid
+   * 否
+   * String(128)
+   * oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
+   * trade_type=JSAPI,此参数必传,用户在子商户appid下的唯一标识。
+   * openid和sub_openid可以选传其中之一,如果选择传sub_openid,则必须传sub_appid。
+   * 下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。
+   * 
+ */ + @XStreamAlias("sub_openid") + private String subOpenid; + public WxPayUnifiedOrderRequest() { } private WxPayUnifiedOrderRequest(Builder builder) { - setAppid(builder.appid); setDeviceInfo(builder.deviceInfo); - setMchId(builder.mchId); + setAppid(builder.appid); setBody(builder.body); + setMchId(builder.mchId); setSubAppId(builder.subAppId); setSubMchId(builder.subMchId); setNonceStr(builder.nonceStr); @@ -297,6 +312,7 @@ private WxPayUnifiedOrderRequest(Builder builder) { setProductId(builder.productId); setLimitPay(builder.limitPay); setOpenid(builder.openid); + setSubOpenid(builder.subOpenid); } public static Builder newBuilder() { @@ -441,6 +457,14 @@ public void setOpenid(String openid) { this.openid = openid; } + public String getSubOpenid() { + return this.subOpenid; + } + + public void setSubOpenid(String subOpenid) { + this.subOpenid = subOpenid; + } + @Override protected void checkConstraints() { // if (!ArrayUtils.contains(TRADE_TYPES, this.getTradeType())) { @@ -471,10 +495,10 @@ public void checkAndSign(WxPayConfig config) throws WxPayException { } public static final class Builder { - private String appid; private String deviceInfo; - private String mchId; + private String appid; private String body; + private String mchId; private String subAppId; private String subMchId; private String nonceStr; @@ -493,22 +517,18 @@ public static final class Builder { private String productId; private String limitPay; private String openid; + private String subOpenid; private Builder() { } - public Builder appid(String appid) { - this.appid = appid; - return this; - } - public Builder deviceInfo(String deviceInfo) { this.deviceInfo = deviceInfo; return this; } - public Builder mchId(String mchId) { - this.mchId = mchId; + public Builder appid(String appid) { + this.appid = appid; return this; } @@ -517,6 +537,11 @@ public Builder body(String body) { return this; } + public Builder mchId(String mchId) { + this.mchId = mchId; + return this; + } + public Builder subAppId(String subAppId) { this.subAppId = subAppId; return this; @@ -607,6 +632,11 @@ public Builder openid(String openid) { return this; } + public Builder subOpenid(String subOpenid) { + this.subOpenid = subOpenid; + return this; + } + public WxPayUnifiedOrderRequest build() { return new WxPayUnifiedOrderRequest(this); } From 518d1d60f51ab018652adbbe13f8b17c11284047 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 27 Jun 2017 18:28:18 +0800 Subject: [PATCH 114/179] =?UTF-8?q?=E5=8F=91=E5=B8=83=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC2.7.1.BETA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index a167cd8f48..fc5d27b6e7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang weixin-java-parent - 2.7.0 + 2.7.1.BETA pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 66e32664ca..fa1a9feff8 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.0 + 2.7.1.BETA weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index bcc4e73bb3..fad1f7fd7b 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.0 + 2.7.1.BETA weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index 71601ef3a4..99681a1099 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.0 + 2.7.1.BETA weixin-java-miniapp WeiXin Java Tools - MiniApp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index bd8f147cb0..ddf830b934 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.0 + 2.7.1.BETA weixin-java-mp WeiXin Java Tools - MP diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 859d982248..d3c5990473 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 2.7.0 + 2.7.1.BETA 4.0.0 From ed7f97ebe44a55e5239be7e083fde5c5f9098d13 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 29 Jun 2017 20:07:35 +0800 Subject: [PATCH 115/179] =?UTF-8?q?#260=20=E4=BF=AE=E5=A4=8D=E5=B0=8F?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=8F=91=E9=80=81=E6=A8=A1=E7=89=88=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=8E=A5=E5=8F=A3=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E9=87=8D=E6=96=B0=E6=95=B4=E7=90=86javadoc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/binarywang/wx/miniapp/api/WxMaMsgService.java | 9 ++++----- .../wx/miniapp/api/impl/WxMaMsgServiceImpl.java | 8 +++----- .../binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java | 6 +++--- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java index 040e81e530..65522f4b75 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java @@ -18,7 +18,7 @@ public interface WxMaMsgService { /** *
    * 发送客服消息
-   * 详情请见: 发送客服消息
+   * 详情请见: 发送客服消息
    * 接口url格式:https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
    * 
*/ @@ -27,10 +27,9 @@ public interface WxMaMsgService { /** *
    * 发送模板消息
-   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN
+   * 详情请见: 发送模板消息
+   * 接口url格式:https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
    * 
- * - * @return 消息Id */ - String sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException; + void sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException; } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java index 238bbe0e7f..70a4e50445 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java @@ -27,14 +27,12 @@ public boolean sendKefuMsg(WxMaKefuMessage message) throws WxErrorException { } @Override - public String sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException { + public void sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException { String responseContent = this.wxMaService.post(TEMPLATE_MSG_SEND_URL, templateMessage.toJson()); JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); - if (jsonObject.get("errcode").getAsInt() == 0) { - return jsonObject.get("msgid").getAsString(); + if (jsonObject.get("errcode").getAsInt() != 0) { + throw new WxErrorException(WxError.fromJson(responseContent)); } - - throw new WxErrorException(WxError.fromJson(responseContent)); } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java index 167341265a..c8605d25de 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java @@ -193,7 +193,7 @@ public synchronized T executeInternal(RequestExecutor executor, Str try { T result = executor.execute(uriWithAccessToken, data); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, result); + this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, data, result); return result; } catch (WxErrorException e) { WxError error = e.getError(); @@ -212,12 +212,12 @@ public synchronized T executeInternal(RequestExecutor executor, Str } if (error.getErrorCode() != 0) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, error); + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, data, error); throw new WxErrorException(error); } return null; } catch (IOException e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uriWithAccessToken, data, e.getMessage()); + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, data, e.getMessage()); throw new RuntimeException(e); } } From d6bb355cd10fbcd029f6212042fc4c3bd678ed4c Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 29 Jun 2017 20:07:50 +0800 Subject: [PATCH 116/179] =?UTF-8?q?#260=20=E4=BF=AE=E5=A4=8D=E5=B0=8F?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=8F=91=E9=80=81=E6=A8=A1=E7=89=88=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=8E=A5=E5=8F=A3=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E9=87=8D=E6=96=B0=E6=95=B4=E7=90=86javadoc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wx/miniapp/bean/WxMaTemplateMessage.java | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java index 7a89dfa8a5..79f955c6d2 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java @@ -13,34 +13,67 @@ */ public class WxMaTemplateMessage implements Serializable { private static final long serialVersionUID = 5063374783759519418L; + /** - * touser 是 接收者(用户)的 openid + *
+   * 参数:touser
+   * 是否必填: 是
+   * 描述: 接收者(用户)的 openid
+   * 
*/ private String toUser; + /** - * template_id 是 所需下发的模板消息的id + *
+   * 参数:template_id
+   * 是否必填: 是
+   * 描述: 所需下发的模板消息的id
+   * 
*/ private String templateId; + /** *
-   * page	否	点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
+   * 参数:page
+   * 是否必填: 否
+   * 描述: 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
    * 
*/ private String page; + /** - * form_id 是 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id + *
+   * 参数:form_id
+   * 是否必填: 是
+   * 描述: 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id
+   * 
*/ private String formId; + /** - * data 是 模板内容,不填则下发空模板 + *
+   * 参数:data
+   * 是否必填: 是
+   * 描述: 模板内容,不填则下发空模板
+   * 
*/ private List data = new ArrayList<>(); + /** - * color 否 模板内容字体的颜色,不填默认黑色 + *
+   * 参数:color
+   * 是否必填: 否
+   * 描述: 模板内容字体的颜色,不填默认黑色
+   * 
*/ private String color; + /** - * emphasis_keyword 否 模板需要放大的关键词,不填则默认无放大 + *
+   * 参数:emphasis_keyword
+   * 是否必填: 否
+   * 描述: 模板需要放大的关键词,不填则默认无放大
+   * 
*/ private String emphasisKeyword; From 57f5cf3eecef4fd6b1e2524e3f434712d6544fa2 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 30 Jun 2017 10:47:42 +0800 Subject: [PATCH 117/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84javadoc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/github/binarywang/wxpay/service/WxPayService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index 495ecb5eb9..03640eb067 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -112,7 +112,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri /** * 读取支付结果通知 - * 详见http://com.github.binarywang.wechat.pay.bean.pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7 + * 详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7 */ WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException; From 9a928f2601acf978c8f41b37b6904d2459ab65c4 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 30 Jun 2017 16:54:13 +0800 Subject: [PATCH 118/179] fix test case --- .../wx/miniapp/api/impl/WxMaMsgServiceImplTest.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java index c5d8f1e86a..9604a25691 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java @@ -9,9 +9,7 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.exception.WxErrorException; -import org.testng.Assert; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; +import org.testng.annotations.*; import java.text.SimpleDateFormat; import java.util.Date; @@ -68,9 +66,7 @@ public void testSendTemplateMsg() throws WxErrorException { .emphasisKeyword("keyword1.DATA") .build(); - String msgId = this.wxService.getMsgService().sendTemplateMsg(templateMessage); - Assert.assertNotNull(msgId); - System.out.println(msgId); + this.wxService.getMsgService().sendTemplateMsg(templateMessage); } } From c494fbe71d85bfa012e7865af0fad3b6e9198e71 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 30 Jun 2017 16:55:55 +0800 Subject: [PATCH 119/179] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98?= =?UTF-8?q?=E8=AF=81=E4=B9=A6=E8=B7=AF=E5=BE=84=E5=88=A4=E6=96=AD=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binarywang/wxpay/config/WxPayConfig.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java index e6c587a13b..d05259ceeb 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java @@ -158,18 +158,27 @@ public SSLContext initSSLContext() throws WxPayException { InputStream inputStream; final String prefix = "classpath:"; + String fileHasProblemMsg = "证书文件【" + this.keyPath + "】有问题,请核实!"; + String fileNotFoundMsg = "证书文件【" + this.keyPath + "】不存在,请核实!"; if (this.keyPath.startsWith(prefix)) { - inputStream = WxPayConfig.class.getResourceAsStream(this.keyPath.replace(prefix, "")); + String path = StringUtils.removeFirst(this.keyPath, prefix); + if (!path.startsWith("/")) { + path = "/" + path; + } + inputStream = WxPayConfig.class.getResourceAsStream(path); + if (inputStream == null) { + throw new WxPayException(fileNotFoundMsg); + } } else { try { File file = new File(this.keyPath); if (!file.exists()) { - throw new WxPayException("证书文件【" + file.getPath() + "】不存在!"); + throw new WxPayException(fileNotFoundMsg); } inputStream = new FileInputStream(file); } catch (IOException e) { - throw new WxPayException("证书文件有问题,请核实!", e); + throw new WxPayException(fileHasProblemMsg, e); } } @@ -180,7 +189,7 @@ public SSLContext initSSLContext() throws WxPayException { this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build(); return this.sslContext; } catch (Exception e) { - throw new WxPayException("证书文件有问题,请核实!", e); + throw new WxPayException(fileHasProblemMsg, e); } finally { IOUtils.closeQuietly(inputStream); } From 61d933196ce3f7849eb5b6ad318032be150bfb4d Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 30 Jun 2017 17:14:55 +0800 Subject: [PATCH 120/179] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E8=AF=B7=E6=B1=82=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wxpay/bean/request/WxPayBaseRequest.java | 2 +- .../wxpay/service/impl/WxPayServiceImpl.java | 68 ++++++++++--------- .../service/impl/WxPayServiceImplTest.java | 10 +-- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java index b44822483b..0d4fc08b9d 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java @@ -119,7 +119,7 @@ protected void checkFields() throws WxPayException { try { BeanUtils.checkRequiredFields(this); } catch (WxErrorException e) { - throw new WxPayException(e.getError().getErrorMsg()); + throw new WxPayException(e.getError().getErrorMsg(), e); } //check other parameters diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java index 14c34d0360..bcf425d792 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java @@ -11,14 +11,13 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.net.SSLSocketHttpConnectionProvider; -import org.apache.commons.lang3.CharEncoding; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; import java.io.File; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -76,7 +75,7 @@ public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeN request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/refundquery"; - String responseContent = this.post(url, request.toXML(), true); + String responseContent = this.post(url, request.toXML()); WxPayRefundQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundQueryResult.class); result.composeRefundRecords(); result.checkResult(this); @@ -96,7 +95,7 @@ public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayE throw e; } catch (Exception e) { log.error(e.getMessage(), e); - throw new WxPayException("发生异常," + e.getMessage()); + throw new WxPayException("发生异常," + e.getMessage(), e); } } @@ -139,7 +138,7 @@ public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/orderquery"; - String responseContent = this.post(url, request.toXML(), true); + String responseContent = this.post(url, request.toXML()); if (StringUtils.isBlank(responseContent)) { throw new WxPayException("无响应结果"); } @@ -161,7 +160,7 @@ public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/closeorder"; - String responseContent = this.post(url, request.toXML(), true); + String responseContent = this.post(url, request.toXML()); WxPayOrderCloseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderCloseResult.class); result.checkResult(this); @@ -173,7 +172,7 @@ public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) th request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/unifiedorder"; - String responseContent = this.post(url, request.toXML(), true); + String responseContent = this.post(url, request.toXML()); WxPayUnifiedOrderResult result = WxPayBaseResult.fromXML(responseContent, WxPayUnifiedOrderResult.class); result.checkResult(this); return result; @@ -294,7 +293,7 @@ public void report(WxPayReportRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/payitil/report"; - String responseContent = this.post(url, request.toXML(), true); + String responseContent = this.post(url, request.toXML()); WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); result.checkResult(this); } @@ -310,7 +309,7 @@ public WxPayBillResult downloadBill(String billDate, String billType, String tar request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/downloadbill"; - String responseContent = this.post(url, request.toXML(), true); + String responseContent = this.post(url, request.toXML()); if (responseContent.startsWith("<")) { WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); result.checkResult(this); @@ -397,7 +396,7 @@ public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayEx request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/micropay"; - String responseContent = this.post(url, request.toXML(), true); + String responseContent = this.post(url, request.toXML()); WxPayMicropayResult result = WxPayBaseResult.fromXML(responseContent, WxPayMicropayResult.class); result.checkResult(this); return result; @@ -419,7 +418,7 @@ public String shorturl(WxPayShorturlRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/tools/shorturl"; - String responseContent = this.post(url, request.toXML(), true); + String responseContent = this.post(url, request.toXML()); WxPayShorturlResult result = WxPayBaseResult.fromXML(responseContent, WxPayShorturlResult.class); result.checkResult(this); return result.getShortUrl(); @@ -435,7 +434,7 @@ public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayE request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/tools/authcodetoopenid"; - String responseContent = this.post(url, request.toXML(), true); + String responseContent = this.post(url, request.toXML()); WxPayAuthcode2OpenidResult result = WxPayBaseResult.fromXML(responseContent, WxPayAuthcode2OpenidResult.class); result.checkResult(this); return result.getOpenid(); @@ -452,26 +451,21 @@ public String getSandboxSignKey() throws WxPayException { request.checkAndSign(this.getConfig()); String url = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey"; - String responseContent = this.post(url, request.toXML(), false); + String responseContent = this.post(url, request.toXML()); WxPaySandboxSignKeyResult result = WxPayBaseResult.fromXML(responseContent, WxPaySandboxSignKeyResult.class); result.checkResult(this); return result.getSandboxSignKey(); } /** - * @param url 请求地址 - * @param xmlParam 请求字符串 - * @param needTransferEncoding 是否需要对结果进行重编码 + * 执行post请求 + * + * @param url 请求地址 + * @param xmlParam 请求字符串 * @return 返回请求结果 */ - private String post(String url, String xmlParam, boolean needTransferEncoding) { - String requestString = xmlParam; - try { - requestString = new String(xmlParam.getBytes(CharEncoding.UTF_8), CharEncoding.ISO_8859_1); - } catch (UnsupportedEncodingException e) { - //实际上不会发生该异常 - e.printStackTrace(); - } + private String post(String url, String xmlParam) throws WxPayException { + String requestString = new String(xmlParam.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); HttpRequest request = HttpRequest.post(url).body(requestString); String responseString = this.getResponseString(request.send()); @@ -481,7 +475,10 @@ private String post(String url, String xmlParam, boolean needTransferEncoding) { } /** - * ecoolper(20170418),修改为jodd-http方式 + * 带证书发送post请求 + * + * @param url 请求地址 + * @param requestStr 请求信息 */ private String postWithKey(String url, String requestStr) throws WxPayException { try { @@ -501,22 +498,27 @@ private String postWithKey(String url, String requestStr) throws WxPayException return responseString; } catch (Exception e) { this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", url, requestStr, e.getMessage()); - throw new WxPayException(e.getMessage()); + throw new WxPayException(e.getMessage(), e); } } - private String getResponseString(HttpResponse response) { - this.log.debug("【微信服务器响应头信息】:\n{}", response.toString(false)); + private String getResponseString(HttpResponse response) throws WxPayException { + try { + this.log.debug("【微信服务器响应头信息】:\n{}", response.toString(false)); + } catch (NullPointerException e) { + throw new WxPayException("response.toString() 居然抛出空指针异常了", e); + } String responseString = response.bodyText(); + if (StringUtils.isBlank(responseString)) { + throw new WxPayException("响应信息为空"); + } + if (StringUtils.isBlank(response.charset())) { - try { - responseString = new String(response.bodyText().getBytes(CharEncoding.ISO_8859_1), CharEncoding.UTF_8); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } + responseString = new String(responseString.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); } + return responseString; } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java index 995aa8275b..1cba44c59b 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java @@ -83,7 +83,7 @@ public void testRefund() throws Exception { } /** - * Test method for {@link WxPayService#refundQuery(java.lang.String, java.lang.String, java.lang.String, java.lang.String)} . + * Test method for {@link WxPayService#refundQuery(String, String, String, String)} . */ @Test public void testRefundQuery() throws Exception { @@ -121,7 +121,7 @@ public void testSendRedpack() throws Exception { } /** - * Test method for {@link WxPayService#queryRedpack(java.lang.String)}. + * Test method for {@link WxPayService#queryRedpack(String)}. */ @Test public void testQueryRedpack() throws Exception { @@ -148,7 +148,7 @@ public void testUnifiedOrder() throws WxPayException { } /** - * Test method for {@link WxPayService#queryOrder(java.lang.String, java.lang.String)} . + * Test method for {@link WxPayService#queryOrder(String, String)} . */ @Test public void testQueryOrder() throws WxPayException { @@ -157,7 +157,7 @@ public void testQueryOrder() throws WxPayException { } /** - * Test method for {@link WxPayService#closeOrder(java.lang.String)} . + * Test method for {@link WxPayService#closeOrder(String)} . */ @Test public void testCloseOrder() throws WxPayException { @@ -174,7 +174,7 @@ public void testEntPay() throws WxPayException { } /** - * Test method for {@link WxPayService#queryEntPay(java.lang.String)}. + * Test method for {@link WxPayService#queryEntPay(String)}. */ @Test public void testQueryEntPay() throws WxPayException { From ca52260f320b63bac6b21e703f39920fe528be5a Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 2 Jul 2017 15:03:20 +0800 Subject: [PATCH 121/179] =?UTF-8?q?=E5=8F=91=E5=B8=83=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC2.7.2.BETA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 ++-- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index fc5d27b6e7..84de33cb46 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang weixin-java-parent - 2.7.1.BETA + 2.7.2.BETA pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM @@ -288,7 +288,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.5 + 1.7-SNAPSHOT sign-artifacts diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index fa1a9feff8..71e09c8f49 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.1.BETA + 2.7.2.BETA weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index fad1f7fd7b..86c5994f4a 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.1.BETA + 2.7.2.BETA weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index 99681a1099..b1bb6a27d9 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.1.BETA + 2.7.2.BETA weixin-java-miniapp WeiXin Java Tools - MiniApp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index ddf830b934..2f1a0d6ef9 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.1.BETA + 2.7.2.BETA weixin-java-mp WeiXin Java Tools - MP diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index d3c5990473..e930a48178 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 2.7.1.BETA + 2.7.2.BETA 4.0.0 From 131402f8f6edfd46ff54d3ca6a17e06b35a7b436 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 2 Jul 2017 15:30:08 +0800 Subject: [PATCH 122/179] =?UTF-8?q?#265=20=E5=87=A0=E4=B8=AANewsBuilder?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=9B=B4=E6=8E=A5=E8=AE=BE=E7=BD=AEArticle?= =?UTF-8?q?=E6=88=96Item=E5=AF=B9=E8=B1=A1=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/bean/messagebuilder/MpnewsBuilder.java | 10 ++++++++-- .../weixin/cp/bean/messagebuilder/NewsBuilder.java | 10 ++++++++-- .../weixin/cp/bean/outxmlbuilder/NewsBuilder.java | 11 ++++++++--- .../me/chanjar/weixin/cp/bean/WxCpMessageTest.java | 10 ++++------ .../chanjar/weixin/mp/builder/kefu/NewsBuilder.java | 11 ++++++++--- .../chanjar/weixin/mp/builder/outxml/NewsBuilder.java | 11 ++++++++--- .../mp/bean/message/WxMpXmlOutNewsMessageTest.java | 5 ++--- 7 files changed, 46 insertions(+), 22 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/MpnewsBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/MpnewsBuilder.java index 21ab2549a7..55ed20abab 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/MpnewsBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/MpnewsBuilder.java @@ -5,6 +5,7 @@ import me.chanjar.weixin.cp.bean.article.MpnewsArticle; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -30,8 +31,13 @@ public MpnewsBuilder mediaId(String mediaId) { return this; } - public MpnewsBuilder addArticle(MpnewsArticle article) { - this.articles.add(article); + public MpnewsBuilder addArticle(MpnewsArticle... articles) { + Collections.addAll(this.articles, articles); + return this; + } + + public MpnewsBuilder articles(List articles) { + this.articles = articles; return this; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/NewsBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/NewsBuilder.java index e0df095e3d..dd23941244 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/NewsBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/NewsBuilder.java @@ -5,6 +5,7 @@ import me.chanjar.weixin.cp.bean.article.NewArticle; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -24,8 +25,13 @@ public NewsBuilder() { this.msgType = WxConsts.CUSTOM_MSG_NEWS; } - public NewsBuilder addArticle(NewArticle article) { - this.articles.add(article); + public NewsBuilder addArticle(NewArticle... articles) { + Collections.addAll(this.articles, articles); + return this; + } + + public NewsBuilder articles(List articles) { + this.articles = articles; return this; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java index 3e910d8dba..5a67056ab6 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java @@ -4,6 +4,7 @@ import me.chanjar.weixin.cp.bean.WxCpXmlOutNewsMessage.Item; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -12,11 +13,15 @@ * @author Daniel Qian */ public final class NewsBuilder extends BaseBuilder { + private List articles = new ArrayList<>(); - protected final List articles = new ArrayList<>(); + public NewsBuilder addArticle(Item... items) { + Collections.addAll(this.articles, items); + return this; + } - public NewsBuilder addArticle(Item item) { - this.articles.add(item); + public NewsBuilder articles(List articles){ + this.articles = articles; return this; } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java index f41f3a55a7..f97c0c79b0 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java @@ -3,9 +3,9 @@ import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.cp.bean.article.MpnewsArticle; import me.chanjar.weixin.cp.bean.article.NewArticle; -import org.testng.annotations.Test; +import org.testng.annotations.*; -import static org.testng.Assert.assertEquals; +import static org.testng.Assert.*; @Test public class WxCpMessageTest { @@ -127,11 +127,9 @@ public void testMpnewsBuild_with_articles() { .thumbMediaId("thumb") .build(); - WxCpMessage reply = WxCpMessage.MPNEWS().toUser("OPENID").addArticle(article1).addArticle(article2).build(); + WxCpMessage reply = WxCpMessage.MPNEWS().toUser("OPENID").addArticle(article1, article2).build(); - assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"mpnews\"," + - "\"mpnews\":{\"articles\":[{\"title\":\"Happy Day\",\"thumb_media_id\":\"thumb\",\"author\":\"aaaaaa\",\"content_source_url\":\"nice url\",\"content\":\"hahaha\",\"digest\":\"digest\",\"show_cover_pic\":\"heihei\"}," + - "{\"title\":\"Happy Day\",\"thumb_media_id\":\"thumb\",\"author\":\"aaaaaa\",\"content_source_url\":\"nice url\",\"content\":\"hahaha\",\"digest\":\"digest\",\"show_cover_pic\":\"heihei\"}]}}"); + assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"mpnews\",\"safe\":\"0\",\"mpnews\":{\"articles\":[{\"title\":\"Happy Day\",\"thumb_media_id\":\"thumb\",\"author\":\"aaaaaa\",\"content_source_url\":\"nice url\",\"content\":\"hahaha\",\"digest\":\"digest\",\"show_cover_pic\":\"heihei\"},{\"title\":\"Happy Day\",\"thumb_media_id\":\"thumb\",\"author\":\"aaaaaa\",\"content_source_url\":\"nice url\",\"content\":\"hahaha\",\"digest\":\"digest\",\"show_cover_pic\":\"heihei\"}]}}"); } public void testMpnewsBuild_with_media_id() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/NewsBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/NewsBuilder.java index 1626f77e2c..11e866e84a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/NewsBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/NewsBuilder.java @@ -4,6 +4,7 @@ import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -16,15 +17,19 @@ * @author chanjarster */ public final class NewsBuilder extends BaseBuilder { - private List articles = new ArrayList<>(); public NewsBuilder() { this.msgType = WxConsts.CUSTOM_MSG_NEWS; } - public NewsBuilder addArticle(WxMpKefuMessage.WxArticle article) { - this.articles.add(article); + public NewsBuilder addArticle(WxMpKefuMessage.WxArticle... articles) { + Collections.addAll(this.articles, articles); + return this; + } + + public NewsBuilder articles(List articles) { + this.articles = articles; return this; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/NewsBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/NewsBuilder.java index 4f9e22e67f..01af0d627f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/NewsBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/NewsBuilder.java @@ -3,6 +3,7 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlOutNewsMessage; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -11,11 +12,15 @@ * @author chanjarster */ public final class NewsBuilder extends BaseBuilder { + private List articles = new ArrayList<>(); - protected final List articles = new ArrayList<>(); + public NewsBuilder addArticle(WxMpXmlOutNewsMessage.Item... items) { + Collections.addAll(this.articles, items); + return this; + } - public NewsBuilder addArticle(WxMpXmlOutNewsMessage.Item item) { - this.articles.add(item); + public NewsBuilder articles(List articles){ + this.articles = articles; return this; } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessageTest.java index c9a1f98264..f8f72c9e5e 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessageTest.java @@ -54,15 +54,13 @@ public void testBuild() { WxMpXmlOutNewsMessage m = WxMpXmlOutMessage.NEWS() .fromUser("fromUser") .toUser("toUser") - .addArticle(item) - .addArticle(item) + .addArticle(item,item) .build(); String expected = "" + "" + "" + "1122" + "" - + " 2" + " " + " " + " <![CDATA[title]]>" @@ -77,6 +75,7 @@ public void testBuild() { + " " + " " + " " + + " 2" + ""; System.out.println(m.toXml()); Assert.assertEquals( From 22344ebe2ce52c70e427ea1acd1da6bfef5f4e12 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 2 Jul 2017 17:01:51 +0800 Subject: [PATCH 123/179] =?UTF-8?q?#256=20=E4=BC=81=E4=B8=9A=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=8F=91=E9=80=81=E6=B6=88=E6=81=AF=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E5=8D=A1=E7=89=87=E6=B6=88=E6=81=AF=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/common/api/WxConsts.java | 1 + .../chanjar/weixin/cp/bean/WxCpMessage.java | 15 ++++ .../cp/bean/messagebuilder/BaseBuilder.java | 4 +- .../bean/messagebuilder/TextCardBuilder.java | 47 ++++++++++++ .../cp/util/json/WxCpMessageGsonAdapter.java | 8 ++ .../weixin/cp/api/WxCpMessageAPITest.java | 1 - .../weixin/cp/bean/WxCpMessageTest.java | 75 +++---------------- 7 files changed, 85 insertions(+), 66 deletions(-) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TextCardBuilder.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java index e04dc45682..e416323e02 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java @@ -35,6 +35,7 @@ public class WxConsts { public static final String CUSTOM_MSG_NEWS = "news";//图文消息(点击跳转到外链) public static final String CUSTOM_MSG_MPNEWS = "mpnews";//图文消息(点击跳转到图文消息页面) public static final String CUSTOM_MSG_FILE = "file";//发送文件(CP专用) + public static final String CUSTOM_MSG_TEXTCARD = "textcard";//文本卡片消息(CP专用) public static final String CUSTOM_MSG_WXCARD = "wxcard";//卡券消息 public static final String CUSTOM_MSG_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; public static final String CUSTOM_MSG_SAFE_NO = "0"; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java index 2d07fcf867..c59ca87e1f 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java @@ -30,6 +30,7 @@ public class WxCpMessage implements Serializable { private String musicUrl; private String hqMusicUrl; private String safe; + private String url; private List articles = new ArrayList<>(); private List mpnewsArticles = new ArrayList<>(); @@ -40,6 +41,13 @@ public static TextBuilder TEXT() { return new TextBuilder(); } + /** + * 获得文本卡片消息builder + */ + public static TextCardBuilder TEXTCARD() { + return new TextCardBuilder(); + } + /** * 获得图片消息builder */ @@ -220,4 +228,11 @@ public String toJson() { return WxCpGsonBuilder.INSTANCE.create().toJson(this); } + public String getUrl() { + return this.url; + } + + public void setUrl(String url) { + this.url = url; + } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java index ea3e710c64..784de9a769 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java @@ -2,6 +2,7 @@ import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.cp.bean.WxCpMessage; +import org.apache.commons.lang3.StringUtils; public class BaseBuilder { protected String msgType; @@ -43,8 +44,7 @@ public WxCpMessage build() { m.setToUser(this.toUser); m.setToParty(this.toParty); m.setToTag(this.toTag); - m.setSafe( - (this.safe == null || "".equals(this.safe)) ? WxConsts.CUSTOM_MSG_SAFE_NO : this.safe); + m.setSafe(StringUtils.defaultIfBlank(this.safe, WxConsts.CUSTOM_MSG_SAFE_NO)); return m; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TextCardBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TextCardBuilder.java new file mode 100644 index 0000000000..a30b9d4059 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TextCardBuilder.java @@ -0,0 +1,47 @@ +package me.chanjar.weixin.cp.bean.messagebuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.cp.bean.WxCpMessage; + +/** + *
+ * 文本卡片消息Builder
+ * 用法: WxCustomMessage m = WxCustomMessage.TEXTCARD().title(...)....toUser(...).build();
+ * Created by Binary Wang on 2017-7-2.
+ * 
+ * + * @author Binary Wang + */ +public class TextCardBuilder extends BaseBuilder { + private String title; + private String description; + private String url; + + public TextCardBuilder() { + this.msgType = WxConsts.CUSTOM_MSG_TEXTCARD; + } + + public TextCardBuilder title(String title) { + this.title = title; + return this; + } + + public TextCardBuilder description(String description) { + this.description = description; + return this; + } + + public TextCardBuilder url(String url) { + this.url = url; + return this; + } + + @Override + public WxCpMessage build() { + WxCpMessage m = super.build(); + m.setTitle(this.title); + m.setDescription(this.description); + m.setUrl(this.url); + return m; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java index a74c17b64c..67e43c4ccc 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java @@ -43,6 +43,14 @@ public JsonElement serialize(WxCpMessage message, Type typeOfSrc, JsonSerializat messageJson.add("text", text); } + if (WxConsts.CUSTOM_MSG_TEXTCARD.equals(message.getMsgType())) { + JsonObject text = new JsonObject(); + text.addProperty("title", message.getTitle()); + text.addProperty("description", message.getDescription()); + text.addProperty("url", message.getUrl()); + messageJson.add("textcard", text); + } + if (WxConsts.CUSTOM_MSG_IMAGE.equals(message.getMsgType())) { JsonObject image = new JsonObject(); image.addProperty("media_id", message.getMediaId()); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java index ece6d5348b..1e0d40b05b 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java @@ -57,6 +57,5 @@ public void testSendMessage1() throws WxErrorException { System.out.println(messageSendResult.getInvalidPartyList()); System.out.println(messageSendResult.getInvalidUserList()); System.out.println(messageSendResult.getInvalidTagList()); - } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java index f97c0c79b0..e02cc6672d 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java @@ -1,6 +1,5 @@ package me.chanjar.weixin.cp.bean; -import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.cp.bean.article.MpnewsArticle; import me.chanjar.weixin.cp.bean.article.NewArticle; import org.testng.annotations.*; @@ -10,82 +9,32 @@ @Test public class WxCpMessageTest { - public void testTextReply() { - WxCpMessage reply = new WxCpMessage(); - reply.setToUser("OPENID"); - reply.setMsgType(WxConsts.CUSTOM_MSG_TEXT); - reply.setContent("sfsfdsdf"); - assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); - } - public void testTextBuild() { WxCpMessage reply = WxCpMessage.TEXT().toUser("OPENID").content("sfsfdsdf").build(); - assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); + assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"},\"safe\":\"0\"}"); } - public void testImageReply() { - WxCpMessage reply = new WxCpMessage(); - reply.setToUser("OPENID"); - reply.setMsgType(WxConsts.CUSTOM_MSG_IMAGE); - reply.setMediaId("MEDIA_ID"); - assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); + public void testTextCardBuild() { + WxCpMessage reply = WxCpMessage.TEXTCARD().toUser("OPENID") + .title("领奖通知") + .description( "
2016年9月26日
恭喜你抽中iPhone 7一台,领奖码:xxxx
请于2016年10月10日前联系行政同事领取
") + .url("http://www.qq.com").build(); + assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"textcard\",\"textcard\":{\"title\":\"领奖通知\",\"description\":\"
2016年9月26日
恭喜你抽中iPhone 7一台,领奖码:xxxx
请于2016年10月10日前联系行政同事领取
\",\"url\":\"http://www.qq.com\"},\"safe\":\"0\"}"); } public void testImageBuild() { WxCpMessage reply = WxCpMessage.IMAGE().toUser("OPENID").mediaId("MEDIA_ID").build(); - assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); - } - - public void testVoiceReply() { - WxCpMessage reply = new WxCpMessage(); - reply.setToUser("OPENID"); - reply.setMsgType(WxConsts.CUSTOM_MSG_VOICE); - reply.setMediaId("MEDIA_ID"); - assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"MEDIA_ID\"}}"); + assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"},\"safe\":\"0\"}"); } public void testVoiceBuild() { WxCpMessage reply = WxCpMessage.VOICE().toUser("OPENID").mediaId("MEDIA_ID").build(); - assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"MEDIA_ID\"}}"); - } - - public void testVideoReply() { - WxCpMessage reply = new WxCpMessage(); - reply.setToUser("OPENID"); - reply.setMsgType(WxConsts.CUSTOM_MSG_VIDEO); - reply.setMediaId("MEDIA_ID"); - reply.setThumbMediaId("MEDIA_ID"); - reply.setTitle("TITLE"); - reply.setDescription("DESCRIPTION"); - assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"video\",\"video\":{\"media_id\":\"MEDIA_ID\",\"thumb_media_id\":\"MEDIA_ID\",\"title\":\"TITLE\",\"description\":\"DESCRIPTION\"}}"); + assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"MEDIA_ID\"},\"safe\":\"0\"}"); } public void testVideoBuild() { WxCpMessage reply = WxCpMessage.VIDEO().toUser("OPENID").title("TITLE").mediaId("MEDIA_ID").thumbMediaId("MEDIA_ID").description("DESCRIPTION").build(); - assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"video\",\"video\":{\"media_id\":\"MEDIA_ID\",\"thumb_media_id\":\"MEDIA_ID\",\"title\":\"TITLE\",\"description\":\"DESCRIPTION\"}}"); - } - - public void testNewsReply() { - WxCpMessage reply = new WxCpMessage(); - reply.setToUser("OPENID"); - reply.setMsgType(WxConsts.CUSTOM_MSG_NEWS); - - NewArticle article1 = new NewArticle(); - article1.setUrl("URL"); - article1.setPicUrl("PIC_URL"); - article1.setDescription("Is Really A Happy Day"); - article1.setTitle("Happy Day"); - reply.getArticles().add(article1); - - NewArticle article2 = new NewArticle(); - article2.setUrl("URL"); - article2.setPicUrl("PIC_URL"); - article2.setDescription("Is Really A Happy Day"); - article2.setTitle("Happy Day"); - reply.getArticles().add(article2); - - - assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"news\":{\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}}"); + assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"video\",\"safe\":\"0\",\"video\":{\"media_id\":\"MEDIA_ID\",\"thumb_media_id\":\"MEDIA_ID\",\"title\":\"TITLE\",\"description\":\"DESCRIPTION\"}}"); } public void testNewsBuild() { @@ -103,7 +52,7 @@ public void testNewsBuild() { WxCpMessage reply = WxCpMessage.NEWS().toUser("OPENID").addArticle(article1).addArticle(article2).build(); - assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"news\":{\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}}"); + assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"safe\":\"0\",\"news\":{\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}}"); } public void testMpnewsBuild_with_articles() { @@ -136,7 +85,7 @@ public void testMpnewsBuild_with_media_id() { WxCpMessage reply = WxCpMessage.MPNEWS().toUser("OPENID").mediaId("mmm").build(); assertEquals(reply.toJson(), - "{\"touser\":\"OPENID\",\"msgtype\":\"mpnews\",\"mpnews\":{\"media_id\":\"mmm\"}}"); + "{\"touser\":\"OPENID\",\"msgtype\":\"mpnews\",\"safe\":\"0\",\"mpnews\":{\"media_id\":\"mmm\"}}"); } } From 554fd08fb8868b679d8fed692de772b2ecdfeb00 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 2 Jul 2017 17:17:35 +0800 Subject: [PATCH 124/179] =?UTF-8?q?#195=20=E6=8A=BD=E5=8F=96=E7=B4=A0?= =?UTF-8?q?=E6=9D=90=E7=AE=A1=E7=90=86=E8=AF=B7=E6=B1=82URL=E5=88=B0?= =?UTF-8?q?=E5=B8=B8=E9=87=8F=E7=B1=BB=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/WxMpMaterialService.java | 14 +++++- .../mp/api/impl/WxMpMaterialServiceImpl.java | 45 +++++++------------ 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java index 8e769d3e2d..05ca87eab7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java @@ -16,6 +16,16 @@ *
*/ public interface WxMpMaterialService { + String MEDIA_GET_URL = "https://api.weixin.qq.com/cgi-bin/media/get"; + String MEDIA_UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?type=%s"; + String IMG_UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadimg"; + String MATERIAL_ADD_URL = "https://api.weixin.qq.com/cgi-bin/material/add_material?type=%s"; + String NEWS_ADD_URL = "https://api.weixin.qq.com/cgi-bin/material/add_news"; + String MATERIAL_GET_URL = "https://api.weixin.qq.com/cgi-bin/material/get_material"; + String NEWS_UPDATE_URL = "https://api.weixin.qq.com/cgi-bin/material/update_news"; + String MATERIAL_DEL_URL = "https://api.weixin.qq.com/cgi-bin/material/del_material"; + String MATERIAL_GET_COUNT_URL = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount"; + String MATERIAL_BATCHGET_URL = "https://api.weixin.qq.com/cgi-bin/material/batchget_material"; /** *
@@ -73,11 +83,11 @@ public interface WxMpMaterialService {
    * 接口url格式:https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
    * 
* - * @param media_id + * @param mediaId 媒体文件Id * @return 保存到本地的临时文件 * @throws WxErrorException */ - File mediaDownload(String media_id) throws WxErrorException; + File mediaDownload(String mediaId) throws WxErrorException; /** *
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
index bb5857be83..99a63f914b 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
@@ -25,8 +25,7 @@
  * Created by Binary Wang on 2016/7/21.
  */
 public class WxMpMaterialServiceImpl implements WxMpMaterialService {
-  private static final String MEDIA_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/media";
-  private static final String MATERIAL_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/material";
+
   private WxMpService wxMpService;
 
   public WxMpMaterialServiceImpl(WxMpService wxMpService) {
@@ -45,28 +44,26 @@ public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputS
 
   @Override
   public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException {
-    String url = MEDIA_API_URL_PREFIX + "/upload?type=" + mediaType;
+    String url = String.format(MEDIA_UPLOAD_URL, mediaType);
     return this.wxMpService.execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, file);
   }
 
   @Override
-  public File mediaDownload(String media_id) throws WxErrorException {
-    String url = MEDIA_API_URL_PREFIX + "/get";
+  public File mediaDownload(String mediaId) throws WxErrorException {
     return this.wxMpService.execute(
       MediaDownloadRequestExecutor.create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()),
-      url,
-      "media_id=" + media_id);
+      MEDIA_GET_URL,
+      "media_id=" + mediaId);
   }
 
   @Override
   public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException {
-    String url = MEDIA_API_URL_PREFIX + "/uploadimg";
-    return this.wxMpService.execute(MediaImgUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, file);
+    return this.wxMpService.execute(MediaImgUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), IMG_UPLOAD_URL, file);
   }
 
   @Override
   public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException {
-    String url = MATERIAL_API_URL_PREFIX + "/add_material?type=" + mediaType;
+    String url = String.format(MATERIAL_ADD_URL, mediaType);
     return this.wxMpService.execute(MaterialUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, material);
   }
 
@@ -75,33 +72,29 @@ public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws
     if (news == null || news.isEmpty()) {
       throw new IllegalArgumentException("news is empty!");
     }
-    String url = MATERIAL_API_URL_PREFIX + "/add_news";
-    String responseContent = this.wxMpService.post(url, news.toJson());
+    String responseContent = this.wxMpService.post(NEWS_ADD_URL, news.toJson());
     return WxMpMaterialUploadResult.fromJson(responseContent);
   }
 
   @Override
   public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException {
-    String url = MATERIAL_API_URL_PREFIX + "/get_material";
-    return this.wxMpService.execute(MaterialVoiceAndImageDownloadRequestExecutor.create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, media_id);
+    return this.wxMpService.execute(MaterialVoiceAndImageDownloadRequestExecutor
+      .create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), MATERIAL_GET_URL, media_id);
   }
 
   @Override
   public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException {
-    String url = MATERIAL_API_URL_PREFIX + "/get_material";
-    return this.wxMpService.execute(MaterialVideoInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), url, media_id);
+    return this.wxMpService.execute(MaterialVideoInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_GET_URL, media_id);
   }
 
   @Override
   public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException {
-    String url = MATERIAL_API_URL_PREFIX + "/get_material";
-    return this.wxMpService.execute(MaterialNewsInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), url, media_id);
+    return this.wxMpService.execute(MaterialNewsInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_GET_URL, media_id);
   }
 
   @Override
   public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException {
-    String url = MATERIAL_API_URL_PREFIX + "/update_news";
-    String responseText = this.wxMpService.post(url, wxMpMaterialArticleUpdate.toJson());
+    String responseText = this.wxMpService.post(NEWS_UPDATE_URL, wxMpMaterialArticleUpdate.toJson());
     WxError wxError = WxError.fromJson(responseText);
     if (wxError.getErrorCode() == 0) {
       return true;
@@ -112,14 +105,12 @@ public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleU
 
   @Override
   public boolean materialDelete(String media_id) throws WxErrorException {
-    String url = MATERIAL_API_URL_PREFIX + "/del_material";
-    return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()), url, media_id);
+    return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_DEL_URL, media_id);
   }
 
   @Override
   public WxMpMaterialCountResult materialCount() throws WxErrorException {
-    String url = MATERIAL_API_URL_PREFIX + "/get_materialcount";
-    String responseText = this.wxMpService.get(url, null);
+    String responseText = this.wxMpService.get(MATERIAL_GET_COUNT_URL, null);
     WxError wxError = WxError.fromJson(responseText);
     if (wxError.getErrorCode() == 0) {
       return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialCountResult.class);
@@ -130,12 +121,11 @@ public WxMpMaterialCountResult materialCount() throws WxErrorException {
 
   @Override
   public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException {
-    String url = MATERIAL_API_URL_PREFIX + "/batchget_material";
     Map params = new HashMap<>();
     params.put("type", WxConsts.MATERIAL_NEWS);
     params.put("offset", offset);
     params.put("count", count);
-    String responseText = this.wxMpService.post(url, WxGsonBuilder.create().toJson(params));
+    String responseText = this.wxMpService.post(MATERIAL_BATCHGET_URL, WxGsonBuilder.create().toJson(params));
     WxError wxError = WxError.fromJson(responseText);
     if (wxError.getErrorCode() == 0) {
       return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialNewsBatchGetResult.class);
@@ -146,12 +136,11 @@ public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count
 
   @Override
   public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException {
-    String url = MATERIAL_API_URL_PREFIX + "/batchget_material";
     Map params = new HashMap<>();
     params.put("type", type);
     params.put("offset", offset);
     params.put("count", count);
-    String responseText = this.wxMpService.post(url, WxGsonBuilder.create().toJson(params));
+    String responseText = this.wxMpService.post(MATERIAL_BATCHGET_URL, WxGsonBuilder.create().toJson(params));
     WxError wxError = WxError.fromJson(responseText);
     if (wxError.getErrorCode() == 0) {
       return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialFileBatchGetResult.class);

From eaad6367de1ee3aba5f1ca7de67da88dd718eb03 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 2 Jul 2017 18:23:21 +0800
Subject: [PATCH 125/179] =?UTF-8?q?#252=20=E5=8E=9F=E6=9C=89=E5=9B=BE?=
 =?UTF-8?q?=E6=96=87=E7=B4=A0=E6=9D=90=E7=AE=A1=E7=90=86=E6=8E=A5=E5=8F=A3?=
 =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=95=99=E8=A8=80=E7=AE=A1=E7=90=86=E6=89=80?=
 =?UTF-8?q?=E9=9C=80=E4=B8=A4=E4=B8=AA=E5=8F=82=E6=95=B0=EF=BC=9Aneed=5Fop?=
 =?UTF-8?q?en=5Fcomment=20=E5=92=8C=20only=5Ffans=5Fcan=5Fcomment?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mp/api/impl/WxMpMaterialServiceImpl.java  | 16 +++---
 .../mp/bean/material/WxMpMaterialNews.java    | 52 ++++++++++++++++++-
 .../material/WxMpMaterialUploadResult.java    | 25 +++++++--
 ...lVoiceAndImageDownloadRequestExecutor.java |  2 -
 ...ApacheMaterialNewsInfoRequestExecutor.java |  5 ++
 ...lVoiceAndImageDownloadRequestExecutor.java |  5 +-
 .../JoddMaterialNewsInfoRequestExecutor.java  |  4 ++
 ...lVoiceAndImageDownloadRequestExecutor.java |  3 +-
 ...OkhttpMaterialNewsInfoRequestExecutor.java |  4 ++
 ...lVoiceAndImageDownloadRequestExecutor.java |  3 +-
 .../WxMpMaterialNewsArticleGsonAdapter.java   | 21 ++++++++
 .../json/WxMpMaterialNewsGsonAdapter.java     | 13 +++++
 .../api/impl/WxMpMaterialServiceImplTest.java |  5 +-
 13 files changed, 137 insertions(+), 21 deletions(-)

diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
index 99a63f914b..90594fe031 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
@@ -77,19 +77,19 @@ public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws
   }
 
   @Override
-  public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException {
+  public InputStream materialImageOrVoiceDownload(String mediaId) throws WxErrorException {
     return this.wxMpService.execute(MaterialVoiceAndImageDownloadRequestExecutor
-      .create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), MATERIAL_GET_URL, media_id);
+      .create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), MATERIAL_GET_URL, mediaId);
   }
 
   @Override
-  public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException {
-    return this.wxMpService.execute(MaterialVideoInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_GET_URL, media_id);
+  public WxMpMaterialVideoInfoResult materialVideoInfo(String mediaId) throws WxErrorException {
+    return this.wxMpService.execute(MaterialVideoInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_GET_URL, mediaId);
   }
 
   @Override
-  public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException {
-    return this.wxMpService.execute(MaterialNewsInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_GET_URL, media_id);
+  public WxMpMaterialNews materialNewsInfo(String mediaId) throws WxErrorException {
+    return this.wxMpService.execute(MaterialNewsInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_GET_URL, mediaId);
   }
 
   @Override
@@ -104,8 +104,8 @@ public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleU
   }
 
   @Override
-  public boolean materialDelete(String media_id) throws WxErrorException {
-    return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_DEL_URL, media_id);
+  public boolean materialDelete(String mediaId) throws WxErrorException {
+    return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_DEL_URL, mediaId);
   }
 
   @Override
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java
index a107facaed..51f2d0c6bd 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java
@@ -4,12 +4,16 @@
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 import java.io.Serializable;
+import java.util.Date;
 import java.util.ArrayList;
 import java.util.List;
 
 public class WxMpMaterialNews implements Serializable {
   private static final long serialVersionUID = -3283203652013494976L;
 
+  private Date createdTime;
+  private Date updatedTime;
+
   private List articles = new ArrayList<>();
 
   public List getArticles() {
@@ -28,9 +32,25 @@ public boolean isEmpty() {
     return this.articles == null || this.articles.isEmpty();
   }
 
+  public Date getCreatedTime() {
+    return this.createdTime;
+  }
+
+  public void setCreatedTime(Date createdTime) {
+    this.createdTime = createdTime;
+  }
+
+  public Date getUpdatedTime() {
+    return this.updatedTime;
+  }
+
+  public void setUpdatedTime(Date updatedTime) {
+    this.updatedTime = updatedTime;
+  }
+
   @Override
   public String toString() {
-    return ToStringUtils.toSimpleString(this);
+    return this.toJson();
   }
 
   /**
@@ -44,6 +64,8 @@ public String toString() {
    * 6. digest          图文消息的描述
    * 7. showCoverPic  是否显示封面,true为显示,false为不显示
    * 8. url           点击图文消息跳转链接
+   * 9. need_open_comment(新增字段)	否	Uint32	是否打开评论,0不打开,1打开
+   * 10. only_fans_can_comment(新增字段)	否	Uint32	是否粉丝才可评论,0所有人可评论,1粉丝才可评论
    * 
* * @author chanjarster @@ -87,6 +109,18 @@ public static class WxMpMaterialNewsArticle { */ private String url; + /** + * need_open_comment + * 是否打开评论,0不打开,1打开 + */ + private Boolean needOpenComment; + + /** + * only_fans_can_comment + * 是否粉丝才可评论,0所有人可评论,1粉丝才可评论 + */ + private Boolean onlyFansCanComment; + public String getThumbMediaId() { return this.thumbMediaId; } @@ -159,6 +193,22 @@ public void setThumbUrl(String thumbUrl) { this.thumbUrl = thumbUrl; } + public Boolean getNeedOpenComment() { + return this.needOpenComment; + } + + public void setNeedOpenComment(Boolean needOpenComment) { + this.needOpenComment = needOpenComment; + } + + public Boolean getOnlyFansCanComment() { + return this.onlyFansCanComment; + } + + public void setOnlyFansCanComment(Boolean onlyFansCanComment) { + this.onlyFansCanComment = onlyFansCanComment; + } + @Override public String toString() { return ToStringUtils.toSimpleString(this); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java index ec1d115496..0e5546b9aa 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java @@ -1,17 +1,16 @@ package me.chanjar.weixin.mp.bean.material; +import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import java.io.Serializable; public class WxMpMaterialUploadResult implements Serializable { - - /** - * - */ private static final long serialVersionUID = -128818731449449537L; private String mediaId; private String url; + private Integer errCode; + private String errMsg; public static WxMpMaterialUploadResult fromJson(String json) { return WxMpGsonBuilder.create().fromJson(json, WxMpMaterialUploadResult.class); @@ -33,9 +32,25 @@ public void setUrl(String url) { this.url = url; } + public Integer getErrCode() { + return this.errCode; + } + + public void setErrCode(Integer errCode) { + this.errCode = errCode; + } + + public String getErrMsg() { + return this.errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } + @Override public String toString() { - return "WxMpMaterialUploadResult [media_id=" + this.mediaId + ", url=" + this.url + "]"; + return ToStringUtils.toSimpleString(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java index 8bf55d03e0..09cb70d0f5 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java @@ -13,13 +13,11 @@ public abstract class MaterialVoiceAndImageDownloadRequestExecutor impleme protected RequestHttp requestHttp; protected File tmpDirFile; - public MaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { this.requestHttp = requestHttp; this.tmpDirFile = tmpDirFile; } - public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialNewsInfoRequestExecutor.java index 77d22659ec..5298160f35 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialNewsInfoRequestExecutor.java @@ -14,6 +14,8 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.HashMap; @@ -23,6 +25,8 @@ * Created by ecoolper on 2017/5/5. */ public class ApacheMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + public ApacheMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @@ -40,6 +44,7 @@ public WxMpMaterialNews execute(String uri, String materialId) throws WxErrorExc httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + this.logger.debug("响应原始数据:{}", responseContent); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVoiceAndImageDownloadRequestExecutor.java index 87d7b545c6..b1011a5282 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVoiceAndImageDownloadRequestExecutor.java @@ -18,6 +18,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -41,10 +42,10 @@ public InputStream execute(String uri, String materialId) throws WxErrorExceptio params.put("media_id", materialId); httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); - InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) { // 下载媒体文件出错 byte[] responseContent = IOUtils.toByteArray(inputStream); - String responseContentString = new String(responseContent, "UTF-8"); + String responseContentString = new String(responseContent, StandardCharsets.UTF_8); if (responseContentString.length() < 100) { try { WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java index a5d5ad1fd3..181a640787 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java @@ -12,6 +12,8 @@ import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; @@ -19,6 +21,7 @@ * Created by ecoolper on 2017/5/5. */ public class JoddMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); public JoddMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @@ -36,6 +39,7 @@ public WxMpMaterialNews execute(String uri, String materialId) throws WxErrorExc response.charset(StringPool.UTF_8); String responseContent = response.bodyText(); + this.logger.debug("响应原始数据:{}", responseContent); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java index a6317d5a00..ca43a1455d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java @@ -17,6 +17,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; /** * Created by ecoolper on 2017/5/5. @@ -40,7 +41,7 @@ public InputStream execute(String uri, String materialId) throws WxErrorExceptio try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { // 下载媒体文件出错 byte[] responseContent = IOUtils.toByteArray(inputStream); - String responseContentString = new String(responseContent, "UTF-8"); + String responseContentString = new String(responseContent, StandardCharsets.UTF_8); if (responseContentString.length() < 100) { try { WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java index d51fbbe481..a0a1c05231 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java @@ -8,6 +8,8 @@ import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; @@ -15,6 +17,7 @@ * Created by ecoolper on 2017/5/5. */ public class OkhttpMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); public OkhttpMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @@ -44,6 +47,7 @@ public Request authenticate(Route route, Response response) throws IOException { Response response = client.newCall(request).execute(); String responseContent = response.body().string(); + this.logger.debug("响应原始数据:{}", responseContent); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java index 336b3a989e..1d0a5f7f65 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java @@ -13,6 +13,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; /** * Created by ecoolper on 2017/5/5. @@ -50,7 +51,7 @@ public Request authenticate(Route route, Response response) throws IOException { // 下载媒体文件出错 byte[] responseContent = IOUtils.toByteArray(inputStream); - String responseContentString = new String(responseContent, "UTF-8"); + String responseContentString = new String(responseContent, StandardCharsets.UTF_8); if (responseContentString.length() < 100) { try { WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsArticleGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsArticleGsonAdapter.java index a74877f126..5a17a7bdb8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsArticleGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsArticleGsonAdapter.java @@ -11,6 +11,7 @@ import com.google.gson.*; import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import org.apache.commons.lang3.BooleanUtils; import java.lang.reflect.Type; @@ -37,6 +38,16 @@ public JsonElement serialize(WxMpMaterialNews.WxMpMaterialNewsArticle article, T if (null != article.getUrl()) { articleJson.addProperty("url", article.getUrl()); } + + if (null != article.getNeedOpenComment()) { + articleJson.addProperty("need_open_comment", + BooleanUtils.toInteger(article.getNeedOpenComment(), 1, 0)); + } + + if (null != article.getOnlyFansCanComment()) { + articleJson.addProperty("only_fans_can_comment", + BooleanUtils.toInteger(article.getOnlyFansCanComment(), 1, 0)); + } return articleJson; } @@ -81,6 +92,16 @@ public WxMpMaterialNews.WxMpMaterialNewsArticle deserialize(JsonElement jsonElem if (url != null && !url.isJsonNull()) { article.setUrl(GsonHelper.getAsString(url)); } + + JsonElement needOpenComment = articleInfo.get("need_open_comment"); + if (needOpenComment != null && !needOpenComment.isJsonNull()) { + article.setNeedOpenComment(GsonHelper.getAsBoolean(needOpenComment)); + } + + JsonElement onlyFansCanComment = articleInfo.get("only_fans_can_comment"); + if (onlyFansCanComment != null && !onlyFansCanComment.isJsonNull()) { + article.setOnlyFansCanComment(GsonHelper.getAsBoolean(onlyFansCanComment)); + } return article; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java index 8da6dacdc4..a77a209814 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java @@ -9,9 +9,11 @@ package me.chanjar.weixin.mp.util.json; import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; import java.lang.reflect.Type; +import java.util.Date; public class WxMpMaterialNewsGsonAdapter implements JsonSerializer, JsonDeserializer { @@ -41,6 +43,17 @@ public WxMpMaterialNews deserialize(JsonElement jsonElement, Type type, JsonDese wxMpMaterialNews.addArticle(article); } } + + if (json.get("create_time") != null && !json.get("create_time").isJsonNull()) { + Date createTime = new Date(GsonHelper.getAsLong(json.get("create_time"))); + wxMpMaterialNews.setCreatedTime(createTime); + } + + if (json.get("update_time") != null && !json.get("update_time").isJsonNull()) { + Date updateTime = new Date(GsonHelper.getAsLong(json.get("update_time"))); + wxMpMaterialNews.setUpdatedTime(updateTime); + } + return wxMpMaterialNews; } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java index b175114af1..309c4e0e47 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java @@ -175,7 +175,7 @@ public void testDownloadMaterial(String mediaId) throws WxErrorException, IOExce } } - @Test(dependsOnMethods = {"testAddNews"}) + @Test(dependsOnMethods = {"testAddNews","testUploadMaterial"}) public void testGetNewsInfo() throws WxErrorException { WxMpMaterialNews wxMpMaterialNewsSingle = this.wxService .getMaterialService().materialNewsInfo(this.singleNewsMediaId); @@ -183,6 +183,9 @@ public void testGetNewsInfo() throws WxErrorException { .getMaterialService().materialNewsInfo(this.multiNewsMediaId); assertNotNull(wxMpMaterialNewsSingle); assertNotNull(wxMpMaterialNewsMultiple); + + System.out.println(wxMpMaterialNewsSingle); + System.out.println(wxMpMaterialNewsMultiple); } @Test(dependsOnMethods = {"testGetNewsInfo"}) From b12a7a859085c9a9fb140e8d792204525adcf0bd Mon Sep 17 00:00:00 2001 From: Jink2005 Date: Mon, 3 Jul 2017 10:37:47 +0800 Subject: [PATCH 126/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E5=9B=9E=E8=B0=83sign=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E7=9A=84bug=20(#266)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bean/result/WxPayOrderNotifyResult.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResult.java index 723702a455..bfeb98f0b4 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResult.java @@ -89,6 +89,24 @@ public class WxPayOrderNotifyResult extends WxPayBaseResult implements Serializa @XStreamAlias("bank_type") private String bankType; + /** + *
+   *     用户是否关注子公众账号
+   *     String(1)
+   *     Y-关注,N-未关注,仅在公众账号类型支付有效
+   * 
+ */ + @XStreamAlias("sub_is_subscribe") + private String subIsSubscribe; + + /** + *
+   *     用户在子商户appid下的唯一标识
+   *     String(128)
+   * 
+ */ + @XStreamAlias("sub_openid") + private String subOpenId; /** *
@@ -293,6 +311,22 @@ public void setBankType(String bankType) {
     this.bankType = bankType;
   }
 
+  public String getSubIsSubscribe() {
+    return subIsSubscribe;
+  }
+
+  public void setSubIsSubscribe(String subIsSubscribe) {
+    this.subIsSubscribe = subIsSubscribe;
+  }
+
+  public String getSubOpenId() {
+    return subOpenId;
+  }
+
+  public void setSubOpenId(String subOpenId) {
+    this.subOpenId = subOpenId;
+  }
+
   public Integer getTotalFee() {
     return totalFee;
   }

From 04e115ce03d57ec6786b4512b622853809173c00 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Mon, 3 Jul 2017 15:48:17 +0800
Subject: [PATCH 127/179] =?UTF-8?q?=E4=BC=98=E5=8C=96javadoc?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../bean/result/WxPayOrderNotifyResult.java   | 260 +++++++++---------
 1 file changed, 134 insertions(+), 126 deletions(-)

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResult.java
index bfeb98f0b4..a411cd2c70 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResult.java
@@ -25,12 +25,12 @@ public class WxPayOrderNotifyResult extends WxPayBaseResult implements Serializa
 
   /**
    * 
-   * 设备号
-   * device_info
-   * 否
-   * String(32)
-   * 013467007045764
-   * 微信支付分配的终端设备号,
+   * 字段名:设备号
+   * 变量名:device_info
+   * 是否必填:否
+   * 类型:String(32)
+   * 示例值:013467007045764
+   * 描述:微信支付分配的终端设备号,
    * 
*/ @XStreamAlias("device_info") @@ -38,12 +38,12 @@ public class WxPayOrderNotifyResult extends WxPayBaseResult implements Serializa /** *
-   * 用户标识
-   * openid
-   * 是
-   * String(128)
-   * wxd930ea5d5a258f4f
-   * 用户在商户appid下的唯一标识
+   * 字段名:用户标识
+   * 变量名:openid
+   * 是否必填:是
+   * 类型:String(128)
+   * 示例值:wxd930ea5d5a258f4f
+   * 描述:用户在商户appid下的唯一标识
    * 
*/ @XStreamAlias("openid") @@ -51,131 +51,139 @@ public class WxPayOrderNotifyResult extends WxPayBaseResult implements Serializa /** *
-   * 是否关注公众账号
-   * is_subscribe
-   * 否
-   * String(1)
-   * Y
-   * 用户是否关注公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效
+   * 字段名:是否关注公众账号
+   * 变量名:is_subscribe
+   * 是否必填:否
+   * 类型:String(1)
+   * 示例值:Y
+   * 描述:用户是否关注公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效
    * 
*/ @XStreamAlias("is_subscribe") private String isSubscribe; - /** *
-   * 交易类型
-   * trade_type
-   * 是
-   * String(16)
-   * JSAPI	JSAPI、NATIVE、APP
+   * 字段名:用户子标识
+   * 变量名:sub_openid
+   * 是否必填:是
+   * 类型:String(128)
+   * 示例值:wxd930ea5d5a258f4f
+   * 描述:用户在子商户appid下的唯一标识
    * 
*/ - @XStreamAlias("trade_type") - private String tradeType; - + @XStreamAlias("sub_openid") + private String subOpenid; /** *
-   * 付款银行
-   * bank_type
-   * 是
-   * String(16)
-   * CMC
-   * 银行类型,采用字符串类型的银行标识,银行类型见银行列表
+   * 字段名:是否关注子公众账号
+   * 变量名:sub_is_subscribe
+   * 是否必填:否
+   * 类型:String(1)
+   * 示例值:Y
+   * 描述:用户是否关注子公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效
    * 
*/ - @XStreamAlias("bank_type") - private String bankType; + @XStreamAlias("sub_is_subscribe") + private String subIsSubscribe; + /** *
-   *     用户是否关注子公众账号
-   *     String(1)
-   *     Y-关注,N-未关注,仅在公众账号类型支付有效
+   * 字段名:交易类型
+   * 变量名:trade_type
+   * 是否必填:是
+   * 类型:String(16)
+   * 示例值:JSAPI
+   * JSA描述:PI、NATIVE、APP
    * 
*/ - @XStreamAlias("sub_is_subscribe") - private String subIsSubscribe; + @XStreamAlias("trade_type") + private String tradeType; + /** *
-   *     用户在子商户appid下的唯一标识
-   *     String(128)
+   * 字段名:付款银行
+   * 变量名:bank_type
+   * 是否必填:是
+   * 类型:String(16)
+   * 示例值:CMC
+   * 描述:银行类型,采用字符串类型的银行标识,银行类型见银行列表
    * 
*/ - @XStreamAlias("sub_openid") - private String subOpenId; + @XStreamAlias("bank_type") + private String bankType; /** *
-   * 订单金额
-   * total_fee
-   * 是
-   * Int
-   * 100
-   * 订单总金额,单位为分
+   * 字段名:订单金额
+   * 变量名:total_fee
+   * 是否必填:是
+   * 类型:Int
+   * 示例值:100
+   * 描述:订单总金额,单位为分
    * 
*/ @XStreamAlias("total_fee") private Integer totalFee; /** *
-   * 应结订单金额
-   * settlement_total_fee
-   * 否
-   * Int
-   * 100
-   * 应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。
+   * 字段名:应结订单金额
+   * 变量名:settlement_total_fee
+   * 是否必填:否
+   * 类型:Int
+   * 示例值:100
+   * 描述:应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。
    * 
*/ @XStreamAlias("settlement_total_fee") private Integer settlementTotalFee; /** *
-   * 货币种类
-   * fee_type
-   * 否
-   * String(8)
-   * CNY
-   * 货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
+   * 字段名:货币种类
+   * 变量名:fee_type
+   * 是否必填:否
+   * 类型:String(8)
+   * 示例值:CNY
+   * 描述:货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
    * 
*/ @XStreamAlias("fee_type") private String feeType; /** *
-   * 现金支付金额
-   * cash_fee
-   * 是
-   * Int
-   * 100
-   * 现金支付金额订单现金支付金额,详见支付金额
+   * 字段名:现金支付金额
+   * 变量名:cash_fee
+   * 是否必填:是
+   * 类型:Int
+   * 示例值:100
+   * 描述:现金支付金额订单现金支付金额,详见支付金额
    * 
*/ @XStreamAlias("cash_fee") private Integer cashFee; /** *
-   * 现金支付货币类型
-   * cash_fee_type
-   * 否
-   * String(16)
-   * CNY
-   * 货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
+   * 字段名:现金支付货币类型
+   * 变量名:cash_fee_type
+   * 是否必填:否
+   * 类型:String(16)
+   * 示例值:CNY
+   * 描述:货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
    * 
*/ @XStreamAlias("cash_fee_type") private String cashFeeType; /** *
-   * 总代金券金额
-   * coupon_fee
-   * 否
-   * Int
-   * 10
-   * 代金券金额<=订单金额,订单金额-代金券金额=现金支付金额,详见支付金额
+   * 字段名:总代金券金额
+   * 变量名:coupon_fee
+   * 是否必填:否
+   * 类型:Int
+   * 示例值:10
+   * 描述:代金券金额<=订单金额,订单金额-代金券金额=现金支付金额,详见支付金额
    * 
*/ @XStreamAlias("coupon_fee") @@ -183,12 +191,12 @@ public class WxPayOrderNotifyResult extends WxPayBaseResult implements Serializa /** *
-   * 代金券使用数量
-   * coupon_count
-   * 否
-   * Int
-   * 1
-   * 代金券使用数量
+   * 字段名:代金券使用数量
+   * 变量名:coupon_count
+   * 是否必填:否
+   * 类型:Int
+   * 示例值:1
+   * 描述:代金券使用数量
    * 
*/ @XStreamAlias("coupon_count") @@ -198,12 +206,12 @@ public class WxPayOrderNotifyResult extends WxPayBaseResult implements Serializa /** *
-   * 微信支付订单号
-   * transaction_id
-   * 是
-   * String(32)
-   * 1217752501201407033233368018
-   * 微信支付订单号
+   * 字段名:微信支付订单号
+   * 变量名:transaction_id
+   * 是否必填:是
+   * 类型:String(32)
+   * 示例值:1217752501201407033233368018
+   * 描述:微信支付订单号
    * 
*/ @XStreamAlias("transaction_id") @@ -211,36 +219,36 @@ public class WxPayOrderNotifyResult extends WxPayBaseResult implements Serializa /** *
-   * 商户订单号
-   * out_trade_no
-   * 是
-   * String(32)
-   * 1212321211201407033568112322
-   * 商户系统的订单号,与请求一致。
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:String(32)
+   * 示例值:1212321211201407033568112322
+   * 描述:商户系统的订单号,与请求一致。
    * 
*/ @XStreamAlias("out_trade_no") private String outTradeNo; /** *
-   * 商家数据包
-   * attach
-   * 否
-   * String(128)
-   * 123456
-   * 商家数据包,原样返回
+   * 字段名:商家数据包
+   * 变量名:attach
+   * 是否必填:否
+   * 类型:String(128)
+   * 示例值:123456
+   * 描述:商家数据包,原样返回
    * 
*/ @XStreamAlias("attach") private String attach; /** *
-   * 支付完成时间
-   * time_end
-   * 是
-   * String(14)
-   * 20141030133525
-   * 支付完成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
+   * 字段名:支付完成时间
+   * 变量名:time_end
+   * 是否必填:是
+   * 类型:String(14)
+   * 示例值:20141030133525
+   * 描述:支付完成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
    * 
*/ @XStreamAlias("time_end") @@ -311,22 +319,6 @@ public void setBankType(String bankType) { this.bankType = bankType; } - public String getSubIsSubscribe() { - return subIsSubscribe; - } - - public void setSubIsSubscribe(String subIsSubscribe) { - this.subIsSubscribe = subIsSubscribe; - } - - public String getSubOpenId() { - return subOpenId; - } - - public void setSubOpenId(String subOpenId) { - this.subOpenId = subOpenId; - } - public Integer getTotalFee() { return totalFee; } @@ -407,6 +399,22 @@ public void setTimeEnd(String timeEnd) { this.timeEnd = timeEnd; } + public String getSubOpenid() { + return this.subOpenid; + } + + public void setSubOpenid(String subOpenid) { + this.subOpenid = subOpenid; + } + + public String getSubIsSubscribe() { + return this.subIsSubscribe; + } + + public void setSubIsSubscribe(String subIsSubscribe) { + this.subIsSubscribe = subIsSubscribe; + } + @Override public Map toMap() { Map resultMap = BeanUtils.xmlBean2Map(this); From d7b32d24f9c706553d5f0f820535143048904ae0 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 3 Jul 2017 15:49:18 +0800 Subject: [PATCH 128/179] fix time --- .../mp/util/json/WxMpMaterialNewsGsonAdapter.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java index a77a209814..084e355cbc 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java @@ -13,6 +13,7 @@ import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; import java.lang.reflect.Type; +import java.text.SimpleDateFormat; import java.util.Date; public class WxMpMaterialNewsGsonAdapter implements JsonSerializer, JsonDeserializer { @@ -28,6 +29,16 @@ public JsonElement serialize(WxMpMaterialNews wxMpMaterialNews, Type typeOfSrc, } newsJson.add("articles", articleJsonArray); + if (wxMpMaterialNews.getCreatedTime() != null) { + newsJson.addProperty("create_time", + SimpleDateFormat.getDateTimeInstance().format(wxMpMaterialNews.getCreatedTime())); + } + + if (wxMpMaterialNews.getUpdatedTime() != null) { + newsJson.addProperty("update_time", + SimpleDateFormat.getDateTimeInstance().format(wxMpMaterialNews.getUpdatedTime())); + } + return newsJson; } @@ -45,12 +56,12 @@ public WxMpMaterialNews deserialize(JsonElement jsonElement, Type type, JsonDese } if (json.get("create_time") != null && !json.get("create_time").isJsonNull()) { - Date createTime = new Date(GsonHelper.getAsLong(json.get("create_time"))); + Date createTime = new Date(GsonHelper.getAsLong(json.get("create_time"))* 1000); wxMpMaterialNews.setCreatedTime(createTime); } if (json.get("update_time") != null && !json.get("update_time").isJsonNull()) { - Date updateTime = new Date(GsonHelper.getAsLong(json.get("update_time"))); + Date updateTime = new Date(GsonHelper.getAsLong(json.get("update_time"))* 1000); wxMpMaterialNews.setUpdatedTime(updateTime); } From 82171685031760e996515ee2bc354fd5768ac638 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 3 Jul 2017 17:36:10 +0800 Subject: [PATCH 129/179] =?UTF-8?q?=E4=BC=98=E5=8C=96javadoc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/WxPayUnifiedOrderRequest.java | 214 +++++++++--------- 1 file changed, 104 insertions(+), 110 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java index f5b58245d9..342a3eb2d2 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java @@ -10,13 +10,6 @@ *
  * 统一下单请求参数对象
  * 参考文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
- * 注释中各行每个字段描述对应如下:
- * 
  • 字段名 - *
  • 变量名 - *
  • 是否必填 - *
  • 类型 - *
  • 示例值 - *
  • 描述 *
  • * Created by Binary Wang on 2016/9/25. * @@ -24,16 +17,16 @@ */ @XStreamAlias("xml") public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { - private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP","MWEB"}; + private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP", "MWEB"}; /** *
    -   * 设备号
    -   * device_info
    -   * 否
    -   * String(32)
    -   * 013467007045764
    -   * 终端设备号(门店号或收银设备Id),注意:PC网页或公众号内支付请传"WEB"
    +   * 字段名:设备号
    +   * 变量名:device_info
    +   * 是否必填:否
    +   * 类型:String(32)
    +   * 示例值:013467007045764
    +   * 描述:终端设备号(门店号或收银设备Id),注意:PC网页或公众号内支付请传"WEB"
        * 
    */ @XStreamAlias("device_info") @@ -41,12 +34,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 商品描述
    -   * body
    -   * 是
    -   * String(128)
    -   * 腾讯充值中心-QQ会员充值
    -   * 商品简单描述,该字段须严格按照规范传递,具体请见参数规定
    +   * 字段名:商品描述
    +   * 变量名:body
    +   * 是否必填:是
    +   * 类型:String(128)
    +   * 示例值: 腾讯充值中心-QQ会员充值
    +   * 描述:商品简单描述,该字段须严格按照规范传递,具体请见参数规定
        * 
    */ @Required @@ -55,12 +48,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 商品详情
    -   * detail
    -   * 否
    -   * String(6000)
    -   *  {  "goods_detail":[
    -   * {
    +   * 字段名:商品详情
    +   * 变量名:detail
    +   * 是否必填:否
    +   * 类型:String(6000)
    +   * 示例值: {  "goods_detail":[
    +   *  {
        * "goods_id":"iphone6s_16G",
        * "wxpay_goods_id":"1001",
        * "goods_name":"iPhone6s 16G",
    @@ -80,7 +73,7 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest {
        * }
        * ]
        * }
    -   * 商品详细列表,使用Json格式,传输签名前请务必使用CDATA标签将JSON文本串保护起来。
    +   * 描述:商品详细列表,使用Json格式,传输签名前请务必使用CDATA标签将JSON文本串保护起来。
        * goods_detail []:
        * └ goods_id String 必填 32 商品的编号
        * └ wxpay_goods_id String 可选 32 微信支付定义的统一商品编号
    @@ -96,12 +89,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest {
     
       /**
        * 
    -   * 附加数据
    -   * attach
    -   * 否
    -   * String(127)
    -   * 深圳分店
    -   *  附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
    +   * 字段名:附加数据
    +   * 变量名:attach
    +   * 是否必填:否
    +   * 类型:String(127)
    +   * 示例值: 深圳分店
    +   * 描述:  附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
        * 
    */ @XStreamAlias("attach") @@ -109,12 +102,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 商户订单号
    -   * out_trade_no
    -   * 是
    -   * String(32)
    -   * 20150806125346
    -   * 商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
    +   * 字段名:商户订单号
    +   * 变量名:out_trade_no
    +   * 是否必填:是
    +   * 类型:String(32)
    +   * 示例值:20150806125346
    +   * 描述:商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
        * 
    */ @Required @@ -123,12 +116,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 货币类型
    -   * fee_type
    -   * 否
    -   * String(16)
    -   * CNY
    -   * 符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
    +   * 字段名:货币类型
    +   * 变量名:fee_type
    +   * 是否必填:否
    +   * 类型:String(16)
    +   * 示例值:CNY
    +   * 描述: 符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
        * 
    */ @XStreamAlias("fee_type") @@ -136,12 +129,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 总金额
    -   * total_fee
    -   * 是
    -   * Int
    -   * 888
    -   * 订单总金额,单位为分,详见支付金额
    +   * 字段名:总金额
    +   * 变量名:total_fee
    +   * 是否必填:是
    +   * 类型:Int
    +   * 示例值: 888
    +   * 描述:订单总金额,单位为分,详见支付金额
        * 
    */ @Required @@ -150,12 +143,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 终端IP
    -   * spbill_create_ip
    -   * 是
    -   * String(16)
    -   * 123.12.12.123
    -   * APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
    +   * 字段名:终端IP
    +   * 变量名:spbill_create_ip
    +   * 是否必填:是
    +   * 类型:String(16)
    +   * 示例值:123.12.12.123
    +   * 描述:APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
        * 
    */ @Required @@ -164,12 +157,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 交易起始时间
    -   * time_start
    -   * 否
    -   * String(14)
    -   * 20091225091010
    -   * 订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
    +   * 字段名:交易起始时间
    +   * 变量名:time_start
    +   * 是否必填:否
    +   * 类型:String(14)
    +   * 示例值:20091225091010
    +   * 描述:订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
        * 
    */ @XStreamAlias("time_start") @@ -177,12 +170,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 交易结束时间
    -   * time_expire
    -   * 否
    -   * String(14)
    -   * 20091227091010
    -   * 订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则
    +   * 字段名:交易结束时间
    +   * 变量名:time_expire
    +   * 是否必填:否
    +   * 类型:String(14)
    +   * 示例值:20091227091010
    +   * 描述:订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则
        *   注意:最短失效时间间隔必须大于5分钟
        * 
    */ @@ -191,12 +184,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 商品标记
    -   * goods_tag
    -   * 否
    -   * String(32)
    -   * WXG
    -   * 商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠
    +   * 字段名:商品标记
    +   * 变量名:goods_tag
    +   * 是否必填:否
    +   * 类型:String(32)
    +   * 示例值:WXG
    +   * 描述:商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠
        * 
    */ @XStreamAlias("goods_tag") @@ -204,12 +197,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 通知地址
    -   * notify_url
    -   * 是
    -   * String(256)
    -   * http://www.weixin.qq.com/wxpay/pay.php
    -   * 接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
    +   * 字段名:通知地址
    +   * 变量名:notify_url
    +   * 是否必填:是
    +   * 类型:String(256)
    +   * 示例值:http://www.weixin.qq.com/wxpay/pay.php
    +   * 描述:接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
        * 
    */ @Required @@ -218,12 +211,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 交易类型
    -   * trade_type
    -   * 是
    -   * String(16)
    -   * JSAPI
    -   * 取值如下:JSAPI,NATIVE,APP,详细说明见参数规定:
    +   * 字段名:交易类型
    +   * 变量名:trade_type
    +   * 是否必填:是
    +   * 类型:String(16)
    +   * 示例值: JSAPI
    +   * 描述: 取值如下:JSAPI,NATIVE,APP,详细说明见参数规定:
        * JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付,统一下单接口trade_type的传参可参考这里
        * 
    */ @@ -233,12 +226,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 商品Id
    -   * product_id
    -   * 否
    -   * String(32)
    -   * 12235413214070356458058
    -   * trade_type=NATIVE,此参数必传。此id为二维码中包含的商品Id,商户自行定义。
    +   * 字段名:商品Id
    +   * 变量名:product_id
    +   * 是否必填:否
    +   * 类型:String(32)
    +   * 示例值:12235413214070356458058
    +   * 描述:trade_type=NATIVE,此参数必传。此id为二维码中包含的商品Id,商户自行定义。
        * 
    */ @XStreamAlias("product_id") @@ -246,11 +239,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 指定支付方式
    -   * limit_pay
    -   * 否
    -   * String(32)
    -   * no_credit no_credit--指定不能使用信用卡支付
    +   * 字段名:指定支付方式
    +   * 变量名:limit_pay
    +   * 是否必填:否
    +   * 类型:String(32)
    +   * 示例值:no_credit
    +   * 描述:no_credit--指定不能使用信用卡支付
        * 
    */ @XStreamAlias("limit_pay") @@ -258,12 +252,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 用户标识
    -   * openid
    -   * 否
    -   * String(128)
    -   * oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
    -   * trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。
    +   * 字段名:用户标识
    +   * 变量名:openid
    +   * 是否必填:否
    +   * 类型:String(128)
    +   * 示例值:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
    +   * 描述:trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。
        * openid如何获取,可参考【获取openid】。
        * 企业号请使用【企业号OAuth2.0接口】获取企业号内成员userid,再调用【企业号userid转openid接口】进行转换
        * 
    @@ -273,12 +267,12 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { /** *
    -   * 用户子标识
    -   * sub_openid
    -   * 否
    -   * String(128)
    -   * oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
    -   * trade_type=JSAPI,此参数必传,用户在子商户appid下的唯一标识。
    +   * 字段名:用户子标识
    +   * 变量名:sub_openid
    +   * 是否必填:否
    +   * 类型:String(128)
    +   * 示例值:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
    +   * 描述:trade_type=JSAPI,此参数必传,用户在子商户appid下的唯一标识。
        * openid和sub_openid可以选传其中之一,如果选择传sub_openid,则必须传sub_appid。
        * 下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。
        * 
    From 1352d7247fa236712ec903cbf0c78bb8f4b997d9 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 3 Jul 2017 17:38:37 +0800 Subject: [PATCH 130/179] =?UTF-8?q?=E5=8F=91=E5=B8=83=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC2.7.3.BETA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 84de33cb46..a718c699bb 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang weixin-java-parent - 2.7.2.BETA + 2.7.3.BETA pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 71e09c8f49..61e4cb7842 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.2.BETA + 2.7.3.BETA weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 86c5994f4a..0fa4104a2e 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.2.BETA + 2.7.3.BETA weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index b1bb6a27d9..fc4c3f43c0 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.2.BETA + 2.7.3.BETA weixin-java-miniapp WeiXin Java Tools - MiniApp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 2f1a0d6ef9..5030f42b1e 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.2.BETA + 2.7.3.BETA weixin-java-mp WeiXin Java Tools - MP diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index e930a48178..0f9e4c8d8b 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 2.7.2.BETA + 2.7.3.BETA 4.0.0 From 55cfcb9abd23ca2a392471bd6ab4f8c532b90287 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 3 Jul 2017 17:57:44 +0800 Subject: [PATCH 131/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E6=89=93=E5=8C=85=E6=97=B6=E5=8F=91=E7=8E=B0=E7=9A=84=E4=B8=8D?= =?UTF-8?q?=E8=A7=84=E8=8C=83=E7=9A=84javadoc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/common/util/crypto/WxCryptUtil.java | 12 +++++------- .../common/util/http/okhttp/OkHttpProxyInfo.java | 3 +-- .../wx/miniapp/message/WxMaMessageRouterRule.java | 2 -- .../java/me/chanjar/weixin/mp/api/WxMpService.java | 2 +- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java index e80419d716..e362e64b2f 100755 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java @@ -13,21 +13,23 @@ import javax.xml.parsers.ParserConfigurationException; import java.io.StringReader; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Random; /** + *
      * 对公众平台发送给公众账号的消息加解密示例代码.
    - *
    - * @copyright Copyright (c) 1998-2014 Tencent Inc.
    + * Copyright (c) 1998-2014 Tencent Inc.
      * 针对org.apache.commons.codec.binary.Base64,
      * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
      * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
    + * 
    */ public class WxCryptUtil { private static final Base64 base64 = new Base64(); - private static final Charset CHARSET = Charset.forName("utf-8"); + private static final Charset CHARSET = StandardCharsets.UTF_8; private static final ThreadLocal builderLocal = new ThreadLocal() { @Override @@ -76,8 +78,6 @@ static String extractEncryptPart(String xml) { /** * 将一个数字转换成生成4个字节的网络字节序bytes数组 - * - * @param number */ private static byte[] number2BytesInNetworkOrder(int number) { byte[] orderBytes = new byte[4]; @@ -90,8 +90,6 @@ private static byte[] number2BytesInNetworkOrder(int number) { /** * 4个字节的网络字节序bytes数组还原成一个数字 - * - * @param bytesInNetworkOrder */ private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) { int sourceNumber = 0; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpProxyInfo.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpProxyInfo.java index 5515b0f713..eb9f7ac908 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpProxyInfo.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpProxyInfo.java @@ -13,6 +13,7 @@ public class OkHttpProxyInfo { private final String proxyUsername; private final String proxyPassword; private final ProxyType proxyType; + public OkHttpProxyInfo(ProxyType proxyType, String proxyHost, int proxyPort, String proxyUser, String proxyPassword) { this.proxyType = proxyType; this.proxyAddress = proxyHost; @@ -91,8 +92,6 @@ public String getProxyPassword() { /** * 返回 java.net.Proxy - * - * @return */ public Proxy getProxy() { Proxy proxy = null; diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java index 9fce8b1a04..835eb2894a 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java @@ -189,8 +189,6 @@ protected boolean test(WxMaMessage wxMessage) { /** * 处理微信推送过来的消息 - * - * @return true 代表继续执行别的router,false 代表停止执行别的router */ protected void service(WxMaMessage wxMessage, Map context, diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index 71a5413523..7199d4e05c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -422,7 +422,7 @@ public interface WxMpService { void initHttp(); /** - * @return + * @return RequestHttp对象 */ RequestHttp getRequestHttp(); From 8dc2b4d0af02ce2357d3da08659f12c94a301ced Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Wed, 5 Jul 2017 12:03:44 +0800 Subject: [PATCH 132/179] =?UTF-8?q?#268=20=E4=BF=AE=E5=A4=8DWxCpUserServic?= =?UTF-8?q?eImpl=E5=88=A0=E9=99=A4=E7=94=A8=E6=88=B7=E7=9A=84=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java index c49c1ffd69..13009427c6 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java @@ -42,15 +42,12 @@ public void update(WxCpUser user) throws WxErrorException { this.mainService.post(url, user.toJson()); } - public void deleteOne(String userId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userId; - this.mainService.get(url, null); - } - @Override public void delete(String... userIds) throws WxErrorException { if (userIds.length == 1) { - this.deleteOne(userIds[0]); + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userIds[0]; + this.mainService.get(url, null); + return; } String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; From 15d7773f8a5e1585331b35f78dafded0669210ca Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 6 Jul 2017 15:21:42 +0800 Subject: [PATCH 133/179] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java | 2 +- .../cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java | 2 +- .../chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java index 6cff26485e..be1b311857 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java @@ -405,7 +405,7 @@ protected synchronized T executeInternal(RequestExecutor executor, if (error.getErrorCode() != 0) { this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, data, error); - throw new WxErrorException(error); + throw new WxErrorException(error, e); } return null; } catch (IOException e) { diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java index c8605d25de..023306634b 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java @@ -213,7 +213,7 @@ public synchronized T executeInternal(RequestExecutor executor, Str if (error.getErrorCode() != 0) { this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, data, error); - throw new WxErrorException(error); + throw new WxErrorException(error, e); } return null; } catch (IOException e) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java index 9dc1d755dd..d3075aa11d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java @@ -306,7 +306,7 @@ public synchronized T executeInternal(RequestExecutor executor, Str if (error.getErrorCode() != 0) { this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, data, error); - throw new WxErrorException(error); + throw new WxErrorException(error, e); } return null; } catch (IOException e) { @@ -397,7 +397,7 @@ public WxMpDeviceService getDeviceService() { } @Override - public WxMpShakeService getShakeService(){ + public WxMpShakeService getShakeService() { return this.shakeService; } From 368dbc97218960139d9d1d05433178784a9ff7f6 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 6 Jul 2017 15:44:58 +0800 Subject: [PATCH 134/179] fix javadoc --- .../java/me/chanjar/weixin/common/annotation/Required.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/annotation/Required.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/annotation/Required.java index 9370561fb7..e18be69e96 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/annotation/Required.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/annotation/Required.java @@ -6,9 +6,10 @@ import java.lang.annotation.Target; /** + *
      * 标识某个字段是否是必填的
    - * 

    * Created by Binary Wang on 2016/9/25. + *

    * * @author binarywang (https://github.com/binarywang) */ From e9f55665ec5784ed35a0d77a550ebf018946e38b Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 6 Jul 2017 15:47:06 +0800 Subject: [PATCH 135/179] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=97=A5=E5=BF=97=E8=BE=93=E5=87=BA=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weixin-java-common/src/test/resources/logback-test.xml | 3 +-- weixin-java-cp/src/test/resources/logback-test.xml | 3 +-- weixin-java-miniapp/src/test/resources/logback-test.xml | 3 +-- weixin-java-mp/src/test/resources/logback-test.xml | 3 +-- weixin-java-pay/src/test/resources/logback-test.xml | 1 - 5 files changed, 4 insertions(+), 9 deletions(-) diff --git a/weixin-java-common/src/test/resources/logback-test.xml b/weixin-java-common/src/test/resources/logback-test.xml index e206e178ec..9a6fe3eea1 100644 --- a/weixin-java-common/src/test/resources/logback-test.xml +++ b/weixin-java-common/src/test/resources/logback-test.xml @@ -5,9 +5,8 @@ - + - diff --git a/weixin-java-cp/src/test/resources/logback-test.xml b/weixin-java-cp/src/test/resources/logback-test.xml index ec3deca97f..e4a33acd88 100644 --- a/weixin-java-cp/src/test/resources/logback-test.xml +++ b/weixin-java-cp/src/test/resources/logback-test.xml @@ -6,9 +6,8 @@ - + - diff --git a/weixin-java-miniapp/src/test/resources/logback-test.xml b/weixin-java-miniapp/src/test/resources/logback-test.xml index 14d6a9a79b..e4a33acd88 100644 --- a/weixin-java-miniapp/src/test/resources/logback-test.xml +++ b/weixin-java-miniapp/src/test/resources/logback-test.xml @@ -6,9 +6,8 @@ - + - diff --git a/weixin-java-mp/src/test/resources/logback-test.xml b/weixin-java-mp/src/test/resources/logback-test.xml index 8e87c71af2..e4a33acd88 100644 --- a/weixin-java-mp/src/test/resources/logback-test.xml +++ b/weixin-java-mp/src/test/resources/logback-test.xml @@ -6,9 +6,8 @@ - + - diff --git a/weixin-java-pay/src/test/resources/logback-test.xml b/weixin-java-pay/src/test/resources/logback-test.xml index 75de28c04c..35deb2ed28 100644 --- a/weixin-java-pay/src/test/resources/logback-test.xml +++ b/weixin-java-pay/src/test/resources/logback-test.xml @@ -12,5 +12,4 @@ - From dde7c643fa998d6a9c640c4af8ef816cc6de95c8 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 6 Jul 2017 15:59:13 +0800 Subject: [PATCH 136/179] =?UTF-8?q?#269=20=E4=BF=AE=E5=A4=8Dokhttp?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=B4=A0=E6=9D=90=E4=B8=8A=E4=BC=A0=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OkHttpMediaUploadRequestExecutor.java | 8 +++-- .../OkhttpMaterialUploadRequestExecutor.java | 35 ++++++++++--------- .../OkhttpMediaImgUploadRequestExecutor.java | 16 +++++---- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java index c01b373808..91b36d7da6 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java @@ -39,8 +39,12 @@ public Request authenticate(Route route, Response response) throws IOException { //得到httpClient OkHttpClient client = clientBuilder.build(); - RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); - RequestBody body = new MultipartBody.Builder().addFormDataPart("media", null, fileBody).build(); + RequestBody body = new MultipartBody.Builder() + .setType(MediaType.parse("multipart/form-data")) + .addFormDataPart("media", + file.getName(), + RequestBody.create(MediaType.parse("application/octet-stream"), file)) + .build(); Request request = new Request.Builder().url(uri).post(body).build(); Response response = client.newCall(request).execute(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java index 27a9b5bfc7..3770aa1b67 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java @@ -25,6 +25,14 @@ public OkhttpMaterialUploadRequestExecutor(RequestHttp requestHttp) { @Override public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material) throws WxErrorException, IOException { + if (material == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); + } + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); //设置代理 if (requestHttp.getRequestHttpProxy() != null) { @@ -40,27 +48,19 @@ public Request authenticate(Route route, Response response) throws IOException { .build(); } }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - - if (material == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); - } - - File file = material.getFile(); - if (file == null || !file.exists()) { - throw new FileNotFoundException(); - } - RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); - MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().addFormDataPart("media", null, fileBody); + MultipartBody.Builder bodyBuilder = new MultipartBody.Builder() + .setType(MediaType.parse("multipart/form-data")) + .addFormDataPart("media", + file.getName(), + RequestBody.create(MediaType.parse("application/octet-stream"), file)); Map form = material.getForm(); - if (material.getForm() != null) { + if (form != null) { bodyBuilder.addFormDataPart("description", WxGsonBuilder.create().toJson(form)); } - RequestBody body = bodyBuilder.build(); - Request request = new Request.Builder().url(uri).post(body).build(); - Response response = client.newCall(request).execute(); + + Request request = new Request.Builder().url(uri).post(bodyBuilder.build()).build(); + Response response = clientBuilder.build().newCall(request).execute(); String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { @@ -69,4 +69,5 @@ public Request authenticate(Route route, Response response) throws IOException { return WxMpMaterialUploadResult.fromJson(responseContent); } } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java index 3d8abd394a..3b10f63bcf 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java @@ -21,7 +21,7 @@ public OkhttpMediaImgUploadRequestExecutor(RequestHttp requestHttp) { } @Override - public WxMediaImgUploadResult execute(String uri, File data) throws WxErrorException, IOException { + public WxMediaImgUploadResult execute(String uri, File file) throws WxErrorException, IOException { OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); //设置代理 if (requestHttp.getRequestHttpProxy() != null) { @@ -37,14 +37,16 @@ public Request authenticate(Route route, Response response) throws IOException { .build(); } }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), data); - RequestBody body = new MultipartBody.Builder().addFormDataPart("media", null, fileBody).build(); - Request request = new Request.Builder().url(uri).post(body).build(); + RequestBody body = new MultipartBody.Builder() + .setType(MediaType.parse("multipart/form-data")) + .addFormDataPart("media", + file.getName(), + RequestBody.create(MediaType.parse("application/octet-stream"), file)) + .build(); - Response response = client.newCall(request).execute(); + Request request = new Request.Builder().url(uri).post(body).build(); + Response response = clientBuilder.build().newCall(request).execute(); String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { From fd4b8e1541deec55c002b24d3b013a224821e6ce Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 6 Jul 2017 16:02:07 +0800 Subject: [PATCH 137/179] =?UTF-8?q?=E8=AE=A9httpclient=E6=94=AF=E6=8C=81sl?= =?UTF-8?q?f4j=E6=97=A5=E5=BF=97=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weixin-java-common/pom.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 61e4cb7842..f198bd70d9 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -37,11 +37,23 @@ org.apache.httpcomponents httpclient + + + commons-logging + commons-logging + + org.apache.httpcomponents httpmime + + org.slf4j + jcl-over-slf4j + 1.7.24 + + com.google.code.gson gson From b3f50e26c21965c4b983f79519bce62e28dbe187 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 6 Jul 2017 16:29:46 +0800 Subject: [PATCH 138/179] add maven-checkstyle-plugin --- pom.xml | 20 +++ quality-checks/google_checks.xml | 217 +++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 quality-checks/google_checks.xml diff --git a/pom.xml b/pom.xml index a718c699bb..3383cb0fb7 100644 --- a/pom.xml +++ b/pom.xml @@ -349,6 +349,26 @@ UTF-8 + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.17 + + quality-checks/google_checks.xml + true + true + true + + + + verify + + check + + + + diff --git a/quality-checks/google_checks.xml b/quality-checks/google_checks.xml new file mode 100644 index 0000000000..925172dab6 --- /dev/null +++ b/quality-checks/google_checks.xml @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 24b954e68ec48b0acd70a15cbd4fae694c0f2c25 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 6 Jul 2017 16:32:30 +0800 Subject: [PATCH 139/179] Update .codeclimate.yml --- .codeclimate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 103ea86efb..fe226677d0 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -4,4 +4,4 @@ engines: ratings: paths: [] exclude_paths: -- "README.md" +- "readme.md" From 812190a19067d09d81ebb450fc26d186f7226ca7 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 6 Jul 2017 16:33:46 +0800 Subject: [PATCH 140/179] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 904ee9a47c..1c533f9765 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: java sudo: false install: true addons: - sonarqube: + sonarcloud: token: secure: "834110c7191f97ecb226970c46dcaff8e681da5a" From c5c204b25db4c10fb91f2be8eefe80e6779de829 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 8 Jul 2017 15:55:48 +0800 Subject: [PATCH 141/179] =?UTF-8?q?#270=20NewArticle=E5=92=8CMpnewsArticle?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=BA=8F=E5=88=97=E5=8C=96=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../me/chanjar/weixin/cp/bean/article/MpnewsArticle.java | 6 +++++- .../java/me/chanjar/weixin/cp/bean/article/NewArticle.java | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/MpnewsArticle.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/MpnewsArticle.java index 82c4e2aaa6..b3f4acf402 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/MpnewsArticle.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/MpnewsArticle.java @@ -1,5 +1,7 @@ package me.chanjar.weixin.cp.bean.article; +import java.io.Serializable; + /** *
      *  Created by BinaryWang on 2017/3/27.
    @@ -7,7 +9,9 @@
      *
      * @author Binary Wang
      */
    -public class MpnewsArticle {
    +public class MpnewsArticle implements Serializable {
    +  private static final long serialVersionUID = 6985871812170756481L;
    +
       private String title;
       private String thumbMediaId;
       private String author;
    diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java
    index d4c056d5ad..02b0b1086f 100644
    --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java
    +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java
    @@ -1,5 +1,7 @@
     package me.chanjar.weixin.cp.bean.article;
     
    +import java.io.Serializable;
    +
     /**
      * 
      *  Created by BinaryWang on 2017/3/27.
    @@ -7,7 +9,8 @@
      *
      * @author Binary Wang
      */
    -public class NewArticle {
    +public class NewArticle implements Serializable {
    +  private static final long serialVersionUID = 4087852055781140659L;
     
       private String title;
       private String description;
    
    From d3c691af094884e0766e1b76418341d91457bac5 Mon Sep 17 00:00:00 2001
    From: Binary Wang 
    Date: Sat, 8 Jul 2017 16:01:46 +0800
    Subject: [PATCH 142/179] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98?=
     =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=AF=B7=E6=B1=82=E5=A2=9E=E5=8A=A0=E8=B6=85?=
     =?UTF-8?q?=E6=97=B6=E6=97=B6=E9=97=B4=E7=9A=84=E8=AE=BE=E7=BD=AE=E5=8F=82?=
     =?UTF-8?q?=E6=95=B0?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    ---
     .../binarywang/wxpay/config/WxPayConfig.java  | 33 +++++++++++++++++++
     .../wxpay/service/impl/WxPayServiceImpl.java  | 10 ++++--
     2 files changed, 40 insertions(+), 3 deletions(-)
    
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java
    index d05259ceeb..aeab939a06 100644
    --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java
    @@ -18,6 +18,17 @@
      * @author Binary Wang (https://github.com/binarywang)
      */
     public class WxPayConfig {
    +
    +  /**
    +   * http请求连接超时时间
    +   */
    +  private int httpConnectionTimeout = 5000;
    +
    +  /**
    +   * http请求数据读取等待时间
    +   */
    +  private int httpTimeout = 10000;
    +
       private String appId;
       private String subAppId;
       private String mchId;
    @@ -194,4 +205,26 @@ public SSLContext initSSLContext() throws WxPayException {
           IOUtils.closeQuietly(inputStream);
         }
       }
    +
    +  /**
    +   * http请求连接超时时间
    +   */
    +  public int getHttpConnectionTimeout() {
    +    return this.httpConnectionTimeout;
    +  }
    +
    +  public void setHttpConnectionTimeout(int httpConnectionTimeout) {
    +    this.httpConnectionTimeout = httpConnectionTimeout;
    +  }
    +
    +  /**
    +   * http请求数据读取等待时间
    +   */
    +  public int getHttpTimeout() {
    +    return this.httpTimeout;
    +  }
    +
    +  public void setHttpTimeout(int httpTimeout) {
    +    this.httpTimeout = httpTimeout;
    +  }
     }
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
    index bcf425d792..a2b036e8e8 100644
    --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
    @@ -465,9 +465,11 @@ public String getSandboxSignKey() throws WxPayException {
        * @return 返回请求结果
        */
       private String post(String url, String xmlParam) throws WxPayException {
    -    String requestString = new String(xmlParam.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
    -
    -    HttpRequest request = HttpRequest.post(url).body(requestString);
    +    HttpRequest request = HttpRequest
    +      .post(url)
    +      .timeout(this.config.getHttpTimeout())
    +      .connectionTimeout(this.config.getHttpConnectionTimeout())
    +      .body(new String(xmlParam.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
         String responseString = this.getResponseString(request.send());
     
         this.log.info("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", url, xmlParam, responseString);
    @@ -489,6 +491,8 @@ private String postWithKey(String url, String requestStr) throws WxPayException
     
           HttpRequest request = HttpRequest
             .post(url)
    +        .timeout(this.config.getHttpTimeout())
    +        .connectionTimeout(this.config.getHttpConnectionTimeout())
             .withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext))
             .bodyText(requestStr);
     
    
    From c3cb050a8aad56e0a5fb78cb2c5c33038620537e Mon Sep 17 00:00:00 2001
    From: Binary Wang 
    Date: Sat, 8 Jul 2017 16:14:03 +0800
    Subject: [PATCH 143/179] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=AE=80=E5=8C=96?=
     =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98=E8=AF=B7=E6=B1=82=E4=BB=A3?=
     =?UTF-8?q?=E7=A0=81?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    ---
     .../wxpay/service/impl/WxPayServiceImpl.java  | 75 ++++++++-----------
     1 file changed, 30 insertions(+), 45 deletions(-)
    
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
    index a2b036e8e8..f799a2c974 100644
    --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
    @@ -57,7 +57,7 @@ public WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayExceptio
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/secapi/pay/refund";
    -    String responseContent = this.postWithKey(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), true);
         WxPayRefundResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundResult.class);
         result.checkResult(this);
         return result;
    @@ -75,7 +75,7 @@ public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeN
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/pay/refundquery";
    -    String responseContent = this.post(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), false);
         WxPayRefundQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundQueryResult.class);
         result.composeRefundRecords();
         result.checkResult(this);
    @@ -109,7 +109,7 @@ public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throw
           url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendgroupredpack";
         }
     
    -    String responseContent = this.postWithKey(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), true);
         WxPaySendRedpackResult result = WxPayBaseResult.fromXML(responseContent, WxPaySendRedpackResult.class);
         //毋须校验,因为没有返回签名信息
         // this.checkResult(result);
    @@ -124,7 +124,7 @@ public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayExcept
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gethbinfo";
    -    String responseContent = this.postWithKey(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), true);
         WxPayRedpackQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRedpackQueryResult.class);
         result.checkResult(this);
         return result;
    @@ -138,7 +138,7 @@ public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo)
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/pay/orderquery";
    -    String responseContent = this.post(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), false);
         if (StringUtils.isBlank(responseContent)) {
           throw new WxPayException("无响应结果");
         }
    @@ -160,7 +160,7 @@ public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/pay/closeorder";
    -    String responseContent = this.post(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), false);
         WxPayOrderCloseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderCloseResult.class);
         result.checkResult(this);
     
    @@ -172,7 +172,7 @@ public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) th
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/pay/unifiedorder";
    -    String responseContent = this.post(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), false);
         WxPayUnifiedOrderResult result = WxPayBaseResult.fromXML(responseContent, WxPayUnifiedOrderResult.class);
         result.checkResult(this);
         return result;
    @@ -227,7 +227,7 @@ public WxEntPayResult entPay(WxEntPayRequest request) throws WxPayException {
         request.checkAndSign(this.getConfig());
         String url = this.getPayBaseUrl() + "/mmpaymkttransfers/promotion/transfers";
     
    -    String responseContent = this.postWithKey(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), true);
         WxEntPayResult result = WxPayBaseResult.fromXML(responseContent, WxEntPayResult.class);
         result.checkResult(this);
         return result;
    @@ -240,7 +240,7 @@ public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayExcept
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gettransferinfo";
    -    String responseContent = this.postWithKey(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), true);
         WxEntPayQueryResult result = WxPayBaseResult.fromXML(responseContent, WxEntPayQueryResult.class);
         result.checkResult(this);
         return result;
    @@ -293,7 +293,7 @@ public void report(WxPayReportRequest request) throws WxPayException {
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/payitil/report";
    -    String responseContent = this.post(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), false);
         WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class);
         result.checkResult(this);
       }
    @@ -309,7 +309,7 @@ public WxPayBillResult downloadBill(String billDate, String billType, String tar
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/pay/downloadbill";
    -    String responseContent = this.post(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), false);
         if (responseContent.startsWith("<")) {
           WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class);
           result.checkResult(this);
    @@ -396,7 +396,7 @@ public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayEx
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/pay/micropay";
    -    String responseContent = this.post(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), false);
         WxPayMicropayResult result = WxPayBaseResult.fromXML(responseContent, WxPayMicropayResult.class);
         result.checkResult(this);
         return result;
    @@ -407,7 +407,7 @@ public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) th
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/secapi/pay/reverse";
    -    String responseContent = this.postWithKey(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), true);
         WxPayOrderReverseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderReverseResult.class);
         result.checkResult(this);
         return result;
    @@ -418,7 +418,7 @@ public String shorturl(WxPayShorturlRequest request) throws WxPayException {
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/tools/shorturl";
    -    String responseContent = this.post(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), false);
         WxPayShorturlResult result = WxPayBaseResult.fromXML(responseContent, WxPayShorturlResult.class);
         result.checkResult(this);
         return result.getShortUrl();
    @@ -434,7 +434,7 @@ public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayE
         request.checkAndSign(this.getConfig());
     
         String url = this.getPayBaseUrl() + "/tools/authcodetoopenid";
    -    String responseContent = this.post(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), false);
         WxPayAuthcode2OpenidResult result = WxPayBaseResult.fromXML(responseContent, WxPayAuthcode2OpenidResult.class);
         result.checkResult(this);
         return result.getOpenid();
    @@ -451,57 +451,42 @@ public String getSandboxSignKey() throws WxPayException {
         request.checkAndSign(this.getConfig());
     
         String url = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey";
    -    String responseContent = this.post(url, request.toXML());
    +    String responseContent = this.post(url, request.toXML(), false);
         WxPaySandboxSignKeyResult result = WxPayBaseResult.fromXML(responseContent, WxPaySandboxSignKeyResult.class);
         result.checkResult(this);
         return result.getSandboxSignKey();
       }
     
       /**
    -   * 执行post请求
    -   *
    -   * @param url      请求地址
    -   * @param xmlParam 请求字符串
    -   * @return 返回请求结果
    -   */
    -  private String post(String url, String xmlParam) throws WxPayException {
    -    HttpRequest request = HttpRequest
    -      .post(url)
    -      .timeout(this.config.getHttpTimeout())
    -      .connectionTimeout(this.config.getHttpConnectionTimeout())
    -      .body(new String(xmlParam.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
    -    String responseString = this.getResponseString(request.send());
    -
    -    this.log.info("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", url, xmlParam, responseString);
    -    return responseString;
    -  }
    -
    -  /**
    -   * 带证书发送post请求
    +   * 发送post请求
        *
        * @param url        请求地址
        * @param requestStr 请求信息
    +   * @param useKey     是否使用证书
    +   * @return 返回请求结果字符串
        */
    -  private String postWithKey(String url, String requestStr) throws WxPayException {
    +  private String post(String url, String requestStr, boolean useKey) throws WxPayException {
         try {
    -      SSLContext sslContext = this.getConfig().getSslContext();
    -      if (null == sslContext) {
    -        sslContext = this.getConfig().initSSLContext();
    -      }
    -
           HttpRequest request = HttpRequest
             .post(url)
             .timeout(this.config.getHttpTimeout())
             .connectionTimeout(this.config.getHttpConnectionTimeout())
    -        .withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext))
             .bodyText(requestStr);
     
    +      if (useKey) {
    +        SSLContext sslContext = this.getConfig().getSslContext();
    +        if (null == sslContext) {
    +          sslContext = this.getConfig().initSSLContext();
    +        }
    +        request.withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext));
    +      }
    +
           String responseString = this.getResponseString(request.send());
     
    -      this.log.info("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", url, requestStr, responseString);
    +      this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, responseString);
           return responseString;
         } catch (Exception e) {
    -      this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", url, requestStr, e.getMessage());
    +      this.log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage());
           throw new WxPayException(e.getMessage(), e);
         }
       }
    
    From 1cd6618f82b1f734be18274963018eafd73de633 Mon Sep 17 00:00:00 2001
    From: Binary Wang 
    Date: Sat, 8 Jul 2017 16:16:15 +0800
    Subject: [PATCH 144/179] =?UTF-8?q?=E5=8F=91=E5=B8=83=E4=B8=B4=E6=97=B6?=
     =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC2.7.4.BETA?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    ---
     pom.xml                     | 2 +-
     weixin-java-common/pom.xml  | 2 +-
     weixin-java-cp/pom.xml      | 2 +-
     weixin-java-miniapp/pom.xml | 2 +-
     weixin-java-mp/pom.xml      | 2 +-
     weixin-java-pay/pom.xml     | 2 +-
     6 files changed, 6 insertions(+), 6 deletions(-)
    
    diff --git a/pom.xml b/pom.xml
    index 3383cb0fb7..5f1d901d4b 100644
    --- a/pom.xml
    +++ b/pom.xml
    @@ -6,7 +6,7 @@
       4.0.0
       com.github.binarywang
       weixin-java-parent
    -  2.7.3.BETA
    +  2.7.4.BETA
       pom
       WeiXin Java Tools - Parent
       微信公众号、企业号上级POM
    diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml
    index f198bd70d9..3800522ceb 100644
    --- a/weixin-java-common/pom.xml
    +++ b/weixin-java-common/pom.xml
    @@ -7,7 +7,7 @@
       
         com.github.binarywang
         weixin-java-parent
    -    2.7.3.BETA
    +    2.7.4.BETA
       
     
       weixin-java-common
    diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml
    index 0fa4104a2e..1790105d8f 100644
    --- a/weixin-java-cp/pom.xml
    +++ b/weixin-java-cp/pom.xml
    @@ -7,7 +7,7 @@
       
         com.github.binarywang
         weixin-java-parent
    -    2.7.3.BETA
    +    2.7.4.BETA
       
     
       weixin-java-cp
    diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml
    index fc4c3f43c0..60d1194a78 100644
    --- a/weixin-java-miniapp/pom.xml
    +++ b/weixin-java-miniapp/pom.xml
    @@ -7,7 +7,7 @@
       
         com.github.binarywang
         weixin-java-parent
    -    2.7.3.BETA
    +    2.7.4.BETA
       
       weixin-java-miniapp
       WeiXin Java Tools - MiniApp
    diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml
    index 5030f42b1e..d65bceef9f 100644
    --- a/weixin-java-mp/pom.xml
    +++ b/weixin-java-mp/pom.xml
    @@ -7,7 +7,7 @@
       
         com.github.binarywang
         weixin-java-parent
    -    2.7.3.BETA
    +    2.7.4.BETA
       
       weixin-java-mp
       WeiXin Java Tools - MP
    diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
    index 0f9e4c8d8b..7e9780f881 100644
    --- a/weixin-java-pay/pom.xml
    +++ b/weixin-java-pay/pom.xml
    @@ -5,7 +5,7 @@
       
         weixin-java-parent
         com.github.binarywang
    -    2.7.3.BETA
    +    2.7.4.BETA
       
       4.0.0
     
    
    From 166e54c3f589018234dc08d09bd3e59244a86549 Mon Sep 17 00:00:00 2001
    From: Binary Wang 
    Date: Sat, 8 Jul 2017 17:37:33 +0800
    Subject: [PATCH 145/179] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98?=
     =?UTF-8?q?=E6=A8=A1=E5=9D=97=E8=B0=83=E6=95=B4=EF=BC=8C=E8=B7=9F=E5=85=B6?=
     =?UTF-8?q?=E4=BB=96=E6=A8=A1=E5=9D=97=E4=BF=9D=E6=8C=81=E7=BB=9F=E4=B8=80?=
     =?UTF-8?q?,=E9=BB=98=E8=AE=A4=E4=BD=BF=E7=94=A8apache=20httpclient?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    ---
     weixin-java-pay/pom.xml                       |   3 +-
     .../wxpay/bean/result/WxPayBaseResult.java    |   4 +-
     .../impl/WxPayServiceAbstractImpl.java        | 466 ++++++++++++++++
     .../impl/WxPayServiceApacheHttpImpl.java      |  66 +++
     .../wxpay/service/impl/WxPayServiceImpl.java  | 515 +-----------------
     .../impl/WxPayServiceJoddHttpImpl.java        |  68 +++
     6 files changed, 610 insertions(+), 512 deletions(-)
     create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java
     create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
     create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
    
    diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
    index 7e9780f881..7bb79b229d 100644
    --- a/weixin-java-pay/pom.xml
    +++ b/weixin-java-pay/pom.xml
    @@ -23,10 +23,11 @@
           com.github.binarywang
           qrcode-utils
         
    +
         
           org.jodd
           jodd-http
    -      compile
    +      provided
         
     
         
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java
    index 3f07a58199..802e22b312 100644
    --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java
    @@ -1,7 +1,7 @@
     package com.github.binarywang.wxpay.bean.result;
     
     import com.github.binarywang.wxpay.exception.WxPayException;
    -import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
    +import com.github.binarywang.wxpay.service.impl.WxPayServiceAbstractImpl;
     import com.github.binarywang.wxpay.util.SignUtils;
     import com.google.common.base.Joiner;
     import com.google.common.collect.Maps;
    @@ -307,7 +307,7 @@ protected Integer getXmlValueAsInt(String... path) {
       /**
        * 校验返回结果签名
        */
    -  public void checkResult(WxPayServiceImpl wxPayService) throws WxPayException {
    +  public void checkResult(WxPayServiceAbstractImpl wxPayService) throws WxPayException {
         //校验返回结果签名
         Map map = toMap();
         if (getSign() != null && !SignUtils.checkSign(map, wxPayService.getConfig().getMchKey())) {
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java
    new file mode 100644
    index 0000000000..aa9291760c
    --- /dev/null
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java
    @@ -0,0 +1,466 @@
    +package com.github.binarywang.wxpay.service.impl;
    +
    +import com.github.binarywang.utils.qrcode.QrcodeUtils;
    +import com.github.binarywang.wxpay.bean.request.*;
    +import com.github.binarywang.wxpay.bean.result.*;
    +import com.github.binarywang.wxpay.config.WxPayConfig;
    +import com.github.binarywang.wxpay.exception.WxPayException;
    +import com.github.binarywang.wxpay.service.WxPayService;
    +import com.github.binarywang.wxpay.util.SignUtils;
    +import com.google.common.collect.Maps;
    +import org.apache.commons.lang3.StringUtils;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import java.io.File;
    +import java.util.HashMap;
    +import java.util.LinkedList;
    +import java.util.List;
    +import java.util.Map;
    +
    +/**
    + * 
    + *  微信支付接口请求抽象实现类
    + * Created by Binary Wang on 2017-7-8.
    + * 
    + * @author Binary Wang + */ +public abstract class WxPayServiceAbstractImpl implements WxPayService { + private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com"; + protected final Logger log = LoggerFactory.getLogger(this.getClass()); + + protected WxPayConfig config; + + @Override + public WxPayConfig getConfig() { + return this.config; + } + + @Override + public void setConfig(WxPayConfig config) { + this.config = config; + } + + private String getPayBaseUrl() { + if (this.getConfig().useSandbox()) { + return PAY_BASE_URL + "/sandboxnew"; + } + + return PAY_BASE_URL; + } + + /** + * 发送post请求 + * + * @param url 请求地址 + * @param requestStr 请求信息 + * @param useKey 是否使用证书 + * @return 返回请求结果字符串 + */ + protected abstract String post(String url, String requestStr, boolean useKey) throws WxPayException; + + @Override + public WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/secapi/pay/refund"; + String responseContent = this.post(url, request.toXML(), true); + WxPayRefundResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundResult.class); + result.checkResult(this); + return result; + } + + @Override + public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) + throws WxPayException { + WxPayRefundQueryRequest request = new WxPayRefundQueryRequest(); + request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); + request.setTransactionId(StringUtils.trimToNull(transactionId)); + request.setOutRefundNo(StringUtils.trimToNull(outRefundNo)); + request.setRefundId(StringUtils.trimToNull(refundId)); + + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/pay/refundquery"; + String responseContent = this.post(url, request.toXML(), false); + WxPayRefundQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundQueryResult.class); + result.composeRefundRecords(); + result.checkResult(this); + return result; + } + + @Override + public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException { + try { + log.debug("微信支付回调参数详细:{}", xmlData); + WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData); + log.debug("微信支付回调结果对象:{}", result); + result.checkResult(this); + return result; + } catch (WxPayException e) { + log.error(e.getMessage(), e); + throw e; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new WxPayException("发生异常," + e.getMessage(), e); + } + } + + @Override + public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendredpack"; + if (request.getAmtType() != null) { + //裂变红包 + url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendgroupredpack"; + } + + String responseContent = this.post(url, request.toXML(), true); + WxPaySendRedpackResult result = WxPayBaseResult.fromXML(responseContent, WxPaySendRedpackResult.class); + //毋须校验,因为没有返回签名信息 + // this.checkResult(result); + return result; + } + + @Override + public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException { + WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest(); + request.setMchBillNo(mchBillNo); + request.setBillType("MCHT"); + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gethbinfo"; + String responseContent = this.post(url, request.toXML(), true); + WxPayRedpackQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRedpackQueryResult.class); + result.checkResult(this); + return result; + } + + @Override + public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxPayException { + WxPayOrderQueryRequest request = new WxPayOrderQueryRequest(); + request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); + request.setTransactionId(StringUtils.trimToNull(transactionId)); + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/pay/orderquery"; + String responseContent = this.post(url, request.toXML(), false); + if (StringUtils.isBlank(responseContent)) { + throw new WxPayException("无响应结果"); + } + + WxPayOrderQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderQueryResult.class); + result.composeCoupons(); + result.checkResult(this); + return result; + } + + @Override + public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException { + if (StringUtils.isBlank(outTradeNo)) { + throw new IllegalArgumentException("out_trade_no不能为空"); + } + + WxPayOrderCloseRequest request = new WxPayOrderCloseRequest(); + request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/pay/closeorder"; + String responseContent = this.post(url, request.toXML(), false); + WxPayOrderCloseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderCloseResult.class); + result.checkResult(this); + + return result; + } + + @Override + public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/pay/unifiedorder"; + String responseContent = this.post(url, request.toXML(), false); + WxPayUnifiedOrderResult result = WxPayBaseResult.fromXML(responseContent, WxPayUnifiedOrderResult.class); + result.checkResult(this); + return result; + } + + @Override + public Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxPayException { + WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request); + String prepayId = unifiedOrderResult.getPrepayId(); + if (StringUtils.isBlank(prepayId)) { + throw new RuntimeException(String.format("无法获取prepay id,错误代码: '%s',信息:%s。", + unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes())); + } + + Map payInfo = new HashMap<>(); + if ("NATIVE".equals(request.getTradeType())) { + payInfo.put("codeUrl", unifiedOrderResult.getCodeURL()); + } else if ("APP".equals(request.getTradeType())) { + // APP支付绑定的是微信开放平台上的账号,APPID为开放平台上绑定APP后发放的参数 + String appId = getConfig().getAppId(); + Map configMap = new HashMap<>(); + // 此map用于参与调起sdk支付的二次签名,格式全小写,timestamp只能是10位,格式固定,切勿修改 + String partnerid = getConfig().getMchId(); + configMap.put("prepayid", prepayId); + configMap.put("partnerid", partnerid); + configMap.put("package", "Sign=WXPay"); + configMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); + configMap.put("noncestr", String.valueOf(System.currentTimeMillis())); + configMap.put("appid", appId); + // 此map用于客户端与微信服务器交互 + payInfo.put("sign", SignUtils.createSign(configMap, this.getConfig().getMchKey())); + payInfo.put("prepayId", prepayId); + payInfo.put("partnerId", partnerid); + payInfo.put("appId", appId); + payInfo.put("packageValue", "Sign=WXPay"); + payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); + payInfo.put("nonceStr", String.valueOf(System.currentTimeMillis())); + } else if ("JSAPI".equals(request.getTradeType())) { + payInfo.put("appId", unifiedOrderResult.getAppid()); + // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 + payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); + payInfo.put("nonceStr", String.valueOf(System.currentTimeMillis())); + payInfo.put("package", "prepay_id=" + prepayId); + payInfo.put("signType", "MD5"); + payInfo.put("paySign", SignUtils.createSign(payInfo, this.getConfig().getMchKey())); + } + return payInfo; + } + + @Override + public WxEntPayResult entPay(WxEntPayRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + String url = this.getPayBaseUrl() + "/mmpaymkttransfers/promotion/transfers"; + + String responseContent = this.post(url, request.toXML(), true); + WxEntPayResult result = WxPayBaseResult.fromXML(responseContent, WxEntPayResult.class); + result.checkResult(this); + return result; + } + + @Override + public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException { + WxEntPayQueryRequest request = new WxEntPayQueryRequest(); + request.setPartnerTradeNo(partnerTradeNo); + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gettransferinfo"; + String responseContent = this.post(url, request.toXML(), true); + WxEntPayQueryResult result = WxPayBaseResult.fromXML(responseContent, WxEntPayQueryResult.class); + result.checkResult(this); + return result; + } + + @Override + public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) { + String content = this.createScanPayQrcodeMode1(productId); + return this.createQrcode(content, logoFile, sideLength); + } + + @Override + public String createScanPayQrcodeMode1(String productId) { + //weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX + StringBuilder codeUrl = new StringBuilder("weixin://wxpay/bizpayurl?"); + Map params = Maps.newHashMap(); + params.put("appid", this.getConfig().getAppId()); + params.put("mch_id", this.getConfig().getMchId()); + params.put("product_id", productId); + params.put("time_stamp", String.valueOf(System.currentTimeMillis() / 1000));//这里需要秒,10位数字 + params.put("nonce_str", String.valueOf(System.currentTimeMillis())); + + String sign = SignUtils.createSign(params, this.getConfig().getMchKey()); + params.put("sign", sign); + + + for (String key : params.keySet()) { + codeUrl.append(key + "=" + params.get(key) + "&"); + } + + String content = codeUrl.toString().substring(0, codeUrl.length() - 1); + log.debug("扫码支付模式一生成二维码的URL:{}", content); + return content; + } + + @Override + public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) { + return this.createQrcode(codeUrl, logoFile, sideLength); + } + + private byte[] createQrcode(String content, File logoFile, Integer sideLength) { + if (sideLength == null || sideLength < 1) { + return QrcodeUtils.createQrcode(content, logoFile); + } + + return QrcodeUtils.createQrcode(content, sideLength, logoFile); + } + + public void report(WxPayReportRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/payitil/report"; + String responseContent = this.post(url, request.toXML(), false); + WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); + result.checkResult(this); + } + + @Override + public WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException { + WxPayDownloadBillRequest request = new WxPayDownloadBillRequest(); + request.setBillType(billType); + request.setBillDate(billDate); + request.setTarType(tarType); + request.setDeviceInfo(deviceInfo); + + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/pay/downloadbill"; + String responseContent = this.post(url, request.toXML(), false); + if (responseContent.startsWith("<")) { + WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); + result.checkResult(this); + return null; + } else { + WxPayBillResult wxPayBillResult = billInformationDeal(responseContent); + return wxPayBillResult; + } + } + + private WxPayBillResult billInformationDeal(String responseContent) { + WxPayBillResult wxPayBillResult = new WxPayBillResult(); + + String listStr = ""; + String objStr = ""; + if (responseContent.contains("总交易单数")) { + listStr = responseContent.substring(0, responseContent.indexOf("总交易单数")); + objStr = responseContent.substring(responseContent.indexOf("总交易单数")); + } + + /* + * 交易时间:2017-04-06 01:00:02 公众账号ID: 商户号: 子商户号:0 设备号:WEB 微信订单号: 商户订单号:2017040519091071873216 用户标识: 交易类型:NATIVE + * 交易状态:REFUND 付款银行:CFT 货币种类:CNY 总金额:0.00 企业红包金额:0.00 微信退款单号: 商户退款单号:20170406010000933 退款金额:0.01 企业红包退款金额:0.00 + * 退款类型:ORIGINAL 退款状态:SUCCESS 商品名称: 商户数据包: 手续费:0.00000 费率 :0.60% + */ + + // 参考以上格式进行取值 + + List wxPayBillBaseResultLst = new LinkedList<>(); + String newStr = listStr.replaceAll(",", " "); // 去空格 + String[] tempStr = newStr.split("`"); // 数据分组 + String[] t = tempStr[0].split(" ");// 分组标题 + int j = tempStr.length / t.length; // 计算循环次数 + int k = 1; // 纪录数组下标 + for (int i = 0; i < j; i++) { + WxPayBillBaseResult wxPayBillBaseResult = new WxPayBillBaseResult(); + + wxPayBillBaseResult.setTradeTime(tempStr[k]); + wxPayBillBaseResult.setAppId(tempStr[k + 1]); + wxPayBillBaseResult.setMchId(tempStr[k + 2]); + wxPayBillBaseResult.setSubMchId(tempStr[k + 3]); + wxPayBillBaseResult.setDeviceInfo(tempStr[k + 4]); + wxPayBillBaseResult.setTransationId(tempStr[k + 5]); + wxPayBillBaseResult.setOutTradeNo(tempStr[k + 6]); + wxPayBillBaseResult.setOpenId(tempStr[k + 7]); + wxPayBillBaseResult.setTradeType(tempStr[k + 8]); + wxPayBillBaseResult.setTradeState(tempStr[k + 9]); + wxPayBillBaseResult.setBankType(tempStr[k + 10]); + wxPayBillBaseResult.setFeeType(tempStr[k + 11]); + wxPayBillBaseResult.setTotalFee(tempStr[k + 12]); + wxPayBillBaseResult.setCouponFee(tempStr[k + 13]); + wxPayBillBaseResult.setRefundId(tempStr[k + 14]); + wxPayBillBaseResult.setOutRefundNo(tempStr[k + 15]); + wxPayBillBaseResult.setSettlementRefundFee(tempStr[k + 16]); + wxPayBillBaseResult.setCouponRefundFee(tempStr[k + 17]); + wxPayBillBaseResult.setRefundChannel(tempStr[k + 18]); + wxPayBillBaseResult.setRefundState(tempStr[k + 19]); + wxPayBillBaseResult.setBody(tempStr[k + 20]); + wxPayBillBaseResult.setAttach(tempStr[k + 21]); + wxPayBillBaseResult.setPoundage(tempStr[k + 22]); + wxPayBillBaseResult.setPoundageRate(tempStr[k + 23]); + wxPayBillBaseResultLst.add(wxPayBillBaseResult); + k += t.length; + } + /* + * 总交易单数,总交易额,总退款金额,总代金券或立减优惠退款金额,手续费总金额 `2,`0.02,`0.0,`0.0,`0 + */ + + // 参考以上格式进行取值 + + String totalStr = objStr.replaceAll(",", " "); + String[] totalTempStr = totalStr.split("`"); + wxPayBillResult.setTotalRecord(totalTempStr[1]); + wxPayBillResult.setTotalFee(totalTempStr[2]); + wxPayBillResult.setTotalRefundFee(totalTempStr[3]); + wxPayBillResult.setTotalCouponFee(totalTempStr[4]); + wxPayBillResult.setTotalPoundageFee(totalTempStr[5]); + + return wxPayBillResult; + } + + @Override + public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/pay/micropay"; + String responseContent = this.post(url, request.toXML(), false); + WxPayMicropayResult result = WxPayBaseResult.fromXML(responseContent, WxPayMicropayResult.class); + result.checkResult(this); + return result; + } + + @Override + public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/secapi/pay/reverse"; + String responseContent = this.post(url, request.toXML(), true); + WxPayOrderReverseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderReverseResult.class); + result.checkResult(this); + return result; + } + + @Override + public String shorturl(WxPayShorturlRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/tools/shorturl"; + String responseContent = this.post(url, request.toXML(), false); + WxPayShorturlResult result = WxPayBaseResult.fromXML(responseContent, WxPayShorturlResult.class); + result.checkResult(this); + return result.getShortUrl(); + } + + @Override + public String shorturl(String longUrl) throws WxPayException { + return this.shorturl(new WxPayShorturlRequest(longUrl)); + } + + @Override + public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/tools/authcodetoopenid"; + String responseContent = this.post(url, request.toXML(), false); + WxPayAuthcode2OpenidResult result = WxPayBaseResult.fromXML(responseContent, WxPayAuthcode2OpenidResult.class); + result.checkResult(this); + return result.getOpenid(); + } + + @Override + public String authcode2Openid(String authCode) throws WxPayException { + return this.authcode2Openid(new WxPayAuthcode2OpenidRequest(authCode)); + } + + @Override + public String getSandboxSignKey() throws WxPayException { + WxPayDefaultRequest request = new WxPayDefaultRequest(); + request.checkAndSign(this.getConfig()); + + String url = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey"; + String responseContent = this.post(url, request.toXML(), false); + WxPaySandboxSignKeyResult result = WxPayBaseResult.fromXML(responseContent, WxPaySandboxSignKeyResult.class); + result.checkResult(this); + return result.getSandboxSignKey(); + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java new file mode 100644 index 0000000000..c5da982c13 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java @@ -0,0 +1,66 @@ +package com.github.binarywang.wxpay.service.impl; + +import com.github.binarywang.wxpay.exception.WxPayException; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.ssl.DefaultHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import javax.net.ssl.SSLContext; +import java.nio.charset.StandardCharsets; + +/** + *
    + * 微信支付请求实现类,apache httpclient实现
    + * Created by Binary Wang on 2016/7/28.
    + * 
    + * + * @author binarywang (https://github.com/binarywang) + */ +public class WxPayServiceApacheHttpImpl extends WxPayServiceAbstractImpl { + + @Override + protected String post(String url, String requestStr, boolean useKey) throws WxPayException { + try { + HttpClientBuilder httpClientBuilder = HttpClients.custom(); + if (useKey) { + SSLContext sslContext = this.getConfig().getSslContext(); + if (null == sslContext) { + sslContext = this.getConfig().initSSLContext(); + } + + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, + new String[]{"TLSv1"}, null, new DefaultHostnameVerifier()); + httpClientBuilder.setSSLSocketFactory(sslsf); + } + + HttpPost httpPost = new HttpPost(url); + httpPost.setConfig(RequestConfig.custom() + .setConnectionRequestTimeout(this.getConfig().getHttpConnectionTimeout()) + .setConnectTimeout(this.getConfig().getHttpConnectionTimeout()) + .setSocketTimeout(this.getConfig().getHttpTimeout()) + .build()); + + try (CloseableHttpClient httpclient = httpClientBuilder.build()) { + httpPost.setEntity(new StringEntity(new String(requestStr.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1))); + try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + String result = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, result); + return result; + } + } finally { + httpPost.releaseConnection(); + } + } catch (Exception e) { + this.log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage()); + throw new WxPayException(e.getMessage(), e); + } + } + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java index f799a2c974..8e795966f4 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java @@ -1,515 +1,12 @@ package com.github.binarywang.wxpay.service.impl; -import com.github.binarywang.utils.qrcode.QrcodeUtils; -import com.github.binarywang.wxpay.bean.request.*; -import com.github.binarywang.wxpay.bean.result.*; -import com.github.binarywang.wxpay.config.WxPayConfig; -import com.github.binarywang.wxpay.exception.WxPayException; -import com.github.binarywang.wxpay.service.WxPayService; -import com.github.binarywang.wxpay.util.SignUtils; -import com.google.common.collect.Maps; -import jodd.http.HttpRequest; -import jodd.http.HttpResponse; -import jodd.http.net.SSLSocketHttpConnectionProvider; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.net.ssl.SSLContext; -import java.io.File; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - /** - * Created by Binary Wang on 2016/7/28. + *
    + * 微信支付接口请求实现类,默认使用Apache HttpClient实现
    + * Created by Binary Wang on 2017-7-8.
    + * 
    * - * @author binarywang (https://github.com/binarywang) + * @author Binary Wang */ -public class WxPayServiceImpl implements WxPayService { - private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com"; - private final Logger log = LoggerFactory.getLogger(this.getClass()); - - private WxPayConfig config; - - @Override - public WxPayConfig getConfig() { - return this.config; - } - - @Override - public void setConfig(WxPayConfig config) { - this.config = config; - } - - private String getPayBaseUrl() { - if (this.getConfig().useSandbox()) { - return PAY_BASE_URL + "/sandboxnew"; - } - - return PAY_BASE_URL; - } - - @Override - public WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayException { - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/secapi/pay/refund"; - String responseContent = this.post(url, request.toXML(), true); - WxPayRefundResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundResult.class); - result.checkResult(this); - return result; - } - - @Override - public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) - throws WxPayException { - WxPayRefundQueryRequest request = new WxPayRefundQueryRequest(); - request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); - request.setTransactionId(StringUtils.trimToNull(transactionId)); - request.setOutRefundNo(StringUtils.trimToNull(outRefundNo)); - request.setRefundId(StringUtils.trimToNull(refundId)); - - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/pay/refundquery"; - String responseContent = this.post(url, request.toXML(), false); - WxPayRefundQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundQueryResult.class); - result.composeRefundRecords(); - result.checkResult(this); - return result; - } - - @Override - public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException { - try { - log.debug("微信支付回调参数详细:{}", xmlData); - WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData); - log.debug("微信支付回调结果对象:{}", result); - result.checkResult(this); - return result; - } catch (WxPayException e) { - log.error(e.getMessage(), e); - throw e; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new WxPayException("发生异常," + e.getMessage(), e); - } - } - - @Override - public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException { - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendredpack"; - if (request.getAmtType() != null) { - //裂变红包 - url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendgroupredpack"; - } - - String responseContent = this.post(url, request.toXML(), true); - WxPaySendRedpackResult result = WxPayBaseResult.fromXML(responseContent, WxPaySendRedpackResult.class); - //毋须校验,因为没有返回签名信息 - // this.checkResult(result); - return result; - } - - @Override - public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException { - WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest(); - request.setMchBillNo(mchBillNo); - request.setBillType("MCHT"); - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gethbinfo"; - String responseContent = this.post(url, request.toXML(), true); - WxPayRedpackQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRedpackQueryResult.class); - result.checkResult(this); - return result; - } - - @Override - public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxPayException { - WxPayOrderQueryRequest request = new WxPayOrderQueryRequest(); - request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); - request.setTransactionId(StringUtils.trimToNull(transactionId)); - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/pay/orderquery"; - String responseContent = this.post(url, request.toXML(), false); - if (StringUtils.isBlank(responseContent)) { - throw new WxPayException("无响应结果"); - } - - WxPayOrderQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderQueryResult.class); - result.composeCoupons(); - result.checkResult(this); - return result; - } - - @Override - public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException { - if (StringUtils.isBlank(outTradeNo)) { - throw new IllegalArgumentException("out_trade_no不能为空"); - } - - WxPayOrderCloseRequest request = new WxPayOrderCloseRequest(); - request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/pay/closeorder"; - String responseContent = this.post(url, request.toXML(), false); - WxPayOrderCloseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderCloseResult.class); - result.checkResult(this); - - return result; - } - - @Override - public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException { - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/pay/unifiedorder"; - String responseContent = this.post(url, request.toXML(), false); - WxPayUnifiedOrderResult result = WxPayBaseResult.fromXML(responseContent, WxPayUnifiedOrderResult.class); - result.checkResult(this); - return result; - } - - @Override - public Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxPayException { - WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request); - String prepayId = unifiedOrderResult.getPrepayId(); - if (StringUtils.isBlank(prepayId)) { - throw new RuntimeException(String.format("无法获取prepay id,错误代码: '%s',信息:%s。", - unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes())); - } - - Map payInfo = new HashMap<>(); - if ("NATIVE".equals(request.getTradeType())) { - payInfo.put("codeUrl", unifiedOrderResult.getCodeURL()); - } else if ("APP".equals(request.getTradeType())) { - // APP支付绑定的是微信开放平台上的账号,APPID为开放平台上绑定APP后发放的参数 - String appId = getConfig().getAppId(); - Map configMap = new HashMap<>(); - // 此map用于参与调起sdk支付的二次签名,格式全小写,timestamp只能是10位,格式固定,切勿修改 - String partnerid = getConfig().getMchId(); - configMap.put("prepayid", prepayId); - configMap.put("partnerid", partnerid); - configMap.put("package", "Sign=WXPay"); - configMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); - configMap.put("noncestr", String.valueOf(System.currentTimeMillis())); - configMap.put("appid", appId); - // 此map用于客户端与微信服务器交互 - payInfo.put("sign", SignUtils.createSign(configMap, this.getConfig().getMchKey())); - payInfo.put("prepayId", prepayId); - payInfo.put("partnerId", partnerid); - payInfo.put("appId", appId); - payInfo.put("packageValue", "Sign=WXPay"); - payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); - payInfo.put("nonceStr", String.valueOf(System.currentTimeMillis())); - } else if ("JSAPI".equals(request.getTradeType())) { - payInfo.put("appId", unifiedOrderResult.getAppid()); - // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 - payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); - payInfo.put("nonceStr", String.valueOf(System.currentTimeMillis())); - payInfo.put("package", "prepay_id=" + prepayId); - payInfo.put("signType", "MD5"); - payInfo.put("paySign", SignUtils.createSign(payInfo, this.getConfig().getMchKey())); - } - return payInfo; - } - - @Override - public WxEntPayResult entPay(WxEntPayRequest request) throws WxPayException { - request.checkAndSign(this.getConfig()); - String url = this.getPayBaseUrl() + "/mmpaymkttransfers/promotion/transfers"; - - String responseContent = this.post(url, request.toXML(), true); - WxEntPayResult result = WxPayBaseResult.fromXML(responseContent, WxEntPayResult.class); - result.checkResult(this); - return result; - } - - @Override - public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException { - WxEntPayQueryRequest request = new WxEntPayQueryRequest(); - request.setPartnerTradeNo(partnerTradeNo); - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gettransferinfo"; - String responseContent = this.post(url, request.toXML(), true); - WxEntPayQueryResult result = WxPayBaseResult.fromXML(responseContent, WxEntPayQueryResult.class); - result.checkResult(this); - return result; - } - - @Override - public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) { - String content = this.createScanPayQrcodeMode1(productId); - return this.createQrcode(content, logoFile, sideLength); - } - - @Override - public String createScanPayQrcodeMode1(String productId) { - //weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX - StringBuilder codeUrl = new StringBuilder("weixin://wxpay/bizpayurl?"); - Map params = Maps.newHashMap(); - params.put("appid", this.getConfig().getAppId()); - params.put("mch_id", this.getConfig().getMchId()); - params.put("product_id", productId); - params.put("time_stamp", String.valueOf(System.currentTimeMillis() / 1000));//这里需要秒,10位数字 - params.put("nonce_str", String.valueOf(System.currentTimeMillis())); - - String sign = SignUtils.createSign(params, this.getConfig().getMchKey()); - params.put("sign", sign); - - - for (String key : params.keySet()) { - codeUrl.append(key + "=" + params.get(key) + "&"); - } - - String content = codeUrl.toString().substring(0, codeUrl.length() - 1); - log.debug("扫码支付模式一生成二维码的URL:{}", content); - return content; - } - - @Override - public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) { - return this.createQrcode(codeUrl, logoFile, sideLength); - } - - private byte[] createQrcode(String content, File logoFile, Integer sideLength) { - if (sideLength == null || sideLength < 1) { - return QrcodeUtils.createQrcode(content, logoFile); - } - - return QrcodeUtils.createQrcode(content, sideLength, logoFile); - } - - public void report(WxPayReportRequest request) throws WxPayException { - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/payitil/report"; - String responseContent = this.post(url, request.toXML(), false); - WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); - result.checkResult(this); - } - - @Override - public WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException { - WxPayDownloadBillRequest request = new WxPayDownloadBillRequest(); - request.setBillType(billType); - request.setBillDate(billDate); - request.setTarType(tarType); - request.setDeviceInfo(deviceInfo); - - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/pay/downloadbill"; - String responseContent = this.post(url, request.toXML(), false); - if (responseContent.startsWith("<")) { - WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); - result.checkResult(this); - return null; - } else { - WxPayBillResult wxPayBillResult = billInformationDeal(responseContent); - return wxPayBillResult; - } - } - - private WxPayBillResult billInformationDeal(String responseContent) { - WxPayBillResult wxPayBillResult = new WxPayBillResult(); - - String listStr = ""; - String objStr = ""; - if (responseContent.contains("总交易单数")) { - listStr = responseContent.substring(0, responseContent.indexOf("总交易单数")); - objStr = responseContent.substring(responseContent.indexOf("总交易单数")); - } - - /* - * 交易时间:2017-04-06 01:00:02 公众账号ID: 商户号: 子商户号:0 设备号:WEB 微信订单号: 商户订单号:2017040519091071873216 用户标识: 交易类型:NATIVE - * 交易状态:REFUND 付款银行:CFT 货币种类:CNY 总金额:0.00 企业红包金额:0.00 微信退款单号: 商户退款单号:20170406010000933 退款金额:0.01 企业红包退款金额:0.00 - * 退款类型:ORIGINAL 退款状态:SUCCESS 商品名称: 商户数据包: 手续费:0.00000 费率 :0.60% - */ - - // 参考以上格式进行取值 - - List wxPayBillBaseResultLst = new LinkedList<>(); - String newStr = listStr.replaceAll(",", " "); // 去空格 - String[] tempStr = newStr.split("`"); // 数据分组 - String[] t = tempStr[0].split(" ");// 分组标题 - int j = tempStr.length / t.length; // 计算循环次数 - int k = 1; // 纪录数组下标 - for (int i = 0; i < j; i++) { - WxPayBillBaseResult wxPayBillBaseResult = new WxPayBillBaseResult(); - - wxPayBillBaseResult.setTradeTime(tempStr[k]); - wxPayBillBaseResult.setAppId(tempStr[k + 1]); - wxPayBillBaseResult.setMchId(tempStr[k + 2]); - wxPayBillBaseResult.setSubMchId(tempStr[k + 3]); - wxPayBillBaseResult.setDeviceInfo(tempStr[k + 4]); - wxPayBillBaseResult.setTransationId(tempStr[k + 5]); - wxPayBillBaseResult.setOutTradeNo(tempStr[k + 6]); - wxPayBillBaseResult.setOpenId(tempStr[k + 7]); - wxPayBillBaseResult.setTradeType(tempStr[k + 8]); - wxPayBillBaseResult.setTradeState(tempStr[k + 9]); - wxPayBillBaseResult.setBankType(tempStr[k + 10]); - wxPayBillBaseResult.setFeeType(tempStr[k + 11]); - wxPayBillBaseResult.setTotalFee(tempStr[k + 12]); - wxPayBillBaseResult.setCouponFee(tempStr[k + 13]); - wxPayBillBaseResult.setRefundId(tempStr[k + 14]); - wxPayBillBaseResult.setOutRefundNo(tempStr[k + 15]); - wxPayBillBaseResult.setSettlementRefundFee(tempStr[k + 16]); - wxPayBillBaseResult.setCouponRefundFee(tempStr[k + 17]); - wxPayBillBaseResult.setRefundChannel(tempStr[k + 18]); - wxPayBillBaseResult.setRefundState(tempStr[k + 19]); - wxPayBillBaseResult.setBody(tempStr[k + 20]); - wxPayBillBaseResult.setAttach(tempStr[k + 21]); - wxPayBillBaseResult.setPoundage(tempStr[k + 22]); - wxPayBillBaseResult.setPoundageRate(tempStr[k + 23]); - wxPayBillBaseResultLst.add(wxPayBillBaseResult); - k += t.length; - } - /* - * 总交易单数,总交易额,总退款金额,总代金券或立减优惠退款金额,手续费总金额 `2,`0.02,`0.0,`0.0,`0 - */ - - // 参考以上格式进行取值 - - String totalStr = objStr.replaceAll(",", " "); - String[] totalTempStr = totalStr.split("`"); - wxPayBillResult.setTotalRecord(totalTempStr[1]); - wxPayBillResult.setTotalFee(totalTempStr[2]); - wxPayBillResult.setTotalRefundFee(totalTempStr[3]); - wxPayBillResult.setTotalCouponFee(totalTempStr[4]); - wxPayBillResult.setTotalPoundageFee(totalTempStr[5]); - - return wxPayBillResult; - } - - @Override - public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException { - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/pay/micropay"; - String responseContent = this.post(url, request.toXML(), false); - WxPayMicropayResult result = WxPayBaseResult.fromXML(responseContent, WxPayMicropayResult.class); - result.checkResult(this); - return result; - } - - @Override - public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxPayException { - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/secapi/pay/reverse"; - String responseContent = this.post(url, request.toXML(), true); - WxPayOrderReverseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderReverseResult.class); - result.checkResult(this); - return result; - } - - @Override - public String shorturl(WxPayShorturlRequest request) throws WxPayException { - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/tools/shorturl"; - String responseContent = this.post(url, request.toXML(), false); - WxPayShorturlResult result = WxPayBaseResult.fromXML(responseContent, WxPayShorturlResult.class); - result.checkResult(this); - return result.getShortUrl(); - } - - @Override - public String shorturl(String longUrl) throws WxPayException { - return this.shorturl(new WxPayShorturlRequest(longUrl)); - } - - @Override - public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayException { - request.checkAndSign(this.getConfig()); - - String url = this.getPayBaseUrl() + "/tools/authcodetoopenid"; - String responseContent = this.post(url, request.toXML(), false); - WxPayAuthcode2OpenidResult result = WxPayBaseResult.fromXML(responseContent, WxPayAuthcode2OpenidResult.class); - result.checkResult(this); - return result.getOpenid(); - } - - @Override - public String authcode2Openid(String authCode) throws WxPayException { - return this.authcode2Openid(new WxPayAuthcode2OpenidRequest(authCode)); - } - - @Override - public String getSandboxSignKey() throws WxPayException { - WxPayDefaultRequest request = new WxPayDefaultRequest(); - request.checkAndSign(this.getConfig()); - - String url = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey"; - String responseContent = this.post(url, request.toXML(), false); - WxPaySandboxSignKeyResult result = WxPayBaseResult.fromXML(responseContent, WxPaySandboxSignKeyResult.class); - result.checkResult(this); - return result.getSandboxSignKey(); - } - - /** - * 发送post请求 - * - * @param url 请求地址 - * @param requestStr 请求信息 - * @param useKey 是否使用证书 - * @return 返回请求结果字符串 - */ - private String post(String url, String requestStr, boolean useKey) throws WxPayException { - try { - HttpRequest request = HttpRequest - .post(url) - .timeout(this.config.getHttpTimeout()) - .connectionTimeout(this.config.getHttpConnectionTimeout()) - .bodyText(requestStr); - - if (useKey) { - SSLContext sslContext = this.getConfig().getSslContext(); - if (null == sslContext) { - sslContext = this.getConfig().initSSLContext(); - } - request.withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext)); - } - - String responseString = this.getResponseString(request.send()); - - this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, responseString); - return responseString; - } catch (Exception e) { - this.log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage()); - throw new WxPayException(e.getMessage(), e); - } - } - - private String getResponseString(HttpResponse response) throws WxPayException { - try { - this.log.debug("【微信服务器响应头信息】:\n{}", response.toString(false)); - } catch (NullPointerException e) { - throw new WxPayException("response.toString() 居然抛出空指针异常了", e); - } - - String responseString = response.bodyText(); - - if (StringUtils.isBlank(responseString)) { - throw new WxPayException("响应信息为空"); - } - - if (StringUtils.isBlank(response.charset())) { - responseString = new String(responseString.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); - } - - return responseString; - } - - +public class WxPayServiceImpl extends WxPayServiceApacheHttpImpl { } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java new file mode 100644 index 0000000000..29008e26bd --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java @@ -0,0 +1,68 @@ +package com.github.binarywang.wxpay.service.impl; + +import com.github.binarywang.wxpay.exception.WxPayException; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.net.SSLSocketHttpConnectionProvider; +import org.apache.commons.lang3.StringUtils; + +import javax.net.ssl.SSLContext; +import java.nio.charset.StandardCharsets; + +/** + * 微信支付请求实现类,jodd-http实现 + * Created by Binary Wang on 2016/7/28. + * + * @author binarywang (https://github.com/binarywang) + */ +public class WxPayServiceJoddHttpImpl extends WxPayServiceAbstractImpl { + + @Override + protected String post(String url, String requestStr, boolean useKey) throws WxPayException { + try { + HttpRequest request = HttpRequest + .post(url) + .timeout(this.config.getHttpTimeout()) + .connectionTimeout(this.config.getHttpConnectionTimeout()) + .bodyText(requestStr); + + if (useKey) { + SSLContext sslContext = this.getConfig().getSslContext(); + if (null == sslContext) { + sslContext = this.getConfig().initSSLContext(); + } + request.withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext)); + } + + String responseString = this.getResponseString(request.send()); + + this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, responseString); + return responseString; + } catch (Exception e) { + this.log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage()); + throw new WxPayException(e.getMessage(), e); + } + } + + private String getResponseString(HttpResponse response) throws WxPayException { + try { + this.log.debug("【微信服务器响应头信息】:\n{}", response.toString(false)); + } catch (NullPointerException e) { + throw new WxPayException("response.toString() 居然抛出空指针异常了", e); + } + + String responseString = response.bodyText(); + + if (StringUtils.isBlank(responseString)) { + throw new WxPayException("响应信息为空"); + } + + if (StringUtils.isBlank(response.charset())) { + responseString = new String(responseString.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); + } + + return responseString; + } + + +} From 57f3755a843eda7ece90e75f05611cdc74709b14 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 8 Jul 2017 19:22:26 +0800 Subject: [PATCH 146/179] =?UTF-8?q?#68=20=E5=AE=9E=E7=8E=B0=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=85=AC=E4=BC=97=E5=8F=B7=E7=9A=84=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=9B=9E=E5=A4=8D=E8=A7=84=E5=88=99=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/json/WxBooleanTypeAdapter.java | 47 +++ .../common/util/json/WxDateTypeAdapter.java | 43 +++ .../me/chanjar/weixin/mp/api/WxMpService.java | 30 +- .../mp/api/impl/AbstractWxMpServiceImpl.java | 5 + .../bean/result/WxMpCurrentAutoReplyInfo.java | 359 ++++++++++++++++++ .../mp/api/impl/WxMpServiceImplTest.java | 12 + .../result/WxMpCurrentAutoReplyInfoTest.java | 157 ++++++++ 7 files changed, 647 insertions(+), 6 deletions(-) create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxBooleanTypeAdapter.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapter.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfoTest.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxBooleanTypeAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxBooleanTypeAdapter.java new file mode 100644 index 0000000000..3fbbef4a43 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxBooleanTypeAdapter.java @@ -0,0 +1,47 @@ +package me.chanjar.weixin.common.util.json; + +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import org.apache.commons.lang3.BooleanUtils; + +import java.io.IOException; + +/** + *
    + * Gson 布尔类型类型转换器
    + * Created by Binary Wang on 2017-7-8.
    + * 
    + * + * @author Binary Wang + */ +public class WxBooleanTypeAdapter extends TypeAdapter { + @Override + public void write(JsonWriter out, Boolean value) throws IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(value); + } + } + + @Override + public Boolean read(JsonReader in) throws IOException { + JsonToken peek = in.peek(); + switch (peek) { + case BOOLEAN: + return in.nextBoolean(); + case NULL: + in.nextNull(); + return null; + case NUMBER: + return BooleanUtils.toBoolean(in.nextInt()); + case STRING: + return BooleanUtils.toBoolean(in.nextString()); + default: + throw new JsonParseException("Expected BOOLEAN or NUMBER but was " + peek); + } + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapter.java new file mode 100644 index 0000000000..fd54cf3f43 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxDateTypeAdapter.java @@ -0,0 +1,43 @@ +package me.chanjar.weixin.common.util.json; + +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.util.Date; + +/** + *
    + * Gson 日期类型转换器
    + * Created by Binary Wang on 2017-7-8.
    + * 
    + * + * @author Binary Wang + */ +public class WxDateTypeAdapter extends TypeAdapter { + @Override + public void write(JsonWriter out, Date value) throws IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(value.getTime() / 1000); + } + } + + @Override + public Date read(JsonReader in) throws IOException { + JsonToken peek = in.peek(); + switch (peek) { + case NULL: + in.nextNull(); + return null; + case NUMBER: + return new Date(in.nextInt() * 1000); + default: + throw new JsonParseException("Expected NUMBER but was " + peek); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index 7199d4e05c..0cff2c1cfd 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -77,6 +77,11 @@ public interface WxMpService { */ String CONNECT_OAUTH2_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"; + /** + * 获取公众号的自动回复规则 + */ + String GET_CURRENT_AUTOREPLY_INFO_URL = "https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info"; + /** *
        * 验证消息的确来自微信服务器
    @@ -273,6 +278,24 @@ public interface WxMpService {
        */
       String[] getCallbackIP() throws WxErrorException;
     
    +  /**
    +   * 
    +   * 获取公众号的自动回复规则
    +   * http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751299&token=&lang=zh_CN
    +   * 开发者可以通过该接口,获取公众号当前使用的自动回复规则,包括关注后自动回复、消息自动回复(60分钟内触发一次)、关键词自动回复。
    +   * 请注意:
    +   * 1、第三方平台开发者可以通过本接口,在旗下公众号将业务授权给你后,立即通过本接口检测公众号的自动回复配置,并通过接口再次给公众号设置好自动回复规则,以提升公众号运营者的业务体验。
    +   * 2、本接口仅能获取公众号在公众平台官网的自动回复功能中设置的自动回复规则,若公众号自行开发实现自动回复,或通过第三方平台开发者来实现,则无法获取。
    +   * 3、认证/未认证的服务号/订阅号,以及接口测试号,均拥有该接口权限。
    +   * 4、从第三方平台的公众号登录授权机制上来说,该接口从属于消息与菜单权限集。
    +   * 5、本接口中返回的图片/语音/视频为临时素材(临时素材每次获取都不同,3天内有效,通过素材管理-获取临时素材接口来获取这些素材),本接口返回的图文消息为永久素材素材(通过素材管理-获取永久素材接口来获取这些素材)。
    +   * 接口调用请求说明
    +   * http请求方式: GET(请使用https协议)
    +   * https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info?access_token=ACCESS_TOKEN
    +   * 
    + */ + WxMpCurrentAutoReplyInfo getCurrentAutoReplyInfo() throws WxErrorException; + /** * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 */ @@ -292,15 +315,10 @@ public interface WxMpService { */ T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; - /** - * 获取代理对象 - */ - //HttpHost getRequestHttpProxy(); - /** *
        * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试
    -   * 默认:1000ms
    +   * @param retrySleepMillis 默认:1000ms
        * 
    */ void setRetrySleepMillis(int retrySleepMillis); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java index d3075aa11d..ed93d4936f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java @@ -231,6 +231,11 @@ public String[] getCallbackIP() throws WxErrorException { return ipArray; } + @Override + public WxMpCurrentAutoReplyInfo getCurrentAutoReplyInfo() throws WxErrorException { + return WxMpCurrentAutoReplyInfo.fromJson(this.get(GET_CURRENT_AUTOREPLY_INFO_URL, null)); + } + @Override public String get(String url, String queryParam) throws WxErrorException { return execute(SimpleGetRequestExecutor.create(this), url, queryParam); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java new file mode 100644 index 0000000000..6738b8bc4a --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java @@ -0,0 +1,359 @@ +package me.chanjar.weixin.mp.bean.result; + +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.json.WxBooleanTypeAdapter; +import me.chanjar.weixin.common.util.json.WxDateTypeAdapter; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.util.Date; +import java.util.List; + +/** + *
    + * 公众号的自动回复规则
    + * Created by Binary Wang on 2017-7-8.
    + * @author Binary Wang
    + * 
    + */ +public class WxMpCurrentAutoReplyInfo { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public static WxMpCurrentAutoReplyInfo fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpCurrentAutoReplyInfo.class); + } + + @SerializedName("is_add_friend_reply_open") + @JsonAdapter(WxBooleanTypeAdapter.class) + private Boolean isAddFriendReplyOpen; + + @SerializedName("is_autoreply_open") + @JsonAdapter(WxBooleanTypeAdapter.class) + private Boolean isAutoReplyOpen; + + @SerializedName("add_friend_autoreply_info") + private AutoReplyInfo addFriendAutoReplyInfo; + + @SerializedName("message_default_autoreply_info") + private AutoReplyInfo messageDefaultAutoReplyInfo; + + @SerializedName("keyword_autoreply_info") + private KeywordAutoReplyInfo keywordAutoReplyInfo; + + public Boolean getAddFriendReplyOpen() { + return this.isAddFriendReplyOpen; + } + + public void setAddFriendReplyOpen(Boolean addFriendReplyOpen) { + isAddFriendReplyOpen = addFriendReplyOpen; + } + + public Boolean getAutoReplyOpen() { + return this.isAutoReplyOpen; + } + + public void setAutoReplyOpen(Boolean autoReplyOpen) { + isAutoReplyOpen = autoReplyOpen; + } + + public AutoReplyInfo getAddFriendAutoReplyInfo() { + return this.addFriendAutoReplyInfo; + } + + public void setAddFriendAutoReplyInfo(AutoReplyInfo addFriendAutoReplyInfo) { + this.addFriendAutoReplyInfo = addFriendAutoReplyInfo; + } + + public AutoReplyInfo getMessageDefaultAutoReplyInfo() { + return this.messageDefaultAutoReplyInfo; + } + + public void setMessageDefaultAutoReplyInfo(AutoReplyInfo messageDefaultAutoReplyInfo) { + this.messageDefaultAutoReplyInfo = messageDefaultAutoReplyInfo; + } + + public KeywordAutoReplyInfo getKeywordAutoReplyInfo() { + return this.keywordAutoReplyInfo; + } + + public void setKeywordAutoReplyInfo(KeywordAutoReplyInfo keywordAutoReplyInfo) { + this.keywordAutoReplyInfo = keywordAutoReplyInfo; + } + + public static class AutoReplyRule { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + @SerializedName("rule_name") + private String ruleName; + + @SerializedName("create_time") + @JsonAdapter(WxDateTypeAdapter.class) + private Date createTime; + + @SerializedName("reply_mode") + private String replyMode; + + @SerializedName("keyword_list_info") + private List keywordListInfo; + + @SerializedName("reply_list_info") + private List replyListInfo; + + public String getRuleName() { + return this.ruleName; + } + + public void setRuleName(String ruleName) { + this.ruleName = ruleName; + } + + public Date getCreateTime() { + return this.createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public String getReplyMode() { + return this.replyMode; + } + + public void setReplyMode(String replyMode) { + this.replyMode = replyMode; + } + + public List getKeywordListInfo() { + return this.keywordListInfo; + } + + public void setKeywordListInfo(List keywordListInfo) { + this.keywordListInfo = keywordListInfo; + } + + public List getReplyListInfo() { + return this.replyListInfo; + } + + public void setReplyListInfo(List replyListInfo) { + this.replyListInfo = replyListInfo; + } + } + + public static class ReplyInfo { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + private String type; + private String content; + + @SerializedName("news_info") + private NewsInfo newsInfo; + + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public NewsInfo getNewsInfo() { + return this.newsInfo; + } + + public void setNewsInfo(NewsInfo newsInfo) { + this.newsInfo = newsInfo; + } + } + + public static class NewsInfo { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + private List list; + + public List getList() { + return this.list; + } + + public void setList(List list) { + this.list = list; + } + } + + public static class NewsItem { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + @SerializedName("cover_url") + private String coverUrl; + private String author; + @SerializedName("content_url") + private String contentUrl; + private String digest; + @SerializedName("show_cover") + @JsonAdapter(WxBooleanTypeAdapter.class) + private Boolean showCover; + @SerializedName("source_url") + private String sourceUrl; + private String title; + + public String getCoverUrl() { + return this.coverUrl; + } + + public void setCoverUrl(String coverUrl) { + this.coverUrl = coverUrl; + } + + public String getAuthor() { + return this.author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getContentUrl() { + return this.contentUrl; + } + + public void setContentUrl(String contentUrl) { + this.contentUrl = contentUrl; + } + + public String getDigest() { + return this.digest; + } + + public void setDigest(String digest) { + this.digest = digest; + } + + public Boolean getShowCover() { + return this.showCover; + } + + public void setShowCover(Boolean showCover) { + this.showCover = showCover; + } + + public String getSourceUrl() { + return this.sourceUrl; + } + + public void setSourceUrl(String sourceUrl) { + this.sourceUrl = sourceUrl; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + } + + public static class KeywordInfo { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + private String type; + @SerializedName("match_mode") + private String matchMode; + private String content; + + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMatchMode() { + return this.matchMode; + } + + public void setMatchMode(String matchMode) { + this.matchMode = matchMode; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + } + + public static class KeywordAutoReplyInfo { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + private List list; + + public List getList() { + return this.list; + } + + public void setList(List list) { + this.list = list; + } + } + + public static class AutoReplyInfo { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + private String type; + private String content; + + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + } + +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java index d5bf621287..c3f9f69d7b 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java @@ -2,12 +2,16 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.test.ApiTestModule; import me.chanjar.weixin.mp.api.test.TestConfigStorage; +import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo; import org.testng.*; import org.testng.annotations.*; +import static org.testng.Assert.*; + @Test @Guice(modules = ApiTestModule.class) public class WxMpServiceImplTest { @@ -15,6 +19,14 @@ public class WxMpServiceImplTest { @Inject private WxMpService wxService; + @Test + public void testGetCurrentAutoReplyInfo() throws WxErrorException { + WxMpCurrentAutoReplyInfo autoReplyInfo = this.wxService.getCurrentAutoReplyInfo(); + + assertNotNull(autoReplyInfo); + System.out.println(autoReplyInfo); + } + @Test public void testCheckSignature() { Assert.fail("Not yet implemented"); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfoTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfoTest.java new file mode 100644 index 0000000000..da2cddff40 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfoTest.java @@ -0,0 +1,157 @@ +package me.chanjar.weixin.mp.bean.result; + +import org.testng.annotations.*; + +import static org.testng.Assert.*; + +/** + *
    + * Created by Binary Wang on 2017-7-8.
    + * @author Binary Wang
    + * 
    + */ +public class WxMpCurrentAutoReplyInfoTest { + @Test + public void testFromJson() throws Exception { + String json = "{ \n" + + " \"is_add_friend_reply_open\": 1, \n" + + " \"is_autoreply_open\": 1, \n" + + " \"add_friend_autoreply_info\": { \n" + + " \"type\": \"text\", \n" + + " \"content\": \"Thanks for your attention!\"\n" + + " }, \n" + + " \"message_default_autoreply_info\": { \n" + + " \"type\": \"text\", \n" + + " \"content\": \"Hello, this is autoreply!\"\n" + + " }, \n" + + " \"keyword_autoreply_info\": { \n" + + " \"list\": [ \n" + + " { \n" + + " \"rule_name\": \"autoreply-news\", \n" + + " \"create_time\": 1423028166, \n" + + " \"reply_mode\": \"reply_all\", \n" + + " \"keyword_list_info\": [ \n" + + " { \n" + + " \"type\": \"text\", \n" + + " \"match_mode\": \"contain\", \n" + + " \"content\": \"news测试\"//此处content即为关键词内容\n" + + " }\n" + + " ], \n" + + " \"reply_list_info\": [ \n" + + " { \n" + + " \"type\": \"news\", \n" + + " \"news_info\": { \n" + + " \"list\": [ \n" + + " { \n" + + " \"title\": \"it's news\", \n" + + " \"author\": \"jim\", \n" + + " \"digest\": \"it's digest\", \n" + + " \"show_cover\": 1, \"cover_url\": \"http://mmbiz.qpic.cn/mmbiz/GE7et87vE9vicuCibqXsX9GPPLuEtBfXfKbE8sWdt2DDcL0dMfQWJWTVn1N8DxI0gcRmrtqBOuwQH\n" + + " euPKmFLK0ZQ/0\", \n" + + " \"content_url\": \"http://mp.weixin.qq.com/s?__biz=MjM5ODUwNTM3Ng==&mid=203929886&idx=1&sn=628f964cf0c6d84c026881b6959aea8b#rd\", \n" + + " \"source_url\": \"http://www.url.com\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " }, \n" + + " { \n" + + " \"type\": \"news\",\n" + + " \"content\":\"KQb_w_Tiz-nSdVLoTV35Psmty8hGBulGhEdbb9SKs-o\", \n" + + " \"news_info\": { \n" + + " \"list\": [ \n" + + " { \n" + + " \"title\": \"MULTI_NEWS\", \n" + + " \"author\": \"JIMZHENG\", \n" + + " \"digest\": \"text\", \n" + + " \"show_cover\": 0, \n" + + " \"cover_url\": \"http://mmbiz.qpic.cn/mmbiz/GE7et87vE9vicuCibqXsX9GPPLuEtBfXfK0HKuBIa1A1cypS0uY1wickv70iaY1gf3I1DTszuJoS3lAVLv\n" + + "hTcm9sDA/0\", \n" + + " \"content_url\": \"http://mp.weixin.qq.com/s?__biz=MjM5ODUwNTM3Ng==&mid=204013432&idx=1&sn=80ce6d9abcb832237bf86c87e50fda15#rd\", \n" + + " \"source_url\": \"\"\n" + + " },\n" + + " { \n" + + " \"title\": \"MULTI_NEWS4\", \n" + + " \"author\": \"JIMZHENG\", \n" + + " \"digest\": \"MULTI_NEWSMULTI_NEWSMULTI_NEWSMULTI_NEWSMULTI_NEWSMULT\", \n" + + " \"show_cover\": 1, \n" + + "\"cover_url\": \"http://mmbiz.qpic.cn/mmbiz/GE7et87vE9vicuCibqXsX9GPPLuEtBfXfKbE8sWdt2DDcL0dMfQWJWTVn1N8DxI0gcRmrtqBOuwQ\n" + + "HeuPKmFLK0ZQ/0\", \n" + + " \"content_url\": \"http://mp.weixin.qq.com/s?__biz=MjM5ODUwNTM3Ng==&mid=204013432&idx=5&sn=b4ef73a915e7c2265e437096582774af#rd\", \n" + + " \"source_url\": \"\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + " ]\n" + + " }, \n" + + " { \n" + + " \"rule_name\": \"autoreply-voice\", \n" + + " \"create_time\": 1423027971, \n" + + " \"reply_mode\": \"random_one\", \n" + + " \"keyword_list_info\": [ \n" + + " { \n" + + " \"type\": \"text\", \n" + + " \"match_mode\": \"contain\", \n" + + " \"content\": \"voice测试\"\n" + + " }\n" + + " ], \n" + + " \"reply_list_info\": [ \n" + + " { \n" + + " \"type\": \"voice\", \n" + + " \"content\": \"NESsxgHEvAcg3egJTtYj4uG1PTL6iPhratdWKDLAXYErhN6oEEfMdVyblWtBY5vp\"\n" + + " }\n" + + " ]\n" + + " }, \n" + + " { \n" + + " \"rule_name\": \"autoreply-text\", \n" + + " \"create_time\": 1423027926, \n" + + " \"reply_mode\": \"random_one\", \n" + + " \"keyword_list_info\": [ \n" + + " { \n" + + " \"type\": \"text\", \n" + + " \"match_mode\": \"contain\", \n" + + " \"content\": \"text测试\"\n" + + " }\n" + + " ], \n" + + " \"reply_list_info\": [ \n" + + " { \n" + + " \"type\": \"text\", \n" + + " \"content\": \"hello!text!\"\n" + + " }\n" + + " ]\n" + + " }, \n" + + " { \n" + + " \"rule_name\": \"autoreply-video\", \n" + + " \"create_time\": 1423027801, \n" + + " \"reply_mode\": \"random_one\", \n" + + " \"keyword_list_info\": [ \n" + + " { \n" + + " \"type\": \"text\", \n" + + " \"match_mode\": \"equal\", \n" + + " \"content\": \"video测试\"\n" + + " }\n" + + " ], \n" + + " \"reply_list_info\": [ \n" + + " { \n" + + " \"type\": \"video\", \n" + + "\"content\": \"http://61.182.133.153/vweixinp.tc.qq.com/1007_114bcede9a2244eeb5ab7f76d951df5f.f10.mp4?vkey=7183E5C952B16C3AB1991BA8138673DE1037CB82A29801A504B64A77F691BF9DF7AD054A9B7FE683&sha=0&save=1\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + + WxMpCurrentAutoReplyInfo autoReplyInfo = WxMpCurrentAutoReplyInfo.fromJson(json); + + assertNotNull(autoReplyInfo); + assertTrue(autoReplyInfo.getAddFriendReplyOpen()); + assertTrue(autoReplyInfo.getAutoReplyOpen()); + assertNotNull(autoReplyInfo.getAddFriendAutoReplyInfo()); + assertNotNull(autoReplyInfo.getMessageDefaultAutoReplyInfo()); + assertTrue(autoReplyInfo.getKeywordAutoReplyInfo().getList().size() > 0); + + System.out.println(autoReplyInfo); + } + +} From f76f9f5a8e781ffbb6310ea26105b71543e9f527 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 11 Jul 2017 17:48:13 +0800 Subject: [PATCH 147/179] =?UTF-8?q?#272=20=E7=BB=9F=E4=B8=80=E4=B8=8B?= =?UTF-8?q?=E5=8D=95=E6=8E=A5=E5=8F=A3=E5=A2=9E=E5=8A=A0H5=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E5=BF=85=E9=A1=BB=E7=9A=84=E5=8F=82=E6=95=B0scene=5Fi?= =?UTF-8?q?nfo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/WxPayUnifiedOrderRequest.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java index 342a3eb2d2..fdfcea3e22 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java @@ -280,6 +280,26 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { @XStreamAlias("sub_openid") private String subOpenid; + /** + *
    +   * 字段名:场景信息
    +   * 变量名:scene_info
    +   * 是否必填:否,对H5支付来说是必填
    +   * 类型:String(256)
    +   * 示例值:{
    +   * "store_id": "SZT10000",
    +   * "store_name":"腾讯大厦腾大餐厅"
    +   * }
    +   * 描述:该字段用于统一下单时上报场景信息,目前支持上报实际门店信息。
    +   * {
    +   * "store_id": "", //门店唯一标识,选填,String(32)
    +   * "store_name":"”//门店名称,选填,String(64)
    +   * }
    +   * 
    + */ + @XStreamAlias("scene_info") + private String sceneInfo; + public WxPayUnifiedOrderRequest() { } @@ -307,6 +327,7 @@ private WxPayUnifiedOrderRequest(Builder builder) { setLimitPay(builder.limitPay); setOpenid(builder.openid); setSubOpenid(builder.subOpenid); + setSceneInfo(builder.sceneInfo); } public static Builder newBuilder() { @@ -459,6 +480,14 @@ public void setSubOpenid(String subOpenid) { this.subOpenid = subOpenid; } + public String getSceneInfo() { + return this.sceneInfo; + } + + public void setSceneInfo(String sceneInfo) { + this.sceneInfo = sceneInfo; + } + @Override protected void checkConstraints() { // if (!ArrayUtils.contains(TRADE_TYPES, this.getTradeType())) { @@ -512,6 +541,7 @@ public static final class Builder { private String limitPay; private String openid; private String subOpenid; + private String sceneInfo; private Builder() { } @@ -631,6 +661,11 @@ public Builder subOpenid(String subOpenid) { return this; } + public Builder sceneInfo(String sceneInfo) { + this.sceneInfo = sceneInfo; + return this; + } + public WxPayUnifiedOrderRequest build() { return new WxPayUnifiedOrderRequest(this); } From fae294099362453eded559177659031ac36ad91a Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 11 Jul 2017 17:59:27 +0800 Subject: [PATCH 148/179] =?UTF-8?q?=E5=8F=91=E5=B8=83=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC2.7.5.BETA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 5f1d901d4b..3b6ab1509b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang weixin-java-parent - 2.7.4.BETA + 2.7.5.BETA pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 3800522ceb..a2f1195b9a 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.4.BETA + 2.7.5.BETA weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 1790105d8f..b63055ebc2 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.4.BETA + 2.7.5.BETA weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index 60d1194a78..b3e0e88e15 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.4.BETA + 2.7.5.BETA weixin-java-miniapp WeiXin Java Tools - MiniApp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index d65bceef9f..bd95d24728 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.4.BETA + 2.7.5.BETA weixin-java-mp WeiXin Java Tools - MP diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 7bb79b229d..7c695abc3e 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 2.7.4.BETA + 2.7.5.BETA 4.0.0 From 55c71a995e4423939906c7a73ae19878ccebce4f Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 14 Jul 2017 10:32:16 +0800 Subject: [PATCH 149/179] update travis settings --- .travis.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1c533f9765..484475232b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,17 @@ language: java -sudo: false -install: true -addons: - sonarcloud: - token: - secure: "834110c7191f97ecb226970c46dcaff8e681da5a" +#sudo: false +#install: true +#addons: +# sonarcloud: +# token: +# secure: "834110c7191f97ecb226970c46dcaff8e681da5a" jdk: - oraclejdk8 -#script: "mvn clean package -Dmaven.test.skip=true" +script: "mvn clean package -Dmaven.test.skip=true" -script: - - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar +#script: +# - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar branches: only: @@ -20,7 +20,7 @@ branches: cache: directories: - '$HOME/.m2/repository' - - '$HOME/.sonar/cache' +# - '$HOME/.sonar/cache' notifications: email: From 687093f755b3ec4a006e5db85e6cd4dc4bd8e7aa Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 15 Jul 2017 13:55:05 +0800 Subject: [PATCH 150/179] =?UTF-8?q?#279=20=E7=BB=9F=E4=B8=80=E4=B8=8B?= =?UTF-8?q?=E5=8D=95=E6=8E=A5=E5=8F=A3=E5=8F=82=E6=95=B0=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?WxPayUnifiedOrderRequest=E5=A2=9E=E5=8A=A0fingerprint=E5=B1=9E?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/WxPayUnifiedOrderRequest.java | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java index fdfcea3e22..7c927425de 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java @@ -299,6 +299,16 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest { */ @XStreamAlias("scene_info") private String sceneInfo; + /** + *
    +   * 字段名:浏览器指纹
    +   * 变量名:fingerprint
    +   * 是否必填:否
    +   * 详细参考 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_7&index=6
    +   * 
    + */ + @XStreamAlias("fingerprint") + private String fingerprint; public WxPayUnifiedOrderRequest() { } @@ -328,6 +338,7 @@ private WxPayUnifiedOrderRequest(Builder builder) { setOpenid(builder.openid); setSubOpenid(builder.subOpenid); setSceneInfo(builder.sceneInfo); + fingerprint = builder.fingerprint; } public static Builder newBuilder() { @@ -518,14 +529,14 @@ public void checkAndSign(WxPayConfig config) throws WxPayException { } public static final class Builder { - private String deviceInfo; private String appid; - private String body; private String mchId; private String subAppId; private String subMchId; private String nonceStr; private String sign; + private String deviceInfo; + private String body; private String detail; private String attach; private String outTradeNo; @@ -542,25 +553,16 @@ public static final class Builder { private String openid; private String subOpenid; private String sceneInfo; + private String fingerprint; private Builder() { } - public Builder deviceInfo(String deviceInfo) { - this.deviceInfo = deviceInfo; - return this; - } - public Builder appid(String appid) { this.appid = appid; return this; } - public Builder body(String body) { - this.body = body; - return this; - } - public Builder mchId(String mchId) { this.mchId = mchId; return this; @@ -586,6 +588,16 @@ public Builder sign(String sign) { return this; } + public Builder deviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + return this; + } + + public Builder body(String body) { + this.body = body; + return this; + } + public Builder detail(String detail) { this.detail = detail; return this; @@ -666,6 +678,11 @@ public Builder sceneInfo(String sceneInfo) { return this; } + public Builder fingerprint(String fingerprint) { + this.fingerprint = fingerprint; + return this; + } + public WxPayUnifiedOrderRequest build() { return new WxPayUnifiedOrderRequest(this); } From 3a2efdd343c4f22e44b8d8e2456c59f22db861c5 Mon Sep 17 00:00:00 2001 From: mgcnrx11 Date: Sat, 15 Jul 2017 16:22:36 +0800 Subject: [PATCH 151/179] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BC=9A=E5=91=98?= =?UTF-8?q?=E5=8D=A1=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3=20(#280)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 新增会员卡相关接口 1. 激活会员卡接口 2. 拉取会员信息接口 --- .../weixin/mp/api/WxMpMemberCardService.java | 38 +++++ .../me/chanjar/weixin/mp/api/WxMpService.java | 7 + .../mp/api/impl/AbstractWxMpServiceImpl.java | 6 + .../api/impl/WxMpMemberCardServiceImpl.java | 78 ++++++++++ .../bean/membercard/MemberCardUserInfo.java | 27 ++++ .../weixin/mp/bean/membercard/NameValues.java | 36 +++++ .../WxMpMemberCardActivatedMessage.java | 144 ++++++++++++++++++ .../WxMpMemberCardUserInfoResult.java | 137 +++++++++++++++++ .../weixin/mp/util/json/WxMpGsonBuilder.java | 2 + ...MpMemberCardUserInfoResultGsonAdapter.java | 72 +++++++++ 10 files changed, 547 insertions(+) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/MemberCardUserInfo.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/NameValues.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardActivatedMessage.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUserInfoResultGsonAdapter.java diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java new file mode 100644 index 0000000000..89b9fd74ea --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java @@ -0,0 +1,38 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardActivatedMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult; + +/** + * 会员卡相关接口 + * + * @author YuJian(mgcnrx11@gmail.com) + * @version 2017/7/8 + */ +public interface WxMpMemberCardService { + + /** + * 得到WxMpService + */ + WxMpService getWxMpService(); + + /** + * 会员卡激活接口 + * + * @param activatedMessage 激活所需参数 + * @return 调用返回的JSON字符串。 + * @throws WxErrorException 接口调用失败抛出的异常 + */ + String activateMemberCard(WxMpMemberCardActivatedMessage activatedMessage) throws WxErrorException; + + /** + * 拉取会员信息接口 + * + * @param cardId 会员卡的CardId,微信分配 + * @param code 领取会员的会员卡Code + * @return 会员信息的结果对象 + * @throws WxErrorException 接口调用失败抛出的异常 + */ + WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) throws WxErrorException; +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index 0cff2c1cfd..e4da721c8e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -434,6 +434,13 @@ public interface WxMpService { */ WxMpShakeService getShakeService(); + /** + * 返回会员卡相关接口方法的实现类对象,以方便调用其各个接口 + * + * @return WxMpMemberCardService + */ + WxMpMemberCardService getMemberCardService(); + /** * 初始化http请求对象 */ diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java index ed93d4936f..cc965026c4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java @@ -42,6 +42,7 @@ public abstract class AbstractWxMpServiceImpl implements WxMpService, Requ private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); private WxMpShakeService shakeService = new WxMpShakeServiceImpl(this); + private WxMpMemberCardService memberCardService = new WxMpMemberCardServiceImpl(this); private int retrySleepMillis = 1000; private int maxRetryTimes = 5; @@ -406,6 +407,11 @@ public WxMpShakeService getShakeService() { return this.shakeService; } + @Override + public WxMpMemberCardService getMemberCardService() { + return this.memberCardService; + } + @Override public RequestHttp getRequestHttp() { return this; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java new file mode 100644 index 0000000000..24c70ebe9f --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java @@ -0,0 +1,78 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpMemberCardService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardActivatedMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 会员卡相关接口的实现类 + * + * @author YuJian(mgcnrx11@gmail.com) + * @version 2017/7/8 + */ +public class WxMpMemberCardServiceImpl implements WxMpMemberCardService { + + private final Logger log = LoggerFactory.getLogger(WxMpMemberCardServiceImpl.class); + + private static final String MEMBER_CARD_ACTIVATE = "https://api.weixin.qq.com/card/membercard/activate"; + private static final String MEMBER_CARD_USER_INFO_GET = "https://api.weixin.qq.com/card/membercard/userinfo/get"; + + private WxMpService wxMpService; + + private static final Gson GSON = new Gson(); + + WxMpMemberCardServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + /** + * 得到WxMpService + */ + @Override + public WxMpService getWxMpService() { + return this.wxMpService; + } + + /** + * 会员卡激活接口 + * + * @param activatedMessage 激活所需参数 + * @return 调用返回的JSON字符串。 + * @throws WxErrorException 接口调用失败抛出的异常 + */ + @Override + public String activateMemberCard(WxMpMemberCardActivatedMessage activatedMessage) throws WxErrorException { + return this.wxMpService.post(MEMBER_CARD_ACTIVATE, GSON.toJson(activatedMessage)); + } + + /** + * 拉取会员信息接口 + * + * @param cardId 会员卡的CardId,微信分配 + * @param code 领取会员的会员卡Code + * @return 会员信息的结果对象 + * @throws WxErrorException 接口调用失败抛出的异常 + */ + @Override + public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) throws WxErrorException { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("card_id", cardId); + jsonObject.addProperty("code",code); + + String responseContent = this.getWxMpService().post(MEMBER_CARD_USER_INFO_GET, jsonObject.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, + new TypeToken() { + }.getType()); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/MemberCardUserInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/MemberCardUserInfo.java new file mode 100644 index 0000000000..336008b085 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/MemberCardUserInfo.java @@ -0,0 +1,27 @@ +package me.chanjar.weixin.mp.bean.membercard; + +/** + * Created by YuJian on 2017/7/11. + */ +public class MemberCardUserInfo { + + private NameValues[] commonFieldList; + + private NameValues[] customFieldList; + + public NameValues[] getCommonFieldList() { + return commonFieldList; + } + + public void setCommonFieldList(NameValues[] commonFieldList) { + this.commonFieldList = commonFieldList; + } + + public NameValues[] getCustomFieldList() { + return customFieldList; + } + + public void setCustomFieldList(NameValues[] customFieldList) { + this.customFieldList = customFieldList; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/NameValues.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/NameValues.java new file mode 100644 index 0000000000..ae30d7a9a4 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/NameValues.java @@ -0,0 +1,36 @@ +package me.chanjar.weixin.mp.bean.membercard; + +/** + * Created by YuJian on 2017/7/11. + */ +public class NameValues { + private String name; + + private String value; + + private String[] valueList; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String[] getValueList() { + return valueList; + } + + public void setValueList(String[] valueList) { + this.valueList = valueList; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardActivatedMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardActivatedMessage.java new file mode 100644 index 0000000000..8040224a09 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardActivatedMessage.java @@ -0,0 +1,144 @@ +package me.chanjar.weixin.mp.bean.membercard; + +import com.google.gson.annotations.SerializedName; + +/** + * 会员卡激活接口的参数 + * + * @author YuJian(mgcnrx11@hotmail.com) + * @version 2017/7/8 + */ +public class WxMpMemberCardActivatedMessage { + + // 会员卡编号,由开发者填入,作为序列号显示在用户的卡包里。可与Code码保持等值。 + @SerializedName("membership_number") + private String membershipNumber; + // 领取会员卡用户获得的code + private String code; + // 卡券ID,自定义code卡券必填 + @SerializedName("card_id") + private String cardId; + // 商家自定义会员卡背景图,须先调用上传图片接口将背景图上传至CDN,否则报错。卡面设计请遵循微信会员卡自定义背景设计规范 + @SerializedName("background_pic_url") + private String backgroundPicUrl; + // 激活后的有效起始时间。若不填写默认以创建时的 data_info 为准。Unix时间戳格式。 + @SerializedName("activate_begin_time") + private Integer activateBeginTime; + // 激活后的有效截至时间。若不填写默认以创建时的 data_info 为准。Unix时间戳格式。 + @SerializedName("activate_end_time") + private Integer activateEndTime; + // 初始积分,不填为0。 + @SerializedName("init_bonus") + private Integer initBonus; + // 积分同步说明。 + @SerializedName("init_bonus_record") + private String initBonusRecord; + // 初始余额,不填为0。 + @SerializedName("init_balance") + private Integer initBalance; + // 创建时字段custom_field1定义类型的初始值,限制为4个汉字,12字节。 + @SerializedName("init_custom_field_value1") + private String initCustomFieldValue1; + // 创建时字段custom_field2定义类型的初始值,限制为4个汉字,12字节。 + @SerializedName("init_custom_field_value2") + private String initCustomFieldValue2; + // 创建时字段custom_field3定义类型的初始值,限制为4个汉字,12字节。 + @SerializedName("init_custom_field_value3") + private String initCustomFieldValue3; + + public String getMembershipNumber() { + return membershipNumber; + } + + public void setMembershipNumber(String membershipNumber) { + this.membershipNumber = membershipNumber; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getCardId() { + return cardId; + } + + public void setCardId(String cardId) { + this.cardId = cardId; + } + + public String getBackgroundPicUrl() { + return backgroundPicUrl; + } + + public void setBackgroundPicUrl(String backgroundPicUrl) { + this.backgroundPicUrl = backgroundPicUrl; + } + + public Integer getActivateBeginTime() { + return activateBeginTime; + } + + public void setActivateBeginTime(Integer activateBeginTime) { + this.activateBeginTime = activateBeginTime; + } + + public Integer getActivateEndTime() { + return activateEndTime; + } + + public void setActivateEndTime(Integer activateEndTime) { + this.activateEndTime = activateEndTime; + } + + public Integer getInitBonus() { + return initBonus; + } + + public void setInitBonus(Integer initBonus) { + this.initBonus = initBonus; + } + + public String getInitBonusRecord() { + return initBonusRecord; + } + + public void setInitBonusRecord(String initBonusRecord) { + this.initBonusRecord = initBonusRecord; + } + + public Integer getInitBalance() { + return initBalance; + } + + public void setInitBalance(Integer initBalance) { + this.initBalance = initBalance; + } + + public String getInitCustomFieldValue1() { + return initCustomFieldValue1; + } + + public void setInitCustomFieldValue1(String initCustomFieldValue1) { + this.initCustomFieldValue1 = initCustomFieldValue1; + } + + public String getInitCustomFieldValue2() { + return initCustomFieldValue2; + } + + public void setInitCustomFieldValue2(String initCustomFieldValue2) { + this.initCustomFieldValue2 = initCustomFieldValue2; + } + + public String getInitCustomFieldValue3() { + return initCustomFieldValue3; + } + + public void setInitCustomFieldValue3(String initCustomFieldValue3) { + this.initCustomFieldValue3 = initCustomFieldValue3; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java new file mode 100644 index 0000000000..b3691da6dd --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java @@ -0,0 +1,137 @@ +package me.chanjar.weixin.mp.bean.membercard; + +import java.io.Serializable; + +/** + * 拉取会员信息返回的结果 + * + * 字段格式参考https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025283 6.2.1小节的步骤5 + * + * @author YuJian + * @version 2017/7/9 + */ +public class WxMpMemberCardUserInfoResult implements Serializable { + + private static final long serialVersionUID = 9084777967442098311L; + + private String errorCode; + + private String errorMsg; + + private String openId; + + private String nickname; + + private String membershipNumber; + + private Integer bonus; + + private String sex; + + private MemberCardUserInfo userInfo; + + private String userCardStatus; + + private Boolean hasActive; + + public static long getSerialVersionUID() { + return serialVersionUID; + } + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public String getMembershipNumber() { + return membershipNumber; + } + + public void setMembershipNumber(String membershipNumber) { + this.membershipNumber = membershipNumber; + } + + public Integer getBonus() { + return bonus; + } + + public void setBonus(Integer bonus) { + this.bonus = bonus; + } + + public String getSex() { + return sex; + } + + public void setSex(String sex) { + this.sex = sex; + } + + public MemberCardUserInfo getUserInfo() { + return userInfo; + } + + public void setUserInfo(MemberCardUserInfo userInfo) { + this.userInfo = userInfo; + } + + public String getUserCardStatus() { + return userCardStatus; + } + + public void setUserCardStatus(String userCardStatus) { + this.userCardStatus = userCardStatus; + } + + public Boolean getHasActive() { + return hasActive; + } + + public void setHasActive(Boolean hasActive) { + this.hasActive = hasActive; + } + + @Override + public String toString() { + return "WxMpMemberCardUserInfoResult{" + + "errorCode='" + errorCode + '\'' + + ", errorMsg='" + errorMsg + '\'' + + ", openId='" + openId + '\'' + + ", nickname='" + nickname + '\'' + + ", membershipNumber='" + membershipNumber + '\'' + + ", bonus=" + bonus + + ", sex='" + sex + '\'' + + ", userInfo=" + userInfo + + ", userCardStatus='" + userCardStatus + '\'' + + ", hasActive=" + hasActive + + '}'; + } +} + diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java index 286778ad4b..8fca5a6a88 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java @@ -6,6 +6,7 @@ import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate; import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult; import me.chanjar.weixin.mp.bean.material.*; import me.chanjar.weixin.mp.bean.result.*; import me.chanjar.weixin.mp.bean.template.WxMpTemplateIndustry; @@ -49,6 +50,7 @@ public class WxMpGsonBuilder { INSTANCE.registerTypeAdapter(WxMediaImgUploadResult.class, new WxMediaImgUploadResultGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpTemplateIndustry.class, new WxMpIndustryGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpUserBlacklistGetResult.class, new WxUserBlacklistGetResultGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpMemberCardUserInfoResult.class, new WxMpMemberCardUserInfoResultGsonAdapter()); } public static Gson create() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUserInfoResultGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUserInfoResultGsonAdapter.java new file mode 100644 index 0000000000..021ea60226 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUserInfoResultGsonAdapter.java @@ -0,0 +1,72 @@ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.membercard.MemberCardUserInfo; +import me.chanjar.weixin.mp.bean.membercard.NameValues; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult; + +import java.lang.reflect.Type; + +/** + * Created by YuJian on 2017/7/11. + * + * @author YuJian + * @version 2017/7/11 + */ +public class WxMpMemberCardUserInfoResultGsonAdapter implements JsonDeserializer { + + @Override + public WxMpMemberCardUserInfoResult deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + WxMpMemberCardUserInfoResult result = new WxMpMemberCardUserInfoResult(); + + JsonObject jsonObject = jsonElement.getAsJsonObject(); + + result.setOpenId(GsonHelper.getString(jsonObject, "openid")); + result.setErrorCode(GsonHelper.getString(jsonObject, "errcode")); + result.setErrorMsg(GsonHelper.getString(jsonObject, "errmsg")); + result.setNickname(GsonHelper.getString(jsonObject, "nickname")); + result.setMembershipNumber(GsonHelper.getString(jsonObject, "membership_number")); + result.setBonus(GsonHelper.getInteger(jsonObject, "bonus")); + result.setSex(GsonHelper.getString(jsonObject, "sex")); + result.setUserCardStatus(GsonHelper.getString(jsonObject, "user_card_status")); + result.setHasActive(GsonHelper.getBoolean(jsonObject, "has_active")); + + JsonObject userInfoJsonObject = jsonObject.getAsJsonObject("user_info"); + MemberCardUserInfo cardUserInfo = new MemberCardUserInfo(); + + JsonArray commonFieldListObj = userInfoJsonObject.getAsJsonArray("common_field_list"); + NameValues[] commonFieldListValues = new NameValues[commonFieldListObj.size()]; + for (int i = 0; i < commonFieldListObj.size(); i++) { + JsonObject commonField = commonFieldListObj.get(i).getAsJsonObject(); + NameValues commonNameValues = new NameValues(); + commonNameValues.setName(GsonHelper.getString(commonField, "name")); + commonNameValues.setValue(GsonHelper.getString(commonField, "value")); + commonFieldListValues[i] = commonNameValues; + } + cardUserInfo.setCommonFieldList(commonFieldListValues); + + JsonArray customFieldListObj = userInfoJsonObject.getAsJsonArray("custom_field_list"); + NameValues[] customFieldListValues = new NameValues[customFieldListObj.size()]; + for (int i = 0; i < customFieldListObj.size(); i++) { + JsonObject customField = customFieldListObj.get(i).getAsJsonObject(); + NameValues customNameValues = new NameValues(); + customNameValues.setName(GsonHelper.getString(customField, "name")); + customNameValues.setValue(GsonHelper.getString(customField, "value")); + + JsonArray valueListArray = customField.getAsJsonArray("value_list"); + String[] valueList = new String[valueListArray.size()]; + for (int j = 0; j < valueListArray.size(); j++) { + JsonObject valueListObj = valueListArray.getAsJsonObject(); + valueList[i] = valueListObj.getAsString(); + } + customNameValues.setValueList(valueList); + customFieldListValues[i] = customNameValues; + } + cardUserInfo.setCustomFieldList(customFieldListValues); + + result.setUserInfo(cardUserInfo); + + return result; + } +} From c8c51a9ceecf7574c68aa31e4ee2d5b87b5a5f26 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 15 Jul 2017 17:13:00 +0800 Subject: [PATCH 152/179] =?UTF-8?q?#178=20=E5=AE=9E=E7=8E=B0=E5=8F=91?= =?UTF-8?q?=E9=80=81=E4=BB=A3=E9=87=91=E5=88=B8=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bean/coupon/WxPayCouponSendRequest.java | 311 ++++++++++++++++++ .../bean/coupon/WxPayCouponSendResult.java | 204 ++++++++++++ .../wxpay/bean/request/WxPayBaseRequest.java | 79 ++--- .../wxpay/service/WxPayService.java | 12 + .../impl/WxPayServiceAbstractImpl.java | 13 + ...java => WxPayServiceAbstractImplTest.java} | 14 +- 6 files changed, 589 insertions(+), 44 deletions(-) create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendRequest.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendResult.java rename weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/{WxPayServiceImplTest.java => WxPayServiceAbstractImplTest.java} (94%) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendRequest.java new file mode 100644 index 0000000000..9a98fd64a2 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendRequest.java @@ -0,0 +1,311 @@ +package com.github.binarywang.wxpay.bean.coupon; + +import com.github.binarywang.wxpay.bean.request.WxPayBaseRequest; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import me.chanjar.weixin.common.annotation.Required; + +/** + *
    + * 发送代金券请求对象类
    + * Created by Binary Wang on 2017-7-15.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxPayCouponSendRequest extends WxPayBaseRequest { + /** + *
    +   * 字段名:代金券批次id
    +   * 变量名:coupon_stock_id
    +   * 是否必填:是
    +   * 示例值:1757
    +   * 类型:String
    +   * 说明:代金券批次id
    +   * 
    + */ + @Required + @XStreamAlias("coupon_stock_id") + private String couponStockId; + + /** + *
    +   * 字段名:openid记录数
    +   * 变量名:openid_count
    +   * 是否必填:是
    +   * 示例值:1
    +   * 类型:int
    +   * 说明:openid记录数(目前支持num=1)
    +   * 
    + */ + @Required + @XStreamAlias("openid_count") + private Integer openidCount; + + /** + *
    +   * 字段名:商户单据号
    +   * 变量名:partner_trade_no
    +   * 是否必填:是
    +   * 示例值:1000009820141203515766
    +   * 类型:String
    +   * 说明:商户此次发放凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性
    +   * 
    + */ + @Required + @XStreamAlias("partner_trade_no") + private String partnerTradeNo; + + /** + *
    +   * 字段名:用户openid
    +   * 变量名:openid
    +   * 是否必填:是
    +   * 示例值:onqOjjrXT-776SpHnfexGm1_P7iE
    +   * 类型:String
    +   * 说明:Openid信息,用户在appid下的openid。
    +   * 
    + */ + @Required + @XStreamAlias("openid") + private String openid; + + /** + *
    +   * 字段名:操作员
    +   * 变量名:op_user_id
    +   * 是否必填:否
    +   * 示例值:10000098
    +   * 类型:String(32)
    +   * 说明:操作员帐号, 默认为商户号,可在商户平台配置操作员对应的api权限
    +   * 
    + */ + @XStreamAlias("op_user_id") + private String opUserId; + + /** + *
    +   * 字段名:设备号
    +   * 变量名:device_info
    +   * 是否必填:否
    +   * 示例值:
    +   * 类型:String(32)
    +   * 说明:微信支付分配的终端设备号
    +   * 
    + */ + @XStreamAlias("device_info") + private String deviceInfo; + + /** + *
    +   * 字段名:协议版本
    +   * 变量名:version
    +   * 是否必填:否
    +   * 示例值:1.0
    +   * 类型:String(32)
    +   * 说明:默认1.0
    +   * 
    + */ + @XStreamAlias("version") + private String version; + + /** + *
    +   * 字段名:协议类型
    +   * 变量名:type
    +   * 是否必填:否
    +   * 示例值:XML
    +   * 类型:String(32)
    +   * 说明:XML【目前仅支持默认XML】
    +   * 
    + */ + @XStreamAlias("type") + private String type; + + public WxPayCouponSendRequest() { + } + + private WxPayCouponSendRequest(Builder builder) { + setAppid(builder.appid); + setMchId(builder.mchId); + setSubAppId(builder.subAppId); + setSubMchId(builder.subMchId); + setNonceStr(builder.nonceStr); + setSign(builder.sign); + setCouponStockId(builder.couponStockId); + setOpenidCount(builder.openidCount); + setPartnerTradeNo(builder.partnerTradeNo); + setOpenid(builder.openid); + setOpUserId(builder.opUserId); + setDeviceInfo(builder.deviceInfo); + setVersion(builder.version); + setType(builder.type); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public String getCouponStockId() { + return this.couponStockId; + } + + public void setCouponStockId(String couponStockId) { + this.couponStockId = couponStockId; + } + + public Integer getOpenidCount() { + return this.openidCount; + } + + public void setOpenidCount(Integer openidCount) { + this.openidCount = openidCount; + } + + public String getPartnerTradeNo() { + return this.partnerTradeNo; + } + + public void setPartnerTradeNo(String partnerTradeNo) { + this.partnerTradeNo = partnerTradeNo; + } + + public String getOpenid() { + return this.openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public String getOpUserId() { + return this.opUserId; + } + + public void setOpUserId(String opUserId) { + this.opUserId = opUserId; + } + + public String getDeviceInfo() { + return this.deviceInfo; + } + + public void setDeviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + } + + public String getVersion() { + return this.version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + protected void checkConstraints() { + //do nothing + } + + public static final class Builder { + private String appid; + private String mchId; + private String subAppId; + private String subMchId; + private String nonceStr; + private String sign; + private String couponStockId; + private Integer openidCount; + private String partnerTradeNo; + private String openid; + private String opUserId; + private String deviceInfo; + private String version; + private String type; + + private Builder() { + } + + public Builder appid(String appid) { + this.appid = appid; + return this; + } + + public Builder mchId(String mchId) { + this.mchId = mchId; + return this; + } + + public Builder subAppId(String subAppId) { + this.subAppId = subAppId; + return this; + } + + public Builder subMchId(String subMchId) { + this.subMchId = subMchId; + return this; + } + + public Builder nonceStr(String nonceStr) { + this.nonceStr = nonceStr; + return this; + } + + public Builder sign(String sign) { + this.sign = sign; + return this; + } + + public Builder couponStockId(String couponStockId) { + this.couponStockId = couponStockId; + return this; + } + + public Builder openidCount(Integer openidCount) { + this.openidCount = openidCount; + return this; + } + + public Builder partnerTradeNo(String partnerTradeNo) { + this.partnerTradeNo = partnerTradeNo; + return this; + } + + public Builder openid(String openid) { + this.openid = openid; + return this; + } + + public Builder opUserId(String opUserId) { + this.opUserId = opUserId; + return this; + } + + public Builder deviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + return this; + } + + public Builder version(String version) { + this.version = version; + return this; + } + + public Builder type(String type) { + this.type = type; + return this; + } + + public WxPayCouponSendRequest build() { + return new WxPayCouponSendRequest(this); + } + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendResult.java new file mode 100644 index 0000000000..1c562adae2 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponSendResult.java @@ -0,0 +1,204 @@ +package com.github.binarywang.wxpay.bean.coupon; + +import com.github.binarywang.wxpay.bean.result.WxPayBaseResult; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + *
    + * 发送代金券响应结果类
    + * Created by Binary Wang on 2017-7-15.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxPayCouponSendResult extends WxPayBaseResult { + /** + *
    +   * 字段名:设备号
    +   * 变量名:device_info
    +   * 是否必填:否
    +   * 示例值:123456sb
    +   * 类型:String(32)
    +   * 描述:微信支付分配的终端设备号,
    +   * 
    + */ + @XStreamAlias("device_info") + private String deviceInfo; + + /** + *
    +   * 字段名:代金券批次id
    +   * 变量名:coupon_stock_id
    +   * 是否必填:是
    +   * 示例值:1757
    +   * 类型:String
    +   * 描述:用户在商户appid下的唯一标识
    +   * 
    + */ + @XStreamAlias("coupon_stock_id") + private String couponStockId; + + /** + *
    +   * 字段名:返回记录数
    +   * 变量名:resp_count
    +   * 是否必填:是
    +   * 示例值:1
    +   * 类型:Int
    +   * 描述:返回记录数
    +   * 
    + */ + @XStreamAlias("resp_count") + private Integer respCount; + + /** + *
    +   * 字段名:成功记录数
    +   * 变量名:success_count
    +   * 是否必填:是
    +   * 示例值:1或者0
    +   * 类型:Int
    +   * 描述:成功记录数
    +   * 
    + */ + @XStreamAlias("success_count") + private Integer successCount; + + /** + *
    +   * 字段名:失败记录数
    +   * 变量名:failed_count
    +   * 是否必填:是
    +   * 示例值:1或者0
    +   * 类型:Int
    +   * 描述:失败记录数
    +   * 
    + */ + @XStreamAlias("failed_count") + private Integer failedCount; + + /** + *
    +   * 字段名:用户标识
    +   * 变量名:openid
    +   * 是否必填:是
    +   * 示例值:onqOjjrXT-776SpHnfexGm1_P7iE
    +   * 类型:String
    +   * 描述:用户在商户appid下的唯一标识
    +   * 
    + */ + @XStreamAlias("openid") + private String openid; + + /** + *
    +   * 字段名:返回码
    +   * 变量名:ret_code
    +   * 是否必填:是
    +   * 示例值:SUCCESS或者FAILED
    +   * 类型:String
    +   * 描述:返回码,SUCCESS/FAILED
    +   * 
    + */ + @XStreamAlias("ret_code") + private String retCode; + + /** + *
    +   * 字段名:代金券id
    +   * 变量名:coupon_id
    +   * 是否必填:是
    +   * 示例值:1870
    +   * 类型:String
    +   * 描述:对一个用户成功发放代金券则返回代金券id,即ret_code为SUCCESS的时候;如果ret_code为FAILED则填写空串""
    +   * 
    + */ + @XStreamAlias("coupon_id") + private String couponId; + + /** + *
    +   * 字段名:返回信息
    +   * 变量名:ret_msg
    +   * 是否必填:是
    +   * 示例值:失败描述信息,例如:“用户已达领用上限”
    +   * 类型:String
    +   * 描述:返回信息,当返回码是FAILED的时候填写,否则填空串“”
    +   * 
    + */ + @XStreamAlias("ret_msg") + private String retMsg; + + public String getDeviceInfo() { + return this.deviceInfo; + } + + public void setDeviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + } + + public String getCouponStockId() { + return this.couponStockId; + } + + public void setCouponStockId(String couponStockId) { + this.couponStockId = couponStockId; + } + + public Integer getRespCount() { + return this.respCount; + } + + public void setRespCount(Integer respCount) { + this.respCount = respCount; + } + + public Integer getSuccessCount() { + return this.successCount; + } + + public void setSuccessCount(Integer successCount) { + this.successCount = successCount; + } + + public Integer getFailedCount() { + return this.failedCount; + } + + public void setFailedCount(Integer failedCount) { + this.failedCount = failedCount; + } + + public String getOpenid() { + return this.openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public String getRetCode() { + return this.retCode; + } + + public void setRetCode(String retCode) { + this.retCode = retCode; + } + + public String getCouponId() { + return this.couponId; + } + + public void setCouponId(String couponId) { + this.couponId = couponId; + } + + public String getRetMsg() { + return this.retMsg; + } + + public void setRetMsg(String retMsg) { + this.retMsg = retMsg; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java index 0d4fc08b9d..b0c2e85d5c 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java @@ -17,13 +17,6 @@ *
      * Created by Binary Wang on 2016-10-24.
      *  微信支付请求对象共用的参数存放类
    - * 注释中各行每个字段描述对应如下:
    - * 
  • 字段名 - *
  • 变量名 - *
  • 是否必填 - *
  • 类型 - *
  • 示例值 - *
  • 描述 *
  • * * @author binarywang(Binary Wang) @@ -31,72 +24,72 @@ public abstract class WxPayBaseRequest { /** *
    -   * 公众账号ID
    -   * appid
    -   * 是
    -   * String(32)
    -   * wxd678efh567hg6787
    -   * 微信分配的公众账号ID(企业号corpid即为此appId)
    +   * 字段名:公众账号ID
    +   * 变量名:appid
    +   * 是否必填:是
    +   * 类型:String(32)
    +   * 示例值:wxd678efh567hg6787
    +   * 描述:微信分配的公众账号ID(企业号corpid即为此appId)
        * 
    */ @XStreamAlias("appid") protected String appid; /** *
    -   * 商户号
    -   * mch_id
    -   * 是
    -   * String(32)
    -   * 1230000109
    -   * 微信支付分配的商户号
    +   * 字段名:商户号
    +   * 变量名:mch_id
    +   * 是否必填:是
    +   * 类型:String(32)
    +   * 示例值:1230000109
    +   * 描述:微信支付分配的商户号
        * 
    */ @XStreamAlias("mch_id") protected String mchId; /** *
    -   * 服务商模式下的子商户公众账号ID
    -   * sub_appid
    -   * 是
    -   * String(32)
    -   * wxd678efh567hg6787
    -   * 微信分配的子商户公众账号ID
    +   * 字段名:服务商模式下的子商户公众账号ID
    +   * 变量名:sub_appid
    +   * 是否必填:是
    +   * 类型:String(32)
    +   * 示例值:wxd678efh567hg6787
    +   * 描述:微信分配的子商户公众账号ID
        * 
    */ @XStreamAlias("sub_appid") protected String subAppId; /** *
    -   * 服务商模式下的子商户号
    -   * sub_mch_id
    -   * 是
    -   * String(32)
    -   * 1230000109
    -   * 微信支付分配的子商户号,开发者模式下必填
    +   * 字段名:服务商模式下的子商户号
    +   * 变量名:sub_mch_id
    +   * 是否必填:是
    +   * 类型:String(32)
    +   * 示例值:1230000109
    +   * 描述:微信支付分配的子商户号,开发者模式下必填
        * 
    */ @XStreamAlias("sub_mch_id") protected String subMchId; /** *
    -   * 随机字符串
    -   * nonce_str
    -   * 是
    -   * String(32)
    -   * 5K8264ILTKCH16CQ2502SI8ZNMTM67VS
    -   * 随机字符串,不长于32位。推荐随机数生成算法
    +   * 字段名:随机字符串
    +   * 变量名:nonce_str
    +   * 是否必填:是
    +   * 类型:String(32)
    +   * 示例值:5K8264ILTKCH16CQ2502SI8ZNMTM67VS
    +   * 描述:随机字符串,不长于32位。推荐随机数生成算法
        * 
    */ @XStreamAlias("nonce_str") protected String nonceStr; /** *
    -   * 签名
    -   * sign
    -   * 是
    -   * String(32)
    -   * C380BEC2BFD727A4B6845133519F3AD6
    -   * 签名,详见签名生成算法
    +   * 字段名:签名
    +   * 变量名:sign
    +   * 是否必填:是
    +   * 类型:String(32)
    +   * 示例值:C380BEC2BFD727A4B6845133519F3AD6
    +   * 描述:签名,详见签名生成算法
        * 
    */ @XStreamAlias("sign") diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index 03640eb067..f2106c7260 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -1,5 +1,7 @@ package com.github.binarywang.wxpay.service; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.config.WxPayConfig; @@ -339,4 +341,14 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri *
    */ String getSandboxSignKey() throws WxPayException; + + /** + *
    +   * 发放代金券
    +   * 接口请求链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/send_coupon
    +   * 是否需要证书:请求需要双向证书。
    +   * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_3
    +   * 
    + */ + WxPayCouponSendResult sendCoupon(WxPayCouponSendRequest request) throws WxPayException; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java index aa9291760c..b1c31b8676 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java @@ -1,6 +1,8 @@ package com.github.binarywang.wxpay.service.impl; import com.github.binarywang.utils.qrcode.QrcodeUtils; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.config.WxPayConfig; @@ -463,4 +465,15 @@ public String getSandboxSignKey() throws WxPayException { result.checkResult(this); return result.getSandboxSignKey(); } + + @Override + public WxPayCouponSendResult sendCoupon(WxPayCouponSendRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/mmpaymkttransfers/send_coupon"; + String responseContent = this.post(url, request.toXML(), true); + WxPayCouponSendResult result = WxPayBaseResult.fromXML(responseContent, WxPayCouponSendResult.class); + result.checkResult(this); + return result; + } } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java similarity index 94% rename from weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java rename to weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java index 1cba44c59b..cc6ab5a0b5 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java @@ -1,6 +1,8 @@ package com.github.binarywang.wxpay.service.impl; import com.github.binarywang.utils.qrcode.QrcodeUtils; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest; +import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.exception.WxPayException; @@ -26,7 +28,7 @@ */ @Test @Guice(modules = ApiTestModule.class) -public class WxPayServiceImplTest { +public class WxPayServiceAbstractImplTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Inject @@ -271,4 +273,14 @@ public void testGetSandboxSignKey() throws Exception { this.logger.info(signKey); } + @Test + public void testSendCoupon() throws Exception { + WxPayCouponSendResult result = this.payService.sendCoupon(WxPayCouponSendRequest.newBuilder() + .couponStockId("123") + .openid("122") + .partnerTradeNo("1212") + .openidCount(1) + .build()); + this.logger.info(result.toString()); + } } From 22287a482da1ddf20307f474cc385928a87d7be6 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 15 Jul 2017 18:05:00 +0800 Subject: [PATCH 153/179] =?UTF-8?q?#281=20=E6=B6=88=E6=81=AF=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E5=99=A8=E5=A2=9E=E5=8A=A0=E5=AF=B9EventKey=E6=AD=A3?= =?UTF-8?q?=E5=88=99=E8=A1=A8=E8=BE=BE=E5=BC=8F=E5=8C=B9=E9=85=8D=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cp/message/WxCpMessageRouterRule.java | 25 +++++++++++++------ .../weixin/mp/api/WxMpMessageRouterRule.java | 25 +++++++++++++------ .../weixin/mp/api/WxMpMessageRouterTest.java | 1 + 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java index 5f41f61783..b5912404ce 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java @@ -6,6 +6,7 @@ import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; +import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.HashMap; @@ -27,6 +28,8 @@ public class WxCpMessageRouterRule { private String eventKey; + private String eventKeyRegex; + private String content; private String rContent; @@ -95,6 +98,14 @@ public WxCpMessageRouterRule eventKey(String eventKey) { return this; } + /** + * 如果eventKey匹配该正则表达式 + */ + public WxCpMessageRouterRule eventKeyRegex(String regex) { + this.eventKeyRegex = regex; + return this; + } + /** * 如果content等于某值 * @@ -207,17 +218,17 @@ protected boolean test(WxCpXmlMessage wxMessage) { && (this.agentId == null || this.agentId.equals(wxMessage.getAgentId())) && - (this.msgType == null || this.msgType.equals(wxMessage.getMsgType())) + (this.msgType == null || this.msgType.equalsIgnoreCase(wxMessage.getMsgType())) + && + (this.event == null || this.event.equalsIgnoreCase(wxMessage.getEvent())) && - (this.event == null || this.event.equals(wxMessage.getEvent())) + (this.eventKey == null || this.eventKey.equalsIgnoreCase(wxMessage.getEventKey())) && - (this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey())) + (this.eventKeyRegex == null || Pattern.matches(this.eventKeyRegex, StringUtils.trimToEmpty(wxMessage.getEventKey()))) && - (this.content == null || this.content - .equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) + (this.content == null || this.content.equals(StringUtils.trimToNull(wxMessage.getContent()))) && - (this.rContent == null || Pattern - .matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) + (this.rContent == null || Pattern.matches(this.rContent, StringUtils.trimToEmpty(wxMessage.getContent()))) && (this.matcher == null || this.matcher.match(wxMessage)) ; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java index e44406f4b1..50e30af6b7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java @@ -5,6 +5,7 @@ import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.HashMap; @@ -26,6 +27,8 @@ public class WxMpMessageRouterRule { private String eventKey; + private String eventKeyRegex; + private String content; private String rContent; @@ -74,6 +77,14 @@ public WxMpMessageRouterRule eventKey(String eventKey) { return this; } + /** + * 如果eventKey匹配该正则表达式 + */ + public WxMpMessageRouterRule eventKeyRegex(String regex) { + this.eventKeyRegex = regex; + return this; + } + /** * 如果content等于某值 */ @@ -170,17 +181,17 @@ protected boolean test(WxMpXmlMessage wxMessage) { return (this.fromUser == null || this.fromUser.equals(wxMessage.getFromUser())) && - (this.msgType == null || this.msgType.toLowerCase().equals((wxMessage.getMsgType() == null ? null : wxMessage.getMsgType().toLowerCase()))) + (this.msgType == null || this.msgType.equalsIgnoreCase(wxMessage.getMsgType())) + && + (this.event == null || this.event.equalsIgnoreCase(wxMessage.getEvent())) && - (this.event == null || this.event.toLowerCase().equals((wxMessage.getEvent() == null ? null : wxMessage.getEvent().toLowerCase()))) + (this.eventKey == null || this.eventKey.equalsIgnoreCase(wxMessage.getEventKey())) && - (this.eventKey == null || this.eventKey.toLowerCase().equals((wxMessage.getEventKey() == null ? null : wxMessage.getEventKey().toLowerCase()))) + (this.eventKeyRegex == null || Pattern.matches(this.eventKeyRegex, StringUtils.trimToEmpty(wxMessage.getEventKey()))) && - (this.content == null || this.content - .equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) + (this.content == null || this.content.equals(StringUtils.trimToNull(wxMessage.getContent()))) && - (this.rContent == null || Pattern - .matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) + (this.rContent == null || Pattern.matches(this.rContent, StringUtils.trimToEmpty(wxMessage.getContent()))) && (this.matcher == null || this.matcher.match(wxMessage)) ; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java index 4360440f04..35d13ee1e9 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java @@ -39,6 +39,7 @@ public void prepare(boolean async, StringBuffer sb, WxMpMessageRouter router) { .rule().async(async).msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoMpMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end() .rule().async(async).event(WxConsts.EVT_CLICK).handler(new WxEchoMpMessageHandler(sb, WxConsts.EVT_CLICK)).end() .rule().async(async).eventKey("KEY_1").handler(new WxEchoMpMessageHandler(sb, "KEY_1")).end() + .rule().async(async).eventKeyRegex("KEY_1*").handler(new WxEchoMpMessageHandler(sb, "KEY_123")).end() .rule().async(async).content("CONTENT_1").handler(new WxEchoMpMessageHandler(sb, "CONTENT_1")).end() .rule().async(async).rContent(".*bc.*").handler(new WxEchoMpMessageHandler(sb, "abcd")).end() .rule().async(async).matcher(new WxMpMessageMatcher() { From 9368177d0058b5030b5003767b9f437041e78d29 Mon Sep 17 00:00:00 2001 From: mgcnrx11 Date: Sat, 15 Jul 2017 18:53:23 +0800 Subject: [PATCH 154/179] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BC=9A=E5=91=98?= =?UTF-8?q?=E5=8D=A1=E7=AE=A1=E7=90=86=E6=9C=8D=E5=8A=A1=E7=9A=84`?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BC=9A=E5=91=98=E4=BF=A1=E6=81=AF`?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=9A=84=E5=AE=9E=E7=8E=B0=20(#283)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修复UserInfo反序列化的bug,补充其单元测试 * 增加`更新会员信息`接口的实现 * 增加会员卡相关接口的测试类 包含下述方法: 1. 会员卡激活接口 2. 会员信息获取接口 3. 更新会员信息接口 --- .../weixin/mp/api/WxMpMemberCardService.java | 15 ++ .../api/impl/WxMpMemberCardServiceImpl.java | 26 +++ .../mp/bean/membercard/NotifyOptional.java | 73 ++++++++ .../WxMpMemberCardUpdateMessage.java | 156 ++++++++++++++++++ .../WxMpMemberCardUpdateResult.java | 82 +++++++++ .../WxMpMemberCardUserInfoResult.java | 6 + .../weixin/mp/util/json/WxMpGsonBuilder.java | 2 + ...WxMpMemberCardUpdateResultGsonAdapter.java | 37 +++++ ...MpMemberCardUserInfoResultGsonAdapter.java | 7 +- .../impl/WxMpMemberCardServiceImplTest.java | 61 +++++++ .../WxMpMemberCardUpdateResultTest.java | 33 ++++ .../WxMpMemberCardUserInfoResultTest.java | 80 +++++++++ 12 files changed, 574 insertions(+), 4 deletions(-) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/NotifyOptional.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateMessage.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUpdateResultGsonAdapter.java create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImplTest.java create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResultTest.java create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResultTest.java diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java index 89b9fd74ea..7cebb8c858 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java @@ -2,6 +2,8 @@ import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardActivatedMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateResult; import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult; /** @@ -35,4 +37,17 @@ public interface WxMpMemberCardService { * @throws WxErrorException 接口调用失败抛出的异常 */ WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) throws WxErrorException; + + /** + * 当会员持卡消费后,支持开发者调用该接口更新会员信息。会员卡交易后的每次信息变更需通过该接口通知微信,便于后续消息通知及其他扩展功能。 + * + * 1.开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。同时传入add_bonus和bonus时 + * add_bonus作为积分变动消息中的变量值,而bonus作为卡面上的总积分额度显示。余额变动同理。 + * 2.开发者可以传入is_notify_bonus控制特殊的积分对账变动不发送消息,余额变动同理。 + * + * @param updateUserMessage 更新会员信息所需字段消息 + * @return 调用返回的JSON字符串。 + * @throws WxErrorException 接口调用失败抛出的异常 + */ + WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessage updateUserMessage) throws WxErrorException; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java index 24c70ebe9f..b3a43a765a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java @@ -9,6 +9,8 @@ import me.chanjar.weixin.mp.api.WxMpMemberCardService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardActivatedMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateResult; import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import org.slf4j.Logger; @@ -26,6 +28,7 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService { private static final String MEMBER_CARD_ACTIVATE = "https://api.weixin.qq.com/card/membercard/activate"; private static final String MEMBER_CARD_USER_INFO_GET = "https://api.weixin.qq.com/card/membercard/userinfo/get"; + private static final String MEMBER_CARD_UPDATE_USER = "https://api.weixin.qq.com/card/membercard/updateuser"; private WxMpService wxMpService; @@ -75,4 +78,27 @@ public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) thro new TypeToken() { }.getType()); } + + /** + * 当会员持卡消费后,支持开发者调用该接口更新会员信息。会员卡交易后的每次信息变更需通过该接口通知微信,便于后续消息通知及其他扩展功能。 + * + * 1.开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。同时传入add_bonus和bonus时 + * add_bonus作为积分变动消息中的变量值,而bonus作为卡面上的总积分额度显示。余额变动同理。 + * 2.开发者可以传入is_notify_bonus控制特殊的积分对账变动不发送消息,余额变动同理。 + * + * @param updateUserMessage 更新会员信息所需字段消息 + * @return 调用返回的JSON字符串。 + * @throws WxErrorException 接口调用失败抛出的异常 + */ + @Override + public WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessage updateUserMessage) + throws WxErrorException { + + String responseContent = this.getWxMpService().post(MEMBER_CARD_UPDATE_USER, GSON.toJson(updateUserMessage)); + + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, + new TypeToken() { + }.getType()); + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/NotifyOptional.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/NotifyOptional.java new file mode 100644 index 0000000000..a8adae8ac7 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/NotifyOptional.java @@ -0,0 +1,73 @@ +package me.chanjar.weixin.mp.bean.membercard; + +import com.google.gson.annotations.SerializedName; + +/** + * 控制原生消息结构体,包含各字段的消息控制字段。 + * + * 用于 `7 更新会员信息` 的接口参数调用 + * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025283 + * + * @author YuJian(mgcnrx11@gmail.com) + * @version 2017/7/15 + */ +public class NotifyOptional { + + // 积分变动时是否触发系统模板消息,默认为true + @SerializedName("is_notify_bonus") + private Boolean isNotifyBonus; + + // 余额变动时是否触发系统模板消息,默认为true + @SerializedName("is_notify_balance") + private Boolean isNotifyBalance; + + // 自定义group1变动时是否触发系统模板消息,默认为false。(2、3同理) + @SerializedName("is_notify_custom_field1") + private Boolean isNotifyCustomField1; + + @SerializedName("is_notify_custom_field2") + private Boolean isNotifyCustomField2; + + @SerializedName("is_notify_custom_field3") + private Boolean isNotifyCustomField3; + + public Boolean getNotifyBonus() { + return isNotifyBonus; + } + + public void setNotifyBonus(Boolean notifyBonus) { + isNotifyBonus = notifyBonus; + } + + public Boolean getNotifyBalance() { + return isNotifyBalance; + } + + public void setNotifyBalance(Boolean notifyBalance) { + isNotifyBalance = notifyBalance; + } + + public Boolean getNotifyCustomField1() { + return isNotifyCustomField1; + } + + public void setNotifyCustomField1(Boolean notifyCustomField1) { + isNotifyCustomField1 = notifyCustomField1; + } + + public Boolean getNotifyCustomField2() { + return isNotifyCustomField2; + } + + public void setNotifyCustomField2(Boolean notifyCustomField2) { + isNotifyCustomField2 = notifyCustomField2; + } + + public Boolean getNotifyCustomField3() { + return isNotifyCustomField3; + } + + public void setNotifyCustomField3(Boolean notifyCustomField3) { + isNotifyCustomField3 = notifyCustomField3; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateMessage.java new file mode 100644 index 0000000000..f4d410185d --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateMessage.java @@ -0,0 +1,156 @@ +package me.chanjar.weixin.mp.bean.membercard; + +import com.google.gson.annotations.SerializedName; + +/** + * 更新会员信息所需字段消息。 + * + * 1.开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。同时传入add_bonus和bonus时 + * add_bonus作为积分变动消息中的变量值,而bonus作为卡面上的总积分额度显示。余额变动同理。 + * 2.开发者可以传入is_notify_bonus控制特殊的积分对账变动不发送消息,余额变动同理。 + * + * @author YuJian(mgcnrx11@gmail.com) + * @version 2017/7/15 + */ +public class WxMpMemberCardUpdateMessage { + + // 领取会员卡用户获得的code + private String code; + // 卡券ID,自定义code卡券必填 + @SerializedName("card_id") + private String cardId; + // 支持商家激活时针对单个会员卡分配自定义的会员卡背景 + @SerializedName("background_pic_url") + private String backgroundPicUrl; + // 需要设置的积分全量值,传入的数值会直接显示 + private Integer bonus; + // 本次积分变动值,传负数代表减少 + @SerializedName("add_bonus") + private Integer addBounus; + // 商家自定义积分消耗记录,不超过14个汉字 + @SerializedName("record_bonus") + private String recordBonus; + // 需要设置的余额全量值,传入的数值会直接显示在卡面 + private Integer balance; + // 本次余额变动值,传负数代表减少 + @SerializedName("add_balance") + private Integer addBalance; + // 商家自定义金额消耗记录,不超过14个汉字。 + @SerializedName("record_balance") + private String recordBalance; + + // 创建时字段custom_field定义类型的最新数值,限制为4个汉字,12字节。 + @SerializedName("custom_field_value1") + private String customFieldValue1; + @SerializedName("custom_field_value2") + private String customFieldValue2; + @SerializedName("custom_field_value3") + private String customFieldValue3; + + @SerializedName("notify_optional") + private NotifyOptional notifyOptional; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getCardId() { + return cardId; + } + + public void setCardId(String cardId) { + this.cardId = cardId; + } + + public String getBackgroundPicUrl() { + return backgroundPicUrl; + } + + public void setBackgroundPicUrl(String backgroundPicUrl) { + this.backgroundPicUrl = backgroundPicUrl; + } + + public Integer getBonus() { + return bonus; + } + + public void setBonus(Integer bonus) { + this.bonus = bonus; + } + + public Integer getAddBounus() { + return addBounus; + } + + public void setAddBounus(Integer addBounus) { + this.addBounus = addBounus; + } + + public String getRecordBonus() { + return recordBonus; + } + + public void setRecordBonus(String recordBonus) { + this.recordBonus = recordBonus; + } + + public Integer getBalance() { + return balance; + } + + public void setBalance(Integer balance) { + this.balance = balance; + } + + public Integer getAddBalance() { + return addBalance; + } + + public void setAddBalance(Integer addBalance) { + this.addBalance = addBalance; + } + + public String getRecordBalance() { + return recordBalance; + } + + public void setRecordBalance(String recordBalance) { + this.recordBalance = recordBalance; + } + + public String getCustomFieldValue1() { + return customFieldValue1; + } + + public void setCustomFieldValue1(String customFieldValue1) { + this.customFieldValue1 = customFieldValue1; + } + + public String getCustomFieldValue2() { + return customFieldValue2; + } + + public void setCustomFieldValue2(String customFieldValue2) { + this.customFieldValue2 = customFieldValue2; + } + + public String getCustomFieldValue3() { + return customFieldValue3; + } + + public void setCustomFieldValue3(String customFieldValue3) { + this.customFieldValue3 = customFieldValue3; + } + + public NotifyOptional getNotifyOptional() { + return notifyOptional; + } + + public void setNotifyOptional(NotifyOptional notifyOptional) { + this.notifyOptional = notifyOptional; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java new file mode 100644 index 0000000000..e615cb0721 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java @@ -0,0 +1,82 @@ +package me.chanjar.weixin.mp.bean.membercard; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * 用于 `7 更新会员信息` 的接口调用后的返回结果 + * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025283 + * + * @author YuJian(mgcnrx11@gmail.com) + * @version 2017/7/15 + */ +public class WxMpMemberCardUpdateResult implements Serializable { + + private static final long serialVersionUID = 9084886191442098311L; + + private String errorCode; + + private String errorMsg; + + private String openId; + + private Integer resultBonus; + + private Integer resultBalance; + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public Integer getResultBonus() { + return resultBonus; + } + + public void setResultBonus(Integer resultBonus) { + this.resultBonus = resultBonus; + } + + public Integer getResultBalance() { + return resultBalance; + } + + public void setResultBalance(Integer resultBalance) { + this.resultBalance = resultBalance; + } + + @Override + public String toString() { + return "WxMpMemberCardUpdateResult{" + + "errorCode='" + errorCode + '\'' + + ", errorMsg='" + errorMsg + '\'' + + ", openId='" + openId + '\'' + + ", resultBonus=" + resultBonus + + ", resultBalance=" + resultBalance + + '}'; + } + + public static WxMpMemberCardUpdateResult fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpMemberCardUpdateResult.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java index b3691da6dd..1ddb57d34b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java @@ -1,5 +1,7 @@ package me.chanjar.weixin.mp.bean.membercard; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + import java.io.Serializable; /** @@ -133,5 +135,9 @@ public String toString() { ", hasActive=" + hasActive + '}'; } + + public static WxMpMemberCardUserInfoResult fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpMemberCardUserInfoResult.class); + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java index 8fca5a6a88..124845ed6b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java @@ -6,6 +6,7 @@ import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate; import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateResult; import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult; import me.chanjar.weixin.mp.bean.material.*; import me.chanjar.weixin.mp.bean.result.*; @@ -51,6 +52,7 @@ public class WxMpGsonBuilder { INSTANCE.registerTypeAdapter(WxMpTemplateIndustry.class, new WxMpIndustryGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpUserBlacklistGetResult.class, new WxUserBlacklistGetResultGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpMemberCardUserInfoResult.class, new WxMpMemberCardUserInfoResultGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpMemberCardUpdateResult.class, new WxMpMemberCardUpdateResultGsonAdapter()); } public static Gson create() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUpdateResultGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUpdateResultGsonAdapter.java new file mode 100644 index 0000000000..dc068db1e8 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUpdateResultGsonAdapter.java @@ -0,0 +1,37 @@ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateResult; + +import java.lang.reflect.Type; + +/** + * Json to WxMpMemberCardUpdateResult 的转换适配器 + * + * @author YuJian + * @version 2017/7/15 + */ +public class WxMpMemberCardUpdateResultGsonAdapter implements JsonDeserializer { + + @Override + public WxMpMemberCardUpdateResult deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext + jsonDeserializationContext) throws JsonParseException { + + WxMpMemberCardUpdateResult result = new WxMpMemberCardUpdateResult(); + + JsonObject jsonObject = jsonElement.getAsJsonObject(); + + result.setOpenId(GsonHelper.getString(jsonObject, "openid")); + result.setErrorCode(GsonHelper.getString(jsonObject, "errcode")); + result.setErrorMsg(GsonHelper.getString(jsonObject, "errmsg")); + result.setResultBalance(GsonHelper.getInteger(jsonObject, "result_balance")); + result.setResultBonus(GsonHelper.getInteger(jsonObject, "result_bonus")); + + return result; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUserInfoResultGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUserInfoResultGsonAdapter.java index 021ea60226..5a97ee7496 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUserInfoResultGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMemberCardUserInfoResultGsonAdapter.java @@ -9,9 +9,9 @@ import java.lang.reflect.Type; /** - * Created by YuJian on 2017/7/11. + * Json to WxMpMemberCardUserInfoResult 的转换适配器 * - * @author YuJian + * @author YuJian(mgcnrx11@gmail.com) * @version 2017/7/11 */ public class WxMpMemberCardUserInfoResultGsonAdapter implements JsonDeserializer { @@ -57,8 +57,7 @@ public WxMpMemberCardUserInfoResult deserialize(JsonElement jsonElement, Type ty JsonArray valueListArray = customField.getAsJsonArray("value_list"); String[] valueList = new String[valueListArray.size()]; for (int j = 0; j < valueListArray.size(); j++) { - JsonObject valueListObj = valueListArray.getAsJsonObject(); - valueList[i] = valueListObj.getAsString(); + valueList[j] = valueListArray.get(j).getAsString(); } customNameValues.setValueList(valueList); customFieldListValues[i] = customNameValues; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImplTest.java new file mode 100644 index 0000000000..67eb5817cc --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImplTest.java @@ -0,0 +1,61 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.test.ApiTestModule; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardActivatedMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateResult; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import static org.testng.AssertJUnit.assertNotNull; + +/** + * 会员卡相关接口的测试类。 + * 数据均为测试数据,由于直接与调用微信的接口,需要填写真实数据进行测试才能通过。 + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMpMemberCardServiceImplTest { + + @Inject + protected WxMpService wxService; + private String cardId = "abc"; + private String code = "123"; + private String openId = "xyz"; + + @Test + public void testActivateMemberCard() throws Exception { + WxMpMemberCardActivatedMessage activatedMessage = new WxMpMemberCardActivatedMessage(); + activatedMessage.setMembershipNumber(openId); + activatedMessage.setCode(code); + activatedMessage.setCardId(cardId); + activatedMessage.setInitBonus(2000); + activatedMessage.setInitBonusRecord("测试激活送积分"); + String response = this.wxService.getMemberCardService().activateMemberCard(activatedMessage); + assertNotNull(response); + System.out.println(response); + } + + @Test + public void testGetUserInfo() throws Exception { + WxMpMemberCardUserInfoResult result = this.wxService.getMemberCardService().getUserInfo(cardId, code); + assertNotNull(result); + System.out.println(result); + } + + @Test + public void testUpdateUserMemberCard() throws Exception { + WxMpMemberCardUpdateMessage updateMessage = new WxMpMemberCardUpdateMessage(); + updateMessage.setAddBounus(100); + updateMessage.setBonus(1000); + updateMessage.setCardId(cardId); + updateMessage.setCode(code); + WxMpMemberCardUpdateResult result = this.wxService.getMemberCardService().updateUserMemberCard(updateMessage); + assertNotNull(result); + System.out.println(result); + } + +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResultTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResultTest.java new file mode 100644 index 0000000000..f7860e7c85 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResultTest.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.mp.bean.membercard; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +/** + * + * @author YuJian + * @version 2017/7/15 + */ +public class WxMpMemberCardUpdateResultTest { + + @Test + public void testFromJson() throws Exception { + String json = "{\n" + + " \"errcode\": 0,\n" + + " \"errmsg\": \"ok\",\n" + + " \"result_bonus\": 100,\n" + + " \"result_balance\": 200,\n" + + " \"openid\": \"oFS7Fjl0WsZ9AMZqrI80nbIq8xrA\"\n" + + "}"; + + WxMpMemberCardUpdateResult result = WxMpMemberCardUpdateResult.fromJson(json); + + assertNotNull(result); + assertTrue(result.getErrorCode().equalsIgnoreCase("0")); + + System.out.println(result); + } +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResultTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResultTest.java new file mode 100644 index 0000000000..da8ff3da36 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResultTest.java @@ -0,0 +1,80 @@ +package me.chanjar.weixin.mp.bean.membercard; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +/** + * + * @author YuJian + * @version 2017/7/15 + */ +public class WxMpMemberCardUserInfoResultTest { + + @Test + public void testFromJson() throws Exception { + String json = "{\n" + + " \"errcode\": 0,\n" + + " \"errmsg\": \"ok\",\n" + + " \"openid\": \"obLatjjwDolFj******wNqRXw\",\n" + + " \"nickname\": \"*******\",\n" + + " \"membership_number\": \"658*****445\",\n" + + " \"bonus\": 995,\n" + + " \"sex\": \"MALE\",\n" + + " \"user_info\": {\n" + + " \"common_field_list\": [\n" + + " {\n" + + " \"name\": \"USER_FORM_INFO_FLAG_MOBILE\",\n" + + " \"value\": \"15*****518\"\n" + + " },\n" + + " {\n" + + " \"name\": \"USER_FORM_INFO_FLAG_NAME\",\n" + + " \"value\": \"HK\"\n" + + " },\n" + + " {\n" + + " \"name\": \"USER_FORM_INFO_FLAG_EDUCATION_BACKGROUND\",\n" + + " \"value\": \"研究生\"\n" + + " }\n" + + " ],\n" + + " \"custom_field_list\": [\n" + + " {\n" + + " \"name\": \"兴趣\",\n" + + " \"value\": \"钢琴\",\n" + + " \"value_list\": []\n" + + " },\n" + + " {\n" + + " \"name\": \"喜好\",\n" + + " \"value\": \"郭敬明\",\n" + + " \"value_list\": []\n" + + " },\n" + + " {\n" + + " \"name\": \"职业\",\n" + + " \"value\": \"\",\n" + + " \"value_list\": [\n" + + " \"赛车手\",\n" + + " \"旅行家\"\n" + + " ]\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"user_card_status\": \"NORMAL\",\n" + + " \"has_active\": false\n" + + "}"; + + + WxMpMemberCardUserInfoResult userInfoResult = WxMpMemberCardUserInfoResult.fromJson(json); + + assertNotNull(userInfoResult); + assertFalse(userInfoResult.getHasActive()); + assertTrue(userInfoResult.getSex().equalsIgnoreCase("MALE")); + assertNotNull(userInfoResult.getUserInfo()); + assertNotNull(userInfoResult.getUserInfo().getCommonFieldList()); + assertNotNull(userInfoResult.getUserInfo().getCustomFieldList()); + assertTrue(userInfoResult.getUserInfo().getCommonFieldList().length == 3); + assertTrue(userInfoResult.getUserInfo().getCustomFieldList()[2].getValueList()[0].equalsIgnoreCase("赛车手")); + + System.out.println(userInfoResult); + } +} From 9f669dff8285942c8b0b3221a3d9ce839a0a4f6a Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 15 Jul 2017 19:16:52 +0800 Subject: [PATCH 155/179] =?UTF-8?q?#178=20=E5=AE=9E=E7=8E=B0=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E4=BB=A3=E9=87=91=E5=88=B8=E6=89=B9=E6=AC=A1=E5=92=8C?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coupon/WxPayCouponInfoQueryRequest.java | 280 ++++++++++++++ .../coupon/WxPayCouponInfoQueryResult.java | 351 ++++++++++++++++++ .../coupon/WxPayCouponStockQueryRequest.java | 221 +++++++++++ .../coupon/WxPayCouponStockQueryResult.java | 288 ++++++++++++++ .../wxpay/service/WxPayService.java | 21 +- .../impl/WxPayServiceAbstractImpl.java | 25 +- .../impl/WxPayServiceAbstractImplTest.java | 21 +- 7 files changed, 1201 insertions(+), 6 deletions(-) create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryRequest.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryResult.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryRequest.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryResult.java diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryRequest.java new file mode 100644 index 0000000000..3d83d0a6c6 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryRequest.java @@ -0,0 +1,280 @@ +package com.github.binarywang.wxpay.bean.coupon; + +import com.github.binarywang.wxpay.bean.request.WxPayBaseRequest; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import me.chanjar.weixin.common.annotation.Required; + +/** + *
    + * 查询代金券信息请求对象类
    + * Created by Binary Wang on 2017-7-15.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxPayCouponInfoQueryRequest extends WxPayBaseRequest { + /** + *
    +   * 字段名:代金券id
    +   * 变量名:coupon_id
    +   * 是否必填:是
    +   * 示例值:1757
    +   * 类型:String
    +   * 说明:代金券id
    +   * 
    + */ + @Required + @XStreamAlias("coupon_id") + private String couponId; + + /** + *
    +   * 字段名:代金券批次号
    +   * 变量名:stock_id
    +   * 是否必填:是
    +   * 示例值:58818
    +   * 类型:String
    +   * 说明:代金劵对应的批次号
    +   * 
    + */ + @Required + @XStreamAlias("stock_id") + private String stockId; + + /** + *
    +   * 字段名:用户openid
    +   * 变量名:openid
    +   * 是否必填:是
    +   * 示例值:onqOjjrXT-776SpHnfexGm1_P7iE
    +   * 类型:String
    +   * 说明:Openid信息,用户在appid下的openid。
    +   * 
    + */ + @Required + @XStreamAlias("openid") + private String openid; + + /** + *
    +   * 字段名:操作员
    +   * 变量名:op_user_id
    +   * 是否必填:否
    +   * 示例值:10000098
    +   * 类型:String(32)
    +   * 说明:操作员帐号, 默认为商户号,可在商户平台配置操作员对应的api权限
    +   * 
    + */ + @XStreamAlias("op_user_id") + private String opUserId; + + /** + *
    +   * 字段名:设备号
    +   * 变量名:device_info
    +   * 是否必填:否
    +   * 示例值:
    +   * 类型:String(32)
    +   * 说明:微信支付分配的终端设备号
    +   * 
    + */ + @XStreamAlias("device_info") + private String deviceInfo; + + /** + *
    +   * 字段名:协议版本
    +   * 变量名:version
    +   * 是否必填:否
    +   * 示例值:1.0
    +   * 类型:String(32)
    +   * 说明:默认1.0
    +   * 
    + */ + @XStreamAlias("version") + private String version; + + /** + *
    +   * 字段名:协议类型
    +   * 变量名:type
    +   * 是否必填:否
    +   * 示例值:XML
    +   * 类型:String(32)
    +   * 说明:XML【目前仅支持默认XML】
    +   * 
    + */ + @XStreamAlias("type") + private String type; + + private WxPayCouponInfoQueryRequest(Builder builder) { + setAppid(builder.appid); + setMchId(builder.mchId); + setSubAppId(builder.subAppId); + setSubMchId(builder.subMchId); + setNonceStr(builder.nonceStr); + setSign(builder.sign); + setCouponId(builder.couponId); + setStockId(builder.stockId); + setOpenid(builder.openid); + setOpUserId(builder.opUserId); + setDeviceInfo(builder.deviceInfo); + setVersion(builder.version); + setType(builder.type); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public String getCouponId() { + return this.couponId; + } + + public void setCouponId(String couponId) { + this.couponId = couponId; + } + + public String getStockId() { + return this.stockId; + } + + public void setStockId(String stockId) { + this.stockId = stockId; + } + + public String getOpenid() { + return this.openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public String getOpUserId() { + return this.opUserId; + } + + public void setOpUserId(String opUserId) { + this.opUserId = opUserId; + } + + public String getDeviceInfo() { + return this.deviceInfo; + } + + public void setDeviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + } + + public String getVersion() { + return this.version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + protected void checkConstraints() { + //do nothing + } + + + public static final class Builder { + private String appid; + private String mchId; + private String subAppId; + private String subMchId; + private String nonceStr; + private String sign; + private String couponId; + private String stockId; + private String openid; + private String opUserId; + private String deviceInfo; + private String version; + private String type; + + private Builder() { + } + + public Builder appid(String appid) { + this.appid = appid; + return this; + } + + public Builder mchId(String mchId) { + this.mchId = mchId; + return this; + } + + public Builder subAppId(String subAppId) { + this.subAppId = subAppId; + return this; + } + + public Builder subMchId(String subMchId) { + this.subMchId = subMchId; + return this; + } + + public Builder nonceStr(String nonceStr) { + this.nonceStr = nonceStr; + return this; + } + + public Builder sign(String sign) { + this.sign = sign; + return this; + } + + public Builder couponId(String couponId) { + this.couponId = couponId; + return this; + } + + public Builder stockId(String stockId) { + this.stockId = stockId; + return this; + } + + public Builder openid(String openid) { + this.openid = openid; + return this; + } + + public Builder opUserId(String opUserId) { + this.opUserId = opUserId; + return this; + } + + public Builder deviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + return this; + } + + public Builder version(String version) { + this.version = version; + return this; + } + + public Builder type(String type) { + this.type = type; + return this; + } + + public WxPayCouponInfoQueryRequest build() { + return new WxPayCouponInfoQueryRequest(this); + } + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryResult.java new file mode 100644 index 0000000000..bec1c9e10a --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryResult.java @@ -0,0 +1,351 @@ +package com.github.binarywang.wxpay.bean.coupon; + +import com.github.binarywang.wxpay.bean.result.WxPayBaseResult; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + *
    + * 查询代金券信息响应结果类
    + * Created by Binary Wang on 2017-7-15.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxPayCouponInfoQueryResult extends WxPayBaseResult { + /** + *
    +   * 字段名:设备号
    +   * 变量名:device_info
    +   * 是否必填:否
    +   * 示例值:123456sb
    +   * 类型:String(32)
    +   * 说明:微信支付分配的终端设备号,
    +   * 
    + */ + @XStreamAlias("device_info") + private String deviceInfo; + + /** + *
    +   * 字段名:批次ID
    +   * 变量名:coupon_stock_id
    +   * 是否必填:是
    +   * 示例值:1567
    +   * 类型:String
    +   * 说明:代金券批次Id
    +   * 
    + */ + @XStreamAlias("coupon_stock_id") + private String couponStockId; + + /** + *
    +   * 字段名:代金券id
    +   * 变量名:coupon_id
    +   * 是否必填:是
    +   * 示例值:4242
    +   * 类型:String
    +   * 说明:代金券id
    +   * 
    + */ + @XStreamAlias("coupon_id") + private String couponId; + + /** + *
    +   * 字段名:代金券面额
    +   * 变量名:coupon_value
    +   * 是否必填:是
    +   * 示例值:4
    +   * 类型:Unsinged int
    +   * 说明:代金券面值,单位是分
    +   * 
    + */ + @XStreamAlias("coupon_value") + private Integer couponValue; + + /** + *
    +   * 字段名:代金券使用门槛
    +   * 变量名:coupon_mininum
    +   * 是否必填:是
    +   * 示例值:10
    +   * 类型:Unsinged int
    +   * 说明:代金券使用最低限额,单位是分
    +   * 
    + */ + @XStreamAlias("coupon_mininum") + private Integer couponMininum; + + /** + *
    +   * 字段名:代金券名称
    +   * 变量名:coupon_name
    +   * 是否必填:是
    +   * 示例值:测试代金券
    +   * 类型:String
    +   * 说明:代金券名称
    +   * 
    + */ + @XStreamAlias("coupon_name") + private String couponName; + + /** + *
    +   * 字段名:代金券状态
    +   * 变量名:coupon_state
    +   * 是否必填:是
    +   * 示例值:SENDED
    +   * 类型:int
    +   * 说明:代金券状态:SENDED-可用,USED-已实扣,EXPIRED-已过期
    +   * 
    + */ + @XStreamAlias("coupon_state") + private Integer couponState; + + /** + *
    +   * 字段名:代金券描述
    +   * 变量名:coupon_desc
    +   * 是否必填:是
    +   * 示例值:微信支付-代金券
    +   * 类型:String
    +   * 说明:代金券描述
    +   * 
    + */ + @XStreamAlias("coupon_desc") + private String couponDesc; + + /** + *
    +   * 字段名:实际优惠金额
    +   * 变量名:coupon_use_value
    +   * 是否必填:是
    +   * 示例值:0
    +   * 类型:Unsinged int
    +   * 说明:代金券实际使用金额
    +   * 
    + */ + @XStreamAlias("coupon_use_value") + private Integer couponUseValue; + + /** + *
    +   * 字段名:优惠剩余可用额
    +   * 变量名:coupon_remain_value
    +   * 是否必填:是
    +   * 示例值:4
    +   * 类型:Unsinged int
    +   * 说明:代金券剩余金额:部分使用情况下,可能会存在券剩余金额
    +   * 
    + */ + @XStreamAlias("coupon_remain_value") + private Integer couponRemainValue; + + /** + *
    +   * 字段名:生效开始时间
    +   * 变量名:begin_time
    +   * 是否必填:是
    +   * 示例值:1943787483
    +   * 类型:String
    +   * 说明:格式为时间戳
    +   * 
    + */ + @XStreamAlias("begin_time") + private String beginTime; + + /** + *
    +   * 字段名:生效结束时间
    +   * 变量名:end_time
    +   * 是否必填:是
    +   * 示例值:1943787484
    +   * 类型:String
    +   * 说明:格式为时间戳
    +   * 
    + */ + @XStreamAlias("end_time") + private String endTime; + + /** + *
    +   * 字段名:发放时间
    +   * 变量名:send_time
    +   * 是否必填:是
    +   * 示例值:1943787420
    +   * 类型:String
    +   * 说明:格式为时间戳
    +   * 
    + */ + @XStreamAlias("send_time") + private String sendTime; + + /** + *
    +   * 字段名:消耗方商户id
    +   * 变量名:consumer_mch_id
    +   * 是否必填:否
    +   * 示例值:10000098
    +   * 类型:String
    +   * 说明:代金券使用后,消耗方商户id
    +   * 
    + */ + @XStreamAlias("consumer_mch_id") + private String consumerMchId; + + /** + *
    +   * 字段名:发放来源
    +   * 变量名:send_source
    +   * 是否必填:是
    +   * 示例值:FULL_SEND
    +   * 类型:String
    +   * 说明:代金券发放来源:FULL_SEND-满送 NORMAL-普通发放场景
    +   * 
    + */ + @XStreamAlias("send_source") + private String sendSource; + + /** + *
    +   * 字段名:是否允许部分使用
    +   * 变量名:is_partial_use
    +   * 是否必填:否
    +   * 示例值:1
    +   * 类型:String
    +   * 说明:该代金券是否允许部分使用标识:1-表示支持部分使用
    +   * 
    + */ + @XStreamAlias("is_partial_use") + private String isPartialUse; + + public String getDeviceInfo() { + return this.deviceInfo; + } + + public void setDeviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + } + + public String getCouponStockId() { + return this.couponStockId; + } + + public void setCouponStockId(String couponStockId) { + this.couponStockId = couponStockId; + } + + public String getCouponId() { + return this.couponId; + } + + public void setCouponId(String couponId) { + this.couponId = couponId; + } + + public Integer getCouponValue() { + return this.couponValue; + } + + public void setCouponValue(Integer couponValue) { + this.couponValue = couponValue; + } + + public Integer getCouponMininum() { + return this.couponMininum; + } + + public void setCouponMininum(Integer couponMininum) { + this.couponMininum = couponMininum; + } + + public String getCouponName() { + return this.couponName; + } + + public void setCouponName(String couponName) { + this.couponName = couponName; + } + + public Integer getCouponState() { + return this.couponState; + } + + public void setCouponState(Integer couponState) { + this.couponState = couponState; + } + + public String getCouponDesc() { + return this.couponDesc; + } + + public void setCouponDesc(String couponDesc) { + this.couponDesc = couponDesc; + } + + public Integer getCouponUseValue() { + return this.couponUseValue; + } + + public void setCouponUseValue(Integer couponUseValue) { + this.couponUseValue = couponUseValue; + } + + public Integer getCouponRemainValue() { + return this.couponRemainValue; + } + + public void setCouponRemainValue(Integer couponRemainValue) { + this.couponRemainValue = couponRemainValue; + } + + public String getBeginTime() { + return this.beginTime; + } + + public void setBeginTime(String beginTime) { + this.beginTime = beginTime; + } + + public String getEndTime() { + return this.endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public String getSendTime() { + return this.sendTime; + } + + public void setSendTime(String sendTime) { + this.sendTime = sendTime; + } + + public String getConsumerMchId() { + return this.consumerMchId; + } + + public void setConsumerMchId(String consumerMchId) { + this.consumerMchId = consumerMchId; + } + + public String getSendSource() { + return this.sendSource; + } + + public void setSendSource(String sendSource) { + this.sendSource = sendSource; + } + + public String getIsPartialUse() { + return this.isPartialUse; + } + + public void setIsPartialUse(String isPartialUse) { + this.isPartialUse = isPartialUse; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryRequest.java new file mode 100644 index 0000000000..24cec5523c --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryRequest.java @@ -0,0 +1,221 @@ +package com.github.binarywang.wxpay.bean.coupon; + +import com.github.binarywang.wxpay.bean.request.WxPayBaseRequest; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import me.chanjar.weixin.common.annotation.Required; + +/** + *
    + * 查询代金券批次请求对象类
    + * Created by Binary Wang on 2017-7-15.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxPayCouponStockQueryRequest extends WxPayBaseRequest { + /** + *
    +   * 字段名:代金券批次id
    +   * 变量名:coupon_stock_id
    +   * 是否必填:是
    +   * 示例值:1757
    +   * 类型:String
    +   * 说明:代金券批次id
    +   * 
    + */ + @Required + @XStreamAlias("coupon_stock_id") + private String couponStockId; + + /** + *
    +   * 字段名:操作员
    +   * 变量名:op_user_id
    +   * 是否必填:否
    +   * 示例值:10000098
    +   * 类型:String(32)
    +   * 说明:操作员帐号, 默认为商户号,可在商户平台配置操作员对应的api权限
    +   * 
    + */ + @XStreamAlias("op_user_id") + private String opUserId; + + /** + *
    +   * 字段名:设备号
    +   * 变量名:device_info
    +   * 是否必填:否
    +   * 示例值:
    +   * 类型:String(32)
    +   * 说明:微信支付分配的终端设备号
    +   * 
    + */ + @XStreamAlias("device_info") + private String deviceInfo; + + /** + *
    +   * 字段名:协议版本
    +   * 变量名:version
    +   * 是否必填:否
    +   * 示例值:1.0
    +   * 类型:String(32)
    +   * 说明:默认1.0
    +   * 
    + */ + @XStreamAlias("version") + private String version; + + /** + *
    +   * 字段名:协议类型
    +   * 变量名:type
    +   * 是否必填:否
    +   * 示例值:XML
    +   * 类型:String(32)
    +   * 说明:XML【目前仅支持默认XML】
    +   * 
    + */ + @XStreamAlias("type") + private String type; + + private WxPayCouponStockQueryRequest(Builder builder) { + setAppid(builder.appid); + setMchId(builder.mchId); + setSubAppId(builder.subAppId); + setSubMchId(builder.subMchId); + setNonceStr(builder.nonceStr); + setSign(builder.sign); + setCouponStockId(builder.couponStockId); + setOpUserId(builder.opUserId); + setDeviceInfo(builder.deviceInfo); + setVersion(builder.version); + setType(builder.type); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public String getCouponStockId() { + return this.couponStockId; + } + + public void setCouponStockId(String couponStockId) { + this.couponStockId = couponStockId; + } + + public String getOpUserId() { + return this.opUserId; + } + + public void setOpUserId(String opUserId) { + this.opUserId = opUserId; + } + + public String getDeviceInfo() { + return this.deviceInfo; + } + + public void setDeviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + } + + public String getVersion() { + return this.version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + protected void checkConstraints() { + //do nothing + } + + public static final class Builder { + private String appid; + private String mchId; + private String subAppId; + private String subMchId; + private String nonceStr; + private String sign; + private String couponStockId; + private String opUserId; + private String deviceInfo; + private String version; + private String type; + + private Builder() { + } + + public Builder appid(String appid) { + this.appid = appid; + return this; + } + + public Builder mchId(String mchId) { + this.mchId = mchId; + return this; + } + + public Builder subAppId(String subAppId) { + this.subAppId = subAppId; + return this; + } + + public Builder subMchId(String subMchId) { + this.subMchId = subMchId; + return this; + } + + public Builder nonceStr(String nonceStr) { + this.nonceStr = nonceStr; + return this; + } + + public Builder sign(String sign) { + this.sign = sign; + return this; + } + + public Builder couponStockId(String couponStockId) { + this.couponStockId = couponStockId; + return this; + } + + public Builder opUserId(String opUserId) { + this.opUserId = opUserId; + return this; + } + + public Builder deviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + return this; + } + + public Builder version(String version) { + this.version = version; + return this; + } + + public Builder type(String type) { + this.type = type; + return this; + } + + public WxPayCouponStockQueryRequest build() { + return new WxPayCouponStockQueryRequest(this); + } + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryResult.java new file mode 100644 index 0000000000..065c3f606d --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryResult.java @@ -0,0 +1,288 @@ +package com.github.binarywang.wxpay.bean.coupon; + +import com.github.binarywang.wxpay.bean.result.WxPayBaseResult; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + *
    + * 查询代金券批次响应结果类
    + * Created by Binary Wang on 2017-7-15.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxPayCouponStockQueryResult extends WxPayBaseResult { + /** + *
    +   * 字段名:设备号
    +   * 变量名:device_info
    +   * 是否必填:否
    +   * 示例值:123456sb
    +   * 类型:String(32)
    +   * 说明:微信支付分配的终端设备号
    +   * 
    + */ + @XStreamAlias("device_info") + private String deviceInfo; + + /** + *
    +   * 字段名:代金券批次ID
    +   * 变量名:coupon_stock_id
    +   * 是否必填:是
    +   * 示例值:1757
    +   * 类型:String
    +   * 说明:代金券批次Id
    +   * 
    + */ + @XStreamAlias("coupon_stock_id") + private String couponStockId; + + /** + *
    +   * 字段名:代金券名称
    +   * 变量名:coupon_name
    +   * 是否必填:否
    +   * 示例值:测试代金券
    +   * 类型:String
    +   * 说明:代金券名称
    +   * 
    + */ + @XStreamAlias("coupon_name") + private String couponName; + + /** + *
    +   * 字段名:代金券面额
    +   * 变量名:coupon_value
    +   * 是否必填:是
    +   * 示例值:5
    +   * 类型:Unsinged int
    +   * 说明:代金券面值,单位是分
    +   * 
    + */ + @XStreamAlias("coupon_value") + private Integer couponValue; + + /** + *
    +   * 字段名:代金券使用最低限额
    +   * 变量名:coupon_mininumn
    +   * 是否必填:否
    +   * 示例值:10
    +   * 类型:Unsinged int
    +   * 说明:代金券使用最低限额,单位是分
    +   * 
    + */ + @XStreamAlias("coupon_mininumn") + private Integer couponMininumn; + + /** + *
    +   * 字段名:代金券批次状态
    +   * 变量名:coupon_stock_status
    +   * 是否必填:是
    +   * 示例值:4
    +   * 类型:int
    +   * 说明:批次状态: 1-未激活;2-审批中;4-已激活;8-已作废;16-中止发放;
    +   * 
    + */ + @XStreamAlias("coupon_stock_status") + private Integer couponStockStatus; + + /** + *
    +   * 字段名:代金券数量
    +   * 变量名:coupon_total
    +   * 是否必填:是
    +   * 示例值:100
    +   * 类型:Unsigned int
    +   * 说明:代金券数量
    +   * 
    + */ + @XStreamAlias("coupon_total") + private Integer couponTotal; + + /** + *
    +   * 字段名:代金券最大领取数量
    +   * 变量名:max_quota
    +   * 是否必填:否
    +   * 示例值:1
    +   * 类型:Unsigned int
    +   * 说明:代金券每个人最多能领取的数量, 如果为0,则表示没有限制
    +   * 
    + */ + @XStreamAlias("max_quota") + private Integer maxQuota; + + /** + *
    +   * 字段名:代金券已经发送的数量
    +   * 变量名:is_send_num
    +   * 是否必填:否
    +   * 示例值:0
    +   * 类型:Unsigned int
    +   * 说明:代金券已经发送的数量
    +   * 
    + */ + @XStreamAlias("is_send_num") + private Integer isSendNum; + + /** + *
    +   * 字段名:生效开始时间
    +   * 变量名:begin_time
    +   * 是否必填:是
    +   * 示例值:1943787483
    +   * 类型:String
    +   * 说明:格式为时间戳
    +   * 
    + */ + @XStreamAlias("begin_time") + private String beginTime; + + /** + *
    +   * 字段名:生效结束时间
    +   * 变量名:end_time
    +   * 是否必填:是
    +   * 示例值:1943787490
    +   * 类型:String
    +   * 说明:格式为时间戳
    +   * 
    + */ + @XStreamAlias("end_time") + private String endTime; + + /** + *
    +   * 字段名:创建时间
    +   * 变量名:create_time
    +   * 是否必填:是
    +   * 示例值:1943787420
    +   * 类型:String
    +   * 说明:格式为时间戳
    +   * 
    + */ + @XStreamAlias("create_time") + private String createTime; + + /** + *
    +   * 字段名:代金券预算额度
    +   * 变量名:coupon_budget
    +   * 是否必填:否
    +   * 示例值:500
    +   * 类型:Unsigned int
    +   * 说明:代金券预算额度
    +   * 
    + */ + @XStreamAlias("coupon_budget") + private Integer couponBudget; + + public String getDeviceInfo() { + return this.deviceInfo; + } + + public void setDeviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + } + + public String getCouponStockId() { + return this.couponStockId; + } + + public void setCouponStockId(String couponStockId) { + this.couponStockId = couponStockId; + } + + public String getCouponName() { + return this.couponName; + } + + public void setCouponName(String couponName) { + this.couponName = couponName; + } + + public Integer getCouponValue() { + return this.couponValue; + } + + public void setCouponValue(Integer couponValue) { + this.couponValue = couponValue; + } + + public Integer getCouponMininumn() { + return this.couponMininumn; + } + + public void setCouponMininumn(Integer couponMininumn) { + this.couponMininumn = couponMininumn; + } + + public Integer getCouponStockStatus() { + return this.couponStockStatus; + } + + public void setCouponStockStatus(Integer couponStockStatus) { + this.couponStockStatus = couponStockStatus; + } + + public Integer getCouponTotal() { + return this.couponTotal; + } + + public void setCouponTotal(Integer couponTotal) { + this.couponTotal = couponTotal; + } + + public Integer getMaxQuota() { + return this.maxQuota; + } + + public void setMaxQuota(Integer maxQuota) { + this.maxQuota = maxQuota; + } + + public Integer getIsSendNum() { + return this.isSendNum; + } + + public void setIsSendNum(Integer isSendNum) { + this.isSendNum = isSendNum; + } + + public String getBeginTime() { + return this.beginTime; + } + + public void setBeginTime(String beginTime) { + this.beginTime = beginTime; + } + + public String getEndTime() { + return this.endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public String getCreateTime() { + return this.createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public Integer getCouponBudget() { + return this.couponBudget; + } + + public void setCouponBudget(Integer couponBudget) { + this.couponBudget = couponBudget; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index f2106c7260..2eef29b85a 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -1,7 +1,6 @@ package com.github.binarywang.wxpay.service; -import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest; -import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult; +import com.github.binarywang.wxpay.bean.coupon.*; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.config.WxPayConfig; @@ -351,4 +350,22 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri *
    */ WxPayCouponSendResult sendCoupon(WxPayCouponSendRequest request) throws WxPayException; + + /** + *
    +   * 查询代金券批次
    +   * 接口请求链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/query_coupon_stock
    +   * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_4
    +   * 
    + */ + WxPayCouponStockQueryResult queryCouponStock(WxPayCouponStockQueryRequest request) throws WxPayException; + + /** + *
    +   * 查询代金券信息
    +   * 接口请求链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/querycouponsinfo
    +   * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_5
    +   * 
    + */ + WxPayCouponInfoQueryResult queryCouponInfo(WxPayCouponInfoQueryRequest request) throws WxPayException; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java index b1c31b8676..8eef35043c 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java @@ -1,8 +1,7 @@ package com.github.binarywang.wxpay.service.impl; import com.github.binarywang.utils.qrcode.QrcodeUtils; -import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest; -import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult; +import com.github.binarywang.wxpay.bean.coupon.*; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.config.WxPayConfig; @@ -476,4 +475,26 @@ public WxPayCouponSendResult sendCoupon(WxPayCouponSendRequest request) throws W result.checkResult(this); return result; } + + @Override + public WxPayCouponStockQueryResult queryCouponStock(WxPayCouponStockQueryRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/mmpaymkttransfers/query_coupon_stock"; + String responseContent = this.post(url, request.toXML(), false); + WxPayCouponStockQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayCouponStockQueryResult.class); + result.checkResult(this); + return result; + } + + @Override + public WxPayCouponInfoQueryResult queryCouponInfo(WxPayCouponInfoQueryRequest request) throws WxPayException { + request.checkAndSign(this.getConfig()); + + String url = this.getPayBaseUrl() + "/mmpaymkttransfers/querycouponsinfo"; + String responseContent = this.post(url, request.toXML(), false); + WxPayCouponInfoQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayCouponInfoQueryResult.class); + result.checkResult(this); + return result; + } } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java index cc6ab5a0b5..bbf444d901 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java @@ -1,8 +1,7 @@ package com.github.binarywang.wxpay.service.impl; import com.github.binarywang.utils.qrcode.QrcodeUtils; -import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest; -import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult; +import com.github.binarywang.wxpay.bean.coupon.*; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.exception.WxPayException; @@ -283,4 +282,22 @@ public void testSendCoupon() throws Exception { .build()); this.logger.info(result.toString()); } + + @Test + public void testQueryCouponStock() throws Exception { + WxPayCouponStockQueryResult result = this.payService.queryCouponStock(WxPayCouponStockQueryRequest.newBuilder() + .couponStockId("123") + .build()); + this.logger.info(result.toString()); + } + + @Test + public void testQueryCouponInfo() throws Exception { + WxPayCouponInfoQueryResult result = this.payService.queryCouponInfo(WxPayCouponInfoQueryRequest.newBuilder() + .openid("onqOjjrXT-776SpHnfexGm1_P7iE") + .couponId("11") + .stockId("1121") + .build()); + this.logger.info(result.toString()); + } } From 66c7ae374ddc52fba7af10e08be2bd6e8e0bad05 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 15 Jul 2017 19:23:32 +0800 Subject: [PATCH 156/179] =?UTF-8?q?=E5=8F=91=E5=B8=83=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC2.7.6.BETA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 3b6ab1509b..0b78452d55 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang weixin-java-parent - 2.7.5.BETA + 2.7.6.BETA pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index a2f1195b9a..9299fa1ce7 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.5.BETA + 2.7.6.BETA weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index b63055ebc2..6732165602 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.5.BETA + 2.7.6.BETA weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index b3e0e88e15..181b505cd3 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.5.BETA + 2.7.6.BETA weixin-java-miniapp WeiXin Java Tools - MiniApp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index bd95d24728..16648606b2 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.5.BETA + 2.7.6.BETA weixin-java-mp WeiXin Java Tools - MP diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 7c695abc3e..4783621af5 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 2.7.5.BETA + 2.7.6.BETA 4.0.0 From 2b7dd7a7bf19d1e92de74df09d3e6716ca03f1aa Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 20 Jul 2017 21:12:07 +0800 Subject: [PATCH 157/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=97=B6=E7=9A=84=E4=B9=B1=E7=A0=81=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/apache/ApacheMaterialUploadRequestExecutor.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialUploadRequestExecutor.java index 474fcb9936..445ff2736e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialUploadRequestExecutor.java @@ -8,6 +8,7 @@ import me.chanjar.weixin.mp.bean.material.WxMpMaterial; import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; import me.chanjar.weixin.mp.util.http.MaterialUploadRequestExecutor; +import org.apache.http.Consts; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -15,6 +16,7 @@ import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.CloseableHttpClient; import java.io.File; @@ -53,7 +55,8 @@ public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material) throw .setMode(HttpMultipartMode.RFC6532); Map form = material.getForm(); if (material.getForm() != null) { - multipartEntityBuilder.addTextBody("description", WxGsonBuilder.create().toJson(form)); + multipartEntityBuilder.addPart("description", + new StringBody(WxGsonBuilder.create().toJson(form), ContentType.create("text/plain", Consts.UTF_8))); } httpPost.setEntity(multipartEntityBuilder.build()); From 1886c6b751bd1cb4e2b9faa9ccc9dd6cc53b6bd0 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 20 Jul 2017 21:21:54 +0800 Subject: [PATCH 158/179] =?UTF-8?q?#284=20=E6=8F=90=E5=8F=96=E5=85=B1?= =?UTF-8?q?=E5=90=8C=E4=BB=A3=E7=A0=81=E5=BF=AB=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=AD=BE=E5=90=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/WxPayServiceAbstractImpl.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java index 8eef35043c..7c57e5edeb 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java @@ -24,6 +24,7 @@ * 微信支付接口请求抽象实现类 * Created by Binary Wang on 2017-7-8. *
    + * * @author Binary Wang */ public abstract class WxPayServiceAbstractImpl implements WxPayService { @@ -196,6 +197,8 @@ public Map getPayInfo(WxPayUnifiedOrderRequest request) throws W } Map payInfo = new HashMap<>(); + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + String nonceStr = String.valueOf(System.currentTimeMillis()); if ("NATIVE".equals(request.getTradeType())) { payInfo.put("codeUrl", unifiedOrderResult.getCodeURL()); } else if ("APP".equals(request.getTradeType())) { @@ -207,8 +210,8 @@ public Map getPayInfo(WxPayUnifiedOrderRequest request) throws W configMap.put("prepayid", prepayId); configMap.put("partnerid", partnerid); configMap.put("package", "Sign=WXPay"); - configMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); - configMap.put("noncestr", String.valueOf(System.currentTimeMillis())); + configMap.put("timestamp", timestamp); + configMap.put("noncestr", nonceStr); configMap.put("appid", appId); // 此map用于客户端与微信服务器交互 payInfo.put("sign", SignUtils.createSign(configMap, this.getConfig().getMchKey())); @@ -216,17 +219,18 @@ public Map getPayInfo(WxPayUnifiedOrderRequest request) throws W payInfo.put("partnerId", partnerid); payInfo.put("appId", appId); payInfo.put("packageValue", "Sign=WXPay"); - payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); - payInfo.put("nonceStr", String.valueOf(System.currentTimeMillis())); + payInfo.put("timeStamp", timestamp); + payInfo.put("nonceStr", nonceStr); } else if ("JSAPI".equals(request.getTradeType())) { payInfo.put("appId", unifiedOrderResult.getAppid()); // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 - payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); - payInfo.put("nonceStr", String.valueOf(System.currentTimeMillis())); + payInfo.put("timeStamp", timestamp); + payInfo.put("nonceStr", nonceStr); payInfo.put("package", "prepay_id=" + prepayId); payInfo.put("signType", "MD5"); payInfo.put("paySign", SignUtils.createSign(payInfo, this.getConfig().getMchKey())); } + return payInfo; } From b9c9b844c88850cbb128daef5995a489f8ef0b80 Mon Sep 17 00:00:00 2001 From: lwxian Date: Fri, 21 Jul 2017 10:24:45 +0800 Subject: [PATCH 159/179] =?UTF-8?q?#287=20=E4=BF=AE=E5=A4=8D=E5=AF=B9?= =?UTF-8?q?=E5=B8=90=E5=8D=95=E4=B8=8B=E8=BD=BDbug=EF=BC=8C=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E7=9A=84=E5=AF=B9=E8=B1=A1=E6=B2=A1=E6=9C=89=E5=AF=B9?= =?UTF-8?q?=E5=B8=90=E5=8D=95=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 同时修复返回对账单的所有属性的值最后多余的空格; --- .../impl/WxPayServiceAbstractImpl.java | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java index 7c57e5edeb..9a75b46973 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java @@ -359,33 +359,34 @@ private WxPayBillResult billInformationDeal(String responseContent) { for (int i = 0; i < j; i++) { WxPayBillBaseResult wxPayBillBaseResult = new WxPayBillBaseResult(); - wxPayBillBaseResult.setTradeTime(tempStr[k]); - wxPayBillBaseResult.setAppId(tempStr[k + 1]); - wxPayBillBaseResult.setMchId(tempStr[k + 2]); - wxPayBillBaseResult.setSubMchId(tempStr[k + 3]); - wxPayBillBaseResult.setDeviceInfo(tempStr[k + 4]); - wxPayBillBaseResult.setTransationId(tempStr[k + 5]); - wxPayBillBaseResult.setOutTradeNo(tempStr[k + 6]); - wxPayBillBaseResult.setOpenId(tempStr[k + 7]); - wxPayBillBaseResult.setTradeType(tempStr[k + 8]); - wxPayBillBaseResult.setTradeState(tempStr[k + 9]); - wxPayBillBaseResult.setBankType(tempStr[k + 10]); - wxPayBillBaseResult.setFeeType(tempStr[k + 11]); - wxPayBillBaseResult.setTotalFee(tempStr[k + 12]); - wxPayBillBaseResult.setCouponFee(tempStr[k + 13]); - wxPayBillBaseResult.setRefundId(tempStr[k + 14]); - wxPayBillBaseResult.setOutRefundNo(tempStr[k + 15]); - wxPayBillBaseResult.setSettlementRefundFee(tempStr[k + 16]); - wxPayBillBaseResult.setCouponRefundFee(tempStr[k + 17]); - wxPayBillBaseResult.setRefundChannel(tempStr[k + 18]); - wxPayBillBaseResult.setRefundState(tempStr[k + 19]); - wxPayBillBaseResult.setBody(tempStr[k + 20]); - wxPayBillBaseResult.setAttach(tempStr[k + 21]); - wxPayBillBaseResult.setPoundage(tempStr[k + 22]); - wxPayBillBaseResult.setPoundageRate(tempStr[k + 23]); + wxPayBillBaseResult.setTradeTime(tempStr[k].trim()); + wxPayBillBaseResult.setAppId(tempStr[k + 1].trim()); + wxPayBillBaseResult.setMchId(tempStr[k + 2].trim()); + wxPayBillBaseResult.setSubMchId(tempStr[k + 3].trim()); + wxPayBillBaseResult.setDeviceInfo(tempStr[k + 4].trim()); + wxPayBillBaseResult.setTransationId(tempStr[k + 5].trim()); + wxPayBillBaseResult.setOutTradeNo(tempStr[k + 6].trim()); + wxPayBillBaseResult.setOpenId(tempStr[k + 7].trim()); + wxPayBillBaseResult.setTradeType(tempStr[k + 8].trim()); + wxPayBillBaseResult.setTradeState(tempStr[k + 9].trim()); + wxPayBillBaseResult.setBankType(tempStr[k + 10].trim()); + wxPayBillBaseResult.setFeeType(tempStr[k + 11].trim()); + wxPayBillBaseResult.setTotalFee(tempStr[k + 12].trim()); + wxPayBillBaseResult.setCouponFee(tempStr[k + 13].trim()); + wxPayBillBaseResult.setRefundId(tempStr[k + 14].trim()); + wxPayBillBaseResult.setOutRefundNo(tempStr[k + 15].trim()); + wxPayBillBaseResult.setSettlementRefundFee(tempStr[k + 16].trim()); + wxPayBillBaseResult.setCouponRefundFee(tempStr[k + 17].trim()); + wxPayBillBaseResult.setRefundChannel(tempStr[k + 18].trim()); + wxPayBillBaseResult.setRefundState(tempStr[k + 19].trim()); + wxPayBillBaseResult.setBody(tempStr[k + 20].trim()); + wxPayBillBaseResult.setAttach(tempStr[k + 21].trim()); + wxPayBillBaseResult.setPoundage(tempStr[k + 22].trim()); + wxPayBillBaseResult.setPoundageRate(tempStr[k + 23].trim()); wxPayBillBaseResultLst.add(wxPayBillBaseResult); k += t.length; } + wxPayBillResult.setWxPayBillBaseResultLst(wxPayBillBaseResultLst); /* * 总交易单数,总交易额,总退款金额,总代金券或立减优惠退款金额,手续费总金额 `2,`0.02,`0.0,`0.0,`0 */ From 30b5a9aa8f6ffd7b97ce9018d8682fd4e0d3668f Mon Sep 17 00:00:00 2001 From: Hyseen Date: Wed, 26 Jul 2017 14:34:57 +0800 Subject: [PATCH 160/179] =?UTF-8?q?#289=20=E5=A2=9E=E5=8A=A0=E4=B8=B4?= =?UTF-8?q?=E6=97=B6=E4=BA=8C=E7=BB=B4=E7=A0=81=E7=9A=84=E5=9C=BA=E6=99=AF?= =?UTF-8?q?=E5=80=BC=E6=94=AF=E6=8C=81=E5=AD=97=E7=AC=A6=E4=B8=B2=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 更新接口:临时二维码的场景值支持字符串 * 新增临时二维码的场景值为字符串的单元测试 --- .../weixin/mp/api/WxMpQrcodeService.java | 12 +++++++ .../mp/api/impl/WxMpQrcodeServiceImpl.java | 33 +++++++++++++++++++ .../api/impl/WxMpQrcodeServiceImplTest.java | 16 +++++++++ 3 files changed, 61 insertions(+) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java index e2e17eb359..37ed7dcd12 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java @@ -26,6 +26,18 @@ public interface WxMpQrcodeService { */ WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds) throws WxErrorException; + + /** + *
    +   * 换取临时二维码ticket
    +   * 详情请见: 生成带参数的二维码
    +   * 
    + * + * @param sceneStr 场景值ID(字符串形式的ID),字符串类型,长度限制为1到64 + * @param expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。 + */ + WxMpQrCodeTicket qrCodeCreateTmpTicket(String sceneStr, Integer expireSeconds) throws WxErrorException; + /** *
        * 换取永久二维码ticket
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
    index 817a0b68f2..5f6c3ad54f 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
    @@ -7,6 +7,7 @@
     import me.chanjar.weixin.mp.api.WxMpService;
     import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
     import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor;
    +import org.apache.commons.lang3.StringUtils;
     
     import java.io.File;
     import java.io.UnsupportedEncodingException;
    @@ -54,6 +55,38 @@ public WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds
         return WxMpQrCodeTicket.fromJson(responseContent);
       }
     
    +
    +  @Override
    +  public WxMpQrCodeTicket qrCodeCreateTmpTicket(String sceneStr, Integer expireSeconds) throws WxErrorException {
    +    if (StringUtils.isBlank(sceneStr)) {
    +      throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("临时二维码场景值不能为空!").build());
    +    }
    +
    +    //expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
    +    if (expireSeconds != null && expireSeconds > 2592000) {
    +      throw new WxErrorException(WxError.newBuilder().setErrorCode(-1)
    +        .setErrorMsg("临时二维码有效时间最大不能超过2592000(即30天)!").build());
    +    }
    +
    +    if (expireSeconds == null) {
    +      expireSeconds = 30;
    +    }
    +
    +    String url = API_URL_PREFIX + "/create";
    +    JsonObject json = new JsonObject();
    +    json.addProperty("action_name", "QR_STR_SCENE");
    +    json.addProperty("expire_seconds", expireSeconds);
    +
    +    JsonObject actionInfo = new JsonObject();
    +    JsonObject scene = new JsonObject();
    +    scene.addProperty("scene_str", sceneStr);
    +    actionInfo.add("scene", scene);
    +    json.add("action_info", actionInfo);
    +    String responseContent = this.wxMpService.post(url, json.toString());
    +    return WxMpQrCodeTicket.fromJson(responseContent);
    +  }
    +
    +
       @Override
       public WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorException {
         if (sceneId < 1 || sceneId > 100000) {
    diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImplTest.java
    index c61e38339c..216eec77f0 100644
    --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImplTest.java
    +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImplTest.java
    @@ -5,6 +5,7 @@
     import me.chanjar.weixin.mp.api.WxMpService;
     import me.chanjar.weixin.mp.api.test.ApiTestModule;
     import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
    +import org.apache.commons.lang3.RandomStringUtils;
     import org.testng.*;
     import org.testng.annotations.*;
     
    @@ -26,6 +27,11 @@ public Object[][] sceneIds() {
         return new Object[][]{{-1}, {0}, {1}, {200000}};
       }
     
    +  @DataProvider
    +  public Object[][] sceneStrs() {
    +    return new Object[][]{{null}, {""}, {"test"}, {RandomStringUtils.randomAlphanumeric(100)}};
    +  }
    +
       @Test(dataProvider = "sceneIds")
       public void testQrCodeCreateTmpTicket(int sceneId) throws WxErrorException {
         WxMpQrCodeTicket ticket = this.wxService.getQrcodeService().qrCodeCreateTmpTicket(sceneId, null);
    @@ -35,6 +41,16 @@ public void testQrCodeCreateTmpTicket(int sceneId) throws WxErrorException {
         System.out.println(ticket);
       }
     
    +
    +  @Test(dataProvider = "sceneStrs")
    +  public void testQrCodeCreateTmpTicketWithSceneStr(String sceneStr) throws WxErrorException {
    +    WxMpQrCodeTicket ticket = this.wxService.getQrcodeService().qrCodeCreateTmpTicket(sceneStr, null);
    +    Assert.assertNotNull(ticket.getUrl());
    +    Assert.assertNotNull(ticket.getTicket());
    +    Assert.assertTrue(ticket.getExpire_seconds() != -1);
    +    System.out.println(ticket);
    +  }
    +
       @Test(dataProvider = "sceneIds")
       public void testQrCodeCreateLastTicket(int sceneId) throws WxErrorException {
         WxMpQrCodeTicket ticket = this.wxService.getQrcodeService().qrCodeCreateLastTicket(sceneId);
    
    From 087f0371b8deda7b054b1b70cdeecb180bbaff51 Mon Sep 17 00:00:00 2001
    From: forfuns 
    Date: Thu, 27 Jul 2017 17:24:48 +0800
    Subject: [PATCH 161/179] =?UTF-8?q?#292=20=E5=A2=9E=E5=8A=A0=E5=B0=8F?=
     =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E7=A0=81=E6=94=AF=E6=8C=81?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    * 更新小程序二维码(小程序码)接口
    修复小程序模板推送读取错误字段导致的NullPoint
    
    * 更新小程序二维码(小程序码)接口
    修复小程序模板推送读取错误字段导致的NullPoint
    
    * 更正WxMaMsgService接口逻辑
    
    * 使用IDEA对miniapp做了批量格式化
    ---
     .../weixin/common/util/fs/FileUtils.java      |  2 +-
     .../wx/miniapp/api/WxMaQrcodeService.java     | 83 +++++++++++++++++++
     .../api/impl/WxMaQrcodeServiceImpl.java       | 47 +++++++++++
     .../bean/WxMaJscode2SessionResult.java        | 15 +++-
     .../wx/miniapp/bean/WxMaQrcode.java           |  2 +-
     .../wx/miniapp/bean/WxMaQrcodeWrapper.java    | 16 ++++
     .../wx/miniapp/bean/WxMaWxcode.java           | 64 ++++++++++++++
     .../wx/miniapp/bean/WxMaWxcodeLimit.java      | 68 +++++++++++++++
     .../wx/miniapp/builder/ImageBuilder.java      |  2 +-
     .../message/WxMaMessageInterceptor.java       |  2 +-
     .../util/http/QrCodeRequestExecutor.java      |  6 +-
     .../util/json/WxMaKefuMessageGsonAdapter.java |  1 -
     .../api/impl/WxMaMsgServiceImplTest.java      |  3 +-
     .../api/impl/WxMaQrcodeServiceImplTest.java   | 12 +++
     .../wx/miniapp/bean/WxMaMessageTest.java      |  1 -
     .../wx/miniapp/demo/WxMaDemoServer.java       |  4 +-
     16 files changed, 314 insertions(+), 14 deletions(-)
     create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcodeWrapper.java
     create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcode.java
     create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcodeLimit.java
    
    diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java
    index df031b3371..37ee5ebe4b 100644
    --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java
    +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java
    @@ -24,7 +24,7 @@ public static File createTmpFile(InputStream inputStream, String name, String ex
           tmpFile = File.createTempFile(name, '.' + ext, tmpDirFile);
         }
     
    -    tmpFile.deleteOnExit();
    +//    tmpFile.deleteOnExit();
     
         try (FileOutputStream fos = new FileOutputStream(tmpFile)) {
           int read = 0;
    diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java
    index 822f5de8a4..c2222bc93e 100644
    --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java
    +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java
    @@ -7,6 +7,9 @@
     /**
      * 
      * 二维码相关操作接口
    + *
    + * 接口A(createWxCode)加上接口C(createQrcode),总共生成的码数量限制为100,000,请谨慎调用。
    + *
      * 文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html
      * 
    * @@ -15,6 +18,7 @@ public interface WxMaQrcodeService { /** + * 接口C *
        * 获取小程序页面二维码
        * 适用于需要的码数量较少的业务场景
    @@ -27,4 +31,83 @@ public interface WxMaQrcodeService {
        * @param width 默认430 二维码的宽度
        */
       File createQrcode(String path, int width) throws WxErrorException;
    +
    +  File createQrcode(String path) throws WxErrorException;
    +
    +  /**
    +   * 接口A
    +   * 获取小程序码
    +   *
    +   * @param path      不能为空,最大长度 128 字节
    +   * @param width     默认430 二维码的宽度
    +   * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
    +   * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}
    +   * @return
    +   * @throws WxErrorException
    +   */
    +  File createWxCode(String path, int width, boolean autoColor, LineColor lineColor) throws WxErrorException;
    +
    +  File createWxCode(String path, int width) throws WxErrorException;
    +
    +  File createWxCode(String path) throws WxErrorException;
    +
    +  /**
    +   * 接口B
    +   * 获取小程序码(永久有效、数量暂无限制)
    +   * 

    + * 通过该接口生成的小程序码,永久有效,数量暂无限制。 + * 用户扫描该码进入小程序后,将统一打开首页,开发者需在对应页面根据获取的码中 scene 字段的值,再做处理逻辑。 + * 使用如下代码可以获取到二维码中的 scene 字段的值。 + * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode + * + * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + * @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 + * @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} + * @return + * @throws WxErrorException + */ + File createWxCodeLimit(String scene, String page, int width, boolean autoColor, LineColor lineColor) throws WxErrorException; + + File createWxCodeLimit(String scene, String page) throws WxErrorException; + + /** + * lineColor 包装类 + * 用于描述二维码(小程序码)颜色(RGB参数值),详情请查看文档 + */ + public static class LineColor { + + private String r = "0", g = "0", b = "0"; + + public LineColor(String r, String g, String b) { + this.r = r; + this.g = g; + this.b = b; + } + + public String getR() { + return r; + } + + public void setR(String r) { + this.r = r; + } + + public String getG() { + return g; + } + + public void setG(String g) { + this.g = g; + } + + public String getB() { + return b; + } + + public void setB(String b) { + this.b = b; + } + } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java index f0fc36af16..fd58855b3d 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java @@ -3,6 +3,8 @@ import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.WxMaQrcode; +import cn.binarywang.wx.miniapp.bean.WxMaWxcode; +import cn.binarywang.wx.miniapp.bean.WxMaWxcodeLimit; import cn.binarywang.wx.miniapp.util.http.QrCodeRequestExecutor; import me.chanjar.weixin.common.exception.WxErrorException; @@ -25,4 +27,49 @@ public File createQrcode(String path, int width) throws WxErrorException { url, new WxMaQrcode(path, width)); } + @Override + public File createQrcode(String path) throws WxErrorException { + return this.createQrcode(path, 430); + } + + @Override + public File createWxCode(String path, int width, boolean autoColor, LineColor lineColor) throws WxErrorException { + String url = "https://api.weixin.qq.com/wxa/getwxacode"; + WxMaWxcode wxMaWxcode = new WxMaWxcode(); + wxMaWxcode.setPath(path); + wxMaWxcode.setWidth(width); + wxMaWxcode.setAutoColor(autoColor); + wxMaWxcode.setLineColor(lineColor); + return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), + url, wxMaWxcode); + } + + @Override + public File createWxCode(String path, int width) throws WxErrorException { + return this.createWxCode(path, width, true, null); + } + + @Override + public File createWxCode(String path) throws WxErrorException { + return this.createWxCode(path, 430, true, null); + } + + @Override + public File createWxCodeLimit(String scene, String page, int width, boolean autoColor, LineColor lineColor) throws WxErrorException { + String url = "http://api.weixin.qq.com/wxa/getwxacodeunlimit"; + WxMaWxcodeLimit wxMaWxcodeLimit = new WxMaWxcodeLimit(); + wxMaWxcodeLimit.setScene(scene); + wxMaWxcodeLimit.setPage(page); + wxMaWxcodeLimit.setWidth(width); + wxMaWxcodeLimit.setAutoColor(autoColor); + wxMaWxcodeLimit.setLineColor(lineColor); + return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), + url, wxMaWxcodeLimit); + } + + @Override + public File createWxCodeLimit(String scene, String page) throws WxErrorException { + return this.createWxCodeLimit(scene, page, 430, true, null); + } + } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaJscode2SessionResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaJscode2SessionResult.java index 4b9cc93d6b..471e6c46ec 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaJscode2SessionResult.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaJscode2SessionResult.java @@ -18,6 +18,13 @@ public class WxMaJscode2SessionResult { @SerializedName("openid") private String openid; + @SerializedName("unionid") + private String unionid; + + public static WxMaJscode2SessionResult fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaJscode2SessionResult.class); + } + public String getSessionKey() { return sessionKey; } @@ -42,8 +49,12 @@ public void setOpenid(String openid) { this.openid = openid; } - public static WxMaJscode2SessionResult fromJson(String json) { - return WxMaGsonBuilder.create().fromJson(json, WxMaJscode2SessionResult.class); + public String getUnionid() { + return unionid; + } + + public void setUnionid(String unionid) { + this.unionid = unionid; } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcode.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcode.java index 83050f0619..a047d7c8b1 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcode.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcode.java @@ -7,7 +7,7 @@ /** * @author Binary Wang */ -public class WxMaQrcode implements Serializable { +public class WxMaQrcode extends WxMaQrcodeWrapper implements Serializable { private static final long serialVersionUID = 5777119669111011584L; private String path; private int width = 430; diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcodeWrapper.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcodeWrapper.java new file mode 100644 index 0000000000..37c5c5db88 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcodeWrapper.java @@ -0,0 +1,16 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; + +/** + * 微信二维码(小程序码)包装器 + * Created by Element on 2017/7/27. + */ +public abstract class WxMaQrcodeWrapper { + + @Override + public String toString() { + return WxMaGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcode.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcode.java new file mode 100644 index 0000000000..9ea674ed98 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcode.java @@ -0,0 +1,64 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; + +/** + * Created by Element on 2017/7/27. + */ +public class WxMaWxcode extends WxMaQrcodeWrapper implements Serializable { + + private static final long serialVersionUID = 1287399621649210322L; + private String path; + private int width = 430; + + @SerializedName("auto_color") + private boolean autoColor = true; + + @SerializedName("line_color") + private WxMaQrcodeService.LineColor lineColor = new WxMaQrcodeService.LineColor("0", "0", "0"); + + public static WxMaWxcode fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaWxcode.class); + } + + public static long getSerialVersionUID() { + return serialVersionUID; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + public boolean isAutoColor() { + return autoColor; + } + + public void setAutoColor(boolean autoColor) { + this.autoColor = autoColor; + } + + public WxMaQrcodeService.LineColor getLineColor() { + return lineColor; + } + + public void setLineColor(WxMaQrcodeService.LineColor lineColor) { + this.lineColor = lineColor; + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcodeLimit.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcodeLimit.java new file mode 100644 index 0000000000..7619fe46f2 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcodeLimit.java @@ -0,0 +1,68 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; + +/** + * Created by Element on 2017/7/27. + */ +public class WxMaWxcodeLimit extends WxMaQrcodeWrapper implements Serializable { + private static final long serialVersionUID = 4782193774524960401L; + private String scene; + private String page; + + private int width = 430; + + @SerializedName("auto_color") + private boolean autoColor = true; + + @SerializedName("line_color") + private WxMaQrcodeService.LineColor lineColor = new WxMaQrcodeService.LineColor("0", "0", "0"); + + public static WxMaWxcodeLimit fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaWxcodeLimit.class); + } + + public String getPage() { + return page; + } + + public void setPage(String page) { + this.page = page; + } + + public String getScene() { + return scene; + } + + public void setScene(String scene) { + this.scene = scene; + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + public boolean isAutoColor() { + return autoColor; + } + + public void setAutoColor(boolean autoColor) { + this.autoColor = autoColor; + } + + public WxMaQrcodeService.LineColor getLineColor() { + return lineColor; + } + + public void setLineColor(WxMaQrcodeService.LineColor lineColor) { + this.lineColor = lineColor; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/ImageBuilder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/ImageBuilder.java index 219e3fd43b..a903e97c43 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/ImageBuilder.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/ImageBuilder.java @@ -10,7 +10,7 @@ public final class ImageBuilder extends BaseBuilder { private String mediaId; public ImageBuilder() { - this.msgType = WxMaConstants.KefuMsgType.IMAGE; + this.msgType = WxMaConstants.KefuMsgType.IMAGE; } public ImageBuilder mediaId(String media_id) { diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java index 1b220a0baa..3443862fe1 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java @@ -17,7 +17,7 @@ public interface WxMaMessageInterceptor { /** * 拦截微信消息 * - * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 * @return true代表OK,false代表不OK */ boolean intercept(WxMaMessage wxMessage, diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java index 7883ffda9b..dc482dff25 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java @@ -1,6 +1,6 @@ package cn.binarywang.wx.miniapp.util.http; -import cn.binarywang.wx.miniapp.bean.WxMaQrcode; +import cn.binarywang.wx.miniapp.bean.WxMaQrcodeWrapper; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; @@ -25,7 +25,7 @@ /** * @author Binary Wang */ -public class QrCodeRequestExecutor implements RequestExecutor { +public class QrCodeRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; public QrCodeRequestExecutor(RequestHttp requestHttp) { @@ -33,7 +33,7 @@ public QrCodeRequestExecutor(RequestHttp requestHttp) { } @Override - public File execute(String uri, WxMaQrcode ticket) throws WxErrorException, IOException { + public File execute(String uri, WxMaQrcodeWrapper ticket) throws WxErrorException, IOException { HttpPost httpPost = new HttpPost(uri); if (requestHttp.getRequestHttpProxy() != null) { httpPost diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaKefuMessageGsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaKefuMessageGsonAdapter.java index 33c46d63cd..829469f872 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaKefuMessageGsonAdapter.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaKefuMessageGsonAdapter.java @@ -14,7 +14,6 @@ import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import org.apache.commons.lang3.StringUtils; import java.lang.reflect.Type; diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java index 9604a25691..37e3608bff 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java @@ -9,7 +9,8 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.exception.WxErrorException; -import org.testng.annotations.*; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; import java.text.SimpleDateFormat; import java.util.Date; diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java index 48dad9362a..eba65f7c34 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java @@ -23,4 +23,16 @@ public void testCreateQrCode() throws Exception { System.out.println(qrCode); } + @Test + public void testCreateWxCode() throws Exception { + final File wxCode = this.wxService.getQrcodeService().createWxCode("111", 122); + System.out.println(wxCode); + } + + @Test + public void testCreateWxCodeLimit() throws Exception { + final File wxCode = this.wxService.getQrcodeService().createWxCodeLimit("111", null); + System.out.println(wxCode); + } + } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaMessageTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaMessageTest.java index 881091a1df..cdf989a6af 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaMessageTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaMessageTest.java @@ -1,6 +1,5 @@ package cn.binarywang.wx.miniapp.bean; -import cn.binarywang.wx.miniapp.bean.WxMaMessage; import me.chanjar.weixin.common.api.WxConsts; import org.testng.annotations.Test; diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java index fe986c8e71..f6dcbae27b 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java @@ -2,8 +2,8 @@ import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; -import cn.binarywang.wx.miniapp.bean.WxMaMessage; import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.constant.WxMaConstants; @@ -69,7 +69,7 @@ public void handle(WxMaMessage wxMessage, Map context, } } }; - + private static final WxMaMessageHandler qrcodeHandler = new WxMaMessageHandler() { @Override public void handle(WxMaMessage wxMessage, Map context, From 945516515cf8ce9357daded93415d490767d3ec0 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 27 Jul 2017 17:19:19 +0800 Subject: [PATCH 162/179] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E4=BC=81=E4=B8=9A=E4=BB=98=E6=AC=BE=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wxpay/bean/request/WxEntPayRequest.java | 258 +++++++++++++----- .../impl/WxPayServiceAbstractImplTest.java | 10 +- 2 files changed, 200 insertions(+), 68 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayRequest.java index fd43fb1aaa..7897ad02da 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayRequest.java @@ -1,18 +1,12 @@ package com.github.binarywang.wxpay.bean.request; import com.thoughtworks.xstream.annotations.XStreamAlias; +import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.util.ToStringUtils; /** *

      * 企业付款请求对象
    - * 注释中各行每个字段描述对应如下:
    - * 
  • 字段名 - *
  • 变量名 - *
  • 是否必填 - *
  • 类型 - *
  • 示例值 - *
  • 描述 *
  • * Created by Binary Wang on 2016/10/02. * @@ -22,12 +16,12 @@ public class WxEntPayRequest extends WxPayBaseRequest { /** *
    -   * 公众账号appid
    -   * mch_appid
    -   * 是
    -   * wx8888888888888888
    -   * String
    -   * 微信分配的公众账号ID(企业号corpid即为此appId)
    +   * 字段名:公众账号appid
    +   * 变量名:mch_appid
    +   * 是否必填:是
    +   * 示例值:wx8888888888888888
    +   * 类型:String
    +   * 描述:微信分配的公众账号ID(企业号corpid即为此appId)
        * 
    */ @XStreamAlias("mch_appid") @@ -35,12 +29,12 @@ public class WxEntPayRequest extends WxPayBaseRequest { /** *
    -   *  商户号
    -   *  mchid
    -   *  是
    -   *  1900000109
    -   *  String(32)
    -   *  微信支付分配的商户号
    +   * 字段名:商户号
    +   * 变量名:mchid
    +   * 是否必填:是
    +   * 示例值:1900000109
    +   * 类型:String(32)
    +   * 描述:微信支付分配的商户号
        * 
    */ @XStreamAlias("mchid") @@ -48,12 +42,12 @@ public class WxEntPayRequest extends WxPayBaseRequest { /** *
    -   * 设备号
    -   * device_info
    -   * 否
    -   * 13467007045764
    -   * String(32)
    -   * 微信支付分配的终端设备号
    +   * 字段名:设备号
    +   * 变量名:device_info
    +   * 是否必填:否
    +   * 示例值:13467007045764
    +   * 类型:String(32)
    +   * 描述:微信支付分配的终端设备号
        * 
    */ @XStreamAlias("device_info") @@ -61,53 +55,56 @@ public class WxEntPayRequest extends WxPayBaseRequest { /** *
    -   * 商户订单号
    -   * partner_trade_no
    -   * 是
    -   * 10000098201411111234567890
    -   * String
    -   * 商户订单号
    +   * 字段名:商户订单号
    +   * 变量名:partner_trade_no
    +   * 是否必填:是
    +   * 示例值:10000098201411111234567890
    +   * 类型:String
    +   * 描述:商户订单号
        * 
    */ + @Required @XStreamAlias("partner_trade_no") private String partnerTradeNo; /** *
    -   * 需保持唯一性 用户openid
    -   * openid
    -   * 是
    -   * oxTWIuGaIt6gTKsQRLau2M0yL16E
    -   * String
    -   * 商户appid下,某用户的openid
    +   * 字段名:需保持唯一性 用户openid
    +   * 变量名:openid
    +   * 是否必填:是
    +   * 示例值:oxTWIuGaIt6gTKsQRLau2M0yL16E
    +   * 类型:String
    +   * 描述:商户appid下,某用户的openid
        * 
    */ + @Required @XStreamAlias("openid") private String openid; /** *
    -   * 校验用户姓名选项
    -   * check_name
    -   * 是
    -   * OPTION_CHECK
    -   * String
    -   * NO_CHECK:不校验真实姓名 
    +   * 字段名:校验用户姓名选项
    +   * 变量名:check_name
    +   * 是否必填:是
    +   * 示例值:OPTION_CHECK
    +   * 类型:String
    +   * 描述:NO_CHECK:不校验真实姓名 
        * FORCE_CHECK:强校验真实姓名(未实名认证的用户会校验失败,无法转账) 
        * OPTION_CHECK:针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功)
        * 
    */ + @Required @XStreamAlias("check_name") private String checkName; /** *
    -   * 收款用户姓名
    -   * re_user_name
    -   * 可选
    -   * 马花花
    -   * String
    -   * 收款用户真实姓名。
    +   * 字段名:收款用户姓名
    +   * 变量名:re_user_name
    +   * 是否必填:可选
    +   * 示例值:马花花
    +   * 类型:String
    +   * 描述:收款用户真实姓名。
        * 如果check_name设置为FORCE_CHECK或OPTION_CHECK,  则必填用户真实姓名
        * 
    */ @@ -116,43 +113,71 @@ public class WxEntPayRequest extends WxPayBaseRequest { /** *
    -   * 金额
    -   * amount
    -   * 是
    -   * 10099
    -   * int
    -   * 企业付款金额, 单位为分
    +   * 字段名:金额
    +   * 变量名:amount
    +   * 是否必填:是
    +   * 示例值:10099
    +   * 类型:int
    +   * 描述:企业付款金额, 单位为分
        * 
    */ + @Required @XStreamAlias("amount") private Integer amount; /** *
    -   * 企业付款描述信息
    -   * desc
    -   * 是
    -   * 理赔
    -   * String
    -   * 企业付款操作说明信息。必填。
    +   * 字段名:企业付款描述信息
    +   * 变量名:desc
    +   * 是否必填:是
    +   * 示例值:理赔
    +   * 类型:String
    +   * 描述:企业付款操作说明信息。必填。
        * 
    */ + @Required @XStreamAlias("desc") private String description; /** *
    -   * Ip地址
    -   * spbill_create_ip
    -   * 是
    -   * 192.168.0.1
    -   * String(32)
    -   * 调用接口的机器Ip地址
    +   * 字段名:Ip地址
    +   * 变量名:spbill_create_ip
    +   * 是否必填:是
    +   * 示例值:192.168.0.1
    +   * 类型:String(32)
    +   * 描述:调用接口的机器Ip地址
        * 
    */ + @Required @XStreamAlias("spbill_create_ip") private String spbillCreateIp; + public WxEntPayRequest() { + } + + private WxEntPayRequest(Builder builder) { + setAppid(builder.appid); + setMchId(builder.mchId); + setSubAppId(builder.subAppId); + setSubMchId(builder.subMchId); + setNonceStr(builder.nonceStr); + setSign(builder.sign); + mchAppid = builder.mchAppid; + setMchId(builder.mchId); + setDeviceInfo(builder.deviceInfo); + setPartnerTradeNo(builder.partnerTradeNo); + setOpenid(builder.openid); + setCheckName(builder.checkName); + setReUserName(builder.reUserName); + setAmount(builder.amount); + setDescription(builder.description); + setSpbillCreateIp(builder.spbillCreateIp); + } + + public static Builder newBuilder() { + return new Builder(); + } @Override protected void checkConstraints() { @@ -248,4 +273,103 @@ public String toString() { return ToStringUtils.toSimpleString(this); } + public static final class Builder { + private String appid; + private String mchId; + private String deviceInfo; + private String partnerTradeNo; + private String openid; + private String checkName; + private String reUserName; + private Integer amount; + private String description; + private String spbillCreateIp; + private String subAppId; + private String subMchId; + private String nonceStr; + private String sign; + private String mchAppid; + + private Builder() { + } + + public Builder appid(String appid) { + this.appid = appid; + return this; + } + + public Builder mchId(String mchId) { + this.mchId = mchId; + return this; + } + + public Builder deviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + return this; + } + + public Builder partnerTradeNo(String partnerTradeNo) { + this.partnerTradeNo = partnerTradeNo; + return this; + } + + public Builder openid(String openid) { + this.openid = openid; + return this; + } + + public Builder checkName(String checkName) { + this.checkName = checkName; + return this; + } + + public Builder reUserName(String reUserName) { + this.reUserName = reUserName; + return this; + } + + public Builder amount(Integer amount) { + this.amount = amount; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public Builder spbillCreateIp(String spbillCreateIp) { + this.spbillCreateIp = spbillCreateIp; + return this; + } + + public WxEntPayRequest build() { + return new WxEntPayRequest(this); + } + + public Builder subAppId(String subAppId) { + this.subAppId = subAppId; + return this; + } + + public Builder subMchId(String subMchId) { + this.subMchId = subMchId; + return this; + } + + public Builder nonceStr(String nonceStr) { + this.nonceStr = nonceStr; + return this; + } + + public Builder sign(String sign) { + this.sign = sign; + return this; + } + + public Builder mchAppid(String mchAppid) { + this.mchAppid = mchAppid; + return this; + } + } } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java index bbf444d901..9b57d77b1c 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java @@ -170,7 +170,15 @@ public void testCloseOrder() throws WxPayException { */ @Test public void testEntPay() throws WxPayException { - WxEntPayRequest request = new WxEntPayRequest(); + WxEntPayRequest request = WxEntPayRequest.newBuilder() + .partnerTradeNo("Eb6Aep7uVTdbkJqrP4") + .openid("ojOQA0y9o-Eb6Aep7uVTdbkJqrP4") + .amount(1) + .spbillCreateIp("10.10.10.10") + .checkName("NO_CHECK") + .description("描述信息") + .build(); + this.logger.info(this.payService.entPay(request).toString()); } From 0a06c4d1a13c39fc83903e83d1647362f280c2ca Mon Sep 17 00:00:00 2001 From: dylanleung <0095103cn@gmail.com> Date: Sun, 30 Jul 2017 22:39:20 -0500 Subject: [PATCH 163/179] =?UTF-8?q?#293=20=E9=87=8D=E6=9E=84OkHttp?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E4=BF=AE=E5=A4=8DJSApi=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update travis settings * feat(okhttp): 修改okhttp底层调用方法 直接用OkHttpClient代替connect.使客户端单一化.Okhttp 自动管理连接池优化 * feat(log,jsApi): 添加log debug 标记明确下调用底层效果,修复jsAPI Lock 为null 问题 添加log debug 标记明确下调用底层效果,修复jsAPI Lock 为null 问题 #293 --- .../OkHttpMediaDownloadRequestExecutor.java | 33 ++++------- .../OkHttpMediaUploadRequestExecutor.java | 23 ++------ .../OkHttpSimpleGetRequestExecutor.java | 25 ++------ .../OkHttpSimplePostRequestExecutor.java | 27 ++------- .../cp/api/impl/WxCpServiceOkHttpImpl.java | 50 ++++++++-------- .../mp/api/impl/AbstractWxMpServiceImpl.java | 3 +- .../mp/api/impl/WxMpServiceOkHttpImpl.java | 52 ++++++++-------- .../OkhttpMaterialDeleteRequestExecutor.java | 23 ++------ ...OkhttpMaterialNewsInfoRequestExecutor.java | 20 +------ .../OkhttpMaterialUploadRequestExecutor.java | 27 ++++----- ...khttpMaterialVideoInfoRequestExecutor.java | 24 +++----- ...lVoiceAndImageDownloadRequestExecutor.java | 59 ++++++------------- .../OkhttpMediaImgUploadRequestExecutor.java | 25 +++----- .../okhttp/OkhttpQrCodeRequestExecutor.java | 33 ++++------- .../weixin/mp/api/WxMpBaseAPITest.java | 6 ++ .../chanjar/weixin/mp/api/WxMpJsAPITest.java | 6 +- .../weixin/mp/api/test/ApiTestModule.java | 3 +- 17 files changed, 159 insertions(+), 280 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java index 97f8cb02c5..e5346c2a26 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java @@ -6,7 +6,11 @@ import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import okhttp3.*; +import okio.BufferedSink; +import okio.Okio; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; import java.io.File; @@ -18,7 +22,8 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkHttpMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor { +public class OkHttpMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); public OkHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { @@ -27,6 +32,7 @@ public OkHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFi @Override public File execute(String uri, String queryParam) throws WxErrorException, IOException { + logger.debug("OkHttpMediaDownloadRequestExecutor is running"); if (queryParam != null) { if (uri.indexOf('?') == -1) { uri += '?'; @@ -34,23 +40,8 @@ public File execute(String uri, String queryParam) throws WxErrorException, IOEx uri += uri.endsWith("?") ? queryParam : '&' + queryParam; } - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); - //设置代理 - if (requestHttp.getRequestHttpProxy() != null) { - clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); //得到httpClient - OkHttpClient client = clientBuilder.build(); + OkHttpClient client = requestHttp.getRequestHttpClient(); Request request = new Request.Builder().url(uri).get().build(); @@ -66,10 +57,12 @@ public Request authenticate(Route route, Response response) throws IOException { if (StringUtils.isBlank(fileName)) { return null; } - - InputStream inputStream = new ByteArrayInputStream(response.body().bytes()); String[] nameAndExt = fileName.split("\\."); - return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], super.tmpDirFile); + File file = File.createTempFile(nameAndExt[0], nameAndExt[1], super.tmpDirFile); + try (BufferedSink sink = Okio.buffer(Okio.sink(file))) { + sink.writeAll(response.body().source()); + } + return file; } private String getFileName(Response response) throws WxErrorException { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java index 91b36d7da6..9edeee89be 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java @@ -6,6 +6,8 @@ import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; @@ -13,7 +15,8 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkHttpMediaUploadRequestExecutor extends MediaUploadRequestExecutor { +public class OkHttpMediaUploadRequestExecutor extends MediaUploadRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); public OkHttpMediaUploadRequestExecutor(RequestHttp requestHttp) { super(requestHttp); @@ -21,23 +24,9 @@ public OkHttpMediaUploadRequestExecutor(RequestHttp requestHttp) { @Override public WxMediaUploadResult execute(String uri, File file) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); - //设置代理 - if (requestHttp.getRequestHttpProxy() != null) { - clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); + logger.debug("OkHttpMediaUploadRequestExecutor is running"); //得到httpClient - OkHttpClient client = clientBuilder.build(); + OkHttpClient client = requestHttp.getRequestHttpClient(); RequestBody body = new MultipartBody.Builder() .setType(MediaType.parse("multipart/form-data")) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java index bbb5d43754..e468c609c8 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java @@ -5,13 +5,16 @@ import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; /** * Created by ecoolper on 2017/5/4. */ -public class OkHttpSimpleGetRequestExecutor extends SimpleGetRequestExecutor { +public class OkHttpSimpleGetRequestExecutor extends SimpleGetRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); public OkHttpSimpleGetRequestExecutor(RequestHttp requestHttp) { super(requestHttp); @@ -19,6 +22,7 @@ public OkHttpSimpleGetRequestExecutor(RequestHttp requestHttp) { @Override public String execute(String uri, String queryParam) throws WxErrorException, IOException { + logger.debug("OkHttpSimpleGetRequestExecutor is running"); if (queryParam != null) { if (uri.indexOf('?') == -1) { uri += '?'; @@ -26,26 +30,9 @@ public String execute(String uri, String queryParam) throws WxErrorException, IO uri += uri.endsWith("?") ? queryParam : '&' + queryParam; } - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); - //设置代理 - if (requestHttp.getRequestHttpProxy() != null) { - clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); //得到httpClient - OkHttpClient client = clientBuilder.build(); - + OkHttpClient client = requestHttp.getRequestHttpClient(); Request request = new Request.Builder().url(uri).build(); - Response response = client.newCall(request).execute(); String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java index 9d153117c5..bc54d7b4cd 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java @@ -5,13 +5,16 @@ import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; /** * Created by ecoolper on 2017/5/4. */ -public class OkHttpSimplePostRequestExecutor extends SimplePostRequestExecutor { +public class OkHttpSimplePostRequestExecutor extends SimplePostRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); public OkHttpSimplePostRequestExecutor(RequestHttp requestHttp) { super(requestHttp); @@ -19,27 +22,9 @@ public OkHttpSimplePostRequestExecutor(RequestHttp requestHttp) { @Override public String execute(String uri, String postEntity) throws WxErrorException, IOException { - ConnectionPool pool = requestHttp.getRequestHttpClient(); - final OkHttpProxyInfo proxyInfo = requestHttp.getRequestHttpProxy(); - - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); - //设置代理 - if (proxyInfo != null) { - clientBuilder.proxy(proxyInfo.getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); + logger.debug("OkHttpSimplePostRequestExecutor running"); //得到httpClient - OkHttpClient client = clientBuilder.build(); - + OkHttpClient client = requestHttp.getRequestHttpClient(); MediaType mediaType = MediaType.parse("text/plain; charset=utf-8"); RequestBody body = RequestBody.create(mediaType, postEntity); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java index 4dd66d9d86..2b8ae0c4af 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java @@ -7,16 +7,20 @@ import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.cp.config.WxCpConfigStorage; import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; -public class WxCpServiceOkHttpImpl extends AbstractWxCpServiceImpl { - protected ConnectionPool httpClient; +public class WxCpServiceOkHttpImpl extends AbstractWxCpServiceImpl { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + protected OkHttpClient httpClient; protected OkHttpProxyInfo httpProxy; @Override - public ConnectionPool getRequestHttpClient() { + public OkHttpClient getRequestHttpClient() { return httpClient; } @@ -32,6 +36,7 @@ public HttpType getRequestType() { @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { + logger.debug("WxCpServiceOkHttpImpl is running"); if (forceRefresh) { this.configStorage.expireAccessToken(); } @@ -41,24 +46,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" + "&corpid=" + this.configStorage.getCorpId() + "&corpsecret=" + this.configStorage.getCorpSecret(); - - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(httpClient); - //设置代理 - if (httpProxy != null) { - clientBuilder.proxy(getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); //得到httpClient - OkHttpClient client = clientBuilder.build(); + OkHttpClient client = getRequestHttpClient(); //请求的request Request request = new Request.Builder().url(url).get().build(); Response response = null; @@ -88,13 +77,24 @@ public Request authenticate(Route route, Response response) throws IOException { @Override public void initHttp() { - WxCpConfigStorage configStorage = this.configStorage; + logger.debug("WxCpServiceOkHttpImpl initHttp"); + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); + //设置代理 + if (httpProxy != null) { + clientBuilder.proxy(getRequestHttpProxy().getProxy()); - if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { - httpProxy = new OkHttpProxyInfo(OkHttpProxyInfo.ProxyType.SOCKS5, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); } - - httpClient = new ConnectionPool(); + httpClient = clientBuilder.build(); } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java index cc965026c4..25eeeadce4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java @@ -66,10 +66,9 @@ public String getJsapiTicket() throws WxErrorException { @Override public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { - Lock lock = this.getWxMpConfigStorage().getJsapiTicketLock(); + Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); try { lock.lock(); - if (forceRefresh) { this.getWxMpConfigStorage().expireJsapiTicket(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java index 81fb848909..dbb957b84c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java @@ -8,16 +8,21 @@ import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.concurrent.locks.Lock; -public class WxMpServiceOkHttpImpl extends AbstractWxMpServiceImpl { - private ConnectionPool httpClient; +public class WxMpServiceOkHttpImpl extends AbstractWxMpServiceImpl { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private OkHttpClient httpClient; private OkHttpProxyInfo httpProxy; @Override - public ConnectionPool getRequestHttpClient() { + public OkHttpClient getRequestHttpClient() { return httpClient; } @@ -33,6 +38,7 @@ public HttpType getRequestType() { @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { + logger.debug("WxMpServiceOkHttpImpl is running"); Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); try { lock.lock(); @@ -45,26 +51,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL, this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret()); - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(httpClient); - //设置代理 - if (httpProxy != null) { - clientBuilder.proxy(getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - Request request = new Request.Builder().url(url).get().build(); - Response response = client.newCall(request).execute(); + Response response = getRequestHttpClient().newCall(request).execute(); String resultContent = response.body().string(); WxError error = WxError.fromJson(resultContent); if (error.getErrorCode() != 0) { @@ -84,13 +72,29 @@ public Request authenticate(Route route, Response response) throws IOException { @Override public void initHttp() { + logger.debug("WxMpServiceOkHttpImpl initHttp"); WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { - httpProxy = new OkHttpProxyInfo(OkHttpProxyInfo.ProxyType.SOCKS5, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + httpProxy = OkHttpProxyInfo.socks5Proxy(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); } + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); + //设置代理 + if (httpProxy != null) { + clientBuilder.proxy(getRequestHttpProxy().getProxy()); - httpClient = new ConnectionPool(); + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + } + httpClient = clientBuilder.build(); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java index 61d4d18b37..40ac27465e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java @@ -6,13 +6,16 @@ import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.util.http.MaterialDeleteRequestExecutor; import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMaterialDeleteRequestExecutor extends MaterialDeleteRequestExecutor { +public class OkhttpMaterialDeleteRequestExecutor extends MaterialDeleteRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); public OkhttpMaterialDeleteRequestExecutor(RequestHttp requestHttp) { @@ -21,23 +24,9 @@ public OkhttpMaterialDeleteRequestExecutor(RequestHttp requestHttp) { @Override public Boolean execute(String uri, String materialId) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); - //设置代理 - if (requestHttp.getRequestHttpProxy() != null) { - clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); + logger.debug("OkhttpMaterialDeleteRequestExecutor is running"); //得到httpClient - OkHttpClient client = clientBuilder.build(); + OkHttpClient client = requestHttp.getRequestHttpClient(); RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); Request request = new Request.Builder().url(uri).post(requestBody).build(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java index a0a1c05231..3f46ab7880 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java @@ -16,7 +16,7 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { +public class OkhttpMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); public OkhttpMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { super(requestHttp); @@ -24,23 +24,9 @@ public OkhttpMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { @Override public WxMpMaterialNews execute(String uri, String materialId) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); - //设置代理 - if (requestHttp.getRequestHttpProxy() != null) { - clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); + //得到httpClient - OkHttpClient client = clientBuilder.build(); + OkHttpClient client = requestHttp.getRequestHttpClient(); RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); Request request = new Request.Builder().url(uri).post(requestBody).build(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java index 3770aa1b67..ef4bcbb299 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java @@ -9,6 +9,8 @@ import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; import me.chanjar.weixin.mp.util.http.MaterialUploadRequestExecutor; import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileNotFoundException; @@ -18,13 +20,16 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMaterialUploadRequestExecutor extends MaterialUploadRequestExecutor { +public class OkhttpMaterialUploadRequestExecutor extends MaterialUploadRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + public OkhttpMaterialUploadRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @Override public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material) throws WxErrorException, IOException { + logger.debug("OkhttpMaterialUploadRequestExecutor is running"); if (material == null) { throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); } @@ -33,21 +38,9 @@ public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material) throw throw new FileNotFoundException(); } - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); - //设置代理 - if (requestHttp.getRequestHttpProxy() != null) { - clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); + //得到httpClient + + OkHttpClient client = requestHttp.getRequestHttpClient(); MultipartBody.Builder bodyBuilder = new MultipartBody.Builder() .setType(MediaType.parse("multipart/form-data")) @@ -60,7 +53,7 @@ public Request authenticate(Route route, Response response) throws IOException { } Request request = new Request.Builder().url(uri).post(bodyBuilder.build()).build(); - Response response = clientBuilder.build().newCall(request).execute(); + Response response = client.newCall(request).execute(); String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java index 90c775bac6..79dd12be53 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java @@ -7,36 +7,26 @@ import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; import me.chanjar.weixin.mp.util.http.MaterialVideoInfoRequestExecutor; import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMaterialVideoInfoRequestExecutor extends MaterialVideoInfoRequestExecutor { +public class OkhttpMaterialVideoInfoRequestExecutor extends MaterialVideoInfoRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + public OkhttpMaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @Override public WxMpMaterialVideoInfoResult execute(String uri, String materialId) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); - //设置代理 - if (requestHttp.getRequestHttpProxy() != null) { - clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); + logger.debug("OkhttpMaterialVideoInfoRequestExecutor is running"); //得到httpClient - OkHttpClient client = clientBuilder.build(); + OkHttpClient client = requestHttp.getRequestHttpClient(); RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); Request request = new Request.Builder().url(uri).post(requestBody).build(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java index 1d0a5f7f65..8c48139183 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java @@ -7,62 +7,39 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.util.http.MaterialVoiceAndImageDownloadRequestExecutor; import okhttp3.*; +import okio.BufferedSink; +import okio.Okio; import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; +import java.io.*; /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMaterialVoiceAndImageDownloadRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { +public class OkhttpMaterialVoiceAndImageDownloadRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + public OkhttpMaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { super(requestHttp, tmpDirFile); } @Override public InputStream execute(String uri, String materialId) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); - //设置代理 - if (requestHttp.getRequestHttpProxy() != null) { - clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); - //得到httpClient - OkHttpClient client = clientBuilder.build(); - + logger.debug("OkhttpMaterialVoiceAndImageDownloadRequestExecutor is running"); + OkHttpClient client = requestHttp.getRequestHttpClient(); RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); Request request = new Request.Builder().url(uri).get().post(requestBody).build(); Response response = client.newCall(request).execute(); - - try (InputStream inputStream = new ByteArrayInputStream(response.body().bytes())) { - - // 下载媒体文件出错 - byte[] responseContent = IOUtils.toByteArray(inputStream); - String responseContentString = new String(responseContent, StandardCharsets.UTF_8); - if (responseContentString.length() < 100) { - try { - WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); - if (wxError.getErrorCode() != 0) { - throw new WxErrorException(wxError); - } - } catch (com.google.gson.JsonSyntaxException ex) { - return new ByteArrayInputStream(responseContent); - } - } - return new ByteArrayInputStream(responseContent); + String contentTypeHeader = response.header("Content-Type"); + if ("text/plain".equals(contentTypeHeader)) { + String responseContent = response.body().string(); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); BufferedSink sink = Okio.buffer(Okio.sink(outputStream))) { + sink.writeAll(response.body().source()); + return new ByteArrayInputStream(outputStream.toByteArray()); } } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java index 3b10f63bcf..f8e5859287 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java @@ -7,6 +7,8 @@ import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; import me.chanjar.weixin.mp.util.http.MediaImgUploadRequestExecutor; import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; @@ -14,7 +16,8 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpMediaImgUploadRequestExecutor extends MediaImgUploadRequestExecutor { +public class OkhttpMediaImgUploadRequestExecutor extends MediaImgUploadRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); public OkhttpMediaImgUploadRequestExecutor(RequestHttp requestHttp) { super(requestHttp); @@ -22,21 +25,9 @@ public OkhttpMediaImgUploadRequestExecutor(RequestHttp requestHttp) { @Override public WxMediaImgUploadResult execute(String uri, File file) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); - //设置代理 - if (requestHttp.getRequestHttpProxy() != null) { - clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); + logger.debug("OkhttpMediaImgUploadRequestExecutor is running"); + //得到httpClient + OkHttpClient client = requestHttp.getRequestHttpClient(); RequestBody body = new MultipartBody.Builder() .setType(MediaType.parse("multipart/form-data")) @@ -46,7 +37,7 @@ public Request authenticate(Route route, Response response) throws IOException { .build(); Request request = new Request.Builder().url(uri).post(body).build(); - Response response = clientBuilder.build().newCall(request).execute(); + Response response = client.newCall(request).execute(); String responseContent = response.body().string(); WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java index f401b021cc..2f9bcc7437 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java @@ -9,6 +9,10 @@ import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; import okhttp3.*; +import okio.BufferedSink; +import okio.Okio; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; import java.io.File; @@ -19,31 +23,18 @@ /** * Created by ecoolper on 2017/5/5. */ -public class OkhttpQrCodeRequestExecutor extends QrCodeRequestExecutor { +public class OkhttpQrCodeRequestExecutor extends QrCodeRequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + public OkhttpQrCodeRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @Override public File execute(String uri, WxMpQrCodeTicket data) throws WxErrorException, IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); - //设置代理 - if (requestHttp.getRequestHttpProxy() != null) { - clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); - } - //设置授权 - clientBuilder.authenticator(new Authenticator() { - @Override - public Request authenticate(Route route, Response response) throws IOException { - String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); - return response.request().newBuilder() - .header("Authorization", credential) - .build(); - } - }); + logger.debug("OkhttpQrCodeRequestExecutor is running"); //得到httpClient - OkHttpClient client = clientBuilder.build(); - + OkHttpClient client = requestHttp.getRequestHttpClient(); Request request = new Request.Builder().url(uri).get().build(); Response response = client.newCall(request).execute(); String contentTypeHeader = response.header("Content-Type"); @@ -51,8 +42,10 @@ public Request authenticate(Route route, Response response) throws IOException { String responseContent = response.body().string(); throw new WxErrorException(WxError.fromJson(responseContent)); } - try (InputStream inputStream = new ByteArrayInputStream(response.body().bytes())) { - return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + File temp = File.createTempFile(UUID.randomUUID().toString(), ".png"); + try (BufferedSink sink = Okio.buffer(Okio.sink(temp))) { + sink.writeAll(response.body().source()); } + return temp; } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java index c8b616fa96..7fb10716f0 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java @@ -29,4 +29,10 @@ public void testRefreshAccessToken() throws WxErrorException { Assert.assertTrue(StringUtils.isNotBlank(after)); } + public void testJsapiTicket() throws WxErrorException { + String jsapiTicket = this.wxService.getJsapiTicket(false); + System.out.println(jsapiTicket); + Assert.assertNotNull(jsapiTicket); + } + } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java index 9fd3227893..e6be87302d 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java @@ -20,11 +20,7 @@ public class WxMpJsAPITest { protected WxMpService wxService; - public void testJsapiTicket() throws WxErrorException { - String jsapiTicket = this.wxService.getJsapiTicket(false); - System.out.println(jsapiTicket); - Assert.assertNotNull(jsapiTicket); - } + public void test() { long timestamp = 1419835025l; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java index 036c534adc..2a9421a499 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java @@ -7,6 +7,7 @@ import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.impl.WxMpServiceApacheHttpClientImpl; +import me.chanjar.weixin.mp.api.impl.WxMpServiceOkHttpImpl; import java.io.IOException; import java.io.InputStream; @@ -19,7 +20,7 @@ public void configure(Binder binder) { try (InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml")) { TestConfigStorage config = this.fromXml(TestConfigStorage.class, is1); config.setAccessTokenLock(new ReentrantLock()); - WxMpService wxService = new WxMpServiceApacheHttpClientImpl(); + WxMpService wxService = new WxMpServiceOkHttpImpl(); wxService.setWxMpConfigStorage(config); binder.bind(WxMpService.class).toInstance(wxService); From 70d90c8b9bd57709245d6ef785c6c213edbee0e4 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 31 Jul 2017 17:42:17 +0800 Subject: [PATCH 164/179] =?UTF-8?q?=E9=9D=9E=E6=B3=95=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E7=9A=84=E5=BC=82=E5=B8=B8=E7=BB=9F=E4=B8=80=E4=BD=BF=E7=94=A8?= =?UTF-8?q?WxPayException?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binarywang/wxpay/bean/request/WxPayBaseRequest.java | 2 +- .../wxpay/bean/request/WxPayDownloadBillRequest.java | 7 ++++--- .../wxpay/bean/request/WxPayOrderQueryRequest.java | 5 +++-- .../wxpay/bean/request/WxPayOrderReverseRequest.java | 5 +++-- .../wxpay/bean/request/WxPayRefundQueryRequest.java | 5 +++-- .../binarywang/wxpay/bean/request/WxPayRefundRequest.java | 6 +++--- .../wxpay/bean/request/WxPayUnifiedOrderRequest.java | 8 ++++---- .../binarywang/wxpay/bean/result/WxPayBaseResult.java | 7 +++---- .../com/github/binarywang/wxpay/config/WxPayConfig.java | 4 ++-- .../wxpay/service/impl/WxPayServiceAbstractImpl.java | 2 +- .../wxpay/service/impl/WxPayServiceAbstractImplTest.java | 2 +- 11 files changed, 28 insertions(+), 25 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java index b0c2e85d5c..cc0490d22e 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java @@ -122,7 +122,7 @@ protected void checkFields() throws WxPayException { /** * 检查约束情况 */ - protected abstract void checkConstraints(); + protected abstract void checkConstraints() throws WxPayException; public String getAppid() { return this.appid; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadBillRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadBillRequest.java index ed02060f83..2838284c80 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadBillRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadBillRequest.java @@ -1,5 +1,6 @@ package com.github.binarywang.wxpay.bean.request; +import com.github.binarywang.wxpay.exception.WxPayException; import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.annotation.Required; import org.apache.commons.lang3.ArrayUtils; @@ -128,13 +129,13 @@ public void setTarType(String tarType) { } @Override - protected void checkConstraints() { + protected void checkConstraints() throws WxPayException { if (StringUtils.isNotBlank(this.getTarType()) && !"GZIP".equals(this.getTarType())) { - throw new IllegalArgumentException("tar_type值如果存在,只能为GZIP"); + throw new WxPayException("tar_type值如果存在,只能为GZIP"); } if (!ArrayUtils.contains(BILL_TYPE, this.getBillType())) { - throw new IllegalArgumentException(String.format("bill_tpye目前必须为%s其中之一,实际值:%s", + throw new WxPayException(String.format("bill_tpye目前必须为%s其中之一,实际值:%s", Arrays.toString(BILL_TYPE), this.getBillType())); } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryRequest.java index 499727995e..e7767da607 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryRequest.java @@ -1,5 +1,6 @@ package com.github.binarywang.wxpay.bean.request; +import com.github.binarywang.wxpay.exception.WxPayException; import com.thoughtworks.xstream.annotations.XStreamAlias; import org.apache.commons.lang3.StringUtils; @@ -64,10 +65,10 @@ public void setOutTradeNo(String outTradeNo) { } @Override - protected void checkConstraints() { + protected void checkConstraints() throws WxPayException { if ((StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo)) || (StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(outTradeNo))) { - throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时存在或同时为空,必须二选一"); + throw new WxPayException("transaction_id 和 out_trade_no 不能同时存在或同时为空,必须二选一"); } } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderReverseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderReverseRequest.java index 6aef2aa0fa..075295238e 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderReverseRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderReverseRequest.java @@ -1,5 +1,6 @@ package com.github.binarywang.wxpay.bean.request; +import com.github.binarywang.wxpay.exception.WxPayException; import com.thoughtworks.xstream.annotations.XStreamAlias; import org.apache.commons.lang3.StringUtils; @@ -91,9 +92,9 @@ public void setSignType(String signType) { } @Override - protected void checkConstraints() { + protected void checkConstraints() throws WxPayException { if (StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo)) { - throw new IllegalArgumentException("transaction_id 和 out_trade_no不能同时为空!"); + throw new WxPayException("transaction_id 和 out_trade_no不能同时为空!"); } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryRequest.java index 1efa23db7a..00545f004c 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryRequest.java @@ -1,5 +1,6 @@ package com.github.binarywang.wxpay.bean.request; +import com.github.binarywang.wxpay.exception.WxPayException; import com.thoughtworks.xstream.annotations.XStreamAlias; import org.apache.commons.lang3.StringUtils; @@ -135,12 +136,12 @@ public void setRefundId(String refundId) { } @Override - protected void checkConstraints() { + protected void checkConstraints() throws WxPayException { if ((StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo) && StringUtils.isBlank(outRefundNo) && StringUtils.isBlank(refundId)) || (StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(outTradeNo) && StringUtils.isNotBlank(outRefundNo) && StringUtils.isNotBlank(refundId))) { - throw new IllegalArgumentException("transaction_id,out_trade_no,out_refund_no,refund_id 必须四选一"); + throw new WxPayException("transaction_id,out_trade_no,out_refund_no,refund_id 必须四选一"); } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java index 7fae6fa0f5..66808738ca 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java @@ -271,16 +271,16 @@ public void checkAndSign(WxPayConfig config) throws WxPayException { } @Override - protected void checkConstraints() { + protected void checkConstraints() throws WxPayException { if (StringUtils.isNotBlank(this.getRefundAccount())) { if (!ArrayUtils.contains(REFUND_ACCOUNT, this.getRefundAccount())) { - throw new IllegalArgumentException(String.format("refund_account目前必须为%s其中之一,实际值:%s", + throw new WxPayException(String.format("refund_account目前必须为%s其中之一,实际值:%s", Arrays.toString(REFUND_ACCOUNT), this.getRefundAccount())); } } if (StringUtils.isBlank(this.getOutTradeNo()) && StringUtils.isBlank(this.getTransactionId())) { - throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时为空,必须提供一个"); + throw new WxPayException("transaction_id 和 out_trade_no 不能同时为空,必须提供一个"); } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java index 7c927425de..8061556cc7 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java @@ -500,18 +500,18 @@ public void setSceneInfo(String sceneInfo) { } @Override - protected void checkConstraints() { + protected void checkConstraints() throws WxPayException { // if (!ArrayUtils.contains(TRADE_TYPES, this.getTradeType())) { -// throw new IllegalArgumentException(String.format("trade_type目前必须为%s其中之一,实际值:%s", +// throw new WxPayException(String.format("trade_type目前必须为%s其中之一,实际值:%s", // Arrays.toString(TRADE_TYPES), this.getTradeType())); // } if ("JSAPI".equals(this.getTradeType()) && this.getOpenid() == null) { - throw new IllegalArgumentException("当 trade_type是'JSAPI'时未指定openid"); + throw new WxPayException("当 trade_type是'JSAPI'时未指定openid"); } if ("NATIVE".equals(this.getTradeType()) && this.getProductId() == null) { - throw new IllegalArgumentException("当 trade_type是'NATIVE'时未指定product_id"); + throw new WxPayException("当 trade_type是'NATIVE'时未指定product_id"); } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java index 802e22b312..d4b96dc408 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java @@ -316,8 +316,8 @@ public void checkResult(WxPayServiceAbstractImpl wxPayService) throws WxPayExcep } //校验结果是否成功 - if (!"SUCCESS".equalsIgnoreCase(getReturnCode()) - || !"SUCCESS".equalsIgnoreCase(getResultCode())) { + if (!StringUtils.equalsAny(StringUtils.trimToEmpty(getReturnCode()).toUpperCase(), "SUCCESS", "") + || !StringUtils.equalsAny(StringUtils.trimToEmpty(getResultCode()).toUpperCase(), "SUCCESS", "")) { StringBuilder errorMsg = new StringBuilder(); if (getReturnCode() != null) { errorMsg.append("返回代码:").append(getReturnCode()); @@ -335,8 +335,7 @@ public void checkResult(WxPayServiceAbstractImpl wxPayService) throws WxPayExcep errorMsg.append(",错误详情:").append(getErrCodeDes()); } - this.getLogger().error("\n结果业务代码异常,返回結果:{},\n{}", - map, errorMsg.toString()); + this.getLogger().error("\n结果业务代码异常,返回結果:{},\n{}", map, errorMsg.toString()); throw WxPayException.from(this); } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java index aeab939a06..b51f28e94a 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java @@ -160,11 +160,11 @@ public void setUseSandboxEnv(boolean useSandboxEnv) { public SSLContext initSSLContext() throws WxPayException { if (StringUtils.isBlank(mchId)) { - throw new IllegalArgumentException("请确保商户号mchId已设置"); + throw new WxPayException("请确保商户号mchId已设置"); } if (StringUtils.isBlank(this.keyPath)) { - throw new IllegalArgumentException("请确保证书文件地址keyPath已配置"); + throw new WxPayException("请确保证书文件地址keyPath已配置"); } InputStream inputStream; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java index 9a75b46973..616f860988 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java @@ -161,7 +161,7 @@ public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) @Override public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException { if (StringUtils.isBlank(outTradeNo)) { - throw new IllegalArgumentException("out_trade_no不能为空"); + throw new WxPayException("out_trade_no不能为空"); } WxPayOrderCloseRequest request = new WxPayOrderCloseRequest(); diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java index 9b57d77b1c..7ac35a6061 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java @@ -139,7 +139,7 @@ public void testUnifiedOrder() throws WxPayException { .unifiedOrder(WxPayUnifiedOrderRequest.newBuilder() .body("我去") .totalFee(1) - .spbillCreateIp("111111") + .spbillCreateIp("11.1.11.1") .notifyURL("111111") .tradeType("JSAPI") .openid(((XmlWxPayConfig) this.payService.getConfig()).getOpenid()) From 2d9d392889bcf6f63d105ecd41ad785c72a3620d Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 31 Jul 2017 17:44:48 +0800 Subject: [PATCH 165/179] =?UTF-8?q?=E5=8F=91=E5=B8=83=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC2.7.7.BETA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 0b78452d55..8bd9de49e5 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang weixin-java-parent - 2.7.6.BETA + 2.7.7.BETA pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 9299fa1ce7..f93c89abb8 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.6.BETA + 2.7.7.BETA weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 6732165602..6e0a3e27b2 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.6.BETA + 2.7.7.BETA weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index 181b505cd3..bc75c8f7f9 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.6.BETA + 2.7.7.BETA weixin-java-miniapp WeiXin Java Tools - MiniApp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 16648606b2..18de637004 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.6.BETA + 2.7.7.BETA weixin-java-mp WeiXin Java Tools - MP diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 4783621af5..0a65663c6b 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 2.7.6.BETA + 2.7.7.BETA 4.0.0 From 5a2b3b61a44c0805b5471172874e8bb9a9da86f5 Mon Sep 17 00:00:00 2001 From: dylanleung <0095103cn@gmail.com> Date: Mon, 31 Jul 2017 05:18:15 -0500 Subject: [PATCH 166/179] =?UTF-8?q?#295=20=E4=BF=AE=E5=A4=8D=E4=B8=B4?= =?UTF-8?q?=E6=97=B6=E6=96=87=E4=BB=B6=E5=85=B3=E9=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update travis settings * feat(okhttp): 修改okhttp底层调用方法 直接用OkHttpClient代替connect.使客户端单一化.Okhttp 自动管理连接池优化 * feat(log,jsApi): 添加log debug 标记明确下调用底层效果,修复jsAPI Lock 为null 问题 添加log debug 标记明确下调用底层效果,修复jsAPI Lock 为null 问题 #293 * fix(File): 修复文件关闭 修复文件关闭 * Update OkHttpMediaDownloadRequestExecutor.java --- .../main/java/me/chanjar/weixin/common/util/fs/FileUtils.java | 2 +- .../util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java | 1 + .../weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java index 37ee5ebe4b..df031b3371 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java @@ -24,7 +24,7 @@ public static File createTmpFile(InputStream inputStream, String name, String ex tmpFile = File.createTempFile(name, '.' + ext, tmpDirFile); } -// tmpFile.deleteOnExit(); + tmpFile.deleteOnExit(); try (FileOutputStream fos = new FileOutputStream(tmpFile)) { int read = 0; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java index e5346c2a26..246ce4dcc0 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java @@ -62,6 +62,7 @@ public File execute(String uri, String queryParam) throws WxErrorException, IOEx try (BufferedSink sink = Okio.buffer(Okio.sink(file))) { sink.writeAll(response.body().source()); } + file.deleteOnExit(); return file; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java index 2f9bcc7437..6feb137925 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java @@ -46,6 +46,8 @@ public File execute(String uri, WxMpQrCodeTicket data) throws WxErrorException, try (BufferedSink sink = Okio.buffer(Okio.sink(temp))) { sink.writeAll(response.body().source()); } + temp.deleteOnExit(); + return temp; } } From afcd62c065d1e2c9418b73bc8f9ebc49a6df1876 Mon Sep 17 00:00:00 2001 From: Bob Date: Tue, 1 Aug 2017 12:03:38 +0800 Subject: [PATCH 167/179] =?UTF-8?q?#297=20WxMpMenu=E7=B1=BB=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=AE=9E=E7=8E=B0=E5=BA=8F=E5=88=97=E5=8C=96=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java index 366ca2f1ba..3c154726fa 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java @@ -6,6 +6,7 @@ import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import java.io.Serializable; import java.util.List; /** @@ -15,7 +16,10 @@ * @author binarywang(Binary Wang) *
    */ -public class WxMpMenu { +public class WxMpMenu implements Serializable{ + + private static final long serialVersionUID = -5794350513426702252L; + @SerializedName("menu") private WxMpConditionalMenu menu; From 289405f8453bf0b57769b851f9692b2c888053e8 Mon Sep 17 00:00:00 2001 From: Bob Date: Tue, 1 Aug 2017 13:00:46 +0800 Subject: [PATCH 168/179] =?UTF-8?q?#298=20WxMpMenu=E7=9A=84=E5=86=85?= =?UTF-8?q?=E9=83=A8=E7=B1=BBWxMpConditionalMenu=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=BA=8F=E5=88=97=E5=8C=96=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java index 3c154726fa..6c7d3e8650 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java @@ -55,7 +55,10 @@ public String toJson() { return WxGsonBuilder.create().toJson(this); } - public static class WxMpConditionalMenu { + public static class WxMpConditionalMenu implements Serializable { + + private static final long serialVersionUID = -2279946921755382289L; + @SerializedName("button") private List buttons; @SerializedName("matchrule") From 9e32f00e6b9e98c78e4989394443a19da6b4d298 Mon Sep 17 00:00:00 2001 From: Bob Date: Tue, 8 Aug 2017 10:39:02 +0800 Subject: [PATCH 169/179] =?UTF-8?q?#302=20WxMpXmlOutNewsMessage=E7=B1=BB?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=86=85=E9=83=A8=E7=B1=BB=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=BA=8F=E5=88=97=E5=8C=96=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/bean/message/WxMpXmlOutNewsMessage.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessage.java index 1d4fb0c767..8865a39358 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessage.java @@ -5,6 +5,7 @@ import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -39,7 +40,9 @@ public List getArticles() { @XStreamAlias("item") - public static class Item { + public static class Item implements Serializable { + + private static final long serialVersionUID = -4971456355028904754L; @XStreamAlias("Title") @XStreamConverter(value = XStreamCDataConverter.class) From 6ce585f2460f01c42b2ec2f8161004f1a4f4128f Mon Sep 17 00:00:00 2001 From: kakotor Date: Thu, 10 Aug 2017 12:25:10 +0800 Subject: [PATCH 170/179] =?UTF-8?q?DefaultApacheHttpClientBuilder=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=8D=95=E4=BE=8B=E6=A8=A1=E5=BC=8F=20(#310)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DefaultApacheHttpClientBuilder.java | 23 +++++-- .../DefaultApacheHttpClientBuilderTest.java | 64 +++++++++++++++++++ 2 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilderTest.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java index b328ede9af..19c79bdcf2 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java @@ -68,13 +68,16 @@ public boolean retryRequest(IOException exception, int executionCount, HttpConte * 闲置连接监控线程 */ private IdleConnectionMonitorThread idleConnectionMonitorThread; - private HttpClientBuilder httpClientBuilder; + /** + * 持有client对象,仅初始化一次,避免多service实例的时候造成重复初始化的问题 + */ + private CloseableHttpClient closeableHttpClient; private DefaultApacheHttpClientBuilder() { } public static DefaultApacheHttpClientBuilder get() { - return new DefaultApacheHttpClientBuilder(); + return DefaultApacheHttpClientBuilder.SingletonHolder.INSTANCE; } @Override @@ -219,7 +222,7 @@ private synchronized void prepare() { this.idleConnectionMonitorThread.setDaemon(true); this.idleConnectionMonitorThread.start(); - this.httpClientBuilder = HttpClients.custom() + HttpClientBuilder httpClientBuilder = HttpClients.custom() .setConnectionManager(connectionManager) .setConnectionManagerShared(true) .setSSLSocketFactory(this.buildSSLConnectionSocketFactory()) @@ -240,12 +243,13 @@ private synchronized void prepare() { new AuthScope(this.httpProxyHost, this.httpProxyPort), new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword)); - this.httpClientBuilder.setDefaultCredentialsProvider(provider); + httpClientBuilder.setDefaultCredentialsProvider(provider); } if (StringUtils.isNotBlank(this.userAgent)) { - this.httpClientBuilder.setUserAgent(this.userAgent); + httpClientBuilder.setUserAgent(this.userAgent); } + this.closeableHttpClient = httpClientBuilder.build(); prepared.set(true); } @@ -277,7 +281,14 @@ public CloseableHttpClient build() { if (!prepared.get()) { prepare(); } - return this.httpClientBuilder.build(); + return this.closeableHttpClient; + } + + /** + * DefaultApacheHttpClientBuilder 改为单例模式,并持有唯一的CloseableHttpClient(仅首次调用创建) + */ + private static class SingletonHolder { + private static final DefaultApacheHttpClientBuilder INSTANCE = new DefaultApacheHttpClientBuilder(); } public static class IdleConnectionMonitorThread extends Thread { diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilderTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilderTest.java new file mode 100644 index 0000000000..24a45eea09 --- /dev/null +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilderTest.java @@ -0,0 +1,64 @@ +package me.chanjar.weixin.common.util.http.apache; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class DefaultApacheHttpClientBuilderTest { + @Test + public void testBuild() throws Exception { + DefaultApacheHttpClientBuilder builder1 = DefaultApacheHttpClientBuilder.get(); + DefaultApacheHttpClientBuilder builder2 = DefaultApacheHttpClientBuilder.get(); + Assert.assertSame(builder1, builder2, "DefaultApacheHttpClientBuilder为单例,获取到的对象应该相同"); + List threadList = new ArrayList<>(10); + for (int i = 0; i < 10; i++) { + TestThread thread = new TestThread(); + thread.start(); + threadList.add(thread); + } + for (TestThread testThread : threadList) { + testThread.join(); + Assert.assertNotEquals(-1,testThread.getRespState(),"请求响应code不应为-1"); + } + + for (int i = 1; i < threadList.size(); i++) { + TestThread thread1 = threadList.get(i - 1); + TestThread thread2 = threadList.get(i); + Assert.assertSame( + thread1.getClient(), + thread2.getClient(), + "DefaultApacheHttpClientBuilder为单例,并持有了相同的HttpClient" + ); + } + } + + + public static class TestThread extends Thread { + private CloseableHttpClient client; + private int respState = -1; + + @Override + public void run() { + client = DefaultApacheHttpClientBuilder.get().build(); + HttpGet httpGet = new HttpGet("http://www.sina.com.cn/"); + try (CloseableHttpResponse resp = client.execute(httpGet)){ + respState = resp.getStatusLine().getStatusCode(); + } catch (IOException ignored) { + } + } + + public CloseableHttpClient getClient() { + return client; + } + + public int getRespState() { + return respState; + } + } +} From 69ebad5e70a0284be05fd1f2350ce7a1af9684c5 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 11 Aug 2017 11:59:38 +0800 Subject: [PATCH 171/179] =?UTF-8?q?#300=20=E4=BF=AE=E5=A4=8D=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=A4=9A=E5=AA=92=E4=BD=93=E6=96=87=E4=BB=B6=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E5=90=8E=E7=BC=80=E5=90=8D=E6=97=B6=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/http/HttpResponseProxy.java | 88 +++++++++++++++++++ .../ApacheMediaDownloadRequestExecutor.java | 25 ++---- .../JoddHttpMediaDownloadRequestExecutor.java | 25 ++---- .../OkHttpMediaDownloadRequestExecutor.java | 33 ++----- 4 files changed, 107 insertions(+), 64 deletions(-) create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java new file mode 100644 index 0000000000..a75aa963e0 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java @@ -0,0 +1,88 @@ +package me.chanjar.weixin.common.util.http; + +import jodd.http.HttpResponse; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import okhttp3.Response; +import org.apache.http.Header; +import org.apache.http.client.methods.CloseableHttpResponse; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + *
    + * 三种http框架的response代理类,方便提取公共方法
    + * Created by Binary Wang on 2017-8-3.
    + * 
    + * + * @author Binary Wang + */ +public class HttpResponseProxy { + private CloseableHttpResponse apacheHttpResponse; + private HttpResponse joddHttpResponse; + private Response okHttpResponse; + + public HttpResponseProxy(CloseableHttpResponse apacheHttpResponse) { + this.apacheHttpResponse = apacheHttpResponse; + } + + public HttpResponseProxy(HttpResponse joddHttpResponse) { + this.joddHttpResponse = joddHttpResponse; + } + + public HttpResponseProxy(Response okHttpResponse) { + this.okHttpResponse = okHttpResponse; + } + + public String getFileName() throws WxErrorException { + //由于对象只能由一个构造方法实现,因此三个response对象必定且只有一个不为空 + if (this.apacheHttpResponse != null) { + return this.getFileName(this.apacheHttpResponse); + } + + if (this.joddHttpResponse != null) { + return this.getFileName(this.joddHttpResponse); + } + + if (this.okHttpResponse != null) { + return this.getFileName(this.okHttpResponse); + } + + //cannot happen + return null; + } + + private String getFileName(CloseableHttpResponse response) throws WxErrorException { + Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); + if (contentDispositionHeader == null || contentDispositionHeader.length == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + return this.extractFileNameFromContentString(contentDispositionHeader[0].getValue()); + } + + private String getFileName(HttpResponse response) throws WxErrorException { + String content = response.header("Content-disposition"); + return this.extractFileNameFromContentString(content); + } + + private String getFileName(Response response) throws WxErrorException { + String content = response.header("Content-disposition"); + return this.extractFileNameFromContentString(content); + } + + private String extractFileNameFromContentString(String content) throws WxErrorException { + if (content == null || content.length() == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(content); + if (m.matches()) { + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java index 6a928648e5..0a5a504873 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java @@ -3,8 +3,10 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.HttpResponseProxy; import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpHost; @@ -17,15 +19,12 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Created by ecoolper on 2017/5/5. */ public class ApacheMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor { - public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { super(requestHttp, tmpDirFile); } @@ -57,31 +56,17 @@ public File execute(String uri, String queryParam) throws WxErrorException, IOEx } } - String fileName = getFileName(response); + String fileName = new HttpResponseProxy(response).getFileName(); if (StringUtils.isBlank(fileName)) { return null; } - String[] nameAndExt = fileName.split("\\."); - return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], super.tmpDirFile); + return FileUtils.createTmpFile(inputStream, FilenameUtils.getBaseName(fileName), FilenameUtils.getExtension(fileName), + super.tmpDirFile); } finally { httpGet.releaseConnection(); } } - private String getFileName(CloseableHttpResponse response) throws WxErrorException { - Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); - if (contentDispositionHeader == null || contentDispositionHeader.length == 0) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - - Pattern p = Pattern.compile(".*filename=\"(.*)\""); - Matcher m = p.matcher(contentDispositionHeader[0].getValue()); - if (m.matches()) { - return m.group(1); - } - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java index edbee76678..bbd8bec47c 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java @@ -5,27 +5,25 @@ import jodd.http.HttpResponse; import jodd.http.ProxyInfo; import jodd.util.StringPool; - import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.HttpResponseProxy; import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Created by ecoolper on 2017/5/5. */ public class JoddHttpMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor { - public JoddHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { super(requestHttp, tmpDirFile); } @@ -54,28 +52,15 @@ public File execute(String uri, String queryParam) throws WxErrorException, IOEx throw new WxErrorException(WxError.fromJson(response.bodyText())); } - String fileName = getFileName(response); + String fileName = new HttpResponseProxy(response).getFileName(); if (StringUtils.isBlank(fileName)) { return null; } InputStream inputStream = new ByteArrayInputStream(response.bodyBytes()); - String[] nameAndExt = fileName.split("\\."); - return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], super.tmpDirFile); + return FileUtils.createTmpFile(inputStream, FilenameUtils.getBaseName(fileName), FilenameUtils.getExtension(fileName), + super.tmpDirFile); } - private String getFileName(HttpResponse response) throws WxErrorException { - String content = response.header("Content-disposition"); - if (content == null || content.length() == 0) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - - Pattern p = Pattern.compile(".*filename=\"(.*)\""); - Matcher m = p.matcher(content); - if (m.matches()) { - return m.group(1); - } - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java index 246ce4dcc0..0923527b71 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java @@ -2,22 +2,21 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.HttpResponseProxy; import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; -import okhttp3.*; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; import okio.BufferedSink; import okio.Okio; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Created by ecoolper on 2017/5/5. @@ -25,7 +24,6 @@ public class OkHttpMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public OkHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { super(requestHttp, tmpDirFile); } @@ -53,12 +51,13 @@ public File execute(String uri, String queryParam) throws WxErrorException, IOEx throw new WxErrorException(WxError.fromJson(response.body().string())); } - String fileName = getFileName(response); + String fileName = new HttpResponseProxy(response).getFileName(); if (StringUtils.isBlank(fileName)) { return null; } - String[] nameAndExt = fileName.split("\\."); - File file = File.createTempFile(nameAndExt[0], nameAndExt[1], super.tmpDirFile); + + File file = File.createTempFile(FilenameUtils.getBaseName(fileName), FilenameUtils.getExtension(fileName), + super.tmpDirFile); try (BufferedSink sink = Okio.buffer(Okio.sink(file))) { sink.writeAll(response.body().source()); } @@ -66,18 +65,4 @@ public File execute(String uri, String queryParam) throws WxErrorException, IOEx return file; } - private String getFileName(Response response) throws WxErrorException { - String content = response.header("Content-disposition"); - if (content == null || content.length() == 0) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - - Pattern p = Pattern.compile(".*filename=\"(.*)\""); - Matcher m = p.matcher(content); - if (m.matches()) { - return m.group(1); - } - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - } From 67dad47be7622f9c275c8410ee5e82b0dd02e681 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 14 Aug 2017 15:02:49 +0800 Subject: [PATCH 172/179] =?UTF-8?q?#305=20=E4=BF=AE=E5=A4=8D=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=8F=98=E6=80=81=E7=9A=84=E6=8B=8D=E7=85=A7=E6=88=96?= =?UTF-8?q?=E5=8F=91=E5=9B=BE=E4=BA=8B=E4=BB=B6=E7=9A=84=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E7=9A=84=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/bean/WxCpXmlMessage.java | 2 + .../weixin/cp/bean/WxCpXmlMessageTest.java | 97 ++++++++----- .../mp/bean/message/WxMpXmlMessage.java | 2 + .../mp/bean/message/WxMpXmlMessageTest.java | 131 +++++++++--------- 4 files changed, 133 insertions(+), 99 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java index 8b7ee5f166..117cf4115b 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java @@ -164,6 +164,8 @@ public class WxCpXmlMessage implements Serializable { private SendLocationInfo sendLocationInfo = new SendLocationInfo(); protected static WxCpXmlMessage fromXml(String xml) { + //修改微信变态的消息内容格式,方便解析 + xml = xml.replace("", ""); return XStreamTransformer.fromXml(WxCpXmlMessage.class, xml); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java index 74b526160b..87e16d773a 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java @@ -1,8 +1,9 @@ package me.chanjar.weixin.cp.bean; import me.chanjar.weixin.common.api.WxConsts; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.testng.annotations.*; + +import static org.testng.Assert.*; @Test public class WxCpXmlMessageTest { @@ -54,38 +55,66 @@ public void testFromXml() { + "" + ""; WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml); - Assert.assertEquals(wxMessage.getToUserName(), "toUser"); - Assert.assertEquals(wxMessage.getFromUserName(), "fromUser"); - Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860l)); - Assert.assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); - Assert.assertEquals(wxMessage.getContent(), "this is a test"); - Assert.assertEquals(wxMessage.getMsgId(), new Long(1234567890123456l)); - Assert.assertEquals(wxMessage.getPicUrl(), "this is a url"); - Assert.assertEquals(wxMessage.getMediaId(), "media_id"); - Assert.assertEquals(wxMessage.getFormat(), "Format"); - Assert.assertEquals(wxMessage.getThumbMediaId(), "thumb_media_id"); - Assert.assertEquals(wxMessage.getLocationX(), new Double(23.134521d)); - Assert.assertEquals(wxMessage.getLocationY(), new Double(113.358803d)); - Assert.assertEquals(wxMessage.getScale(), new Double(20)); - Assert.assertEquals(wxMessage.getLabel(), "位置信息"); - Assert.assertEquals(wxMessage.getDescription(), "公众平台官网链接"); - Assert.assertEquals(wxMessage.getUrl(), "url"); - Assert.assertEquals(wxMessage.getTitle(), "公众平台官网链接"); - Assert.assertEquals(wxMessage.getEvent(), "subscribe"); - Assert.assertEquals(wxMessage.getEventKey(), "qrscene_123123"); - Assert.assertEquals(wxMessage.getTicket(), "TICKET"); - Assert.assertEquals(wxMessage.getLatitude(), new Double(23.137466)); - Assert.assertEquals(wxMessage.getLongitude(), new Double(113.352425)); - Assert.assertEquals(wxMessage.getPrecision(), new Double(119.385040)); - Assert.assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); - Assert.assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); - Assert.assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1l)); - Assert.assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getScale(), "15"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getLabel(), " 广州市海珠区客村艺苑路 106号"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getPoiname(), "wo de poi"); + assertEquals(wxMessage.getToUserName(), "toUser"); + assertEquals(wxMessage.getFromUserName(), "fromUser"); + assertEquals(wxMessage.getCreateTime(), new Long(1348831860l)); + assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); + assertEquals(wxMessage.getContent(), "this is a test"); + assertEquals(wxMessage.getMsgId(), new Long(1234567890123456l)); + assertEquals(wxMessage.getPicUrl(), "this is a url"); + assertEquals(wxMessage.getMediaId(), "media_id"); + assertEquals(wxMessage.getFormat(), "Format"); + assertEquals(wxMessage.getThumbMediaId(), "thumb_media_id"); + assertEquals(wxMessage.getLocationX(), 23.134521d); + assertEquals(wxMessage.getLocationY(), 113.358803d); + assertEquals(wxMessage.getScale(), 20d); + assertEquals(wxMessage.getLabel(), "位置信息"); + assertEquals(wxMessage.getDescription(), "公众平台官网链接"); + assertEquals(wxMessage.getUrl(), "url"); + assertEquals(wxMessage.getTitle(), "公众平台官网链接"); + assertEquals(wxMessage.getEvent(), "subscribe"); + assertEquals(wxMessage.getEventKey(), "qrscene_123123"); + assertEquals(wxMessage.getTicket(), "TICKET"); + assertEquals(wxMessage.getLatitude(), 23.137466); + assertEquals(wxMessage.getLongitude(), 113.352425); + assertEquals(wxMessage.getPrecision(), 119.385040); + assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); + assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); + assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1l)); + assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); + assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); + assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); + assertEquals(wxMessage.getSendLocationInfo().getScale(), "15"); + assertEquals(wxMessage.getSendLocationInfo().getLabel(), " 广州市海珠区客村艺苑路 106号"); + assertEquals(wxMessage.getSendLocationInfo().getPoiname(), "wo de poi"); } + public void testSendPicsInfo() { + String xml = "" + + "" + + "" + + "1502012364" + + "" + + "1000004" + + "" + + "" + + "" + + "" + + "" + + "2" + + "" + + ""; + WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml.replace("","")); + assertEquals(wxMessage.getToUserName(), "wx45a0972125658be9"); + assertEquals(wxMessage.getFromUserName(), "xiaohe"); + assertEquals(wxMessage.getCreateTime(), new Long(1502012364L)); + assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_EVENT); + assertEquals(wxMessage.getAgentId(), Integer.valueOf(1000004)); + assertEquals(wxMessage.getEvent(), "pic_weixin"); + assertEquals(wxMessage.getEventKey(), "faceSimilarity"); + assertNotNull(wxMessage.getSendPicsInfo()); + assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(2L)); + assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "aef52ae501537e552725c5d7f99c1741"); + assertEquals(wxMessage.getSendPicsInfo().getPicList().get(1).getPicMd5Sum(), "c4564632a4fab91378c39bea6aad6f9e"); + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java index 262399b8f4..730310185c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java @@ -425,6 +425,8 @@ public class WxMpXmlMessage implements Serializable { private Integer deviceStatus; public static WxMpXmlMessage fromXml(String xml) { + //修改微信变态的消息内容格式,方便解析 + xml = xml.replace("", ""); return XStreamTransformer.fromXml(WxMpXmlMessage.class, xml); } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java index bbb8ce83ee..9c2bbf56ac 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java @@ -1,9 +1,10 @@ package me.chanjar.weixin.mp.bean.message; import me.chanjar.weixin.common.api.WxConsts; -import org.testng.*; import org.testng.annotations.*; +import static org.testng.Assert.*; + @Test public class WxMpXmlMessageTest { @@ -54,38 +55,38 @@ public void testFromXml() { + "" + ""; WxMpXmlMessage wxMessage = WxMpXmlMessage.fromXml(xml); - Assert.assertEquals(wxMessage.getToUser(), "toUser"); - Assert.assertEquals(wxMessage.getFromUser(), "fromUser"); - Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860L)); - Assert.assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); - Assert.assertEquals(wxMessage.getContent(), "this is a test"); - Assert.assertEquals(wxMessage.getMsgId(), new Long(1234567890123456L)); - Assert.assertEquals(wxMessage.getPicUrl(), "this is a url"); - Assert.assertEquals(wxMessage.getMediaId(), "media_id"); - Assert.assertEquals(wxMessage.getFormat(), "Format"); - Assert.assertEquals(wxMessage.getThumbMediaId(), "thumb_media_id"); - Assert.assertEquals(wxMessage.getLocationX(), 23.134521d); - Assert.assertEquals(wxMessage.getLocationY(), 113.358803d); - Assert.assertEquals(wxMessage.getScale(), 20d); - Assert.assertEquals(wxMessage.getLabel(), "位置信息"); - Assert.assertEquals(wxMessage.getDescription(), "公众平台官网链接"); - Assert.assertEquals(wxMessage.getUrl(), "url"); - Assert.assertEquals(wxMessage.getTitle(), "公众平台官网链接"); - Assert.assertEquals(wxMessage.getEvent(), "subscribe"); - Assert.assertEquals(wxMessage.getEventKey(), "qrscene_123123"); - Assert.assertEquals(wxMessage.getTicket(), "TICKET"); - Assert.assertEquals(wxMessage.getLatitude(), 23.137466); - Assert.assertEquals(wxMessage.getLongitude(), 113.352425); - Assert.assertEquals(wxMessage.getPrecision(), 119.385040); - Assert.assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); - Assert.assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); - Assert.assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1L)); - Assert.assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getScale(), "15"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getLabel(), " 广州市海珠区客村艺苑路 106号"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getPoiname(), "wo de poi"); + assertEquals(wxMessage.getToUser(), "toUser"); + assertEquals(wxMessage.getFromUser(), "fromUser"); + assertEquals(wxMessage.getCreateTime(), new Long(1348831860L)); + assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); + assertEquals(wxMessage.getContent(), "this is a test"); + assertEquals(wxMessage.getMsgId(), new Long(1234567890123456L)); + assertEquals(wxMessage.getPicUrl(), "this is a url"); + assertEquals(wxMessage.getMediaId(), "media_id"); + assertEquals(wxMessage.getFormat(), "Format"); + assertEquals(wxMessage.getThumbMediaId(), "thumb_media_id"); + assertEquals(wxMessage.getLocationX(), 23.134521d); + assertEquals(wxMessage.getLocationY(), 113.358803d); + assertEquals(wxMessage.getScale(), 20d); + assertEquals(wxMessage.getLabel(), "位置信息"); + assertEquals(wxMessage.getDescription(), "公众平台官网链接"); + assertEquals(wxMessage.getUrl(), "url"); + assertEquals(wxMessage.getTitle(), "公众平台官网链接"); + assertEquals(wxMessage.getEvent(), "subscribe"); + assertEquals(wxMessage.getEventKey(), "qrscene_123123"); + assertEquals(wxMessage.getTicket(), "TICKET"); + assertEquals(wxMessage.getLatitude(), 23.137466); + assertEquals(wxMessage.getLongitude(), 113.352425); + assertEquals(wxMessage.getPrecision(), 119.385040); + assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); + assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); + assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1L)); + assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); + assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); + assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); + assertEquals(wxMessage.getSendLocationInfo().getScale(), "15"); + assertEquals(wxMessage.getSendLocationInfo().getLabel(), " 广州市海珠区客村艺苑路 106号"); + assertEquals(wxMessage.getSendLocationInfo().getPoiname(), "wo de poi"); } public void testFromXml2() { @@ -135,38 +136,38 @@ public void testFromXml2() { + "" + ""; WxMpXmlMessage wxMessage = WxMpXmlMessage.fromXml(xml); - Assert.assertEquals(wxMessage.getToUser(), "toUser"); - Assert.assertEquals(wxMessage.getFromUser(), "fromUser"); - Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860L)); - Assert.assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); - Assert.assertEquals(wxMessage.getContent(), "this is a test"); - Assert.assertEquals(wxMessage.getMsgId(), new Long(1234567890123456L)); - Assert.assertEquals(wxMessage.getPicUrl(), "this is a url"); - Assert.assertEquals(wxMessage.getMediaId(), "media_id"); - Assert.assertEquals(wxMessage.getFormat(), "Format"); - Assert.assertEquals(wxMessage.getThumbMediaId(), "thumb_media_id"); - Assert.assertEquals(wxMessage.getLocationX(), 23.134521d); - Assert.assertEquals(wxMessage.getLocationY(), 113.358803d); - Assert.assertEquals(wxMessage.getScale(), 20d); - Assert.assertEquals(wxMessage.getLabel(), "位置信息"); - Assert.assertEquals(wxMessage.getDescription(), "公众平台官网链接"); - Assert.assertEquals(wxMessage.getUrl(), "url"); - Assert.assertEquals(wxMessage.getTitle(), "公众平台官网链接"); - Assert.assertEquals(wxMessage.getEvent(), "subscribe"); - Assert.assertEquals(wxMessage.getEventKey(), "qrscene_123123"); - Assert.assertEquals(wxMessage.getTicket(), "TICKET"); - Assert.assertEquals(wxMessage.getLatitude(), 23.137466); - Assert.assertEquals(wxMessage.getLongitude(), 113.352425); - Assert.assertEquals(wxMessage.getPrecision(), 119.385040); - Assert.assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); - Assert.assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); - Assert.assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1L)); - Assert.assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getScale(), "15"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getLabel(), " 广州市海珠区客村艺苑路 106号"); - Assert.assertEquals(wxMessage.getSendLocationInfo().getPoiname(), "wo de poi"); + assertEquals(wxMessage.getToUser(), "toUser"); + assertEquals(wxMessage.getFromUser(), "fromUser"); + assertEquals(wxMessage.getCreateTime(), new Long(1348831860L)); + assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); + assertEquals(wxMessage.getContent(), "this is a test"); + assertEquals(wxMessage.getMsgId(), new Long(1234567890123456L)); + assertEquals(wxMessage.getPicUrl(), "this is a url"); + assertEquals(wxMessage.getMediaId(), "media_id"); + assertEquals(wxMessage.getFormat(), "Format"); + assertEquals(wxMessage.getThumbMediaId(), "thumb_media_id"); + assertEquals(wxMessage.getLocationX(), 23.134521d); + assertEquals(wxMessage.getLocationY(), 113.358803d); + assertEquals(wxMessage.getScale(), 20d); + assertEquals(wxMessage.getLabel(), "位置信息"); + assertEquals(wxMessage.getDescription(), "公众平台官网链接"); + assertEquals(wxMessage.getUrl(), "url"); + assertEquals(wxMessage.getTitle(), "公众平台官网链接"); + assertEquals(wxMessage.getEvent(), "subscribe"); + assertEquals(wxMessage.getEventKey(), "qrscene_123123"); + assertEquals(wxMessage.getTicket(), "TICKET"); + assertEquals(wxMessage.getLatitude(), 23.137466); + assertEquals(wxMessage.getLongitude(), 113.352425); + assertEquals(wxMessage.getPrecision(), 119.385040); + assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); + assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); + assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1L)); + assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); + assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); + assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); + assertEquals(wxMessage.getSendLocationInfo().getScale(), "15"); + assertEquals(wxMessage.getSendLocationInfo().getLabel(), " 广州市海珠区客村艺苑路 106号"); + assertEquals(wxMessage.getSendLocationInfo().getPoiname(), "wo de poi"); } } From 1d1c4c74f0f86174516974f799efbb169757db4e Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 14 Aug 2017 15:14:13 +0800 Subject: [PATCH 173/179] =?UTF-8?q?=E5=8F=91=E5=B8=83=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC2.7.8.BETA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 8bd9de49e5..fd6312842c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang weixin-java-parent - 2.7.7.BETA + 2.7.8.BETA pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index f93c89abb8..bd7bb51cee 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.7.BETA + 2.7.8.BETA weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 6e0a3e27b2..330a34b098 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.7.BETA + 2.7.8.BETA weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index bc75c8f7f9..11ab7d392e 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.7.BETA + 2.7.8.BETA weixin-java-miniapp WeiXin Java Tools - MiniApp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 18de637004..d8aa707aee 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang weixin-java-parent - 2.7.7.BETA + 2.7.8.BETA weixin-java-mp WeiXin Java Tools - MP diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 0a65663c6b..74704e6a87 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 2.7.7.BETA + 2.7.8.BETA 4.0.0 From a8cdb44e6db6276b45e33f74b2a4340ed35699b2 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 14 Aug 2017 15:31:50 +0800 Subject: [PATCH 174/179] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=B8=8D=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E7=9A=84=E7=B1=BB=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...bstractWxCpServiceImpl.java => WxCpServiceAbstractImpl.java} | 2 +- .../weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java | 2 +- .../me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java | 2 +- .../me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java | 2 +- ...bstractWxMpServiceImpl.java => WxMpServiceAbstractImpl.java} | 2 +- .../weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java | 2 +- .../me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java | 2 +- .../me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/{AbstractWxCpServiceImpl.java => WxCpServiceAbstractImpl.java} (99%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/{AbstractWxMpServiceImpl.java => WxMpServiceAbstractImpl.java} (99%) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java similarity index 99% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java index be1b311857..a1f07e68cc 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java @@ -30,7 +30,7 @@ import java.io.InputStream; import java.util.List; -public abstract class AbstractWxCpServiceImpl implements WxCpService, RequestHttp { +public abstract class WxCpServiceAbstractImpl implements WxCpService, RequestHttp { protected final Logger log = LoggerFactory.getLogger(this.getClass()); private WxCpUserService userService = new WxCpUserServiceImpl(this); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java index d9388f0345..fc6249662b 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java @@ -17,7 +17,7 @@ import java.io.IOException; -public class WxCpServiceApacheHttpClientImpl extends AbstractWxCpServiceImpl { +public class WxCpServiceApacheHttpClientImpl extends WxCpServiceAbstractImpl { protected CloseableHttpClient httpClient; protected HttpHost httpProxy; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java index 3000916fac..5a14eb27fe 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java @@ -7,7 +7,7 @@ import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.cp.config.WxCpConfigStorage; -public class WxCpServiceJoddHttpImpl extends AbstractWxCpServiceImpl { +public class WxCpServiceJoddHttpImpl extends WxCpServiceAbstractImpl { protected HttpConnectionProvider httpClient; protected ProxyInfo httpProxy; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java index 2b8ae0c4af..2ad4c72015 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java @@ -12,7 +12,7 @@ import java.io.IOException; -public class WxCpServiceOkHttpImpl extends AbstractWxCpServiceImpl { +public class WxCpServiceOkHttpImpl extends WxCpServiceAbstractImpl { private final Logger logger = LoggerFactory.getLogger(this.getClass()); protected OkHttpClient httpClient; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceAbstractImpl.java similarity index 99% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceAbstractImpl.java index 25eeeadce4..fbf3861e00 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceAbstractImpl.java @@ -22,7 +22,7 @@ import java.io.IOException; import java.util.concurrent.locks.Lock; -public abstract class AbstractWxMpServiceImpl implements WxMpService, RequestHttp { +public abstract class WxMpServiceAbstractImpl implements WxMpService, RequestHttp { private static final JsonParser JSON_PARSER = new JsonParser(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java index d929b0974c..ceb0b783e2 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java @@ -21,7 +21,7 @@ /** * apache-http方式实现 */ -public class WxMpServiceApacheHttpClientImpl extends AbstractWxMpServiceImpl { +public class WxMpServiceApacheHttpClientImpl extends WxMpServiceAbstractImpl { private CloseableHttpClient httpClient; private HttpHost httpProxy; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java index 5c0fb75300..0551db67c6 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java @@ -14,7 +14,7 @@ /** * jodd-http方式实现 */ -public class WxMpServiceJoddHttpImpl extends AbstractWxMpServiceImpl { +public class WxMpServiceJoddHttpImpl extends WxMpServiceAbstractImpl { private HttpConnectionProvider httpClient; private ProxyInfo httpProxy; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java index dbb957b84c..9f2a17add1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java @@ -14,7 +14,7 @@ import java.io.IOException; import java.util.concurrent.locks.Lock; -public class WxMpServiceOkHttpImpl extends AbstractWxMpServiceImpl { +public class WxMpServiceOkHttpImpl extends WxMpServiceAbstractImpl { private final Logger logger = LoggerFactory.getLogger(this.getClass()); From 914042501519616643aad48bf2da09d22059ff30 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Wed, 16 Aug 2017 10:20:06 +0800 Subject: [PATCH 175/179] =?UTF-8?q?=E6=B7=BB=E5=8A=A0buttons=E7=9A=84gette?= =?UTF-8?q?r=E5=92=8Csetter=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java index 588e8a9c05..699a41ecfb 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java @@ -24,6 +24,14 @@ public String toString() { return ToStringUtils.toSimpleString(this); } + public List getButtons() { + return this.buttons; + } + + public void setButtons(List buttons) { + this.buttons = buttons; + } + public static class WxMpSelfMenuButton { /** *
    
    From af4bb1d85b4a6bd864535575c2fd64e7ad627502 Mon Sep 17 00:00:00 2001
    From: Binary Wang 
    Date: Wed, 16 Aug 2017 10:20:21 +0800
    Subject: [PATCH 176/179] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=99=E8=AF=AF?=
     =?UTF-8?q?=E7=9A=84javadoc?=
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    ---
     .../main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java  | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java
    index cee28b73ba..4a666eff1b 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java
    @@ -76,7 +76,7 @@ WxTagListUser tagListUser(Long tagId, String nextOpenid)
        * 
        * 批量为用户取消标签
        * 详情请见:用户标签管理
    -   * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token=ACCESS_TOKEN
    +   * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/members/batchuntagging?access_token=ACCESS_TOKEN
        * 
    */ boolean batchUntagging(Long tagId, String[] openids) throws WxErrorException; From 92947b344a24785215649b8388b45f71b012df71 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Wed, 16 Aug 2017 19:26:21 +0800 Subject: [PATCH 177/179] =?UTF-8?q?=E8=BD=AC=E7=A7=BB=E7=BE=A4=E5=8F=91?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3=E5=88=B0?= =?UTF-8?q?=E5=8D=95=E7=8B=AC=E6=8E=A5=E5=8F=A3=E5=8F=8A=E5=85=B6=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E7=B1=BB=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/WxMpMassMessageService.java | 95 +++++++++++++++++++ .../me/chanjar/weixin/mp/api/WxMpService.java | 83 +--------------- .../api/impl/WxMpMassMessageServiceImpl.java | 58 +++++++++++ .../mp/api/impl/WxMpServiceAbstractImpl.java | 36 ++----- .../WxMpMassMessageServiceImplTest.java} | 63 ++++++------ weixin-java-mp/src/test/resources/testng.xml | 2 +- 6 files changed, 197 insertions(+), 140 deletions(-) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMassMessageServiceImpl.java rename weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/{WxMpMassMessageAPITest.java => impl/WxMpMassMessageServiceImplTest.java} (80%) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java new file mode 100644 index 0000000000..e4a57de99b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java @@ -0,0 +1,95 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.bean.*; +import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult; +import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; + +/** + *
    + * 群发消息服务类
    + * Created by Binary Wang on 2017-8-16.
    + * 
    + * + * @author Binary Wang + */ +public interface WxMpMassMessageService { + /** + * 上传群发用的图文消息 + */ + String MEDIA_UPLOAD_NEWS_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; + /** + * 上传群发用的视频 + */ + String MEDIA_UPLOAD_VIDEO_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; + /** + * 分组群发消息 + */ + String MESSAGE_MASS_SENDALL_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; + /** + * 按openId列表群发消息 + */ + String MESSAGE_MASS_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; + /** + * 群发消息预览接口 + */ + String MESSAGE_MASS_PREVIEW_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; + + /** + *
    +   * 上传群发用的图文消息,上传后才能群发图文消息
    +   *
    +   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
    +   * 
    + * + * @see #massGroupMessageSend(WxMpMassTagMessage) + * @see #massOpenIdsMessageSend(WxMpMassOpenIdsMessage) + */ + WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException; + + /** + *
    +   * 上传群发用的视频,上传后才能群发视频消息
    +   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
    +   * 
    + * + * @see #massGroupMessageSend(WxMpMassTagMessage) + * @see #massOpenIdsMessageSend(WxMpMassOpenIdsMessage) + */ + WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException; + + /** + *
    +   * 分组群发消息
    +   * 如果发送图文消息,必须先使用 {@link #massNewsUpload(WxMpMassNews)} 获得media_id,然后再发送
    +   * 如果发送视频消息,必须先使用 {@link #massVideoUpload(WxMpMassVideo)} 获得media_id,然后再发送
    +   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
    +   * 
    + */ + WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException; + + /** + *
    +   * 按openId列表群发消息
    +   * 如果发送图文消息,必须先使用 {@link #massNewsUpload(WxMpMassNews)} 获得media_id,然后再发送
    +   * 如果发送视频消息,必须先使用 {@link #massVideoUpload(WxMpMassVideo)} 获得media_id,然后再发送
    +   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
    +   * 
    + */ + WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException; + + /** + *
    +   * 群发消息预览接口
    +   * 开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版。为了满足第三方平台开发者的需求,在保留对openID预览能力的同时,增加了对指定微信号发送预览的能力,但该能力每日调用次数有限制(100次),请勿滥用。
    +   * 接口调用请求说明
    +   *  http请求方式: POST
    +   *  https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=ACCESS_TOKEN
    +   * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
    +   * 
    + * + * @return wxMpMassSendResult + */ + WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index e4da721c8e..f684f4e8a4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -20,26 +20,6 @@ public interface WxMpService { * 获得jsapi_ticket */ String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; - /** - * 上传群发用的图文消息 - */ - String MEDIA_UPLOAD_NEWS_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; - /** - * 上传群发用的视频 - */ - String MEDIA_UPLOAD_VIDEO_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; - /** - * 分组群发消息 - */ - String MESSAGE_MASS_SENDALL_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; - /** - * 按openId列表群发消息 - */ - String MESSAGE_MASS_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; - /** - * 群发消息预览接口 - */ - String MESSAGE_MASS_PREVIEW_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; /** * 长链接转短链接接口 */ @@ -141,63 +121,6 @@ public interface WxMpService { */ WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; - /** - *
    -   * 上传群发用的图文消息,上传后才能群发图文消息
    -   *
    -   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
    -   * 
    - * - * @see #massGroupMessageSend(me.chanjar.weixin.mp.bean.WxMpMassTagMessage) - * @see #massOpenIdsMessageSend(me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage) - */ - WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException; - - /** - *
    -   * 上传群发用的视频,上传后才能群发视频消息
    -   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
    -   * 
    - * - * @see #massGroupMessageSend(me.chanjar.weixin.mp.bean.WxMpMassTagMessage) - * @see #massOpenIdsMessageSend(me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage) - */ - WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException; - - /** - *
    -   * 分组群发消息
    -   * 如果发送图文消息,必须先使用 {@link #massNewsUpload(me.chanjar.weixin.mp.bean.WxMpMassNews)} 获得media_id,然后再发送
    -   * 如果发送视频消息,必须先使用 {@link #massVideoUpload(me.chanjar.weixin.mp.bean.WxMpMassVideo)} 获得media_id,然后再发送
    -   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
    -   * 
    - */ - WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException; - - /** - *
    -   * 按openId列表群发消息
    -   * 如果发送图文消息,必须先使用 {@link #massNewsUpload(me.chanjar.weixin.mp.bean.WxMpMassNews)} 获得media_id,然后再发送
    -   * 如果发送视频消息,必须先使用 {@link #massVideoUpload(me.chanjar.weixin.mp.bean.WxMpMassVideo)} 获得media_id,然后再发送
    -   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
    -   * 
    - */ - WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException; - - /** - *
    -   * 群发消息预览接口
    -   * 开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版。为了满足第三方平台开发者的需求,在保留对openID预览能力的同时,增加了对指定微信号发送预览的能力,但该能力每日调用次数有限制(100次),请勿滥用。
    -   * 接口调用请求说明
    -   *  http请求方式: POST
    -   *  https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=ACCESS_TOKEN
    -   * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
    -   * 
    - * - * @return wxMpMassSendResult - */ - WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception; - /** *
        * 长链接转短链接接口
    @@ -451,5 +374,9 @@ public interface WxMpService {
        */
       RequestHttp getRequestHttp();
     
    -
    +  /**
    +   * 返回群发消息相关接口方法的实现类对象,以方便调用其各个接口
    +   * @return WxMpMassMessageService
    +   */
    +  WxMpMassMessageService getMassMessageService();
     }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMassMessageServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMassMessageServiceImpl.java
    new file mode 100644
    index 0000000000..015c465c0f
    --- /dev/null
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMassMessageServiceImpl.java
    @@ -0,0 +1,58 @@
    +package me.chanjar.weixin.mp.api.impl;
    +
    +import me.chanjar.weixin.common.exception.WxErrorException;
    +import me.chanjar.weixin.mp.api.WxMpMassMessageService;
    +import me.chanjar.weixin.mp.api.WxMpService;
    +import me.chanjar.weixin.mp.bean.*;
    +import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult;
    +import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +/**
    + * 
    + * 群发消息服务类
    + * Created by Binary Wang on 2017-8-16.
    + * 
    + * + * @author Binary Wang + */ +public class WxMpMassMessageServiceImpl implements WxMpMassMessageService { + protected final Logger log = LoggerFactory.getLogger(this.getClass()); + private WxMpService wxMpService; + + public WxMpMassMessageServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override + public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { + String responseContent = this.wxMpService.post(MEDIA_UPLOAD_NEWS_URL, news.toJson()); + return WxMpMassUploadResult.fromJson(responseContent); + } + + @Override + public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException { + String responseContent = this.wxMpService.post(MEDIA_UPLOAD_VIDEO_URL, video.toJson()); + return WxMpMassUploadResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException { + String responseContent = this.wxMpService.post(WxMpMassMessageService.MESSAGE_MASS_SENDALL_URL, message.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException { + String responseContent = this.wxMpService.post(MESSAGE_MASS_SEND_URL, message.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception { + String responseContent = this.wxMpService.post(MESSAGE_MASS_PREVIEW_URL, wxMpMassPreviewMessage.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceAbstractImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceAbstractImpl.java index fbf3861e00..91dff9babb 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceAbstractImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceAbstractImpl.java @@ -43,6 +43,7 @@ public abstract class WxMpServiceAbstractImpl implements WxMpService, Requ private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); private WxMpShakeService shakeService = new WxMpShakeServiceImpl(this); private WxMpMemberCardService memberCardService = new WxMpMemberCardServiceImpl(this); + private WxMpMassMessageService massMessageService = new WxMpMassMessageServiceImpl(this); private int retrySleepMillis = 1000; private int maxRetryTimes = 5; @@ -108,36 +109,6 @@ public String getAccessToken() throws WxErrorException { return getAccessToken(false); } - @Override - public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { - String responseContent = this.post(WxMpService.MEDIA_UPLOAD_NEWS_URL, news.toJson()); - return WxMpMassUploadResult.fromJson(responseContent); - } - - @Override - public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException { - String responseContent = this.post(WxMpService.MEDIA_UPLOAD_VIDEO_URL, video.toJson()); - return WxMpMassUploadResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException { - String responseContent = this.post(WxMpService.MESSAGE_MASS_SENDALL_URL, message.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException { - String responseContent = this.post(WxMpService.MESSAGE_MASS_SEND_URL, message.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception { - String responseContent = this.post(WxMpService.MESSAGE_MASS_PREVIEW_URL, wxMpMassPreviewMessage.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - @Override public String shortUrl(String long_url) throws WxErrorException { JsonObject o = new JsonObject(); @@ -415,4 +386,9 @@ public WxMpMemberCardService getMemberCardService() { public RequestHttp getRequestHttp() { return this; } + + @Override + public WxMpMassMessageService getMassMessageService() { + return this.massMessageService; + } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMassMessageServiceImplTest.java similarity index 80% rename from weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMassMessageServiceImplTest.java index dd7541ff8c..b896723ab0 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMassMessageServiceImplTest.java @@ -1,9 +1,10 @@ -package me.chanjar.weixin.mp.api; +package me.chanjar.weixin.mp.api.impl; import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.test.ApiTestModule; import me.chanjar.weixin.mp.api.test.TestConfigStorage; import me.chanjar.weixin.mp.api.test.TestConstants; @@ -13,21 +14,21 @@ import me.chanjar.weixin.mp.bean.WxMpMassVideo; import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult; import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; -import org.testng.*; import org.testng.annotations.*; import java.io.IOException; import java.io.InputStream; +import static org.testng.Assert.*; + /** * 测试群发消息 * * @author chanjarster */ -@Test(groups = "massAPI", dependsOnGroups = {"baseAPI", "mediaAPI", "groupAPI"}) +@Test @Guice(modules = ApiTestModule.class) -public class WxMpMassMessageAPITest { - +public class WxMpMassMessageServiceImplTest { @Inject protected WxMpService wxService; @@ -41,10 +42,10 @@ public void testTextMassOpenIdsMessageSend() throws WxErrorException { massMessage.setContent("测试群发消息\n欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); massMessage.getToUsers().add(configProvider.getOpenid()); - WxMpMassSendResult massResult = this.wxService + WxMpMassSendResult massResult = this.wxService.getMassMessageService() .massOpenIdsMessageSend(massMessage); - Assert.assertNotNull(massResult); - Assert.assertNotNull(massResult.getMsgId()); + assertNotNull(massResult); + assertNotNull(massResult.getMsgId()); } @Test(dataProvider = "massMessages") @@ -57,10 +58,10 @@ public void testMediaMassOpenIdsMessageSend(String massMsgType, String mediaId) massMessage.setMediaId(mediaId); massMessage.getToUsers().add(configProvider.getOpenid()); - WxMpMassSendResult massResult = this.wxService + WxMpMassSendResult massResult = this.wxService.getMassMessageService() .massOpenIdsMessageSend(massMessage); - Assert.assertNotNull(massResult); - Assert.assertNotNull(massResult.getMsgId()); + assertNotNull(massResult); + assertNotNull(massResult.getMsgId()); } @Test @@ -71,10 +72,10 @@ public void testTextMassGroupMessageSend() throws WxErrorException { massMessage .setTagId(this.wxService.getUserTagService().tagGet().get(0).getId()); - WxMpMassSendResult massResult = this.wxService + WxMpMassSendResult massResult = this.wxService.getMassMessageService() .massGroupMessageSend(massMessage); - Assert.assertNotNull(massResult); - Assert.assertNotNull(massResult.getMsgId()); + assertNotNull(massResult); + assertNotNull(massResult.getMsgId()); } @Test(dataProvider = "massMessages") @@ -85,10 +86,10 @@ public void testMediaMassGroupMessageSend(String massMsgType, String mediaId) massMessage.setMediaId(mediaId); massMessage.setTagId(this.wxService.getUserTagService().tagGet().get(0).getId()); - WxMpMassSendResult massResult = this.wxService + WxMpMassSendResult massResult = this.wxService.getMassMessageService() .massGroupMessageSend(massMessage); - Assert.assertNotNull(massResult); - Assert.assertNotNull(massResult.getMsgId()); + assertNotNull(massResult); + assertNotNull(massResult.getMsgId()); } @DataProvider @@ -103,17 +104,17 @@ public Object[][] massMessages() throws WxErrorException, IOException { // 上传视频到媒体库 WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService() .mediaUpload(WxConsts.MEDIA_VIDEO, TestConstants.FILE_MP4, inputStream); - Assert.assertNotNull(uploadMediaRes); - Assert.assertNotNull(uploadMediaRes.getMediaId()); + assertNotNull(uploadMediaRes); + assertNotNull(uploadMediaRes.getMediaId()); // 把视频变成可被群发的媒体 WxMpMassVideo video = new WxMpMassVideo(); video.setTitle("测试标题"); video.setDescription("测试描述"); video.setMediaId(uploadMediaRes.getMediaId()); - WxMpMassUploadResult uploadResult = this.wxService.massVideoUpload(video); - Assert.assertNotNull(uploadResult); - Assert.assertNotNull(uploadResult.getMediaId()); + WxMpMassUploadResult uploadResult = this.wxService.getMassMessageService().massVideoUpload(video); + assertNotNull(uploadResult); + assertNotNull(uploadResult.getMediaId()); messages[0] = new Object[]{WxConsts.MASS_MSG_VIDEO, uploadResult.getMediaId()}; } @@ -124,8 +125,8 @@ public Object[][] massMessages() throws WxErrorException, IOException { .getSystemResourceAsStream("mm.jpeg")) { WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService() .mediaUpload(WxConsts.MEDIA_IMAGE, TestConstants.FILE_JPG, inputStream); - Assert.assertNotNull(uploadMediaRes); - Assert.assertNotNull(uploadMediaRes.getMediaId()); + assertNotNull(uploadMediaRes); + assertNotNull(uploadMediaRes.getMediaId()); messages[1] = new Object[]{WxConsts.MASS_MSG_IMAGE, uploadMediaRes.getMediaId()}; } @@ -136,8 +137,8 @@ public Object[][] massMessages() throws WxErrorException, IOException { .getSystemResourceAsStream("mm.mp3")) { WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService() .mediaUpload(WxConsts.MEDIA_VOICE, TestConstants.FILE_MP3, inputStream); - Assert.assertNotNull(uploadMediaRes); - Assert.assertNotNull(uploadMediaRes.getMediaId()); + assertNotNull(uploadMediaRes); + assertNotNull(uploadMediaRes.getMediaId()); messages[2] = new Object[]{WxConsts.MASS_MSG_VOICE, uploadMediaRes.getMediaId()}; } @@ -149,8 +150,8 @@ public Object[][] massMessages() throws WxErrorException, IOException { // 上传照片到媒体库 WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService() .mediaUpload(WxConsts.MEDIA_IMAGE, TestConstants.FILE_JPG, inputStream); - Assert.assertNotNull(uploadMediaRes); - Assert.assertNotNull(uploadMediaRes.getMediaId()); + assertNotNull(uploadMediaRes); + assertNotNull(uploadMediaRes.getMediaId()); // 上传图文消息 WxMpMassNews news = new WxMpMassNews(); @@ -170,10 +171,10 @@ public Object[][] massMessages() throws WxErrorException, IOException { article2.setDigest("摘要2"); news.addArticle(article2); - WxMpMassUploadResult massUploadResult = this.wxService + WxMpMassUploadResult massUploadResult = this.wxService.getMassMessageService() .massNewsUpload(news); - Assert.assertNotNull(massUploadResult); - Assert.assertNotNull(uploadMediaRes.getMediaId()); + assertNotNull(massUploadResult); + assertNotNull(uploadMediaRes.getMediaId()); messages[3] = new Object[]{WxConsts.MASS_MSG_NEWS, massUploadResult.getMediaId()}; } diff --git a/weixin-java-mp/src/test/resources/testng.xml b/weixin-java-mp/src/test/resources/testng.xml index d864635569..ea264e6717 100644 --- a/weixin-java-mp/src/test/resources/testng.xml +++ b/weixin-java-mp/src/test/resources/testng.xml @@ -5,7 +5,7 @@ - + From f0d3a1af73e747e2896b5e792171ff9605d2c7ab Mon Sep 17 00:00:00 2001 From: forfuns Date: Thu, 17 Aug 2017 15:33:45 +0800 Subject: [PATCH 178/179] =?UTF-8?q?#315=20=E4=BF=AE=E6=94=B9messageSend?= =?UTF-8?q?=E6=96=B9=E6=B3=95=EF=BC=8C=E8=87=AA=E5=8A=A8=E4=BB=8EwxCpConfi?= =?UTF-8?q?gStorage=E8=8E=B7=E5=8F=96agentId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/api/impl/WxCpServiceAbstractImpl.java | 4 ++++ .../java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java index a1f07e68cc..43c3415ef1 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java @@ -131,6 +131,10 @@ public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException @Override public WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"; + Integer agentId = message.getAgentId(); + if(null == agentId){ + message.setAgentId(this.getWxCpConfigStorage().getAgentId()); + } return WxCpMessageSendResult.fromJson(this.post(url, message.toJson())); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java index 1e0d40b05b..0cecc01588 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java @@ -20,7 +20,8 @@ public class WxCpMessageAPITest { @Inject - protected WxCpServiceImpl wxService; + protected WxCpService wxService; + private ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage; @BeforeTest @@ -30,7 +31,7 @@ public void setup() { public void testSendMessage() throws WxErrorException { WxCpMessage message = new WxCpMessage(); - message.setAgentId(configStorage.getAgentId()); +// message.setAgentId(configStorage.getAgentId()); message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); message.setToUser(configStorage.getUserId()); message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); @@ -43,10 +44,11 @@ public void testSendMessage() throws WxErrorException { System.out.println(messageSendResult.getInvalidTagList()); } + @Test public void testSendMessage1() throws WxErrorException { WxCpMessage message = WxCpMessage .TEXT() - .agentId(configStorage.getAgentId()) +// .agentId(configStorage.getAgentId()) .toUser(configStorage.getUserId()) .content("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World") .build(); From bf1ce7ff168f63c60b0988c3879aa201999c8f43 Mon Sep 17 00:00:00 2001 From: forfuns Date: Fri, 18 Aug 2017 11:11:12 +0800 Subject: [PATCH 179/179] =?UTF-8?q?#317=20=E4=BF=AE=E5=A4=8D=E5=B0=8F?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E8=AF=B7=E6=B1=82=E4=BA=8C=E7=BB=B4=E7=A0=81?= =?UTF-8?q?=E6=97=B6=E5=AF=B9=E9=94=99=E8=AF=AF=E7=B1=BB=E5=9E=8B=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=EF=BC=88text/plain=20=E6=94=B9=E4=B8=BA=20app/json?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 更新messageSend自动向wxCpConfigStorage里获取agentId * 修复小程序请求二维码时对错误类型检查(text/plain 改为 app/json) * 修复小程序请求二维码时对错误类型检查(text/plain 改为 app/json) --- .../binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java index dc482dff25..3c026f4a18 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java @@ -48,7 +48,7 @@ public File execute(String uri, WxMaQrcodeWrapper ticket) throws WxErrorExceptio InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { Header[] contentTypeHeader = response.getHeaders("Content-Type"); if (contentTypeHeader != null && contentTypeHeader.length > 0 - && ContentType.TEXT_PLAIN.getMimeType().equals(contentTypeHeader[0].getValue())) { + && ContentType.APPLICATION_JSON.getMimeType().equals(contentTypeHeader[0].getValue())) { String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); throw new WxErrorException(WxError.fromJson(responseContent)); }