From 3d6778f83a7dae453e35c3d39a3d50037872e52e Mon Sep 17 00:00:00 2001 From: BinaryWang Date: Wed, 27 Jul 2016 17:57:13 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= =?UTF-8?q?=EF=BC=8C=E7=94=B1IDEA=E8=87=AA=E5=8A=A8=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E7=9A=84Code=20Cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/api/WxErrorExceptionHandler.java | 2 +- .../common/api/WxMessageDuplicateChecker.java | 2 +- .../WxMessageInMemoryDuplicateChecker.java | 6 +- .../common/session/InternalSession.java | 2 +- .../session/InternalSessionManager.java | 8 +-- .../common/session/StandardSession.java | 3 +- .../weixin/common/session/WxSession.java | 10 ++-- .../common/session/WxSessionManager.java | 4 +- .../util/http/InputStreamResponseHandler.java | 2 +- .../http/MediaDownloadRequestExecutor.java | 2 +- .../util/http/MediaUploadRequestExecutor.java | 2 +- .../common/util/http/RequestExecutor.java | 2 +- .../util/http/SimpleGetRequestExecutor.java | 2 +- .../util/http/SimplePostRequestExecutor.java | 2 +- .../common/util/http/Utf8ResponseHandler.java | 2 +- .../weixin/common/util/json/GsonHelper.java | 2 +- .../weixin/common/util/res/StringManager.java | 5 +- .../weixin/cp/api/WxCpConfigStorage.java | 44 +++++++-------- .../weixin/cp/api/WxCpMessageHandler.java | 8 +-- .../weixin/cp/api/WxCpMessageInterceptor.java | 8 +-- .../weixin/cp/api/WxCpMessageMatcher.java | 2 +- .../weixin/cp/api/WxCpMessageRouter.java | 5 +- .../me/chanjar/weixin/cp/api/WxCpService.java | 6 +- .../weixin/cp/api/WxCpMessageRouterTest.java | 1 - .../weixin/mp/api/WxMpConfigStorage.java | 56 +++++++++---------- .../weixin/mp/api/WxMpGroupService.java | 10 ++-- .../weixin/mp/api/WxMpMaterialService.java | 28 +++++----- .../weixin/mp/api/WxMpMenuService.java | 10 ++-- .../weixin/mp/api/WxMpMessageHandler.java | 8 +-- .../weixin/mp/api/WxMpMessageInterceptor.java | 8 +-- .../weixin/mp/api/WxMpMessageMatcher.java | 2 +- .../weixin/mp/api/WxMpMessageRouter.java | 5 +- .../weixin/mp/api/WxMpQrcodeService.java | 12 ++-- .../weixin/mp/api/WxMpUserService.java | 6 +- .../http/MaterialDeleteRequestExecutor.java | 2 +- .../http/MaterialNewsInfoRequestExecutor.java | 2 +- .../http/MaterialUploadRequestExecutor.java | 2 +- .../MaterialVideoInfoRequestExecutor.java | 2 +- ...lVoiceAndImageDownloadRequestExecutor.java | 2 +- .../http/MediaImgUploadRequestExecutor.java | 2 +- .../mp/util/http/QrCodeRequestExecutor.java | 2 +- .../util/json/WxLongTimeJsonSerializer.java | 2 +- .../mp/util/json/WxMpUserGsonAdapter.java | 2 +- .../weixin/mp/api/WxMpMessageRouterTest.java | 1 - 44 files changed, 140 insertions(+), 156 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxErrorExceptionHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxErrorExceptionHandler.java index 9abda804..d6acf55b 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxErrorExceptionHandler.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxErrorExceptionHandler.java @@ -7,6 +7,6 @@ import me.chanjar.weixin.common.exception.WxErrorException; */ public interface WxErrorExceptionHandler { - public void handle(WxErrorException e); + void handle(WxErrorException e); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageDuplicateChecker.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageDuplicateChecker.java index 6cdb689a..2bcc98f8 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageDuplicateChecker.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageDuplicateChecker.java @@ -22,6 +22,6 @@ public interface WxMessageDuplicateChecker { * @param messageId messageId需要根据上面讲的方式构造 * @return 如果是重复消息,返回true,否则返回false */ - public boolean isDuplicate(String messageId); + boolean isDuplicate(String messageId); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java index 1efc7a27..5b0f4e4e 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java @@ -87,11 +87,7 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec } checkBackgroundProcessStarted(); Long timestamp = msgId2Timestamp.putIfAbsent(messageId, System.currentTimeMillis()); - if (timestamp == null) { - // 第一次接收到这个消息 - return false; - } - return true; + return timestamp != null; } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSession.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSession.java index 79a7f4db..283672af 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSession.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSession.java @@ -13,7 +13,7 @@ public interface InternalSession { * * @param isValid The new value for the isValid flag */ - public void setValid(boolean isValid); + void setValid(boolean isValid); /** * Return the isValid flag for this session. diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java index 556d8ab8..bb9a8dca 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java @@ -28,14 +28,14 @@ public interface InternalSessionManager { * @exception IllegalStateException if a new session cannot be * instantiated for any reason */ - public InternalSession createSession(String sessionId); + InternalSession createSession(String sessionId); /** * Remove this Session from the active Sessions for this Manager. * * @param session Session to be removed */ - public void remove(InternalSession session); + void remove(InternalSession session); /** * Remove this Session from the active Sessions for this Manager. @@ -43,7 +43,7 @@ public interface InternalSessionManager { * @param session Session to be removed * @param update Should the expiration statistics be updated */ - public void remove(InternalSession session, boolean update); + void remove(InternalSession session, boolean update); /** * Add this Session to the set of active Sessions for this Manager. @@ -71,7 +71,7 @@ public interface InternalSessionManager { /** * Implements the Manager interface, direct call to processExpires */ - public void backgroundProcess(); + void backgroundProcess(); /** * Set the default maximum inactive interval (in seconds) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSession.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSession.java index d9827308..b482c2b7 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSession.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSession.java @@ -323,9 +323,8 @@ public class StandardSession implements WxSession, InternalSession { if (!attributes.equals(session.attributes)) return false; if (!facade.equals(session.facade)) return false; if (!id.equals(session.id)) return false; - if (!manager.equals(session.manager)) return false; + return manager.equals(session.manager); - return true; } @Override diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSession.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSession.java index 816b172b..25bed2d2 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSession.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSession.java @@ -4,14 +4,14 @@ import java.util.Enumeration; public interface WxSession { - public Object getAttribute(String name); + Object getAttribute(String name); - public Enumeration getAttributeNames(); + Enumeration getAttributeNames(); - public void setAttribute(String name, Object value); + void setAttribute(String name, Object value); - public void removeAttribute(String name); + void removeAttribute(String name); - public void invalidate(); + void invalidate(); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java index 9f74162e..c966ddab 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java @@ -5,12 +5,12 @@ public interface WxSessionManager { /** * 获取某个sessionId对应的session,如果sessionId没有对应的session,则新建一个并返回。 */ - public WxSession getSession(String sessionId); + WxSession getSession(String sessionId); /** * 获取某个sessionId对应的session,如果sessionId没有对应的session,若create为true则新建一个,否则返回null。 */ - public WxSession getSession(String sessionId, boolean create); + WxSession getSession(String sessionId, boolean create); } 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 index cf7f26cf..1bf13b9c 100644 --- 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 @@ -14,7 +14,7 @@ public class InputStreamResponseHandler implements ResponseHandler public static final ResponseHandler INSTANCE = new InputStreamResponseHandler(); - public InputStream handleResponse(final HttpResponse response) throws HttpResponseException, IOException { + public InputStream handleResponse(final HttpResponse response) throws IOException { final StatusLine statusLine = response.getStatusLine(); final HttpEntity entity = response.getEntity(); if (statusLine.getStatusCode() >= 300) { 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 c0bd21ce..306ac258 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 @@ -39,7 +39,7 @@ public class MediaDownloadRequestExecutor implements RequestExecutor { @Override - public WxMediaUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File file) throws WxErrorException, ClientProtocolException, IOException { + 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(); 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 1172a2fc..50f52468 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,6 +26,6 @@ public interface RequestExecutor { * @throws ClientProtocolException * @throws IOException */ - public T execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, E data) throws WxErrorException, ClientProtocolException, IOException; + T execute(CloseableHttpClient httpclient, HttpHost httpProxy, 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 5a1fb328..36852377 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 @@ -19,7 +19,7 @@ import java.io.IOException; public class SimpleGetRequestExecutor implements RequestExecutor { @Override - public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, ClientProtocolException, IOException { + public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { if (queryParam != null) { if (uri.indexOf('?') == -1) { uri += '?'; 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 1613c96c..e60ee06f 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 @@ -21,7 +21,7 @@ import java.io.IOException; public class SimplePostRequestExecutor implements RequestExecutor { @Override - public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String postEntity) throws WxErrorException, ClientProtocolException, IOException { + 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(); 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 index bad067c0..1ca1929a 100644 --- 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 @@ -19,7 +19,7 @@ public class Utf8ResponseHandler implements ResponseHandler { public static final ResponseHandler INSTANCE = new Utf8ResponseHandler(); - public String handleResponse(final HttpResponse response) throws HttpResponseException, IOException { + public String handleResponse(final HttpResponse response) throws IOException { final StatusLine statusLine = response.getStatusLine(); final HttpEntity entity = response.getEntity(); if (statusLine.getStatusCode() >= 300) { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java index 614e28e2..9c274569 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java @@ -91,7 +91,7 @@ public class GsonHelper { public static boolean getAsPrimitiveBool(JsonElement element) { Boolean r = getAsBoolean(element); - return r == null ? false : r.booleanValue(); + return r != null && r.booleanValue(); } public static Double getAsDouble(JsonElement element) { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/res/StringManager.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/res/StringManager.java index 4668ec25..0abe4d89 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/res/StringManager.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/res/StringManager.java @@ -211,10 +211,7 @@ public class StringManager { @Override protected boolean removeEldestEntry( Map.Entry eldest) { - if (size() > (LOCALE_CACHE_SIZE - 1)) { - return true; - } - return false; + return size() > (LOCALE_CACHE_SIZE - 1); } }; managers.put(packageName, map); 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 38e6135a..2b2ccf1d 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 @@ -12,61 +12,61 @@ import java.io.File; */ public interface WxCpConfigStorage { - public String getAccessToken(); + String getAccessToken(); - public boolean isAccessTokenExpired(); + boolean isAccessTokenExpired(); /** * 强制将access token过期掉 */ - public void expireAccessToken(); + void expireAccessToken(); - public void updateAccessToken(WxAccessToken accessToken); + void updateAccessToken(WxAccessToken accessToken); - public void updateAccessToken(String accessToken, int expiresIn); + void updateAccessToken(String accessToken, int expiresIn); - public String getJsapiTicket(); + String getJsapiTicket(); - public boolean isJsapiTicketExpired(); + boolean isJsapiTicketExpired(); /** * 强制将jsapi ticket过期掉 */ - public void expireJsapiTicket(); + void expireJsapiTicket(); /** * 应该是线程安全的 * @param jsapiTicket */ - public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); + void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); - public String getCorpId(); + String getCorpId(); - public String getCorpSecret(); + String getCorpSecret(); - public String getAgentId(); + String getAgentId(); - public String getToken(); + String getToken(); - public String getAesKey(); + String getAesKey(); - public long getExpiresTime(); + long getExpiresTime(); - public String getOauth2redirectUri(); + String getOauth2redirectUri(); - public String getHttp_proxy_host(); + String getHttp_proxy_host(); - public int getHttp_proxy_port(); + int getHttp_proxy_port(); - public String getHttp_proxy_username(); + String getHttp_proxy_username(); - public String getHttp_proxy_password(); + String getHttp_proxy_password(); - public File getTmpDirFile(); + File getTmpDirFile(); /** * http client builder * @return ApacheHttpClientBuilder */ - public ApacheHttpClientBuilder getApacheHttpClientBuilder(); + ApacheHttpClientBuilder getApacheHttpClientBuilder(); } 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/api/WxCpMessageHandler.java index e4ee9ec7..36649c46 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/api/WxCpMessageHandler.java @@ -22,9 +22,9 @@ public interface WxCpMessageHandler { * @param sessionManager * @return xml格式的消息,如果在异步规则里处理的话,可以返回null */ - public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, - Map context, - WxCpService wxCpService, - WxSessionManager sessionManager) throws WxErrorException; + 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/api/WxCpMessageInterceptor.java index f17e7954..e6de0e69 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/api/WxCpMessageInterceptor.java @@ -22,9 +22,9 @@ public interface WxCpMessageInterceptor { * @param sessionManager * @return true代表OK,false代表不OK */ - public boolean intercept(WxCpXmlMessage wxMessage, - Map context, - WxCpService wxCpService, - WxSessionManager sessionManager) throws WxErrorException; + 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/api/WxCpMessageMatcher.java index 09fbdd21..c2c62b93 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/api/WxCpMessageMatcher.java @@ -10,6 +10,6 @@ public interface WxCpMessageMatcher { /** * 消息是否匹配某种模式 */ - public boolean match(WxCpXmlMessage message); + 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/api/WxCpMessageRouter.java index 96b4e77d..f7e5286b 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 @@ -210,10 +210,7 @@ public class WxCpMessageRouter { messageId = String.valueOf(wxMessage.getMsgId()); } - if (messageDuplicateChecker.isDuplicate(messageId)) { - return true; - } - return false; + return messageDuplicateChecker.isDuplicate(messageId); } 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 33de577d..7cf9332a 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 @@ -70,7 +70,7 @@ public interface WxCpService { * @see #getJsapiTicket(boolean) * @throws WxErrorException */ - public String getJsapiTicket() throws WxErrorException; + String getJsapiTicket() throws WxErrorException; /** *
@@ -82,7 +82,7 @@ public interface WxCpService {
    * @param forceRefresh 强制刷新
    * @throws WxErrorException
    */
-  public String getJsapiTicket(boolean forceRefresh) throws WxErrorException;
+  String getJsapiTicket(boolean forceRefresh) throws WxErrorException;
 
   /**
    * 
@@ -92,7 +92,7 @@ public interface WxCpService {
    * 
* @param url url */ - public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; + WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; /** *
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 aac58a10..ccf981dd 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
@@ -49,7 +49,6 @@ public class WxCpMessageRouterTest {
         }
       }).handler(new WxEchoCpMessageHandler(sb, "matcher")).end()
       .rule().async(async).handler(new WxEchoCpMessageHandler(sb, "ALL")).end();
-    ;
   }
   
   @Test(dataProvider="messages-1")
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 d57b94a8..0cf9d2e1 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
@@ -13,89 +13,89 @@ import java.io.File;
  */
 public interface WxMpConfigStorage {
 
-  public String getAccessToken();
+  String getAccessToken();
 
-  public boolean isAccessTokenExpired();
+  boolean isAccessTokenExpired();
 
   /**
    * 强制将access token过期掉
    */
-  public void expireAccessToken();
+  void expireAccessToken();
 
   /**
    * 应该是线程安全的
    * @param accessToken
    */
-  public void updateAccessToken(WxAccessToken accessToken);
+  void updateAccessToken(WxAccessToken accessToken);
 
   /**
    * 应该是线程安全的
    * @param accessToken
    * @param expiresIn
    */
-  public void updateAccessToken(String accessToken, int expiresIn);
+  void updateAccessToken(String accessToken, int expiresIn);
 
-  public String getJsapiTicket();
+  String getJsapiTicket();
 
-  public boolean isJsapiTicketExpired();
+  boolean isJsapiTicketExpired();
 
   /**
    * 强制将jsapi ticket过期掉
    */
-  public void expireJsapiTicket();
+  void expireJsapiTicket();
 
   /**
    * 应该是线程安全的
    * @param jsapiTicket
    */
-  public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
+  void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
 
-  public String getCardApiTicket();
+  String getCardApiTicket();
 
-  public boolean isCardApiTicketExpired();
+  boolean isCardApiTicketExpired();
 
   /**
    * 强制将卡券api ticket过期掉
    */
-  public void expireCardApiTicket();
+  void expireCardApiTicket();
 
   /**
    * 应该是线程安全的
    * @param cardApiTicket
    */
-  public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds);
+  void updateCardApiTicket(String cardApiTicket, int expiresInSeconds);
 
-  public String getAppId();
+  String getAppId();
 
-  public String getSecret();
+  String getSecret();
 
-  public String getPartnerId();
+  String getPartnerId();
   
-  public String getPartnerKey();
+  String getPartnerKey();
 
-  public String getToken();
+  String getToken();
 
-  public String getAesKey();
+  String getAesKey();
 
-  public long getExpiresTime();
+  long getExpiresTime();
 
-  public String getOauth2redirectUri();
+  String getOauth2redirectUri();
 
-  public String getHttp_proxy_host();
+  String getHttp_proxy_host();
 
-  public int getHttp_proxy_port();
+  int getHttp_proxy_port();
 
-  public String getHttp_proxy_username();
+  String getHttp_proxy_username();
 
-  public String getHttp_proxy_password();
+  String getHttp_proxy_password();
   
-  public File getTmpDirFile();
+  File getTmpDirFile();
 
-  public SSLContext getSSLContext();
+  SSLContext getSSLContext();
 
   /**
    * http client builder
    * @return ApacheHttpClientBuilder
    */
-  public ApacheHttpClientBuilder getApacheHttpClientBuilder();
+  ApacheHttpClientBuilder getApacheHttpClientBuilder();
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGroupService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGroupService.java
index 80cadd55..80bcf524 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGroupService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGroupService.java
@@ -22,7 +22,7 @@ public interface WxMpGroupService {
    *
    * @param name 分组名字(30个字符以内)
    */
-  public WxMpGroup groupCreate(String name) throws WxErrorException;
+  WxMpGroup groupCreate(String name) throws WxErrorException;
 
   /**
    * 
@@ -30,7 +30,7 @@ public interface WxMpGroupService {
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
    * 
*/ - public List groupGet() throws WxErrorException; + List groupGet() throws WxErrorException; /** *
@@ -40,7 +40,7 @@ public interface WxMpGroupService {
    *
    * @param openid 微信用户的openid
    */
-  public long userGetGroup(String openid) throws WxErrorException;
+  long userGetGroup(String openid) throws WxErrorException;
 
   /**
    * 
@@ -52,7 +52,7 @@ public interface WxMpGroupService {
    *
    * @param group 要更新的group,group的id,name必须设置
    */
-  public void groupUpdate(WxMpGroup group) throws WxErrorException;
+  void groupUpdate(WxMpGroup group) throws WxErrorException;
 
   /**
    * 
@@ -65,5 +65,5 @@ public interface WxMpGroupService {
    * @param openid     用户openid
    * @param to_groupid 移动到的分组id
    */
-  public void userUpdateGroup(String openid, long to_groupid) throws WxErrorException;
+  void userUpdateGroup(String openid, long to_groupid) throws WxErrorException;
 }
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 7254a008..2325ccac 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
@@ -25,7 +25,7 @@ public interface WxMpMaterialService {
    * @throws WxErrorException
    * @see #mediaUpload(String, String, InputStream)
    */
-  public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException;
+  WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException;
 
   /**
    * 
@@ -39,7 +39,7 @@ public interface WxMpMaterialService {
    * @return 保存到本地的临时文件
    * @throws WxErrorException
    */
-  public File mediaDownload(String media_id) throws WxErrorException;
+  File mediaDownload(String media_id) throws WxErrorException;
 
   /**
    * 
@@ -51,7 +51,7 @@ public interface WxMpMaterialService {
    * @return WxMediaImgUploadResult 返回图片url
    * @throws WxErrorException
    */
-  public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException;
+  WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException;
 
   /**
    * 
@@ -72,7 +72,7 @@ public interface WxMpMaterialService {
    * @param inputStream 输入流
    * @throws WxErrorException
    */
-  public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException;
+  WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException;
 
   /**
    * 
@@ -90,7 +90,7 @@ public interface WxMpMaterialService {
    * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts}
    * @param material  上传的素材, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterial}
    */
-  public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException;
+  WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException;
 
   /**
    * 
@@ -101,7 +101,7 @@ public interface WxMpMaterialService {
    *
    * @param news 上传的图文消息, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterialNews}
    */
-  public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException;
+  WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException;
 
   /**
    * 
@@ -112,7 +112,7 @@ public interface WxMpMaterialService {
    *
    * @param media_id 永久素材的id
    */
-  public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException;
+  InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException;
 
   /**
    * 
@@ -123,7 +123,7 @@ public interface WxMpMaterialService {
    *
    * @param media_id 永久素材的id
    */
-  public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException;
+  WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException;
 
   /**
    * 
@@ -134,7 +134,7 @@ public interface WxMpMaterialService {
    *
    * @param media_id 永久素材的id
    */
-  public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException;
+  WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException;
 
   /**
    * 
@@ -145,7 +145,7 @@ public interface WxMpMaterialService {
    *
    * @param wxMpMaterialArticleUpdate 用来更新图文素材的bean, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterialArticleUpdate}
    */
-  public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException;
+  boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException;
 
   /**
    * 
@@ -156,7 +156,7 @@ public interface WxMpMaterialService {
    *
    * @param media_id 永久素材的id
    */
-  public boolean materialDelete(String media_id) throws WxErrorException;
+  boolean materialDelete(String media_id) throws WxErrorException;
 
   /**
    * 
@@ -165,7 +165,7 @@ public interface WxMpMaterialService {
    * 详情请见: http://mp.weixin.qq.com/wiki/16/8cc64f8c189674b421bee3ed403993b8.html
    * 
*/ - public WxMpMaterialCountResult materialCount() throws WxErrorException; + WxMpMaterialCountResult materialCount() throws WxErrorException; /** *
@@ -177,7 +177,7 @@ public interface WxMpMaterialService {
    * @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回
    * @param count  返回素材的数量,取值在1到20之间
    */
-  public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException;
+  WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException;
 
   /**
    * 
@@ -190,6 +190,6 @@ public interface WxMpMaterialService {
    * @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回
    * @param count  返回素材的数量,取值在1到20之间
    */
-  public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException;
+  WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException;
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java
index 670921db..31ce48d3 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java
@@ -18,7 +18,7 @@ public interface WxMpMenuService {
    * 详情请见:http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
    * 
*/ - public void menuCreate(WxMenu menu) throws WxErrorException; + void menuCreate(WxMenu menu) throws WxErrorException; /** *
@@ -26,7 +26,7 @@ public interface WxMpMenuService {
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
    * 
*/ - public void menuDelete() throws WxErrorException; + void menuDelete() throws WxErrorException; /** *
@@ -36,7 +36,7 @@ public interface WxMpMenuService {
    *
    * @param menuid
    */
-  public void menuDelete(String menuid) throws WxErrorException;
+  void menuDelete(String menuid) throws WxErrorException;
 
   /**
    * 
@@ -44,7 +44,7 @@ public interface WxMpMenuService {
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
    * 
*/ - public WxMenu menuGet() throws WxErrorException; + WxMenu menuGet() throws WxErrorException; /** *
@@ -54,6 +54,6 @@ public interface WxMpMenuService {
    *
    * @param userid 可以是粉丝的OpenID,也可以是粉丝的微信号。
    */
-  public WxMenu menuTryMatch(String userid) throws WxErrorException;
+  WxMenu menuTryMatch(String userid) throws WxErrorException;
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java
index 0fbc589c..dae2a238 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java
@@ -21,9 +21,9 @@ public interface WxMpMessageHandler {
    * @param sessionManager
    * @return xml格式的消息,如果在异步规则里处理的话,可以返回null
    */
-  public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
-                                  Map context,
-                                  WxMpService wxMpService,
-                                  WxSessionManager sessionManager) throws WxErrorException;
+  WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                           Map context,
+                           WxMpService wxMpService,
+                           WxSessionManager sessionManager) throws WxErrorException;
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageInterceptor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageInterceptor.java
index 4b60c450..3fcd6d95 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageInterceptor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageInterceptor.java
@@ -22,9 +22,9 @@ public interface WxMpMessageInterceptor {
    * @param sessionManager
    * @return true代表OK,false代表不OK
    */
-  public boolean intercept(WxMpXmlMessage wxMessage,
-                            Map context,
-                            WxMpService wxMpService,
-                            WxSessionManager sessionManager) throws WxErrorException;
+  boolean intercept(WxMpXmlMessage wxMessage,
+                    Map context,
+                    WxMpService wxMpService,
+                    WxSessionManager sessionManager) throws WxErrorException;
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageMatcher.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageMatcher.java
index c4e3c456..68798ae2 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageMatcher.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageMatcher.java
@@ -11,6 +11,6 @@ public interface WxMpMessageMatcher {
    * 消息是否匹配某种模式
    * @param message
    */
-  public boolean match(WxMpXmlMessage message);
+  boolean match(WxMpXmlMessage message);
 
 }
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 73d0cabe..1de7ba90 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
@@ -209,10 +209,7 @@ public class WxMpMessageRouter {
       messageId.append(wxMessage.getMsgId());
     }
 
-    if (messageDuplicateChecker.isDuplicate(messageId.toString())) {
-      return true;
-    }
-    return false;
+    return messageDuplicateChecker.isDuplicate(messageId.toString());
 
   }
 
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 2015ae1b..7997a70d 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
@@ -21,7 +21,7 @@ public interface WxMpQrcodeService {
    * @param scene_id       参数。
    * @param expire_seconds 过期秒数,默认60秒,最小60秒,最大1800秒
    */
-  public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException;
+  WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException;
 
   /**
    * 
@@ -31,7 +31,7 @@ public interface WxMpQrcodeService {
    *
    * @param scene_id 参数。永久二维码时最大值为100000(目前参数只支持1--100000)
    */
-  public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException;
+  WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException;
 
   /**
    * 
@@ -41,7 +41,7 @@ public interface WxMpQrcodeService {
    *
    * @param scene_str 参数。字符串类型长度现在为1到64
    */
-  public WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException;
+  WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException;
 
   /**
    * 
@@ -51,7 +51,7 @@ public interface WxMpQrcodeService {
    *
    * @param ticket 二维码ticket
    */
-  public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException;
+  File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException;
 
   /**
    * 
@@ -62,7 +62,7 @@ public interface WxMpQrcodeService {
    * @param ticket       二维码ticket
    * @param needShortUrl 是否需要压缩的二维码地址
    */
-  public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException;
+  String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException;
 
   /**
    * 
@@ -72,6 +72,6 @@ public interface WxMpQrcodeService {
    *
    * @param ticket 二维码ticket
    */
-  public String qrCodePictureUrl(String ticket) throws WxErrorException;
+  String qrCodePictureUrl(String ticket) throws WxErrorException;
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java
index 818087b4..0705e990 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java
@@ -25,7 +25,7 @@ public interface WxMpUserService {
    * @param openid 用户openid
    * @param remark 备注名
    */
-  public void userUpdateRemark(String openid, String remark) throws WxErrorException;
+  void userUpdateRemark(String openid, String remark) throws WxErrorException;
 
   /**
    * 
@@ -36,7 +36,7 @@ public interface WxMpUserService {
    * @param openid 用户openid
    * @param lang   语言,zh_CN 简体(默认),zh_TW 繁体,en 英语
    */
-  public WxMpUser userInfo(String openid, String lang) throws WxErrorException;
+  WxMpUser userInfo(String openid, String lang) throws WxErrorException;
 
   /**
    * 
@@ -46,7 +46,7 @@ public interface WxMpUserService {
    *
    * @param next_openid 可选,第一个拉取的OPENID,null为从头开始拉取
    */
-  public WxMpUserList userList(String next_openid) throws WxErrorException;
+  WxMpUserList userList(String next_openid) throws WxErrorException;
 
   /**
    * 
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 751261bf..e0529bd3 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
@@ -24,7 +24,7 @@ public class MaterialDeleteRequestExecutor implements RequestExecutor {
 
   @Override
-  public WxMpMaterialUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, WxMpMaterial material) throws WxErrorException, ClientProtocolException, IOException {
+  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();
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 c9698b49..1434c8eb 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
@@ -24,7 +24,7 @@ public class MaterialVideoInfoRequestExecutor implements RequestExecutor {
   @Override
-  public WxMediaImgUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File data) throws WxErrorException, ClientProtocolException, IOException {
+  public WxMediaImgUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File data) 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/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java
index a643c68d..96e444e7 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
@@ -31,7 +31,7 @@ public class QrCodeRequestExecutor implements RequestExecutor {
   @Override
   public void serialize(Long value, JsonGenerator gen,
       SerializerProvider serializers)
-      throws IOException, JsonProcessingException {
+      throws IOException {
     gen.writeString(DF.format(value * 1000));
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java
index 0b80e90a..060c362a 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java
@@ -21,7 +21,7 @@ public class WxMpUserGsonAdapter implements JsonDeserializer {
     WxMpUser wxMpUser = new WxMpUser();
     Integer subscribe = GsonHelper.getInteger(o, "subscribe");
     if (subscribe != null) {
-      wxMpUser.setSubscribe(new Integer(0).equals(subscribe) ? false : true);
+      wxMpUser.setSubscribe(!new Integer(0).equals(subscribe));
     }
     wxMpUser.setCity(GsonHelper.getString(o, "city"));
     wxMpUser.setCountry(GsonHelper.getString(o, "country"));
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 bcc78edd..a6cb0a63 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
@@ -49,7 +49,6 @@ public class WxMpMessageRouterTest {
         }
       }).handler(new WxEchoMpMessageHandler(sb, "matcher")).end()
       .rule().async(async).handler(new WxEchoMpMessageHandler(sb, "ALL")).end();
-    ;
   }
   
   @Test(dataProvider="messages-1")

From 1e4dd17ff50310cce4aff0e74b319068f7369b2e Mon Sep 17 00:00:00 2001
From: BinaryWang 
Date: Thu, 28 Jul 2016 09:52:19 +0800
Subject: [PATCH 2/3] =?UTF-8?q?=E5=8D=A1=E5=88=B8=E6=8E=A5=E5=8F=A3?=
 =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E5=87=BA=E5=8D=95=E7=8B=AC=E7=B1=BB?=
 =?UTF-8?q?=E4=B8=AD=E7=BB=B4=E6=8A=A4=EF=BC=8C=E5=B9=B6=E6=B7=BB=E5=8A=A0?=
 =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../common/bean/WxCardApiSignature.java       | 128 ++++-----
 .../weixin/mp/api/WxMpCardService.java        | 115 ++++++++
 .../me/chanjar/weixin/mp/api/WxMpService.java | 168 +++---------
 .../mp/api/impl/WxMpCardServiceImpl.java      | 248 ++++++++++++++++++
 .../weixin/mp/api/impl/WxMpServiceImpl.java   | 236 +----------------
 .../weixin/mp/bean/result/WxMpCardResult.java |  11 +-
 .../mp/api/impl/WxMpCardServiceImplTest.java  |  93 +++++++
 7 files changed, 574 insertions(+), 425 deletions(-)
 create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java
 create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java
 create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java

diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java
index e1d1b058..898decfa 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java
@@ -1,5 +1,8 @@
 package me.chanjar.weixin.common.bean;
 
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
 import java.io.Serializable;
 
 /**
@@ -10,95 +13,100 @@ import java.io.Serializable;
  */
 public class WxCardApiSignature implements Serializable {
 
-    private static final long serialVersionUID = 158176707226975979L;
+  private static final long serialVersionUID = 158176707226975979L;
 
-    private String appId;
+  private String appId;
 
-    private String cardId;
+  private String cardId;
 
-    private String cardType;
+  private String cardType;
 
-    private String locationId;
+  private String locationId;
 
-    private String code;
+  private String code;
 
-    private String openId;
+  private String openId;
 
-    private Long timestamp;
+  private Long timestamp;
 
-    private String nonceStr;
+  private String nonceStr;
 
-    private String signature;
+  private String signature;
 
-    public String getAppId() {
-      return appId;
-    }
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+  }
 
-    public void setAppId(String appId) {
-      this.appId = appId;
-    }
+  public String getAppId() {
+    return appId;
+  }
+
+  public void setAppId(String appId) {
+    this.appId = appId;
+  }
 
-    public String getCardId() {
-      return cardId;
-    }
+  public String getCardId() {
+    return cardId;
+  }
 
-    public void setCardId(String cardId) {
-      this.cardId = cardId;
-    }
+  public void setCardId(String cardId) {
+    this.cardId = cardId;
+  }
 
-    public String getCardType() {
-      return cardType;
-    }
+  public String getCardType() {
+    return cardType;
+  }
 
-    public void setCardType(String cardType) {
-      this.cardType = cardType;
-    }
+  public void setCardType(String cardType) {
+    this.cardType = cardType;
+  }
 
-    public String getLocationId() {
-      return locationId;
-    }
+  public String getLocationId() {
+    return locationId;
+  }
 
   public void setLocationId(String locationId) {
     this.locationId = locationId;
   }
 
   public String getCode() {
-      return code;
-    }
+    return code;
+  }
 
-    public void setCode(String code) {
-      this.code = code;
-    }
+  public void setCode(String code) {
+    this.code = code;
+  }
 
-    public String getOpenId() {
-      return openId;
-    }
+  public String getOpenId() {
+    return openId;
+  }
 
-    public void setOpenId(String openId) {
-      this.openId = openId;
-    }
+  public void setOpenId(String openId) {
+    this.openId = openId;
+  }
 
-    public Long getTimestamp() {
-      return timestamp;
-    }
+  public Long getTimestamp() {
+    return timestamp;
+  }
 
-    public void setTimestamp(Long timestamp) {
-      this.timestamp = timestamp;
-    }
+  public void setTimestamp(Long timestamp) {
+    this.timestamp = timestamp;
+  }
 
-    public String getNonceStr() {
-      return nonceStr;
-    }
+  public String getNonceStr() {
+    return nonceStr;
+  }
 
-    public void setNonceStr(String nonceStr) {
-      this.nonceStr = nonceStr;
-    }
+  public void setNonceStr(String nonceStr) {
+    this.nonceStr = nonceStr;
+  }
 
-    public String getSignature() {
-      return signature;
-    }
+  public String getSignature() {
+    return signature;
+  }
 
-    public void setSignature(String signature) {
-      this.signature = signature;
-    }
+  public void setSignature(String signature) {
+    this.signature = signature;
+  }
 }
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
new file mode 100644
index 00000000..80bf38a6
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java
@@ -0,0 +1,115 @@
+package me.chanjar.weixin.mp.api;
+
+import me.chanjar.weixin.common.bean.WxCardApiSignature;
+import me.chanjar.weixin.common.exception.WxErrorException;
+import me.chanjar.weixin.mp.bean.result.WxMpCardResult;
+
+/**
+ * 卡券相关接口
+ * Created by Binary Wang on 2016/7/27.
+ * @author binarywang(https://github.com/binarywang)
+ */
+public interface WxMpCardService {
+
+  /**
+   * 获得卡券api_ticket,不强制刷新卡券api_ticket
+   *
+   * @return 卡券api_ticket
+   * @throws WxErrorException
+   * @see #getCardApiTicket(boolean)
+   */
+  String getCardApiTicket() throws WxErrorException;
+
+  /**
+   * 
+   * 获得卡券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 + * @throws WxErrorException + */ + String getCardApiTicket(boolean forceRefresh) throws WxErrorException; + + /** + *
+   * 创建调用卡券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签名对象 + */ + WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws + WxErrorException; + + /** + * 卡券Code解码 + * + * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 + * @return 解密后的Code + */ + String decryptCardCode(String encryptCode) throws WxErrorException; + + /** + * 卡券Code查询 + * + * @param cardId 卡券ID代表一类卡券 + * @param code 单张卡券的唯一标准 + * @param checkConsume 是否校验code核销状态,填入true和false时的code异常状态返回数据不同 + * @return WxMpCardResult对象 + */ + WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) + throws WxErrorException; + + /** + * 卡券Code核销。核销失败会抛出异常 + * + * @param code 单张卡券的唯一标准 + * @return 调用返回的JSON字符串。 + *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + */ + String consumeCardCode(String code) throws WxErrorException; + + /** + * 卡券Code核销。核销失败会抛出异常 + * + * @param code 单张卡券的唯一标准 + * @param cardId 当自定义Code卡券时需要传入card_id + * @return 调用返回的JSON字符串。 + *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + */ + String consumeCardCode(String code, String cardId) throws WxErrorException; + + /** + * 卡券Mark接口。 + * 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住), + * 才能进一步调用核销接口,否则报错。 + * + * @param code 卡券的code码 + * @param cardId 卡券的ID + * @param openId 用券用户的openid + * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 + */ + void markCardCode(String code, String cardId, String openId, boolean isMark) throws + WxErrorException; + + /** + * 查看卡券详情接口 + * 详见 https://mp.weixin.qq.com/wiki/14/8dd77aeaee85f922db5f8aa6386d385e.html#.E6.9F.A5.E7.9C.8B.E5.8D.A1.E5.88.B8.E8.AF.A6.E6.83.85 + * + * @param cardId 卡券的ID + * @return 返回的卡券详情JSON字符串 + *
[注] 由于返回的JSON格式过于复杂,难以定义其对应格式的Bean并且难以维护,因此只返回String格式的JSON串。 + *
可由 com.google.gson.JsonParser#parse 等方法直接取JSON串中的某个字段。 + */ + String getCardDetail(String cardId) 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 7bff3027..3811647b 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 @@ -1,6 +1,5 @@ package me.chanjar.weixin.mp.api; -import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; @@ -15,7 +14,7 @@ import java.util.Map; */ public interface WxMpService { - public static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); /** *
@@ -23,14 +22,14 @@ public interface WxMpService {
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=验证消息真实性
    * 
*/ - public boolean checkSignature(String timestamp, String nonce, String signature); + boolean checkSignature(String timestamp, String nonce, String signature); /** * 获取access_token, 不强制刷新access_token * * @see #getAccessToken(boolean) */ - public String getAccessToken() throws WxErrorException; + String getAccessToken() throws WxErrorException; /** *
@@ -46,14 +45,14 @@ public interface WxMpService {
    *
    * @param forceRefresh 强制刷新
    */
-  public String getAccessToken(boolean forceRefresh) throws WxErrorException;
+  String getAccessToken(boolean forceRefresh) throws WxErrorException;
 
   /**
    * 获得jsapi_ticket,不强制刷新jsapi_ticket
    *
    * @see #getJsapiTicket(boolean)
    */
-  public String getJsapiTicket() throws WxErrorException;
+  String getJsapiTicket() throws WxErrorException;
 
   /**
    * 
@@ -65,7 +64,7 @@ public interface WxMpService {
    *
    * @param forceRefresh 强制刷新
    */
-  public String getJsapiTicket(boolean forceRefresh) throws WxErrorException;
+  String getJsapiTicket(boolean forceRefresh) throws WxErrorException;
 
   /**
    * 
@@ -74,7 +73,7 @@ public interface WxMpService {
    * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95
    * 
*/ - public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; + WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; /** *
@@ -82,7 +81,7 @@ public interface WxMpService {
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
    * 
*/ - public void customMessageSend(WxMpCustomMessage message) throws WxErrorException; + void customMessageSend(WxMpCustomMessage message) throws WxErrorException; /** *
@@ -96,7 +95,7 @@ public interface WxMpService {
    * @see #massGroupMessageSend(me.chanjar.weixin.mp.bean.WxMpMassGroupMessage)
    * @see #massOpenIdsMessageSend(me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage)
    */
-  public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException;
+  WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException;
 
   /**
    * 
@@ -107,7 +106,7 @@ public interface WxMpService {
    * @see #massGroupMessageSend(me.chanjar.weixin.mp.bean.WxMpMassGroupMessage)
    * @see #massOpenIdsMessageSend(me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage)
    */
-  public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException;
+  WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException;
 
   /**
    * 
@@ -117,7 +116,7 @@ public interface WxMpService {
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口
    * 
*/ - public WxMpMassSendResult massGroupMessageSend(WxMpMassGroupMessage message) throws WxErrorException; + WxMpMassSendResult massGroupMessageSend(WxMpMassGroupMessage message) throws WxErrorException; /** *
@@ -127,7 +126,7 @@ public interface WxMpService {
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口
    * 
*/ - public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException; + WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException; /** *
@@ -137,7 +136,7 @@ public interface WxMpService {
    *
    * @param long_url
    */
-  public String shortUrl(String long_url) throws WxErrorException;
+  String shortUrl(String long_url) throws WxErrorException;
 
   /**
    * 
@@ -149,7 +148,7 @@ public interface WxMpService {
    * @return msgid
    * @throws WxErrorException
    */
-  public String templateSend(WxMpTemplateMessage templateMessage) throws WxErrorException;
+  String templateSend(WxMpTemplateMessage templateMessage) throws WxErrorException;
 
   /**
    * 
@@ -169,7 +168,7 @@ public interface WxMpService {
    * @param state
    * @return url
    */
-  public String oauth2buildAuthorizationUrl(String scope, String state);
+  String oauth2buildAuthorizationUrl(String scope, String state);
 
   /**
    * 
@@ -182,7 +181,7 @@ public interface WxMpService {
    * @param state
    * @return url
    */
-  public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state);
+  String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state);
 
   /**
    * 
@@ -190,14 +189,14 @@ public interface WxMpService {
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息
    * 
*/ - public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException; + WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException; /** *
    * 刷新oauth2的access token
    * 
*/ - public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException; + WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException; /** *
@@ -207,7 +206,7 @@ public interface WxMpService {
    * @param oAuth2AccessToken
    * @param lang              zh_CN, zh_TW, en
    */
-  public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException;
+  WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException;
 
   /**
    * 
@@ -216,7 +215,7 @@ public interface WxMpService {
    *
    * @param oAuth2AccessToken
    */
-  public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken);
+  boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken);
 
   /**
    * 
@@ -243,12 +242,12 @@ public interface WxMpService {
    * 可以参考,{@link me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor}的实现方法
    * 
*/ - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; /** * 注入 {@link WxMpConfigStorage} 的实现 */ - public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider); + void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider); /** *
@@ -361,7 +360,7 @@ public interface WxMpService {
    * @return 退款操作结果
    * @throws WxErrorException
    */
-  public WxMpPayRefundResult refundPay(Map parameters) throws WxErrorException;
+  WxMpPayRefundResult refundPay(Map parameters) throws WxErrorException;
 
   /**
    * 
@@ -372,7 +371,7 @@ public interface WxMpService {
    * @param kvm
    * @param signature
    */
-  public boolean checkJSSDKCallbackDataSignature(Map kvm, String signature);
+  boolean checkJSSDKCallbackDataSignature(Map kvm, String signature);
 
   /**
    * 发送微信红包给个人用户
@@ -395,115 +394,7 @@ public interface WxMpService {
    *
    * @param parameters
    */
-  public WxRedpackResult sendRedpack(Map parameters) throws WxErrorException;
-
-  /**
-   * 获得卡券api_ticket,不强制刷新卡券api_ticket
-   *
-   * @return 卡券api_ticket
-   * @throws WxErrorException
-   * @see #getCardApiTicket(boolean)
-   */
-  public String getCardApiTicket() throws WxErrorException;
-
-  /**
-   * 
-   * 获得卡券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 - * @throws WxErrorException - */ - public String getCardApiTicket(boolean forceRefresh) throws WxErrorException; - - /** - *
-   * 创建调用卡券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签名对象 - */ - public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws - WxErrorException; - - /** - * 卡券Code解码 - * - * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 - * @return 解密后的Code - * @throws WxErrorException - */ - public String decryptCardCode(String encryptCode) throws WxErrorException; - - /** - * 卡券Code查询 - * - * @param cardId 卡券ID代表一类卡券 - * @param code 单张卡券的唯一标准 - * @param checkConsume 是否校验code核销状态,填入true和false时的code异常状态返回数据不同 - * @return WxMpCardResult对象 - * @throws WxErrorException - */ - public WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) - throws WxErrorException; - - /** - * 卡券Code核销。核销失败会抛出异常 - * - * @param code 单张卡券的唯一标准 - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 - * @throws WxErrorException - */ - public String consumeCardCode(String code) throws WxErrorException; - - /** - * 卡券Code核销。核销失败会抛出异常 - * - * @param code 单张卡券的唯一标准 - * @param cardId 当自定义Code卡券时需要传入card_id - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 - * @throws WxErrorException - */ - public String consumeCardCode(String code, String cardId) throws WxErrorException; - - /** - * 卡券Mark接口。 - * 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住), - * 才能进一步调用核销接口,否则报错。 - * - * @param code 卡券的code码 - * @param cardId 卡券的ID - * @param openId 用券用户的openid - * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 - * @throws WxErrorException - */ - public void markCardCode(String code, String cardId, String openId, boolean isMark) throws - WxErrorException; - - /** - * 查看卡券详情接口 - * 详见 https://mp.weixin.qq.com/wiki/14/8dd77aeaee85f922db5f8aa6386d385e.html#.E6.9F.A5.E7.9C.8B.E5.8D.A1.E5.88.B8.E8.AF.A6.E6.83.85 - * - * @param cardId 卡券的ID - * @return 返回的卡券详情JSON字符串 - *
[注] 由于返回的JSON格式过于复杂,难以定义其对应格式的Bean并且难以维护,因此只返回String格式的JSON串。 - *
可由 com.google.gson.JsonParser#parse 等方法直接取JSON串中的某个字段。 - * @throws WxErrorException - */ - public String getCardDetail(String cardId) throws WxErrorException; + WxRedpackResult sendRedpack(Map parameters) throws WxErrorException; /** *
@@ -515,7 +406,7 @@ public interface WxMpService {
    * @return wxMpMassSendResult
    * @throws WxErrorException
    */
-  public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception;
+  WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception;
 
   /**
    * 
@@ -589,4 +480,11 @@ public interface WxMpService {
    * @return WxMpQrcodeService
    */
   WxMpQrcodeService getQrcodeService();
+
+  /**
+   * 返回卡券相关接口的方法实现类,以方便调用个其各种接口
+   *
+   * @return WxMpCardService
+   */
+  WxMpCardService getCardService();
 }
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
new file mode 100644
index 00000000..40d35572
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java
@@ -0,0 +1,248 @@
+package me.chanjar.weixin.mp.api.impl;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.internal.Streams;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+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.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.io.StringReader;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/**
+ * Created by Binary Wang on 2016/7/27.
+ */
+public class WxMpCardServiceImpl implements WxMpCardService {
+
+  private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class);
+
+  /**
+   * 全局的是否正在刷新卡券api_ticket的锁
+   */
+  private final Object globalCardApiTicketRefreshLock = new Object();
+
+  private WxMpService wxMpService;
+
+  WxMpCardServiceImpl(WxMpService wxMpService) {
+    this.wxMpService = 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 { + if (forceRefresh) { + this.wxMpService.getWxMpConfigStorage().expireCardApiTicket(); + } + if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) { + synchronized (this.globalCardApiTicketRefreshLock) { + if (this.wxMpService.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 = Streams.parse(new JsonReader(new StringReader(responseContent))); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); + } + } + } + return this.wxMpService.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; + try { + String signature = SHA1.gen(signParam); + WxCardApiSignature cardApiSignature = new WxCardApiSignature(); + cardApiSignature.setTimestamp(timestamp); + cardApiSignature.setNonceStr(nonceStr); + cardApiSignature.setSignature(signature); + return cardApiSignature; + } catch (NoSuchAlgorithmException e) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg(e.getMessage()).build()); + } + } + + /** + * 卡券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 = Streams.parse(new JsonReader(new StringReader(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 = Streams.parse(new JsonReader(new StringReader(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.wxMpService.post(url, param.toString()); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(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/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java index 8c29dd8b..505d01fd 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 @@ -1,12 +1,12 @@ package me.chanjar.weixin.mp.api.impl; -import com.google.gson.*; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.google.gson.internal.Streams; -import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.thoughtworks.xstream.XStream; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; @@ -20,7 +20,6 @@ import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.mp.api.*; import me.chanjar.weixin.mp.bean.*; import me.chanjar.weixin.mp.bean.result.*; -import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import org.apache.http.Consts; import org.apache.http.HttpHost; import org.apache.http.client.ClientProtocolException; @@ -39,8 +38,11 @@ import org.slf4j.helpers.MessageFormatter; import java.io.IOException; import java.io.StringReader; import java.security.NoSuchAlgorithmException; -import java.util.*; +import java.util.HashMap; +import java.util.Map; import java.util.Map.Entry; +import java.util.SortedMap; +import java.util.TreeMap; public class WxMpServiceImpl implements WxMpService { @@ -56,11 +58,6 @@ public class WxMpServiceImpl implements WxMpService { */ protected final Object globalJsapiTicketRefreshLock = new Object(); - /** - * 全局的是否正在刷新卡券api_ticket的锁 - */ - protected final Object globalCardApiTicketRefreshLock = new Object(); - protected WxMpConfigStorage wxMpConfigStorage; protected WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); @@ -75,6 +72,8 @@ public class WxMpServiceImpl implements WxMpService { protected WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); + protected WxMpCardService cardService = new WxMpCardServiceImpl(this); + protected CloseableHttpClient httpClient; protected HttpHost httpProxy; @@ -782,218 +781,6 @@ public class WxMpServiceImpl implements WxMpService { } } - /** - * 获得卡券api_ticket,不强制刷新卡券api_ticket - * - * @return 卡券api_ticket - * @throws WxErrorException - * @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 - * @throws WxErrorException - */ - @Override - public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { - if (forceRefresh) { - this.wxMpConfigStorage.expireCardApiTicket(); - } - if (this.wxMpConfigStorage.isCardApiTicketExpired()) { - synchronized (this.globalCardApiTicketRefreshLock) { - if (this.wxMpConfigStorage.isCardApiTicketExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, null); - JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); - int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.wxMpConfigStorage.updateCardApiTicket(cardApiTicket, expiresInSeconds); - } - } - } - return this.wxMpConfigStorage.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; - try { - String signature = SHA1.gen(signParam); - WxCardApiSignature cardApiSignature = new WxCardApiSignature(); - cardApiSignature.setTimestamp(timestamp); - cardApiSignature.setNonceStr(nonceStr); - cardApiSignature.setSignature(signature); - return cardApiSignature; - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - } - - /** - * 卡券Code解码 - * - * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 - * @return 解密后的Code - * @throws WxErrorException - */ - @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 = post(url, param.toString()); - JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(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对象 - * @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 = post(url, param.toString()); - JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); - return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, - new TypeToken() { - }.getType()); - } - - /** - * 卡券Code核销。核销失败会抛出异常 - * - * @param code 单张卡券的唯一标准 - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 - * @throws WxErrorException - */ - @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等信息。 - * @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); - - if (cardId != null && !"".equals(cardId)) { - param.addProperty("card_id", cardId); - } - - String responseContent = post(url, param.toString()); - return responseContent; - } - - /** - * 卡券Mark接口。 - * 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住), - * 才能进一步调用核销接口,否则报错。 - * - * @param code 卡券的code码 - * @param cardId 卡券的ID - * @param openId 用券用户的openid - * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 - * @throws WxErrorException - */ - @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 = post(url, param.toString()); - JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(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 = 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; - } - @Override public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception { String url = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; @@ -1048,4 +835,9 @@ public class WxMpServiceImpl implements WxMpService { return this.qrCodeService; } + @Override + public WxMpCardService getCardService() { + return this.cardService; + } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java index e6cd9a5f..4f2e9979 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java @@ -1,6 +1,8 @@ package me.chanjar.weixin.mp.bean.result; import me.chanjar.weixin.mp.bean.WxMpCard; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import java.io.Serializable; @@ -58,14 +60,7 @@ public class WxMpCardResult implements Serializable { @Override public String toString() { - return "WxMpCardResult{" + - "errorCode='" + errorCode + '\'' + - ", errorMsg='" + errorMsg + '\'' + - ", openId='" + openId + '\'' + - ", card=" + card + - ", userCardStatus='" + userCardStatus + '\'' + - ", canConsume=" + canConsume + - '}'; + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } public String getUserCardStatus() { diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java new file mode 100644 index 00000000..a28723c5 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java @@ -0,0 +1,93 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.bean.WxCardApiSignature; +import me.chanjar.weixin.mp.api.ApiTestModule; +import me.chanjar.weixin.mp.bean.result.WxMpCardResult; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import static org.testng.AssertJUnit.assertNotNull; + +/** + * 测试代码仅供参考,未做严格测试,因原接口作者并未提供单元测试代码 + * Created by Binary Wang on 2016/7/27. + * @author binarywang (https://github.com/binarywang) + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMpCardServiceImplTest { + + @Inject + protected WxMpServiceImpl wxService; + private String cardId = "123"; + private String code = "good"; + private String openid = "abc"; + + @Test + public void testGetCardApiTicket() throws Exception { + String cardApiTicket = this.wxService.getCardService().getCardApiTicket(); + assertNotNull(cardApiTicket); + System.out.println(cardApiTicket); + } + + @Test + public void testGetCardApiTicketWithParam() throws Exception { + String cardApiTicket = this.wxService.getCardService().getCardApiTicket(true); + assertNotNull(cardApiTicket); + System.out.println(cardApiTicket); + } + + @Test + public void testCreateCardApiSignature() throws Exception { + //app_id, card_id, card_type, code, openid, location_id + + String[] param = {"123", cardId, "", code, openid, ""}; + WxCardApiSignature cardApiSignature = this.wxService.getCardService().createCardApiSignature(param); + assertNotNull(cardApiSignature); + System.out.println(cardApiSignature); + } + + @Test + public void testDecryptCardCode() throws Exception { + String encryptCode = "pd0vTUHSHc9tMUCL2gXABcUmINm6yxqJh0y9Phsy63E="; + String cardCode = this.wxService.getCardService().decryptCardCode(encryptCode); + assertNotNull(cardCode); + System.out.println(cardCode); + } + + @Test + public void testQueryCardCode() throws Exception { + WxMpCardResult wxMpCardResult = this.wxService.getCardService().queryCardCode(cardId, code, false); + assertNotNull(wxMpCardResult); + System.out.println(wxMpCardResult); + } + + @Test + public void testConsumeCardCode() throws Exception { + String result = this.wxService.getCardService().consumeCardCode(code); + assertNotNull(result); + System.out.println(result); + } + + @Test + public void testConsumeCardCodeWithCardId() throws Exception { + String result = this.wxService.getCardService().consumeCardCode(code, cardId); + assertNotNull(result); + System.out.println(result); + } + + @Test + public void testMarkCardCode() throws Exception { + this.wxService.getCardService().markCardCode(code, cardId, openid, true); + System.out.println("done"); + } + + @Test + public void testGetCardDetail() throws Exception { + String result = this.wxService.getCardService().getCardDetail(cardId); + assertNotNull(result); + System.out.println(result); + } + +} \ No newline at end of file From ffeb3eef93214926f33be29f3b2a70b7cc2cb8c5 Mon Sep 17 00:00:00 2001 From: BinaryWang Date: Thu, 28 Jul 2016 13:10:02 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E4=BB=A3=E7=A0=81=E6=8B=89=E5=87=BA=E5=88=B0?= =?UTF-8?q?=E5=8D=95=E7=8B=AC=E7=B1=BB=E4=B8=AD=E7=BB=B4=E6=8A=A4=EF=BC=8C?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=E6=9A=82=E6=97=B6=E6=9C=AA?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/mp/api/WxMpPayService.java | 138 +++++++ .../me/chanjar/weixin/mp/api/WxMpService.java | 155 +------- .../mp/api/impl/WxMpPayServiceImpl.java | 335 ++++++++++++++++ .../weixin/mp/api/impl/WxMpServiceImpl.java | 375 ++---------------- .../mp/api/impl/WxMpPayServiceImplTest.java | 60 +++ 5 files changed, 573 insertions(+), 490 deletions(-) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java new file mode 100644 index 00000000..0db67cb7 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java @@ -0,0 +1,138 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.bean.result.*; + +import java.util.Map; + +/** + * 微信支付相关接口 + * Created by Binary Wang on 2016/7/28. + * @author binarywang (https://github.com/binarywang) + */ +public interface WxMpPayService { + + + /** + * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) + * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" + * + * @param openId 支付人openId + * @param outTradeNo 商户端对应订单号 + * @param amt 金额(单位元) + * @param body 商品描述 + * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP + * @param ip 发起支付的客户端IP + * @param notifyUrl 通知地址 + * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getPrepayId(Map) instead + */ + @Deprecated + WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String notifyUrl); + + /** + * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) + * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" + * + * @param parameters All required/optional parameters for weixin payment + */ + WxMpPrepayIdResult getPrepayId(Map parameters); + + /** + * 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数 + * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 + * + * @param parameters the required or optional parameters + */ + Map getPayInfo(Map parameters) throws WxErrorException; + + /** + * 该接口调用“统一下单”接口,并拼装NATIVE发起支付请求需要的参数 + * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 + * tradeType 交易类型 NATIVE (其他交易类型JSAPI,APP,WAP) + * + * @param productId 商户商品ID + * @param outTradeNo 商户端对应订单号 + * @param amt 金额(单位元) + * @param body 商品描述 + * @param ip 发起支付的客户端IP + * @param notifyUrl 通知地址 + * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getPayInfo(Map) instead + */ + @Deprecated + Map getNativePayInfo(String productId, String outTradeNo, double amt, String body, String ip, String notifyUrl) throws WxErrorException; + + /** + * 该接口调用“统一下单”接口,并拼装JSAPI发起支付请求需要的参数 + * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 + * tradeType 交易类型 JSAPI(其他交易类型NATIVE,APP,WAP) + * + * @param openId 支付人openId + * @param outTradeNo 商户端对应订单号 + * @param amt 金额(单位元) + * @param body 商品描述 + * @param ip 发起支付的客户端IP + * @param notifyUrl 通知地址 + * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getPayInfo(Map) instead + */ + @Deprecated + Map getJsapiPayInfo(String openId, String outTradeNo, double amt, String body, String ip, String notifyUrl) throws WxErrorException; + + /** + * 该接口提供所有微信支付订单的查询,当支付通知处理异常戒丢失的情冴,商户可以通过该接口查询订单支付状态。 + * 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2 + * + */ + WxMpPayResult getJSSDKPayResult(String transactionId, String outTradeNo); + + /** + * 读取支付结果通知 + * 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7 + * + */ + WxMpPayCallback getJSSDKCallbackData(String xmlData); + + /** + * 微信支付-申请退款 + * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4 + * + * @param parameters 需要传入的退款参数的Map。以下几项为参数的必须项:
+ *
  • transaction_id + *
  • out_trade_no (仅在上述transaction_id为空时是必须项) + *
  • out_refund_no + *
  • total_fee + *
  • refund_fee + * @return 退款操作结果 + */ + WxMpPayRefundResult refundPay(Map parameters) throws WxErrorException; + + /** + *
    +   * 计算Map键值对是否和签名相符,
    +   * 按照字段名的 ASCII 码从小到大排序(字典序)后,使用 URL 键值对的 格式(即 key1=value1&key2=value2...)拼接成字符串
    +   * 
    + * + */ + boolean checkJSSDKCallbackDataSignature(Map kvm, String signature); + + /** + * 发送微信红包给个人用户 + *

    + * 需要传入的必填参数如下: + * mch_billno//商户订单号 + * send_name//商户名称 + * re_openid//用户openid + * total_amount//红包总额 + * total_num//红包发放总人数 + * wishing//红包祝福语 + * client_ip//服务器Ip地址 + * act_name//活动名称 + * remark //备注 + * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5 + *

    + * 使用现金红包功能需要在xml配置文件中额外设置: + * 微信商户平台ID + * 商户平台设置的API密钥 + * + */ + WxRedpackResult sendRedpack(Map parameters) 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 3811647b..d1366152 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 @@ -7,7 +7,6 @@ import me.chanjar.weixin.mp.bean.*; import me.chanjar.weixin.mp.bean.result.*; import java.text.SimpleDateFormat; -import java.util.Map; /** * 微信API的Service @@ -90,8 +89,6 @@ public interface WxMpService { * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口 *

  • * - * @param news - * @throws WxErrorException * @see #massGroupMessageSend(me.chanjar.weixin.mp.bean.WxMpMassGroupMessage) * @see #massOpenIdsMessageSend(me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage) */ @@ -134,7 +131,6 @@ public interface WxMpService { * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=长链接转短链接接口 *
    * - * @param long_url */ String shortUrl(String long_url) throws WxErrorException; @@ -144,9 +140,7 @@ public interface WxMpService { * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=模板消息接口 *
    * - * @param templateMessage * @return msgid - * @throws WxErrorException */ String templateSend(WxMpTemplateMessage templateMessage) throws WxErrorException; @@ -164,8 +158,6 @@ public interface WxMpService { * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息 *
    * - * @param scope - * @param state * @return url */ String oauth2buildAuthorizationUrl(String scope, String state); @@ -177,8 +169,6 @@ public interface WxMpService { *
    * * @param redirectURI 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode - * @param scope - * @param state * @return url */ String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state); @@ -203,7 +193,6 @@ public interface WxMpService { * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以 *
    * - * @param oAuth2AccessToken * @param lang zh_CN, zh_TW, en */ WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException; @@ -213,7 +202,6 @@ public interface WxMpService { * 验证oauth2的access token是否有效 *
    * - * @param oAuth2AccessToken */ boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken); @@ -265,146 +253,13 @@ public interface WxMpService { */ void setMaxRetryTimes(int maxRetryTimes); - /** - * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) - * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" - * - * @param openId 支付人openId - * @param outTradeNo 商户端对应订单号 - * @param amt 金额(单位元) - * @param body 商品描述 - * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP - * @param ip 发起支付的客户端IP - * @param notifyUrl 通知地址 - * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getPrepayId(Map) instead - */ - @Deprecated - WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String notifyUrl); - - /** - * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) - * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" - * - * @param parameters All required/optional parameters for weixin payment - * @throws IllegalArgumentException - */ - WxMpPrepayIdResult getPrepayId(Map parameters); - - /** - * 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数 - * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 - * - * @param parameters the required or optional parameters - */ - Map getPayInfo(Map parameters) throws WxErrorException; - - /** - * 该接口调用“统一下单”接口,并拼装NATIVE发起支付请求需要的参数 - * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 - * tradeType 交易类型 NATIVE (其他交易类型JSAPI,APP,WAP) - * - * @param productId 商户商品ID - * @param outTradeNo 商户端对应订单号 - * @param amt 金额(单位元) - * @param body 商品描述 - * @param ip 发起支付的客户端IP - * @param notifyUrl 通知地址 - * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getPayInfo(Map) instead - */ - @Deprecated - Map getNativePayInfo(String productId, String outTradeNo, double amt, String body, String ip, String notifyUrl) throws WxErrorException; - - /** - * 该接口调用“统一下单”接口,并拼装JSAPI发起支付请求需要的参数 - * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 - * tradeType 交易类型 JSAPI(其他交易类型NATIVE,APP,WAP) - * - * @param openId 支付人openId - * @param outTradeNo 商户端对应订单号 - * @param amt 金额(单位元) - * @param body 商品描述 - * @param ip 发起支付的客户端IP - * @param notifyUrl 通知地址 - * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getPayInfo(Map) instead - */ - @Deprecated - Map getJsapiPayInfo(String openId, String outTradeNo, double amt, String body, String ip, String notifyUrl) throws WxErrorException; - - /** - * 该接口提供所有微信支付订单的查询,当支付通知处理异常戒丢失的情冴,商户可以通过该接口查询订单支付状态。 - * 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2 - * - * @param transactionId - * @param outTradeNo - */ - WxMpPayResult getJSSDKPayResult(String transactionId, String outTradeNo); - - /** - * 读取支付结果通知 - * 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7 - * - * @param xmlData - */ - WxMpPayCallback getJSSDKCallbackData(String xmlData); - - /** - * 微信支付-申请退款 - * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4 - * - * @param parameters 需要传入的退款参数的Map。以下几项为参数的必须项:
    - *
  • transaction_id - *
  • out_trade_no (仅在上述transaction_id为空时是必须项) - *
  • out_refund_no - *
  • total_fee - *
  • refund_fee - * @return 退款操作结果 - * @throws WxErrorException - */ - WxMpPayRefundResult refundPay(Map parameters) throws WxErrorException; - - /** - *
    -   * 计算Map键值对是否和签名相符,
    -   * 按照字段名的 ASCII 码从小到大排序(字典序)后,使用 URL 键值对的 格式(即 key1=value1&key2=value2...)拼接成字符串
    -   * 
    - * - * @param kvm - * @param signature - */ - boolean checkJSSDKCallbackDataSignature(Map kvm, String signature); - - /** - * 发送微信红包给个人用户 - *

    - * 需要传入的必填参数如下: - * mch_billno//商户订单号 - * send_name//商户名称 - * re_openid//用户openid - * total_amount//红包总额 - * total_num//红包发放总人数 - * wishing//红包祝福语 - * client_ip//服务器Ip地址 - * act_name//活动名称 - * remark //备注 - * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5 - *

    - * 使用现金红包功能需要在xml配置文件中额外设置: - * 微信商户平台ID - * 商户平台设置的API密钥 - * - * @param parameters - */ - WxRedpackResult sendRedpack(Map parameters) throws WxErrorException; - /** *

        * 预览接口
        * 详情请见:http://mp.weixin.qq.com/wiki/15/40b6865b893947b764e2de8e4a1fb55f.html#.E9.A2.84.E8.A7.88.E6.8E.A5.E5.8F.A3.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91
        * 
    * - * @param wxMpMassPreviewMessage * @return wxMpMassSendResult - * @throws WxErrorException */ WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception; @@ -415,9 +270,7 @@ public interface WxMpService { * 详情请见:http://mp.weixin.qq.com/wiki/5/6dde9eaa909f83354e0094dc3ad99e05.html#.E8.AE.BE.E7.BD.AE.E6.89.80.E5.B1.9E.E8.A1.8C.E4.B8.9A *
  • * - * @param wxMpIndustry * @return JsonObject - * @throws WxErrorException */ String setIndustry(WxMpIndustry wxMpIndustry) throws WxErrorException; @@ -428,7 +281,6 @@ public interface WxMpService { *
    * * @return wxMpIndustry - * @throws WxErrorException */ WxMpIndustry getIndustry() throws WxErrorException; @@ -487,4 +339,11 @@ public interface WxMpService { * @return WxMpCardService */ WxMpCardService getCardService(); + + /** + * 返回微信支付相关接口的方法实现类,以方便调用个其各种接口 + * + * @return WxMpPayService + */ + WxMpPayService getPayService(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java new file mode 100644 index 00000000..81638b7a --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java @@ -0,0 +1,335 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.thoughtworks.xstream.XStream; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.crypto.WxCryptUtil; +import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import me.chanjar.weixin.mp.api.WxMpPayService; +import me.chanjar.weixin.mp.bean.result.*; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * Created by Binary Wang on 2016/7/28. + * @author binarywang (https://github.com/binarywang) + */ +public class WxMpPayServiceImpl implements WxMpPayService { + + private final Logger log = LoggerFactory.getLogger(WxMpPayServiceImpl.class); + + private HttpHost httpProxy; + private WxMpServiceImpl wxMpService; + + public WxMpPayServiceImpl(WxMpServiceImpl wxMpService) { + this.wxMpService = wxMpService; + this.httpProxy = wxMpService.getHttpProxy(); + } + + @Override + public WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String callbackUrl) { + Map packageParams = new HashMap<>(); + packageParams.put("appid", this.wxMpService.getWxMpConfigStorage().getAppId()); + packageParams.put("mch_id", this.wxMpService.getWxMpConfigStorage().getPartnerId()); + packageParams.put("body", body); + packageParams.put("out_trade_no", outTradeNo); + packageParams.put("total_fee", (int) (amt * 100) + ""); + packageParams.put("spbill_create_ip", ip); + packageParams.put("notify_url", callbackUrl); + packageParams.put("trade_type", tradeType); + packageParams.put("openid", openId); + + return getPrepayId(packageParams); + } + + @Override + public WxMpPrepayIdResult getPrepayId(final Map parameters) { + String nonce_str = System.currentTimeMillis() + ""; + + final SortedMap packageParams = new TreeMap<>(parameters); + packageParams.put("appid", this.wxMpService.getWxMpConfigStorage().getAppId()); + packageParams.put("mch_id", this.wxMpService.getWxMpConfigStorage().getPartnerId()); + packageParams.put("nonce_str", nonce_str); + checkParameters(packageParams); + + String sign = WxCryptUtil.createSign(packageParams, this.wxMpService.getWxMpConfigStorage().getPartnerKey()); + packageParams.put("sign", sign); + + StringBuilder request = new StringBuilder(""); + for (Map.Entry para : packageParams.entrySet()) { + request.append(String.format("<%s>%s", para.getKey(), para.getValue(), para.getKey())); + } + request.append(""); + + HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder"); + if (this.httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); + httpPost.setConfig(config); + } + + StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); + httpPost.setEntity(entity); + try(CloseableHttpResponse response = this.wxMpService.getHttpclient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + XStream xstream = XStreamInitializer.getInstance(); + xstream.alias("xml", WxMpPrepayIdResult.class); + return (WxMpPrepayIdResult) xstream.fromXML(responseContent); + } catch (IOException e) { + throw new RuntimeException("Failed to get prepay id due to IO exception.", e); + }finally { + httpPost.releaseConnection(); + } + } + + private final String[] REQUIRED_ORDER_PARAMETERS = new String[] { "appid", "mch_id", "body", "out_trade_no", + "total_fee", "spbill_create_ip", "notify_url","trade_type"}; + + private void checkParameters(Map parameters) { + for (String para : this.REQUIRED_ORDER_PARAMETERS) { + if (!parameters.containsKey(para)) + throw new IllegalArgumentException("Reqiured argument '" + para + "' is missing."); + } + if ("JSAPI".equals(parameters.get("trade_type")) && !parameters.containsKey("openid")) + throw new IllegalArgumentException("Reqiured argument 'openid' is missing when trade_type is 'JSAPI'."); + if ("NATIVE".equals(parameters.get("trade_type")) && !parameters.containsKey("product_id")) + throw new IllegalArgumentException("Reqiured argument 'product_id' is missing when trade_type is 'NATIVE'."); + } + + @Override + public Map getJsapiPayInfo(String openId,String outTradeNo, double amt, String body,String ip, String callbackUrl) throws WxErrorException { + Map packageParams = new HashMap<>(); + packageParams.put("appid", this.wxMpService.getWxMpConfigStorage().getAppId()); + packageParams.put("mch_id", this.wxMpService.getWxMpConfigStorage().getPartnerId()); + packageParams.put("body", body); + packageParams.put("out_trade_no", outTradeNo); + packageParams.put("total_fee", (int) (amt * 100) + ""); + packageParams.put("spbill_create_ip", ip); + packageParams.put("notify_url", callbackUrl); + packageParams.put("trade_type", "JSAPI"); + packageParams.put("openid", openId); + + return getPayInfo(packageParams); + } + + @Override + public Map getNativePayInfo(String productId,String outTradeNo, double amt, String body,String ip, String callbackUrl) throws WxErrorException{ + Map packageParams = new HashMap<>(); + packageParams.put("appid", this.wxMpService.getWxMpConfigStorage().getAppId()); + packageParams.put("mch_id", this.wxMpService.getWxMpConfigStorage().getPartnerId()); + packageParams.put("body", body); + packageParams.put("out_trade_no", outTradeNo); + packageParams.put("total_fee", (int) (amt * 100) + ""); + packageParams.put("spbill_create_ip", ip); + packageParams.put("notify_url", callbackUrl); + packageParams.put("trade_type", "NATIVE"); + packageParams.put("product_id", productId); + + return getPayInfo(packageParams); + } + + @Override + public Map getPayInfo(Map parameters) throws WxErrorException { + WxMpPrepayIdResult wxMpPrepayIdResult = getPrepayId(parameters); + + if (!"SUCCESS".equalsIgnoreCase(wxMpPrepayIdResult.getReturn_code()) + ||!"SUCCESS".equalsIgnoreCase(wxMpPrepayIdResult.getResult_code())) { + WxError error = new WxError(); + error.setErrorCode(-1); + error.setErrorMsg("return_code:" + wxMpPrepayIdResult.getReturn_code() + + ";return_msg:" + wxMpPrepayIdResult.getReturn_msg() + + ";result_code:" + wxMpPrepayIdResult.getResult_code() + + ";err_code" + wxMpPrepayIdResult.getErr_code() + + ";err_code_des" + wxMpPrepayIdResult.getErr_code_des()); + throw new WxErrorException(error); + } + + String prepayId = wxMpPrepayIdResult.getPrepay_id(); + if (prepayId == null || prepayId.equals("")) { + throw new RuntimeException(String.format("Failed to get prepay id due to error code '%s'(%s).", wxMpPrepayIdResult.getErr_code(), wxMpPrepayIdResult.getErr_code_des())); + } + + Map payInfo = new HashMap<>(); + payInfo.put("appId", this.wxMpService.getWxMpConfigStorage().getAppId()); + // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 + payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); + payInfo.put("nonceStr", System.currentTimeMillis() + ""); + payInfo.put("package", "prepay_id=" + prepayId); + payInfo.put("signType", "MD5"); + if("NATIVE".equals(parameters.get("trade_type"))){ + payInfo.put("codeUrl", wxMpPrepayIdResult.getCode_url()); + } + + String finalSign = WxCryptUtil.createSign(payInfo, this.wxMpService.getWxMpConfigStorage().getPartnerKey()); + payInfo.put("paySign", finalSign); + return payInfo; + } + + @Override + public WxMpPayResult getJSSDKPayResult(String transactionId, String outTradeNo) { + String nonce_str = System.currentTimeMillis() + ""; + + SortedMap packageParams = new TreeMap<>(); + packageParams.put("appid", this.wxMpService.getWxMpConfigStorage().getAppId()); + packageParams.put("mch_id", this.wxMpService.getWxMpConfigStorage().getPartnerId()); + if (transactionId != null && !"".equals(transactionId.trim())) + packageParams.put("transaction_id", transactionId); + else if (outTradeNo != null && !"".equals(outTradeNo.trim())) + packageParams.put("out_trade_no", outTradeNo); + else + throw new IllegalArgumentException("Either 'transactionId' or 'outTradeNo' must be given."); + packageParams.put("nonce_str", nonce_str); + packageParams.put("sign", WxCryptUtil.createSign(packageParams, this.wxMpService.getWxMpConfigStorage().getPartnerKey())); + + StringBuilder request = new StringBuilder(""); + for (Map.Entry para : packageParams.entrySet()) { + request.append(String.format("<%s>%s", para.getKey(), para.getValue(), para.getKey())); + } + request.append(""); + + HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/orderquery"); + if (this.httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); + httpPost.setConfig(config); + } + + StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); + httpPost.setEntity(entity); + try(CloseableHttpResponse response = this.wxMpService.getHttpclient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + XStream xstream = XStreamInitializer.getInstance(); + xstream.alias("xml", WxMpPayResult.class); + return (WxMpPayResult) xstream.fromXML(responseContent); + } catch (IOException e) { + throw new RuntimeException("Failed to query order due to IO exception.", e); + } + } + + @Override + public WxMpPayCallback getJSSDKCallbackData(String xmlData) { + try { + XStream xstream = XStreamInitializer.getInstance(); + xstream.alias("xml", WxMpPayCallback.class); + return (WxMpPayCallback) xstream.fromXML(xmlData); + } catch (Exception e){ + e.printStackTrace(); + } + + return new WxMpPayCallback(); + } + + @Override + public WxMpPayRefundResult refundPay(Map parameters) throws WxErrorException { + SortedMap refundParams = new TreeMap<>(parameters); + refundParams.put("appid", this.wxMpService.getWxMpConfigStorage().getAppId()); + refundParams.put("mch_id", this.wxMpService.getWxMpConfigStorage().getPartnerId()); + refundParams.put("nonce_str", System.currentTimeMillis() + ""); + refundParams.put("op_user_id", this.wxMpService.getWxMpConfigStorage().getPartnerId()); + String sign = WxCryptUtil.createSign(refundParams, this.wxMpService.getWxMpConfigStorage().getPartnerKey()); + refundParams.put("sign", sign); + + StringBuilder request = new StringBuilder(""); + for (Map.Entry para : refundParams.entrySet()) { + request.append(String.format("<%s>%s", para.getKey(), para.getValue(), para.getKey())); + } + request.append(""); + + HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund"); + if (this.httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); + httpPost.setConfig(config); + } + + StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); + httpPost.setEntity(entity); + try(CloseableHttpResponse response = this.wxMpService.getHttpclient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + XStream xstream = XStreamInitializer.getInstance(); + xstream.processAnnotations(WxMpPayRefundResult.class); + WxMpPayRefundResult wxMpPayRefundResult = (WxMpPayRefundResult) xstream.fromXML(responseContent); + + if (!"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getResultCode()) + ||!"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getReturnCode())) { + WxError error = new WxError(); + error.setErrorCode(-1); + error.setErrorMsg("return_code:" + wxMpPayRefundResult.getReturnCode() + + ";return_msg:" + wxMpPayRefundResult.getReturnMsg() + + ";result_code:" + wxMpPayRefundResult.getResultCode() + + ";err_code" + wxMpPayRefundResult.getErrCode() + + ";err_code_des" + wxMpPayRefundResult.getErrCodeDes()); + throw new WxErrorException(error); + } + + return wxMpPayRefundResult; + } catch (IOException e) { + this.log.error(MessageFormatter.format("The exception was happened when sending refund '{}'.", + request.toString()).getMessage(), e); + WxError error = new WxError(); + error.setErrorCode(-1); + error.setErrorMsg("incorrect response."); + throw new WxErrorException(error); + }finally { + httpPost.releaseConnection(); + } + } + + @Override + public boolean checkJSSDKCallbackDataSignature(Map kvm, String signature) { + return signature.equals(WxCryptUtil.createSign(kvm, this.wxMpService.getWxMpConfigStorage().getPartnerKey())); + } + + @Override + public WxRedpackResult sendRedpack(Map parameters) throws WxErrorException { + String nonce_str = System.currentTimeMillis() + ""; + + SortedMap packageParams = new TreeMap<>(parameters); + packageParams.put("wxappid", this.wxMpService.getWxMpConfigStorage().getAppId()); + packageParams.put("mch_id", this.wxMpService.getWxMpConfigStorage().getPartnerId()); + packageParams.put("nonce_str", nonce_str); + + String sign = WxCryptUtil.createSign(packageParams, this.wxMpService.getWxMpConfigStorage().getPartnerKey()); + packageParams.put("sign", sign); + + StringBuilder request = new StringBuilder(""); + for (Map.Entry para : packageParams.entrySet()) { + request.append(String.format("<%s>%s", para.getKey(), para.getValue(), para.getKey())); + } + request.append(""); + + HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack"); + if (this.httpProxy != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); + httpPost.setConfig(config); + } + + StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); + httpPost.setEntity(entity); + try(CloseableHttpResponse response = this.wxMpService.getHttpclient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + XStream xstream = XStreamInitializer.getInstance(); + xstream.processAnnotations(WxRedpackResult.class); + return (WxRedpackResult) xstream.fromXML(responseContent); + } catch (IOException e) { + this.log.error(MessageFormatter.format("The exception was happened when sending redpack '{}'.", request.toString()).getMessage(), e); + WxError error = new WxError(); + error.setErrorCode(-1); + throw new WxErrorException(error); + }finally { + httpPost.releaseConnection(); + } + } + +} 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 505d01fd..f0ca0d17 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 @@ -5,7 +5,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.internal.Streams; import com.google.gson.stream.JsonReader; -import com.thoughtworks.xstream.XStream; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.bean.result.WxError; @@ -14,35 +13,23 @@ 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.crypto.WxCryptUtil; import me.chanjar.weixin.common.util.http.*; -import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.mp.api.*; import me.chanjar.weixin.mp.bean.*; import me.chanjar.weixin.mp.bean.result.*; -import org.apache.http.Consts; import org.apache.http.HttpHost; -import org.apache.http.client.ClientProtocolException; 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.client.methods.HttpPost; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.CloseableHttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.slf4j.helpers.MessageFormatter; import java.io.IOException; import java.io.StringReader; import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.SortedMap; -import java.util.TreeMap; public class WxMpServiceImpl implements WxMpService { @@ -51,32 +38,38 @@ public class WxMpServiceImpl implements WxMpService { /** * 全局的是否正在刷新access token的锁 */ - protected final Object globalAccessTokenRefreshLock = new Object(); + private final Object globalAccessTokenRefreshLock = new Object(); /** * 全局的是否正在刷新jsapi_ticket的锁 */ - protected final Object globalJsapiTicketRefreshLock = new Object(); + private final Object globalJsapiTicketRefreshLock = new Object(); - protected WxMpConfigStorage wxMpConfigStorage; + private WxMpConfigStorage wxMpConfigStorage; - protected WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); + private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); - protected WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); + private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); - protected WxMpMenuService menuService = new WxMpMenuServiceImpl(this); + private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); - protected WxMpUserService userService = new WxMpUserServiceImpl(this); + private WxMpUserService userService = new WxMpUserServiceImpl(this); - protected WxMpGroupService groupService = new WxMpGroupServiceImpl(this); + private WxMpGroupService groupService = new WxMpGroupServiceImpl(this); - protected WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); + private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); - protected WxMpCardService cardService = new WxMpCardServiceImpl(this); + private WxMpCardService cardService = new WxMpCardServiceImpl(this); - protected CloseableHttpClient httpClient; + private WxMpPayService payService = new WxMpPayServiceImpl(this); - protected HttpHost httpProxy; + private CloseableHttpClient httpClient; + + private HttpHost httpProxy; + + public HttpHost getHttpProxy() { + return this.httpProxy; + } private int retrySleepMillis = 1000; @@ -106,10 +99,9 @@ public class WxMpServiceImpl implements WxMpService { if (this.wxMpConfigStorage.isAccessTokenExpired()) { synchronized (this.globalAccessTokenRefreshLock) { if (this.wxMpConfigStorage.isAccessTokenExpired()) { - String url = new StringBuffer() - .append("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential") - .append("&appid=").append(this.wxMpConfigStorage.getAppId()) - .append("&secret=").append(this.wxMpConfigStorage.getSecret()).toString(); + String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + + "&appid=" + this.wxMpConfigStorage.getAppId() + + "&secret=" + this.wxMpConfigStorage.getSecret(); try { HttpGet httpGet = new HttpGet(url); if (this.httpProxy != null) { @@ -127,8 +119,6 @@ public class WxMpServiceImpl implements WxMpService { }finally { httpGet.releaseConnection(); } - } catch (ClientProtocolException e) { - throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } @@ -148,6 +138,7 @@ public class WxMpServiceImpl implements WxMpService { if (forceRefresh) { this.wxMpConfigStorage.expireJsapiTicket(); } + if (this.wxMpConfigStorage.isJsapiTicketExpired()) { synchronized (this.globalJsapiTicketRefreshLock) { if (this.wxMpConfigStorage.isJsapiTicketExpired()) { @@ -258,7 +249,7 @@ public class WxMpServiceImpl implements WxMpService { @Override public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { - StringBuffer url = new StringBuffer(); + StringBuilder url = new StringBuilder(); url.append("https://open.weixin.qq.com/connect/oauth2/authorize?"); url.append("appid=").append(this.wxMpConfigStorage.getAppId()); url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); @@ -273,7 +264,7 @@ public class WxMpServiceImpl implements WxMpService { @Override public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { - StringBuffer url = new StringBuffer(); + StringBuilder url = new StringBuilder(); url.append("https://api.weixin.qq.com/sns/oauth2/access_token?"); url.append("appid=").append(this.wxMpConfigStorage.getAppId()); url.append("&secret=").append(this.wxMpConfigStorage.getSecret()); @@ -284,8 +275,6 @@ public class WxMpServiceImpl implements WxMpService { RequestExecutor executor = new SimpleGetRequestExecutor(); String responseText = executor.execute(getHttpclient(), this.httpProxy, url.toString(), null); return WxMpOAuth2AccessToken.fromJson(responseText); - } catch (ClientProtocolException e) { - throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } @@ -293,7 +282,7 @@ public class WxMpServiceImpl implements WxMpService { @Override public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { - StringBuffer url = new StringBuffer(); + StringBuilder url = new StringBuilder(); url.append("https://api.weixin.qq.com/sns/oauth2/refresh_token?"); url.append("appid=").append(this.wxMpConfigStorage.getAppId()); url.append("&grant_type=refresh_token"); @@ -303,8 +292,6 @@ public class WxMpServiceImpl implements WxMpService { RequestExecutor executor = new SimpleGetRequestExecutor(); String responseText = executor.execute(getHttpclient(), this.httpProxy, url.toString(), null); return WxMpOAuth2AccessToken.fromJson(responseText); - } catch (ClientProtocolException e) { - throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } @@ -312,7 +299,7 @@ public class WxMpServiceImpl implements WxMpService { @Override public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { - StringBuffer url = new StringBuffer(); + 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()); @@ -326,8 +313,6 @@ public class WxMpServiceImpl implements WxMpService { RequestExecutor executor = new SimpleGetRequestExecutor(); String responseText = executor.execute(getHttpclient(), this.httpProxy, url.toString(), null); return WxMpUser.fromJson(responseText); - } catch (ClientProtocolException e) { - throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } @@ -335,7 +320,7 @@ public class WxMpServiceImpl implements WxMpService { @Override public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { - StringBuffer url = new StringBuffer(); + 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()); @@ -343,8 +328,6 @@ public class WxMpServiceImpl implements WxMpService { try { RequestExecutor executor = new SimpleGetRequestExecutor(); executor.execute(getHttpclient(), this.httpProxy, url.toString(), null); - } catch (ClientProtocolException e) { - throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } catch (WxErrorException e) { @@ -434,14 +417,12 @@ public class WxMpServiceImpl implements WxMpService { throw new WxErrorException(error); } return null; - } catch (ClientProtocolException e) { - throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } - protected CloseableHttpClient getHttpclient() { + public CloseableHttpClient getHttpclient() { return this.httpClient; } @@ -486,301 +467,6 @@ public class WxMpServiceImpl implements WxMpService { this.maxRetryTimes = maxRetryTimes; } - @Override - public WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String callbackUrl) { - Map packageParams = new HashMap<>(); - packageParams.put("appid", this.wxMpConfigStorage.getAppId()); - packageParams.put("mch_id", this.wxMpConfigStorage.getPartnerId()); - packageParams.put("body", body); - packageParams.put("out_trade_no", outTradeNo); - packageParams.put("total_fee", (int) (amt * 100) + ""); - packageParams.put("spbill_create_ip", ip); - packageParams.put("notify_url", callbackUrl); - packageParams.put("trade_type", tradeType); - packageParams.put("openid", openId); - - return getPrepayId(packageParams); - } - - @Override - public WxMpPrepayIdResult getPrepayId(final Map parameters) { - String nonce_str = System.currentTimeMillis() + ""; - - final SortedMap packageParams = new TreeMap<>(parameters); - packageParams.put("appid", this.wxMpConfigStorage.getAppId()); - packageParams.put("mch_id", this.wxMpConfigStorage.getPartnerId()); - packageParams.put("nonce_str", nonce_str); - checkParameters(packageParams); - - String sign = WxCryptUtil.createSign(packageParams, this.wxMpConfigStorage.getPartnerKey()); - packageParams.put("sign", sign); - - StringBuilder request = new StringBuilder(""); - for (Entry para : packageParams.entrySet()) { - request.append(String.format("<%s>%s", para.getKey(), para.getValue(), para.getKey())); - } - request.append(""); - - HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder"); - if (this.httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); - httpPost.setConfig(config); - } - - StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); - httpPost.setEntity(entity); - try(CloseableHttpResponse response = getHttpclient().execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - XStream xstream = XStreamInitializer.getInstance(); - xstream.alias("xml", WxMpPrepayIdResult.class); - WxMpPrepayIdResult wxMpPrepayIdResult = (WxMpPrepayIdResult) xstream.fromXML(responseContent); - return wxMpPrepayIdResult; - } catch (IOException e) { - throw new RuntimeException("Failed to get prepay id due to IO exception.", e); - }finally { - httpPost.releaseConnection(); - } - } - - final String[] REQUIRED_ORDER_PARAMETERS = new String[] { "appid", "mch_id", "body", "out_trade_no", "total_fee", "spbill_create_ip", "notify_url", - "trade_type", }; - - private void checkParameters(Map parameters) { - for (String para : this.REQUIRED_ORDER_PARAMETERS) { - if (!parameters.containsKey(para)) - throw new IllegalArgumentException("Reqiured argument '" + para + "' is missing."); - } - if ("JSAPI".equals(parameters.get("trade_type")) && !parameters.containsKey("openid")) - throw new IllegalArgumentException("Reqiured argument 'openid' is missing when trade_type is 'JSAPI'."); - if ("NATIVE".equals(parameters.get("trade_type")) && !parameters.containsKey("product_id")) - throw new IllegalArgumentException("Reqiured argument 'product_id' is missing when trade_type is 'NATIVE'."); - } - - @Override - public Map getJsapiPayInfo(String openId,String outTradeNo, double amt, String body,String ip, String callbackUrl) throws WxErrorException{ - Map packageParams = new HashMap<>(); - packageParams.put("appid", this.wxMpConfigStorage.getAppId()); - packageParams.put("mch_id", this.wxMpConfigStorage.getPartnerId()); - packageParams.put("body", body); - packageParams.put("out_trade_no", outTradeNo); - packageParams.put("total_fee", (int) (amt * 100) + ""); - packageParams.put("spbill_create_ip", ip); - packageParams.put("notify_url", callbackUrl); - packageParams.put("trade_type", "JSAPI"); - packageParams.put("openid", openId); - - return getPayInfo(packageParams); - } - - @Override - public Map getNativePayInfo(String productId,String outTradeNo, double amt, String body,String ip, String callbackUrl) throws WxErrorException{ - Map packageParams = new HashMap<>(); - packageParams.put("appid", this.wxMpConfigStorage.getAppId()); - packageParams.put("mch_id", this.wxMpConfigStorage.getPartnerId()); - packageParams.put("body", body); - packageParams.put("out_trade_no", outTradeNo); - packageParams.put("total_fee", (int) (amt * 100) + ""); - packageParams.put("spbill_create_ip", ip); - packageParams.put("notify_url", callbackUrl); - packageParams.put("trade_type", "NATIVE"); - packageParams.put("product_id", productId); - - return getPayInfo(packageParams); - } - - @Override - public Map getPayInfo(Map parameters) throws WxErrorException { - WxMpPrepayIdResult wxMpPrepayIdResult = getPrepayId(parameters); - - if (!"SUCCESS".equalsIgnoreCase(wxMpPrepayIdResult.getReturn_code()) - ||!"SUCCESS".equalsIgnoreCase(wxMpPrepayIdResult.getResult_code())) { - WxError error = new WxError(); - error.setErrorCode(-1); - error.setErrorMsg("return_code:" + wxMpPrepayIdResult.getReturn_code() + - ";return_msg:" + wxMpPrepayIdResult.getReturn_msg() + - ";result_code:" + wxMpPrepayIdResult.getResult_code() + - ";err_code" + wxMpPrepayIdResult.getErr_code() + - ";err_code_des" + wxMpPrepayIdResult.getErr_code_des()); - throw new WxErrorException(error); - } - - String prepayId = wxMpPrepayIdResult.getPrepay_id(); - if (prepayId == null || prepayId.equals("")) { - throw new RuntimeException(String.format("Failed to get prepay id due to error code '%s'(%s).", wxMpPrepayIdResult.getErr_code(), wxMpPrepayIdResult.getErr_code_des())); - } - - Map payInfo = new HashMap<>(); - payInfo.put("appId", this.wxMpConfigStorage.getAppId()); - // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 - payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); - payInfo.put("nonceStr", System.currentTimeMillis() + ""); - payInfo.put("package", "prepay_id=" + prepayId); - payInfo.put("signType", "MD5"); - if("NATIVE".equals(parameters.get("trade_type"))){ - payInfo.put("codeUrl", wxMpPrepayIdResult.getCode_url()); - } - - String finalSign = WxCryptUtil.createSign(payInfo, this.wxMpConfigStorage.getPartnerKey()); - payInfo.put("paySign", finalSign); - return payInfo; - } - - @Override - public WxMpPayResult getJSSDKPayResult(String transactionId, String outTradeNo) { - String nonce_str = System.currentTimeMillis() + ""; - - SortedMap packageParams = new TreeMap<>(); - packageParams.put("appid", this.wxMpConfigStorage.getAppId()); - packageParams.put("mch_id", this.wxMpConfigStorage.getPartnerId()); - if (transactionId != null && !"".equals(transactionId.trim())) - packageParams.put("transaction_id", transactionId); - else if (outTradeNo != null && !"".equals(outTradeNo.trim())) - packageParams.put("out_trade_no", outTradeNo); - else - throw new IllegalArgumentException("Either 'transactionId' or 'outTradeNo' must be given."); - packageParams.put("nonce_str", nonce_str); - packageParams.put("sign", WxCryptUtil.createSign(packageParams, this.wxMpConfigStorage.getPartnerKey())); - - StringBuilder request = new StringBuilder(""); - for (Entry para : packageParams.entrySet()) { - request.append(String.format("<%s>%s", para.getKey(), para.getValue(), para.getKey())); - } - request.append(""); - - HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/orderquery"); - if (this.httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); - httpPost.setConfig(config); - } - - StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); - httpPost.setEntity(entity); - try(CloseableHttpResponse response = this.httpClient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - XStream xstream = XStreamInitializer.getInstance(); - xstream.alias("xml", WxMpPayResult.class); - WxMpPayResult wxMpPayResult = (WxMpPayResult) xstream.fromXML(responseContent); - return wxMpPayResult; - } catch (IOException e) { - throw new RuntimeException("Failed to query order due to IO exception.", e); - } - } - - @Override - public WxMpPayCallback getJSSDKCallbackData(String xmlData) { - try { - XStream xstream = XStreamInitializer.getInstance(); - xstream.alias("xml", WxMpPayCallback.class); - WxMpPayCallback wxMpCallback = (WxMpPayCallback) xstream.fromXML(xmlData); - return wxMpCallback; - } catch (Exception e){ - e.printStackTrace(); - } - return new WxMpPayCallback(); - } - - @Override - public WxMpPayRefundResult refundPay(Map parameters) throws WxErrorException { - SortedMap refundParams = new TreeMap<>(parameters); - refundParams.put("appid", this.wxMpConfigStorage.getAppId()); - refundParams.put("mch_id", this.wxMpConfigStorage.getPartnerId()); - refundParams.put("nonce_str", System.currentTimeMillis() + ""); - refundParams.put("op_user_id", this.wxMpConfigStorage.getPartnerId()); - String sign = WxCryptUtil.createSign(refundParams, this.wxMpConfigStorage.getPartnerKey()); - refundParams.put("sign", sign); - - StringBuilder request = new StringBuilder(""); - for (Entry para : refundParams.entrySet()) { - request.append(String.format("<%s>%s", para.getKey(), para.getValue(), para.getKey())); - } - request.append(""); - - HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund"); - if (this.httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); - httpPost.setConfig(config); - } - - StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); - httpPost.setEntity(entity); - try( - CloseableHttpResponse response = getHttpclient().execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - XStream xstream = XStreamInitializer.getInstance(); - xstream.processAnnotations(WxMpPayRefundResult.class); - WxMpPayRefundResult wxMpPayRefundResult = (WxMpPayRefundResult) xstream.fromXML(responseContent); - - if (!"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getResultCode()) - ||!"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getReturnCode())) { - WxError error = new WxError(); - error.setErrorCode(-1); - error.setErrorMsg("return_code:" + wxMpPayRefundResult.getReturnCode() + - ";return_msg:" + wxMpPayRefundResult.getReturnMsg() + - ";result_code:" + wxMpPayRefundResult.getResultCode() + - ";err_code" + wxMpPayRefundResult.getErrCode() + - ";err_code_des" + wxMpPayRefundResult.getErrCodeDes()); - throw new WxErrorException(error); - } - - return wxMpPayRefundResult; - } catch (IOException e) { - this.log.error(MessageFormatter.format("The exception was happened when sending refund '{}'.", request.toString()).getMessage(), e); - WxError error = new WxError(); - error.setErrorCode(-1); - error.setErrorMsg("incorrect response."); - throw new WxErrorException(error); - }finally { - httpPost.releaseConnection(); - } - } - - @Override - public boolean checkJSSDKCallbackDataSignature(Map kvm, String signature) { - return signature.equals(WxCryptUtil.createSign(kvm, this.wxMpConfigStorage.getPartnerKey())); - } - - @Override - public WxRedpackResult sendRedpack(Map parameters) throws WxErrorException { - String nonce_str = System.currentTimeMillis() + ""; - - SortedMap packageParams = new TreeMap<>(parameters); - packageParams.put("wxappid", this.wxMpConfigStorage.getAppId()); - packageParams.put("mch_id", this.wxMpConfigStorage.getPartnerId()); - packageParams.put("nonce_str", nonce_str); - - String sign = WxCryptUtil.createSign(packageParams, this.wxMpConfigStorage.getPartnerKey()); - packageParams.put("sign", sign); - - StringBuilder request = new StringBuilder(""); - for (Entry para : packageParams.entrySet()) { - request.append(String.format("<%s>%s", para.getKey(), para.getValue(), para.getKey())); - } - request.append(""); - - HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack"); - if (this.httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); - httpPost.setConfig(config); - } - - StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); - httpPost.setEntity(entity); - try(CloseableHttpResponse response = getHttpclient().execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - XStream xstream = XStreamInitializer.getInstance(); - xstream.processAnnotations(WxRedpackResult.class); - WxRedpackResult wxMpRedpackResult = (WxRedpackResult) xstream.fromXML(responseContent); - return wxMpRedpackResult; - } catch (IOException e) { - this.log.error(MessageFormatter.format("The exception was happened when sending redpack '{}'.", request.toString()).getMessage(), e); - WxError error = new WxError(); - error.setErrorCode(-1); - throw new WxErrorException(error); - }finally { - httpPost.releaseConnection(); - } - } - @Override public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception { String url = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; @@ -840,4 +526,9 @@ public class WxMpServiceImpl implements WxMpService { return this.cardService; } + @Override + public WxMpPayService getPayService() { + return this.payService; + } + } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java new file mode 100644 index 00000000..79a5a631 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java @@ -0,0 +1,60 @@ +package me.chanjar.weixin.mp.api.impl; + +import org.testng.annotations.Test; + +/** + * Created by Binary Wang on 2016/7/28. + * @author binarywang (https://github.com/binarywang) + */ +public class WxMpPayServiceImplTest { + @Test + public void testGetPrepayId() throws Exception { + + } + + @Test + public void testGetPrepayId1() throws Exception { + + } + + @Test + public void testGetJsapiPayInfo() throws Exception { + + } + + @Test + public void testGetNativePayInfo() throws Exception { + + } + + @Test + public void testGetPayInfo() throws Exception { + + } + + @Test + public void testGetJSSDKPayResult() throws Exception { + + } + + @Test + public void testGetJSSDKCallbackData() throws Exception { + + } + + @Test + public void testRefundPay() throws Exception { + + } + + @Test + public void testCheckJSSDKCallbackDataSignature() throws Exception { + + } + + @Test + public void testSendRedpack() throws Exception { + + } + +} \ No newline at end of file