diff --git a/pom.xml b/pom.xml index 2447fd71d4..a167cd8f48 100644 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,12 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0"> 4.0.0 com.github.binarywang weixin-java-parent - 2.6.0 + 2.7.0 pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM @@ -74,6 +75,11 @@ aimilin@yeah.net https://github.com/aimilin6688 + + ecoolper + crskyp@gmail.com + https://github.com/crskyp + @@ -87,6 +93,7 @@ weixin-java-cp weixin-java-mp weixin-java-pay + weixin-java-miniapp @@ -98,73 +105,90 @@ true true 4.5 - 1.7.10 - 1.1.2 - 2.7 - 19.0 - 3.5 - 2.5 - 1.10 9.3.0.RC0 - 2.9.0 - - - org.slf4j - slf4j-api - ${slf4j.version} - - - com.thoughtworks.xstream - xstream - 1.4.9 - - - ch.qos.logback - logback-classic - ${logback.version} - test - - - org.apache.httpcomponents - httpclient - ${httpclient.version} - - - org.apache.httpcomponents - httpmime - ${httpclient.version} - - - com.google.code.gson - gson - ${gson.version} - - - commons-codec - commons-codec - ${commons-codec.version} - - - commons-io - commons-io - ${commons-io.version} - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - - com.google.guava - guava - ${guava.version} - - - + + com.github.binarywang + qrcode-utils + 1.1 + + + + org.jodd + jodd-http + 3.7.1 + provided + + + com.squareup.okhttp3 + okhttp + 3.7.0 + provided + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + org.apache.httpcomponents + httpmime + ${httpclient.version} + + + commons-codec + commons-codec + 1.10 + + + commons-io + commons-io + 2.5 + + + org.apache.commons + commons-lang3 + 3.5 + + + org.slf4j + slf4j-api + 1.7.24 + + + com.thoughtworks.xstream + xstream + 1.4.9 + + + + com.google.guava + guava + 20.0 + + + com.google.code.gson + gson + 2.8.0 + + + + + joda-time + joda-time + 2.9.7 + test + + + ch.qos.logback + logback-classic + 1.1.11 + test + com.google.inject guice @@ -174,7 +198,7 @@ org.testng testng - 6.8.7 + 6.10 test @@ -198,7 +222,8 @@ redis.clients jedis - ${jedis.version} + 2.9.0 + provided diff --git a/weixin-java-common/build.gradle b/weixin-java-common/build.gradle deleted file mode 100644 index 718004931c..0000000000 --- a/weixin-java-common/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ - -description = 'WeiXin Java Tools - Common' -dependencies { - compile group: 'com.thoughtworks.xstream', name: 'xstream', version:'1.4.7' - testCompile group: 'junit', name: 'junit', version:'4.11' - testCompile group: 'org.testng', name: 'testng', version:'6.8.7' - testCompile group: 'org.mockito', name: 'mockito-all', version:'1.9.5' - testCompile group: 'com.google.inject', name: 'guice', version:'3.0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.RC0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.RC0' -} -test.useTestNG() diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 946c65c24e..66e32664ca 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -1,12 +1,13 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0"> 4.0.0 com.github.binarywang weixin-java-parent - 2.6.0 + 2.7.0 weixin-java-common @@ -14,6 +15,59 @@ 微信公众号、企业号Java SDK Common + + org.jodd + jodd-http + provided + + + com.squareup.okhttp3 + okhttp + provided + + + + org.slf4j + slf4j-api + + + com.thoughtworks.xstream + xstream + + + org.apache.httpcomponents + httpclient + + + org.apache.httpcomponents + httpmime + + + com.google.code.gson + gson + + + commons-codec + commons-codec + + + commons-io + commons-io + + + org.apache.commons + commons-lang3 + + + com.google.guava + guava + + + + ch.qos.logback + logback-classic + test + org.testng testng diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/annotation/Required.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/annotation/Required.java index 9ed249da6b..9370561fb7 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/annotation/Required.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/annotation/Required.java @@ -7,13 +7,13 @@ /** * 标识某个字段是否是必填的 - * + *

* Created by Binary Wang on 2016/9/25. - * @author binarywang (https://github.com/binarywang) * + * @author binarywang (https://github.com/binarywang) */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Required { -} \ No newline at end of file +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java index 435ba8e0fb..e04dc45682 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java @@ -24,7 +24,6 @@ public class WxConsts { public static final String XML_MSG_HARDWARE = "hardware"; public static final String XML_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; - /////////////////////// // 主动发送消息(即客服消息)的消息类型 /////////////////////// @@ -88,45 +87,6 @@ public class WxConsts { public static final String EVT_LOCATION_SELECT = "location_select"; public static final String EVT_TEMPLATESENDJOBFINISH = "TEMPLATESENDJOBFINISH"; public static final String EVT_ENTER_AGENT = "enter_agent"; - public static final String EVT_CARD_PASS_CHECK = "card_pass_check"; - public static final String EVT_CARD_NOT_PASS_CHECK = "card_not_pass_check"; - public static final String EVT_USER_GET_CARD = "user_get_card"; - public static final String EVT_USER_DEL_CARD = "user_del_card"; - public static final String EVT_USER_CONSUME_CARD = "user_consume_card"; - public static final String EVT_USER_PAY_FROM_PAY_CELL = "user_pay_from_pay_cell"; - public static final String EVT_USER_VIEW_CARD = "user_view_card"; - public static final String EVT_USER_ENTER_SESSION_FROM_CARD = "user_enter_session_from_card"; - public static final String EVT_CARD_SKU_REMIND = "card_sku_remind"; // 库存报警 - public static final String EVT_KF_CREATE_SESSION = "kf_create_session"; // 客服接入会话 - public static final String EVT_KF_CLOSE_SESSION = "kf_close_session"; // 客服关闭会话 - public static final String EVT_KF_SWITCH_SESSION = "kf_switch_session"; // 客服转接会话 - public static final String EVT_POI_CHECK_NOTIFY = "poi_check_notify"; //门店审核事件推送 - public static final String EVN_SUBMIT_MEMBERCARD_USER_INFO = "submit_membercard_user_info"; //接收会员信息事件推送 - //以下为微信认证事件 - /** - * 资质认证成功 - */ - public static final String EVT_QUALIFICATION_VERIFY_SUCCESS = "qualification_verify_success"; - /** - * 资质认证失败 - */ - public static final String EVT_QUALIFICATION_VERIFY_FAIL = "qualification_verify_fail"; - /** - * 名称认证成功 - */ - public static final String EVT_NAMING_VERIFY_SUCCESS = "naming_verify_success"; - /** - * 名称认证失败 - */ - public static final String EVT_NAMING_VERIFY_FAIL = "naming_verify_fail"; - /** - * 年审通知 - */ - public static final String EVT_ANNUAL_RENEW = "annual_renew"; - /** - * 认证过期失效通知 - */ - public static final String EVT_VERIFY_EXPIRED = "verify_expired"; /////////////////////// // 上传多媒体文件的类型 @@ -185,7 +145,7 @@ public class WxConsts { * 跳转图文消息URL */ public static final String BUTTON_VIEW_LIMITED = "view_limited"; - + /** * 不弹出授权页面,直接跳转,只能获取用户openid */ diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java index 09901c3e0e..706de712c7 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java @@ -1,6 +1,8 @@ package me.chanjar.weixin.common.bean.result; import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import java.io.Serializable; @@ -50,8 +52,7 @@ public void setThumbMediaId(String thumbMediaId) { @Override public String toString() { - return "WxUploadResult [type=" + this.type + ", media_id=" + this.mediaId + ", thumb_media_id=" + this.thumbMediaId - + ", created_at=" + this.createdAt + "]"; + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java index 7e6c95a28f..f20fd5c2a3 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java @@ -14,7 +14,7 @@ public class StandardSessionManager implements WxSessionManager, InternalSessionManager { protected static final StringManager sm = - StringManager.getManager(Constants.Package); + StringManager.getManager(Constants.Package); /** * The descriptive name of this Manager implementation (for logging). */ @@ -82,7 +82,7 @@ public WxSession getSession(String sessionId) { public WxSession getSession(String sessionId, boolean create) { if (sessionId == null) { throw new IllegalStateException - (sm.getString("sessionManagerImpl.getSession.ise")); + (sm.getString("sessionManagerImpl.getSession.ise")); } InternalSession session = findSession(sessionId); @@ -135,15 +135,15 @@ public InternalSession findSession(String id) { public InternalSession createSession(String sessionId) { if (sessionId == null) { throw new IllegalStateException - (sm.getString("sessionManagerImpl.createSession.ise")); + (sm.getString("sessionManagerImpl.createSession.ise")); } if ((this.maxActiveSessions >= 0) && - (getActiveSessions() >= this.maxActiveSessions)) { + (getActiveSessions() >= this.maxActiveSessions)) { this.rejectedSessions++; throw new TooManyActiveSessionsException( - sm.getString("sessionManagerImpl.createSession.tmase"), - this.maxActiveSessions); + sm.getString("sessionManagerImpl.createSession.tmase"), + this.maxActiveSessions); } // Recycle or create a Session instance diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/TooManyActiveSessionsException.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/TooManyActiveSessionsException.java index 72a2b4c416..fa1b45fafe 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/TooManyActiveSessionsException.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/TooManyActiveSessionsException.java @@ -21,7 +21,7 @@ * reached and the server is refusing to create any new sessions. */ public class TooManyActiveSessionsException - extends IllegalStateException { + extends IllegalStateException { private static final long serialVersionUID = 1L; /** diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/ToStringUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/ToStringUtils.java index 0fa38391c0..333e484a8f 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/ToStringUtils.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/ToStringUtils.java @@ -13,25 +13,10 @@ */ public class ToStringUtils { public static final ToStringStyle THE_STYLE = new SimpleMultiLineToStringStyle(); - private static class SimpleMultiLineToStringStyle extends ToStringStyle { - private static final long serialVersionUID = 4645306494220335355L; - private static final String LINE_SEPARATOR = "\n"; - private static final String NULL_TEXT = ""; - - public SimpleMultiLineToStringStyle() { - super(); - this.setContentStart("["); - this.setFieldSeparator(LINE_SEPARATOR + " "); - this.setFieldSeparatorAtStart(true); - this.setContentEnd(LINE_SEPARATOR + "]"); - this.setNullText(NULL_TEXT); - this.setUseShortClassName(true); - this.setUseIdentityHashCode(false); - } - } /** * 用于产生去掉空值属性并以换行符分割各属性键值的toString字符串 + * * @param obj */ public static String toSimpleString(Object obj) { @@ -58,4 +43,21 @@ public static String toSimpleString(Object obj) { return result.deleteCharAt(result.length() - 1).toString(); } + + private static class SimpleMultiLineToStringStyle extends ToStringStyle { + private static final long serialVersionUID = 4645306494220335355L; + private static final String LINE_SEPARATOR = "\n"; + private static final String NULL_TEXT = ""; + + public SimpleMultiLineToStringStyle() { + super(); + this.setContentStart("["); + this.setFieldSeparator(LINE_SEPARATOR + " "); + this.setFieldSeparatorAtStart(true); + this.setContentEnd(LINE_SEPARATOR + "]"); + this.setNullText(NULL_TEXT); + this.setUseShortClassName(true); + this.setUseIdentityHashCode(false); + } + } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java index 683f2ecfc3..3cdc572387 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java @@ -1,8 +1,9 @@ package me.chanjar.weixin.common.util.crypto; -import java.util.Arrays; - import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; /** * Created by Daniel Qian on 14/10/19. @@ -13,6 +14,10 @@ public class SHA1 { * 串接arr参数,生成sha1 digest */ public static String gen(String... arr) { + if (StringUtils.isAnyEmpty(arr)) { + throw new IllegalArgumentException("非法请求参数,有部分参数为空 : " + Arrays.toString(arr)); + } + Arrays.sort(arr); StringBuilder sb = new StringBuilder(); for (String a : arr) { @@ -25,6 +30,10 @@ public static String gen(String... arr) { * 用&串接arr参数,生成sha1 digest */ public static String genWithAmple(String... arr) { + if (StringUtils.isAnyEmpty(arr)) { + throw new IllegalArgumentException("非法请求参数,有部分参数为空 : " + Arrays.toString(arr)); + } + Arrays.sort(arr); StringBuilder sb = new StringBuilder(); for (int i = 0; i < arr.length; i++) { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java index a809fe3b1b..e80419d716 100755 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java @@ -1,26 +1,9 @@ -/** - * 对公众平台发送给公众账号的消息加解密示例代码. - * - * @copyright Copyright (c) 1998-2014 Tencent Inc. - *

- * 针对org.apache.commons.codec.binary.Base64, - * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) - * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi - */ - -// ------------------------------------------------------------------------ - -/** - * 针对org.apache.commons.codec.binary.Base64, - * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) - * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi - */ package me.chanjar.weixin.common.util.crypto; -import java.io.StringReader; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.Random; +import org.apache.commons.codec.binary.Base64; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; @@ -28,12 +11,19 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Random; -import org.apache.commons.codec.binary.Base64; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.InputSource; - +/** + * 对公众平台发送给公众账号的消息加解密示例代码. + * + * @copyright Copyright (c) 1998-2014 Tencent Inc. + * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + */ public class WxCryptUtil { private static final Base64 base64 = new Base64(); @@ -61,9 +51,9 @@ public WxCryptUtil() { /** * 构造函数 * - * @param token 公众平台上,开发者设置的token - * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey - * @param appidOrCorpid 公众平台appid/corpid + * @param token 公众平台上,开发者设置的token + * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey + * @param appidOrCorpid 公众平台appid/corpid */ public WxCryptUtil(String token, String encodingAesKey, String appidOrCorpid) { @@ -84,6 +74,66 @@ static String extractEncryptPart(String xml) { } } + /** + * 将一个数字转换成生成4个字节的网络字节序bytes数组 + * + * @param number + */ + private static byte[] number2BytesInNetworkOrder(int number) { + byte[] orderBytes = new byte[4]; + orderBytes[3] = (byte) (number & 0xFF); + orderBytes[2] = (byte) (number >> 8 & 0xFF); + orderBytes[1] = (byte) (number >> 16 & 0xFF); + orderBytes[0] = (byte) (number >> 24 & 0xFF); + return orderBytes; + } + + /** + * 4个字节的网络字节序bytes数组还原成一个数字 + * + * @param bytesInNetworkOrder + */ + private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) { + int sourceNumber = 0; + for (int i = 0; i < 4; i++) { + sourceNumber <<= 8; + sourceNumber |= bytesInNetworkOrder[i] & 0xff; + } + return sourceNumber; + } + + /** + * 随机生成16位字符串 + */ + private static String genRandomStr() { + String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + Random random = new Random(); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < 16; i++) { + int number = random.nextInt(base.length()); + sb.append(base.charAt(number)); + } + return sb.toString(); + } + + /** + * 生成xml消息 + * + * @param encrypt 加密后的消息密文 + * @param signature 安全签名 + * @param timestamp 时间戳 + * @param nonce 随机字符串 + * @return 生成的xml字符串 + */ + private static String generateXml(String encrypt, String signature, + String timestamp, String nonce) { + String format = "\n" + "\n" + + "\n" + + "%3$s\n" + "\n" + + ""; + return String.format(format, encrypt, signature, timestamp, nonce); + } + /** * 将公众平台回复用户的消息加密打包. *

    @@ -119,7 +169,7 @@ protected String encrypt(String randomStr, String plainText) { byte[] randomStringBytes = randomStr.getBytes(CHARSET); byte[] plainTextBytes = plainText.getBytes(CHARSET); byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder( - plainTextBytes.length); + plainTextBytes.length); byte[] appIdBytes = this.appidOrCorpid.getBytes(CHARSET); // randomStr + networkBytesOrder + text + appid @@ -168,8 +218,7 @@ protected String encrypt(String randomStr, String plainText) { * @param encryptedXml 密文,对应POST请求的数据 * @return 解密后的原文 */ - public String decrypt(String msgSignature, String timeStamp, String nonce, - String encryptedXml) { + public String decrypt(String msgSignature, String timeStamp, String nonce, String encryptedXml) { // 密钥,公众账号的app corpSecret // 提取密文 String cipherText = extractEncryptPart(encryptedXml); @@ -198,7 +247,7 @@ public String decrypt(String cipherText) { Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); SecretKeySpec key_spec = new SecretKeySpec(this.aesKey, "AES"); IvParameterSpec iv = new IvParameterSpec( - Arrays.copyOfRange(this.aesKey, 0, 16)); + Arrays.copyOfRange(this.aesKey, 0, 16)); cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); // 使用BASE64对密文进行解码 @@ -221,9 +270,9 @@ public String decrypt(String cipherText) { int xmlLength = bytesNetworkOrder2Number(networkOrder); xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), - CHARSET); + CHARSET); from_appid = new String( - Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); + Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); } catch (Exception e) { throw new RuntimeException(e); } @@ -237,64 +286,4 @@ public String decrypt(String cipherText) { } - /** - * 将一个数字转换成生成4个字节的网络字节序bytes数组 - * - * @param number - */ - private static byte[] number2BytesInNetworkOrder(int number) { - byte[] orderBytes = new byte[4]; - orderBytes[3] = (byte) (number & 0xFF); - orderBytes[2] = (byte) (number >> 8 & 0xFF); - orderBytes[1] = (byte) (number >> 16 & 0xFF); - orderBytes[0] = (byte) (number >> 24 & 0xFF); - return orderBytes; - } - - /** - * 4个字节的网络字节序bytes数组还原成一个数字 - * - * @param bytesInNetworkOrder - */ - private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) { - int sourceNumber = 0; - for (int i = 0; i < 4; i++) { - sourceNumber <<= 8; - sourceNumber |= bytesInNetworkOrder[i] & 0xff; - } - return sourceNumber; - } - - /** - * 随机生成16位字符串 - */ - private static String genRandomStr() { - String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - Random random = new Random(); - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < 16; i++) { - int number = random.nextInt(base.length()); - sb.append(base.charAt(number)); - } - return sb.toString(); - } - - /** - * 生成xml消息 - * - * @param encrypt 加密后的消息密文 - * @param signature 安全签名 - * @param timestamp 时间戳 - * @param nonce 随机字符串 - * @return 生成的xml字符串 - */ - private static String generateXml(String encrypt, String signature, - String timestamp, String nonce) { - String format = "\n" + "\n" - + "\n" - + "%3$s\n" + "\n" - + ""; - return String.format(format, encrypt, signature, timestamp, nonce); - } - } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java index 9ff25ebc10..df031b3371 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java @@ -25,7 +25,7 @@ public static File createTmpFile(InputStream inputStream, String name, String ex } tmpFile.deleteOnExit(); - + try (FileOutputStream fos = new FileOutputStream(tmpFile)) { int read = 0; byte[] bytes = new byte[1024 * 100]; @@ -35,7 +35,7 @@ public static File createTmpFile(InputStream inputStream, String name, String ex fos.flush(); return tmpFile; - } + } } /** diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java new file mode 100644 index 0000000000..c692eb9100 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java @@ -0,0 +1,8 @@ +package me.chanjar.weixin.common.util.http; + +/** + * Created by ecoolper on 2017/4/28. + */ +public enum HttpType { + JODD_HTTP, APACHE_HTTP, OK_HTTP; +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java index 57024f5001..d948859748 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java @@ -1,93 +1,37 @@ package me.chanjar.weixin.common.util.http; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.fs.FileUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.http.Header; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.entity.ContentType; -import org.apache.http.impl.client.CloseableHttpClient; +import me.chanjar.weixin.common.util.http.apache.ApacheMediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaDownloadRequestExecutor; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File * 视频文件不支持下载 + * * @author Daniel Qian */ -public class MediaDownloadRequestExecutor implements RequestExecutor { +public abstract class MediaDownloadRequestExecutor implements RequestExecutor { - private File tmpDirFile; - - public MediaDownloadRequestExecutor() { - } - - public MediaDownloadRequestExecutor(File tmpDirFile) { + protected RequestHttp requestHttp; + protected File tmpDirFile; + public MediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + this.requestHttp = requestHttp; this.tmpDirFile = tmpDirFile; } - @Override - public File execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - - HttpGet httpGet = new HttpGet(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpGet.setConfig(config); - } - - try (CloseableHttpResponse response = httpclient.execute(httpGet); - InputStream inputStream = InputStreamResponseHandler.INSTANCE - .handleResponse(response)) { - - Header[] contentTypeHeader = response.getHeaders("Content-Type"); - if (contentTypeHeader != null && contentTypeHeader.length > 0) { - if (contentTypeHeader[0].getValue().startsWith(ContentType.APPLICATION_JSON.getMimeType())) { - // application/json; encoding=utf-8 下载媒体文件出错 - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - throw new WxErrorException(WxError.fromJson(responseContent)); - } - } - - String fileName = getFileName(response); - if (StringUtils.isBlank(fileName)) { + public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheMediaDownloadRequestExecutor(requestHttp, tmpDirFile); + case JODD_HTTP: + return new JoddHttpMediaDownloadRequestExecutor(requestHttp, tmpDirFile); + case OK_HTTP: + return new OkHttpMediaDownloadRequestExecutor(requestHttp, tmpDirFile); + default: return null; - } - - String[] nameAndExt = fileName.split("\\."); - return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); - - } finally { - httpGet.releaseConnection(); - } - - } - - private String getFileName(CloseableHttpResponse response) throws WxErrorException { - Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); - if(contentDispositionHeader == null || contentDispositionHeader.length == 0){ - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); - } - - Pattern p = Pattern.compile(".*filename=\"(.*)\""); - Matcher m = p.matcher(contentDispositionHeader[0].getValue()); - if(m.matches()){ - return m.group(1); } - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java index 54ded05a7a..6b883ce7cd 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java @@ -1,53 +1,34 @@ package me.chanjar.weixin.common.util.http; -import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.common.exception.WxErrorException; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.HttpMultipartMode; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.impl.client.CloseableHttpClient; +import me.chanjar.weixin.common.util.http.apache.ApacheMediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaUploadRequestExecutor; import java.io.File; -import java.io.IOException; /** * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String * * @author Daniel Qian */ -public class MediaUploadRequestExecutor implements RequestExecutor { +public abstract class MediaUploadRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; - @Override - public WxMediaUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File file) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - if (file != null) { - HttpEntity entity = MultipartEntityBuilder - .create() - .addBinaryBody("media", file) - .setMode(HttpMultipartMode.RFC6532) - .build(); - httpPost.setEntity(entity); - httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); - } - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return WxMediaUploadResult.fromJson(responseContent); - } finally { - httpPost.releaseConnection(); + public MediaUploadRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } + + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheMediaUploadRequestExecutor(requestHttp); + case JODD_HTTP: + return new JoddHttpMediaUploadRequestExecutor(requestHttp); + case OK_HTTP: + return new OkHttpMediaUploadRequestExecutor(requestHttp); + default: + return null; } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java index 6d2dbe9ab8..583db4f5ae 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java @@ -1,8 +1,6 @@ package me.chanjar.weixin.common.util.http; import me.chanjar.weixin.common.exception.WxErrorException; -import org.apache.http.HttpHost; -import org.apache.http.impl.client.CloseableHttpClient; import java.io.IOException; @@ -15,13 +13,47 @@ public interface RequestExecutor { /** - * @param httpclient 传入的httpClient - * @param httpProxy http代理对象,如果没有配置代理则为空 - * @param uri uri - * @param data 数据 + * @param uri uri + * @param data 数据 * @throws WxErrorException * @throws IOException */ - T execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, E data) throws WxErrorException, IOException; + T execute(String uri, E data) throws WxErrorException, IOException; + /** + * apache-http实现方式 + * @param httpclient + * @param httpProxy + * @param uri + * @param data + * @return + * @throws WxErrorException + * @throws IOException + *//* + T executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, E data) throws WxErrorException, IOException; + + *//** + * jodd-http实现方式 + * @param provider + * @param proxyInfo + * @param uri + * @param data + * @return + * @throws WxErrorException + * @throws IOException + *//* + T executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, E data) throws WxErrorException, IOException; + + + *//** okhttp实现方式 + * @param pool + * @param proxyInfo + * @param uri + * @param data + * @return + * @throws WxErrorException + * @throws IOException + *//* + T executeOkhttp(ConnectionPool pool, final OkHttpProxyInfo proxyInfo, String uri, E data) throws WxErrorException, IOException; +*/ } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java new file mode 100644 index 0000000000..efd9f99b9d --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java @@ -0,0 +1,22 @@ +package me.chanjar.weixin.common.util.http; + +/** + * Created by ecoolper on 2017/4/22. + */ +public interface RequestHttp { + + /** + * 返回httpClient + * + */ + H getRequestHttpClient(); + + /** + * 返回httpProxy + * + */ + P getRequestHttpProxy(); + + HttpType getRequestType(); + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java index ec221e28b8..e72acc9084 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java @@ -1,45 +1,31 @@ package me.chanjar.weixin.common.util.http; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.IOException; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientSimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimpleGetRequestExecutor; /** * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String * * @author Daniel Qian */ -public class SimpleGetRequestExecutor implements RequestExecutor { +public abstract class SimpleGetRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; - @Override - public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { - if (queryParam != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") ? queryParam : '&' + queryParam; - } - HttpGet httpGet = new HttpGet(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpGet.setConfig(config); - } + public SimpleGetRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } - try (CloseableHttpResponse response = httpclient.execute(httpGet)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return responseContent; - } finally { - httpGet.releaseConnection(); + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheHttpClientSimpleGetRequestExecutor(requestHttp); + case JODD_HTTP: + return new JoddHttpSimpleGetRequestExecutor(requestHttp); + case OK_HTTP: + return new OkHttpSimpleGetRequestExecutor(requestHttp); + default: + throw new IllegalArgumentException("非法请求参数"); } } 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 bdea8573c0..2932f24728 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java @@ -1,58 +1,32 @@ package me.chanjar.weixin.common.util.http; -import java.io.IOException; - -import org.apache.http.Consts; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.apache.ApacheSimplePostRequestExecutor; +import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimplePostRequestExecutor; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimplePostRequestExecutor; /** + * 用装饰模式实现 * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String * * @author Daniel Qian */ -public class SimplePostRequestExecutor implements RequestExecutor { - - @Override - public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String postEntity) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } +public abstract class SimplePostRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; - if (postEntity != null) { - StringEntity entity = new StringEntity(postEntity, Consts.UTF_8); - httpPost.setEntity(entity); - } - - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - if (responseContent.isEmpty()) { - throw new WxErrorException( - WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") - .build()); - } - - if (responseContent.startsWith("")) { - //xml格式输出直接返回 - return responseContent; - } + public SimplePostRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return responseContent; - } finally { - httpPost.releaseConnection(); + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheSimplePostRequestExecutor(requestHttp); + case JODD_HTTP: + return new JoddHttpSimplePostRequestExecutor(requestHttp); + case OK_HTTP: + return new OkHttpSimplePostRequestExecutor(requestHttp); + default: + return null; } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/WxDnsResolver.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/WxDnsResolver.java new file mode 100644 index 0000000000..6c6137089a --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/WxDnsResolver.java @@ -0,0 +1,61 @@ +package me.chanjar.weixin.common.util.http; + +import org.apache.http.conn.DnsResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; + +/** + * 微信DNS域名解析器,将微信域名绑定到指定IP + * -------------------------------------------- + * 适用于服务器端调用微信服务器需要开通出口防火墙情况 + *

    + * Created by Andy Huo on 17/03/28. + */ +public class WxDnsResolver implements DnsResolver { + + private final static String WECHAT_API_URL = "api.weixin.qq.com"; + private static Map MAPPINGS = new HashMap(); + protected final Logger log = LoggerFactory.getLogger(WxDnsResolver.class); + private String wxApiIp; + + public WxDnsResolver(String ip) { + + this.wxApiIp = ip; + this.init(); + } + + private void init() { + if (log.isDebugEnabled()) { + log.debug("init wechat dns config with ip {}", wxApiIp); + } + try { + MAPPINGS.put(WECHAT_API_URL, new InetAddress[]{InetAddress.getByName(wxApiIp)}); + } catch (UnknownHostException e) { + //如果初始化DNS配置失败则使用默认配置,不影响服务的启动 + log.error("init WxDnsResolver error", e); + MAPPINGS = new HashMap(); + } + + } + + @Override + public InetAddress[] resolve(String host) throws UnknownHostException { + + + return MAPPINGS.containsKey(host) ? MAPPINGS.get(host) : new InetAddress[0]; + } + + public String getWxApiIp() { + return wxApiIp; + } + + public void setWxApiIp(String wxApiIp) { + this.wxApiIp = wxApiIp; + this.init(); + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java similarity index 95% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java index c932445d33..939b624785 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java @@ -1,10 +1,11 @@ -package me.chanjar.weixin.common.util.http; +package me.chanjar.weixin.common.util.http.apache; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; /** * httpclient build interface + * * @author kakotor */ public interface ApacheHttpClientBuilder { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientSimpleGetRequestExecutor.java new file mode 100644 index 0000000000..e47216e6cd --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientSimpleGetRequestExecutor.java @@ -0,0 +1,50 @@ +package me.chanjar.weixin.common.util.http.apache; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class ApacheHttpClientSimpleGetRequestExecutor extends SimpleGetRequestExecutor { + + public ApacheHttpClientSimpleGetRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + HttpGet httpGet = new HttpGet(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } finally { + httpGet.releaseConnection(); + } + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java new file mode 100644 index 0000000000..d3e5a1c167 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java @@ -0,0 +1,306 @@ +package me.chanjar.weixin.common.util.http.apache; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.annotation.NotThreadSafe; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.HttpRequestRetryHandler; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.config.SocketConfig; +import org.apache.http.conn.DnsResolver; +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.protocol.HttpContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * httpclient 连接管理器 自带DNS解析 + *

    + * 大部分代码拷贝自:DefaultApacheHttpClientBuilder + * + * @author Andy.Huo + */ +@NotThreadSafe +public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { + protected final Logger log = LoggerFactory.getLogger(ApacheHttpDnsClientBuilder.class); + private final AtomicBoolean prepared = new AtomicBoolean(false); + private int connectionRequestTimeout = 3000; + private int connectionTimeout = 5000; + private int soTimeout = 5000; + private int idleConnTimeout = 60000; + private int checkWaitTime = 60000; + private int maxConnPerHost = 10; + private int maxTotalConn = 50; + private String userAgent; + + private DnsResolver dnsResover; + + private HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { + @Override + public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { + return false; + } + }; + private SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory(); + private PlainConnectionSocketFactory plainConnectionSocketFactory = PlainConnectionSocketFactory.getSocketFactory(); + private String httpProxyHost; + private int httpProxyPort; + private String httpProxyUsername; + private String httpProxyPassword; + + /** + * 闲置连接监控线程 + */ + private IdleConnectionMonitorThread idleConnectionMonitorThread; + private HttpClientBuilder httpClientBuilder; + + private ApacheHttpDnsClientBuilder() { + } + + public static ApacheHttpDnsClientBuilder get() { + return new ApacheHttpDnsClientBuilder(); + } + + @Override + public ApacheHttpClientBuilder httpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + return this; + } + + @Override + public ApacheHttpClientBuilder httpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + return this; + } + + @Override + public ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + return this; + } + + @Override + public ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + return this; + } + + @Override + public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory) { + this.sslConnectionSocketFactory = sslConnectionSocketFactory; + return this; + } + + /** + * 获取链接的超时时间设置,默认3000ms + *

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

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

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

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

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

    + * + * @param idleConnTimeout 空闲链接的超时时间,默认60000ms. + */ + public void setIdleConnTimeout(int idleConnTimeout) { + this.idleConnTimeout = idleConnTimeout; + } + + /** + * 检查空间链接的间隔周期,默认60000ms. + * + * @param checkWaitTime 检查空间链接的间隔周期,默认60000ms. + */ + public void setCheckWaitTime(int checkWaitTime) { + this.checkWaitTime = checkWaitTime; + } + + /** + * 每路的最大链接数,默认10 + * + * @param maxConnPerHost 每路的最大链接数,默认10 + */ + public void setMaxConnPerHost(int maxConnPerHost) { + this.maxConnPerHost = maxConnPerHost; + } + + /** + * 最大总连接数,默认50 + * + * @param maxTotalConn 最大总连接数,默认50 + */ + public void setMaxTotalConn(int maxTotalConn) { + this.maxTotalConn = maxTotalConn; + } + + /** + * 自定义httpclient的User Agent + * + * @param userAgent User Agent + */ + public void setUserAgent(String userAgent) { + this.userAgent = userAgent; + } + + public IdleConnectionMonitorThread getIdleConnectionMonitorThread() { + return this.idleConnectionMonitorThread; + } + + private synchronized void prepare() { + if (prepared.get()) { + return; + } + Registry registry = RegistryBuilder.create() + .register("http", this.plainConnectionSocketFactory).register("https", this.sslConnectionSocketFactory) + .build(); + + @SuppressWarnings("resource") + PoolingHttpClientConnectionManager connectionManager; + if (dnsResover != null) { + if (log.isDebugEnabled()) { + log.debug("specified dns resolver."); + } + connectionManager = new PoolingHttpClientConnectionManager(registry, dnsResover); + } else { + if (log.isDebugEnabled()) { + log.debug("Not specified dns resolver."); + } + connectionManager = new PoolingHttpClientConnectionManager(registry); + } + + connectionManager.setMaxTotal(this.maxTotalConn); + connectionManager.setDefaultMaxPerRoute(this.maxConnPerHost); + connectionManager + .setDefaultSocketConfig(SocketConfig.copy(SocketConfig.DEFAULT).setSoTimeout(this.soTimeout).build()); + + this.idleConnectionMonitorThread = new IdleConnectionMonitorThread(connectionManager, this.idleConnTimeout, + this.checkWaitTime); + this.idleConnectionMonitorThread.setDaemon(true); + this.idleConnectionMonitorThread.start(); + + this.httpClientBuilder = HttpClients.custom().setConnectionManager(connectionManager) + .setConnectionManagerShared(true) + .setDefaultRequestConfig(RequestConfig.custom().setSocketTimeout(this.soTimeout) + .setConnectTimeout(this.connectionTimeout) + .setConnectionRequestTimeout(this.connectionRequestTimeout).build()) + .setRetryHandler(this.httpRequestRetryHandler); + + if (StringUtils.isNotBlank(this.httpProxyHost) && StringUtils.isNotBlank(this.httpProxyUsername)) { + // 使用代理服务器 需要用户认证的代理服务器 + CredentialsProvider provider = new BasicCredentialsProvider(); + provider.setCredentials(new AuthScope(this.httpProxyHost, this.httpProxyPort), + new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword)); + this.httpClientBuilder.setDefaultCredentialsProvider(provider); + } + + if (StringUtils.isNotBlank(this.userAgent)) { + this.httpClientBuilder.setUserAgent(this.userAgent); + } + prepared.set(true); + } + + @Override + public CloseableHttpClient build() { + if (!prepared.get()) { + prepare(); + } + return this.httpClientBuilder.build(); + } + + public DnsResolver getDnsResover() { + return dnsResover; + } + + public void setDnsResover(DnsResolver dnsResover) { + this.dnsResover = dnsResover; + } + + public static class IdleConnectionMonitorThread extends Thread { + private final HttpClientConnectionManager connMgr; + private final int idleConnTimeout; + private final int checkWaitTime; + private volatile boolean shutdown; + + public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, + int checkWaitTime) { + super("IdleConnectionMonitorThread"); + this.connMgr = connMgr; + this.idleConnTimeout = idleConnTimeout; + this.checkWaitTime = checkWaitTime; + } + + @Override + public void run() { + try { + while (!this.shutdown) { + synchronized (this) { + wait(this.checkWaitTime); + this.connMgr.closeExpiredConnections(); + this.connMgr.closeIdleConnections(this.idleConnTimeout, TimeUnit.MILLISECONDS); + } + } + } catch (InterruptedException ignore) { + } + } + + public void trigger() { + synchronized (this) { + notifyAll(); + } + } + + public void shutdown() { + this.shutdown = true; + synchronized (this) { + notifyAll(); + } + } + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java new file mode 100644 index 0000000000..6a928648e5 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java @@ -0,0 +1,87 @@ +package me.chanjar.weixin.common.util.http.apache; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor { + + + public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public File execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpGet httpGet = new HttpGet(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet); + InputStream inputStream = InputStreamResponseHandler.INSTANCE + .handleResponse(response)) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0) { + if (contentTypeHeader[0].getValue().startsWith(ContentType.APPLICATION_JSON.getMimeType())) { + // application/json; encoding=utf-8 下载媒体文件出错 + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + } + + String fileName = getFileName(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + + String[] nameAndExt = fileName.split("\\."); + return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], super.tmpDirFile); + + } finally { + httpGet.releaseConnection(); + } + } + + private String getFileName(CloseableHttpResponse response) throws WxErrorException { + Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); + if (contentDispositionHeader == null || contentDispositionHeader.length == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(contentDispositionHeader[0].getValue()); + if (m.matches()) { + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java new file mode 100644 index 0000000000..bdddf0dfb9 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java @@ -0,0 +1,55 @@ +package me.chanjar.weixin.common.util.http.apache; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMediaUploadRequestExecutor extends MediaUploadRequestExecutor { + public ApacheMediaUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaUploadResult execute(String uri, File file) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + if (file != null) { + HttpEntity entity = MultipartEntityBuilder + .create() + .addBinaryBody("media", file) + .setMode(HttpMultipartMode.RFC6532) + .build(); + httpPost.setEntity(entity); + } + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMediaUploadResult.fromJson(responseContent); + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java new file mode 100644 index 0000000000..cc85fa76d7 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java @@ -0,0 +1,61 @@ +package me.chanjar.weixin.common.util.http.apache; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import org.apache.http.Consts; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class ApacheSimplePostRequestExecutor extends SimplePostRequestExecutor { + + public ApacheSimplePostRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String postEntity) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + if (postEntity != null) { + StringEntity entity = new StringEntity(postEntity, Consts.UTF_8); + httpPost.setEntity(entity); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + if (responseContent.isEmpty()) { + throw new WxErrorException( + WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") + .build()); + } + + if (responseContent.startsWith("")) { + //xml格式输出直接返回 + return responseContent; + } + + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java similarity index 88% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/DefaultApacheHttpClientBuilder.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java index 030fe98fe2..b328ede9af 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/DefaultApacheHttpClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.common.util.http; +package me.chanjar.weixin.common.util.http.apache; import org.apache.commons.lang3.StringUtils; import org.apache.http.annotation.NotThreadSafe; @@ -14,16 +14,24 @@ import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.protocol.HttpContext; +import org.apache.http.ssl.SSLContexts; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.net.ssl.SSLContext; import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -188,7 +196,7 @@ public IdleConnectionMonitorThread getIdleConnectionMonitorThread() { } private synchronized void prepare() { - if(prepared.get()){ + if (prepared.get()) { return; } Registry registry = RegistryBuilder.create() @@ -214,6 +222,7 @@ private synchronized void prepare() { this.httpClientBuilder = HttpClients.custom() .setConnectionManager(connectionManager) .setConnectionManagerShared(true) + .setSSLSocketFactory(this.buildSSLConnectionSocketFactory()) .setDefaultRequestConfig( RequestConfig.custom() .setSocketTimeout(this.soTimeout) @@ -240,9 +249,32 @@ private synchronized void prepare() { prepared.set(true); } + private SSLConnectionSocketFactory buildSSLConnectionSocketFactory() { + try { + SSLContext sslcontext = SSLContexts.custom() + //忽略掉对服务器端证书的校验 + .loadTrustMaterial(new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return true; + } + }).build(); + + return new SSLConnectionSocketFactory( + sslcontext, + new String[]{"TLSv1"}, + null, + SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) { + this.log.error(e.getMessage(), e); + } + + return null; + } + @Override public CloseableHttpClient build() { - if(!prepared.get()){ + if (!prepared.get()) { prepare(); } return this.httpClientBuilder.build(); 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/apache/InputStreamResponseHandler.java similarity index 94% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamResponseHandler.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java index 0cc1562b59..d4cea91da1 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/apache/InputStreamResponseHandler.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.common.util.http; +package me.chanjar.weixin.common.util.http.apache; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/Utf8ResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java similarity index 95% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/Utf8ResponseHandler.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java index 148ef9650d..697d4695e2 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/apache/Utf8ResponseHandler.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.common.util.http; +package me.chanjar.weixin.common.util.http.apache; import org.apache.http.Consts; import org.apache.http.HttpEntity; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java new file mode 100644 index 0000000000..edbee76678 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java @@ -0,0 +1,81 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.StringPool; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import org.apache.commons.lang3.StringUtils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddHttpMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor { + + + public JoddHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public File execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpRequest request = HttpRequest.get(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + + String contentType = response.header("Content-Type"); + if (contentType != null && contentType.startsWith("application/json")) { + // application/json; encoding=utf-8 下载媒体文件出错 + throw new WxErrorException(WxError.fromJson(response.bodyText())); + } + + String fileName = getFileName(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + + InputStream inputStream = new ByteArrayInputStream(response.bodyBytes()); + String[] nameAndExt = fileName.split("\\."); + return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], super.tmpDirFile); + } + + private String getFileName(HttpResponse response) throws WxErrorException { + String content = response.header("Content-disposition"); + if (content == null || content.length() == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(content); + if (m.matches()) { + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java new file mode 100644 index 0000000000..b4eef26a79 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java @@ -0,0 +1,44 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.StringPool; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; + +import java.io.File; +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddHttpMediaUploadRequestExecutor extends MediaUploadRequestExecutor { + public JoddHttpMediaUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaUploadResult execute(String uri, File file) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + request.form("media", file); + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMediaUploadResult.fromJson(responseContent); + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java new file mode 100644 index 0000000000..63386e77a8 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java @@ -0,0 +1,48 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.*; +import jodd.util.StringPool; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class JoddHttpSimpleGetRequestExecutor extends SimpleGetRequestExecutor { + + public JoddHttpSimpleGetRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpRequest request = HttpRequest.get(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + + String responseContent = response.bodyText(); + + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java new file mode 100644 index 0000000000..8fa349c67a --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java @@ -0,0 +1,60 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.StringPool; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class JoddHttpSimplePostRequestExecutor extends SimplePostRequestExecutor { + + public JoddHttpSimplePostRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String postEntity) throws WxErrorException, IOException { + HttpConnectionProvider provider = requestHttp.getRequestHttpClient(); + ProxyInfo proxyInfo = requestHttp.getRequestHttpProxy(); + + HttpRequest request = HttpRequest.post(uri); + if (proxyInfo != null) { + provider.useProxy(proxyInfo); + } + request.withConnectionProvider(provider); + if (postEntity != null) { + request.bodyText(postEntity); + } + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + + String responseContent = response.bodyText(); + if (responseContent.isEmpty()) { + throw new WxErrorException( + WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") + .build()); + } + + if (responseContent.startsWith("")) { + //xml格式输出直接返回 + return responseContent; + } + + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java new file mode 100644 index 0000000000..97f8cb02c5 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java @@ -0,0 +1,89 @@ +package me.chanjar.weixin.common.util.http.okhttp; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import okhttp3.*; +import org.apache.commons.lang3.StringUtils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkHttpMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor { + + + public OkHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public File execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + Request request = new Request.Builder().url(uri).get().build(); + + Response response = client.newCall(request).execute(); + + String contentType = response.header("Content-Type"); + if (contentType != null && contentType.startsWith("application/json")) { + // application/json; encoding=utf-8 下载媒体文件出错 + throw new WxErrorException(WxError.fromJson(response.body().string())); + } + + String fileName = getFileName(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + + InputStream inputStream = new ByteArrayInputStream(response.body().bytes()); + String[] nameAndExt = fileName.split("\\."); + return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], super.tmpDirFile); + } + + private String getFileName(Response response) throws WxErrorException { + String content = response.header("Content-disposition"); + if (content == null || content.length() == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(content); + if (m.matches()) { + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java new file mode 100644 index 0000000000..c01b373808 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java @@ -0,0 +1,55 @@ +package me.chanjar.weixin.common.util.http.okhttp; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import okhttp3.*; + +import java.io.File; +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkHttpMediaUploadRequestExecutor extends MediaUploadRequestExecutor { + + public OkHttpMediaUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaUploadResult execute(String uri, File file) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); + RequestBody body = new MultipartBody.Builder().addFormDataPart("media", null, fileBody).build(); + Request request = new Request.Builder().url(uri).post(body).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMediaUploadResult.fromJson(responseContent); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpProxyInfo.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpProxyInfo.java new file mode 100644 index 0000000000..5515b0f713 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpProxyInfo.java @@ -0,0 +1,117 @@ +package me.chanjar.weixin.common.util.http.okhttp; + +import java.net.InetSocketAddress; +import java.net.Proxy; + +/** + * Created by ecoolper on 2017/4/26. + * Proxy information. + */ +public class OkHttpProxyInfo { + private final String proxyAddress; + private final int proxyPort; + private final String proxyUsername; + private final String proxyPassword; + private final ProxyType proxyType; + public OkHttpProxyInfo(ProxyType proxyType, String proxyHost, int proxyPort, String proxyUser, String proxyPassword) { + this.proxyType = proxyType; + this.proxyAddress = proxyHost; + this.proxyPort = proxyPort; + this.proxyUsername = proxyUser; + this.proxyPassword = proxyPassword; + } + + /** + * Creates directProxy. + */ + public static OkHttpProxyInfo directProxy() { + return new OkHttpProxyInfo(ProxyType.NONE, null, 0, null, null); + } + + // ---------------------------------------------------------------- factory + + /** + * Creates SOCKS4 proxy. + */ + public static OkHttpProxyInfo socks4Proxy(String proxyAddress, int proxyPort, String proxyUser) { + return new OkHttpProxyInfo(ProxyType.SOCKS4, proxyAddress, proxyPort, proxyUser, null); + } + + /** + * Creates SOCKS5 proxy. + */ + public static OkHttpProxyInfo socks5Proxy(String proxyAddress, int proxyPort, String proxyUser, String proxyPassword) { + return new OkHttpProxyInfo(ProxyType.SOCKS5, proxyAddress, proxyPort, proxyUser, proxyPassword); + } + + /** + * Creates HTTP proxy. + */ + public static OkHttpProxyInfo httpProxy(String proxyAddress, int proxyPort, String proxyUser, String proxyPassword) { + return new OkHttpProxyInfo(ProxyType.HTTP, proxyAddress, proxyPort, proxyUser, proxyPassword); + } + + /** + * Returns proxy type. + */ + public ProxyType getProxyType() { + return proxyType; + } + + // ---------------------------------------------------------------- getter + + /** + * Returns proxy address. + */ + public String getProxyAddress() { + return proxyAddress; + } + + /** + * Returns proxy port. + */ + public int getProxyPort() { + return proxyPort; + } + + /** + * Returns proxy user name or null if + * no authentication required. + */ + public String getProxyUsername() { + return proxyUsername; + } + + /** + * Returns proxy password or null. + */ + public String getProxyPassword() { + return proxyPassword; + } + + /** + * 返回 java.net.Proxy + * + * @return + */ + public Proxy getProxy() { + Proxy proxy = null; + if (getProxyType().equals(ProxyType.SOCKS5)) { + proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(getProxyAddress(), getProxyPort())); + } else if (getProxyType().equals(ProxyType.SOCKS4)) { + proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(getProxyAddress(), getProxyPort())); + } else if (getProxyType().equals(ProxyType.HTTP)) { + proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(getProxyAddress(), getProxyPort())); + } else if (getProxyType().equals(ProxyType.NONE)) { + proxy = new Proxy(Proxy.Type.DIRECT, new InetSocketAddress(getProxyAddress(), getProxyPort())); + } + return proxy; + } + + /** + * Proxy types. + */ + public enum ProxyType { + NONE, HTTP, SOCKS4, SOCKS5 + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java new file mode 100644 index 0000000000..bbb5d43754 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java @@ -0,0 +1,58 @@ +package me.chanjar.weixin.common.util.http.okhttp; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import okhttp3.*; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class OkHttpSimpleGetRequestExecutor extends SimpleGetRequestExecutor { + + public OkHttpSimpleGetRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + Request request = new Request.Builder().url(uri).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java new file mode 100644 index 0000000000..9d153117c5 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java @@ -0,0 +1,58 @@ +package me.chanjar.weixin.common.util.http.okhttp; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import okhttp3.*; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/4. + */ +public class OkHttpSimplePostRequestExecutor extends SimplePostRequestExecutor { + + public OkHttpSimplePostRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, String postEntity) throws WxErrorException, IOException { + ConnectionPool pool = requestHttp.getRequestHttpClient(); + final OkHttpProxyInfo proxyInfo = requestHttp.getRequestHttpProxy(); + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); + //设置代理 + if (proxyInfo != null) { + clientBuilder.proxy(proxyInfo.getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(proxyInfo.getProxyUsername(), proxyInfo.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + + MediaType mediaType = MediaType.parse("text/plain; charset=utf-8"); + RequestBody body = RequestBody.create(mediaType, postEntity); + + Request request = new Request.Builder().url(uri).post(body).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java index 100ef52303..9847d16211 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java @@ -2,7 +2,6 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; - import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.result.WxError; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java index 526b5f29c9..c506c1ed75 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java @@ -90,9 +90,14 @@ public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationCon * 操蛋的微信 * 创建菜单时是 { button : ... } * 查询菜单时是 { menu : { button : ... } } + * 现在企业号升级为企业微信后,没有此问题,因此需要单独处理 */ - WxMenu menu = new WxMenu(); JsonArray buttonsJson = json.getAsJsonObject().get("menu").getAsJsonObject().get("button").getAsJsonArray(); + return this.buildMenuFromJson(buttonsJson); + } + + protected WxMenu buildMenuFromJson(JsonArray buttonsJson) { + WxMenu menu = new WxMenu(); for (int i = 0; i < buttonsJson.size(); i++) { JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject(); WxMenuButton button = convertFromJson(buttonJson); diff --git a/weixin-java-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 32f4e42aaa..3d66125eb7 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 @@ -47,7 +47,7 @@ public class StringManager { private static final Map> managers = - new Hashtable<>(); + new Hashtable<>(); private static int LOCALE_CACHE_SIZE = 10; /** * The ResourceBundle for this StringManager. @@ -103,7 +103,7 @@ private StringManager(String packageName, Locale locale) { * @param packageName The package name */ public static final synchronized StringManager getManager( - String packageName) { + String packageName) { return getManager(packageName, Locale.getDefault()); } @@ -116,7 +116,7 @@ public static final synchronized StringManager getManager( * @param locale The Locale */ public static final synchronized StringManager getManager( - String packageName, Locale locale) { + String packageName, Locale locale) { Map map = managers.get(packageName); if (map == null) { @@ -133,7 +133,7 @@ public static final synchronized StringManager getManager( @Override protected boolean removeEldestEntry( - Map.Entry eldest) { + Map.Entry eldest) { return size() > (LOCALE_CACHE_SIZE - 1); } }; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java index ba49528aaf..aa2ce1763d 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java @@ -1,7 +1,5 @@ package me.chanjar.weixin.common.util.xml; -import java.io.Writer; - import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.core.util.QuickWriter; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; @@ -10,6 +8,8 @@ import com.thoughtworks.xstream.security.NullPermission; import com.thoughtworks.xstream.security.PrimitiveTypePermission; +import java.io.Writer; + public class XStreamInitializer { public static XStream getInstance() { diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateCheckerTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateCheckerTest.java similarity index 68% rename from weixin-java-common/src/test/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateCheckerTest.java rename to weixin-java-common/src/test/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateCheckerTest.java index a3a243a428..8599b29f89 100644 --- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateCheckerTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateCheckerTest.java @@ -1,34 +1,36 @@ -package me.chanjar.weixin.common.util; +package me.chanjar.weixin.common.api; -import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; import org.testng.Assert; import org.testng.annotations.Test; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + @Test public class WxMessageInMemoryDuplicateCheckerTest { + private WxMessageInMemoryDuplicateChecker checker = new WxMessageInMemoryDuplicateChecker(2000l, 1000l); public void test() throws InterruptedException { Long[] msgIds = new Long[]{1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l}; - WxMessageInMemoryDuplicateChecker checker = new WxMessageInMemoryDuplicateChecker(2000l, 1000l); // 第一次检查 for (Long msgId : msgIds) { boolean result = checker.isDuplicate(String.valueOf(msgId)); - Assert.assertFalse(result); + assertFalse(result); } // 过1秒再检查 Thread.sleep(1000l); for (Long msgId : msgIds) { boolean result = checker.isDuplicate(String.valueOf(msgId)); - Assert.assertTrue(result); + assertTrue(result); } // 过1.5秒再检查 Thread.sleep(1500l); for (Long msgId : msgIds) { boolean result = checker.isDuplicate(String.valueOf(msgId)); - Assert.assertFalse(result); + assertFalse(result); } } diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxAccessTokenTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxAccessTokenTest.java index b2bc7fe7d1..1f88df29bb 100644 --- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxAccessTokenTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxAccessTokenTest.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.common.bean; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.testng.*; +import org.testng.annotations.*; @Test public class WxAccessTokenTest { diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxErrorTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxErrorTest.java index 3fe40795f3..477fcdabc0 100644 --- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxErrorTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxErrorTest.java @@ -1,8 +1,8 @@ package me.chanjar.weixin.common.bean; import me.chanjar.weixin.common.bean.result.WxError; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.testng.*; +import org.testng.annotations.*; @Test public class WxErrorTest { diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxMenuTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxMenuTest.java index e2a0c2c1f8..506b2dbaca 100644 --- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxMenuTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/bean/WxMenuTest.java @@ -1,12 +1,10 @@ package me.chanjar.weixin.common.bean; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.menu.WxMenuButton; import me.chanjar.weixin.common.bean.menu.WxMenuRule; +import org.testng.*; +import org.testng.annotations.*; @Test public class WxMenuTest { @@ -87,75 +85,75 @@ public Object[][] wxReturnMenu() { Object[][] res = menuJson(); String json = "{ \"menu\" : " + res[0][0] + " }"; return new Object[][]{ - new Object[]{json} + new Object[]{json} }; } @DataProvider(name = "wxPushMenu") public Object[][] menuJson() { String json = - "{" - + "\"button\":[" - + "{" - + "\"type\":\"click\"," - + "\"name\":\"今日歌曲\"," - + "\"key\":\"V1001_TODAY_MUSIC\"" - + "}," - + "{" - + "\"type\":\"click\"," - + "\"name\":\"歌手简介\"," - + "\"key\":\"V1001_TODAY_SINGER\"" - + "}," - + "{" - + "\"name\":\"菜单\"," - + "\"sub_button\":[" - + "{" - + "\"type\":\"view\"," - + "\"name\":\"搜索\"," - + "\"url\":\"http://www.soso.com/\"" - + "}," - + "{" - + "\"type\":\"view\"," - + "\"name\":\"视频\"," - + "\"url\":\"http://v.qq.com/\"" - + "}," - + "{" - + "\"type\":\"click\"," - + "\"name\":\"赞一下我们\"," - + "\"key\":\"V1001_GOOD\"" - + "}" - + "]" - + "}" - + "]" - + "}"; + "{" + + "\"button\":[" + + "{" + + "\"type\":\"click\"," + + "\"name\":\"今日歌曲\"," + + "\"key\":\"V1001_TODAY_MUSIC\"" + + "}," + + "{" + + "\"type\":\"click\"," + + "\"name\":\"歌手简介\"," + + "\"key\":\"V1001_TODAY_SINGER\"" + + "}," + + "{" + + "\"name\":\"菜单\"," + + "\"sub_button\":[" + + "{" + + "\"type\":\"view\"," + + "\"name\":\"搜索\"," + + "\"url\":\"http://www.soso.com/\"" + + "}," + + "{" + + "\"type\":\"view\"," + + "\"name\":\"视频\"," + + "\"url\":\"http://v.qq.com/\"" + + "}," + + "{" + + "\"type\":\"click\"," + + "\"name\":\"赞一下我们\"," + + "\"key\":\"V1001_GOOD\"" + + "}" + + "]" + + "}" + + "]" + + "}"; return new Object[][]{ - new Object[]{json} + new Object[]{json} }; } @DataProvider(name = "wxAddConditionalMenu") public Object[][] addConditionalMenuJson() { String json = - "{" - + "\"button\":[" - + "{" - + "\"type\":\"click\"," - + "\"name\":\"今日歌曲\"," - + "\"key\":\"V1001_TODAY_MUSIC\"" - + "}" - + "]," - + "\"matchrule\":{" - + "\"group_id\":\"2\"," - + "\"sex\":\"1\"," - + "\"country\":\"中国\"," - + "\"province\":\"广东\"," - + "\"city\":\"广州\"," - + "\"client_platform_type\":\"2\"," - + "\"language\":\"zh_CN\"" - + "}" - + "}"; + "{" + + "\"button\":[" + + "{" + + "\"type\":\"click\"," + + "\"name\":\"今日歌曲\"," + + "\"key\":\"V1001_TODAY_MUSIC\"" + + "}" + + "]," + + "\"matchrule\":{" + + "\"group_id\":\"2\"," + + "\"sex\":\"1\"," + + "\"country\":\"中国\"," + + "\"province\":\"广东\"," + + "\"city\":\"广州\"," + + "\"client_platform_type\":\"2\"," + + "\"language\":\"zh_CN\"" + + "}" + + "}"; return new Object[][]{ - new Object[]{json} + new Object[]{json} }; } diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/session/SessionTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/session/SessionTest.java index e0248c7960..93ad2bfc0c 100644 --- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/session/SessionTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/session/SessionTest.java @@ -1,8 +1,7 @@ package me.chanjar.weixin.common.session; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.testng.*; +import org.testng.annotations.*; @Test public class SessionTest { @@ -11,7 +10,7 @@ public class SessionTest { public Object[][] getSessionManager() { return new Object[][]{ - new Object[]{new StandardSessionManager()} + new Object[]{new StandardSessionManager()} }; } diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/SHA1Test.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/SHA1Test.java new file mode 100644 index 0000000000..323fc7060e --- /dev/null +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/SHA1Test.java @@ -0,0 +1,36 @@ +package me.chanjar.weixin.common.util.crypto; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +/** + *
    + *  Created by BinaryWang on 2017/6/10.
    + * 
    + * + * @author binarywang(Binary Wang) + */ +public class SHA1Test { + @Test + public void testGen() throws Exception { + final String result = SHA1.gen("123", "345"); + assertNotNull(result); + assertEquals(result,"9f537aeb751ec72605f57f94a2f6dc3e3958e1dd"); + } + + @Test(expectedExceptions = {IllegalArgumentException.class}) + public void testGen_illegalArguments() { + final String result = SHA1.gen(null, "", "345"); + assertNotNull(result); + } + + @Test + public void testGenWithAmple() throws Exception { + final String result = SHA1.genWithAmple("123", "345"); + assertNotNull(result); + assertEquals(result,"20b896ccbd5a72dde5dbe0878ff985e4069771c6"); + } + +} diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/WxCryptUtilTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/WxCryptUtilTest.java index 91095a20e9..b13fee5f5f 100755 --- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/WxCryptUtilTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/WxCryptUtilTest.java @@ -1,6 +1,6 @@ package me.chanjar.weixin.common.util.crypto; -import org.testng.annotations.Test; +import org.testng.annotations.*; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -13,8 +13,7 @@ import java.io.IOException; import java.io.StringReader; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; +import static org.testng.Assert.*; @Test public class WxCryptUtilTest { @@ -77,7 +76,7 @@ public void testAesEncrypt2() { } public void testValidateSignatureError() throws ParserConfigurationException, SAXException, - IOException { + IOException { try { WxCryptUtil pc = new WxCryptUtil(this.token, this.encodingAesKey, this.appId); String afterEncrpt = pc.encrypt(this.replyMsg); diff --git a/weixin-java-common/src/test/resources/logback-test.xml b/weixin-java-common/src/test/resources/logback-test.xml index 2c421e49ab..e206e178ec 100644 --- a/weixin-java-common/src/test/resources/logback-test.xml +++ b/weixin-java-common/src/test/resources/logback-test.xml @@ -1,17 +1,13 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %-5level %replace(%caller{1}){'Caller', ''} - %msg%n - + - + diff --git a/weixin-java-common/src/test/resources/testng.xml b/weixin-java-common/src/test/resources/testng.xml index f2222275b2..9eeba0df4c 100644 --- a/weixin-java-common/src/test/resources/testng.xml +++ b/weixin-java-common/src/test/resources/testng.xml @@ -7,8 +7,8 @@ - - + + diff --git a/weixin-java-cp/build.gradle b/weixin-java-cp/build.gradle deleted file mode 100644 index 85d7c4bba2..0000000000 --- a/weixin-java-cp/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ - -description = 'WeiXin Java Tools - CP' -dependencies { - compile project(':weixin-java-common') - testCompile group: 'junit', name: 'junit', version:'4.11' - testCompile group: 'org.testng', name: 'testng', version:'6.8.7' - testCompile group: 'org.mockito', name: 'mockito-all', version:'1.9.5' - testCompile group: 'com.google.inject', name: 'guice', version:'3.0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.RC0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.RC0' -} -test.useTestNG() diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 88f83f0f24..bcc4e73bb3 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -1,12 +1,13 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0"> 4.0.0 com.github.binarywang weixin-java-parent - 2.6.0 + 2.7.0 weixin-java-cp @@ -19,10 +20,25 @@ weixin-java-common ${project.version} + + org.jodd + jodd-http + provided + + + com.squareup.okhttp3 + okhttp + provided + redis.clients jedis + + org.slf4j + slf4j-api + + org.testng testng @@ -48,6 +64,11 @@ jetty-servlet test + + ch.qos.logback + logback-classic + test + diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java new file mode 100644 index 0000000000..7ca1ade3e5 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java @@ -0,0 +1,57 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.bean.WxCpDepart; + +import java.util.List; + +/** + *
    + *  部门管理接口
    + *  Created by BinaryWang on 2017/6/24.
    + * 
    + * + * @author Binary Wang + */ +public interface WxCpDepartmentService { + + /** + *
    +   * 部门管理接口 - 创建部门
    +   * 最多支持创建500个部门
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
    +   * 
    + * + * @param depart 部门 + * @return 部门id + */ + Integer create(WxCpDepart depart) throws WxErrorException; + + /** + *
    +   * 部门管理接口 - 查询所有部门
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
    +   * 
    + */ + List listAll() throws WxErrorException; + + /** + *
    +   * 部门管理接口 - 修改部门名
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
    +   * 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
    +   * 
    + * + * @param group 要更新的group,group的id,name必须设置 + */ + void update(WxCpDepart group) throws WxErrorException; + + /** + *
    +   * 部门管理接口 - 删除部门
    +   * 
    + * + * @param departId 部门id + */ + void delete(Integer departId) throws WxErrorException; +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java new file mode 100644 index 0000000000..f813f1bf3f --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java @@ -0,0 +1,57 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +/** + *
    + *  媒体管理接口
    + *  Created by BinaryWang on 2017/6/24.
    + * 
    + * + * @author Binary Wang + */ +public interface WxCpMediaService { + + /** + *
    +   * 上传多媒体文件
    +   * 上传的多媒体文件有格式和大小限制,如下:
    +   *   图片(image): 1M,支持JPG格式
    +   *   语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
    +   *   视频(video):10MB,支持MP4格式
    +   *   缩略图(thumb):64KB,支持JPG格式
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
    +   * 
    + * + * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} + * @param fileType 文件类型,请看{@link me.chanjar.weixin.common.api.WxConsts} + * @param inputStream 输入流 + */ + WxMediaUploadResult upload(String mediaType, String fileType, InputStream inputStream) + throws WxErrorException, IOException; + + /** + * @param mediaType 媒体类型 + * @param file 文件对象 + * @see #upload(String, String, InputStream) + */ + WxMediaUploadResult upload(String mediaType, File file) throws WxErrorException; + + /** + *
    +   * 下载多媒体文件
    +   * 根据微信文档,视频文件下载不了,会返回null
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
    +   * 
    + * + * @param mediaId 媒体id + * @return 保存到本地的临时文件 + */ + File download(String mediaId) throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java new file mode 100644 index 0000000000..012efefb7f --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java @@ -0,0 +1,91 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.bean.menu.WxMenu; +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + *
    + *  菜单管理相关接口
    + *  Created by BinaryWang on 2017/6/24.
    + * 
    + * + * @author Binary Wang + */ +public interface WxCpMenuService { + /** + *
    +   * 自定义菜单创建接口
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
    +   *
    +   * 注意: 这个方法使用WxCpConfigStorage里的agentId
    +   * 
    + * + * @param menu 菜单对象 + * @see #create(Integer, WxMenu) + */ + void create(WxMenu menu) throws WxErrorException; + + /** + *
    +   * 自定义菜单创建接口
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
    +   *
    +   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
    +   * 
    + * + * @param agentId 企业号应用的id + * @param menu 菜单对象 + * @see #create(me.chanjar.weixin.common.bean.menu.WxMenu) + */ + void create(Integer agentId, WxMenu menu) throws WxErrorException; + + /** + *
    +   * 自定义菜单删除接口
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
    +   *
    +   * 注意: 这个方法使用WxCpConfigStorage里的agentId
    +   * 
    + * + * @see #delete(Integer) + */ + void delete() throws WxErrorException; + + /** + *
    +   * 自定义菜单删除接口
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
    +   *
    +   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
    +   * 
    + * + * @param agentId 企业号应用的id + * @see #delete() + */ + void delete(Integer agentId) throws WxErrorException; + + /** + *
    +   * 自定义菜单查询接口
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
    +   *
    +   * 注意: 这个方法使用WxCpConfigStorage里的agentId
    +   * 
    + * + * @see #get(Integer) + */ + WxMenu get() throws WxErrorException; + + /** + *
    +   * 自定义菜单查询接口
    +   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
    +   *
    +   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
    +   * 
    + * + * @param agentId 企业号应用的id + * @see #get() + */ + WxMenu get(Integer agentId) throws WxErrorException; +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java new file mode 100644 index 0000000000..3312489538 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java @@ -0,0 +1,67 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + *
    + * OAuth2相关管理接口
    + *  Created by BinaryWang on 2017/6/24.
    + * 
    + * + * @author Binary Wang + */ +public interface WxCpOAuth2Service { + /** + *
    +   * 构造oauth2授权的url连接
    +   * 
    + * + * @param state 状态码 + * @return url + */ + String buildAuthorizationUrl(String state); + + /** + *
    +   * 构造oauth2授权的url连接
    +   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=企业获取code
    +   * 
    + * + * @param redirectUri 跳转链接地址 + * @param state 状态码 + * @return url + */ + String buildAuthorizationUrl(String redirectUri, String state); + + /** + *
    +   * 用oauth2获取用户信息
    +   * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息
    +   * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。
    +   *
    +   * 注意: 这个方法使用WxCpConfigStorage里的agentId
    +   * 
    + * + * @param code 微信oauth授权返回的代码 + * @return [userid, deviceid] + * @see #getUserInfo(Integer, String) + */ + String[] getUserInfo(String code) throws WxErrorException; + + /** + *
    +   * 用oauth2获取用户信息
    +   * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息
    +   * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。
    +   *
    +   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
    +   * 
    + * + * @param agentId 企业号应用的id + * @param code 微信oauth授权返回的代码 + * @return [userid, deviceid] + * @see #getUserInfo(String) + */ + String[] getUserInfo(Integer agentId, String code) throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index bd0b322f72..880a92b06e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -6,11 +6,11 @@ import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.WxSession; import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.cp.bean.WxCpDepart; -import me.chanjar.weixin.cp.bean.WxCpMessage; -import me.chanjar.weixin.cp.bean.WxCpTag; -import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.cp.bean.*; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import java.io.File; import java.io.IOException; @@ -35,16 +35,6 @@ public interface WxCpService { */ boolean checkSignature(String msgSignature, String timestamp, String nonce, String data); - /** - *
    -   *   用在二次验证的时候
    -   *   企业在员工验证成功后,调用本方法告诉企业号平台该员工关注成功。
    -   * 
    - * - * @param userId 用户id - */ - void userAuthenticated(String userId) throws WxErrorException; - /** * 获取access_token, 不强制刷新access_token * @@ -96,337 +86,208 @@ public interface WxCpService { WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; /** - *
    -   * 上传多媒体文件
    -   * 上传的多媒体文件有格式和大小限制,如下:
    -   *   图片(image): 1M,支持JPG格式
    -   *   语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
    -   *   视频(video):10MB,支持MP4格式
    -   *   缩略图(thumb):64KB,支持JPG格式
    -   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
    -   * 
    - * - * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} - * @param fileType 文件类型,请看{@link me.chanjar.weixin.common.api.WxConsts} - * @param inputStream 输入流 + * @deprecated 请使用 {@link WxCpMenuService#create(WxMenu)} */ - WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) - throws WxErrorException, IOException; + @Deprecated + void menuCreate(WxMenu menu) throws WxErrorException; /** - * @param mediaType 媒体类型 - * @param file 文件对象 - * @see #mediaUpload(String, String, InputStream) + * @deprecated 请使用 {@link WxCpMenuService#create(Integer, WxMenu)} */ - WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException; - - /** - *
    -   * 下载多媒体文件
    -   * 根据微信文档,视频文件下载不了,会返回null
    -   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
    -   * 
    - * - * @param mediaId 媒体id - * @return 保存到本地的临时文件 - */ - File mediaDownload(String mediaId) throws WxErrorException; + @Deprecated + void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException; /** - *
    -   * 发送消息
    -   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E
    -   * 
    - * - * @param message 要发送的消息对象 + * @deprecated 请使用 {@link WxCpMenuService#delete()} } */ - void messageSend(WxCpMessage message) throws WxErrorException; + @Deprecated + void menuDelete() throws WxErrorException; /** - *
    -   * 自定义菜单创建接口
    -   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
    -   *
    -   * 注意: 这个方法使用WxCpConfigStorage里的agentId
    -   * 
    - * - * @param menu 菜单对象 - * @see #menuCreate(Integer, WxMenu) + * @deprecated 请使用 {@link WxCpMenuService#delete(Integer)} */ - void menuCreate(WxMenu menu) throws WxErrorException; + @Deprecated + void menuDelete(Integer agentId) throws WxErrorException; /** - *
    -   * 自定义菜单创建接口
    -   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
    -   *
    -   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
    -   * 
    - * - * @param agentId 企业号应用的id - * @param menu 菜单对象 - * @see #menuCreate(me.chanjar.weixin.common.bean.menu.WxMenu) + * @deprecated 请使用 {@link WxCpMenuService#get() } */ - void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException; + @Deprecated + WxMenu menuGet() throws WxErrorException; /** - *
    -   * 自定义菜单删除接口
    -   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
    -   *
    -   * 注意: 这个方法使用WxCpConfigStorage里的agentId
    -   * 
    - * - * @see #menuDelete(Integer) + * @deprecated 请使用 {@link WxCpMenuService#get(Integer)} */ - void menuDelete() throws WxErrorException; + @Deprecated + WxMenu menuGet(Integer agentId) throws WxErrorException; /** *
    -   * 自定义菜单删除接口
    -   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
    -   *
    -   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
    +   * 发送消息
    +   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E
        * 
    * - * @param agentId 企业号应用的id - * @see #menuDelete() + * @param message 要发送的消息对象 */ - void menuDelete(Integer agentId) throws WxErrorException; + WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorException; /** - *
    -   * 自定义菜单查询接口
    -   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
    -   *
    -   * 注意: 这个方法使用WxCpConfigStorage里的agentId
    -   * 
    - * - * @see #menuGet(Integer) + * @deprecated 请使用 {@link WxCpDepartmentService#create(WxCpDepart)} */ - WxMenu menuGet() throws WxErrorException; + @Deprecated + Integer departCreate(WxCpDepart depart) throws WxErrorException; /** - *
    -   * 自定义菜单查询接口
    -   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
    -   *
    -   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
    -   * 
    - * - * @param agentId 企业号应用的id - * @see #menuGet() + * @deprecated 请使用 {@link WxCpDepartmentService#update(WxCpDepart)} */ - WxMenu menuGet(Integer agentId) throws WxErrorException; + @Deprecated + void departUpdate(WxCpDepart group) throws WxErrorException; /** - *
    -   * 部门管理接口 - 创建部门
    -   * 最多支持创建500个部门
    -   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
    -   * 
    - * - * @param depart 部门 - * @return 部门id + * @deprecated 请使用 {@link WxCpDepartmentService#delete(Integer)} */ - Integer departCreate(WxCpDepart depart) throws WxErrorException; + @Deprecated + void departDelete(Integer departId) throws WxErrorException; /** - *
    -   * 部门管理接口 - 查询所有部门
    -   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
    -   * 
    + * @deprecated 请使用 {@link WxCpDepartmentService#listAll() } */ + @Deprecated List departGet() throws WxErrorException; /** - *
    -   * 部门管理接口 - 修改部门名
    -   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
    -   * 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
    -   * 
    - * - * @param group 要更新的group,group的id,name必须设置 + * @deprecated 请使用 {@link WxCpMediaService#upload(String, String, InputStream)} */ - void departUpdate(WxCpDepart group) throws WxErrorException; + @Deprecated + WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) + throws WxErrorException, IOException; /** - *
    -   * 部门管理接口 - 删除部门
    -   * 
    - * - * @param departId 部门id + * @deprecated 请使用 {@link WxCpMediaService#upload(String, File)} */ - void departDelete(Integer departId) throws WxErrorException; + @Deprecated + WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException; /** - *
    -   * 获取部门成员(详情)
    -   *
    -   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98.28.E8.AF.A6.E6.83.85.29
    -   * 
    - * - * @param departId 必填。部门id - * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 - * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 + * @deprecated 请使用 {@link WxCpMediaService#download(String)} */ - List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + @Deprecated + File mediaDownload(String mediaId) throws WxErrorException; /** - *
    -   * 获取部门成员
    -   *
    -   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98
    -   * 
    - * - * @param departId 必填。部门id - * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 - * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 + * @deprecated 请使用 {@link WxCpUserService#authenticate(String)} */ - List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + @Deprecated + void userAuthenticated(String userId) throws WxErrorException; /** - * 新建用户 - * - * @param user 用户对象 + * @deprecated 请使用 {@link WxCpUserService#create(WxCpUser)} */ + @Deprecated void userCreate(WxCpUser user) throws WxErrorException; /** - * 更新用户 - * - * @param user 用户对象 + * @deprecated 请使用 {@link WxCpUserService#update(WxCpUser)} */ + @Deprecated void userUpdate(WxCpUser user) throws WxErrorException; /** - * 删除用户 - * - * @param userid 用户id + * @deprecated 请使用 {@link WxCpUserService#delete(String...)} */ + @Deprecated void userDelete(String userid) throws WxErrorException; /** - *
    -   * 批量删除成员
    -   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E6.89.B9.E9.87.8F.E5.88.A0.E9.99.A4.E6.88.90.E5.91.98
    -   * 
    - * - * @param userids 员工UserID列表。对应管理端的帐号 + * @deprecated 请使用 {@link WxCpUserService#delete(String...)} */ + @Deprecated void userDelete(String[] userids) throws WxErrorException; /** - * 获取用户 - * - * @param userid 用户id + * @deprecated 请使用 {@link WxCpUserService#getById(String)} */ + @Deprecated WxCpUser userGet(String userid) throws WxErrorException; /** - * 创建标签 - * - * @param tagName 标签名 + * @deprecated 请使用 {@link WxCpUserService#listByDepartment(Integer, Boolean, Integer)} */ + @Deprecated + List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + + /** + * @deprecated 请使用 {@link WxCpUserService#listSimpleByDepartment(Integer, Boolean, Integer)} + */ + @Deprecated + List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + + /** + * @deprecated 请使用 {@link WxCpTagService#create(String)} + */ + @Deprecated String tagCreate(String tagName) throws WxErrorException; /** - * 更新标签 - * - * @param tagId 标签id - * @param tagName 标签名 + * @deprecated 请使用 {@link WxCpTagService#update(String, String)} */ + @Deprecated void tagUpdate(String tagId, String tagName) throws WxErrorException; /** - * 删除标签 - * - * @param tagId 标签id + * @deprecated 请使用 {@link WxCpTagService#delete(String)} */ + @Deprecated void tagDelete(String tagId) throws WxErrorException; /** - * 获得标签列表 + * @deprecated 请使用 {@link WxCpTagService#listAll()} */ + @Deprecated List tagGet() throws WxErrorException; /** - * 获取标签成员 - * - * @param tagId 标签ID + * @deprecated 请使用 {@link WxCpTagService#listUsersByTagId(String)} */ + @Deprecated List tagGetUsers(String tagId) throws WxErrorException; /** - * 增加标签成员 - * - * @param tagId 标签id - * @param userIds 用户ID 列表 + * @deprecated 请使用 {@link WxCpTagService#addUsers2Tag(String, List, List)} */ + @Deprecated void tagAddUsers(String tagId, List userIds, List partyIds) throws WxErrorException; /** - *
    -   * 构造oauth2授权的url连接
    -   * 
    - * - * @param state 状态码 - * @return url + * @deprecated 请使用 {@link WxCpTagService#removeUsersFromTag(String, List)} */ + @Deprecated + void tagRemoveUsers(String tagId, List userIds) throws WxErrorException; + + /** + * @deprecated 请使用 {@link WxCpOAuth2Service#buildAuthorizationUrl(String)} + */ + @Deprecated String oauth2buildAuthorizationUrl(String state); /** - *
    -   * 构造oauth2授权的url连接
    -   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=企业获取code
    -   * 
    - * - * @param redirectUri 跳转链接地址 - * @param state 状态码 - * @return url + * @deprecated 请使用 {@link WxCpOAuth2Service#buildAuthorizationUrl(String, String)} */ + @Deprecated String oauth2buildAuthorizationUrl(String redirectUri, String state); /** - *
    -   * 用oauth2获取用户信息
    -   * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息
    -   * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。
    -   *
    -   * 注意: 这个方法使用WxCpConfigStorage里的agentId
    -   * 
    - * - * @param code 微信oauth授权返回的代码 - * @return [userid, deviceid] - * @see #oauth2getUserInfo(Integer, String) + * @deprecated 请使用 {@link WxCpOAuth2Service#getUserInfo(String)} */ + @Deprecated String[] oauth2getUserInfo(String code) throws WxErrorException; /** - *
    -   * 用oauth2获取用户信息
    -   * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息
    -   * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。
    -   *
    -   * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
    -   * 
    - * - * @param agentId 企业号应用的id - * @param code 微信oauth授权返回的代码 - * @return [userid, deviceid] - * @see #oauth2getUserInfo(String) + * @deprecated 请使用 {@link WxCpOAuth2Service#getUserInfo(Integer, String)} */ + @Deprecated String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException; - - /** - * 移除标签成员 - * - * @param tagId 标签id - * @param userIds 用户id列表 - */ - void tagRemoveUsers(String tagId, List userIds) throws WxErrorException; - /** *
        * 邀请成员关注
    @@ -469,7 +330,7 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i
        * 
        * Service没有实现某个API的时候,可以用这个,
        * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
    -   * 可以参考,{@link me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor}的实现方法
    +   * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
        * 
    * * @param executor 执行器 @@ -480,13 +341,6 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i */ T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; - /** - * 注入 {@link WxCpConfigStorage} 的实现 - * - * @param wxConfigProvider 配置对象 - */ - void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider); - /** *
        * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试
    @@ -550,4 +404,58 @@ WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream i
        * 获取异步任务结果
        */
       String getTaskResult(String joinId) throws WxErrorException;
    +
    +  /**
    +   * 初始化http请求对象
    +   */
    +  void initHttp();
    +
    +  /**
    +   * 获取WxMpConfigStorage 对象
    +   *
    +   * @return WxMpConfigStorage
    +   */
    +  WxCpConfigStorage getWxCpConfigStorage();
    +
    +  /**
    +   * 注入 {@link WxCpConfigStorage} 的实现
    +   *
    +   * @param wxConfigProvider 配置对象
    +   */
    +  void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider);
    +
    +  /**
    +   * 获取部门相关接口的服务类对象
    +   */
    +  WxCpDepartmentService getDepartmentService();
    +
    +  /**
    +   * 获取媒体相关接口的服务类对象
    +   */
    +  WxCpMediaService getMediaService();
    +
    +  /**
    +   * 获取菜单相关接口的服务类对象
    +   */
    +  WxCpMenuService getMenuService();
    +
    +  /**
    +   * 获取Oauth2相关接口的服务类对象
    +   */
    +  WxCpOAuth2Service getOauth2Service();
    +
    +  /**
    +   * 获取标签相关接口的服务类对象
    +   */
    +  WxCpTagService getTagService();
    +
    +  /**
    +   * 获取用户相关接口的服务类对象
    +   */
    +  WxCpUserService getUserService();
    +
    +  /**
    +   * http请求对象
    +   */
    +  RequestHttp getRequestHttp();
     }
    diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
    deleted file mode 100644
    index 0105e78d52..0000000000
    --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
    +++ /dev/null
    @@ -1,697 +0,0 @@
    -package me.chanjar.weixin.cp.api;
    -
    -import com.google.gson.*;
    -import com.google.gson.reflect.TypeToken;
    -import me.chanjar.weixin.common.bean.WxAccessToken;
    -import me.chanjar.weixin.common.bean.WxJsapiSignature;
    -import me.chanjar.weixin.common.bean.menu.WxMenu;
    -import me.chanjar.weixin.common.bean.result.WxError;
    -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
    -import me.chanjar.weixin.common.exception.WxErrorException;
    -import me.chanjar.weixin.common.session.StandardSessionManager;
    -import me.chanjar.weixin.common.session.WxSession;
    -import me.chanjar.weixin.common.session.WxSessionManager;
    -import me.chanjar.weixin.common.util.RandomUtils;
    -import me.chanjar.weixin.common.util.crypto.SHA1;
    -import me.chanjar.weixin.common.util.fs.FileUtils;
    -import me.chanjar.weixin.common.util.http.*;
    -import me.chanjar.weixin.common.util.json.GsonHelper;
    -import me.chanjar.weixin.cp.bean.WxCpDepart;
    -import me.chanjar.weixin.cp.bean.WxCpMessage;
    -import me.chanjar.weixin.cp.bean.WxCpTag;
    -import me.chanjar.weixin.cp.bean.WxCpUser;
    -import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
    -import org.apache.commons.lang3.StringUtils;
    -import org.apache.http.HttpHost;
    -import org.apache.http.client.config.RequestConfig;
    -import org.apache.http.client.methods.CloseableHttpResponse;
    -import org.apache.http.client.methods.HttpGet;
    -import org.apache.http.impl.client.BasicResponseHandler;
    -import org.apache.http.impl.client.CloseableHttpClient;
    -import org.slf4j.Logger;
    -import org.slf4j.LoggerFactory;
    -
    -import java.io.File;
    -import java.io.IOException;
    -import java.io.InputStream;
    -import java.util.List;
    -import java.util.UUID;
    -
    -public class WxCpServiceImpl implements WxCpService {
    -
    -  protected final Logger log = LoggerFactory.getLogger(WxCpServiceImpl.class);
    -
    -  /**
    -   * 全局的是否正在刷新access token的锁
    -   */
    -  protected final Object globalAccessTokenRefreshLock = new Object();
    -
    -  /**
    -   * 全局的是否正在刷新jsapi_ticket的锁
    -   */
    -  protected final Object globalJsapiTicketRefreshLock = new Object();
    -
    -  protected WxCpConfigStorage configStorage;
    -
    -  protected CloseableHttpClient httpClient;
    -
    -  protected HttpHost httpProxy;
    -  protected WxSessionManager sessionManager = new StandardSessionManager();
    -  /**
    -   * 临时文件目录
    -   */
    -  protected File tmpDirFile;
    -  private int retrySleepMillis = 1000;
    -  private int maxRetryTimes = 5;
    -
    -  @Override
    -  public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) {
    -    try {
    -      return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data)
    -        .equals(msgSignature);
    -    } catch (Exception e) {
    -      return false;
    -    }
    -  }
    -
    -  @Override
    -  public void userAuthenticated(String userId) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId;
    -    get(url, null);
    -  }
    -
    -  @Override
    -  public String getAccessToken() throws WxErrorException {
    -    return getAccessToken(false);
    -  }
    -
    -  @Override
    -  public String getAccessToken(boolean forceRefresh) throws WxErrorException {
    -    if (forceRefresh) {
    -      this.configStorage.expireAccessToken();
    -    }
    -    if (this.configStorage.isAccessTokenExpired()) {
    -      synchronized (this.globalAccessTokenRefreshLock) {
    -        if (this.configStorage.isAccessTokenExpired()) {
    -          String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
    -            + "&corpid=" + this.configStorage.getCorpId()
    -            + "&corpsecret=" + this.configStorage.getCorpSecret();
    -          try {
    -            HttpGet httpGet = new HttpGet(url);
    -            if (this.httpProxy != null) {
    -              RequestConfig config = RequestConfig.custom()
    -                .setProxy(this.httpProxy).build();
    -              httpGet.setConfig(config);
    -            }
    -            String resultContent = null;
    -            try (CloseableHttpClient httpclient = getHttpclient();
    -                 CloseableHttpResponse response = httpclient.execute(httpGet)) {
    -              resultContent = new BasicResponseHandler().handleResponse(response);
    -            } finally {
    -              httpGet.releaseConnection();
    -            }
    -            WxError error = WxError.fromJson(resultContent);
    -            if (error.getErrorCode() != 0) {
    -              throw new WxErrorException(error);
    -            }
    -            WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
    -            this.configStorage.updateAccessToken(
    -              accessToken.getAccessToken(), accessToken.getExpiresIn());
    -          } catch (IOException e) {
    -            throw new RuntimeException(e);
    -          }
    -        }
    -      }
    -    }
    -    return this.configStorage.getAccessToken();
    -  }
    -
    -  @Override
    -  public String getJsapiTicket() throws WxErrorException {
    -    return getJsapiTicket(false);
    -  }
    -
    -  @Override
    -  public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
    -    if (forceRefresh) {
    -      this.configStorage.expireJsapiTicket();
    -    }
    -    if (this.configStorage.isJsapiTicketExpired()) {
    -      synchronized (this.globalJsapiTicketRefreshLock) {
    -        if (this.configStorage.isJsapiTicketExpired()) {
    -          String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket";
    -          String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
    -          JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
    -          JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
    -          String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
    -          int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
    -          this.configStorage.updateJsapiTicket(jsapiTicket,
    -            expiresInSeconds);
    -        }
    -      }
    -    }
    -    return this.configStorage.getJsapiTicket();
    -  }
    -
    -  @Override
    -  public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException {
    -    long timestamp = System.currentTimeMillis() / 1000;
    -    String noncestr = RandomUtils.getRandomStr();
    -    String jsapiTicket = getJsapiTicket(false);
    -    String signature = SHA1.genWithAmple(
    -      "jsapi_ticket=" + jsapiTicket,
    -      "noncestr=" + noncestr,
    -      "timestamp=" + timestamp,
    -      "url=" + url
    -    );
    -    WxJsapiSignature jsapiSignature = new WxJsapiSignature();
    -    jsapiSignature.setTimestamp(timestamp);
    -    jsapiSignature.setNonceStr(noncestr);
    -    jsapiSignature.setUrl(url);
    -    jsapiSignature.setSignature(signature);
    -
    -    // Fixed bug
    -    jsapiSignature.setAppId(this.configStorage.getCorpId());
    -
    -    return jsapiSignature;
    -  }
    -
    -  @Override
    -  public void messageSend(WxCpMessage message) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send";
    -    post(url, message.toJson());
    -  }
    -
    -  @Override
    -  public void menuCreate(WxMenu menu) throws WxErrorException {
    -    menuCreate(this.configStorage.getAgentId(), menu);
    -  }
    -
    -  @Override
    -  public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid="
    -      + this.configStorage.getAgentId();
    -    post(url, menu.toJson());
    -  }
    -
    -  @Override
    -  public void menuDelete() throws WxErrorException {
    -    menuDelete(this.configStorage.getAgentId());
    -  }
    -
    -  @Override
    -  public void menuDelete(Integer agentId) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId;
    -    get(url, null);
    -  }
    -
    -  @Override
    -  public WxMenu menuGet() throws WxErrorException {
    -    return menuGet(this.configStorage.getAgentId());
    -  }
    -
    -  @Override
    -  public WxMenu menuGet(Integer agentId) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId;
    -    try {
    -      String resultContent = get(url, null);
    -      return WxMenu.fromJson(resultContent);
    -    } catch (WxErrorException e) {
    -      // 46003 不存在的菜单数据
    -      if (e.getError().getErrorCode() == 46003) {
    -        return null;
    -      }
    -      throw e;
    -    }
    -  }
    -
    -  @Override
    -  public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream)
    -    throws WxErrorException, IOException {
    -    return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType));
    -  }
    -
    -  @Override
    -  public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType;
    -    return execute(new MediaUploadRequestExecutor(), url, file);
    -  }
    -
    -  @Override
    -  public File mediaDownload(String mediaId) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get";
    -    return execute(
    -      new MediaDownloadRequestExecutor(
    -        this.configStorage.getTmpDirFile()),
    -      url, "media_id=" + mediaId);
    -  }
    -
    -
    -  @Override
    -  public Integer departCreate(WxCpDepart depart) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create";
    -    String responseContent = execute(
    -      new SimplePostRequestExecutor(),
    -      url,
    -      depart.toJson());
    -    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
    -    return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id"));
    -  }
    -
    -  @Override
    -  public void departUpdate(WxCpDepart group) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update";
    -    post(url, group.toJson());
    -  }
    -
    -  @Override
    -  public void departDelete(Integer departId) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId;
    -    get(url, null);
    -  }
    -
    -  @Override
    -  public List departGet() throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list";
    -    String responseContent = get(url, null);
    -    /*
    -     * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} }
    -     * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] }
    -     */
    -    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
    -    return WxCpGsonBuilder.INSTANCE.create()
    -      .fromJson(
    -        tmpJsonElement.getAsJsonObject().get("department"),
    -        new TypeToken>() {
    -        }.getType()
    -      );
    -  }
    -
    -  @Override
    -  public void userCreate(WxCpUser user) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create";
    -    post(url, user.toJson());
    -  }
    -
    -  @Override
    -  public void userUpdate(WxCpUser user) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update";
    -    post(url, user.toJson());
    -  }
    -
    -  @Override
    -  public void userDelete(String userid) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userid;
    -    get(url, null);
    -  }
    -
    -  @Override
    -  public void userDelete(String[] userids) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete";
    -    JsonObject jsonObject = new JsonObject();
    -    JsonArray jsonArray = new JsonArray();
    -    for (String userid : userids) {
    -      jsonArray.add(new JsonPrimitive(userid));
    -    }
    -    jsonObject.add("useridlist", jsonArray);
    -    post(url, jsonObject.toString());
    -  }
    -
    -  @Override
    -  public WxCpUser userGet(String userid) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid;
    -    String responseContent = get(url, null);
    -    return WxCpUser.fromJson(responseContent);
    -  }
    -
    -  @Override
    -  public List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId;
    -    String params = "";
    -    if (fetchChild != null) {
    -      params += "&fetch_child=" + (fetchChild ? "1" : "0");
    -    }
    -    if (status != null) {
    -      params += "&status=" + status;
    -    } else {
    -      params += "&status=0";
    -    }
    -
    -    String responseContent = get(url, params);
    -    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
    -    return WxCpGsonBuilder.INSTANCE.create()
    -      .fromJson(
    -        tmpJsonElement.getAsJsonObject().get("userlist"),
    -        new TypeToken>() {
    -        }.getType()
    -      );
    -  }
    -
    -  @Override
    -  public List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId;
    -    String params = "";
    -    if (fetchChild != null) {
    -      params += "&fetch_child=" + (fetchChild ? "1" : "0");
    -    }
    -    if (status != null) {
    -      params += "&status=" + status;
    -    } else {
    -      params += "&status=0";
    -    }
    -
    -    String responseContent = get(url, params);
    -    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
    -    return WxCpGsonBuilder.INSTANCE.create()
    -      .fromJson(
    -        tmpJsonElement.getAsJsonObject().get("userlist"),
    -        new TypeToken>() {
    -        }.getType()
    -      );
    -  }
    -
    -  @Override
    -  public String tagCreate(String tagName) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create";
    -    JsonObject o = new JsonObject();
    -    o.addProperty("tagname", tagName);
    -    String responseContent = post(url, o.toString());
    -    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
    -    return tmpJsonElement.getAsJsonObject().get("tagid").getAsString();
    -  }
    -
    -  @Override
    -  public void tagUpdate(String tagId, String tagName) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update";
    -    JsonObject o = new JsonObject();
    -    o.addProperty("tagid", tagId);
    -    o.addProperty("tagname", tagName);
    -    post(url, o.toString());
    -  }
    -
    -  @Override
    -  public void tagDelete(String tagId) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId;
    -    get(url, null);
    -  }
    -
    -  @Override
    -  public List tagGet() throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list";
    -    String responseContent = get(url, null);
    -    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
    -    return WxCpGsonBuilder.INSTANCE.create()
    -      .fromJson(
    -        tmpJsonElement.getAsJsonObject().get("taglist"),
    -        new TypeToken>() {
    -        }.getType()
    -      );
    -  }
    -
    -  @Override
    -  public List tagGetUsers(String tagId) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId;
    -    String responseContent = get(url, null);
    -    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
    -    return WxCpGsonBuilder.INSTANCE.create()
    -      .fromJson(
    -        tmpJsonElement.getAsJsonObject().get("userlist"),
    -        new TypeToken>() {
    -        }.getType()
    -      );
    -  }
    -
    -  @Override
    -  public void tagAddUsers(String tagId, List userIds, List partyIds) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers";
    -    JsonObject jsonObject = new JsonObject();
    -    jsonObject.addProperty("tagid", tagId);
    -    if (userIds != null) {
    -      JsonArray jsonArray = new JsonArray();
    -      for (String userId : userIds) {
    -        jsonArray.add(new JsonPrimitive(userId));
    -      }
    -      jsonObject.add("userlist", jsonArray);
    -    }
    -    if (partyIds != null) {
    -      JsonArray jsonArray = new JsonArray();
    -      for (String userId : partyIds) {
    -        jsonArray.add(new JsonPrimitive(userId));
    -      }
    -      jsonObject.add("partylist", jsonArray);
    -    }
    -    post(url, jsonObject.toString());
    -  }
    -
    -  @Override
    -  public void tagRemoveUsers(String tagId, List userIds) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers";
    -    JsonObject jsonObject = new JsonObject();
    -    jsonObject.addProperty("tagid", tagId);
    -    JsonArray jsonArray = new JsonArray();
    -    for (String userId : userIds) {
    -      jsonArray.add(new JsonPrimitive(userId));
    -    }
    -    jsonObject.add("userlist", jsonArray);
    -    post(url, jsonObject.toString());
    -  }
    -
    -  @Override
    -  public String oauth2buildAuthorizationUrl(String state) {
    -    return this.oauth2buildAuthorizationUrl(
    -      this.configStorage.getOauth2redirectUri(),
    -      state
    -    );
    -  }
    -
    -  @Override
    -  public String oauth2buildAuthorizationUrl(String redirectUri, String state) {
    -    String url = "https://open.weixin.qq.com/connect/oauth2/authorize?";
    -    url += "appid=" + this.configStorage.getCorpId();
    -    url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri);
    -    url += "&response_type=code";
    -    url += "&scope=snsapi_base";
    -    if (state != null) {
    -      url += "&state=" + state;
    -    }
    -    url += "#wechat_redirect";
    -    return url;
    -  }
    -
    -  @Override
    -  public String[] oauth2getUserInfo(String code) throws WxErrorException {
    -    return oauth2getUserInfo(this.configStorage.getAgentId(), code);
    -  }
    -
    -  @Override
    -  public String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?"
    -      + "code=" + code
    -      + "&agentid=" + agentId;
    -    String responseText = get(url, null);
    -    JsonElement je = new JsonParser().parse(responseText);
    -    JsonObject jo = je.getAsJsonObject();
    -    return new String[]{GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId"), GsonHelper.getString(jo, "OpenId")};
    -  }
    -
    -  @Override
    -  public int invite(String userId, String inviteTips) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/invite/send";
    -    JsonObject jsonObject = new JsonObject();
    -    jsonObject.addProperty("userid", userId);
    -    if (StringUtils.isNotEmpty(inviteTips)) {
    -      jsonObject.addProperty("invite_tips", inviteTips);
    -    }
    -    String responseContent = post(url, jsonObject.toString());
    -    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
    -    return tmpJsonElement.getAsJsonObject().get("type").getAsInt();
    -  }
    -
    -  @Override
    -  public String[] getCallbackIp() throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip";
    -    String responseContent = get(url, null);
    -    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
    -    JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray();
    -    String[] ips = new String[jsonArray.size()];
    -    for (int i = 0; i < jsonArray.size(); i++) {
    -      ips[i] = jsonArray.get(i).getAsString();
    -    }
    -    return ips;
    -  }
    -
    -  @Override
    -  public String get(String url, String queryParam) throws WxErrorException {
    -    return execute(new SimpleGetRequestExecutor(), url, queryParam);
    -  }
    -
    -  @Override
    -  public String post(String url, String postData) throws WxErrorException {
    -    return execute(new SimplePostRequestExecutor(), url, postData);
    -  }
    -
    -  /**
    -   * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求
    -   */
    -  @Override
    -  public  T execute(RequestExecutor executor, String uri, E data) throws WxErrorException {
    -    int retryTimes = 0;
    -    do {
    -      try {
    -        T result = this.executeInternal(executor, uri, data);
    -        this.log.debug("\n[URL]:  {}\n[PARAMS]: {}\n[RESPONSE]: {}",uri, data, result);
    -        return result;
    -      } catch (WxErrorException e) {
    -        if (retryTimes + 1 > this.maxRetryTimes) {
    -          this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
    -          //最后一次重试失败后,直接抛出异常,不再等待
    -          throw new RuntimeException("微信服务端异常,超出重试次数");
    -        }
    -
    -        WxError error = e.getError();
    -        /*
    -         * -1 系统繁忙, 1000ms后重试
    -         */
    -        if (error.getErrorCode() == -1) {
    -          int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
    -          try {
    -            this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
    -            Thread.sleep(sleepMillis);
    -          } catch (InterruptedException e1) {
    -            throw new RuntimeException(e1);
    -          }
    -        } else {
    -          throw e;
    -        }
    -      }
    -    } while (retryTimes++ < this.maxRetryTimes);
    -
    -    this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
    -    throw new RuntimeException("微信服务端异常,超出重试次数");
    -  }
    -
    -  protected synchronized  T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
    -    if (uri.contains("access_token=")) {
    -      throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri);
    -    }
    -    String accessToken = getAccessToken(false);
    -
    -    String uriWithAccessToken = uri;
    -    uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken;
    -
    -    try {
    -      return executor.execute(getHttpclient(), this.httpProxy, uriWithAccessToken, data);
    -    } catch (WxErrorException e) {
    -      WxError error = e.getError();
    -      /*
    -       * 发生以下情况时尝试刷新access_token
    -       * 40001 获取access_token时AppSecret错误,或者access_token无效
    -       * 42001 access_token超时
    -       */
    -      if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) {
    -        // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token
    -        this.configStorage.expireAccessToken();
    -        return execute(executor, uri, data);
    -      }
    -
    -      if (error.getErrorCode() != 0) {
    -        this.log.error("\n[URL]:  {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error);
    -        throw new WxErrorException(error);
    -      }
    -      return null;
    -    } catch (IOException e) {
    -      this.log.error("\n[URL]:  {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage());
    -      throw new RuntimeException(e);
    -    }
    -  }
    -
    -  protected CloseableHttpClient getHttpclient() {
    -    return this.httpClient;
    -  }
    -
    -  @Override
    -  public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) {
    -    this.configStorage = wxConfigProvider;
    -    ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage
    -      .getApacheHttpClientBuilder();
    -    if (null == apacheHttpClientBuilder) {
    -      apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get();
    -    }
    -
    -    apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost())
    -      .httpProxyPort(this.configStorage.getHttpProxyPort())
    -      .httpProxyUsername(this.configStorage.getHttpProxyUsername())
    -      .httpProxyPassword(this.configStorage.getHttpProxyPassword());
    -
    -    if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
    -      this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort());
    -    }
    -
    -    this.httpClient = apacheHttpClientBuilder.build();
    -  }
    -
    -  @Override
    -  public void setRetrySleepMillis(int retrySleepMillis) {
    -    this.retrySleepMillis = retrySleepMillis;
    -  }
    -
    -
    -  @Override
    -  public void setMaxRetryTimes(int maxRetryTimes) {
    -    this.maxRetryTimes = maxRetryTimes;
    -  }
    -
    -  @Override
    -  public WxSession getSession(String id) {
    -    if (this.sessionManager == null) {
    -      return null;
    -    }
    -    return this.sessionManager.getSession(id);
    -  }
    -
    -  @Override
    -  public WxSession getSession(String id, boolean create) {
    -    if (this.sessionManager == null) {
    -      return null;
    -    }
    -    return this.sessionManager.getSession(id, create);
    -  }
    -
    -
    -  @Override
    -  public void setSessionManager(WxSessionManager sessionManager) {
    -    this.sessionManager = sessionManager;
    -  }
    -
    -  @Override
    -  public String replaceParty(String mediaId) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty";
    -    JsonObject jsonObject = new JsonObject();
    -    jsonObject.addProperty("media_id", mediaId);
    -    return post(url, jsonObject.toString());
    -  }
    -
    -  @Override
    -  public String replaceUser(String mediaId) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser";
    -    JsonObject jsonObject = new JsonObject();
    -    jsonObject.addProperty("media_id", mediaId);
    -    return post(url, jsonObject.toString());
    -  }
    -
    -  @Override
    -  public String getTaskResult(String joinId) throws WxErrorException {
    -    String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?jobid=" + joinId;
    -    return get(url, null);
    -  }
    -
    -  public File getTmpDirFile() {
    -    return this.tmpDirFile;
    -  }
    -
    -  public void setTmpDirFile(File tmpDirFile) {
    -    this.tmpDirFile = tmpDirFile;
    -  }
    -
    -
    -}
    diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
    new file mode 100644
    index 0000000000..c96318b80b
    --- /dev/null
    +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
    @@ -0,0 +1,66 @@
    +package me.chanjar.weixin.cp.api;
    +
    +import me.chanjar.weixin.common.exception.WxErrorException;
    +import me.chanjar.weixin.cp.bean.WxCpTag;
    +import me.chanjar.weixin.cp.bean.WxCpTagAddOrRemoveUsersResult;
    +import me.chanjar.weixin.cp.bean.WxCpUser;
    +
    +import java.util.List;
    +
    +/**
    + * 
    + *  标签管理接口
    + *  Created by BinaryWang on 2017/6/24.
    + * 
    + * + * @author Binary Wang + */ +public interface WxCpTagService { + /** + * 创建标签 + * + * @param tagName 标签名 + */ + String create(String tagName) throws WxErrorException; + + /** + * 更新标签 + * + * @param tagId 标签id + * @param tagName 标签名 + */ + void update(String tagId, String tagName) throws WxErrorException; + + /** + * 删除标签 + * + * @param tagId 标签id + */ + void delete(String tagId) throws WxErrorException; + + /** + * 获得标签列表 + */ + List listAll() throws WxErrorException; + + /** + * 获取标签成员 + * + * @param tagId 标签ID + */ + List listUsersByTagId(String tagId) throws WxErrorException; + + /** + * 增加标签成员 + * @param tagId 标签id + * @param userIds 用户ID 列表 + */ + WxCpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List userIds, List partyIds) throws WxErrorException; + + /** + * 移除标签成员 + * @param tagId 标签id + * @param userIds 用户id列表 + */ + WxCpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds) throws WxErrorException; +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java new file mode 100644 index 0000000000..49ef9134f5 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java @@ -0,0 +1,83 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.bean.WxCpUser; + +import java.util.List; + +/** + *
    + * 用户管理接口
    + *  Created by BinaryWang on 2017/6/24.
    + * 
    + * + * @author Binary Wang + */ +public interface WxCpUserService { + /** + *
    +   *   用在二次验证的时候
    +   *   企业在员工验证成功后,调用本方法告诉企业号平台该员工关注成功。
    +   * 
    + * + * @param userId 用户id + */ + void authenticate(String userId) throws WxErrorException; + + /** + *
    +   * 获取部门成员(详情)
    +   *
    +   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98.28.E8.AF.A6.E6.83.85.29
    +   * 
    + * + * @param departId 必填。部门id + * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 + * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 + */ + List listByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + + /** + *
    +   * 获取部门成员
    +   *
    +   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98
    +   * 
    + * + * @param departId 必填。部门id + * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 + * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 + */ + List listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + + /** + * 新建用户 + * + * @param user 用户对象 + */ + void create(WxCpUser user) throws WxErrorException; + + /** + * 更新用户 + * + * @param user 用户对象 + */ + void update(WxCpUser user) throws WxErrorException; + + /** + *
    +   * 删除用户/批量删除成员
    +   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E6.89.B9.E9.87.8F.E5.88.A0.E9.99.A4.E6.88.90.E5.91.98
    +   * 
    + * + * @param userIds 员工UserID列表。对应管理端的帐号 + */ + void delete(String... userIds) throws WxErrorException; + + /** + * 获取用户 + * + * @param userid 用户id + */ + WxCpUser getById(String userid) throws WxErrorException; +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java new file mode 100644 index 0000000000..6cff26485e --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/AbstractWxCpServiceImpl.java @@ -0,0 +1,543 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.menu.WxMenu; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.StandardSessionManager; +import me.chanjar.weixin.common.session.WxSession; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.RandomUtils; +import me.chanjar.weixin.common.util.crypto.SHA1; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import me.chanjar.weixin.cp.api.*; +import me.chanjar.weixin.cp.bean.*; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +public abstract class AbstractWxCpServiceImpl implements WxCpService, RequestHttp { + protected final Logger log = LoggerFactory.getLogger(this.getClass()); + + private WxCpUserService userService = new WxCpUserServiceImpl(this); + private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this); + private WxCpMediaService mediaService = new WxCpMediaServiceImpl(this); + private WxCpMenuService menuService = new WxCpMenuServiceImpl(this); + private WxCpOAuth2Service oauth2Service = new WxCpOAuth2ServiceImpl(this); + private WxCpTagService tagService = new WxCpTagServiceImpl(this); + + /** + * 全局的是否正在刷新access token的锁 + */ + protected final Object globalAccessTokenRefreshLock = new Object(); + + /** + * 全局的是否正在刷新jsapi_ticket的锁 + */ + protected final Object globalJsapiTicketRefreshLock = new Object(); + + protected WxCpConfigStorage configStorage; + + + protected WxSessionManager sessionManager = new StandardSessionManager(); + /** + * 临时文件目录 + */ + protected File tmpDirFile; + private int retrySleepMillis = 1000; + private int maxRetryTimes = 5; + + @Override + public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) { + try { + return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data) + .equals(msgSignature); + } catch (Exception e) { + this.log.error("Checking signature failed, and the reason is :" + e.getMessage()); + return false; + } + } + + @Override + public String getAccessToken() throws WxErrorException { + return getAccessToken(false); + } + + + @Override + public String getJsapiTicket() throws WxErrorException { + return getJsapiTicket(false); + } + + @Override + public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { + if (forceRefresh) { + this.configStorage.expireJsapiTicket(); + } + if (this.configStorage.isJsapiTicketExpired()) { + synchronized (this.globalJsapiTicketRefreshLock) { + if (this.configStorage.isJsapiTicketExpired()) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket"; + String responseContent = execute(SimpleGetRequestExecutor.create(this), url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + this.configStorage.updateJsapiTicket(jsapiTicket, + expiresInSeconds); + } + } + } + return this.configStorage.getJsapiTicket(); + } + + @Override + public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { + long timestamp = System.currentTimeMillis() / 1000; + String noncestr = RandomUtils.getRandomStr(); + String jsapiTicket = getJsapiTicket(false); + String signature = SHA1.genWithAmple( + "jsapi_ticket=" + jsapiTicket, + "noncestr=" + noncestr, + "timestamp=" + timestamp, + "url=" + url + ); + WxJsapiSignature jsapiSignature = new WxJsapiSignature(); + jsapiSignature.setTimestamp(timestamp); + jsapiSignature.setNonceStr(noncestr); + jsapiSignature.setUrl(url); + jsapiSignature.setSignature(signature); + + // Fixed bug + jsapiSignature.setAppId(this.configStorage.getCorpId()); + + return jsapiSignature; + } + + @Override + public WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"; + return WxCpMessageSendResult.fromJson(this.post(url, message.toJson())); + } + + @Override + @Deprecated + public void menuCreate(WxMenu menu) throws WxErrorException { + this.getMenuService().create(menu); + } + + @Override + @Deprecated + public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException { + this.getMenuService().create(agentId, menu); + } + + @Override + @Deprecated + public void menuDelete() throws WxErrorException { + this.getMenuService().delete(); + } + + @Override + @Deprecated + public void menuDelete(Integer agentId) throws WxErrorException { + this.getMenuService().delete(agentId); + } + + @Override + @Deprecated + public WxMenu menuGet() throws WxErrorException { + return this.getMenuService().get(); + } + + @Override + @Deprecated + public WxMenu menuGet(Integer agentId) throws WxErrorException { + return this.getMenuService().get(agentId); + } + + @Override + @Deprecated + public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) + throws WxErrorException, IOException { + return this.getMediaService().upload(mediaType, fileType, inputStream); + } + + @Override + @Deprecated + public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { + return this.getMediaService().upload(mediaType, file); + } + + @Override + @Deprecated + public File mediaDownload(String mediaId) throws WxErrorException { + return this.getMediaService().download(mediaId); + } + + @Override + @Deprecated + public void userAuthenticated(String userId) throws WxErrorException { + this.getUserService().authenticate(userId); + } + + @Override + @Deprecated + public void userCreate(WxCpUser user) throws WxErrorException { + this.getUserService().create(user); + } + + @Override + @Deprecated + public void userUpdate(WxCpUser user) throws WxErrorException { + this.getUserService().update(user); + } + + @Override + @Deprecated + public void userDelete(String userid) throws WxErrorException { + this.getUserService().delete(userid); + } + + @Override + @Deprecated + public void userDelete(String[] userids) throws WxErrorException { + this.getUserService().delete(userids); + } + + @Override + @Deprecated + public WxCpUser userGet(String userid) throws WxErrorException { + return this.getUserService().getById(userid); + } + + @Override + @Deprecated + public List userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + return this.getUserService().listByDepartment(departId, fetchChild, status); + } + + @Override + @Deprecated + public List departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + return this.getUserService().listSimpleByDepartment(departId, fetchChild, status); + } + + @Override + @Deprecated + public String tagCreate(String tagName) throws WxErrorException { + return this.getTagService().create(tagName); + } + + @Override + @Deprecated + public void tagUpdate(String tagId, String tagName) throws WxErrorException { + this.getTagService().update(tagId, tagName); + } + + @Override + @Deprecated + public void tagDelete(String tagId) throws WxErrorException { + this.getTagService().delete(tagId); + } + + @Override + @Deprecated + public List tagGet() throws WxErrorException { + return this.getTagService().listAll(); + } + + @Override + @Deprecated + public List tagGetUsers(String tagId) throws WxErrorException { + return this.getTagService().listUsersByTagId(tagId); + } + + @Override + @Deprecated + public void tagAddUsers(String tagId, List userIds, List partyIds) throws WxErrorException { + this.getTagService().addUsers2Tag(tagId, userIds, partyIds); + } + + @Override + @Deprecated + public void tagRemoveUsers(String tagId, List userIds) throws WxErrorException { + this.getTagService().removeUsersFromTag(tagId, userIds); + } + + @Override + @Deprecated + public String oauth2buildAuthorizationUrl(String state) { + return this.getOauth2Service().buildAuthorizationUrl(state); + } + + @Override + @Deprecated + public String oauth2buildAuthorizationUrl(String redirectUri, String state) { + return this.getOauth2Service().buildAuthorizationUrl(redirectUri, state); + } + + @Override + @Deprecated + public String[] oauth2getUserInfo(String code) throws WxErrorException { + return this.getOauth2Service().getUserInfo(code); + } + + @Override + @Deprecated + public String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException { + return this.getOauth2Service().getUserInfo(agentId, code); + } + + @Override + public int invite(String userId, String inviteTips) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/invite/send"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("userid", userId); + if (StringUtils.isNotEmpty(inviteTips)) { + jsonObject.addProperty("invite_tips", inviteTips); + } + String responseContent = post(url, jsonObject.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("type").getAsInt(); + } + + @Override + public String[] getCallbackIp() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip"; + String responseContent = get(url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); + String[] ips = new String[jsonArray.size()]; + for (int i = 0; i < jsonArray.size(); i++) { + ips[i] = jsonArray.get(i).getAsString(); + } + return ips; + } + + @Override + public String get(String url, String queryParam) throws WxErrorException { + return execute(SimpleGetRequestExecutor.create(this), url, queryParam); + } + + @Override + public String post(String url, String postData) throws WxErrorException { + return execute(SimplePostRequestExecutor.create(this), url, postData); + } + + /** + * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 + */ + @Override + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + int retryTimes = 0; + do { + try { + return this.executeInternal(executor, uri, data); + } catch (WxErrorException e) { + if (retryTimes + 1 > this.maxRetryTimes) { + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + //最后一次重试失败后,直接抛出异常,不再等待 + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + WxError error = e.getError(); + /* + * -1 系统繁忙, 1000ms后重试 + */ + if (error.getErrorCode() == -1) { + int sleepMillis = this.retrySleepMillis * (1 << retryTimes); + try { + this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + Thread.sleep(sleepMillis); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + } else { + throw e; + } + } + } while (retryTimes++ < this.maxRetryTimes); + + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + protected synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + if (uri.contains("access_token=")) { + throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); + } + String accessToken = getAccessToken(false); + + String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken; + + try { + T result = executor.execute(uriWithAccessToken, data); + this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, data, result); + return result; + } catch (WxErrorException e) { + WxError error = e.getError(); + /* + * 发生以下情况时尝试刷新access_token + * 40001 获取access_token时AppSecret错误,或者access_token无效 + * 42001 access_token超时 + * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口 + */ + if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001 || error.getErrorCode() == 40014) { + // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token + this.configStorage.expireAccessToken(); + return execute(executor, uri, data); + } + + if (error.getErrorCode() != 0) { + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, data, error); + throw new WxErrorException(error); + } + return null; + } catch (IOException e) { + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, data, e.getMessage()); + throw new RuntimeException(e); + } + } + + @Override + public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) { + this.configStorage = wxConfigProvider; + this.initHttp(); + } + + @Override + public void setRetrySleepMillis(int retrySleepMillis) { + this.retrySleepMillis = retrySleepMillis; + } + + + @Override + public void setMaxRetryTimes(int maxRetryTimes) { + this.maxRetryTimes = maxRetryTimes; + } + + @Override + public WxSession getSession(String id) { + if (this.sessionManager == null) { + return null; + } + return this.sessionManager.getSession(id); + } + + @Override + public WxSession getSession(String id, boolean create) { + if (this.sessionManager == null) { + return null; + } + return this.sessionManager.getSession(id, create); + } + + @Override + public void setSessionManager(WxSessionManager sessionManager) { + this.sessionManager = sessionManager; + } + + @Override + public String replaceParty(String mediaId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("media_id", mediaId); + return post(url, jsonObject.toString()); + } + + @Override + public String replaceUser(String mediaId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("media_id", mediaId); + return post(url, jsonObject.toString()); + } + + @Override + public String getTaskResult(String joinId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?jobid=" + joinId; + return get(url, null); + } + + public File getTmpDirFile() { + return this.tmpDirFile; + } + + public void setTmpDirFile(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public WxCpDepartmentService getDepartmentService() { + return departmentService; + } + + @Override + public WxCpMediaService getMediaService() { + return mediaService; + } + + @Override + public WxCpMenuService getMenuService() { + return menuService; + } + + @Override + public WxCpOAuth2Service getOauth2Service() { + return oauth2Service; + } + + @Override + public WxCpTagService getTagService() { + return tagService; + } + + @Override + public WxCpUserService getUserService() { + return userService; + } + + @Override + @Deprecated + public Integer departCreate(WxCpDepart depart) throws WxErrorException { + return this.getDepartmentService().create(depart); + } + + @Override + @Deprecated + public void departUpdate(WxCpDepart depart) throws WxErrorException { + this.getDepartmentService().update(depart); + } + + @Override + @Deprecated + public void departDelete(Integer departId) throws WxErrorException { + this.getDepartmentService().delete(departId); + } + + @Override + @Deprecated + public List departGet() throws WxErrorException { + return this.getDepartmentService().listAll(); + } + + @Override + public RequestHttp getRequestHttp() { + return this; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java new file mode 100644 index 0000000000..82cd8c345c --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java @@ -0,0 +1,65 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.api.WxCpDepartmentService; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpDepart; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; + +/** + *
    + *  部门管理接口
    + *  Created by BinaryWang on 2017/6/24.
    + * 
    + * + * @author Binary Wang + */ +public class WxCpDepartmentServiceImpl implements WxCpDepartmentService { + private WxCpService mainService; + + public WxCpDepartmentServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public Integer create(WxCpDepart depart) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; + String responseContent = this.mainService.post(url, depart.toJson()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id")); + } + + @Override + public void update(WxCpDepart group) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update"; + this.mainService.post(url, group.toJson()); + } + + @Override + public void delete(Integer departId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId; + this.mainService.get(url, null); + } + + @Override + public List listAll() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; + String responseContent = this.mainService.get(url, null); + /* + * 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } + * 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } + */ + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson(tmpJsonElement.getAsJsonObject().get("department"), + new TypeToken>() { + }.getType() + ); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java new file mode 100644 index 0000000000..1364550aac --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java @@ -0,0 +1,50 @@ +package me.chanjar.weixin.cp.api.impl; + +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.cp.api.WxCpMediaService; +import me.chanjar.weixin.cp.api.WxCpService; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +/** + *
    + * 媒体管理接口
    + * Created by Binary Wang on 2017-6-25.
    + * @author Binary Wang
    + * 
    + */ +public class WxCpMediaServiceImpl implements WxCpMediaService { + private WxCpService mainService; + + public WxCpMediaServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public WxMediaUploadResult upload(String mediaType, String fileType, InputStream inputStream) + throws WxErrorException, IOException { + return this.upload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); + } + + @Override + public WxMediaUploadResult upload(String mediaType, File file) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; + return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), url, file); + } + + @Override + public File download(String mediaId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; + return this.mainService.execute( + MediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(), + this.mainService.getWxCpConfigStorage().getTmpDirFile()), + url, "media_id=" + mediaId); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java new file mode 100644 index 0000000000..7c3937d83e --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java @@ -0,0 +1,64 @@ +package me.chanjar.weixin.cp.api.impl; + +import me.chanjar.weixin.common.bean.menu.WxMenu; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpMenuService; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +/** + *
    + * 菜单管理相关接口
    + * Created by Binary Wang on 2017-6-25.
    + * @author Binary Wang
    + * 
    + */ +public class WxCpMenuServiceImpl implements WxCpMenuService { + private WxCpService mainService; + + public WxCpMenuServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public void create(WxMenu menu) throws WxErrorException { + this.create(this.mainService.getWxCpConfigStorage().getAgentId(), menu); + } + + @Override + public void create(Integer agentId, WxMenu menu) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" + agentId; + this.mainService.post(url, menu.toJson()); + } + + @Override + public void delete() throws WxErrorException { + this.delete(this.mainService.getWxCpConfigStorage().getAgentId()); + } + + @Override + public void delete(Integer agentId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId; + this.mainService.get(url, null); + } + + @Override + public WxMenu get() throws WxErrorException { + return this.get(this.mainService.getWxCpConfigStorage().getAgentId()); + } + + @Override + public WxMenu get(Integer agentId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId; + try { + String resultContent = this.mainService.get(url, null); + return WxCpGsonBuilder.create().fromJson(resultContent, WxMenu.class); + } catch (WxErrorException e) { + // 46003 不存在的菜单数据 + if (e.getError().getErrorCode() == 46003) { + return null; + } + throw e; + } + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java new file mode 100644 index 0000000000..a317bfb4e6 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.URIUtil; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.api.WxCpOAuth2Service; +import me.chanjar.weixin.cp.api.WxCpService; + +/** + *
    + *
    + * Created by Binary Wang on 2017-6-25.
    + * @author Binary Wang
    + * 
    + */ +public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { + private WxCpService mainService; + + public WxCpOAuth2ServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public String buildAuthorizationUrl(String state) { + return this.buildAuthorizationUrl( + this.mainService.getWxCpConfigStorage().getOauth2redirectUri(), + state + ); + } + + @Override + public String buildAuthorizationUrl(String redirectUri, String state) { + String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"; + url += "appid=" + this.mainService.getWxCpConfigStorage().getCorpId(); + url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri); + url += "&response_type=code"; + url += "&scope=snsapi_base"; + if (state != null) { + url += "&state=" + state; + } + url += "#wechat_redirect"; + return url; + } + + @Override + public String[] getUserInfo(String code) throws WxErrorException { + return getUserInfo(this.mainService.getWxCpConfigStorage().getAgentId(), code); + } + + @Override + public String[] getUserInfo(Integer agentId, String code) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?" + + "code=" + code + + "&agentid=" + agentId; + String responseText = this.mainService.get(url, null); + JsonElement je = new JsonParser().parse(responseText); + JsonObject jo = je.getAsJsonObject(); + return new String[]{GsonHelper.getString(jo, "UserId"), + GsonHelper.getString(jo, "DeviceId"), + GsonHelper.getString(jo, "OpenId")}; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java new file mode 100644 index 0000000000..d9388f0345 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java @@ -0,0 +1,105 @@ +package me.chanjar.weixin.cp.api.impl; + + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.HttpType; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; + +public class WxCpServiceApacheHttpClientImpl extends AbstractWxCpServiceImpl { + protected CloseableHttpClient httpClient; + protected HttpHost httpProxy; + + @Override + public CloseableHttpClient getRequestHttpClient() { + return httpClient; + } + + @Override + public HttpHost getRequestHttpProxy() { + return httpProxy; + } + + @Override + public HttpType getRequestType() { + return HttpType.APACHE_HTTP; + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + if (forceRefresh) { + this.configStorage.expireAccessToken(); + } + if (this.configStorage.isAccessTokenExpired()) { + synchronized (this.globalAccessTokenRefreshLock) { + if (this.configStorage.isAccessTokenExpired()) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" + + "&corpid=" + this.configStorage.getCorpId() + + "&corpsecret=" + this.configStorage.getCorpSecret(); + try { + HttpGet httpGet = new HttpGet(url); + if (this.httpProxy != null) { + RequestConfig config = RequestConfig.custom() + .setProxy(this.httpProxy).build(); + httpGet.setConfig(config); + } + String resultContent = null; + try (CloseableHttpClient httpclient = getRequestHttpClient(); + CloseableHttpResponse response = httpclient.execute(httpGet)) { + resultContent = new BasicResponseHandler().handleResponse(response); + } finally { + httpGet.releaseConnection(); + } + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.configStorage.updateAccessToken( + accessToken.getAccessToken(), accessToken.getExpiresIn()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + } + return this.configStorage.getAccessToken(); + } + + @Override + public void initHttp() { + ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage + .getApacheHttpClientBuilder(); + if (null == apacheHttpClientBuilder) { + apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); + } + + apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost()) + .httpProxyPort(this.configStorage.getHttpProxyPort()) + .httpProxyUsername(this.configStorage.getHttpProxyUsername()) + .httpProxyPassword(this.configStorage.getHttpProxyPassword()); + + if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) { + this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort()); + } + + this.httpClient = apacheHttpClientBuilder.build(); + } + + @Override + public WxCpConfigStorage getWxCpConfigStorage() { + return this.configStorage; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java new file mode 100644 index 0000000000..ff8e149c77 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java @@ -0,0 +1,11 @@ +package me.chanjar.weixin.cp.api.impl; + +/** + *
    + *  默认接口实现类,使用apache httpclient实现
    + * Created by Binary Wang on 2017-5-27.
    + * @author binarywang(Binary Wang)
    + * 
    + */ +public class WxCpServiceImpl extends WxCpServiceApacheHttpClientImpl { +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java new file mode 100644 index 0000000000..3000916fac --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java @@ -0,0 +1,76 @@ +package me.chanjar.weixin.cp.api.impl; + +import jodd.http.*; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.HttpType; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; + +public class WxCpServiceJoddHttpImpl extends AbstractWxCpServiceImpl { + protected HttpConnectionProvider httpClient; + protected ProxyInfo httpProxy; + + + @Override + public HttpConnectionProvider getRequestHttpClient() { + return httpClient; + } + + @Override + public ProxyInfo getRequestHttpProxy() { + return httpProxy; + } + + @Override + public HttpType getRequestType() { + return HttpType.JODD_HTTP; + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + if (forceRefresh) { + this.configStorage.expireAccessToken(); + } + if (this.configStorage.isAccessTokenExpired()) { + synchronized (this.globalAccessTokenRefreshLock) { + if (this.configStorage.isAccessTokenExpired()) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" + + "&corpid=" + this.configStorage.getCorpId() + + "&corpsecret=" + this.configStorage.getCorpSecret(); + + HttpRequest request = HttpRequest.get(url); + if (this.httpProxy != null) { + httpClient.useProxy(this.httpProxy); + } + request.withConnectionProvider(httpClient); + HttpResponse response = request.send(); + + String resultContent = response.bodyText(); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.configStorage.updateAccessToken( + accessToken.getAccessToken(), accessToken.getExpiresIn()); + } + } + } + return this.configStorage.getAccessToken(); + } + + @Override + public void initHttp() { + if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) { + httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + } + + httpClient = JoddHttp.httpConnectionProvider; + } + + @Override + public WxCpConfigStorage getWxCpConfigStorage() { + return this.configStorage; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java new file mode 100644 index 0000000000..4dd66d9d86 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java @@ -0,0 +1,104 @@ +package me.chanjar.weixin.cp.api.impl; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.HttpType; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import okhttp3.*; + +import java.io.IOException; + +public class WxCpServiceOkHttpImpl extends AbstractWxCpServiceImpl { + protected ConnectionPool httpClient; + protected OkHttpProxyInfo httpProxy; + + + @Override + public ConnectionPool getRequestHttpClient() { + return httpClient; + } + + @Override + public OkHttpProxyInfo getRequestHttpProxy() { + return httpProxy; + } + + @Override + public HttpType getRequestType() { + return HttpType.OK_HTTP; + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + if (forceRefresh) { + this.configStorage.expireAccessToken(); + } + if (this.configStorage.isAccessTokenExpired()) { + synchronized (this.globalAccessTokenRefreshLock) { + if (this.configStorage.isAccessTokenExpired()) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" + + "&corpid=" + this.configStorage.getCorpId() + + "&corpsecret=" + this.configStorage.getCorpSecret(); + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(httpClient); + //设置代理 + if (httpProxy != null) { + clientBuilder.proxy(getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + //请求的request + Request request = new Request.Builder().url(url).get().build(); + Response response = null; + try { + response = client.newCall(request).execute(); + } catch (IOException e) { + e.printStackTrace(); + } + String resultContent = null; + try { + resultContent = response.body().string(); + } catch (IOException e) { + e.printStackTrace(); + } + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.configStorage.updateAccessToken(accessToken.getAccessToken(), + accessToken.getExpiresIn()); + } + } + } + return this.configStorage.getAccessToken(); + } + + @Override + public void initHttp() { + WxCpConfigStorage configStorage = this.configStorage; + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + httpProxy = new OkHttpProxyInfo(OkHttpProxyInfo.ProxyType.SOCKS5, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + } + + httpClient = new ConnectionPool(); + } + + @Override + public WxCpConfigStorage getWxCpConfigStorage() { + return this.configStorage; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java new file mode 100644 index 0000000000..ff995d9724 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java @@ -0,0 +1,116 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.api.WxCpTagService; +import me.chanjar.weixin.cp.bean.WxCpTag; +import me.chanjar.weixin.cp.bean.WxCpTagAddOrRemoveUsersResult; +import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; + +/** + *
    + *  标签管理接口
    + * Created by Binary Wang on 2017-6-25.
    + * @author Binary Wang
    + * 
    + */ +public class WxCpTagServiceImpl implements WxCpTagService { + private WxCpService mainService; + + public WxCpTagServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public String create(String tagName) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; + JsonObject o = new JsonObject(); + o.addProperty("tagname", tagName); + String responseContent = this.mainService.post(url, o.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("tagid").getAsString(); + } + + @Override + public void update(String tagId, String tagName) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; + JsonObject o = new JsonObject(); + o.addProperty("tagid", tagId); + o.addProperty("tagname", tagName); + this.mainService.post(url, o.toString()); + } + + @Override + public void delete(String tagId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; + this.mainService.get(url, null); + } + + @Override + public List listAll() throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; + String responseContent = this.mainService.get(url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("taglist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public List listUsersByTagId(String tagId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; + String responseContent = this.mainService.get(url, null); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public WxCpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List userIds, List partyIds) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + if (userIds != null) { + JsonArray jsonArray = new JsonArray(); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("userlist", jsonArray); + } + if (partyIds != null) { + JsonArray jsonArray = new JsonArray(); + for (String userId : partyIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("partylist", jsonArray); + } + + return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(url, jsonObject.toString())); + } + + @Override + public WxCpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + JsonArray jsonArray = new JsonArray(); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("userlist", jsonArray); + + return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(url, jsonObject.toString())); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java new file mode 100644 index 0000000000..c49c1ffd69 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java @@ -0,0 +1,118 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.api.WxCpUserService; +import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; + +/** + *
    + *  Created by BinaryWang on 2017/6/24.
    + * 
    + * + * @author Binary Wang + */ +public class WxCpUserServiceImpl implements WxCpUserService { + private WxCpService mainService; + + public WxCpUserServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public void authenticate(String userId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId; + this.mainService.get(url, null); + } + + @Override + public void create(WxCpUser user) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; + this.mainService.post(url, user.toJson()); + } + + @Override + public void update(WxCpUser user) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; + this.mainService.post(url, user.toJson()); + } + + public void deleteOne(String userId) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userId; + this.mainService.get(url, null); + } + + @Override + public void delete(String... userIds) throws WxErrorException { + if (userIds.length == 1) { + this.deleteOne(userIds[0]); + } + + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; + JsonObject jsonObject = new JsonObject(); + JsonArray jsonArray = new JsonArray(); + for (String userid : userIds) { + jsonArray.add(new JsonPrimitive(userid)); + } + jsonObject.add("useridlist", jsonArray); + this.mainService.post(url, jsonObject.toString()); + } + + @Override + public WxCpUser getById(String userid) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid; + String responseContent = this.mainService.get(url, null); + return WxCpUser.fromJson(responseContent); + } + + @Override + public List listByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; + String params = ""; + if (fetchChild != null) { + params += "&fetch_child=" + (fetchChild ? "1" : "0"); + } + if (status != null) { + params += "&status=" + status; + } else { + params += "&status=0"; + } + + String responseContent = this.mainService.get(url, params); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson(tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + + @Override + public List listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; + String params = ""; + if (fetchChild != null) { + params += "&fetch_child=" + (fetchChild ? "1" : "0"); + } + if (status != null) { + params += "&status=" + status; + } else { + params += "&status=0"; + } + + String responseContent = this.mainService.get(url, params); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return WxCpGsonBuilder.INSTANCE.create() + .fromJson( + tmpJsonElement.getAsJsonObject().get("userlist"), + new TypeToken>() { + }.getType() + ); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java index a679dffe23..118c500488 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java @@ -1,9 +1,9 @@ package me.chanjar.weixin.cp.bean; -import java.io.Serializable; - import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import java.io.Serializable; + /** * 微信部门 * @@ -60,10 +60,10 @@ public String toJson() { @Override public String toString() { return "WxCpDepart{" + - "id=" + this.id + - ", name='" + this.name + '\'' + - ", parentId=" + this.parentId + - ", order=" + this.order + - '}'; + "id=" + this.id + + ", name='" + this.name + '\'' + + ", parentId=" + this.parentId + + ", order=" + this.order + + '}'; } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java index 324df20902..2d07fcf867 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java @@ -33,14 +33,6 @@ public class WxCpMessage implements Serializable { private List articles = new ArrayList<>(); private List mpnewsArticles = new ArrayList<>(); - public List getMpnewsArticles() { - return mpnewsArticles; - } - - public void setMpnewsArticles(List mpnewsArticles) { - this.mpnewsArticles = mpnewsArticles; - } - /** * 获得文本消息builder */ @@ -90,6 +82,14 @@ public static FileBuilder FILE() { return new FileBuilder(); } + public List getMpnewsArticles() { + return mpnewsArticles; + } + + public void setMpnewsArticles(List mpnewsArticles) { + this.mpnewsArticles = mpnewsArticles; + } + public String getToUser() { return this.toUser; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java new file mode 100644 index 0000000000..6989c4988f --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java @@ -0,0 +1,103 @@ +package me.chanjar.weixin.cp.bean; + +import com.google.common.base.Splitter; +import com.google.gson.annotations.SerializedName; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.List; + +/** + *
    + * 消息发送结果对象类
    + * Created by Binary Wang on 2017-6-22.
    + * @author Binary Wang
    + * 
    + */ +public class WxCpMessageSendResult { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public static WxCpMessageSendResult fromJson(String json) { + return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpMessageSendResult.class); + } + + @SerializedName("errcode") + private Integer errCode; + + @SerializedName("errmsg") + private String errMsg; + + @SerializedName("invaliduser") + private String invalidUser; + + @SerializedName("invalidparty") + private String invalidParty; + + @SerializedName("invalidtag") + private String invalidTag; + + public Integer getErrCode() { + return this.errCode; + } + + public void setErrCode(Integer errCode) { + this.errCode = errCode; + } + + public String getErrMsg() { + return this.errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } + + public String getInvalidUser() { + return this.invalidUser; + } + + public void setInvalidUser(String invalidUser) { + this.invalidUser = invalidUser; + } + + public String getInvalidParty() { + return this.invalidParty; + } + + public void setInvalidParty(String invalidParty) { + this.invalidParty = invalidParty; + } + + public String getInvalidTag() { + return this.invalidTag; + } + + public void setInvalidTag(String invalidTag) { + this.invalidTag = invalidTag; + } + + public List getInvalidUserList() { + return this.content2List(this.invalidUser); + } + + private List content2List(String content) { + if(StringUtils.isBlank(content)){ + return Collections.emptyList(); + } + + return Splitter.on("|").splitToList(content); + } + + public List getInvalidPartyList() { + return this.content2List(this.invalidParty); + } + + public List getInvalidTagList() { + return this.content2List(this.invalidTag); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java index 4e1c034f6a..79ec3f1321 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java @@ -1,9 +1,9 @@ package me.chanjar.weixin.cp.bean; -import java.io.Serializable; - import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import java.io.Serializable; + /** * Created by Daniel Qian */ diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java new file mode 100644 index 0000000000..c216ae46a6 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java @@ -0,0 +1,85 @@ +package me.chanjar.weixin.cp.bean; + +import com.google.common.base.Splitter; +import com.google.gson.annotations.SerializedName; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.List; + +/** + *
    + * 为标签添加或移除用户结果对象类
    + * Created by Binary Wang on 2017-6-22.
    + * @author Binary Wang
    + * 
    + */ +public class WxCpTagAddOrRemoveUsersResult { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public static WxCpTagAddOrRemoveUsersResult fromJson(String json) { + return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpTagAddOrRemoveUsersResult.class); + } + + @SerializedName("errcode") + private Integer errCode; + + @SerializedName("errmsg") + private String errMsg; + + @SerializedName("invalidlist") + private String invalidUsers; + + @SerializedName("invalidparty") + private String[] invalidParty; + + public Integer getErrCode() { + return this.errCode; + } + + public void setErrCode(Integer errCode) { + this.errCode = errCode; + } + + public String getErrMsg() { + return this.errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } + + public String getInvalidUser() { + return this.invalidUsers; + } + + public void setInvalidUser(String invalidUser) { + this.invalidUsers = invalidUser; + } + + public String[] getInvalidParty() { + return this.invalidParty; + } + + public void setInvalidParty(String[] invalidParty) { + this.invalidParty = invalidParty; + } + + public List getInvalidUserList() { + return this.content2List(this.invalidUsers); + } + + private List content2List(String content) { + if(StringUtils.isBlank(content)){ + return Collections.emptyList(); + } + + return Splitter.on("|").splitToList(content); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java index 93c3e5feb4..647a4e6ba2 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java @@ -1,11 +1,11 @@ package me.chanjar.weixin.cp.bean; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; - /** * 微信用户信息 * @@ -13,20 +13,54 @@ */ public class WxCpUser implements Serializable { + public enum Gender { + MALE("男", "1"), + FEMAIL("女", "2"); + + private String genderName; + private String code; + + Gender(String genderName, String code) { + this.genderName = genderName; + this.code = code; + } + + public String getGenderName() { + return this.genderName; + } + + public String getCode() { + return this.code; + } + + public static Gender fromCode(String code) { + if ("1".equals(code)) { + return Gender.MALE; + } + if ("2".equals(code)) { + return Gender.FEMAIL; + } + + return null; + } + } + private static final long serialVersionUID = -5696099236344075582L; - private final List extAttrs = new ArrayList<>(); private String userId; private String name; private Integer[] departIds; private String position; private String mobile; - private String gender; - private String tel; + private Gender gender; private String email; - private String weiXinId; private String avatar; private Integer status; private Integer enable; + private Integer isLeader; + private final List extAttrs = new ArrayList<>(); + private Integer hideMobile; + private String englishName; + private String telephone; public static WxCpUser fromJson(String json) { return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpUser.class); @@ -56,11 +90,11 @@ public void setDepartIds(Integer[] departIds) { this.departIds = departIds; } - public String getGender() { + public Gender getGender() { return this.gender; } - public void setGender(String gender) { + public void setGender(Gender gender) { this.gender = gender; } @@ -80,12 +114,12 @@ public void setMobile(String mobile) { this.mobile = mobile; } - public String getTel() { - return this.tel; + public String getTelephone() { + return this.telephone; } - public void setTel(String tel) { - this.tel = tel; + public void setTelephone(String telephone) { + this.telephone = telephone; } public String getEmail() { @@ -96,14 +130,6 @@ public void setEmail(String email) { this.email = email; } - public String getWeiXinId() { - return this.weiXinId; - } - - public void setWeiXinId(String weiXinId) { - this.weiXinId = weiXinId; - } - public String getAvatar() { return this.avatar; } @@ -136,12 +162,35 @@ public List getExtAttrs() { return this.extAttrs; } + public Integer getIsLeader() { + return isLeader; + } + + public void setIsLeader(Integer isLeader) { + this.isLeader = isLeader; + } + + public Integer getHideMobile() { + return hideMobile; + } + + public void setHideMobile(Integer hideMobile) { + this.hideMobile = hideMobile; + } + + public String getEnglishName() { + return englishName; + } + + public void setEnglishName(String englishName) { + this.englishName = englishName; + } + public String toJson() { return WxCpGsonBuilder.INSTANCE.create().toJson(this); } public static class Attr { - private String name; private String value; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java index 93ca45c36e..8b7ee5f166 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java @@ -1,20 +1,18 @@ package me.chanjar.weixin.cp.bean; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.io.IOUtils; - import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamConverter; - import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; import me.chanjar.weixin.cp.util.xml.XStreamTransformer; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; /** *
    @@ -183,18 +181,18 @@ protected static WxCpXmlMessage fromXml(InputStream is) {
        * @param msgSignature
        */
       public static WxCpXmlMessage fromEncryptedXml(
    -          String encryptedXml,
    -          WxCpConfigStorage wxCpConfigStorage,
    -          String timestamp, String nonce, String msgSignature) {
    +    String encryptedXml,
    +    WxCpConfigStorage wxCpConfigStorage,
    +    String timestamp, String nonce, String msgSignature) {
         WxCpCryptUtil cryptUtil = new WxCpCryptUtil(wxCpConfigStorage);
         String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml);
         return fromXml(plainText);
       }
     
       public static WxCpXmlMessage fromEncryptedXml(
    -          InputStream is,
    -          WxCpConfigStorage wxCpConfigStorage,
    -          String timestamp, String nonce, String msgSignature) {
    +    InputStream is,
    +    WxCpConfigStorage wxCpConfigStorage,
    +    String timestamp, String nonce, String msgSignature) {
         try {
           return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxCpConfigStorage, timestamp, nonce, msgSignature);
         } catch (IOException e) {
    @@ -493,40 +491,40 @@ public void setSendLocationInfo(WxCpXmlMessage.SendLocationInfo sendLocationInfo
       @Override
       public String toString() {
         return "WxCpXmlMessage{" +
    -            "agentId=" + this.agentId +
    -            ", toUserName='" + this.toUserName + '\'' +
    -            ", fromUserName='" + this.fromUserName + '\'' +
    -            ", createTime=" + this.createTime +
    -            ", msgType='" + this.msgType + '\'' +
    -            ", content='" + this.content + '\'' +
    -            ", msgId=" + this.msgId +
    -            ", picUrl='" + this.picUrl + '\'' +
    -            ", mediaId='" + this.mediaId + '\'' +
    -            ", format='" + this.format + '\'' +
    -            ", thumbMediaId='" + this.thumbMediaId + '\'' +
    -            ", locationX=" + this.locationX +
    -            ", locationY=" + this.locationY +
    -            ", scale=" + this.scale +
    -            ", label='" + this.label + '\'' +
    -            ", title='" + this.title + '\'' +
    -            ", description='" + this.description + '\'' +
    -            ", url='" + this.url + '\'' +
    -            ", event='" + this.event + '\'' +
    -            ", eventKey='" + this.eventKey + '\'' +
    -            ", ticket='" + this.ticket + '\'' +
    -            ", latitude=" + this.latitude +
    -            ", longitude=" + this.longitude +
    -            ", precision=" + this.precision +
    -            ", recognition='" + this.recognition + '\'' +
    -            ", status='" + this.status + '\'' +
    -            ", totalCount=" + this.totalCount +
    -            ", filterCount=" + this.filterCount +
    -            ", sentCount=" + this.sentCount +
    -            ", errorCount=" + this.errorCount +
    -            ", scanCodeInfo=" + this.scanCodeInfo +
    -            ", sendPicsInfo=" + this.sendPicsInfo +
    -            ", sendLocationInfo=" + this.sendLocationInfo +
    -            '}';
    +      "agentId=" + this.agentId +
    +      ", toUserName='" + this.toUserName + '\'' +
    +      ", fromUserName='" + this.fromUserName + '\'' +
    +      ", createTime=" + this.createTime +
    +      ", msgType='" + this.msgType + '\'' +
    +      ", content='" + this.content + '\'' +
    +      ", msgId=" + this.msgId +
    +      ", picUrl='" + this.picUrl + '\'' +
    +      ", mediaId='" + this.mediaId + '\'' +
    +      ", format='" + this.format + '\'' +
    +      ", thumbMediaId='" + this.thumbMediaId + '\'' +
    +      ", locationX=" + this.locationX +
    +      ", locationY=" + this.locationY +
    +      ", scale=" + this.scale +
    +      ", label='" + this.label + '\'' +
    +      ", title='" + this.title + '\'' +
    +      ", description='" + this.description + '\'' +
    +      ", url='" + this.url + '\'' +
    +      ", event='" + this.event + '\'' +
    +      ", eventKey='" + this.eventKey + '\'' +
    +      ", ticket='" + this.ticket + '\'' +
    +      ", latitude=" + this.latitude +
    +      ", longitude=" + this.longitude +
    +      ", precision=" + this.precision +
    +      ", recognition='" + this.recognition + '\'' +
    +      ", status='" + this.status + '\'' +
    +      ", totalCount=" + this.totalCount +
    +      ", filterCount=" + this.filterCount +
    +      ", sentCount=" + this.sentCount +
    +      ", errorCount=" + this.errorCount +
    +      ", scanCodeInfo=" + this.scanCodeInfo +
    +      ", sendPicsInfo=" + this.sendPicsInfo +
    +      ", sendLocationInfo=" + this.sendLocationInfo +
    +      '}';
       }
     
       @XStreamAlias("ScanCodeInfo")
    diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessage.java
    index 35cbe75424..2ddb78afc9 100644
    --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessage.java
    +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessage.java
    @@ -2,7 +2,6 @@
     
     import com.thoughtworks.xstream.annotations.XStreamAlias;
     import com.thoughtworks.xstream.annotations.XStreamConverter;
    -
     import me.chanjar.weixin.common.api.WxConsts;
     import me.chanjar.weixin.common.util.xml.XStreamMediaIdConverter;
     
    diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java
    index 0d90a012c7..d69703502f 100644
    --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java
    +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java
    @@ -3,7 +3,7 @@
     import com.thoughtworks.xstream.annotations.XStreamAlias;
     import com.thoughtworks.xstream.annotations.XStreamConverter;
     import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
    -import me.chanjar.weixin.cp.api.WxCpConfigStorage;
    +import me.chanjar.weixin.cp.config.WxCpConfigStorage;
     import me.chanjar.weixin.cp.bean.outxmlbuilder.*;
     import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
     import me.chanjar.weixin.cp.util.xml.XStreamTransformer;
    diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessage.java
    index 8910f03fa6..0997841081 100644
    --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessage.java
    +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessage.java
    @@ -1,14 +1,13 @@
     package me.chanjar.weixin.cp.bean;
     
    -import java.util.ArrayList;
    -import java.util.List;
    -
     import com.thoughtworks.xstream.annotations.XStreamAlias;
     import com.thoughtworks.xstream.annotations.XStreamConverter;
    -
     import me.chanjar.weixin.common.api.WxConsts;
     import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
     
    +import java.util.ArrayList;
    +import java.util.List;
    +
     @XStreamAlias("xml")
     public class WxCpXmlOutNewsMessage extends WxCpXmlOutMessage {
       private static final long serialVersionUID = -5796178637883178826L;
    diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessage.java
    index 532e06c341..5f09abf485 100644
    --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessage.java
    +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessage.java
    @@ -2,7 +2,6 @@
     
     import com.thoughtworks.xstream.annotations.XStreamAlias;
     import com.thoughtworks.xstream.annotations.XStreamConverter;
    -
     import me.chanjar.weixin.common.api.WxConsts;
     import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
     
    diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessage.java
    index 73c56d4c2c..46dae31c3f 100644
    --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessage.java
    +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessage.java
    @@ -2,7 +2,6 @@
     
     import com.thoughtworks.xstream.annotations.XStreamAlias;
     import com.thoughtworks.xstream.annotations.XStreamConverter;
    -
     import me.chanjar.weixin.common.api.WxConsts;
     import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
     
    diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessage.java
    index bba95cfdbf..b1827706dd 100644
    --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessage.java
    +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessage.java
    @@ -2,7 +2,6 @@
     
     import com.thoughtworks.xstream.annotations.XStreamAlias;
     import com.thoughtworks.xstream.annotations.XStreamConverter;
    -
     import me.chanjar.weixin.common.api.WxConsts;
     import me.chanjar.weixin.common.util.xml.XStreamMediaIdConverter;
     
    diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/cp/bean/article/MpnewsArticle.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/MpnewsArticle.java
    similarity index 99%
    rename from weixin-java-common/src/main/java/me/chanjar/weixin/cp/bean/article/MpnewsArticle.java
    rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/MpnewsArticle.java
    index 7904da202c..82c4e2aaa6 100644
    --- a/weixin-java-common/src/main/java/me/chanjar/weixin/cp/bean/article/MpnewsArticle.java
    +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/MpnewsArticle.java
    @@ -4,6 +4,7 @@
      * 
      *  Created by BinaryWang on 2017/3/27.
      * 
    + * * @author Binary Wang */ public class MpnewsArticle { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java similarity index 100% rename from weixin-java-common/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/article/NewArticle.java diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java index 7800f1c61e..ea3e710c64 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java @@ -44,7 +44,7 @@ public WxCpMessage build() { m.setToParty(this.toParty); m.setToTag(this.toTag); m.setSafe( - (this.safe == null || "".equals(this.safe)) ? WxConsts.CUSTOM_MSG_SAFE_NO : this.safe); + (this.safe == null || "".equals(this.safe)) ? WxConsts.CUSTOM_MSG_SAFE_NO : this.safe); return m; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java similarity index 91% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java index eb1e57cafa..65dd3affff 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java @@ -1,7 +1,7 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.config; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import java.io.File; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java similarity index 97% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java index 867dd6bb68..1b57f83bf8 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java @@ -1,8 +1,8 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.config; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.ToStringUtils; -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import java.io.File; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java similarity index 92% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java index 9251396560..39b2ae5023 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java @@ -1,9 +1,10 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.config; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; import java.io.File; @@ -38,6 +39,15 @@ public WxCpJedisConfigStorage(String host, int port) { this.jedisPool = new JedisPool(host, port); } + + public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port) { + this.jedisPool = new JedisPool(poolConfig, host, port); + } + + public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, final String password) { + this.jedisPool = new JedisPool(poolConfig, host, port, timeout, password); + } + /** * This method will be destroy jedis pool */ diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageHandler.java similarity index 91% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageHandler.java index 9a3920a285..615fa8f220 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageHandler.java @@ -1,7 +1,8 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.message; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageInterceptor.java similarity index 90% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageInterceptor.java index e6de0e69f4..21abb5cdb4 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageInterceptor.java @@ -1,7 +1,8 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.message; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import java.util.Map; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageMatcher.java similarity index 86% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageMatcher.java index c2c62b9361..1bf36705b7 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageMatcher.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.message; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java similarity index 91% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java index da18e28e4f..3c53d26106 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.message; import me.chanjar.weixin.common.api.WxErrorExceptionHandler; import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; @@ -8,13 +8,16 @@ import me.chanjar.weixin.common.session.StandardSessionManager; import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.LogExceptionHandler; +import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -135,8 +138,9 @@ public WxCpMessageRouterRule rule() { * 处理微信消息 * * @param wxMessage + * @param context */ - public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) { + public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage, final Map context) { if (isDuplicateMessage(wxMessage)) { // 如果是重复消息,那么就不做处理 return null; @@ -166,12 +170,12 @@ public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) { this.executorService.submit(new Runnable() { @Override public void run() { - rule.service(wxMessage, WxCpMessageRouter.this.wxCpService, WxCpMessageRouter.this.sessionManager, WxCpMessageRouter.this.exceptionHandler); + rule.service(wxMessage, context, WxCpMessageRouter.this.wxCpService, WxCpMessageRouter.this.sessionManager, WxCpMessageRouter.this.exceptionHandler); } }) ); } else { - res = rule.service(wxMessage, this.wxCpService, this.sessionManager, this.exceptionHandler); + res = rule.service(wxMessage, context, this.wxCpService, this.sessionManager, this.exceptionHandler); // 在同步操作结束,session访问结束 this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUserName()); sessionEndAccess(wxMessage); @@ -200,6 +204,16 @@ public void run() { return res; } + + /** + * 处理微信消息 + * + * @param wxMessage + */ + public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) { + return this.route(wxMessage, new HashMap()); + } + protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) { String messageId = ""; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java similarity index 97% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java index 7bd332ad9b..5f41f61783 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouterRule.java @@ -1,8 +1,9 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.message; import me.chanjar.weixin.common.api.WxErrorExceptionHandler; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; @@ -229,13 +230,16 @@ protected boolean test(WxCpXmlMessage wxMessage) { * @return true 代表继续执行别的router,false 代表停止执行别的router */ protected WxCpXmlOutMessage service(WxCpXmlMessage wxMessage, + Map context, WxCpService wxCpService, WxSessionManager sessionManager, WxErrorExceptionHandler exceptionHandler) { - try { + if (context == null) { + context = new HashMap<>(); + } - Map context = new HashMap<>(); + try { // 如果拦截器不通过 for (WxCpMessageInterceptor interceptor : this.interceptors) { if (!interceptor.intercept(wxMessage, context, wxCpService, sessionManager)) { diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java index 104b124377..770ef82797 100755 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java @@ -1,47 +1,51 @@ -/** - * 对公众平台发送给公众账号的消息加解密示例代码. - * - * @copyright Copyright (c) 1998-2014 Tencent Inc. - *

    - * 针对org.apache.commons.codec.binary.Base64, - * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) - * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi - */ - -// ------------------------------------------------------------------------ - -/** - * 针对org.apache.commons.codec.binary.Base64, - * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) - * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi - */ -package me.chanjar.weixin.cp.util.crypto; - -import me.chanjar.weixin.common.util.crypto.WxCryptUtil; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import org.apache.commons.codec.binary.Base64; - -public class WxCpCryptUtil extends WxCryptUtil { - - /** - * 构造函数 - * - * @param wxCpConfigStorage - */ - public WxCpCryptUtil(WxCpConfigStorage wxCpConfigStorage) { - /* - * @param token 公众平台上,开发者设置的token - * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey - * @param appidOrCorpid 公众平台appid - */ - String encodingAesKey = wxCpConfigStorage.getAesKey(); - String token = wxCpConfigStorage.getToken(); - String corpId = wxCpConfigStorage.getCorpId(); - - this.token = token; - this.appidOrCorpid = corpId; - this.aesKey = Base64.decodeBase64(encodingAesKey + "="); - } - - -} +/** + * 对公众平台发送给公众账号的消息加解密示例代码. + * + * @copyright Copyright (c) 1998-2014 Tencent Inc. + *

    + * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + *

    + * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + */ + +// ------------------------------------------------------------------------ + +/** + * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + */ +package me.chanjar.weixin.cp.util.crypto; + +import me.chanjar.weixin.common.util.crypto.WxCryptUtil; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import org.apache.commons.codec.binary.Base64; + +public class WxCpCryptUtil extends WxCryptUtil { + + /** + * 构造函数 + * + * @param wxCpConfigStorage + */ + public WxCpCryptUtil(WxCpConfigStorage wxCpConfigStorage) { + /* + * @param token 公众平台上,开发者设置的token + * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey + * @param appidOrCorpid 公众平台appid + */ + String encodingAesKey = wxCpConfigStorage.getAesKey(); + String token = wxCpConfigStorage.getToken(); + String corpId = wxCpConfigStorage.getCorpId(); + + this.token = token; + this.appidOrCorpid = corpId; + this.aesKey = Base64.decodeBase64(encodingAesKey + "="); + } + + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java index a547ce020d..431c38039b 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java @@ -39,7 +39,7 @@ public JsonElement serialize(WxCpDepart group, Type typeOfSrc, JsonSerialization @Override public WxCpDepart deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { + throws JsonParseException { WxCpDepart depart = new WxCpDepart(); JsonObject departJson = json.getAsJsonObject(); if (departJson.get("id") != null && !departJson.get("id").isJsonNull()) { diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java index 3235864811..5efee45ce5 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java @@ -2,6 +2,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.util.json.WxErrorAdapter; import me.chanjar.weixin.cp.bean.WxCpDepart; @@ -19,6 +20,7 @@ public class WxCpGsonBuilder { INSTANCE.registerTypeAdapter(WxCpDepart.class, new WxCpDepartGsonAdapter()); INSTANCE.registerTypeAdapter(WxCpUser.class, new WxCpUserGsonAdapter()); INSTANCE.registerTypeAdapter(WxError.class, new WxErrorAdapter()); + INSTANCE.registerTypeAdapter(WxMenu.class, new WxCpMenuGsonAdapter()); INSTANCE.registerTypeAdapter(WxCpTag.class, new WxCpTagGsonAdapter()); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMenuGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMenuGsonAdapter.java new file mode 100644 index 0000000000..c7cb05cc62 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMenuGsonAdapter.java @@ -0,0 +1,24 @@ +package me.chanjar.weixin.cp.util.json; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import me.chanjar.weixin.common.bean.menu.WxMenu; +import me.chanjar.weixin.common.util.json.WxMenuGsonAdapter; + +import java.lang.reflect.Type; + +/** + *

    + * 企业号菜单json转换适配器
    + * Created by Binary Wang on 2017-6-25.
    + * @author Binary Wang
    + * 
    + */ +public class WxCpMenuGsonAdapter extends WxMenuGsonAdapter { + + @Override + public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + return this.buildMenuFromJson(json.getAsJsonObject().get("button").getAsJsonArray()); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java index 949709abec..a74c17b64c 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java @@ -61,6 +61,10 @@ public JsonElement serialize(WxCpMessage message, Type typeOfSrc, JsonSerializat messageJson.add("voice", voice); } + if (StringUtils.isNotBlank(message.getSafe())) { + messageJson.addProperty("safe", message.getSafe()); + } + if (WxConsts.CUSTOM_MSG_VIDEO.equals(message.getMsgType())) { JsonObject video = new JsonObject(); video.addProperty("media_id", message.getMediaId()); @@ -89,7 +93,7 @@ public JsonElement serialize(WxCpMessage message, Type typeOfSrc, JsonSerializat JsonObject newsJsonObject = new JsonObject(); if (message.getMediaId() != null) { newsJsonObject.addProperty("media_id", message.getMediaId()); - }else { + } else { JsonArray articleJsonArray = new JsonArray(); for (MpnewsArticle article : message.getMpnewsArticles()) { JsonObject articleJson = new JsonObject(); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java index 43e84a00fb..872190688c 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java @@ -29,7 +29,7 @@ public JsonElement serialize(WxCpTag tag, Type typeOfSrc, JsonSerializationConte @Override public WxCpTag deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { + throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); return new WxCpTag(GsonHelper.getString(jsonObject, "tagid"), GsonHelper.getString(jsonObject, "tagname")); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java index bbabf054e1..6531d07ba9 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java @@ -21,11 +21,9 @@ public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSeri @Override public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { + throws JsonParseException { JsonObject o = json.getAsJsonObject(); WxCpUser user = new WxCpUser(); - user.setUserId(GsonHelper.getString(o, "userid")); - user.setName(GsonHelper.getString(o, "name")); if (o.get("department") != null) { JsonArray departJsonArray = o.get("department").getAsJsonArray(); @@ -37,21 +35,26 @@ public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationC user.setDepartIds(departIds); } + user.setUserId(GsonHelper.getString(o, "userid")); + user.setName(GsonHelper.getString(o, "name")); user.setPosition(GsonHelper.getString(o, "position")); user.setMobile(GsonHelper.getString(o, "mobile")); - user.setGender(GsonHelper.getString(o, "gender")); - user.setTel(GsonHelper.getString(o, "tel")); + user.setGender(WxCpUser.Gender.fromCode(GsonHelper.getString(o, "gender"))); user.setEmail(GsonHelper.getString(o, "email")); - user.setWeiXinId(GsonHelper.getString(o, "weixinid")); user.setAvatar(GsonHelper.getString(o, "avatar")); user.setStatus(GsonHelper.getInteger(o, "status")); + user.setEnable(GsonHelper.getInteger(o, "enable")); + user.setIsLeader(GsonHelper.getInteger(o, "isleader")); + user.setHideMobile(GsonHelper.getInteger(o, "hide_mobile")); + user.setEnglishName(GsonHelper.getString(o, "english_name")); + user.setTelephone(GsonHelper.getString(o, "telephone")); if (GsonHelper.isNotNull(o.get("extattr"))) { JsonArray attrJsonElements = o.get("extattr").getAsJsonObject().get("attrs").getAsJsonArray(); for (JsonElement attrJsonElement : attrJsonElements) { WxCpUser.Attr attr = new WxCpUser.Attr( - GsonHelper.getString(attrJsonElement.getAsJsonObject(), "name"), - GsonHelper.getString(attrJsonElement.getAsJsonObject(), "value") + GsonHelper.getString(attrJsonElement.getAsJsonObject(), "name"), + GsonHelper.getString(attrJsonElement.getAsJsonObject(), "value") ); user.getExtAttrs().add(attr); } @@ -82,17 +85,11 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon o.addProperty("mobile", user.getMobile()); } if (user.getGender() != null) { - o.addProperty("gender", user.getGender()); - } - if (user.getTel() != null) { - o.addProperty("tel", user.getTel()); + o.addProperty("gender", user.getGender().getCode()); } if (user.getEmail() != null) { o.addProperty("email", user.getEmail()); } - if (user.getWeiXinId() != null) { - o.addProperty("weixinid", user.getWeiXinId()); - } if (user.getAvatar() != null) { o.addProperty("avatar", user.getAvatar()); } @@ -102,6 +99,18 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon if (user.getEnable() != null) { o.addProperty("enable", user.getEnable()); } + if (user.getIsLeader() != null) { + o.addProperty("isleader", user.getIsLeader()); + } + if (user.getHideMobile() != null) { + o.addProperty("hide_mobile", user.getHideMobile()); + } + if (user.getEnglishName() != null) { + o.addProperty("english_name", user.getEnglishName()); + } + if (user.getTelephone() != null) { + o.addProperty("telephone", user.getTelephone()); + } if (user.getExtAttrs().size() > 0) { JsonArray attrsJsonArray = new JsonArray(); for (WxCpUser.Attr attr : user.getExtAttrs()) { diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java index 2a694ff32f..179086f739 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java @@ -1,14 +1,16 @@ package me.chanjar.weixin.cp.api; -import java.io.IOException; -import java.io.InputStream; - import com.google.inject.Binder; import com.google.inject.Module; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; - import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.config.WxCpInMemoryConfigStorage; + +import java.io.IOException; +import java.io.InputStream; public class ApiTestModule implements Module { @@ -22,14 +24,14 @@ public static T fromXml(Class clazz, InputStream is) { @Override public void configure(Binder binder) { try (InputStream is1 = ClassLoader - .getSystemResourceAsStream("test-config.xml")) { + .getSystemResourceAsStream("test-config.xml")) { WxXmlCpInMemoryConfigStorage config = fromXml( - WxXmlCpInMemoryConfigStorage.class, is1); - WxCpServiceImpl wxService = new WxCpServiceImpl(); + WxXmlCpInMemoryConfigStorage.class, is1); + WxCpService wxService = new WxCpServiceImpl(); wxService.setWxCpConfigStorage(config); - binder.bind(WxCpServiceImpl.class).toInstance(wxService); - binder.bind(WxCpConfigStorage.class).toInstance(config); + binder.bind(WxCpService.class).toInstance(wxService); + binder.bind(WxXmlCpInMemoryConfigStorage.class).toInstance(config); } catch (IOException e) { e.printStackTrace(); } @@ -71,10 +73,10 @@ public void setTagId(String tagId) { @Override public String toString() { return super.toString() + " > WxXmlCpConfigStorage{" + - "userId='" + this.userId + '\'' + - ", departmentId='" + this.departmentId + '\'' + - ", tagId='" + this.tagId + '\'' + - '}'; + "userId='" + this.userId + '\'' + + ", departmentId='" + this.departmentId + '\'' + + ", tagId='" + this.tagId + '\'' + + '}'; } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java index 894bb3b67d..b535634a45 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java @@ -2,6 +2,8 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import org.apache.commons.lang3.StringUtils; import org.testng.Assert; import org.testng.annotations.Guice; @@ -20,7 +22,7 @@ public class WxCpBaseAPITest { protected WxCpServiceImpl wxService; public void testRefreshAccessToken() throws WxErrorException { - WxCpConfigStorage configStorage = this.wxService.configStorage; + WxCpConfigStorage configStorage = this.wxService.getWxCpConfigStorage(); String before = configStorage.getAccessToken(); this.wxService.getAccessToken(false); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java index e1b005bd83..2c964d309c 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java @@ -3,6 +3,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -19,9 +20,9 @@ public Object[][] getService() { WxCpService service = new WxCpServiceImpl() { @Override - protected synchronized T executeInternal( - RequestExecutor executor, String uri, E data) - throws WxErrorException { + public synchronized T executeInternal( + RequestExecutor executor, String uri, E data) + throws WxErrorException { this.log.info("Executed"); WxError error = new WxError(); error.setErrorCode(-1); @@ -32,7 +33,7 @@ protected synchronized T executeInternal( service.setMaxRetryTimes(3); service.setRetrySleepMillis(500); return new Object[][]{ - new Object[]{service} + new Object[]{service} }; } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java deleted file mode 100644 index c0cc3251ae..0000000000 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java +++ /dev/null @@ -1,64 +0,0 @@ -package me.chanjar.weixin.cp.api; - -import java.util.List; - -import org.testng.Assert; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import com.google.inject.Inject; - -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.cp.bean.WxCpDepart; - -/** - * 测试部门接口 - * - * @author Daniel Qian - */ -@Test(groups = "departAPI", dependsOnGroups = "baseAPI") -@Guice(modules = ApiTestModule.class) -public class WxCpDepartAPITest { - - @Inject - protected WxCpServiceImpl wxCpService; - - protected WxCpDepart depart; - - public void testDepartCreate() throws WxErrorException { - WxCpDepart cpDepart = new WxCpDepart(); - cpDepart.setName("子部门" + System.currentTimeMillis()); - cpDepart.setParentId(1); - cpDepart.setOrder(1); - Integer departId = this.wxCpService.departCreate(cpDepart); - System.out.println(departId); - } - - @Test(dependsOnMethods = "testDepartCreate") - public void testDepartGet() throws WxErrorException { - System.out.println("=================获取部门"); - List departList = this.wxCpService.departGet(); - Assert.assertNotNull(departList); - Assert.assertTrue(departList.size() > 0); - for (WxCpDepart g : departList) { - this.depart = g; - System.out.println(this.depart.getId() + ":" + this.depart.getName()); - Assert.assertNotNull(g.getName()); - } - } - - @Test(dependsOnMethods = {"testDepartGet", "testDepartCreate"}) - public void testDepartUpdate() throws WxErrorException { - System.out.println("=================更新部门"); - this.depart.setName("子部门改名" + System.currentTimeMillis()); - this.wxCpService.departUpdate(this.depart); - } - - @Test(dependsOnMethods = "testDepartUpdate") - public void testDepartDelete() throws WxErrorException { - System.out.println("=================删除部门"); - System.out.println(this.depart.getId() + ":" + this.depart.getName()); - this.wxCpService.departDelete(this.depart.getId()); - } - -} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java deleted file mode 100644 index d9fb2605d0..0000000000 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java +++ /dev/null @@ -1,78 +0,0 @@ -package me.chanjar.weixin.cp.api; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import com.google.inject.Inject; - -import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.common.exception.WxErrorException; - -/** - * 测试多媒体文件上传下载 - * - * @author Daniel Qian - */ -//@Test(groups="mediaAPI", dependsOnGroups="baseAPI") -@Test -@Guice(modules = ApiTestModule.class) -public class WxCpMediaAPITest { - - @Inject - protected WxCpServiceImpl wxService; - - private List media_ids = new ArrayList<>(); - - @Test(dataProvider = "uploadMedia") - public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { - try (InputStream inputStream = ClassLoader - .getSystemResourceAsStream(fileName);) { - WxMediaUploadResult res = this.wxService.mediaUpload(mediaType, fileType, - inputStream); - Assert.assertNotNull(res.getType()); - Assert.assertNotNull(res.getCreatedAt()); - Assert.assertTrue( - res.getMediaId() != null || res.getThumbMediaId() != null); - - if (res.getMediaId() != null) { - this.media_ids.add(res.getMediaId()); - } - if (res.getThumbMediaId() != null) { - this.media_ids.add(res.getThumbMediaId()); - } - } - } - - @DataProvider - public Object[][] uploadMedia() { - return new Object[][]{ - new Object[]{WxConsts.MEDIA_IMAGE, TestConstants.FILE_JPG, "mm.jpeg"}, - new Object[]{WxConsts.MEDIA_VOICE, TestConstants.FILE_MP3, "mm.mp3"}, - new Object[]{WxConsts.MEDIA_VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, - new Object[]{WxConsts.MEDIA_FILE, TestConstants.FILE_JPG, "mm.jpeg"} - }; - } - - @Test(dependsOnMethods = {"testUploadMedia"}, dataProvider = "downloadMedia") - public void testDownloadMedia(String media_id) throws WxErrorException { - this.wxService.mediaDownload(media_id); - } - - @DataProvider - public Object[][] downloadMedia() { - Object[][] params = new Object[this.media_ids.size()][]; - for (int i = 0; i < this.media_ids.size(); i++) { - params[i] = new Object[]{this.media_ids.get(i)}; - } - return params; - } - -} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java index b7bcf7a377..ece6d5348b 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java @@ -1,43 +1,62 @@ package me.chanjar.weixin.cp.api; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - import com.google.inject.Inject; - import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; import me.chanjar.weixin.cp.bean.WxCpMessage; +import me.chanjar.weixin.cp.bean.WxCpMessageSendResult; +import org.testng.annotations.*; + +import static org.testng.Assert.*; /*** * 测试发送消息 * @author Daniel Qian * */ -@Test(groups = "customMessageAPI", dependsOnGroups = "baseAPI") +@Test(groups = "customMessageAPI") @Guice(modules = ApiTestModule.class) public class WxCpMessageAPITest { @Inject protected WxCpServiceImpl wxService; + private ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage; - public void testSendCustomMessage() throws WxErrorException { - ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlCpInMemoryConfigStorage) this.wxService.configStorage; - WxCpMessage message1 = new WxCpMessage(); - message1.setAgentId(configStorage.getAgentId()); - message1.setMsgType(WxConsts.CUSTOM_MSG_TEXT); - message1.setToUser(configStorage.getUserId()); - message1.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); - this.wxService.messageSend(message1); - - WxCpMessage message2 = WxCpMessage - .TEXT() - .agentId(configStorage.getAgentId()) - .toUser(configStorage.getUserId()) - .content("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World") - .build(); - this.wxService.messageSend(message2); + @BeforeTest + public void setup() { + configStorage = (ApiTestModule.WxXmlCpInMemoryConfigStorage) this.wxService.getWxCpConfigStorage(); + } + public void testSendMessage() throws WxErrorException { + WxCpMessage message = new WxCpMessage(); + message.setAgentId(configStorage.getAgentId()); + message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); + message.setToUser(configStorage.getUserId()); + message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); + + WxCpMessageSendResult messageSendResult = this.wxService.messageSend(message); + assertNotNull(messageSendResult); + System.out.println(messageSendResult); + System.out.println(messageSendResult.getInvalidPartyList()); + System.out.println(messageSendResult.getInvalidUserList()); + System.out.println(messageSendResult.getInvalidTagList()); } + public void testSendMessage1() throws WxErrorException { + WxCpMessage message = WxCpMessage + .TEXT() + .agentId(configStorage.getAgentId()) + .toUser(configStorage.getUserId()) + .content("欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World") + .build(); + + WxCpMessageSendResult messageSendResult = this.wxService.messageSend(message); + assertNotNull(messageSendResult); + System.out.println(messageSendResult); + System.out.println(messageSendResult.getInvalidPartyList()); + System.out.println(messageSendResult.getInvalidUserList()); + System.out.println(messageSendResult.getInvalidTagList()); + + } } 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 4b0fc56a92..e52101f508 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java @@ -3,6 +3,9 @@ import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.session.StandardSessionManager; import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.message.WxCpMessageHandler; +import me.chanjar.weixin.cp.message.WxCpMessageMatcher; +import me.chanjar.weixin.cp.message.WxCpMessageRouter; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; import org.testng.Assert; @@ -22,33 +25,33 @@ public class WxCpMessageRouterTest { @Test(enabled = false) public void prepare(boolean async, StringBuffer sb, WxCpMessageRouter router) { router - .rule() - .async(async) - .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1") - .handler(new WxEchoCpMessageHandler(sb, "COMBINE_4")) - .end() - .rule() - .async(async) - .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1") - .handler(new WxEchoCpMessageHandler(sb, "COMBINE_3")) - .end() - .rule() - .async(async) - .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK) - .handler(new WxEchoCpMessageHandler(sb, "COMBINE_2")) - .end() - .rule().async(async).msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoCpMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end() - .rule().async(async).event(WxConsts.EVT_CLICK).handler(new WxEchoCpMessageHandler(sb, WxConsts.EVT_CLICK)).end() - .rule().async(async).eventKey("KEY_1").handler(new WxEchoCpMessageHandler(sb, "KEY_1")).end() - .rule().async(async).content("CONTENT_1").handler(new WxEchoCpMessageHandler(sb, "CONTENT_1")).end() - .rule().async(async).rContent(".*bc.*").handler(new WxEchoCpMessageHandler(sb, "abcd")).end() - .rule().async(async).matcher(new WxCpMessageMatcher() { + .rule() + .async(async) + .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1") + .handler(new WxEchoCpMessageHandler(sb, "COMBINE_4")) + .end() + .rule() + .async(async) + .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1") + .handler(new WxEchoCpMessageHandler(sb, "COMBINE_3")) + .end() + .rule() + .async(async) + .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK) + .handler(new WxEchoCpMessageHandler(sb, "COMBINE_2")) + .end() + .rule().async(async).msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoCpMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end() + .rule().async(async).event(WxConsts.EVT_CLICK).handler(new WxEchoCpMessageHandler(sb, WxConsts.EVT_CLICK)).end() + .rule().async(async).eventKey("KEY_1").handler(new WxEchoCpMessageHandler(sb, "KEY_1")).end() + .rule().async(async).content("CONTENT_1").handler(new WxEchoCpMessageHandler(sb, "CONTENT_1")).end() + .rule().async(async).rContent(".*bc.*").handler(new WxEchoCpMessageHandler(sb, "abcd")).end() + .rule().async(async).matcher(new WxCpMessageMatcher() { @Override public boolean match(WxCpXmlMessage message) { return "strangeformat".equals(message.getFormat()); } }).handler(new WxEchoCpMessageHandler(sb, "matcher")).end() - .rule().async(async).handler(new WxEchoCpMessageHandler(sb, "ALL")).end(); + .rule().async(async).handler(new WxEchoCpMessageHandler(sb, "ALL")).end(); } @Test(dataProvider = "messages-1") @@ -138,16 +141,16 @@ public Object[][] messages2() { return new Object[][]{ - new Object[]{message1, WxConsts.XML_MSG_TEXT + ","}, - new Object[]{message2, WxConsts.EVT_CLICK + ","}, - new Object[]{message3, "KEY_1,"}, - new Object[]{message4, "CONTENT_1,"}, - new Object[]{message5, "ALL,"}, - new Object[]{message6, "abcd,"}, - new Object[]{message7, "matcher,"}, - new Object[]{c2, "COMBINE_2,"}, - new Object[]{c3, "COMBINE_3,"}, - new Object[]{c4, "COMBINE_4,"} + new Object[]{message1, WxConsts.XML_MSG_TEXT + ","}, + new Object[]{message2, WxConsts.EVT_CLICK + ","}, + new Object[]{message3, "KEY_1,"}, + new Object[]{message4, "CONTENT_1,"}, + new Object[]{message5, "ALL,"}, + new Object[]{message6, "abcd,"}, + new Object[]{message7, "matcher,"}, + new Object[]{c2, "COMBINE_2,"}, + new Object[]{c3, "COMBINE_3,"}, + new Object[]{c4, "COMBINE_4,"} }; } @@ -162,7 +165,7 @@ public Object[][] standardSessionManager() { ism.setBackgroundProcessorDelay(1); return new Object[][]{ - new Object[]{ism} + new Object[]{ism} }; } @@ -174,8 +177,8 @@ public void testSessionClean1(StandardSessionManager ism) throws InterruptedExce final WxCpMessageRouter router = new WxCpMessageRouter(null); router.setSessionManager(ism); router - .rule().async(false).handler(new WxSessionMessageHandler()).next() - .rule().async(false).handler(new WxSessionMessageHandler()).end(); + .rule().async(false).handler(new WxSessionMessageHandler()).next() + .rule().async(false).handler(new WxSessionMessageHandler()).end(); WxCpXmlMessage msg = new WxCpXmlMessage(); msg.setFromUserName("abc"); @@ -194,8 +197,8 @@ public void testSessionClean2(StandardSessionManager ism) throws InterruptedExce final WxCpMessageRouter router = new WxCpMessageRouter(null); router.setSessionManager(ism); router - .rule().async(false).handler(new WxSessionMessageHandler()).next() - .rule().async(true).handler(new WxSessionMessageHandler()).end(); + .rule().async(false).handler(new WxSessionMessageHandler()).next() + .rule().async(true).handler(new WxSessionMessageHandler()).end(); WxCpXmlMessage msg = new WxCpXmlMessage(); msg.setFromUserName("abc"); @@ -208,8 +211,8 @@ public void testSessionClean2(StandardSessionManager ism) throws InterruptedExce final WxCpMessageRouter router = new WxCpMessageRouter(null); router.setSessionManager(ism); router - .rule().async(true).handler(new WxSessionMessageHandler()).next() - .rule().async(false).handler(new WxSessionMessageHandler()).end(); + .rule().async(true).handler(new WxSessionMessageHandler()).next() + .rule().async(false).handler(new WxSessionMessageHandler()).end(); WxCpXmlMessage msg = new WxCpXmlMessage(); msg.setFromUserName("abc"); @@ -228,8 +231,8 @@ public void testSessionClean3(StandardSessionManager ism) throws InterruptedExce final WxCpMessageRouter router = new WxCpMessageRouter(null); router.setSessionManager(ism); router - .rule().async(true).handler(new WxSessionMessageHandler()).next() - .rule().async(true).handler(new WxSessionMessageHandler()).end(); + .rule().async(true).handler(new WxSessionMessageHandler()).next() + .rule().async(true).handler(new WxSessionMessageHandler()).end(); WxCpXmlMessage msg = new WxCpXmlMessage(); msg.setFromUserName("abc"); @@ -248,7 +251,7 @@ public void testSessionClean4(StandardSessionManager ism) throws InterruptedExce final WxCpMessageRouter router = new WxCpMessageRouter(null); router.setSessionManager(ism); router - .rule().async(false).handler(new WxSessionMessageHandler()).end(); + .rule().async(false).handler(new WxSessionMessageHandler()).end(); WxCpXmlMessage msg = new WxCpXmlMessage(); msg.setFromUserName("abc"); @@ -262,7 +265,7 @@ public void testSessionClean4(StandardSessionManager ism) throws InterruptedExce final WxCpMessageRouter router = new WxCpMessageRouter(null); router.setSessionManager(ism); router - .rule().async(true).handler(new WxSessionMessageHandler()).end(); + .rule().async(true).handler(new WxSessionMessageHandler()).end(); WxCpXmlMessage msg = new WxCpXmlMessage(); msg.setFromUserName("abc"); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java deleted file mode 100644 index aa26e9620a..0000000000 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java +++ /dev/null @@ -1,66 +0,0 @@ -package me.chanjar.weixin.cp.api; - -import com.google.inject.Inject; -import me.chanjar.weixin.cp.bean.WxCpTag; -import me.chanjar.weixin.cp.bean.WxCpUser; -import org.testng.Assert; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import java.util.ArrayList; -import java.util.List; - -@Test(groups = "departAPI", dependsOnGroups = "baseAPI") -@Guice(modules = ApiTestModule.class) -public class WxCpTagAPITest { - - @Inject - protected WxCpServiceImpl wxService; - - @Inject - protected WxCpConfigStorage configStorage; - - protected String tagId; - - public void testTagCreate() throws Exception { - this.tagId = this.wxService.tagCreate("测试标签4"); - System.out.println(this.tagId); - } - - @Test(dependsOnMethods = "testTagCreate") - public void testTagUpdate() throws Exception { - this.wxService.tagUpdate(this.tagId, "测试标签-改名"); - } - - @Test(dependsOnMethods = "testTagUpdate") - public void testTagGet() throws Exception { - List tags = this.wxService.tagGet(); - Assert.assertNotEquals(tags.size(), 0); - } - - @Test(dependsOnMethods = "testTagGet") - public void testTagAddUsers() throws Exception { - List userIds = new ArrayList<>(); - userIds.add(((ApiTestModule.WxXmlCpInMemoryConfigStorage) this.configStorage).getUserId()); - this.wxService.tagAddUsers(this.tagId, userIds, null); - } - - @Test(dependsOnMethods = "testTagAddUsers") - public void testTagGetUsers() throws Exception { - List users = this.wxService.tagGetUsers(this.tagId); - Assert.assertNotEquals(users.size(), 0); - } - - @Test(dependsOnMethods = "testTagGetUsers") - public void testTagRemoveUsers() throws Exception { - List userIds = new ArrayList<>(); - userIds.add(((ApiTestModule.WxXmlCpInMemoryConfigStorage) this.configStorage).getUserId()); - this.wxService.tagRemoveUsers(this.tagId, userIds); - } - - @Test(dependsOnMethods = "testTagRemoveUsers") - public void testTagDelete() throws Exception { - this.wxService.tagDelete(this.tagId); - } - -} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java deleted file mode 100644 index 4d5a7a91f0..0000000000 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java +++ /dev/null @@ -1,66 +0,0 @@ -package me.chanjar.weixin.cp.api; - -import com.google.inject.Inject; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.cp.bean.WxCpDepart; -import me.chanjar.weixin.cp.bean.WxCpUser; -import org.testng.Assert; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - -import java.util.List; - -/** - * 测试用户接口 - * - * @author Daniel Qian - */ -@Test(groups = "userAPI", dependsOnGroups = "baseAPI") -@Guice(modules = ApiTestModule.class) -public class WxCpUserAPITest { - - @Inject - protected WxCpServiceImpl wxCpService; - - protected WxCpDepart depart; - - public void testUserCreate() throws WxErrorException { - WxCpUser user = new WxCpUser(); - user.setUserId("some.woman"); - user.setName("Some Woman"); - user.setDepartIds(new Integer[]{9, 8}); - user.setEmail("none@none.com"); - user.setGender("女"); - user.setMobile("13560084979"); - user.setPosition("woman"); - user.setTel("3300393"); - user.addExtAttr("爱好", "table"); - this.wxCpService.userCreate(user); - } - - @Test(dependsOnMethods = "testUserCreate") - public void testUserUpdate() throws WxErrorException { - WxCpUser user = new WxCpUser(); - user.setUserId("some.woman"); - user.setName("Some Woman"); - user.addExtAttr("爱好", "table2"); - this.wxCpService.userUpdate(user); - } - - @Test(dependsOnMethods = "testUserUpdate") - public void testUserGet() throws WxErrorException { - WxCpUser user = this.wxCpService.userGet("some.woman"); - Assert.assertNotNull(user); - } - - @Test(dependsOnMethods = "testUserGet") - public void testDepartGetUsers() throws WxErrorException { - List users = this.wxCpService.departGetUsers(1, true, 0); - Assert.assertNotEquals(users.size(), 0); - } - - @Test(dependsOnMethods = "testDepartGetUsers") - public void testUserDelete() throws WxErrorException { - this.wxCpService.userDelete("some.woman"); - } -} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java new file mode 100644 index 0000000000..685f37444f --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java @@ -0,0 +1,66 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpDepart; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.List; + +import static org.testng.Assert.*; + +/** + *
    + *  Created by BinaryWang on 2017/6/24.
    + * 
    + * + * @author Binary Wang + */ +@Guice(modules = ApiTestModule.class) +public class WxCpDepartmentServiceImplTest { + @Inject + private WxCpService wxCpService; + + private WxCpDepart depart; + + @Test + public void testCreate() throws Exception { + WxCpDepart cpDepart = new WxCpDepart(); + cpDepart.setName("子部门" + System.currentTimeMillis()); + cpDepart.setParentId(1); + cpDepart.setOrder(1); + Integer departId = this.wxCpService.getDepartmentService().create(cpDepart); + System.out.println(departId); + } + + @Test + public void testListAll() throws Exception { + System.out.println("=================获取部门"); + List departList = this.wxCpService.getDepartmentService().listAll(); + assertNotNull(departList); + assertTrue(departList.size() > 0); + for (WxCpDepart g : departList) { + this.depart = g; + System.out.println(this.depart.getId() + ":" + this.depart.getName()); + assertNotNull(g.getName()); + } + } + + @Test(dependsOnMethods = {"testListAll", "testCreate"}) + public void testUpdate() throws Exception { + System.out.println("=================更新部门"); + this.depart.setName("子部门改名" + System.currentTimeMillis()); + this.wxCpService.getDepartmentService().update(this.depart); + } + + @Test(dependsOnMethods = "testUpdate") + public void testDelete() throws Exception { + System.out.println("=================删除部门"); + System.out.println(this.depart.getId() + ":" + this.depart.getName()); + this.wxCpService.getDepartmentService().delete(this.depart.getId()); + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java new file mode 100644 index 0000000000..4bdb73413d --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java @@ -0,0 +1,78 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.TestConstants; +import me.chanjar.weixin.cp.api.WxCpService; +import org.testng.annotations.*; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import static org.testng.Assert.*; + +/** + *
    + *
    + * Created by Binary Wang on 2017-6-25.
    + * @author Binary Wang
    + * 
    + */ +@Guice(modules = ApiTestModule.class) +public class WxCpMediaServiceImplTest { + @Inject + private WxCpService wxService; + + private List mediaIds = new ArrayList<>(); + + @DataProvider + public Object[][] mediaData() { + return new Object[][]{ + new Object[]{WxConsts.MEDIA_IMAGE, TestConstants.FILE_JPG, "mm.jpeg"}, + new Object[]{WxConsts.MEDIA_VOICE, TestConstants.FILE_MP3, "mm.mp3"}, + new Object[]{WxConsts.MEDIA_VOICE, TestConstants.FILE_AMR, "mm.amr"},//{"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"} + new Object[]{WxConsts.MEDIA_VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, + new Object[]{WxConsts.MEDIA_FILE, TestConstants.FILE_JPG, "mm.jpeg"} + }; + } + + @Test(dataProvider = "mediaData") + public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { + try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)) { + WxMediaUploadResult res = this.wxService.getMediaService().upload(mediaType, fileType, inputStream); + assertNotNull(res.getType()); + assertNotNull(res.getCreatedAt()); + assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null); + + if (res.getMediaId() != null) { + this.mediaIds.add(res.getMediaId()); + } + if (res.getThumbMediaId() != null) { + this.mediaIds.add(res.getThumbMediaId()); + } + } + } + + @DataProvider + public Object[][] downloadMedia() { + Object[][] params = new Object[this.mediaIds.size()][]; + for (int i = 0; i < this.mediaIds.size(); i++) { + params[i] = new Object[]{this.mediaIds.get(i)}; + } + return params; + } + + @Test(dependsOnMethods = {"testUploadMedia"}, dataProvider = "downloadMedia") + public void testDownloadMedia(String media_id) throws WxErrorException { + File file = this.wxService.getMediaService().download(media_id); + assertNotNull(file); + System.out.println(file); + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImplTest.java similarity index 60% rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImplTest.java index c837e51e1d..def6419820 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImplTest.java @@ -1,44 +1,29 @@ -package me.chanjar.weixin.cp.api; +package me.chanjar.weixin.cp.api.impl; import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.menu.WxMenuButton; -import me.chanjar.weixin.common.exception.WxErrorException; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Guice; -import org.testng.annotations.Test; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.WxCpService; +import org.testng.annotations.*; + +import static org.testng.Assert.*; /** - * 测试菜单 + *
      *
    - * @author Daniel Qian
    + * Created by Binary Wang on 2017-6-25.
    + * @author Binary Wang
    + * 
    */ -@Test(groups = "menuAPI", dependsOnGroups = "baseAPI") @Guice(modules = ApiTestModule.class) -public class WxMenuAPITest { - +public class WxCpMenuServiceImplTest { @Inject - protected WxCpServiceImpl wxService; - - @Test(dataProvider = "menu") - public void testCreateMenu(WxMenu wxMenu) throws WxErrorException { - this.wxService.menuCreate(wxMenu); - } + protected WxCpService wxService; - @Test(dependsOnMethods = {"testCreateMenu"}) - public void testGetMenu() throws WxErrorException { - Assert.assertNotNull(this.wxService.menuGet()); - } - - @Test(dependsOnMethods = {"testGetMenu"}) - public void testDeleteMenu() throws WxErrorException { - this.wxService.menuDelete(); - } - - @DataProvider(name = "menu") - public Object[][] getMenu() { + @DataProvider + public Object[][] menuData() { WxMenu menu = new WxMenu(); WxMenuButton button1 = new WxMenuButton(); button1.setType(WxConsts.BUTTON_CLICK); @@ -77,12 +62,28 @@ public Object[][] getMenu() { button3.getSubButtons().add(button33); return new Object[][]{ - new Object[]{ - menu - } + new Object[]{ + menu + } }; } + @Test(dataProvider = "menuData") + public void testCreate(WxMenu wxMenu) throws Exception { + this.wxService.getMenuService().create(wxMenu); + } + + @Test(dependsOnMethods = "testCreate") + public void testGet() throws Exception { + WxMenu menu = this.wxService.getMenuService().get(); + assertNotNull(menu); + System.out.println(menu.toJson()); + } + + @Test(dependsOnMethods = {"testGet", "testCreate"}) + public void testDelete() throws Exception { + this.wxService.getMenuService().delete(); + } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java new file mode 100644 index 0000000000..94ac3b09db --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java @@ -0,0 +1,75 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.common.base.Splitter; +import com.google.inject.Inject; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpTag; +import me.chanjar.weixin.cp.bean.WxCpTagAddOrRemoveUsersResult; +import me.chanjar.weixin.cp.bean.WxCpUser; +import org.testng.annotations.*; + +import java.util.List; + +import static org.testng.Assert.*; + +/** + *
    + *
    + * Created by Binary Wang on 2017-6-25.
    + * @author Binary Wang
    + * 
    + */ +@Guice(modules = ApiTestModule.class) +public class WxCpTagServiceImplTest { + @Inject + protected WxCpService wxService; + + @Inject + protected ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage; + + protected String tagId; + + @Test + public void testCreate() throws Exception { + this.tagId = this.wxService.getTagService().create("测试标签" + System.currentTimeMillis()); + System.out.println(this.tagId); + } + + @Test(dependsOnMethods = "testCreate") + public void testUpdate() throws Exception { + this.wxService.getTagService().update(this.tagId, "测试标签-改名" + System.currentTimeMillis()); + } + + @Test(dependsOnMethods = {"testUpdate", "testCreate"}) + public void testListAll() throws Exception { + List tags = this.wxService.getTagService().listAll(); + assertNotEquals(tags.size(), 0); + } + + @Test(dependsOnMethods = {"testListAll", "testUpdate", "testCreate"}) + public void testAddUsers2Tag() throws Exception { + List userIds = Splitter.on("|").splitToList(this.configStorage.getUserId()); + WxCpTagAddOrRemoveUsersResult result = this.wxService.getTagService().addUsers2Tag(this.tagId, userIds, null); + assertEquals(result.getErrCode(), Integer.valueOf(0)); + } + + @Test(dependsOnMethods = {"testAddUsers2Tag", "testListAll", "testUpdate", "testCreate"}) + public void testListUsersByTagId() throws Exception { + List users = this.wxService.getTagService().listUsersByTagId(this.tagId); + assertNotEquals(users.size(), 0); + } + + @Test(dependsOnMethods = {"testListUsersByTagId", "testAddUsers2Tag", "testListAll", "testUpdate", "testCreate"}) + public void testRemoveUsersFromTag() throws Exception { + List userIds = Splitter.on("|").splitToList(this.configStorage.getUserId()); + WxCpTagAddOrRemoveUsersResult result = this.wxService.getTagService().removeUsersFromTag(this.tagId, userIds); + assertEquals(result.getErrCode(), Integer.valueOf(0)); + } + + @Test(dependsOnMethods = {"testRemoveUsersFromTag", "testListUsersByTagId", "testAddUsers2Tag", "testListAll", "testUpdate", "testCreate"}) + public void testDelete() throws Exception { + this.wxService.getTagService().delete(this.tagId); + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java new file mode 100644 index 0000000000..a01f03436e --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java @@ -0,0 +1,86 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpUser; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.testng.annotations.*; + +import java.util.List; + +import static org.testng.Assert.*; + +/** + *
    + *  Created by BinaryWang on 2017/6/24.
    + * 
    + * + * @author Binary Wang + */ +@Guice(modules = ApiTestModule.class) +public class WxCpUserServiceImplTest { + @Inject + private WxCpService wxCpService; + private String userId = "someone" + System.currentTimeMillis(); + + @Test + public void testAuthenticate() throws Exception { + this.wxCpService.getUserService().authenticate("abc"); + } + + @Test + public void testCreate() throws Exception { + WxCpUser user = new WxCpUser(); + user.setUserId(userId); + user.setName("Some Woman"); + user.setDepartIds(new Integer[]{2}); + user.setEmail("none@none.com"); + user.setGender(WxCpUser.Gender.FEMAIL); + user.setMobile("13560084979"); + user.setPosition("woman"); + user.setTelephone("3300393"); + user.addExtAttr("爱好", "table"); + this.wxCpService.getUserService().create(user); + } + + @Test(dependsOnMethods = "testCreate") + public void testUpdate() throws Exception { + WxCpUser user = new WxCpUser(); + user.setUserId(userId); + user.setName("Some Woman"); + user.addExtAttr("爱好", "table2"); + this.wxCpService.getUserService().update(user); + } + + @Test(dependsOnMethods = {"testCreate", "testUpdate"}) + public void testDelete() throws Exception { + this.wxCpService.getUserService().delete(userId); + } + + @Test(dependsOnMethods = "testUpdate") + public void testGetById() throws Exception { + WxCpUser user = this.wxCpService.getUserService().getById(userId); + assertNotNull(user); + } + + @Test + public void testListByDepartment() throws Exception { + List users = this.wxCpService.getUserService().listByDepartment(1, true, 0); + assertNotEquals(users.size(), 0); + for (WxCpUser user : users) { + System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); + } + } + + @Test + public void testListSimpleByDepartment() throws Exception { + List users = this.wxCpService.getUserService().listSimpleByDepartment(1, true, 0); + assertNotEquals(users.size(), 0); + for (WxCpUser user : users) { + System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); + } + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java index ce75b06690..f41f3a55a7 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java @@ -1,9 +1,8 @@ package me.chanjar.weixin.cp.bean; import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.cp.bean.article.NewArticle; import me.chanjar.weixin.cp.bean.article.MpnewsArticle; -import org.testng.Assert; +import me.chanjar.weixin.cp.bean.article.NewArticle; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java index 270fa1d349..74b526160b 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java @@ -10,49 +10,49 @@ public class WxCpXmlMessageTest { public void testFromXml() { String xml = "" - + "" - + " " - + "1348831860" - + "" - + "" - + "1234567890123456" - + "" - + "" - + "" - + "" - + "23.134521" - + "113.358803" - + "20" - + "" - + "" - + "" - + "<![CDATA[公众平台官网链接]]>" - + "" - + "" - + "" - + "23.137466" - + "113.352425" - + "119.385040" - + "" - + " " - + " " - + "" - + "" - + " 1\n" - + " " - + " " - + " " - + " " - + " " - + "" - + "" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + "" - + ""; + + "" + + " " + + "1348831860" + + "" + + "" + + "1234567890123456" + + "" + + "" + + "" + + "" + + "23.134521" + + "113.358803" + + "20" + + "" + + "" + + "" + + "<![CDATA[公众平台官网链接]]>" + + "" + + "" + + "" + + "23.137466" + + "113.352425" + + "119.385040" + + "" + + " " + + " " + + "" + + "" + + " 1\n" + + " " + + " " + + " " + + " " + + " " + + "" + + "" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "" + + ""; WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml); Assert.assertEquals(wxMessage.getToUserName(), "toUser"); Assert.assertEquals(wxMessage.getFromUserName(), "fromUser"); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java index 8ace5d0aae..6f366988eb 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java @@ -14,12 +14,12 @@ public void test() { m.setToUserName("to"); String expected = "" - + "" - + "" - + "1122" - + "" - + "" - + ""; + + "" + + "" + + "1122" + + "" + + "" + + ""; System.out.println(m.toXml()); Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); } @@ -27,21 +27,21 @@ public void test() { public void testBuild() { WxCpXmlOutImageMessage m = WxCpXmlOutMessage.IMAGE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); String expected = "" - + "" - + "" - + "1122" - + "" - + "" - + ""; + + "" + + "" + + "1122" + + "" + + "" + + ""; System.out.println(m.toXml()); Assert.assertEquals( - m - .toXml() - .replaceAll("\\s", "") - .replaceAll(".*?", ""), - expected - .replaceAll("\\s", "") - .replaceAll(".*?", "") + m + .toXml() + .replaceAll("\\s", "") + .replaceAll(".*?", ""), + expected + .replaceAll("\\s", "") + .replaceAll(".*?", "") ); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java index 872c0ac327..71dbf4125d 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java @@ -21,26 +21,26 @@ public void test() { m.addArticle(item); String expected = "" - + "" - + "" - + "1122" - + "" - + " " - + " " - + " <![CDATA[title]]>" - + " " - + " " - + " " - + " " - + " " - + " <![CDATA[title]]>" - + " " - + " " - + " " - + " " - + " " - + " 2" - + ""; + + "" + + "" + + "1122" + + "" + + " " + + " " + + " <![CDATA[title]]>" + + " " + + " " + + " " + + " " + + " " + + " <![CDATA[title]]>" + + " " + + " " + + " " + + " " + + " " + + " 2" + + ""; System.out.println(m.toXml()); Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); } @@ -53,41 +53,41 @@ public void testBuild() { item.setUrl("url"); WxCpXmlOutNewsMessage m = WxCpXmlOutMessage.NEWS() - .fromUser("fromUser") - .toUser("toUser") - .addArticle(item) - .addArticle(item) - .build(); + .fromUser("fromUser") + .toUser("toUser") + .addArticle(item) + .addArticle(item) + .build(); String expected = "" - + "" - + "" - + "1122" - + "" - + " " - + " " - + " <![CDATA[title]]>" - + " " - + " " - + " " - + " " - + " " - + " <![CDATA[title]]>" - + " " - + " " - + " " - + " " - + " " - + " 2" - + ""; + + "" + + "" + + "1122" + + "" + + " " + + " " + + " <![CDATA[title]]>" + + " " + + " " + + " " + + " " + + " " + + " <![CDATA[title]]>" + + " " + + " " + + " " + + " " + + " " + + " 2" + + ""; System.out.println(m.toXml()); Assert.assertEquals( - m - .toXml() - .replaceAll("\\s", "") - .replaceAll(".*?", ""), - expected - .replaceAll("\\s", "") - .replaceAll(".*?", "") + m + .toXml() + .replaceAll("\\s", "") + .replaceAll(".*?", ""), + expected + .replaceAll("\\s", "") + .replaceAll(".*?", "") ); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java index 57fcf8eb98..4d73b27f5b 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java @@ -14,12 +14,12 @@ public void test() { m.setToUserName("to"); String expected = "" - + "" - + "" - + "1122" - + "" - + "" - + ""; + + "" + + "" + + "1122" + + "" + + "" + + ""; System.out.println(m.toXml()); Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); } @@ -27,21 +27,21 @@ public void test() { public void testBuild() { WxCpXmlOutTextMessage m = WxCpXmlOutMessage.TEXT().content("content").fromUser("from").toUser("to").build(); String expected = "" - + "" - + "" - + "1122" - + "" - + "" - + ""; + + "" + + "" + + "1122" + + "" + + "" + + ""; System.out.println(m.toXml()); Assert.assertEquals( - m - .toXml() - .replaceAll("\\s", "") - .replaceAll(".*?", ""), - expected - .replaceAll("\\s", "") - .replaceAll(".*?", "") + m + .toXml() + .replaceAll("\\s", "") + .replaceAll(".*?", ""), + expected + .replaceAll("\\s", "") + .replaceAll(".*?", "") ); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java index 512dfef3b7..b4124c6130 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java @@ -16,48 +16,48 @@ public void test() { m.setToUserName("toUser"); String expected = "" - + "" - + "" - + "1122" - + "" - + " " - + ""; + + "" + + "" + + "1122" + + "" + + " " + + ""; System.out.println(m.toXml()); Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); } public void testBuild() { WxCpXmlOutVideoMessage m = WxCpXmlOutMessage.VIDEO() - .mediaId("media_id") - .fromUser("fromUser") - .toUser("toUser") - .title("title") - .description("ddfff") - .build(); + .mediaId("media_id") + .fromUser("fromUser") + .toUser("toUser") + .title("title") + .description("ddfff") + .build(); String expected = "" - + "" - + "" - + "1122" - + "" - + " " - + ""; + + "" + + "" + + "1122" + + "" + + " " + + ""; System.out.println(m.toXml()); Assert.assertEquals( - m - .toXml() - .replaceAll("\\s", "") - .replaceAll(".*?", ""), - expected - .replaceAll("\\s", "") - .replaceAll(".*?", "") + m + .toXml() + .replaceAll("\\s", "") + .replaceAll(".*?", ""), + expected + .replaceAll("\\s", "") + .replaceAll(".*?", "") ); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java index 26db29c3c3..f414256a5f 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java @@ -14,12 +14,12 @@ public void test() { m.setToUserName("to"); String expected = "" - + "" - + "" - + "1122" - + "" - + "" - + ""; + + "" + + "" + + "1122" + + "" + + "" + + ""; System.out.println(m.toXml()); Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); } @@ -27,21 +27,21 @@ public void test() { public void testBuild() { WxCpXmlOutVoiceMessage m = WxCpXmlOutMessage.VOICE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); String expected = "" - + "" - + "" - + "1122" - + "" - + "" - + ""; + + "" + + "" + + "1122" + + "" + + "" + + ""; System.out.println(m.toXml()); Assert.assertEquals( - m - .toXml() - .replaceAll("\\s", "") - .replaceAll(".*?", ""), - expected - .replaceAll("\\s", "") - .replaceAll(".*?", "") + m + .toXml() + .replaceAll("\\s", "") + .replaceAll(".*?", ""), + expected + .replaceAll("\\s", "") + .replaceAll(".*?", "") ); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java index 9a97b6cd11..93ff1bbc0a 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java @@ -3,7 +3,7 @@ import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.util.xml.XStreamInitializer; -import me.chanjar.weixin.cp.api.WxCpInMemoryConfigStorage; +import me.chanjar.weixin.cp.config.WxCpInMemoryConfigStorage; import java.io.InputStream; @@ -22,7 +22,7 @@ public static WxCpDemoInMemoryConfigStorage fromXml(InputStream is) { @Override public String toString() { return "SimpleWxConfigProvider [appidOrCorpid=" + this.corpId + ", corpSecret=" + this.corpSecret + ", accessToken=" + this.accessToken - + ", expiresTime=" + this.expiresTime + ", token=" + this.token + ", aesKey=" + this.aesKey + "]"; + + ", expiresTime=" + this.expiresTime + ", token=" + this.token + ", aesKey=" + this.aesKey + "]"; } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java index dc667d88ba..a9ab309c37 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java @@ -1,22 +1,21 @@ package me.chanjar.weixin.cp.demo; -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; - -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.ServletHandler; -import org.eclipse.jetty.servlet.ServletHolder; - import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.WxCpMessageHandler; -import me.chanjar.weixin.cp.api.WxCpMessageRouter; import me.chanjar.weixin.cp.api.WxCpService; -import me.chanjar.weixin.cp.api.WxCpServiceImpl; +import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.message.WxCpMessageHandler; +import me.chanjar.weixin.cp.message.WxCpMessageRouter; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; public class WxCpDemoServer { @@ -44,9 +43,9 @@ public static void main(String[] args) throws Exception { private static void initWeixin() throws IOException { try (InputStream is1 = ClassLoader - .getSystemResourceAsStream("test-config.xml")) { + .getSystemResourceAsStream("test-config.xml")) { WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage - .fromXml(is1); + .fromXml(is1); wxCpConfigStorage = config; wxCpService = new WxCpServiceImpl(); @@ -55,11 +54,11 @@ private static void initWeixin() throws IOException { WxCpMessageHandler handler = new WxCpMessageHandler() { @Override public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, - Map context, WxCpService wxService, - WxSessionManager sessionManager) { + Map context, WxCpService wxService, + WxSessionManager sessionManager) { WxCpXmlOutTextMessage m = WxCpXmlOutMessage.TEXT().content("测试加密消息") - .fromUser(wxMessage.getToUserName()) - .toUser(wxMessage.getFromUserName()).build(); + .fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()).build(); return m; } }; @@ -67,22 +66,21 @@ public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, WxCpMessageHandler oauth2handler = new WxCpMessageHandler() { @Override public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, - Map context, WxCpService wxService, - WxSessionManager sessionManager) { + Map context, WxCpService wxService, + WxSessionManager sessionManager) { String href = "测试oauth2"; + + wxService.getOauth2Service().buildAuthorizationUrl(wxCpConfigStorage.getOauth2redirectUri(), null) + + "\">测试oauth2"; return WxCpXmlOutMessage.TEXT().content(href) - .fromUser(wxMessage.getToUserName()) - .toUser(wxMessage.getFromUserName()).build(); + .fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()).build(); } }; wxCpMessageRouter = new WxCpMessageRouter(wxCpService); wxCpMessageRouter.rule().async(false).content("哈哈") // 拦截内容为“哈哈”的消息 - .handler(handler).end().rule().async(false).content("oauth") - .handler(oauth2handler).end(); + .handler(handler).end().rule().async(false).content("oauth") + .handler(oauth2handler).end(); } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java index 43bf179943..291cef403d 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.cp.demo; -import me.chanjar.weixin.cp.api.WxCpConfigStorage; -import me.chanjar.weixin.cp.api.WxCpMessageRouter; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.message.WxCpMessageRouter; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; @@ -31,7 +31,7 @@ public WxCpEndpointServlet(WxCpConfigStorage wxCpConfigStorage, WxCpService wxCp @Override protected void service(HttpServletRequest request, HttpServletResponse response) - throws IOException { + throws IOException { response.setContentType("text/html;charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); @@ -55,7 +55,7 @@ protected void service(HttpServletRequest request, HttpServletResponse response) } WxCpXmlMessage inMessage = WxCpXmlMessage - .fromEncryptedXml(request.getInputStream(), this.wxCpConfigStorage, timestamp, nonce, msgSignature); + .fromEncryptedXml(request.getInputStream(), this.wxCpConfigStorage, timestamp, nonce, msgSignature); WxCpXmlOutMessage outMessage = this.wxCpMessageRouter.route(inMessage); if (outMessage != null) { response.getWriter().write(outMessage.toEncryptedXml(this.wxCpConfigStorage)); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java index edab896644..37c2b7a12f 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java @@ -1,14 +1,13 @@ package me.chanjar.weixin.cp.demo; -import java.io.IOException; -import java.util.Arrays; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpService; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.cp.api.WxCpService; +import java.io.IOException; +import java.util.Arrays; public class WxCpOAuth2Servlet extends HttpServlet { private static final long serialVersionUID = 1L; @@ -21,7 +20,7 @@ public WxCpOAuth2Servlet(WxCpService wxCpService) { @Override protected void service(HttpServletRequest request, HttpServletResponse response) - throws IOException { + throws IOException { response.setContentType("text/html;charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); @@ -31,7 +30,7 @@ protected void service(HttpServletRequest request, HttpServletResponse response) response.getWriter().println("

    code

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

    result

    "); response.getWriter().println(Arrays.toString(res)); } catch (WxErrorException e) { diff --git a/weixin-java-cp/src/test/resources/logback-test.xml b/weixin-java-cp/src/test/resources/logback-test.xml index 9c2ec6ae38..ec3deca97f 100644 --- a/weixin-java-cp/src/test/resources/logback-test.xml +++ b/weixin-java-cp/src/test/resources/logback-test.xml @@ -1,16 +1,14 @@ - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %-5level %replace(%caller{1}){'Caller', ''} - %msg%n - + - + diff --git a/weixin-java-cp/src/test/resources/mm.amr b/weixin-java-cp/src/test/resources/mm.amr new file mode 100644 index 0000000000..a4df01a0d9 Binary files /dev/null and b/weixin-java-cp/src/test/resources/mm.amr differ diff --git a/weixin-java-cp/src/test/resources/test-config.sample.xml b/weixin-java-cp/src/test/resources/test-config.sample.xml index aa99a962bd..6f98ebafc1 100644 --- a/weixin-java-cp/src/test/resources/test-config.sample.xml +++ b/weixin-java-cp/src/test/resources/test-config.sample.xml @@ -1,13 +1,13 @@ - 企业号corpid - 企业号corpsecret - 企业号应用id - 企业号应用Token - 企业号应用EncodingAESKey - 可以不填写 - 可以不填写 - 企业号通讯录里的某个userid - 企业号通讯录的某个部门id - 企业号通讯录里的某个tagid - 网页授权获取用户信息回调地址 + 企业号corpid + 企业号corpsecret + 企业号应用id + 企业号应用Token + 企业号应用EncodingAESKey + 可以不填写 + 可以不填写 + 企业号通讯录里的某个userid + 企业号通讯录的某个部门id + 企业号通讯录里的某个tagid + 网页授权获取用户信息回调地址 diff --git a/weixin-java-cp/src/test/resources/testng.xml b/weixin-java-cp/src/test/resources/testng.xml index ba92bc0c0c..ffa8a2edff 100644 --- a/weixin-java-cp/src/test/resources/testng.xml +++ b/weixin-java-cp/src/test/resources/testng.xml @@ -6,12 +6,7 @@ - - - - - diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml new file mode 100644 index 0000000000..71601ef3a4 --- /dev/null +++ b/weixin-java-miniapp/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + com.github.binarywang + weixin-java-parent + 2.7.0 + + weixin-java-miniapp + WeiXin Java Tools - MiniApp + 微信小程序Java SDK + + + + com.github.binarywang + weixin-java-common + ${project.version} + + + + org.jodd + jodd-http + provided + + + com.squareup.okhttp3 + okhttp + provided + + + + org.testng + testng + test + + + ch.qos.logback + logback-classic + test + + + com.google.inject + guice + test + + + org.eclipse.jetty + jetty-server + test + + + org.eclipse.jetty + jetty-servlet + test + + + joda-time + joda-time + test + + + redis.clients + jedis + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + src/test/resources/testng.xml + + + + + + + diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMediaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMediaService.java new file mode 100644 index 0000000000..09c8aa5b9d --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMediaService.java @@ -0,0 +1,65 @@ +package cn.binarywang.wx.miniapp.api; + +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.File; +import java.io.InputStream; + +/** + *
    + * 临时素材接口
    + * Created by Binary Wang on 2016/7/21.
    + * 
    + * + * @author Binary Wang + */ +public interface WxMaMediaService { + String MEDIA_UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?type=%s"; + String MEDIA_GET_URL = "https://api.weixin.qq.com/cgi-bin/media/get"; + + /** + *
    +   * 新增临时素材
    +   * 小程序可以使用本接口把媒体文件(目前仅支持图片)上传到微信服务器,用户发送客服消息或被动回复用户消息。
    +   * 详情请见: 新增临时素材
    +   * 接口url格式:https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
    +   * 
    + * + * @param mediaType 媒体类型, + * @param file 文件对象 + * @see #uploadMedia(String, String, InputStream) + */ + WxMediaUploadResult uploadMedia(String mediaType, File file) throws WxErrorException; + + /** + *
    +   * 新增临时素材
    +   * 小程序可以使用本接口把媒体文件(目前仅支持图片)上传到微信服务器,用户发送客服消息或被动回复用户消息。
    +   *
    +   * 详情请见: 新增临时素材
    +   * 接口url格式:https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
    +   * 
    + * + * @param mediaType 媒体类型 + * @param fileType 文件类型 + * @param inputStream 输入流 + * @see #uploadMedia(java.lang.String, java.io.File) + */ + WxMediaUploadResult uploadMedia(String mediaType, String fileType, InputStream inputStream) throws WxErrorException; + + /** + *
    +   * 获取临时素材
    +   * 小程序可以使用本接口获取客服消息内的临时素材(即下载临时的多媒体文件)。目前小程序仅支持下载图片文件。
    +   *
    +   * 详情请见: 获取临时素材
    +   * 接口url格式:https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
    +   * 
    + * + * @param mediaId 媒体Id + * @return 保存到本地的临时文件 + */ + File getMedia(String mediaId) throws WxErrorException; + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java new file mode 100644 index 0000000000..040e81e530 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaMsgService.java @@ -0,0 +1,36 @@ +package cn.binarywang.wx.miniapp.api; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + *
    + * 消息发送接口
    + * 
    + * + * @author Binary Wang + */ +public interface WxMaMsgService { + String KEFU_MESSAGE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; + String TEMPLATE_MSG_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send"; + + /** + *
    +   * 发送客服消息
    +   * 详情请见: 发送客服消息
    +   * 接口url格式:https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
    +   * 
    + */ + boolean sendKefuMsg(WxMaKefuMessage message) throws WxErrorException; + + /** + *
    +   * 发送模板消息
    +   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN
    +   * 
    + * + * @return 消息Id + */ + String sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException; +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java new file mode 100644 index 0000000000..822f5de8a4 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java @@ -0,0 +1,30 @@ +package cn.binarywang.wx.miniapp.api; + +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.File; + +/** + *
    + * 二维码相关操作接口
    + * 文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html
    + * 
    + * + * @author Binary Wang + */ +public interface WxMaQrcodeService { + + /** + *
    +   * 获取小程序页面二维码
    +   * 适用于需要的码数量较少的业务场景
    +   * 通过该接口,仅能生成已发布的小程序的二维码。
    +   * 可以在开发者工具预览时生成开发版的带参二维码。
    +   * 带参二维码只有 100000 个,请谨慎调用。
    +   * 
    + * + * @param path 不能为空,最大长度 128 字节 + * @param width 默认430 二维码的宽度 + */ + File createQrcode(String path, int width) throws WxErrorException; +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java new file mode 100644 index 0000000000..9098d4ac48 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java @@ -0,0 +1,135 @@ +package cn.binarywang.wx.miniapp.api; + +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; + +/** + * @author Binary Wang + */ +public interface WxMaService { + /** + * 获取access_token + */ + String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; + + /** + *
    +   * 验证消息的确来自微信服务器
    +   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
    +   * 
    + */ + boolean checkSignature(String timestamp, String nonce, String signature); + + /** + * 获取access_token, 不强制刷新access_token + * + * @see #getAccessToken(boolean) + */ + String getAccessToken() throws WxErrorException; + + /** + *
    +   * 获取access_token,本方法线程安全
    +   * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
    +   *
    +   * 另:本service的所有方法都会在access_token过期是调用此方法
    +   *
    +   * 程序员在非必要情况下尽量不要主动调用此方法
    +   *
    +   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN
    +   * 
    + * + * @param forceRefresh 强制刷新 + */ + String getAccessToken(boolean forceRefresh) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 + */ + String get(String url, String queryParam) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 + */ + String post(String url, String postData) throws WxErrorException; + + /** + *
    +   * Service没有实现某个API的时候,可以用这个,
    +   * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
    +   * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
    +   * 
    + */ + T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + + /** + *
    +   * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试
    +   * 默认:1000ms
    +   * 
    + */ + void setRetrySleepMillis(int retrySleepMillis); + + /** + *
    +   * 设置当微信系统响应系统繁忙时,最大重试次数
    +   * 默认:5次
    +   * 
    + */ + void setMaxRetryTimes(int maxRetryTimes); + + /** + * 获取WxMaConfig 对象 + * + * @return WxMaConfig + */ + WxMaConfig getWxMaConfig(); + + /** + * 注入 {@link WxMaConfig} 的实现 + */ + void setWxMaConfig(WxMaConfig wxConfigProvider); + + /** + * 返回消息(客服消息和模版消息)发送接口方法实现类,以方便调用其各个接口 + * + * @return WxMaMsgService + */ + WxMaMsgService getMsgService(); + + /** + * 返回素材相关接口方法的实现类对象,以方便调用其各个接口 + * + * @return WxMaMediaService + */ + WxMaMediaService getMediaService(); + + /** + * 返回用户相关接口方法的实现类对象,以方便调用其各个接口 + * + * @return WxMaUserService + */ + WxMaUserService getUserService(); + + /** + * 返回二维码相关接口方法的实现类对象,以方便调用其各个接口 + * + * @return WxMaQrcodeService + */ + WxMaQrcodeService getQrcodeService(); + + /** + * 初始化http请求对象 + */ + void initHttp(); + + /** + * 请求http请求相关信息 + */ + RequestHttp getRequestHttp(); + + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java new file mode 100644 index 0000000000..84b17378ca --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java @@ -0,0 +1,39 @@ +package cn.binarywang.wx.miniapp.api; + +import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; +import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + * 用户信息相关操作接口 + * + * @author Binary Wang + */ +public interface WxMaUserService { + String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session"; + + /** + * 获取登录后的session信息 + * + * @param jsCode 登录时获取的 code + */ + WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException; + + /** + * 解密用户敏感数据 + * + * @param sessionKey 会话密钥 + * @param encryptedData 消息密文 + * @param ivStr 加密算法的初始向量 + */ + WxMaUserInfo getUserInfo(String sessionKey, String encryptedData, String ivStr); + + /** + * 验证用户信息完整性 + * + * @param sessionKey 会话密钥 + * @param rawData 微信用户基本信息 + * @param signature 数据签名 + */ + boolean checkUserInfo(String sessionKey, String rawData, String signature); +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImpl.java new file mode 100644 index 0000000000..66ad3c2a91 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImpl.java @@ -0,0 +1,61 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaMediaService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.UUID; + +/** + * @author Binary Wang + */ +public class WxMaMediaServiceImpl implements WxMaMediaService { + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private WxMaService wxMaService; + + public WxMaMediaServiceImpl(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + @Override + public WxMediaUploadResult uploadMedia(String mediaType, String fileType, InputStream inputStream) throws WxErrorException { + try { + return this.uploadMedia(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); + } catch (IOException e) { + e.printStackTrace(); + throw new WxErrorException(WxError.newBuilder().setErrorMsg(e.getMessage()).build()); + } + } + + @Override + public WxMediaUploadResult uploadMedia(String mediaType, File file) throws WxErrorException { + String url = String.format(MEDIA_UPLOAD_URL, mediaType); + return this.wxMaService.execute(MediaUploadRequestExecutor.create(this.wxMaService.getRequestHttp()), url, file); + } + + @Override + public File getMedia(String mediaId) throws WxErrorException { + try { + RequestExecutor executor = MediaDownloadRequestExecutor + .create(this.wxMaService.getRequestHttp(), Files.createTempDirectory("wxma").toFile()); + return this.wxMaService.execute(executor, MEDIA_GET_URL, "media_id=" + mediaId); + } catch (IOException e) { + this.log.error(e.getMessage(), e); + throw new WxErrorException(WxError.newBuilder().setErrorMsg(e.getMessage()).build()); + } + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java new file mode 100644 index 0000000000..238bbe0e7f --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java @@ -0,0 +1,40 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaMsgService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; + +/** + * @author Binary Wang + */ +public class WxMaMsgServiceImpl implements WxMaMsgService { + private static final JsonParser JSON_PARSER = new JsonParser(); + private WxMaService wxMaService; + + public WxMaMsgServiceImpl(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + @Override + public boolean sendKefuMsg(WxMaKefuMessage message) throws WxErrorException { + String responseContent = this.wxMaService.post(KEFU_MESSAGE_SEND_URL, message.toJson()); + return responseContent != null; + } + + @Override + public String sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException { + String responseContent = this.wxMaService.post(TEMPLATE_MSG_SEND_URL, templateMessage.toJson()); + JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); + if (jsonObject.get("errcode").getAsInt() == 0) { + return jsonObject.get("msgid").getAsString(); + } + + throw new WxErrorException(WxError.fromJson(responseContent)); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java new file mode 100644 index 0000000000..f0fc36af16 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java @@ -0,0 +1,28 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaQrcode; +import cn.binarywang.wx.miniapp.util.http.QrCodeRequestExecutor; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.File; + +/** + * @author Binary Wang + */ +public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { + private WxMaService wxMaService; + + public WxMaQrcodeServiceImpl(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + @Override + public File createQrcode(String path, int width) throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode"; + return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), + url, new WxMaQrcode(path, width)); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java new file mode 100644 index 0000000000..167341265a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java @@ -0,0 +1,265 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.*; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import com.google.gson.JsonParser; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.crypto.SHA1; +import me.chanjar.weixin.common.util.http.*; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.concurrent.locks.Lock; + +/** + * @author Binary Wang + */ +public class WxMaServiceImpl implements WxMaService, RequestHttp { + private static final JsonParser JSON_PARSER = new JsonParser(); + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private CloseableHttpClient httpClient; + private HttpHost httpProxy; + private WxMaConfig wxMaConfig; + + private WxMaMsgService kefuService = new WxMaMsgServiceImpl(this); + private WxMaMediaService materialService = new WxMaMediaServiceImpl(this); + private WxMaUserService userService = new WxMaUserServiceImpl(this); + private WxMaQrcodeService qrCodeService = new WxMaQrcodeServiceImpl(this); + + private int retrySleepMillis = 1000; + private int maxRetryTimes = 5; + + @Override + public CloseableHttpClient getRequestHttpClient() { + return httpClient; + } + + @Override + public HttpHost getRequestHttpProxy() { + return httpProxy; + } + + @Override + public HttpType getRequestType() { + return HttpType.APACHE_HTTP; + } + + @Override + public void initHttp() { + WxMaConfig configStorage = this.getWxMaConfig(); + ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder(); + if (null == apacheHttpClientBuilder) { + apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); + } + + apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost()) + .httpProxyPort(configStorage.getHttpProxyPort()) + .httpProxyUsername(configStorage.getHttpProxyUsername()) + .httpProxyPassword(configStorage.getHttpProxyPassword()); + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort()); + } + + this.httpClient = apacheHttpClientBuilder.build(); + } + + @Override + public RequestHttp getRequestHttp() { + return this; + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMaConfig().getAccessTokenLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.getWxMaConfig().expireAccessToken(); + } + + if (this.getWxMaConfig().isAccessTokenExpired()) { + String url = String.format(WxMaService.GET_ACCESS_TOKEN_URL, this.getWxMaConfig().getAppid(), + this.getWxMaConfig().getSecret()); + try { + HttpGet httpGet = new HttpGet(url); + if (this.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) { + String resultContent = new BasicResponseHandler().handleResponse(response); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.getWxMaConfig().updateAccessToken(accessToken.getAccessToken(), + accessToken.getExpiresIn()); + } finally { + httpGet.releaseConnection(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } finally { + lock.unlock(); + } + + return this.getWxMaConfig().getAccessToken(); + } + + @Override + public boolean checkSignature(String timestamp, String nonce, String signature) { + try { + return SHA1.gen(this.getWxMaConfig().getToken(), timestamp, nonce).equals(signature); + } catch (Exception e) { + this.log.error("Checking signature failed, and the reason is :" + e.getMessage()); + return false; + } + } + + @Override + public String getAccessToken() throws WxErrorException { + return getAccessToken(false); + } + + @Override + public String get(String url, String queryParam) throws WxErrorException { + return execute(SimpleGetRequestExecutor.create(this), url, queryParam); + } + + @Override + public String post(String url, String postData) throws WxErrorException { + return execute(SimplePostRequestExecutor.create(this), url, postData); + } + + /** + * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 + */ + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + int retryTimes = 0; + do { + try { + return this.executeInternal(executor, uri, data); + } catch (WxErrorException e) { + if (retryTimes + 1 > this.maxRetryTimes) { + this.log.warn("重试达到最大次数【{}】", maxRetryTimes); + //最后一次重试失败后,直接抛出异常,不再等待 + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + WxError error = e.getError(); + // -1 系统繁忙, 1000ms后重试 + if (error.getErrorCode() == -1) { + int sleepMillis = this.retrySleepMillis * (1 << retryTimes); + try { + this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + Thread.sleep(sleepMillis); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + } else { + throw e; + } + } + } while (retryTimes++ < this.maxRetryTimes); + + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + if (uri.contains("access_token=")) { + throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); + } + String accessToken = getAccessToken(false); + + String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken; + + try { + T result = executor.execute(uriWithAccessToken, data); + this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, result); + return result; + } catch (WxErrorException e) { + WxError error = e.getError(); + /* + * 发生以下情况时尝试刷新access_token + * 40001 获取access_token时AppSecret错误,或者access_token无效 + * 42001 access_token超时 + * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期) + */ + if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001 || error.getErrorCode() == 40014) { + // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token + this.getWxMaConfig().expireAccessToken(); + if (this.getWxMaConfig().autoRefreshToken()) { + return this.execute(executor, uri, data); + } + } + + if (error.getErrorCode() != 0) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uriWithAccessToken, data, error); + throw new WxErrorException(error); + } + return null; + } catch (IOException e) { + this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uriWithAccessToken, data, e.getMessage()); + throw new RuntimeException(e); + } + } + + @Override + public WxMaConfig getWxMaConfig() { + return this.wxMaConfig; + } + + @Override + public void setWxMaConfig(WxMaConfig wxConfigProvider) { + this.wxMaConfig = wxConfigProvider; + this.initHttp(); + } + + @Override + public void setRetrySleepMillis(int retrySleepMillis) { + this.retrySleepMillis = retrySleepMillis; + } + + @Override + public void setMaxRetryTimes(int maxRetryTimes) { + this.maxRetryTimes = maxRetryTimes; + } + + @Override + public WxMaMsgService getMsgService() { + return this.kefuService; + } + + @Override + public WxMaMediaService getMediaService() { + return this.materialService; + } + + @Override + public WxMaUserService getUserService() { + return this.userService; + } + + @Override + public WxMaQrcodeService getQrcodeService() { + return this.qrCodeService; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java new file mode 100644 index 0000000000..e2fdb9dc2b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java @@ -0,0 +1,51 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.WxMaUserService; +import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; +import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; +import com.google.common.base.Joiner; +import me.chanjar.weixin.common.exception.WxErrorException; +import org.apache.commons.codec.digest.DigestUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Binary Wang + */ +public class WxMaUserServiceImpl implements WxMaUserService { + private WxMaService service; + + WxMaUserServiceImpl(WxMaService service) { + this.service = service; + } + + @Override + public WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException { + final WxMaConfig config = service.getWxMaConfig(); + Map params = new HashMap<>(); + params.put("appid", config.getAppid()); + params.put("secret", config.getSecret()); + params.put("js_code", jsCode); + params.put("grant_type", "authorization_code"); + + String result = this.service.get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params)); + return WxMaJscode2SessionResult.fromJson(result); + } + + @Override + public WxMaUserInfo getUserInfo(String sessionKey, String encryptedData, String ivStr) { + return WxMaUserInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)); + } + + @Override + public boolean checkUserInfo(String sessionKey, String rawData, String signature) { + final String generatedSignature = DigestUtils.sha1Hex(rawData + sessionKey); + System.out.println(generatedSignature); + return generatedSignature.equals(signature); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaJscode2SessionResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaJscode2SessionResult.java new file mode 100644 index 0000000000..4b9cc93d6b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaJscode2SessionResult.java @@ -0,0 +1,49 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; + +/** + * {"session_key":"nzoqhc3OnwHzeTxJs+inbQ==","expires_in":2592000,"openid":"oVBkZ0aYgDMDIywRdgPW8-joxXc4"} + * + * @author Binary Wang + */ +public class WxMaJscode2SessionResult { + @SerializedName("session_key") + private String sessionKey; + + @SerializedName("expires_in") + private Integer expiresin; + + @SerializedName("openid") + private String openid; + + public String getSessionKey() { + return sessionKey; + } + + public void setSessionKey(String sessionKey) { + this.sessionKey = sessionKey; + } + + public Integer getExpiresin() { + return expiresin; + } + + public void setExpiresin(Integer expiresin) { + this.expiresin = expiresin; + } + + public String getOpenid() { + return openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public static WxMaJscode2SessionResult fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaJscode2SessionResult.class); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessage.java new file mode 100644 index 0000000000..d75fbf12ae --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessage.java @@ -0,0 +1,99 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.builder.ImageBuilder; +import cn.binarywang.wx.miniapp.builder.TextBuilder; +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; + +import java.io.Serializable; + +/** + * 客服消息 + * + * @author Binary Wang + */ +public class WxMaKefuMessage implements Serializable { + private static final long serialVersionUID = -9196732086954365246L; + + private String toUser; + private String msgType; + private String content; + private String mediaId; + private String thumbMediaId; + private String title; + private String description; + + /** + * 获得文本消息builder + */ + public static TextBuilder TEXT() { + return new TextBuilder(); + } + + /** + * 获得图片消息builder + */ + public static ImageBuilder IMAGE() { + return new ImageBuilder(); + } + + public String getToUser() { + return this.toUser; + } + + public void setToUser(String toUser) { + this.toUser = toUser; + } + + public String getMsgType() { + return this.msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getMediaId() { + return this.mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public String getThumbMediaId() { + return this.thumbMediaId; + } + + public void setThumbMediaId(String thumbMediaId) { + this.thumbMediaId = thumbMediaId; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java new file mode 100644 index 0000000000..4b201da1cd --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java @@ -0,0 +1,236 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import cn.binarywang.wx.miniapp.util.xml.XStreamTransformer; +import com.google.gson.annotations.SerializedName; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.nio.charset.StandardCharsets; + +/** + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxMaMessage implements Serializable { + private static final long serialVersionUID = -3586245291677274914L; + + @SerializedName("Encrypt") + @XStreamAlias("Encrypt") + @XStreamConverter(value = XStreamCDataConverter.class) + private String encrypt; + + @SerializedName("ToUserName") + @XStreamAlias("ToUserName") + @XStreamConverter(value = XStreamCDataConverter.class) + private String toUser; + + @SerializedName("FromUserName") + @XStreamAlias("FromUserName") + @XStreamConverter(value = XStreamCDataConverter.class) + private String fromUser; + + @SerializedName("CreateTime") + @XStreamAlias("CreateTime") + @XStreamConverter(value = XStreamCDataConverter.class) + private Integer createTime; + + @SerializedName("MsgDataFormat") + @XStreamAlias("MsgDataFormat") + @XStreamConverter(value = XStreamCDataConverter.class) + private String msgType; + + // 文本消息 + @SerializedName("Content") + @XStreamAlias("Content") + @XStreamConverter(value = XStreamCDataConverter.class) + private String content; + + @SerializedName("MsgId") + @XStreamAlias("MsgId") + @XStreamConverter(value = XStreamCDataConverter.class) + private Long msgId; + + // 图片消息 + @SerializedName("PicUrl") + @XStreamAlias("PicUrl") + @XStreamConverter(value = XStreamCDataConverter.class) + private String picUrl; + + @SerializedName("MediaId") + @XStreamAlias("MediaId") + @XStreamConverter(value = XStreamCDataConverter.class) + private String mediaId; + + // 事件消息 + @SerializedName("Event") + @XStreamAlias("Event") + @XStreamConverter(value = XStreamCDataConverter.class) + private String event; + + @SerializedName("SessionFrom") + @XStreamAlias("SessionFrom") + @XStreamConverter(value = XStreamCDataConverter.class) + private String sessionFrom; + + public static WxMaMessage fromXml(String xml) { + return XStreamTransformer.fromXml(WxMaMessage.class, xml); + } + + public static WxMaMessage fromXml(InputStream is) { + return XStreamTransformer.fromXml(WxMaMessage.class, is); + } + + /** + * 从加密字符串转换 + * + * @param encryptedXml 密文 + * @param wxMaConfig 配置存储器对象 + * @param timestamp 时间戳 + * @param nonce 随机串 + * @param msgSignature 签名串 + */ + public static WxMaMessage fromEncryptedXml(String encryptedXml, + WxMaConfig wxMaConfig, String timestamp, String nonce, + String msgSignature) { + String plainText = new WxMaCryptUtils(wxMaConfig).decrypt(msgSignature, timestamp, nonce, encryptedXml); + return fromXml(plainText); + } + + public static WxMaMessage fromEncryptedXml(InputStream is, WxMaConfig wxMaConfig, String timestamp, + String nonce, String msgSignature) { + try { + return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), wxMaConfig, + timestamp, nonce, msgSignature); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static WxMaMessage fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaMessage.class); + } + + public static WxMaMessage fromEncryptedJson(String encryptedJson, WxMaConfig config) { + try { + WxMaMessage encryptedMessage = fromJson(encryptedJson); + String plainText = new WxMaCryptUtils(config).decrypt(encryptedMessage.getEncrypt()); + return fromJson(plainText); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static WxMaMessage fromEncryptedJson(InputStream inputStream, WxMaConfig config) { + try { + return fromEncryptedJson(IOUtils.toString(inputStream, StandardCharsets.UTF_8), config); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } + + public String getToUser() { + return toUser; + } + + public void setToUser(String toUser) { + this.toUser = toUser; + } + + public String getFromUser() { + return fromUser; + } + + public void setFromUser(String fromUser) { + this.fromUser = fromUser; + } + + public Integer getCreateTime() { + return createTime; + } + + public void setCreateTime(Integer createTime) { + this.createTime = createTime; + } + + public String getMsgType() { + return msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Long getMsgId() { + return msgId; + } + + public void setMsgId(Long msgId) { + this.msgId = msgId; + } + + public String getPicUrl() { + return picUrl; + } + + public void setPicUrl(String picUrl) { + this.picUrl = picUrl; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public String getEvent() { + return event; + } + + public void setEvent(String event) { + this.event = event; + } + + public String getSessionFrom() { + return sessionFrom; + } + + public void setSessionFrom(String sessionFrom) { + this.sessionFrom = sessionFrom; + } + + public String getEncrypt() { + return encrypt; + } + + public void setEncrypt(String encrypt) { + this.encrypt = encrypt; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcode.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcode.java new file mode 100644 index 0000000000..83050f0619 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaQrcode.java @@ -0,0 +1,44 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; + +import java.io.Serializable; + +/** + * @author Binary Wang + */ +public class WxMaQrcode implements Serializable { + private static final long serialVersionUID = 5777119669111011584L; + private String path; + private int width = 430; + + public WxMaQrcode(String path, int width) { + this.path = path; + this.width = width; + } + + public static WxMaQrcode fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaQrcode.class); + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + @Override + public String toString() { + return WxMaGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java new file mode 100644 index 0000000000..7a89dfa8a5 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessage.java @@ -0,0 +1,214 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html#接口说明 模板消息部分 + * + * @author Binary Wang + */ +public class WxMaTemplateMessage implements Serializable { + private static final long serialVersionUID = 5063374783759519418L; + /** + * touser 是 接收者(用户)的 openid + */ + private String toUser; + /** + * template_id 是 所需下发的模板消息的id + */ + private String templateId; + /** + *
    +   * page	否	点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
    +   * 
    + */ + private String page; + /** + * form_id 是 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id + */ + private String formId; + /** + * data 是 模板内容,不填则下发空模板 + */ + private List data = new ArrayList<>(); + /** + * color 否 模板内容字体的颜色,不填默认黑色 + */ + private String color; + /** + * emphasis_keyword 否 模板需要放大的关键词,不填则默认无放大 + */ + private String emphasisKeyword; + + private WxMaTemplateMessage(Builder builder) { + setToUser(builder.toUser); + setTemplateId(builder.templateId); + setPage(builder.page); + setFormId(builder.formId); + setData(builder.data); + setColor(builder.color); + setEmphasisKeyword(builder.emphasisKeyword); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } + + public String getToUser() { + return toUser; + } + + public void setToUser(String toUser) { + this.toUser = toUser; + } + + public String getTemplateId() { + return templateId; + } + + public void setTemplateId(String templateId) { + this.templateId = templateId; + } + + public String getPage() { + return page; + } + + public void setPage(String page) { + this.page = page; + } + + public String getFormId() { + return formId; + } + + public void setFormId(String formId) { + this.formId = formId; + } + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + public String getEmphasisKeyword() { + return emphasisKeyword; + } + + public void setEmphasisKeyword(String emphasisKeyword) { + this.emphasisKeyword = emphasisKeyword; + } + + public static class Data { + private String name; + private String value; + private String color; + + public Data(String name, String value) { + this.name = name; + this.value = value; + } + + public Data(String name, String value, String color) { + this.name = name; + this.value = value; + this.color = color; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return this.value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getColor() { + return this.color; + } + + public void setColor(String color) { + this.color = color; + } + + } + + public static final class Builder { + private String toUser; + private String templateId; + private String page; + private String formId; + private List data; + private String color; + private String emphasisKeyword; + + private Builder() { + } + + public Builder toUser(String toUser) { + this.toUser = toUser; + return this; + } + + public Builder templateId(String templateId) { + this.templateId = templateId; + return this; + } + + public Builder page(String page) { + this.page = page; + return this; + } + + public Builder formId(String formId) { + this.formId = formId; + return this; + } + + public Builder data(List data) { + this.data = data; + return this; + } + + public Builder color(String color) { + this.color = color; + return this; + } + + public Builder emphasisKeyword(String emphasisKeyword) { + this.emphasisKeyword = emphasisKeyword; + return this; + } + + public WxMaTemplateMessage build() { + return new WxMaTemplateMessage(this); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaUserInfo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaUserInfo.java new file mode 100644 index 0000000000..e3cc69d913 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaUserInfo.java @@ -0,0 +1,131 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * @author Binary Wang + */ +public class WxMaUserInfo { + private String openId; + private String nickName; + private String gender; + private String language; + private String city; + private String province; + private String country; + private String avatarUrl; + private String unionId; + private Watermark watermark; + + public static WxMaUserInfo fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaUserInfo.class); + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getProvince() { + return province; + } + + public void setProvince(String province) { + this.province = province; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getAvatarUrl() { + return avatarUrl; + } + + public void setAvatarUrl(String avatarUrl) { + this.avatarUrl = avatarUrl; + } + + public String getUnionId() { + return unionId; + } + + public void setUnionId(String unionId) { + this.unionId = unionId; + } + + public Watermark getWatermark() { + return watermark; + } + + public void setWatermark(Watermark watermark) { + this.watermark = watermark; + } + + public static class Watermark { + private String timestamp; + private String appid; + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/BaseBuilder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/BaseBuilder.java new file mode 100644 index 0000000000..70d7cf4b7c --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/BaseBuilder.java @@ -0,0 +1,24 @@ +package cn.binarywang.wx.miniapp.builder; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; + +/** + * @author Binary Wang + */ +public class BaseBuilder { + protected String msgType; + protected String toUser; + + @SuppressWarnings("unchecked") + public T toUser(String toUser) { + this.toUser = toUser; + return (T) this; + } + + public WxMaKefuMessage build() { + WxMaKefuMessage m = new WxMaKefuMessage(); + m.setMsgType(this.msgType); + m.setToUser(this.toUser); + return m; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/ImageBuilder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/ImageBuilder.java new file mode 100644 index 0000000000..219e3fd43b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/ImageBuilder.java @@ -0,0 +1,27 @@ +package cn.binarywang.wx.miniapp.builder; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; + +/** + * @author Binary Wang + */ +public final class ImageBuilder extends BaseBuilder { + private String mediaId; + + public ImageBuilder() { + this.msgType = WxMaConstants.KefuMsgType.IMAGE; + } + + public ImageBuilder mediaId(String media_id) { + this.mediaId = media_id; + return this; + } + + @Override + public WxMaKefuMessage build() { + WxMaKefuMessage m = super.build(); + m.setMediaId(this.mediaId); + return m; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/TextBuilder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/TextBuilder.java new file mode 100644 index 0000000000..35c58a67df --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/TextBuilder.java @@ -0,0 +1,27 @@ +package cn.binarywang.wx.miniapp.builder; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; + +/** + * @author Binary Wang + */ +public final class TextBuilder extends BaseBuilder { + private String content; + + public TextBuilder() { + this.msgType = WxMaConstants.KefuMsgType.TEXT; + } + + public TextBuilder content(String content) { + this.content = content; + return this; + } + + @Override + public WxMaKefuMessage build() { + WxMaKefuMessage m = super.build(); + m.setContent(this.content); + return m; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java new file mode 100644 index 0000000000..df72bb2c7d --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java @@ -0,0 +1,73 @@ +package cn.binarywang.wx.miniapp.config; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + +import java.util.concurrent.locks.Lock; + +/** + * 小程序配置 + * + * @author Binary Wang + */ +public interface WxMaConfig { + + String getAccessToken(); + + Lock getAccessTokenLock(); + + boolean isAccessTokenExpired(); + + /** + * 强制将access token过期掉 + */ + void expireAccessToken(); + + /** + * 应该是线程安全的 + * + * @param accessToken 要更新的WxAccessToken对象 + */ + void updateAccessToken(WxAccessToken accessToken); + + /** + * 应该是线程安全的 + * + * @param accessToken 新的accessToken值 + * @param expiresInSeconds 过期时间,以秒为单位 + */ + void updateAccessToken(String accessToken, int expiresInSeconds); + + String getAppid(); + + String getSecret(); + + String getToken(); + + String getAesKey(); + + String getMsgDataFormat(); + + long getExpiresTime(); + + String getHttpProxyHost(); + + int getHttpProxyPort(); + + String getHttpProxyUsername(); + + String getHttpProxyPassword(); + + /** + * http client builder + * + * @return ApacheHttpClientBuilder + */ + ApacheHttpClientBuilder getApacheHttpClientBuilder(); + + /** + * 是否自动刷新token + */ + boolean autoRefreshToken(); + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java new file mode 100644 index 0000000000..735a52b56a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java @@ -0,0 +1,185 @@ +package cn.binarywang.wx.miniapp.config; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + +import java.io.File; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 + * + * @author Binary Wang + */ +public class WxMaInMemoryConfig implements WxMaConfig { + protected volatile String msgDataFormat; + protected volatile String appid; + protected volatile String secret; + protected volatile String token; + protected volatile String accessToken; + protected volatile String aesKey; + protected volatile long expiresTime; + + protected volatile String httpProxyHost; + protected volatile int httpProxyPort; + protected volatile String httpProxyUsername; + protected volatile String httpProxyPassword; + + protected Lock accessTokenLock = new ReentrantLock(); + + /** + * 临时文件目录 + */ + protected volatile File tmpDirFile; + + protected volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + + @Override + public String getAccessToken() { + return this.accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + @Override + public Lock getAccessTokenLock() { + return this.accessTokenLock; + } + + public void setAccessTokenLock(Lock accessTokenLock) { + this.accessTokenLock = accessTokenLock; + } + + @Override + public boolean isAccessTokenExpired() { + return System.currentTimeMillis() > this.expiresTime; + } + + @Override + public synchronized void updateAccessToken(WxAccessToken accessToken) { + updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + } + + @Override + public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { + this.accessToken = accessToken; + this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + } + + @Override + public void expireAccessToken() { + this.expiresTime = 0; + } + + @Override + public String getSecret() { + return this.secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } + + @Override + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public long getExpiresTime() { + return this.expiresTime; + } + + public void setExpiresTime(long expiresTime) { + this.expiresTime = expiresTime; + } + + @Override + public String getAesKey() { + return this.aesKey; + } + + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } + + @Override + public String getMsgDataFormat() { + return this.msgDataFormat; + } + + public void setMsgDataFormat(String msgDataFormat) { + this.msgDataFormat = msgDataFormat; + } + + @Override + public String getHttpProxyHost() { + return this.httpProxyHost; + } + + public void setHttpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + } + + @Override + public int getHttpProxyPort() { + return this.httpProxyPort; + } + + public void setHttpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + } + + @Override + public String getHttpProxyUsername() { + return this.httpProxyUsername; + } + + public void setHttpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + } + + @Override + public String getHttpProxyPassword() { + return this.httpProxyPassword; + } + + public void setHttpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + } + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + @Override + public ApacheHttpClientBuilder getApacheHttpClientBuilder() { + return this.apacheHttpClientBuilder; + } + + public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { + this.apacheHttpClientBuilder = apacheHttpClientBuilder; + } + + @Override + public boolean autoRefreshToken() { + return true; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaConstants.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaConstants.java new file mode 100644 index 0000000000..14016fa578 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaConstants.java @@ -0,0 +1,33 @@ +package cn.binarywang.wx.miniapp.constant; + +/** + *
    + *  小程序常量
    + * 
    + * + * @author Binary Wang + */ +public class WxMaConstants { + /** + * 素材类型 + */ + public static class MediaType { + public static final String IMAGE = "image";//图片 + } + + /** + * 消息格式 + */ + public static class MsgDataFormat { + public static final String XML = "XML"; + public static final String JSON = "JSON"; + } + + /** + * 客服消息的消息类型 + */ + public static class KefuMsgType { + public static final String TEXT = "text";//文本消息 + public static final String IMAGE = "image";//图片消息 + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java new file mode 100644 index 0000000000..794d60e98a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java @@ -0,0 +1,20 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; + +import java.util.Map; + +/** + * 处理小程序推送消息的处理器接口 + * + * @author Binary Wang + */ +public interface WxMaMessageHandler { + + void handle(WxMaMessage message, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException; + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java new file mode 100644 index 0000000000..1b220a0baa --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java @@ -0,0 +1,28 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; + +import java.util.Map; + +/** + * 微信消息拦截器,可以用来做验证 + * + * @author Binary Wang + */ +public interface WxMaMessageInterceptor { + + /** + * 拦截微信消息 + * + * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @return true代表OK,false代表不OK + */ + boolean intercept(WxMaMessage wxMessage, + Map context, + WxMaService wxMaService, + WxSessionManager sessionManager) throws WxErrorException; + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageMatcher.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageMatcher.java new file mode 100644 index 0000000000..9d4e54f89b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageMatcher.java @@ -0,0 +1,17 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.bean.WxMaMessage; + +/** + * 消息匹配器,用在消息路由的时候 + * + * @author Binary Wang + */ +public interface WxMaMessageMatcher { + + /** + * 消息是否匹配某种模式 + */ + boolean match(WxMaMessage message); + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java new file mode 100644 index 0000000000..cbe42b1f26 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java @@ -0,0 +1,176 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; +import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; +import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; +import me.chanjar.weixin.common.session.InternalSession; +import me.chanjar.weixin.common.session.InternalSessionManager; +import me.chanjar.weixin.common.session.StandardSessionManager; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.LogExceptionHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + * @author Binary Wang + */ +public class WxMaMessageRouter { + private static final int DEFAULT_THREAD_POOL_SIZE = 100; + private final Logger log = LoggerFactory.getLogger(WxMaMessageRouter.class); + private final List rules = new ArrayList<>(); + + private final WxMaService wxMaService; + + private ExecutorService executorService; + + private WxMessageDuplicateChecker messageDuplicateChecker; + + private WxSessionManager sessionManager; + + private WxErrorExceptionHandler exceptionHandler; + + public WxMaMessageRouter(WxMaService wxMaService) { + this.wxMaService = wxMaService; + this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); + this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); + this.sessionManager = new StandardSessionManager(); + this.exceptionHandler = new LogExceptionHandler(); + } + + /** + *
    +   * 设置自定义的 {@link ExecutorService}
    +   * 如果不调用该方法,默认使用 Executors.newFixedThreadPool(100)
    +   * 
    + */ + public void setExecutorService(ExecutorService executorService) { + this.executorService = executorService; + } + + /** + *
    +   * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker}
    +   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker}
    +   * 
    + */ + public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { + this.messageDuplicateChecker = messageDuplicateChecker; + } + + /** + *
    +   * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager}
    +   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager}
    +   * 
    + */ + public void setSessionManager(WxSessionManager sessionManager) { + this.sessionManager = sessionManager; + } + + /** + *
    +   * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler}
    +   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler}
    +   * 
    + */ + public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + + List getRules() { + return this.rules; + } + + /** + * 开始一个新的Route规则 + */ + public WxMaMessageRouterRule rule() { + return new WxMaMessageRouterRule(this); + } + + /** + * 处理微信消息 + */ + public void route(final WxMaMessage wxMessage, final Map context) { + final List matchRules = new ArrayList<>(); + // 收集匹配的规则 + for (final WxMaMessageRouterRule rule : this.rules) { + if (rule.test(wxMessage)) { + matchRules.add(rule); + if (!rule.isReEnter()) { + break; + } + } + } + + if (matchRules.size() == 0) { + return; + } + + final List> futures = new ArrayList<>(); + for (final WxMaMessageRouterRule rule : matchRules) { + // 返回最后一个非异步的rule的执行结果 + if (rule.isAsync()) { + futures.add( + this.executorService.submit(new Runnable() { + @Override + public void run() { + rule.service(wxMessage, context, WxMaMessageRouter.this.wxMaService, WxMaMessageRouter.this.sessionManager, WxMaMessageRouter.this.exceptionHandler); + } + }) + ); + } else { + rule.service(wxMessage, context, this.wxMaService, this.sessionManager, this.exceptionHandler); + // 在同步操作结束,session访问结束 + this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser()); + sessionEndAccess(wxMessage); + } + } + + if (futures.size() > 0) { + this.executorService.submit(new Runnable() { + @Override + public void run() { + for (Future future : futures) { + try { + future.get(); + WxMaMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUser()); + // 异步操作结束,session访问结束 + sessionEndAccess(wxMessage); + } catch (InterruptedException | ExecutionException e) { + WxMaMessageRouter.this.log.error("Error happened when wait task finish", e); + } + } + } + }); + } + + } + + public void route(final WxMaMessage wxMessage) { + this.route(wxMessage, new HashMap()); + } + + /** + * 对session的访问结束 + */ + protected void sessionEndAccess(WxMaMessage wxMessage) { + + InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUser()); + if (session != null) { + session.endAccess(); + } + + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java new file mode 100644 index 0000000000..9fce8b1a04 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java @@ -0,0 +1,316 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +/** + * @author Binary Wang + */ +public class WxMaMessageRouterRule { + + private final WxMaMessageRouter routerBuilder; + + private boolean async = true; + + private String fromUser; + + private String msgType; + + private String event; + + private String eventKey; + + private String content; + + private String rContent; + + private WxMaMessageMatcher matcher; + + private boolean reEnter = false; + + private List handlers = new ArrayList<>(); + + private List interceptors = new ArrayList<>(); + + public WxMaMessageRouterRule(WxMaMessageRouter routerBuilder) { + this.routerBuilder = routerBuilder; + } + + /** + * 设置是否异步执行,默认是true + */ + public WxMaMessageRouterRule async(boolean async) { + this.async = async; + return this; + } + + /** + * 如果msgType等于某值 + */ + public WxMaMessageRouterRule msgType(String msgType) { + this.msgType = msgType; + return this; + } + + /** + * 如果event等于某值 + */ + public WxMaMessageRouterRule event(String event) { + this.event = event; + return this; + } + + /** + * 如果eventKey等于某值 + */ + public WxMaMessageRouterRule eventKey(String eventKey) { + this.eventKey = eventKey; + return this; + } + + /** + * 如果content等于某值 + */ + public WxMaMessageRouterRule content(String content) { + this.content = content; + return this; + } + + /** + * 如果content匹配该正则表达式 + */ + public WxMaMessageRouterRule rContent(String regex) { + this.rContent = regex; + return this; + } + + /** + * 如果fromUser等于某值 + */ + public WxMaMessageRouterRule fromUser(String fromUser) { + this.fromUser = fromUser; + return this; + } + + /** + * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 + */ + public WxMaMessageRouterRule matcher(WxMaMessageMatcher matcher) { + this.matcher = matcher; + return this; + } + + /** + * 设置微信消息拦截器 + */ + public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor) { + return interceptor(interceptor, (WxMaMessageInterceptor[]) null); + } + + /** + * 设置微信消息拦截器 + */ + public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor, WxMaMessageInterceptor... otherInterceptors) { + this.interceptors.add(interceptor); + if (otherInterceptors != null && otherInterceptors.length > 0) { + for (WxMaMessageInterceptor i : otherInterceptors) { + this.interceptors.add(i); + } + } + return this; + } + + /** + * 设置微信消息处理器 + */ + public WxMaMessageRouterRule handler(WxMaMessageHandler handler) { + return handler(handler, (WxMaMessageHandler[]) null); + } + + /** + * 设置微信消息处理器 + */ + public WxMaMessageRouterRule handler(WxMaMessageHandler handler, WxMaMessageHandler... otherHandlers) { + this.handlers.add(handler); + if (otherHandlers != null && otherHandlers.length > 0) { + for (WxMaMessageHandler i : otherHandlers) { + this.handlers.add(i); + } + } + return this; + } + + /** + * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 + */ + public WxMaMessageRouter end() { + this.routerBuilder.getRules().add(this); + return this.routerBuilder; + } + + /** + * 规则结束,但是消息还会进入其他规则 + */ + public WxMaMessageRouter next() { + this.reEnter = true; + return end(); + } + + /** + * 将微信自定义的事件修正为不区分大小写, + * 比如框架定义的事件常量为click,但微信传递过来的却是CLICK + */ + protected boolean test(WxMaMessage wxMessage) { + return + (this.fromUser == null || this.fromUser.equals(wxMessage.getFromUser())) + && + (this.msgType == null || this.msgType.toLowerCase().equals((wxMessage.getMsgType() == null ? null : wxMessage.getMsgType().toLowerCase()))) + && + (this.event == null || this.event.toLowerCase().equals((wxMessage.getEvent() == null ? null : wxMessage.getEvent().toLowerCase()))) + && + (this.content == null || this.content + .equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) + && + (this.rContent == null || Pattern + .matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) + && + (this.matcher == null || this.matcher.match(wxMessage)) + ; + } + + /** + * 处理微信推送过来的消息 + * + * @return true 代表继续执行别的router,false 代表停止执行别的router + */ + protected void service(WxMaMessage wxMessage, + Map context, + WxMaService wxMaService, + WxSessionManager sessionManager, + WxErrorExceptionHandler exceptionHandler) { + if (context == null) { + context = new HashMap<>(); + } + + try { + // 如果拦截器不通过 + for (WxMaMessageInterceptor interceptor : this.interceptors) { + if (!interceptor.intercept(wxMessage, context, wxMaService, sessionManager)) { + return; + } + } + + // 交给handler处理 + for (WxMaMessageHandler handler : this.handlers) { + // 返回最后handler的结果 + if (handler == null) { + continue; + } + handler.handle(wxMessage, context, wxMaService, sessionManager); + } + } catch (WxErrorException e) { + exceptionHandler.handle(e); + } + } + + public WxMaMessageRouter getRouterBuilder() { + return this.routerBuilder; + } + + public boolean isAsync() { + return this.async; + } + + public void setAsync(boolean async) { + this.async = async; + } + + public String getFromUser() { + return this.fromUser; + } + + public void setFromUser(String fromUser) { + this.fromUser = fromUser; + } + + public String getMsgType() { + return this.msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + public String getEvent() { + return this.event; + } + + public void setEvent(String event) { + this.event = event; + } + + public String getEventKey() { + return this.eventKey; + } + + public void setEventKey(String eventKey) { + this.eventKey = eventKey; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getrContent() { + return this.rContent; + } + + public void setrContent(String rContent) { + this.rContent = rContent; + } + + public WxMaMessageMatcher getMatcher() { + return this.matcher; + } + + public void setMatcher(WxMaMessageMatcher matcher) { + this.matcher = matcher; + } + + public boolean isReEnter() { + return this.reEnter; + } + + public void setReEnter(boolean reEnter) { + this.reEnter = reEnter; + } + + public List getHandlers() { + return this.handlers; + } + + public void setHandlers(List handlers) { + this.handlers = handlers; + } + + public List getInterceptors() { + return this.interceptors; + } + + public void setInterceptors(List interceptors) { + this.interceptors = interceptors; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java new file mode 100644 index 0000000000..e05bac5fb7 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java @@ -0,0 +1,43 @@ +package cn.binarywang.wx.miniapp.util.crypt; + +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import me.chanjar.weixin.common.util.crypto.PKCS7Encoder; +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.AlgorithmParameters; + +/** + * @author Binary Wang + */ +public class WxMaCryptUtils extends me.chanjar.weixin.common.util.crypto.WxCryptUtil { + public WxMaCryptUtils(WxMaConfig config) { + this.appidOrCorpid = config.getAppid(); + this.token = config.getToken(); + this.aesKey = Base64.decodeBase64(config.getAesKey() + "="); + } + + /** + * AES解密 + * + * @param encryptedData 消息密文 + * @param ivStr iv字符串 + */ + public static String decrypt(String sessionKey, String encryptedData, String ivStr) { + try { + AlgorithmParameters params = AlgorithmParameters.getInstance("AES"); + params.init(new IvParameterSpec(Base64.decodeBase64(ivStr))); + + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(sessionKey), "AES"), params); + + return new String(PKCS7Encoder.decode(cipher.doFinal(Base64.decodeBase64(encryptedData))), StandardCharsets.UTF_8); + } catch (Exception e) { + throw new RuntimeException("AES解密失败", e); + } + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java new file mode 100644 index 0000000000..7883ffda9b --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java @@ -0,0 +1,61 @@ +package cn.binarywang.wx.miniapp.util.http; + +import cn.binarywang.wx.miniapp.bean.WxMaQrcode; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +/** + * @author Binary Wang + */ +public class QrCodeRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; + + public QrCodeRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } + + @Override + public File execute(String uri, WxMaQrcode ticket) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + httpPost + .setConfig(RequestConfig.custom() + .setProxy(requestHttp.getRequestHttpProxy()) + .build() + ); + } + httpPost.setEntity(new StringEntity(ticket.toString())); + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0 + && ContentType.TEXT_PLAIN.getMimeType().equals(contentTypeHeader[0].getValue())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaGsonBuilder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaGsonBuilder.java new file mode 100644 index 0000000000..4eb3a8adf0 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaGsonBuilder.java @@ -0,0 +1,24 @@ +package cn.binarywang.wx.miniapp.util.json; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +/** + * @author Binary Wang + */ +public class WxMaGsonBuilder { + private static final GsonBuilder INSTANCE = new GsonBuilder(); + + static { + INSTANCE.disableHtmlEscaping(); + INSTANCE.registerTypeAdapter(WxMaKefuMessage.class, new WxMaKefuMessageGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMaTemplateMessage.class, new WxMaTemplateMessageGsonAdapter()); + } + + public static Gson create() { + return INSTANCE.create(); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaKefuMessageGsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaKefuMessageGsonAdapter.java new file mode 100644 index 0000000000..33c46d63cd --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaKefuMessageGsonAdapter.java @@ -0,0 +1,47 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package cn.binarywang.wx.miniapp.util.json; + +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Type; + +/** + * @author Binary Wang + */ +public class WxMaKefuMessageGsonAdapter implements JsonSerializer { + + @Override + public JsonElement serialize(WxMaKefuMessage message, Type typeOfSrc, JsonSerializationContext context) { + JsonObject messageJson = new JsonObject(); + messageJson.addProperty("touser", message.getToUser()); + messageJson.addProperty("msgtype", message.getMsgType()); + + if (WxMaConstants.KefuMsgType.TEXT.equals(message.getMsgType())) { + JsonObject text = new JsonObject(); + text.addProperty("content", message.getContent()); + messageJson.add("text", text); + } + + if (WxMaConstants.KefuMsgType.IMAGE.equals(message.getMsgType())) { + JsonObject image = new JsonObject(); + image.addProperty("media_id", message.getMediaId()); + messageJson.add("image", image); + } + + return messageJson; + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaTemplateMessageGsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaTemplateMessageGsonAdapter.java new file mode 100644 index 0000000000..0b4edee286 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/json/WxMaTemplateMessageGsonAdapter.java @@ -0,0 +1,60 @@ +package cn.binarywang.wx.miniapp.util.json; + +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import java.lang.reflect.Type; + +/** + * @author Binary Wang + */ +public class WxMaTemplateMessageGsonAdapter implements JsonSerializer { + + @Override + public JsonElement serialize(WxMaTemplateMessage message, Type typeOfSrc, JsonSerializationContext context) { + JsonObject messageJson = new JsonObject(); + messageJson.addProperty("touser", message.getToUser()); + messageJson.addProperty("template_id", message.getTemplateId()); + if (message.getPage() != null) { + messageJson.addProperty("page", message.getPage()); + } + + if (message.getFormId() != null) { + messageJson.addProperty("form_id", message.getFormId()); + } + + if (message.getPage() != null) { + messageJson.addProperty("page", message.getPage()); + } + + if (message.getColor() != null) { + messageJson.addProperty("color", message.getColor()); + } + + if (message.getEmphasisKeyword() != null) { + messageJson.addProperty("emphasis_keyword", message.getEmphasisKeyword()); + } + + JsonObject data = new JsonObject(); + messageJson.add("data", data); + + if (message.getData() == null) { + return messageJson; + } + + for (WxMaTemplateMessage.Data datum : message.getData()) { + JsonObject dataJson = new JsonObject(); + dataJson.addProperty("value", datum.getValue()); + if (datum.getColor() != null) { + dataJson.addProperty("color", datum.getColor()); + } + data.add(datum.getName(), dataJson); + } + + return messageJson; + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/xml/XStreamTransformer.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/xml/XStreamTransformer.java new file mode 100644 index 0000000000..f85c716acb --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/xml/XStreamTransformer.java @@ -0,0 +1,88 @@ +package cn.binarywang.wx.miniapp.util.xml; + +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import com.thoughtworks.xstream.XStream; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; + +import java.io.InputStream; +import java.util.*; + +/** + * @author Binary Wang + */ +public class XStreamTransformer { + private static final Map, XStream> CLASS_2_XSTREAM_INSTANCE = new HashMap<>(); + + static { + registerClass(WxMaMessage.class); + } + + /** + * xml -> pojo + */ + @SuppressWarnings("unchecked") + public static T fromXml(Class clazz, String xml) { + T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(xml); + return object; + } + + @SuppressWarnings("unchecked") + public static T fromXml(Class clazz, InputStream is) { + T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(is); + return object; + } + + /** + * pojo -> xml + */ + public static String toXml(Class clazz, T object) { + return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); + } + + /** + * 注册扩展消息的解析器 + * + * @param clz 类型 + * @param xStream xml解析器 + */ + private static void register(Class clz, XStream xStream) { + CLASS_2_XSTREAM_INSTANCE.put(clz, xStream); + } + + /** + * 会自动注册该类及其子类 + * + * @param clz 要注册的类 + */ + private static void registerClass(Class clz) { + XStream xstream = XStreamInitializer.getInstance(); + xstream.processAnnotations(clz); + xstream.processAnnotations(getInnerClasses(clz)); + if (clz.equals(WxMaMessage.class)) { + // 操蛋的微信,模板消息推送成功的消息是MsgID,其他消息推送过来是MsgId + xstream.aliasField("MsgID", WxMaMessage.class, "msgId"); + } + + register(clz, xstream); + } + + private static Class[] getInnerClasses(Class clz) { + Class[] innerClasses = clz.getClasses(); + if (innerClasses == null) { + return null; + } + + List> result = new ArrayList<>(); + result.addAll(Arrays.asList(innerClasses)); + for (Class inner : innerClasses) { + Class[] innerClz = getInnerClasses(inner); + if (innerClz == null) { + continue; + } + + result.addAll(Arrays.asList(innerClz)); + } + + return result.toArray(new Class[0]); + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImplTest.java new file mode 100644 index 0000000000..825ad05f76 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMediaServiceImplTest.java @@ -0,0 +1,52 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +/** + * 临时素材接口的测试 + * + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaMediaServiceImplTest { + @Inject + protected WxMaService wxService; + + private String mediaId; + + @Test + public void testUploadMedia() throws WxErrorException, IOException { + String mediaType = "image"; + String fileType = "png"; + String fileName = "tmp.png"; + try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)) { + WxMediaUploadResult res = this.wxService.getMediaService().uploadMedia(mediaType, fileType, inputStream); + assertNotNull(res.getType()); + assertNotNull(res.getCreatedAt()); + assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null); + this.mediaId = res.getMediaId(); + System.out.println(res); + } + } + + @Test(dependsOnMethods = {"testUploadMedia"}) + public void testGetMedia() throws WxErrorException { + File file = this.wxService.getMediaService().getMedia(this.mediaId); + assertNotNull(file); + System.out.println(file.getAbsolutePath()); + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java new file mode 100644 index 0000000000..c5d8f1e86a --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImplTest.java @@ -0,0 +1,76 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import cn.binarywang.wx.miniapp.test.TestConfig; +import com.google.common.collect.Lists; +import com.google.inject.Inject; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.exception.WxErrorException; +import org.testng.Assert; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 测试客服相关接口 + * + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaMsgServiceImplTest { + + @Inject + protected WxMaService wxService; + + public void testSendKefuMpNewsMessage() throws WxErrorException { + TestConfig configStorage = (TestConfig) this.wxService + .getWxMaConfig(); + WxMaKefuMessage message = new WxMaKefuMessage(); + message.setMsgType(WxConsts.CUSTOM_MSG_MPNEWS); + message.setToUser(configStorage.getOpenid()); + + this.wxService.getMsgService().sendKefuMsg(message); + } + + public void testSendKefuMessage() throws WxErrorException { + TestConfig config = (TestConfig) this.wxService + .getWxMaConfig(); + WxMaKefuMessage message = new WxMaKefuMessage(); + message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); + message.setToUser(config.getOpenid()); + message.setContent( + "欢迎欢迎,热烈欢迎\n换行测试\n超链接:Hello World"); + + this.wxService.getMsgService().sendKefuMsg(message); + } + + @Test(invocationCount = 5, threadPoolSize = 3) + public void testSendTemplateMsg() throws WxErrorException { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + TestConfig config = (TestConfig) this.wxService.getWxMaConfig(); + + WxMaTemplateMessage templateMessage = WxMaTemplateMessage.newBuilder() + .toUser(config.getOpenid()) + .formId("FORMID") + .page("index") + .data(Lists.newArrayList( + new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177"), + new WxMaTemplateMessage.Data("keyword2", dateFormat.format(new Date()), "#173177"), + new WxMaTemplateMessage.Data("keyword3", "粤海喜来登酒店", "#173177"), + new WxMaTemplateMessage.Data("keyword4", "广州市天河区天河路208号", "#173177"))) + .templateId(config.getTemplateId()) + .emphasisKeyword("keyword1.DATA") + .build(); + + String msgId = this.wxService.getMsgService().sendTemplateMsg(templateMessage); + Assert.assertNotNull(msgId); + System.out.println(msgId); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java new file mode 100644 index 0000000000..48dad9362a --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java @@ -0,0 +1,26 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.io.File; + +/** + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaQrcodeServiceImplTest { + @Inject + protected WxMaService wxService; + + @Test + public void testCreateQrCode() throws Exception { + final File qrCode = this.wxService.getQrcodeService().createQrcode("111", 122); + System.out.println(qrCode); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java new file mode 100644 index 0000000000..1c99530d36 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java @@ -0,0 +1,35 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import me.chanjar.weixin.common.exception.WxErrorException; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertTrue; + +/** + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaServiceImplTest { + + @Inject + private WxMaService wxService; + + public void testRefreshAccessToken() throws WxErrorException { + WxMaConfig configStorage = this.wxService.getWxMaConfig(); + String before = configStorage.getAccessToken(); + this.wxService.getAccessToken(false); + + String after = configStorage.getAccessToken(); + assertNotEquals(before, after); + assertTrue(StringUtils.isNotBlank(after)); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplTest.java new file mode 100644 index 0000000000..a19692763b --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplTest.java @@ -0,0 +1,46 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +/** + * 测试用户相关的接口 + * + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaUserServiceImplTest { + + @Inject + private WxMaService wxService; + + @Test + public void testGetSessionKey() throws Exception { + assertNotNull(this.wxService.getUserService().getSessionInfo("aaa")); + } + + @Test + public void testGetUserInfo() throws Exception { + WxMaUserInfo userInfo = this.wxService.getUserService().getUserInfo("tiihtNczf5v6AKRyjwEUhQ==", + "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew==", + "r7BXXKkLb8qrSNn05n0qiA=="); + assertNotNull(userInfo); + System.out.println(userInfo.toString()); + } + + @Test + public void testCheckUserInfo() throws Exception { + assertTrue(this.wxService.getUserService().checkUserInfo("HyVFkGl5F5OQWJZZaNzBBg==", + "{\"nickName\":\"Band\",\"gender\":1,\"language\":\"zh_CN\",\"city\":\"Guangzhou\",\"province\":\"Guangdong\",\"country\":\"CN\",\"avatarUrl\":\"http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0\"}", + "75e81ceda165f4ffa64f4068af58c64b8f54b88c")); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessageTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessageTest.java new file mode 100644 index 0000000000..f2ef8bfac5 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessageTest.java @@ -0,0 +1,40 @@ +package cn.binarywang.wx.miniapp.bean; + +import me.chanjar.weixin.common.api.WxConsts; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author Binary Wang + */ +@Test +public class WxMaKefuMessageTest { + + public void testTextReply() { + WxMaKefuMessage reply = new WxMaKefuMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxConsts.CUSTOM_MSG_TEXT); + reply.setContent("sfsfdsdf"); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); + } + + public void testTextBuild() { + WxMaKefuMessage reply = WxMaKefuMessage.TEXT().toUser("OPENID").content("sfsfdsdf").build(); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); + } + + public void testImageReply() { + WxMaKefuMessage reply = new WxMaKefuMessage(); + reply.setToUser("OPENID"); + reply.setMsgType(WxConsts.CUSTOM_MSG_IMAGE); + reply.setMediaId("MEDIA_ID"); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); + } + + public void testImageBuild() { + WxMaKefuMessage reply = WxMaKefuMessage.IMAGE().toUser("OPENID").mediaId("MEDIA_ID").build(); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); + } + + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaMessageTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaMessageTest.java new file mode 100644 index 0000000000..881091a1df --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaMessageTest.java @@ -0,0 +1,130 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import me.chanjar.weixin.common.api.WxConsts; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +/** + * @author Binary Wang + */ +@Test +public class WxMaMessageTest { + + public void testFromXml() { + String xml = "" + + "" + + " " + + "1348831860" + + "" + + "" + + "1234567890123456" + + "" + + "" + + "" + + "" + + "23.134521" + + "113.358803" + + "20" + + "" + + "" + + "" + + "<![CDATA[公众平台官网链接]]>" + + "" + + "" + + "" + + "23.137466" + + "113.352425" + + "119.385040" + + "" + + " " + + " " + + "" + + "" + + " 1\n" + + " " + + " " + + " " + + " " + + " " + + "" + + "" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "" + + ""; + WxMaMessage wxMessage = WxMaMessage.fromXml(xml); + assertEquals(wxMessage.getToUser(), "toUser"); + assertEquals(wxMessage.getFromUser(), "fromUser"); + assertEquals(wxMessage.getCreateTime(), new Long(1348831860L)); + assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); + assertEquals(wxMessage.getContent(), "this is a test"); + assertEquals(wxMessage.getMsgId(), new Long(1234567890123456L)); + assertEquals(wxMessage.getPicUrl(), "this is a url"); + assertEquals(wxMessage.getMediaId(), "media_id"); + assertEquals(wxMessage.getEvent(), "subscribe"); + } + + public void testFromXml2() { + + String xml = "" + + "" + + " " + + "1348831860" + + "" + + "" + + "1234567890123456" + + "" + + "" + + "" + + "" + + "23.134521" + + "113.358803" + + "20" + + "" + + "" + + "" + + "<![CDATA[公众平台官网链接]]>" + + "" + + "" + + "" + + "23.137466" + + "113.352425" + + "119.385040" + + "" + + " " + + " " + + "" + + "" + + " 1\n" + + " " + + " " + + " " + + " " + + " " + + "" + + "" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "" + + ""; + WxMaMessage wxMessage = WxMaMessage.fromXml(xml); + assertEquals(wxMessage.getToUser(), "toUser"); + assertEquals(wxMessage.getFromUser(), "fromUser"); + assertEquals(wxMessage.getCreateTime(), new Integer(1348831860)); + assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); + assertEquals(wxMessage.getContent(), "this is a test"); + assertEquals(wxMessage.getMsgId(), new Long(1234567890123456L)); + assertEquals(wxMessage.getPicUrl(), "this is a url"); + assertEquals(wxMessage.getMediaId(), "media_id"); + assertEquals(wxMessage.getEvent(), "subscribe"); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessageTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessageTest.java new file mode 100644 index 0000000000..ad6e62c2ca --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateMessageTest.java @@ -0,0 +1,31 @@ +package cn.binarywang.wx.miniapp.bean; + +import com.google.common.collect.Lists; +import org.testng.annotations.Test; + +import static org.testng.AssertJUnit.assertEquals; + +/** + * @author Binary Wang + */ +public class WxMaTemplateMessageTest { + @Test + public void testToJson() throws Exception { + WxMaTemplateMessage tm = WxMaTemplateMessage.newBuilder() + .toUser("OPENID") + //.color("aaaaa") + .formId("FORMID") + .page("index") + .data(Lists.newArrayList( + new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177"), + new WxMaTemplateMessage.Data("keyword2", "2015年01月05日12:30", "#173177"), + new WxMaTemplateMessage.Data("keyword3", "粤海喜来登酒店", "#173177"), + new WxMaTemplateMessage.Data("keyword4", "广州市天河区天河路208号", "#173177"))) + .templateId("TEMPLATE_ID") + .emphasisKeyword("keyword1.DATA") + .build(); + + assertEquals(tm.toJson(), "{\"touser\":\"OPENID\",\"template_id\":\"TEMPLATE_ID\",\"page\":\"index\",\"form_id\":\"FORMID\",\"emphasis_keyword\":\"keyword1.DATA\",\"data\":{\"keyword1\":{\"value\":\"339208499\",\"color\":\"#173177\"},\"keyword2\":{\"value\":\"2015年01月05日12:30\",\"color\":\"#173177\"},\"keyword3\":{\"value\":\"粤海喜来登酒店\",\"color\":\"#173177\"},\"keyword4\":{\"value\":\"广州市天河区天河路208号\",\"color\":\"#173177\"}}}"); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java new file mode 100644 index 0000000000..fe986c8e71 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java @@ -0,0 +1,148 @@ +package cn.binarywang.wx.miniapp.demo; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; +import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; +import cn.binarywang.wx.miniapp.message.WxMaMessageHandler; +import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; +import cn.binarywang.wx.miniapp.test.TestConfig; +import com.google.common.collect.Lists; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @author Binary Wang + */ +public class WxMaDemoServer { + + private static final WxMaMessageHandler logHandler = new WxMaMessageHandler() { + @Override + public void handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + System.out.println("收到消息:" + wxMessage.toString()); + service.getMsgService().sendKefuMsg(WxMaKefuMessage.TEXT().content("收到信息为:" + wxMessage.toJson()) + .toUser(wxMessage.getFromUser()).build()); + } + }; + + private static final WxMaMessageHandler textHandler = new WxMaMessageHandler() { + @Override + public void handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) + throws WxErrorException { + service.getMsgService().sendKefuMsg(WxMaKefuMessage.TEXT().content("回复文本消息") + .toUser(wxMessage.getFromUser()).build()); + } + + }; + + private static final WxMaMessageHandler picHandler = new WxMaMessageHandler() { + @Override + public void handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + try { + WxMediaUploadResult uploadResult = service.getMediaService() + .uploadMedia(WxMaConstants.MediaType.IMAGE, "png", + ClassLoader.getSystemResourceAsStream("tmp.png")); + service.getMsgService().sendKefuMsg( + WxMaKefuMessage + .IMAGE() + .mediaId(uploadResult.getMediaId()) + .toUser(wxMessage.getFromUser()) + .build()); + } catch (WxErrorException e) { + e.printStackTrace(); + } + } + }; + + private static final WxMaMessageHandler qrcodeHandler = new WxMaMessageHandler() { + @Override + public void handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + try { + final File file = service.getQrcodeService().createQrcode("123", 430); + WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia(WxMaConstants.MediaType.IMAGE, file); + service.getMsgService().sendKefuMsg( + WxMaKefuMessage + .IMAGE() + .mediaId(uploadResult.getMediaId()) + .toUser(wxMessage.getFromUser()) + .build()); + } catch (WxErrorException e) { + e.printStackTrace(); + } + } + }; + + private static final WxMaMessageHandler templateMsgHandler = new WxMaMessageHandler() { + @Override + public void handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) + throws WxErrorException { + service.getMsgService().sendTemplateMsg(WxMaTemplateMessage.newBuilder() + .templateId(templateId).data(Lists.newArrayList( + new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177"))) + .toUser(wxMessage.getFromUser()) + .formId("自己替换可用的formid") + .build()); + } + + }; + + private static WxMaConfig config; + private static WxMaService service; + private static WxMaMessageRouter router; + private static String templateId; + + public static void main(String[] args) throws Exception { + init(); + + Server server = new Server(8080); + + ServletHandler servletHandler = new ServletHandler(); + server.setHandler(servletHandler); + + ServletHolder endpointServletHolder = new ServletHolder(new WxMaPortalServlet(config, service, router)); + servletHandler.addServletWithMapping(endpointServletHolder, "/*"); + + server.start(); + server.join(); + } + + private static void init() { + try (InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml")) { + TestConfig config = TestConfig.fromXml(is1); + config.setAccessTokenLock(new ReentrantLock()); + templateId = config.getTemplateId(); + + WxMaDemoServer.config = config; + service = new WxMaServiceImpl(); + service.setWxMaConfig(config); + + router = new WxMaMessageRouter(service); + + router.rule().handler(logHandler).next() + .rule().async(false).content("模板").handler(templateMsgHandler).end() + .rule().async(false).content("文本").handler(textHandler).end() + .rule().async(false).content("图片").handler(picHandler).end() + .rule().async(false).content("二维码").handler(qrcodeHandler).end(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java new file mode 100644 index 0000000000..5cadb68925 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java @@ -0,0 +1,92 @@ +package cn.binarywang.wx.miniapp.demo; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaMessage; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; +import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +/** + * @author Binary Wang + */ +public class WxMaPortalServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + private WxMaConfig wxMaConfig; + private WxMaService wxMaService; + private WxMaMessageRouter wxMaMessageRouter; + + WxMaPortalServlet(WxMaConfig wxMaConfig, WxMaService wxMaService, + WxMaMessageRouter wxMaMessageRouter) { + this.wxMaConfig = wxMaConfig; + this.wxMaService = wxMaService; + this.wxMaMessageRouter = wxMaMessageRouter; + } + + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) + throws IOException { + response.setContentType("text/html;charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + + String signature = request.getParameter("signature"); + String nonce = request.getParameter("nonce"); + String timestamp = request.getParameter("timestamp"); + + if (!this.wxMaService.checkSignature(timestamp, nonce, signature)) { + // 消息签名不正确,说明不是公众平台发过来的消息 + response.getWriter().println("非法请求"); + return; + } + + String echoStr = request.getParameter("echostr"); + if (StringUtils.isNotBlank(echoStr)) { + // 说明是一个仅仅用来验证的请求,回显echostr + response.getWriter().println(echoStr); + return; + } + + String encryptType = request.getParameter("encrypt_type"); + final boolean isJson = Objects.equals(this.wxMaConfig.getMsgDataFormat(), WxMaConstants.MsgDataFormat.JSON); + if (StringUtils.isBlank(encryptType)) { + // 明文传输的消息 + WxMaMessage inMessage; + if (isJson) { + inMessage = WxMaMessage.fromJson(IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8)); + } else {//xml + inMessage = WxMaMessage.fromXml(request.getInputStream()); + } + + this.wxMaMessageRouter.route(inMessage); + response.getWriter().write("success"); + return; + } + + if ("aes".equals(encryptType)) { + // 是aes加密的消息 + String msgSignature = request.getParameter("msg_signature"); + WxMaMessage inMessage; + if (isJson) { + inMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(), this.wxMaConfig); + } else {//xml + inMessage = WxMaMessage.fromEncryptedXml(request.getInputStream(), this.wxMaConfig, timestamp, nonce, msgSignature); + } + + this.wxMaMessageRouter.route(inMessage); + response.getWriter().write("success"); + return; + } + + response.getWriter().println("不可识别的加密类型"); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java new file mode 100644 index 0000000000..3b569e1b89 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java @@ -0,0 +1,33 @@ +package cn.binarywang.wx.miniapp.test; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import com.google.inject.Binder; +import com.google.inject.Module; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @author Binary Wang + */ +public class ApiTestModule implements Module { + + @Override + public void configure(Binder binder) { + try (InputStream inputStream = ClassLoader.getSystemResourceAsStream("test-config.xml")) { + TestConfig config = TestConfig.fromXml(inputStream); + config.setAccessTokenLock(new ReentrantLock()); + + WxMaService wxService = new cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl(); + wxService.setWxMaConfig(config); + + binder.bind(WxMaService.class).toInstance(wxService); + binder.bind(WxMaConfig.class).toInstance(config); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java new file mode 100644 index 0000000000..ee941ef349 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java @@ -0,0 +1,61 @@ +package cn.binarywang.wx.miniapp.test; + +import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import org.apache.commons.lang3.builder.ToStringBuilder; + +import java.io.InputStream; +import java.util.concurrent.locks.Lock; + +/** + * @author Binary Wang + */ +@XStreamAlias("xml") +public class TestConfig extends WxMaInMemoryConfig { + + private String openid; + private String kfAccount; + private String templateId; + + public static TestConfig fromXml(InputStream is) { + XStream xstream = XStreamInitializer.getInstance(); + xstream.processAnnotations(TestConfig.class); + return (TestConfig) xstream.fromXML(is); + } + + public String getOpenid() { + return this.openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + + public String getKfAccount() { + return this.kfAccount; + } + + public void setKfAccount(String kfAccount) { + this.kfAccount = kfAccount; + } + + public String getTemplateId() { + return this.templateId; + } + + public void setTemplateId(String templateId) { + this.templateId = templateId; + } + + public void setAccessTokenLock(Lock lock) { + super.accessTokenLock = lock; + } + +} diff --git a/weixin-java-miniapp/src/test/resources/logback-test.xml b/weixin-java-miniapp/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..14d6a9a79b --- /dev/null +++ b/weixin-java-miniapp/src/test/resources/logback-test.xml @@ -0,0 +1,14 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %replace(%caller{1}){'Caller', ''} - %msg%n + + + + + + + + + diff --git a/weixin-java-miniapp/src/test/resources/test-config.sample.xml b/weixin-java-miniapp/src/test/resources/test-config.sample.xml new file mode 100644 index 0000000000..1f6cc38887 --- /dev/null +++ b/weixin-java-miniapp/src/test/resources/test-config.sample.xml @@ -0,0 +1,11 @@ + + JSON或者XML + appid + secret + Token + EncodingAESKey + 可以不填写 + 可以不填写 + 某个用户的openId + 模版消息的模版ID + diff --git a/weixin-java-miniapp/src/test/resources/tmp.png b/weixin-java-miniapp/src/test/resources/tmp.png new file mode 100644 index 0000000000..5cb4a40605 Binary files /dev/null and b/weixin-java-miniapp/src/test/resources/tmp.png differ diff --git a/weixin-java-mp/build.gradle b/weixin-java-mp/build.gradle deleted file mode 100644 index de1534a3a9..0000000000 --- a/weixin-java-mp/build.gradle +++ /dev/null @@ -1,13 +0,0 @@ - -description = 'WeiXin Java Tools - MP' -dependencies { - compile project(':weixin-java-common') - testCompile group: 'junit', name: 'junit', version:'4.11' - testCompile group: 'org.testng', name: 'testng', version:'6.8.7' - testCompile group: 'org.mockito', name: 'mockito-all', version:'1.9.5' - testCompile group: 'com.google.inject', name: 'guice', version:'3.0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.RC0' - testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.RC0' - testCompile group: 'joda-time', name: 'joda-time', version:'2.9.4' -} -test.useTestNG() diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 3f4bf6498f..bd8f147cb0 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -1,12 +1,13 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0"> 4.0.0 com.github.binarywang weixin-java-parent - 2.6.0 + 2.7.0 weixin-java-mp WeiXin Java Tools - MP @@ -18,6 +19,18 @@ weixin-java-common ${project.version} + + + org.jodd + jodd-http + provided + + + com.squareup.okhttp3 + okhttp + provided + + org.testng testng @@ -41,13 +54,17 @@ joda-time joda-time - 2.9.4 test redis.clients jedis + + ch.qos.logback + logback-classic + test + diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java index d4a36c65b8..08ea9a7007 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java @@ -6,15 +6,26 @@ /** * 卡券相关接口 - * @author YuJian(mgcnrx11@hotmail.com) on 01/11/2016 + * + * @author YuJian(mgcnrx11@hotmail.com) on 01/11/2016 */ public interface WxMpCardService { + String CARD_GET = "https://api.weixin.qq.com/card/get"; + String CARD_GET_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; + String CARD_CODE_DECRYPT = "https://api.weixin.qq.com/card/code/decrypt"; + String CARD_CODE_GET = "https://api.weixin.qq.com/card/code/get"; + String CARD_CODE_CONSUME = "https://api.weixin.qq.com/card/code/consume"; + String CARD_CODE_MARK = "https://api.weixin.qq.com/card/code/mark"; + + /** + * 得到WxMpService + */ + WxMpService getWxMpService(); /** * 获得卡券api_ticket,不强制刷新卡券api_ticket * * @return 卡券api_ticket - * @throws WxErrorException * @see #getCardApiTicket(boolean) */ String getCardApiTicket() throws WxErrorException; @@ -48,7 +59,7 @@ public interface WxMpCardService { * @return 卡券Api签名对象 */ WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws - WxErrorException; + WxErrorException; /** * 卡券Code解码 @@ -67,7 +78,7 @@ WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws * @return WxMpCardResult对象 */ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) - throws WxErrorException; + throws WxErrorException; /** * 卡券Code核销。核销失败会抛出异常 @@ -99,7 +110,7 @@ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 */ void markCardCode(String code, String cardId, String openId, boolean isMark) throws - WxErrorException; + WxErrorException; /** * 查看卡券详情接口 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java index f4053899ee..dbff2a7abe 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import java.io.File; import java.util.concurrent.locks.Lock; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java index 32f219d51a..7610b03d3a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java @@ -1,22 +1,36 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.mp.bean.datacube.WxDataCubeArticleResult; -import me.chanjar.weixin.mp.bean.datacube.WxDataCubeArticleTotal; -import me.chanjar.weixin.mp.bean.datacube.WxDataCubeInterfaceResult; -import me.chanjar.weixin.mp.bean.datacube.WxDataCubeMsgResult; -import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate; -import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; +import me.chanjar.weixin.mp.bean.datacube.*; import java.util.Date; import java.util.List; /** * 统计分析相关接口 - * Created by Binary Wang on 2016/8/23. + * Created by Binary Wang on 2016/8/23. + * * @author binarywang (https://github.com/binarywang) */ public interface WxMpDataCubeService { + String GET_USER_SUMMARY = "https://api.weixin.qq.com/datacube/getusersummary"; + String GET_USER_CUMULATE = "https://api.weixin.qq.com/datacube/getusercumulate"; + String GET_ARTICLE_SUMMARY = "https://api.weixin.qq.com/datacube/getarticlesummary"; + String GET_ARTICLE_TOTAL = "https://api.weixin.qq.com/datacube/getarticletotal"; + String GET_USER_READ = "https://api.weixin.qq.com/datacube/getuserread"; + String GET_USER_READ_HOUR = "https://api.weixin.qq.com/datacube/getuserreadhour"; + String GET_USER_SHARE = "https://api.weixin.qq.com/datacube/getusershare"; + String GET_USER_SHARE_HOUR = "https://api.weixin.qq.com/datacube/getusersharehour"; + String GET_UPSTREAM_MSG = "https://api.weixin.qq.com/datacube/getupstreammsg"; + String GET_UPSTREAM_MSG_HOUR = "https://api.weixin.qq.com/datacube/getupstreammsghour"; + String GET_UPSTREAM_MSG_WEEK = "https://api.weixin.qq.com/datacube/getupstreammsgweek"; + String GET_UPSTREAM_MSG_MONTH = "https://api.weixin.qq.com/datacube/getupstreammsgmonth"; + String GET_UPSTREAM_MSG_DIST = "https://api.weixin.qq.com/datacube/getupstreammsgdist"; + String GET_UPSTREAM_MSG_DIST_WEEK = "https://api.weixin.qq.com/datacube/getupstreammsgdistweek"; + String GET_UPSTREAM_MSG_DIST_MONTH = "https://api.weixin.qq.com/datacube/getupstreammsgdistmonth"; + String GET_INTERFACE_SUMMARY = "https://api.weixin.qq.com/datacube/getinterfacesummary"; + String GET_INTERFACE_SUMMARY_HOUR = "https://api.weixin.qq.com/datacube/getinterfacesummaryhour"; + //*******************用户分析数据接口***********************// /** @@ -192,6 +206,7 @@ public interface WxMpDataCubeService { List getUpstreamMsgDistMonth(Date beginDate, Date endDate) throws WxErrorException; //*******************接口分析数据接口***********************// + /** *
        * 获取接口分析数据(getinterfacesummary)
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java
    index 2580d23a76..6b3fcd9e39 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java
    @@ -20,6 +20,7 @@ public interface WxMpDeviceService {
        *   获取一组新的deviceid和设备二维码
        *   详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-6
        * 
    + * * @param productId 产品id * @return 返回WxDeviceQrCodeResult */ @@ -30,6 +31,7 @@ public interface WxMpDeviceService { * 将device id及其属性信息提交公众平台进行授权 * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-6 *
    + * * @param wxDeviceAuthorize 授权请求对象 * @return WxDeviceAuthorizeResult */ @@ -41,6 +43,7 @@ public interface WxMpDeviceService { * 第三方后台绑定成功后,通知公众平台 * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html/page=3-4-7 *
    + * * @param wxDeviceBind 绑定请求对象 * @return WxDeviceBindResult */ @@ -51,6 +54,7 @@ public interface WxMpDeviceService { * 强制绑定用户和设备 * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-7 *
    + * * @param wxDeviceBind 强制绑定请求对象 * @return WxDeviceBindResult */ @@ -61,6 +65,7 @@ public interface WxMpDeviceService { * 第三方确认用户和设备的解绑操作 * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html/page=3-4-7 * + * * @param wxDeviceBind 绑定请求对象 * @return WxDeviceBidResult */ @@ -71,6 +76,7 @@ public interface WxMpDeviceService { * 强制解绑用户和设备 * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-7 * + * * @param wxDeviceBind 强制解绑请求对象 * @return WxDeviceBindResult */ @@ -81,17 +87,19 @@ public interface WxMpDeviceService { * 通过device type和device id 获取设备主人的openid * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-11 * + * * @param deviceType 设备类型,目前为"公众账号原始ID" - * @param deviceId 设备ID + * @param deviceId 设备ID * @return WxDeviceOpenIdResult */ - WxDeviceOpenIdResult getOpenId(String deviceType,String deviceId) throws WxErrorException; + WxDeviceOpenIdResult getOpenId(String deviceType, String deviceId) throws WxErrorException; /** *
        *   通过openid获取用户在当前devicetype下绑定的deviceid列表`
        *   详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-12
        * 
    + * * @param openId 要查询的用户的openid * @return WxDeviceBindDeviceResult */ diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java index 4bd1daec7e..e74f518867 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java @@ -2,7 +2,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.ToStringUtils; -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import java.io.File; import java.util.concurrent.locks.Lock; @@ -51,6 +51,10 @@ public String getAccessToken() { return this.accessToken; } + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + @Override public Lock getAccessTokenLock() { return this.accessTokenLock; @@ -82,6 +86,10 @@ public String getJsapiTicket() { return this.jsapiTicket; } + public void setJsapiTicket(String jsapiTicket) { + this.jsapiTicket = jsapiTicket; + } + @Override public Lock getJsapiTicketLock() { return this.jsapiTicketLock; @@ -112,6 +120,10 @@ public String getCardApiTicket() { return this.cardApiTicket; } + public void setCardApiTicket(String cardApiTicket) { + this.cardApiTicket = cardApiTicket; + } + @Override public Lock getCardApiTicketLock() { return this.cardApiTicketLock; @@ -247,14 +259,6 @@ public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientB this.apacheHttpClientBuilder = apacheHttpClientBuilder; } - public void setAccessToken(String accessToken) { - this.accessToken = accessToken; - } - - public void setJsapiTicket(String jsapiTicket) { - this.jsapiTicket = jsapiTicket; - } - public long getJsapiTicketExpiresTime() { return this.jsapiTicketExpiresTime; } @@ -263,10 +267,6 @@ public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) { this.jsapiTicketExpiresTime = jsapiTicketExpiresTime; } - public void setCardApiTicket(String cardApiTicket) { - this.cardApiTicket = cardApiTicket; - } - public long getCardApiTicketExpiresTime() { return this.cardApiTicketExpiresTime; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java index b2bb9b4e89..d22214dfa1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java @@ -25,10 +25,10 @@ public String getAccessToken() { @Override public boolean isAccessTokenExpired() { - return getAccessToken() == null ? true : false; + return jedis.ttl(ACCESS_TOKEN_KEY.concat(appId)) < 2; } -@Override + @Override public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { jedis.set(ACCESS_TOKEN_KEY.concat(appId), accessToken); jedis.expire(ACCESS_TOKEN_KEY.concat(appId), expiresInSeconds - 200); @@ -46,7 +46,7 @@ public String getJsapiTicket() { @Override public boolean isJsapiTicketExpired() { - return getJsapiTicket() == null ? true : false; + return jedis.ttl(JSAPI_TICKET_KEY.concat(appId)) < 2; } @Override @@ -70,7 +70,7 @@ public String getCardApiTicket() { @Override public boolean isCardApiTicketExpired() { - return getCardApiTicket() == null ? true : false; + return jedis.ttl(CARDAPI_TICKET_KEY.concat(appId)) < 2; } @Override @@ -87,4 +87,4 @@ public void expireCardApiTicket() { public void setJedis(Jedis jedis) { this.jedis = jedis; } -} \ No newline at end of file +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java index f57c963019..36e13b13c4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java @@ -9,14 +9,28 @@ import java.util.Date; /** + *
      * 客服接口 ,
    - * 命名采用kefu拼音的原因是:
    - * 其英文CustomerService如果再加上Service后缀显得有点啰嗦,
    - * 如果不加又显得表意不完整
    + * 注意:命名采用kefu拼音的原因是:其英文CustomerService如果再加上Service后缀显得有点啰嗦,如果不加又显得表意不完整。
    + * 
    * * @author Binary Wang */ public interface WxMpKefuService { + String MESSAGE_CUSTOM_SEND = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; + String GET_KF_LIST = "https://api.weixin.qq.com/cgi-bin/customservice/getkflist"; + String GET_ONLINE_KF_LIST = "https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist"; + String KFACCOUNT_ADD = "https://api.weixin.qq.com/customservice/kfaccount/add"; + String KFACCOUNT_UPDATE = "https://api.weixin.qq.com/customservice/kfaccount/update"; + String KFACCOUNT_INVITE_WORKER = "https://api.weixin.qq.com/customservice/kfaccount/inviteworker"; + String KFACCOUNT_UPLOAD_HEAD_IMG = "https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?kf_account=%s"; + String KFACCOUNT_DEL = "https://api.weixin.qq.com/customservice/kfaccount/del?kf_account=%s"; + String KFSESSION_CREATE = "https://api.weixin.qq.com/customservice/kfsession/create"; + String KFSESSION_CLOSE = "https://api.weixin.qq.com/customservice/kfsession/close"; + String KFSESSION_GET_SESSION = "https://api.weixin.qq.com/customservice/kfsession/getsession?openid=%s"; + String KFSESSION_GET_SESSION_LIST = "https://api.weixin.qq.com/customservice/kfsession/getsessionlist?kf_account=%s"; + String KFSESSION_GET_WAIT_CASE = "https://api.weixin.qq.com/customservice/kfsession/getwaitcase"; + String MSGRECORD_GET_MSG_LIST = "https://api.weixin.qq.com/customservice/msgrecord/getmsglist"; /** *
    @@ -82,7 +96,7 @@ public interface WxMpKefuService {
        * 
    */ boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) - throws WxErrorException; + 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 8c867c5fc0..8e769d3e2d 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
    @@ -2,9 +2,6 @@
     
     import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
     import me.chanjar.weixin.common.exception.WxErrorException;
    -import me.chanjar.weixin.mp.bean.material.WxMpMaterial;
    -import me.chanjar.weixin.mp.bean.material.WxMpMaterialArticleUpdate;
    -import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews;
     import me.chanjar.weixin.mp.bean.material.*;
     
     import java.io.File;
    @@ -37,12 +34,13 @@ public interface WxMpMaterialService {
        *    语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
        *    视频(video):10MB,支持MP4格式
        *    缩略图(thumb):64KB,支持JPG格式
    -   *媒体文件在后台保存时间为3天,即3天后media_id失效。
    +   * 媒体文件在后台保存时间为3天,即3天后media_id失效。
        * 详情请见: 新增临时素材
        * 接口url格式:https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
        * 
    + * * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} - * @param file 文件对象 + * @param file 文件对象 * @throws WxErrorException * @see #mediaUpload(String, String, InputStream) */ @@ -106,12 +104,12 @@ public interface WxMpMaterialService { * 接口url格式:https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE * * 除了3天就会失效的临时素材外,开发者有时需要永久保存一些素材,届时就可以通过本接口新增永久素材。 - 永久图片素材新增后,将带有URL返回给开发者,开发者可以在腾讯系域名内使用(腾讯系域名外使用,图片将被屏蔽)。 - 请注意: - 1、新增的永久素材也可以在公众平台官网素材管理模块中看到 - 2、永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000,其他类型为1000 - 3、素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式 - 4、调用该接口需https协议 + * 永久图片素材新增后,将带有URL返回给开发者,开发者可以在腾讯系域名内使用(腾讯系域名外使用,图片将被屏蔽)。 + * 请注意: + * 1、新增的永久素材也可以在公众平台官网素材管理模块中看到 + * 2、永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000,其他类型为1000 + * 3、素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式 + * 4、调用该接口需https协议 * * * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} @@ -127,12 +125,12 @@ public interface WxMpMaterialService { * 接口url格式:https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN * * 除了3天就会失效的临时素材外,开发者有时需要永久保存一些素材,届时就可以通过本接口新增永久素材。 - 永久图片素材新增后,将带有URL返回给开发者,开发者可以在腾讯系域名内使用(腾讯系域名外使用,图片将被屏蔽)。 - 请注意: - 1、新增的永久素材也可以在公众平台官网素材管理模块中看到 - 2、永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000,其他类型为1000 - 3、素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式 - 4、调用该接口需https协议 + * 永久图片素材新增后,将带有URL返回给开发者,开发者可以在腾讯系域名内使用(腾讯系域名外使用,图片将被屏蔽)。 + * 请注意: + * 1、新增的永久素材也可以在公众平台官网素材管理模块中看到 + * 2、永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000,其他类型为1000 + * 3、素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式 + * 4、调用该接口需https协议 * * * @param news 上传的图文消息, 请看{@link WxMpMaterialNews} 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 f1c9fd47d9..bfd606175c 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 @@ -19,6 +19,7 @@ public interface WxMpMenuService { * 如果要创建个性化菜单,请设置matchrule属性 * 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN * + * * @return 如果是个性化菜单,则返回menuid,否则返回null */ String menuCreate(WxMenu menu) throws WxErrorException; @@ -30,6 +31,7 @@ public interface WxMpMenuService { * 如果要创建个性化菜单,请设置matchrule属性 * 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN * + * * @return 如果是个性化菜单,则返回menuid,否则返回null */ String menuCreate(String json) throws WxErrorException; @@ -74,16 +76,16 @@ public interface WxMpMenuService { *
        * 获取自定义菜单配置接口
        * 本接口将会提供公众号当前使用的自定义菜单的配置,如果公众号是通过API调用设置的菜单,则返回菜单的开发配置,而如果公众号是在公众平台官网通过网站功能发布菜单,则本接口返回运营者设置的菜单配置。
    -     请注意:
    -     1、第三方平台开发者可以通过本接口,在旗下公众号将业务授权给你后,立即通过本接口检测公众号的自定义菜单配置,并通过接口再次给公众号设置好自动回复规则,以提升公众号运营者的业务体验。
    -     2、本接口与自定义菜单查询接口的不同之处在于,本接口无论公众号的接口是如何设置的,都能查询到接口,而自定义菜单查询接口则仅能查询到使用API设置的菜单配置。
    -     3、认证/未认证的服务号/订阅号,以及接口测试号,均拥有该接口权限。
    -     4、从第三方平台的公众号登录授权机制上来说,该接口从属于消息与菜单权限集。
    -     5、本接口中返回的图片/语音/视频为临时素材(临时素材每次获取都不同,3天内有效,通过素材管理-获取临时素材接口来获取这些素材),本接口返回的图文消息为永久素材素材(通过素材管理-获取永久素材接口来获取这些素材)。
    +   * 请注意:
    +   * 1、第三方平台开发者可以通过本接口,在旗下公众号将业务授权给你后,立即通过本接口检测公众号的自定义菜单配置,并通过接口再次给公众号设置好自动回复规则,以提升公众号运营者的业务体验。
    +   * 2、本接口与自定义菜单查询接口的不同之处在于,本接口无论公众号的接口是如何设置的,都能查询到接口,而自定义菜单查询接口则仅能查询到使用API设置的菜单配置。
    +   * 3、认证/未认证的服务号/订阅号,以及接口测试号,均拥有该接口权限。
    +   * 4、从第三方平台的公众号登录授权机制上来说,该接口从属于消息与菜单权限集。
    +   * 5、本接口中返回的图片/语音/视频为临时素材(临时素材每次获取都不同,3天内有效,通过素材管理-获取临时素材接口来获取这些素材),本接口返回的图文消息为永久素材素材(通过素材管理-获取永久素材接口来获取这些素材)。
        *  接口调用请求说明:
    -        http请求方式: GET(请使用https协议)
    -        https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
    -   *
    + * http请求方式: GET(请使用https协议) + * https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN + * */ WxMpGetSelfMenuInfoResult getSelfMenuInfo() 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 812992c9b1..fd522c7730 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 @@ -9,6 +9,7 @@ public interface WxMpMessageMatcher { /** * 消息是否匹配某种模式 + * * @param 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 24dc4451a1..5acf0040aa 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java @@ -1,15 +1,5 @@ package me.chanjar.weixin.mp.api; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import me.chanjar.weixin.common.api.WxErrorExceptionHandler; import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; @@ -20,6 +10,17 @@ import me.chanjar.weixin.common.util.LogExceptionHandler; import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; /** *
    @@ -46,15 +47,13 @@
      * router.route(message);
      *
      * 
    - * @author Daniel Qian * + * @author Daniel Qian */ public class WxMpMessageRouter { - protected final Logger log = LoggerFactory.getLogger(WxMpMessageRouter.class); - private static final int DEFAULT_THREAD_POOL_SIZE = 100; - + protected final Logger log = LoggerFactory.getLogger(WxMpMessageRouter.class); private final List rules = new ArrayList<>(); private final WxMpService wxMpService; @@ -80,7 +79,6 @@ public WxMpMessageRouter(WxMpService wxMpService) { * 设置自定义的 {@link ExecutorService} * 如果不调用该方法,默认使用 Executors.newFixedThreadPool(100) * - * @param executorService */ public void setExecutorService(ExecutorService executorService) { this.executorService = executorService; @@ -91,7 +89,6 @@ public void setExecutorService(ExecutorService executorService) { * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker} * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker} * - * @param messageDuplicateChecker */ public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { this.messageDuplicateChecker = messageDuplicateChecker; @@ -102,7 +99,6 @@ public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicat * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager} * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager} * - * @param sessionManager */ public void setSessionManager(WxSessionManager sessionManager) { this.sessionManager = sessionManager; @@ -113,7 +109,6 @@ public void setSessionManager(WxSessionManager sessionManager) { * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler} * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler} * - * @param exceptionHandler */ public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { this.exceptionHandler = exceptionHandler; @@ -132,10 +127,9 @@ public WxMpMessageRouterRule rule() { /** * 处理微信消息 - * @param wxMessage */ - public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) { - if (isDuplicateMessage(wxMessage)) { + public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map context) { + if (isMsgDuplicated(wxMessage)) { // 如果是重复消息,那么就不做处理 return null; } @@ -145,7 +139,7 @@ public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) { for (final WxMpMessageRouterRule rule : this.rules) { if (rule.test(wxMessage)) { matchRules.add(rule); - if(!rule.isReEnter()) { + if (!rule.isReEnter()) { break; } } @@ -159,17 +153,17 @@ public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) { final List> futures = new ArrayList<>(); for (final WxMpMessageRouterRule rule : matchRules) { // 返回最后一个非异步的rule的执行结果 - if(rule.isAsync()) { + if (rule.isAsync()) { futures.add( - this.executorService.submit(new Runnable() { - @Override - public void run() { - rule.service(wxMessage, WxMpMessageRouter.this.wxMpService, WxMpMessageRouter.this.sessionManager, WxMpMessageRouter.this.exceptionHandler); - } - }) + this.executorService.submit(new Runnable() { + @Override + public void run() { + rule.service(wxMessage, context, WxMpMessageRouter.this.wxMpService, WxMpMessageRouter.this.sessionManager, WxMpMessageRouter.this.exceptionHandler); + } + }) ); } else { - res = rule.service(wxMessage, this.wxMpService, this.sessionManager, this.exceptionHandler); + res = rule.service(wxMessage, context, this.wxMpService, this.sessionManager, this.exceptionHandler); // 在同步操作结束,session访问结束 this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser()); sessionEndAccess(wxMessage); @@ -186,9 +180,7 @@ public void run() { WxMpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUser()); // 异步操作结束,session访问结束 sessionEndAccess(wxMessage); - } catch (InterruptedException e) { - WxMpMessageRouter.this.log.error("Error happened when wait task finish", e); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { WxMpMessageRouter.this.log.error("Error happened when wait task finish", e); } } @@ -198,9 +190,13 @@ public void run() { return res; } - protected boolean isDuplicateMessage(WxMpXmlMessage wxMessage) { + public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) { + return this.route(wxMessage, new HashMap()); + } + + protected boolean isMsgDuplicated(WxMpXmlMessage wxMessage) { - StringBuffer messageId = new StringBuffer(); + StringBuilder messageId = new StringBuilder(); if (wxMessage.getMsgId() == null) { messageId.append(wxMessage.getCreateTime()) .append("-").append(wxMessage.getFromUser()) @@ -217,11 +213,10 @@ protected boolean isDuplicateMessage(WxMpXmlMessage wxMessage) { /** * 对session的访问结束 - * @param wxMessage */ protected void sessionEndAccess(WxMpXmlMessage wxMessage) { - InternalSession session = ((InternalSessionManager)this.sessionManager).findSession(wxMessage.getFromUser()); + InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUser()); if (session != null) { session.endAccess(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java index 6859b7d77d..e44406f4b1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java @@ -1,8 +1,8 @@ package me.chanjar.weixin.mp.api; +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.api.WxErrorExceptionHandler; import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; @@ -168,22 +168,22 @@ public WxMpMessageRouter next() { */ protected boolean test(WxMpXmlMessage wxMessage) { return - (this.fromUser == null || this.fromUser.equals(wxMessage.getFromUser())) - && - (this.msgType == null || this.msgType.toLowerCase().equals((wxMessage.getMsgType()==null?null:wxMessage.getMsgType().toLowerCase()))) - && - (this.event == null || this.event.toLowerCase().equals((wxMessage.getEvent()==null?null:wxMessage.getEvent().toLowerCase()))) - && - (this.eventKey == null || this.eventKey.toLowerCase().equals((wxMessage.getEventKey()==null?null:wxMessage.getEventKey().toLowerCase()))) - && - (this.content == null || this.content - .equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) - && - (this.rContent == null || Pattern - .matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) - && - (this.matcher == null || this.matcher.match(wxMessage)) - ; + (this.fromUser == null || this.fromUser.equals(wxMessage.getFromUser())) + && + (this.msgType == null || this.msgType.toLowerCase().equals((wxMessage.getMsgType() == null ? null : wxMessage.getMsgType().toLowerCase()))) + && + (this.event == null || this.event.toLowerCase().equals((wxMessage.getEvent() == null ? null : wxMessage.getEvent().toLowerCase()))) + && + (this.eventKey == null || this.eventKey.toLowerCase().equals((wxMessage.getEventKey() == null ? null : wxMessage.getEventKey().toLowerCase()))) + && + (this.content == null || this.content + .equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) + && + (this.rContent == null || Pattern + .matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) + && + (this.matcher == null || this.matcher.match(wxMessage)) + ; } /** @@ -193,13 +193,16 @@ protected boolean test(WxMpXmlMessage wxMessage) { * @return true 代表继续执行别的router,false 代表停止执行别的router */ protected WxMpXmlOutMessage service(WxMpXmlMessage wxMessage, - WxMpService wxMpService, - WxSessionManager sessionManager, - WxErrorExceptionHandler exceptionHandler) { + Map context, + WxMpService wxMpService, + WxSessionManager sessionManager, + WxErrorExceptionHandler exceptionHandler) { - try { + if (context == null) { + context = new HashMap<>(); + } - Map context = new HashMap<>(); + try { // 如果拦截器不通过 for (WxMpMessageInterceptor interceptor : this.interceptors) { if (!interceptor.intercept(wxMessage, context, wxMpService, sessionManager)) { @@ -211,7 +214,7 @@ protected WxMpXmlOutMessage service(WxMpXmlMessage wxMessage, WxMpXmlOutMessage res = null; for (WxMpMessageHandler handler : this.handlers) { // 返回最后handler的结果 - if(handler == null){ + if (handler == null) { continue; } res = handler.handle(wxMessage, context, wxMpService, sessionManager); 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 ba8665e946..e2e17eb359 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 @@ -10,6 +10,7 @@ * 二维码相关操作接口 * 文档地址:https://mp.weixin.qq.com/wiki?action=doc&id=mp1443433542&t=0.9274944716856435 * + * * @author Binary Wang */ public interface WxMpQrcodeService { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index cf1401a571..71a5413523 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -2,15 +2,80 @@ import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.mp.bean.*; import me.chanjar.weixin.mp.bean.result.*; -import org.apache.http.HttpHost; /** * 微信API的Service */ public interface WxMpService { + /** + * 获取access_token + */ + String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; + /** + * 获得jsapi_ticket + */ + String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; + /** + * 上传群发用的图文消息 + */ + String MEDIA_UPLOAD_NEWS_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; + /** + * 上传群发用的视频 + */ + String MEDIA_UPLOAD_VIDEO_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; + /** + * 分组群发消息 + */ + String MESSAGE_MASS_SENDALL_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; + /** + * 按openId列表群发消息 + */ + String MESSAGE_MASS_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; + /** + * 群发消息预览接口 + */ + String MESSAGE_MASS_PREVIEW_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; + /** + * 长链接转短链接接口 + */ + String SHORTURL_API_URL = "https://api.weixin.qq.com/cgi-bin/shorturl"; + /** + * 语义查询接口 + */ + String SEMANTIC_SEMPROXY_SEARCH_URL = "https://api.weixin.qq.com/semantic/semproxy/search"; + /** + * 用code换取oauth2的access token + */ + String OAUTH2_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"; + /** + * 刷新oauth2的access token + */ + String OAUTH2_REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"; + /** + * 用oauth2获取用户信息 + */ + String OAUTH2_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s"; + /** + * 验证oauth2的access token是否有效 + */ + String OAUTH2_VALIDATE_TOKEN_URL = "https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s"; + /** + * 获取微信服务器IP地址 + */ + String GET_CALLBACK_IP_URL = "https://api.weixin.qq.com/cgi-bin/getcallbackip"; + /** + * 第三方使用网站应用授权登录的url + */ + String QRCONNECT_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"; + /** + * oauth2授权的url连接 + */ + String CONNECT_OAUTH2_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"; /** *
    @@ -133,7 +198,6 @@ public interface WxMpService {
        * 长链接转短链接接口
        * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=长链接转短链接接口
        * 
    - * */ String shortUrl(String long_url) throws WxErrorException; @@ -153,8 +217,8 @@ public interface WxMpService { * * * @param redirectURI 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode - * @param scope 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可 - * @param state 非必填,用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验 + * @param scope 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可 + * @param state 非必填,用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验 * @return url */ String buildQrConnectUrl(String redirectURI, String scope, String state); @@ -190,7 +254,7 @@ public interface WxMpService { * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以 * * - * @param lang zh_CN, zh_TW, en + * @param lang zh_CN, zh_TW, en */ WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException; @@ -198,7 +262,6 @@ public interface WxMpService { *
        * 验证oauth2的access token是否有效
        * 
    - * */ boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken); @@ -224,7 +287,7 @@ public interface WxMpService { *
        * Service没有实现某个API的时候,可以用这个,
        * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
    -   * 可以参考,{@link me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor}的实现方法
    +   * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
        * 
    */ T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; @@ -232,12 +295,7 @@ public interface WxMpService { /** * 获取代理对象 */ - HttpHost getHttpProxy(); - - /** - * 注入 {@link WxMpConfigStorage} 的实现 - */ - void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider); + //HttpHost getRequestHttpProxy(); /** *
    @@ -262,6 +320,11 @@ public interface WxMpService {
        */
       WxMpConfigStorage getWxMpConfigStorage();
     
    +  /**
    +   * 注入 {@link WxMpConfigStorage} 的实现
    +   */
    +  void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider);
    +
       /**
        * 返回客服接口方法实现类,以方便调用其各个接口
        *
    @@ -345,4 +408,23 @@ public interface WxMpService {
        * @return WxMpDeviceService
        */
       WxMpDeviceService getDeviceService();
    +
    +  /**
    +   * 返回摇一摇周边相关接口方法的实现类对象,以方便调用其各个接口
    +   *
    +   * @return WxMpShakeService
    +   */
    +  WxMpShakeService getShakeService();
    +
    +  /**
    +   * 初始化http请求对象
    +   */
    +  void initHttp();
    +
    +  /**
    +   * @return
    +   */
    +  RequestHttp getRequestHttp();
    +
    +
     }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java
    new file mode 100644
    index 0000000000..87a6747af5
    --- /dev/null
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java
    @@ -0,0 +1,27 @@
    +package me.chanjar.weixin.mp.api;
    +
    +import me.chanjar.weixin.common.exception.WxErrorException;
    +import me.chanjar.weixin.mp.bean.WxMpShakeInfoResult;
    +import me.chanjar.weixin.mp.bean.WxMpShakeQuery;
    +
    +/**
    + * 摇一摇周边的相关接口
    + *
    + * @author rememberber
    + */
    +public interface WxMpShakeService {
    +
    +  /**
    +   * 
    +   * 获取设备及用户信息
    + * 获取设备信息,包括UUID、major、minor,以及距离、openID等信息。 + * 详情请见: https://mp.weixin.qq.com/wiki?action=doc&id=mp1443447963 + * http请求方式: POST(请使用https协议) + * 接口地址:https://api.weixin.qq.com/shakearound/user/getshakeinfo?access_token=ACCESS_TOKE + *
    + * + * @param wxMpShakeQuery 查询参数 + */ + WxMpShakeInfoResult getShakeInfo(WxMpShakeQuery wxMpShakeQuery) throws WxErrorException; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java index c214c46d9e..2634c3f36c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java @@ -9,10 +9,11 @@ /** * 门店管理的相关接口代码 - * @author binarywang(Binary Wang) + * + * @author binarywang(Binary Wang) * Created by Binary Wang on 2016-09-23. */ -public interface WxMpStoreService { +public interface WxMpStoreService { /** *
        * 创建门店
    @@ -23,7 +24,6 @@ public interface WxMpStoreService {
        * 详情请见: 微信门店接口
        * 接口格式: http://api.weixin.qq.com/cgi-bin/poi/addpoi?access_token=TOKEN
        * 
    - * */ void add(WxMpStoreBaseInfo request) throws WxErrorException; @@ -37,7 +37,8 @@ public interface WxMpStoreService { * 详情请见: 微信门店接口 * 接口格式:http://api.weixin.qq.com/cgi-bin/poi/getpoi?access_token=TOKEN *
    - * @param poiId 门店Id + * + * @param poiId 门店Id * @throws WxErrorException */ WxMpStoreBaseInfo get(String poiId) throws WxErrorException; @@ -49,7 +50,8 @@ public interface WxMpStoreService { * 详情请见: 微信门店接口 * 接口格式:http://api.weixin.qq.com/cgi-bin/poi/delpoi?access_token=TOKEN * - * @param poiId 门店Id + * + * @param poiId 门店Id * @throws WxErrorException */ void delete(String poiId) throws WxErrorException; @@ -61,6 +63,7 @@ public interface WxMpStoreService { * 详情请见: 微信门店接口 * 接口格式:http://api.weixin.qq.com/cgi-bin/poi/getpoilist?access_token=TOKEN * + * * @param begin 开始位置,0 即为从第一条开始查询 * @param limit 返回数据条数,最大允许50,默认为20 * @throws WxErrorException @@ -74,6 +77,7 @@ public interface WxMpStoreService { * 详情请见: 微信门店接口 * 接口格式:http://api.weixin.qq.com/cgi-bin/poi/getpoilist?access_token=TOKEN * + * * @throws WxErrorException */ List listAll() throws WxErrorException; @@ -85,6 +89,7 @@ public interface WxMpStoreService { * 详情请见: 微信门店接口 * 接口格式:http://api.weixin.qq.com/cgi-bin/poi/updatepoi?access_token=TOKEN * + * * @throws WxErrorException */ void update(WxMpStoreBaseInfo info) throws WxErrorException; @@ -96,6 +101,7 @@ public interface WxMpStoreService { * 详情请见: 微信门店接口 * 接口格式:http://api.weixin.qq.com/cgi-bin/poi/getwxcategory?access_token=TOKEN * + * * @throws WxErrorException */ List listCategories() throws WxErrorException; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java index 9b66f7223f..f9203c1644 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java @@ -56,6 +56,7 @@ public interface WxMpTemplateMsgService { * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN * 接口地址格式:https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token=ACCESS_TOKEN * + * * @param shortTemplateId 模板库中模板的编号,有“TM**”和“OPENTMTM**”等形式 * @return templateId 模板Id */ 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 964991281a..e207e5efc3 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 @@ -48,7 +48,7 @@ public interface WxMpUserService { * * * @param openid 用户openid - * @param lang 语言,zh_CN 简体(默认),zh_TW 繁体,en 英语 + * @param lang 语言,zh_CN 简体(默认),zh_TW 繁体,en 英语 */ WxMpUser userInfo(String openid, String lang) throws WxErrorException; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java index 4c0ab7c8ba..cee28b73ba 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java @@ -1,16 +1,16 @@ package me.chanjar.weixin.mp.api; -import java.util.List; - import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.mp.bean.tag.WxTagListUser; import me.chanjar.weixin.mp.bean.tag.WxUserTag; +import java.util.List; + /** * 用户标签管理相关接口 * Created by Binary Wang on 2016/9/2. - * @author binarywang(Binary Wang) * + * @author binarywang(Binary Wang) */ public interface WxMpUserTagService { @@ -32,7 +32,6 @@ public interface WxMpUserTagService { * 详情请见:用户标签管理 * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/get?access_token=ACCESS_TOKEN * - * */ List tagGet() throws WxErrorException; @@ -42,7 +41,6 @@ public interface WxMpUserTagService { * 详情请见:用户标签管理 * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/update?access_token=ACCESS_TOKEN * - * */ Boolean tagUpdate(Long tagId, String name) throws WxErrorException; @@ -52,7 +50,6 @@ public interface WxMpUserTagService { * 详情请见:用户标签管理 * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/delete?access_token=ACCESS_TOKEN * - * */ Boolean tagDelete(Long tagId) throws WxErrorException; @@ -62,10 +59,9 @@ public interface WxMpUserTagService { * 详情请见:用户标签管理 * 接口url格式: https://api.weixin.qq.com/cgi-bin/user/tag/get?access_token=ACCESS_TOKEN * - * */ WxTagListUser tagListUser(Long tagId, String nextOpenid) - throws WxErrorException; + throws WxErrorException; /** *
    @@ -73,7 +69,6 @@ WxTagListUser tagListUser(Long tagId, String nextOpenid)
        * 详情请见:用户标签管理
        * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token=ACCESS_TOKEN
        * 
    - * */ boolean batchTagging(Long tagId, String[] openids) throws WxErrorException; @@ -83,7 +78,6 @@ WxTagListUser tagListUser(Long tagId, String nextOpenid) * 详情请见:用户标签管理 * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token=ACCESS_TOKEN * - * */ boolean batchUntagging(Long tagId, String[] openids) throws WxErrorException; @@ -94,7 +88,8 @@ WxTagListUser tagListUser(Long tagId, String nextOpenid) * 详情请见:用户标签管理 * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/getidlist?access_token=ACCESS_TOKEN * - * @return 标签Id的列表 + * + * @return 标签Id的列表 */ List userTagList(String openid) throws WxErrorException; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java new file mode 100644 index 0000000000..9dc1d755dd --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/AbstractWxMpServiceImpl.java @@ -0,0 +1,408 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.StandardSessionManager; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.RandomUtils; +import me.chanjar.weixin.common.util.crypto.SHA1; +import me.chanjar.weixin.common.util.http.*; +import me.chanjar.weixin.mp.api.*; +import me.chanjar.weixin.mp.bean.*; +import me.chanjar.weixin.mp.bean.result.*; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.concurrent.locks.Lock; + +public abstract class AbstractWxMpServiceImpl implements WxMpService, RequestHttp { + + private static final JsonParser JSON_PARSER = new JsonParser(); + + protected final Logger log = LoggerFactory.getLogger(this.getClass()); + protected WxSessionManager sessionManager = new StandardSessionManager(); + private WxMpConfigStorage wxMpConfigStorage; + private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); + private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); + private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); + private WxMpUserService userService = new WxMpUserServiceImpl(this); + private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this); + private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); + private WxMpCardService cardService = new WxMpCardServiceImpl(this); + private WxMpStoreService storeService = new WxMpStoreServiceImpl(this); + private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this); + private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this); + private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); + private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); + private WxMpShakeService shakeService = new WxMpShakeServiceImpl(this); + + private int retrySleepMillis = 1000; + private int maxRetryTimes = 5; + + + @Override + public boolean checkSignature(String timestamp, String nonce, String signature) { + try { + return SHA1.gen(this.getWxMpConfigStorage().getToken(), timestamp, nonce) + .equals(signature); + } catch (Exception e) { + this.log.error("Checking signature failed, and the reason is :" + e.getMessage()); + return false; + } + } + + @Override + public String getJsapiTicket() throws WxErrorException { + return getJsapiTicket(false); + } + + @Override + public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMpConfigStorage().getJsapiTicketLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.getWxMpConfigStorage().expireJsapiTicket(); + } + + if (this.getWxMpConfigStorage().isJsapiTicketExpired()) { + String responseContent = execute(SimpleGetRequestExecutor.create(this), WxMpService.GET_JSAPI_TICKET_URL, null); + JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + this.getWxMpConfigStorage().updateJsapiTicket(jsapiTicket, expiresInSeconds); + } + } finally { + lock.unlock(); + } + return this.getWxMpConfigStorage().getJsapiTicket(); + } + + @Override + public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { + long timestamp = System.currentTimeMillis() / 1000; + String noncestr = RandomUtils.getRandomStr(); + String jsapiTicket = getJsapiTicket(false); + String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket, + "noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url); + WxJsapiSignature jsapiSignature = new WxJsapiSignature(); + jsapiSignature.setAppId(this.getWxMpConfigStorage().getAppId()); + jsapiSignature.setTimestamp(timestamp); + jsapiSignature.setNonceStr(noncestr); + jsapiSignature.setUrl(url); + jsapiSignature.setSignature(signature); + return jsapiSignature; + } + + @Override + public String getAccessToken() throws WxErrorException { + return getAccessToken(false); + } + + @Override + public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { + String responseContent = this.post(WxMpService.MEDIA_UPLOAD_NEWS_URL, news.toJson()); + return WxMpMassUploadResult.fromJson(responseContent); + } + + @Override + public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException { + String responseContent = this.post(WxMpService.MEDIA_UPLOAD_VIDEO_URL, video.toJson()); + return WxMpMassUploadResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException { + String responseContent = this.post(WxMpService.MESSAGE_MASS_SENDALL_URL, message.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException { + String responseContent = this.post(WxMpService.MESSAGE_MASS_SEND_URL, message.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + + @Override + public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception { + String responseContent = this.post(WxMpService.MESSAGE_MASS_PREVIEW_URL, wxMpMassPreviewMessage.toJson()); + return WxMpMassSendResult.fromJson(responseContent); + } + + @Override + public String shortUrl(String long_url) throws WxErrorException { + JsonObject o = new JsonObject(); + o.addProperty("action", "long2short"); + o.addProperty("long_url", long_url); + String responseContent = this.post(WxMpService.SHORTURL_API_URL, o.toString()); + JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("short_url").getAsString(); + } + + @Override + public WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException { + String responseContent = this.post(WxMpService.SEMANTIC_SEMPROXY_SEARCH_URL, semanticQuery.toJson()); + return WxMpSemanticQueryResult.fromJson(responseContent); + } + + @Override + public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { + return String.format(WxMpService.CONNECT_OAUTH2_AUTHORIZE_URL, + this.getWxMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state)); + } + + @Override + public String buildQrConnectUrl(String redirectURI, String scope, String state) { + return String.format(WxMpService.QRCONNECT_URL, + this.getWxMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state)); + } + + private WxMpOAuth2AccessToken getOAuth2AccessToken(String url) throws WxErrorException { + try { + RequestExecutor executor = SimpleGetRequestExecutor.create(this); + String responseText = executor.execute(url, null); + return WxMpOAuth2AccessToken.fromJson(responseText); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { + String url = String.format(WxMpService.OAUTH2_ACCESS_TOKEN_URL, this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret(), code); + return this.getOAuth2AccessToken(url); + } + + @Override + public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { + String url = String.format(WxMpService.OAUTH2_REFRESH_TOKEN_URL, this.getWxMpConfigStorage().getAppId(), refreshToken); + return this.getOAuth2AccessToken(url); + } + + @Override + public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { + if (lang == null) { + lang = "zh_CN"; + } + + String url = String.format(WxMpService.OAUTH2_USERINFO_URL, oAuth2AccessToken.getAccessToken(), oAuth2AccessToken.getOpenId(), lang); + + try { + RequestExecutor executor = SimpleGetRequestExecutor.create(this); + String responseText = executor.execute(url, null); + return WxMpUser.fromJson(responseText); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { + String url = String.format(WxMpService.OAUTH2_VALIDATE_TOKEN_URL, oAuth2AccessToken.getAccessToken(), oAuth2AccessToken.getOpenId()); + + try { + SimpleGetRequestExecutor.create(this).execute(url, null); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (WxErrorException e) { + return false; + } + return true; + } + + @Override + public String[] getCallbackIP() throws WxErrorException { + String responseContent = this.get(WxMpService.GET_CALLBACK_IP_URL, null); + JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); + JsonArray ipList = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); + String[] ipArray = new String[ipList.size()]; + for (int i = 0; i < ipList.size(); i++) { + ipArray[i] = ipList.get(i).getAsString(); + } + return ipArray; + } + + @Override + public String get(String url, String queryParam) throws WxErrorException { + return execute(SimpleGetRequestExecutor.create(this), url, queryParam); + } + + @Override + public String post(String url, String postData) throws WxErrorException { + return execute(SimplePostRequestExecutor.create(this), url, postData); + } + + /** + * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 + */ + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + int retryTimes = 0; + do { + try { + return this.executeInternal(executor, uri, data); + } catch (WxErrorException e) { + if (retryTimes + 1 > this.maxRetryTimes) { + this.log.warn("重试达到最大次数【{}】", maxRetryTimes); + //最后一次重试失败后,直接抛出异常,不再等待 + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + WxError error = e.getError(); + // -1 系统繁忙, 1000ms后重试 + if (error.getErrorCode() == -1) { + int sleepMillis = this.retrySleepMillis * (1 << retryTimes); + try { + this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + Thread.sleep(sleepMillis); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + } else { + throw e; + } + } + } while (retryTimes++ < this.maxRetryTimes); + + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + public synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + if (uri.contains("access_token=")) { + throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); + } + String accessToken = getAccessToken(false); + + String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken; + + try { + T result = executor.execute(uriWithAccessToken, data); + this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, data, result); + return result; + } catch (WxErrorException e) { + WxError error = e.getError(); + /* + * 发生以下情况时尝试刷新access_token + * 40001 获取access_token时AppSecret错误,或者access_token无效 + * 42001 access_token超时 + * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口 + */ + if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001 || error.getErrorCode() == 40014) { + // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token + this.getWxMpConfigStorage().expireAccessToken(); + if (this.getWxMpConfigStorage().autoRefreshToken()) { + return this.execute(executor, uri, data); + } + } + + if (error.getErrorCode() != 0) { + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, data, error); + throw new WxErrorException(error); + } + return null; + } catch (IOException e) { + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, data, e.getMessage()); + throw new RuntimeException(e); + } + } + + @Override + public WxMpConfigStorage getWxMpConfigStorage() { + return this.wxMpConfigStorage; + } + + @Override + public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { + this.wxMpConfigStorage = wxConfigProvider; + this.initHttp(); + } + + @Override + public void setRetrySleepMillis(int retrySleepMillis) { + this.retrySleepMillis = retrySleepMillis; + } + + @Override + public void setMaxRetryTimes(int maxRetryTimes) { + this.maxRetryTimes = maxRetryTimes; + } + + @Override + public WxMpKefuService getKefuService() { + return this.kefuService; + } + + @Override + public WxMpMaterialService getMaterialService() { + return this.materialService; + } + + @Override + public WxMpMenuService getMenuService() { + return this.menuService; + } + + @Override + public WxMpUserService getUserService() { + return this.userService; + } + + @Override + public WxMpUserTagService getUserTagService() { + return this.tagService; + } + + @Override + public WxMpQrcodeService getQrcodeService() { + return this.qrCodeService; + } + + @Override + public WxMpCardService getCardService() { + return this.cardService; + } + + @Override + public WxMpDataCubeService getDataCubeService() { + return this.dataCubeService; + } + + @Override + public WxMpUserBlacklistService getBlackListService() { + return this.blackListService; + } + + @Override + public WxMpStoreService getStoreService() { + return this.storeService; + } + + @Override + public WxMpTemplateMsgService getTemplateMsgService() { + return this.templateMsgService; + } + + @Override + public WxMpDeviceService getDeviceService() { + return this.deviceService; + } + + @Override + public WxMpShakeService getShakeService(){ + return this.shakeService; + } + + @Override + public RequestHttp getRequestHttp() { + return this; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java index 2e6bf88e50..8ec5945f7b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java @@ -1,17 +1,10 @@ package me.chanjar.weixin.mp.api.impl; -import java.util.Arrays; -import java.util.concurrent.locks.Lock; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import com.google.gson.reflect.TypeToken; - import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; @@ -22,6 +15,11 @@ import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.result.WxMpCardResult; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.concurrent.locks.Lock; /** * Created by Binary Wang on 2016/7/27. @@ -36,6 +34,11 @@ public WxMpCardServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; } + @Override + public WxMpService getWxMpService() { + return this.wxMpService; + } + /** * 获得卡券api_ticket,不强制刷新卡券api_ticket * @@ -62,27 +65,26 @@ public String getCardApiTicket() throws WxErrorException { */ @Override public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { - Lock lock = wxMpService.getWxMpConfigStorage().getCardApiTicketLock(); + Lock lock = getWxMpService().getWxMpConfigStorage().getCardApiTicketLock(); try { lock.lock(); if (forceRefresh) { - this.wxMpService.getWxMpConfigStorage().expireCardApiTicket(); + this.getWxMpService().getWxMpConfigStorage().expireCardApiTicket(); } - if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; - String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null); + if (this.getWxMpService().getWxMpConfigStorage().isCardApiTicketExpired()) { + String responseContent = this.wxMpService.execute(SimpleGetRequestExecutor.create(this.getWxMpService().getRequestHttp()), CARD_GET_TICKET, null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); + this.getWxMpService().getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); } } finally { lock.unlock(); } - return this.wxMpService.getWxMpConfigStorage().getCardApiTicket(); + return this.getWxMpService().getWxMpConfigStorage().getCardApiTicket(); } /** @@ -95,13 +97,13 @@ public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { * * * @param optionalSignParam 参与签名的参数数组。 - * 可以为下列字段:app_id, card_id, card_type, code, openid, location_id - *
    注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空 + * 可以为下列字段:app_id, card_id, card_type, code, openid, location_id + *
    注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空 * @return 卡券Api签名对象 */ @Override public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws - WxErrorException { + WxErrorException { long timestamp = System.currentTimeMillis() / 1000; String nonceStr = RandomUtils.getRandomStr(); String cardApiTicket = getCardApiTicket(false); @@ -126,10 +128,9 @@ public WxCardApiSignature createCardApiSignature(String... optionalSignParam) th */ @Override public String decryptCardCode(String encryptCode) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/code/decrypt"; JsonObject param = new JsonObject(); param.addProperty("encrypt_code", encryptCode); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(CARD_CODE_DECRYPT, param.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); JsonPrimitive jsonPrimitive = tmpJsonObject.getAsJsonPrimitive("code"); @@ -146,16 +147,15 @@ public String decryptCardCode(String encryptCode) throws WxErrorException { */ @Override public WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/code/get"; JsonObject param = new JsonObject(); param.addProperty("card_id", cardId); param.addProperty("code", code); param.addProperty("check_consume", checkConsume); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(CARD_CODE_GET, param.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, - new TypeToken() { - }.getType()); + new TypeToken() { + }.getType()); } /** @@ -180,7 +180,6 @@ public String consumeCardCode(String code) throws WxErrorException { */ @Override public String consumeCardCode(String code, String cardId) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/code/consume"; JsonObject param = new JsonObject(); param.addProperty("code", code); @@ -188,7 +187,7 @@ public String consumeCardCode(String code, String cardId) throws WxErrorExceptio param.addProperty("card_id", cardId); } - return this.wxMpService.post(url, param.toString()); + return this.wxMpService.post(CARD_CODE_CONSUME, param.toString()); } /** @@ -203,17 +202,17 @@ public String consumeCardCode(String code, String cardId) throws WxErrorExceptio */ @Override public void markCardCode(String code, String cardId, String openId, boolean isMark) throws - WxErrorException { - String url = "https://api.weixin.qq.com/card/code/mark"; + WxErrorException { 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()); + String responseContent = this.getWxMpService().post(CARD_CODE_MARK, param.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); WxMpCardResult cardResult = WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, - new TypeToken() { }.getType()); + new TypeToken() { + }.getType()); if (!cardResult.getErrorCode().equals("0")) { this.log.warn("朋友的券mark失败:{}", cardResult.getErrorMsg()); } @@ -221,10 +220,9 @@ public void markCardCode(String code, String cardId, String openId, boolean isMa @Override public String getCardDetail(String cardId) throws WxErrorException { - String url = "https://api.weixin.qq.com/card/get"; JsonObject param = new JsonObject(); param.addProperty("card_id", cardId); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(CARD_GET, param.toString()); // 判断返回值 JsonObject json = (new JsonParser()).parse(responseContent).getAsJsonObject(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java index 2dbee076a1..25bd3cfaab 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java @@ -12,11 +12,11 @@ import java.util.List; /** - * Created by Binary Wang on 2016/8/23. + * Created by Binary Wang on 2016/8/23. + * * @author binarywang (https://github.com/binarywang) */ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService { - private static final String API_URL_PREFIX = "https://api.weixin.qq.com/datacube"; private final Format dateFormat = FastDateFormat.getInstance("yyyy-MM-dd"); @@ -28,180 +28,108 @@ public WxMpDataCubeServiceImpl(WxMpService wxMpService) { @Override public List getUserSummary(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getusersummary"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(GET_USER_SUMMARY, buildParams(beginDate, endDate)); return WxDataCubeUserSummary.fromJson(responseContent); } @Override public List getUserCumulate(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getusercumulate"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(GET_USER_CUMULATE, buildParams(beginDate, endDate)); return WxDataCubeUserCumulate.fromJson(responseContent); } @Override public List getArticleSummary(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getarticlesummary"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeArticleResult.fromJson(responseContent); + return this.getArticleResults(GET_ARTICLE_SUMMARY, beginDate, endDate); } @Override public List getArticleTotal(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getarticletotal"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(GET_ARTICLE_TOTAL, buildParams(beginDate, endDate)); return WxDataCubeArticleTotal.fromJson(responseContent); } @Override public List getUserRead(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getuserread"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeArticleResult.fromJson(responseContent); + return this.getArticleResults(GET_USER_READ, beginDate, endDate); } @Override public List getUserReadHour(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getuserreadhour"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeArticleResult.fromJson(responseContent); + return this.getArticleResults(GET_USER_READ_HOUR, beginDate, endDate); } @Override public List getUserShare(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getusershare"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeArticleResult.fromJson(responseContent); + return this.getArticleResults(GET_USER_SHARE, beginDate, endDate); } @Override public List getUserShareHour(Date beginDate, Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getusersharehour"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + return this.getArticleResults(GET_USER_SHARE_HOUR, beginDate, endDate); + } + + private List getArticleResults(String url, Date beginDate, Date endDate) throws WxErrorException { + String responseContent = this.wxMpService.post(url, buildParams(beginDate, endDate)); return WxDataCubeArticleResult.fromJson(responseContent); } @Override - public List getUpstreamMsg(Date beginDate, Date endDate) - throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsg"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsg(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG, beginDate, endDate); } @Override - public List getUpstreamMsgHour(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsghour"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsgHour(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_HOUR, beginDate, endDate); } @Override - public List getUpstreamMsgWeek(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsgweek"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsgWeek(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_WEEK, beginDate, endDate); } @Override - public List getUpstreamMsgMonth(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsgmonth"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsgMonth(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_MONTH, beginDate, endDate); } @Override - public List getUpstreamMsgDist(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsgdist"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsgDist(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_DIST, beginDate, endDate); } @Override - public List getUpstreamMsgDistWeek(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsgdistweek"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); - return WxDataCubeMsgResult.fromJson(responseContent); + public List getUpstreamMsgDistWeek(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_DIST_WEEK, beginDate, endDate); } @Override - public List getUpstreamMsgDistMonth(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getupstreammsgdistmonth"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + public List getUpstreamMsgDistMonth(Date beginDate, Date endDate) throws WxErrorException { + return this.getUpstreamMsg(GET_UPSTREAM_MSG_DIST_MONTH, beginDate, endDate); + } + + private List getUpstreamMsg(String url, Date beginDate, Date endDate) throws WxErrorException { + String responseContent = this.wxMpService.post(url, buildParams(beginDate, endDate)); return WxDataCubeMsgResult.fromJson(responseContent); } @Override - public List getInterfaceSummary(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getinterfacesummary"; - JsonObject param = new JsonObject(); - param.addProperty("begin_date", this.dateFormat.format(beginDate)); - param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + public List getInterfaceSummary(Date beginDate, Date endDate) throws WxErrorException { + String responseContent = this.wxMpService.post(GET_INTERFACE_SUMMARY, buildParams(beginDate, endDate)); return WxDataCubeInterfaceResult.fromJson(responseContent); } - @Override - public List getInterfaceSummaryHour(Date beginDate, - Date endDate) throws WxErrorException { - String url = API_URL_PREFIX + "/getinterfacesummaryhour"; + private String buildParams(Date beginDate, Date endDate) { JsonObject param = new JsonObject(); param.addProperty("begin_date", this.dateFormat.format(beginDate)); param.addProperty("end_date", this.dateFormat.format(endDate)); - String responseContent = this.wxMpService.post(url, param.toString()); + return param.toString(); + } + + @Override + public List getInterfaceSummaryHour(Date beginDate, Date endDate) throws WxErrorException { + String responseContent = this.wxMpService.post(GET_INTERFACE_SUMMARY_HOUR, buildParams(beginDate, endDate)); return WxDataCubeInterfaceResult.fromJson(responseContent); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java index 5c94236511..284c0a2966 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java @@ -16,7 +16,7 @@ public class WxMpDeviceServiceImpl implements WxMpDeviceService { private WxMpService wxMpService; - WxMpDeviceServiceImpl(WxMpService wxMpService) { + public WxMpDeviceServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; } @@ -78,8 +78,8 @@ public WxDeviceOpenIdResult getOpenId(String deviceType, String deviceId) throws @Override public WxDeviceBindDeviceResult getBindDevice(String openId) throws WxErrorException { - String url = API_URL_PREFIX+"/get_bind_device"; - String response = this.wxMpService.get(url,"openid="+openId); + String url = API_URL_PREFIX + "/get_bind_device"; + String response = this.wxMpService.get(url, "openid=" + openId); return WxDeviceBindDeviceResult.fromJson(response); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java index 09a68adf89..8d98a07a32 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java @@ -1,39 +1,27 @@ package me.chanjar.weixin.mp.api.impl; -import java.io.File; -import java.util.Date; - -import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.google.gson.JsonObject; - import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.mp.api.WxMpKefuService; import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfSessionRequest; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfMsgList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionGetResult; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList; +import me.chanjar.weixin.mp.bean.kefu.result.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Date; /** - * * @author Binary Wang - * */ public class WxMpKefuServiceImpl implements WxMpKefuService { - protected final Logger log = LoggerFactory - .getLogger(WxMpKefuServiceImpl.class); - private static final String API_URL_PREFIX = "https://api.weixin.qq.com/customservice"; - private static final String API_URL_PREFIX_WITH_CGI_BIN = "https://api.weixin.qq.com/cgi-bin/customservice"; + protected final Logger log = LoggerFactory.getLogger(this.getClass()); private WxMpService wxMpService; public WxMpKefuServiceImpl(WxMpService wxMpService) { @@ -41,127 +29,103 @@ public WxMpKefuServiceImpl(WxMpService wxMpService) { } @Override - public boolean sendKefuMessage(WxMpKefuMessage message) - throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; - String responseContent = this.wxMpService.post(url, message.toJson()); + public boolean sendKefuMessage(WxMpKefuMessage message) throws WxErrorException { + String responseContent = this.wxMpService.post(MESSAGE_CUSTOM_SEND, message.toJson()); return responseContent != null; } @Override public WxMpKfList kfList() throws WxErrorException { - String url = API_URL_PREFIX_WITH_CGI_BIN + "/getkflist"; - String responseContent = this.wxMpService.get(url, null); + String responseContent = this.wxMpService.get(GET_KF_LIST, null); return WxMpKfList.fromJson(responseContent); } @Override public WxMpKfOnlineList kfOnlineList() throws WxErrorException { - String url = API_URL_PREFIX_WITH_CGI_BIN + "/getonlinekflist"; - String responseContent = this.wxMpService.get(url, null); + String responseContent = this.wxMpService.get(GET_ONLINE_KF_LIST, null); return WxMpKfOnlineList.fromJson(responseContent); } @Override - public boolean kfAccountAdd(WxMpKfAccountRequest request) - throws WxErrorException { - String url = API_URL_PREFIX + "/kfaccount/add"; - String responseContent = this.wxMpService.post(url, request.toJson()); + public boolean kfAccountAdd(WxMpKfAccountRequest request) throws WxErrorException { + String responseContent = this.wxMpService.post(KFACCOUNT_ADD, request.toJson()); return responseContent != null; } @Override - public boolean kfAccountUpdate(WxMpKfAccountRequest request) - throws WxErrorException { - String url = API_URL_PREFIX + "/kfaccount/update"; - String responseContent = this.wxMpService.post(url, request.toJson()); + public boolean kfAccountUpdate(WxMpKfAccountRequest request) throws WxErrorException { + String responseContent = this.wxMpService.post(KFACCOUNT_UPDATE, request.toJson()); return responseContent != null; } @Override public boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErrorException { - String url = API_URL_PREFIX + "/kfaccount/inviteworker"; - String responseContent = this.wxMpService.post(url, request.toJson()); + String responseContent = this.wxMpService.post(KFACCOUNT_INVITE_WORKER, request.toJson()); return responseContent != null; } @Override - public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) - throws WxErrorException { - String url = API_URL_PREFIX + "/kfaccount/uploadheadimg?kf_account=" + kfAccount; + public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) throws WxErrorException { WxMediaUploadResult responseContent = this.wxMpService - .execute(new MediaUploadRequestExecutor(), url, imgFile); + .execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), String.format(KFACCOUNT_UPLOAD_HEAD_IMG, kfAccount), imgFile); return responseContent != null; } @Override public boolean kfAccountDel(String kfAccount) throws WxErrorException { - String url = API_URL_PREFIX + "/kfaccount/del?kf_account=" + kfAccount; - String responseContent = this.wxMpService.get(url, null); + String responseContent = this.wxMpService.get(String.format(KFACCOUNT_DEL, kfAccount), null); return responseContent != null; } @Override - public boolean kfSessionCreate(String openid, String kfAccount) - throws WxErrorException { + public boolean kfSessionCreate(String openid, String kfAccount) throws WxErrorException { WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid); - String url = API_URL_PREFIX + "/kfsession/create"; - String responseContent = this.wxMpService.post(url, request.toJson()); + String responseContent = this.wxMpService.post(KFSESSION_CREATE, request.toJson()); return responseContent != null; } @Override - public boolean kfSessionClose(String openid, String kfAccount) - throws WxErrorException { + public boolean kfSessionClose(String openid, String kfAccount) throws WxErrorException { WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid); - String url = API_URL_PREFIX + "/kfsession/close"; - String responseContent = this.wxMpService.post(url, request.toJson()); + String responseContent = this.wxMpService.post(KFSESSION_CLOSE, request.toJson()); return responseContent != null; } @Override - public WxMpKfSessionGetResult kfSessionGet(String openid) - throws WxErrorException { - String url = API_URL_PREFIX + "/kfsession/getsession?openid=" + openid; - String responseContent = this.wxMpService.get(url, null); + public WxMpKfSessionGetResult kfSessionGet(String openid) throws WxErrorException { + String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION, openid), null); return WxMpKfSessionGetResult.fromJson(responseContent); } @Override - public WxMpKfSessionList kfSessionList(String kfAccount) - throws WxErrorException { - String url = API_URL_PREFIX + "/kfsession/getsessionlist?kf_account=" + kfAccount; - String responseContent = this.wxMpService.get(url, null); + public WxMpKfSessionList kfSessionList(String kfAccount) throws WxErrorException { + String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION_LIST, kfAccount), null); return WxMpKfSessionList.fromJson(responseContent); } @Override - public WxMpKfSessionWaitCaseList kfSessionGetWaitCase() - throws WxErrorException { - String url = API_URL_PREFIX + "/kfsession/getwaitcase"; - String responseContent = this.wxMpService.get(url, null); + public WxMpKfSessionWaitCaseList kfSessionGetWaitCase() throws WxErrorException { + String responseContent = this.wxMpService.get(KFSESSION_GET_WAIT_CASE, null); return WxMpKfSessionWaitCaseList.fromJson(responseContent); } @Override public WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer number) throws WxErrorException { - if(number > 10000){ + if (number > 10000) { throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法参数请求,每次最多查询10000条记录!").build()); } - if(startTime.after(endTime)){ + if (startTime.after(endTime)) { throw new WxErrorException(WxError.newBuilder().setErrorMsg("起始时间不能晚于结束时间!").build()); } - String url = API_URL_PREFIX + "/msgrecord/getmsglist"; - JsonObject param = new JsonObject(); param.addProperty("starttime", startTime.getTime() / 1000); //starttime 起始时间,unix时间戳 param.addProperty("endtime", endTime.getTime() / 1000); //endtime 结束时间,unix时间戳,每次查询时段不能超过24小时 param.addProperty("msgid", msgId); //msgid 消息id顺序从小到大,从1开始 param.addProperty("number", number); //number 每次获取条数,最多10000条 - String responseContent = this.wxMpService.post(url, param.toString()); + String responseContent = this.wxMpService.post(MSGRECORD_GET_MSG_LIST, param.toString()); return WxMpKfMsgList.fromJson(responseContent); } @@ -169,16 +133,16 @@ public WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer @Override public WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorException { int number = 10000; - WxMpKfMsgList result = this.kfMsgList(startTime,endTime, 1L, number); + WxMpKfMsgList result = this.kfMsgList(startTime, endTime, 1L, number); - if(result != null && result.getNumber() == number){ + if (result != null && result.getNumber() == number) { Long msgId = result.getMsgId(); - WxMpKfMsgList followingResult = this.kfMsgList(startTime,endTime, msgId, number); - while(followingResult != null && followingResult.getRecords().size() > 0){ + WxMpKfMsgList followingResult = this.kfMsgList(startTime, endTime, msgId, number); + while (followingResult != null && followingResult.getRecords().size() > 0) { result.getRecords().addAll(followingResult.getRecords()); result.setNumber(result.getNumber() + followingResult.getNumber()); result.setMsgId(followingResult.getMsgId()); - followingResult = this.kfMsgList(startTime,endTime, followingResult.getMsgId(), number); + followingResult = this.kfMsgList(startTime, endTime, followingResult.getMsgId(), number); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java index af9fa54c35..bb5857be83 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java @@ -10,9 +10,6 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.api.WxMpMaterialService; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.material.WxMpMaterial; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialArticleUpdate; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; import me.chanjar.weixin.mp.bean.material.*; import me.chanjar.weixin.mp.util.http.*; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -49,14 +46,14 @@ public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputS @Override public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { String url = MEDIA_API_URL_PREFIX + "/upload?type=" + mediaType; - return this.wxMpService.execute(new MediaUploadRequestExecutor(), url, file); + return this.wxMpService.execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, file); } @Override public File mediaDownload(String media_id) throws WxErrorException { String url = MEDIA_API_URL_PREFIX + "/get"; return this.wxMpService.execute( - new MediaDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), + MediaDownloadRequestExecutor.create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, "media_id=" + media_id); } @@ -64,13 +61,13 @@ public File mediaDownload(String media_id) throws WxErrorException { @Override public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException { String url = MEDIA_API_URL_PREFIX + "/uploadimg"; - return this.wxMpService.execute(new MediaImgUploadRequestExecutor(), url, file); + return this.wxMpService.execute(MediaImgUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, file); } @Override public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException { String url = MATERIAL_API_URL_PREFIX + "/add_material?type=" + mediaType; - return this.wxMpService.execute(new MaterialUploadRequestExecutor(), url, material); + return this.wxMpService.execute(MaterialUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, material); } @Override @@ -86,19 +83,19 @@ public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws @Override public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException { String url = MATERIAL_API_URL_PREFIX + "/get_material"; - return this.wxMpService.execute(new MaterialVoiceAndImageDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, media_id); + return this.wxMpService.execute(MaterialVoiceAndImageDownloadRequestExecutor.create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, media_id); } @Override public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException { String url = MATERIAL_API_URL_PREFIX + "/get_material"; - return this.wxMpService.execute(new MaterialVideoInfoRequestExecutor(), url, media_id); + return this.wxMpService.execute(MaterialVideoInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), url, media_id); } @Override public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException { String url = MATERIAL_API_URL_PREFIX + "/get_material"; - return this.wxMpService.execute(new MaterialNewsInfoRequestExecutor(), url, media_id); + return this.wxMpService.execute(MaterialNewsInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), url, media_id); } @Override @@ -116,7 +113,7 @@ public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleU @Override public boolean materialDelete(String media_id) throws WxErrorException { String url = MATERIAL_API_URL_PREFIX + "/del_material"; - return this.wxMpService.execute(new MaterialDeleteRequestExecutor(), url, media_id); + return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()), url, media_id); } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java index 8659f2af9d..817a0b68f2 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java @@ -89,7 +89,7 @@ public WxMpQrCodeTicket qrCodeCreateLastTicket(String sceneStr) throws WxErrorEx @Override public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException { String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode"; - return this.wxMpService.execute(new QrCodeRequestExecutor(), url, ticket); + return this.wxMpService.execute(QrCodeRequestExecutor.create(this.wxMpService.getRequestHttp()), url, ticket); } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java new file mode 100644 index 0000000000..d929b0974c --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceApacheHttpClientImpl.java @@ -0,0 +1,103 @@ +package me.chanjar.weixin.mp.api.impl; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.HttpType; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.api.WxMpService; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; +import java.util.concurrent.locks.Lock; + +/** + * apache-http方式实现 + */ +public class WxMpServiceApacheHttpClientImpl extends AbstractWxMpServiceImpl { + private CloseableHttpClient httpClient; + private HttpHost httpProxy; + + @Override + public CloseableHttpClient getRequestHttpClient() { + return httpClient; + } + + @Override + public HttpHost getRequestHttpProxy() { + return httpProxy; + } + + @Override + public HttpType getRequestType() { + return HttpType.APACHE_HTTP; + } + + @Override + public void initHttp() { + WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); + ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder(); + if (null == apacheHttpClientBuilder) { + apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); + } + + apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost()) + .httpProxyPort(configStorage.getHttpProxyPort()) + .httpProxyUsername(configStorage.getHttpProxyUsername()) + .httpProxyPassword(configStorage.getHttpProxyPassword()); + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort()); + } + + this.httpClient = apacheHttpClientBuilder.build(); + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.getWxMpConfigStorage().expireAccessToken(); + } + + if (this.getWxMpConfigStorage().isAccessTokenExpired()) { + String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL, + this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret()); + try { + HttpGet httpGet = new HttpGet(url); + if (this.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) { + String resultContent = new BasicResponseHandler().handleResponse(response); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), + accessToken.getExpiresIn()); + } finally { + httpGet.releaseConnection(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } finally { + lock.unlock(); + } + return this.getWxMpConfigStorage().getAccessToken(); + } +} 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 406e871267..4d2017dd63 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java @@ -1,521 +1,11 @@ package me.chanjar.weixin.mp.api.impl; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.bean.WxJsapiSignature; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.StandardSessionManager; -import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.util.RandomUtils; -import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.http.*; -import me.chanjar.weixin.mp.api.*; -import me.chanjar.weixin.mp.bean.*; -import me.chanjar.weixin.mp.bean.result.*; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.BasicResponseHandler; -import org.apache.http.impl.client.CloseableHttpClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.concurrent.locks.Lock; - -public class WxMpServiceImpl implements WxMpService { - - private static final JsonParser JSON_PARSER = new JsonParser(); - - protected final Logger log = LoggerFactory.getLogger(this.getClass()); - protected WxSessionManager sessionManager = new StandardSessionManager(); - private WxMpConfigStorage wxMpConfigStorage; - private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); - private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); - private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); - private WxMpUserService userService = new WxMpUserServiceImpl(this); - private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this); - private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); - private WxMpCardService cardService = new WxMpCardServiceImpl(this); - private WxMpStoreService storeService = new WxMpStoreServiceImpl(this); - private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this); - private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this); - private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); - private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); - private CloseableHttpClient httpClient; - private HttpHost httpProxy; - private int retrySleepMillis = 1000; - private int maxRetryTimes = 5; - - @Override - public boolean checkSignature(String timestamp, String nonce, String signature) { - try { - return SHA1.gen(this.getWxMpConfigStorage().getToken(), timestamp, nonce) - .equals(signature); - } catch (Exception e) { - return false; - } - } - - @Override - public String getAccessToken() throws WxErrorException { - return getAccessToken(false); - } - - @Override - public String getAccessToken(boolean forceRefresh) throws WxErrorException { - Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); - try { - lock.lock(); - - if (forceRefresh) { - this.getWxMpConfigStorage().expireAccessToken(); - } - - if (this.getWxMpConfigStorage().isAccessTokenExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + - "&appid=" + this.getWxMpConfigStorage().getAppId() + "&secret=" - + this.getWxMpConfigStorage().getSecret(); - try { - HttpGet httpGet = new HttpGet(url); - if (this.httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build(); - httpGet.setConfig(config); - } - try (CloseableHttpResponse response = getHttpclient().execute(httpGet)) { - String resultContent = new BasicResponseHandler().handleResponse(response); - WxError error = WxError.fromJson(resultContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); - this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), - accessToken.getExpiresIn()); - } finally { - httpGet.releaseConnection(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } finally { - lock.unlock(); - } - return this.getWxMpConfigStorage().getAccessToken(); - } - - @Override - public String getJsapiTicket() throws WxErrorException { - return getJsapiTicket(false); - } - - @Override - public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { - Lock lock = this.getWxMpConfigStorage().getJsapiTicketLock(); - try { - lock.lock(); - - if (forceRefresh) { - this.getWxMpConfigStorage().expireJsapiTicket(); - } - - if (this.getWxMpConfigStorage().isJsapiTicketExpired()) { - String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; - String responseContent = execute(new SimpleGetRequestExecutor(), url, null); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); - String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); - int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.getWxMpConfigStorage().updateJsapiTicket(jsapiTicket, expiresInSeconds); - } - } finally { - lock.unlock(); - } - return this.getWxMpConfigStorage().getJsapiTicket(); - } - - @Override - public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { - long timestamp = System.currentTimeMillis() / 1000; - String noncestr = RandomUtils.getRandomStr(); - String jsapiTicket = getJsapiTicket(false); - String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket, - "noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url); - WxJsapiSignature jsapiSignature = new WxJsapiSignature(); - jsapiSignature.setAppId(this.getWxMpConfigStorage().getAppId()); - jsapiSignature.setTimestamp(timestamp); - jsapiSignature.setNonceStr(noncestr); - jsapiSignature.setUrl(url); - jsapiSignature.setSignature(signature); - return jsapiSignature; - } - - @Override - public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; - String responseContent = this.post(url, news.toJson()); - return WxMpMassUploadResult.fromJson(responseContent); - } - - @Override - public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; - String responseContent = this.post(url, video.toJson()); - return WxMpMassUploadResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; - String responseContent = this.post(url, message.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; - String responseContent = this.post(url, message.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws Exception { - String url = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; - String responseContent = this.post(url, wxMpMassPreviewMessage.toJson()); - return WxMpMassSendResult.fromJson(responseContent); - } - - @Override - public String shortUrl(String long_url) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/shorturl"; - JsonObject o = new JsonObject(); - o.addProperty("action", "long2short"); - o.addProperty("long_url", long_url); - String responseContent = this.post(url, o.toString()); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - return tmpJsonElement.getAsJsonObject().get("short_url").getAsString(); - } - - @Override - public WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/semantic/semproxy/search"; - String responseContent = this.post(url, semanticQuery.toJson()); - return WxMpSemanticQueryResult.fromJson(responseContent); - } - - @Override - public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { - StringBuilder url = new StringBuilder(); - url.append("https://open.weixin.qq.com/connect/oauth2/authorize?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); - url.append("&response_type=code"); - url.append("&scope=").append(scope); - if (state != null) { - url.append("&state=").append(state); - } - url.append("#wechat_redirect"); - return url.toString(); - } - - @Override - public String buildQrConnectUrl(String redirectURI, String scope, - String state) { - StringBuilder url = new StringBuilder(); - url.append("https://open.weixin.qq.com/connect/qrconnect?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); - url.append("&response_type=code"); - url.append("&scope=").append(scope); - if (state != null) { - url.append("&state=").append(state); - } - - url.append("#wechat_redirect"); - return url.toString(); - } - - private WxMpOAuth2AccessToken getOAuth2AccessToken(StringBuilder url) throws WxErrorException { - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(this.getHttpclient(), this.httpProxy, url.toString(), null); - return WxMpOAuth2AccessToken.fromJson(responseText); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/oauth2/access_token?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&secret=").append(this.getWxMpConfigStorage().getSecret()); - url.append("&code=").append(code); - url.append("&grant_type=authorization_code"); - - return this.getOAuth2AccessToken(url); - } - - @Override - public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/oauth2/refresh_token?"); - url.append("appid=").append(this.getWxMpConfigStorage().getAppId()); - url.append("&grant_type=refresh_token"); - url.append("&refresh_token=").append(refreshToken); - - return this.getOAuth2AccessToken(url); - } - - @Override - public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/userinfo?"); - url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); - url.append("&openid=").append(oAuth2AccessToken.getOpenId()); - if (lang == null) { - url.append("&lang=zh_CN"); - } else { - url.append("&lang=").append(lang); - } - - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - String responseText = executor.execute(getHttpclient(), this.httpProxy, url.toString(), null); - return WxMpUser.fromJson(responseText); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { - StringBuilder url = new StringBuilder(); - url.append("https://api.weixin.qq.com/sns/auth?"); - url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); - url.append("&openid=").append(oAuth2AccessToken.getOpenId()); - - try { - RequestExecutor executor = new SimpleGetRequestExecutor(); - executor.execute(getHttpclient(), this.httpProxy, url.toString(), null); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (WxErrorException e) { - return false; - } - return true; - } - - @Override - public String[] getCallbackIP() throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/getcallbackip"; - String responseContent = get(url, null); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - JsonArray ipList = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); - String[] ipArray = new String[ipList.size()]; - for (int i = 0; i < ipList.size(); i++) { - ipArray[i] = ipList.get(i).getAsString(); - } - return ipArray; - } - - @Override - public String get(String url, String queryParam) throws WxErrorException { - return execute(new SimpleGetRequestExecutor(), url, queryParam); - } - - @Override - public String post(String url, String postData) throws WxErrorException { - return execute(new SimplePostRequestExecutor(), url, postData); - } - - /** - * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 - */ - @Override - public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { - int retryTimes = 0; - do { - try { - T result = executeInternal(executor, uri, data); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, result); - return result; - } catch (WxErrorException e) { - if (retryTimes + 1 > this.maxRetryTimes) { - this.log.warn("重试达到最大次数【{}】", maxRetryTimes); - //最后一次重试失败后,直接抛出异常,不再等待 - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - WxError error = e.getError(); - // -1 系统繁忙, 1000ms后重试 - if (error.getErrorCode() == -1) { - int sleepMillis = this.retrySleepMillis * (1 << retryTimes); - try { - this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); - Thread.sleep(sleepMillis); - } catch (InterruptedException e1) { - throw new RuntimeException(e1); - } - } else { - throw e; - } - } - } while (retryTimes++ < this.maxRetryTimes); - - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); - throw new RuntimeException("微信服务端异常,超出重试次数"); - } - - protected synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { - if (uri.indexOf("access_token=") != -1) { - throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); - } - String accessToken = getAccessToken(false); - - String uriWithAccessToken = uri; - uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; - - try { - return executor.execute(getHttpclient(), this.httpProxy, uriWithAccessToken, data); - } catch (WxErrorException e) { - WxError error = e.getError(); - /* - * 发生以下情况时尝试刷新access_token - * 40001 获取access_token时AppSecret错误,或者access_token无效 - * 42001 access_token超时 - */ - if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { - // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token - this.getWxMpConfigStorage().expireAccessToken(); - if (this.getWxMpConfigStorage().autoRefreshToken()) { - return this.execute(executor, uri, data); - } - } - - if (error.getErrorCode() != 0) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error); - throw new WxErrorException(error); - } - return null; - } catch (IOException e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage()); - throw new RuntimeException(e); - } - } - - @Override - public HttpHost getHttpProxy() { - return this.httpProxy; - } - - public CloseableHttpClient getHttpclient() { - return this.httpClient; - } - - private void initHttpClient() { - WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); - ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder(); - if (null == apacheHttpClientBuilder) { - apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); - } - - apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost()) - .httpProxyPort(configStorage.getHttpProxyPort()) - .httpProxyUsername(configStorage.getHttpProxyUsername()) - .httpProxyPassword(configStorage.getHttpProxyPassword()); - - if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { - this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort()); - } - - this.httpClient = apacheHttpClientBuilder.build(); - } - - @Override - public WxMpConfigStorage getWxMpConfigStorage() { - return this.wxMpConfigStorage; - } - - @Override - public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { - this.wxMpConfigStorage = wxConfigProvider; - this.initHttpClient(); - } - - @Override - public void setRetrySleepMillis(int retrySleepMillis) { - this.retrySleepMillis = retrySleepMillis; - } - - @Override - public void setMaxRetryTimes(int maxRetryTimes) { - this.maxRetryTimes = maxRetryTimes; - } - - @Override - public WxMpKefuService getKefuService() { - return this.kefuService; - } - - @Override - public WxMpMaterialService getMaterialService() { - return this.materialService; - } - - @Override - public WxMpMenuService getMenuService() { - return this.menuService; - } - - @Override - public WxMpUserService getUserService() { - return this.userService; - } - - @Override - public WxMpUserTagService getUserTagService() { - return this.tagService; - } - - @Override - public WxMpQrcodeService getQrcodeService() { - return this.qrCodeService; - } - - @Override - public WxMpCardService getCardService() { - return this.cardService; - } - - @Override - public WxMpDataCubeService getDataCubeService() { - return this.dataCubeService; - } - - @Override - public WxMpUserBlacklistService getBlackListService() { - return this.blackListService; - } - - @Override - public WxMpStoreService getStoreService() { - return this.storeService; - } - - @Override - public WxMpTemplateMsgService getTemplateMsgService() { - return this.templateMsgService; - } - - @Override - public WxMpDeviceService getDeviceService() { - return this.deviceService; - } +/** + *
    + * 默认接口实现类,使用apache httpclient实现
    + * Created by Binary Wang on 2017-5-27.
    + * @author binarywang(Binary Wang)
    + * 
    + */ +public class WxMpServiceImpl extends WxMpServiceApacheHttpClientImpl { } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java new file mode 100644 index 0000000000..5c0fb75300 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java @@ -0,0 +1,86 @@ +package me.chanjar.weixin.mp.api.impl; + +import jodd.http.*; +import jodd.http.net.SocketHttpConnectionProvider; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.HttpType; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.api.WxMpService; + +import java.util.concurrent.locks.Lock; + +/** + * jodd-http方式实现 + */ +public class WxMpServiceJoddHttpImpl extends AbstractWxMpServiceImpl { + private HttpConnectionProvider httpClient; + private ProxyInfo httpProxy; + + @Override + public HttpConnectionProvider getRequestHttpClient() { + return httpClient; + } + + @Override + public ProxyInfo getRequestHttpProxy() { + return httpProxy; + } + + @Override + public HttpType getRequestType() { + return HttpType.JODD_HTTP; + } + + @Override + public void initHttp() { + + WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + } + + httpClient = JoddHttp.httpConnectionProvider; + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.getWxMpConfigStorage().expireAccessToken(); + } + + if (this.getWxMpConfigStorage().isAccessTokenExpired()) { + String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL, + this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret()); + + HttpRequest request = HttpRequest.get(url); + + if (this.getRequestHttpProxy() != null) { + SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); + provider.useProxy(getRequestHttpProxy()); + + request.withConnectionProvider(provider); + } + HttpResponse response = request.send(); + String resultContent = response.bodyText(); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), + accessToken.getExpiresIn()); + } + } finally { + lock.unlock(); + } + return this.getWxMpConfigStorage().getAccessToken(); + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java new file mode 100644 index 0000000000..81fb848909 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java @@ -0,0 +1,96 @@ +package me.chanjar.weixin.mp.api.impl; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.HttpType; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.api.WxMpService; +import okhttp3.*; + +import java.io.IOException; +import java.util.concurrent.locks.Lock; + +public class WxMpServiceOkHttpImpl extends AbstractWxMpServiceImpl { + private ConnectionPool httpClient; + private OkHttpProxyInfo httpProxy; + + @Override + public ConnectionPool getRequestHttpClient() { + return httpClient; + } + + @Override + public OkHttpProxyInfo getRequestHttpProxy() { + return httpProxy; + } + + @Override + public HttpType getRequestType() { + return HttpType.OK_HTTP; + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); + try { + lock.lock(); + + if (forceRefresh) { + this.getWxMpConfigStorage().expireAccessToken(); + } + + if (this.getWxMpConfigStorage().isAccessTokenExpired()) { + String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL, + this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret()); + + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(httpClient); + //设置代理 + if (httpProxy != null) { + clientBuilder.proxy(getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + Request request = new Request.Builder().url(url).get().build(); + Response response = client.newCall(request).execute(); + String resultContent = response.body().string(); + WxError error = WxError.fromJson(resultContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), + accessToken.getExpiresIn()); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + return this.getWxMpConfigStorage().getAccessToken(); + } + + @Override + public void initHttp() { + WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + httpProxy = new OkHttpProxyInfo(OkHttpProxyInfo.ProxyType.SOCKS5, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + } + + httpClient = new ConnectionPool(); + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java new file mode 100644 index 0000000000..bee636fd54 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.mp.api.impl; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.WxMpShakeService; +import me.chanjar.weixin.mp.bean.WxMpShakeInfoResult; +import me.chanjar.weixin.mp.bean.WxMpShakeQuery; + +/** + * Created by rememberber on 2017/6/5. + * @author rememberber + */ +public class WxMpShakeServiceImpl implements WxMpShakeService { + + private WxMpService wxMpService; + + public WxMpShakeServiceImpl(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + /** + *
    +   * 获取设备及用户信息
    + * 获取设备信息,包括UUID、major、minor,以及距离、openID等信息。 + * 详情请见: https://mp.weixin.qq.com/wiki?action=doc&id=mp1443447963 + * http请求方式: POST(请使用https协议) + * 接口地址:https://api.weixin.qq.com/shakearound/user/getshakeinfo?access_token=ACCESS_TOKE + *
    + * + * @param wxMpShakeQuery 查询参数 + */ + @Override + public WxMpShakeInfoResult getShakeInfo(WxMpShakeQuery wxMpShakeQuery) throws WxErrorException { + String url = "https://api.weixin.qq.com/shakearound/user/getshakeinfo"; + String postData = wxMpShakeQuery.toJsonString(); + String responseContent = this.wxMpService.post(url, postData); + return WxMpShakeInfoResult.fromJson(responseContent); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java index e1984204df..5f1b5f2a82 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java @@ -16,9 +16,9 @@ import java.util.List; /** - * Created by Binary Wang on 2016/9/26. - * @author binarywang (https://github.com/binarywang) + * Created by Binary Wang on 2016/9/26. * + * @author binarywang (https://github.com/binarywang) */ public class WxMpStoreServiceImpl implements WxMpStoreService { private static final String API_BASE_URL = "http://api.weixin.qq.com/cgi-bin/poi"; @@ -45,21 +45,21 @@ public void add(WxMpStoreBaseInfo request) throws WxErrorException { public WxMpStoreBaseInfo get(String poiId) throws WxErrorException { String url = API_BASE_URL + "/getpoi"; JsonObject paramObject = new JsonObject(); - paramObject.addProperty("poi_id",poiId); + paramObject.addProperty("poi_id", poiId); String response = this.wxMpService.post(url, paramObject.toString()); WxError wxError = WxError.fromJson(response); if (wxError.getErrorCode() != 0) { throw new WxErrorException(wxError); } return WxMpStoreBaseInfo.fromJson(new JsonParser().parse(response).getAsJsonObject() - .get("business").getAsJsonObject().get("base_info").toString()); + .get("business").getAsJsonObject().get("base_info").toString()); } @Override public void delete(String poiId) throws WxErrorException { String url = API_BASE_URL + "/delpoi"; JsonObject paramObject = new JsonObject(); - paramObject.addProperty("poi_id",poiId); + paramObject.addProperty("poi_id", poiId); String response = this.wxMpService.post(url, paramObject.toString()); WxError wxError = WxError.fromJson(response); if (wxError.getErrorCode() != 0) { @@ -69,7 +69,7 @@ public void delete(String poiId) throws WxErrorException { @Override public WxMpStoreListResult list(int begin, int limit) - throws WxErrorException { + throws WxErrorException { String url = API_BASE_URL + "/getpoilist"; JsonObject params = new JsonObject(); params.addProperty("begin", begin); @@ -125,8 +125,9 @@ public List listCategories() throws WxErrorException { } return WxMpGsonBuilder.create().fromJson( - new JsonParser().parse(response).getAsJsonObject().get("category_list"), - new TypeToken>(){}.getType()); + new JsonParser().parse(response).getAsJsonObject().get("category_list"), + new TypeToken>() { + }.getType()); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java index b0b35343e8..4e3f78140a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java @@ -28,7 +28,7 @@ public WxMpUserBlacklistGetResult getBlacklist(String nextOpenid) throws WxError JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("begin_openid", nextOpenid); String url = API_BLACKLIST_PREFIX + "/getblacklist"; - String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, jsonObject.toString()); + String responseContent = this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, jsonObject.toString()); return WxMpUserBlacklistGetResult.fromJson(responseContent); } @@ -37,7 +37,7 @@ public void pushToBlacklist(List openidList) throws WxErrorException { Map map = new HashMap<>(); map.put("openid_list", openidList); String url = API_BLACKLIST_PREFIX + "/batchblacklist"; - this.wxMpService.execute(new SimplePostRequestExecutor(), url, new Gson().toJson(map)); + this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, new Gson().toJson(map)); } @Override @@ -45,6 +45,6 @@ public void pullFromBlacklist(List openidList) throws WxErrorException { Map map = new HashMap<>(); map.put("openid_list", openidList); String url = API_BLACKLIST_PREFIX + "/batchunblacklist"; - this.wxMpService.execute(new SimplePostRequestExecutor(), url, new Gson().toJson(map)); + this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, new Gson().toJson(map)); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java index c796cbd315..ba74f0e4a7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java @@ -40,7 +40,7 @@ public WxMpUser userInfo(String openid, String lang) throws WxErrorException { String url = API_URL_PREFIX + "/info"; lang = lang == null ? "zh_CN" : lang; String responseContent = this.wxMpService.get(url, - "openid=" + openid + "&lang=" + lang); + "openid=" + openid + "&lang=" + lang); return WxMpUser.fromJson(responseContent); } @@ -48,13 +48,13 @@ public WxMpUser userInfo(String openid, String lang) throws WxErrorException { public WxMpUserList userList(String next_openid) throws WxErrorException { String url = API_URL_PREFIX + "/get"; String responseContent = this.wxMpService.get(url, - next_openid == null ? null : "next_openid=" + next_openid); + next_openid == null ? null : "next_openid=" + next_openid); return WxMpUserList.fromJson(responseContent); } @Override public List userInfoList(List openids) - throws WxErrorException { + throws WxErrorException { return this.userInfoList(new WxMpUserQuery(openids)); } @@ -62,7 +62,7 @@ public List userInfoList(List openids) public List userInfoList(WxMpUserQuery userQuery) throws WxErrorException { String url = API_URL_PREFIX + "/info/batchget"; String responseContent = this.wxMpService.post(url, - userQuery.toJsonString()); + userQuery.toJsonString()); return WxMpUser.fromJsonList(responseContent); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java index d1bdae1e2d..99f271065c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java @@ -1,14 +1,9 @@ package me.chanjar.weixin.mp.api.impl; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; - import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; - import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; @@ -16,9 +11,11 @@ import me.chanjar.weixin.mp.bean.tag.WxTagListUser; import me.chanjar.weixin.mp.bean.tag.WxUserTag; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; /** - * * @author binarywang(Binary Wang) * Created by Binary Wang on 2016/9/2. */ @@ -90,7 +87,7 @@ public Boolean tagDelete(Long id) throws WxErrorException { @Override public WxTagListUser tagListUser(Long tagId, String nextOpenid) - throws WxErrorException { + throws WxErrorException { String url = "https://api.weixin.qq.com/cgi-bin/user/tag/get"; JsonObject json = new JsonObject(); @@ -103,7 +100,7 @@ public WxTagListUser tagListUser(Long tagId, String nextOpenid) @Override public boolean batchTagging(Long tagId, String[] openids) - throws WxErrorException { + throws WxErrorException { String url = API_URL_PREFIX + "/members/batchtagging"; JsonObject json = new JsonObject(); @@ -125,7 +122,7 @@ public boolean batchTagging(Long tagId, String[] openids) @Override public boolean batchUntagging(Long tagId, String[] openids) - throws WxErrorException { + throws WxErrorException { String url = API_URL_PREFIX + "/members/batchuntagging"; JsonObject json = new JsonObject(); @@ -155,8 +152,8 @@ public List userTagList(String openid) throws WxErrorException { String responseContent = this.wxMpService.post(url, json.toString()); return WxMpGsonBuilder.create().fromJson( - new JsonParser().parse(responseContent).getAsJsonObject().get("tagid_list"), - new TypeToken>() { - }.getType()); + new JsonParser().parse(responseContent).getAsJsonObject().get("tagid_list"), + new TypeToken>() { + }.getType()); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java index 3e65fcded9..dc1acd3bd3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java @@ -36,6 +36,11 @@ public boolean isEmpty() { return this.articles == null || this.articles.isEmpty(); } + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + /** *
        * 群发图文消息article
    @@ -141,9 +146,4 @@ public String toString() {
           return ToStringUtils.toSimpleString(this);
         }
       }
    -
    -  @Override
    -  public String toString() {
    -    return ToStringUtils.toSimpleString(this);
    -  }
     }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java
    index e0b33f0dd7..73b6c9e241 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java
    @@ -38,6 +38,7 @@ public String getMsgType() {
        * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_VOICE}
        * 如果msgtype和media_id不匹配的话,会返回系统繁忙的错误
        * 
    + * * @param msgType */ public void setMsgType(String msgType) { @@ -71,28 +72,29 @@ public List getToUsers() { return this.toUsers; } - /** - * 添加openid,最多支持10,000个 - * @param openid - */ - public void addUser(String openid) { - this.toUsers.add(openid); - } - /** * 提供set方法,方便客户端直接设置所有群发对象的openid列表 + * * @param toUsers */ public void setToUsers(List toUsers) { this.toUsers = toUsers; } + /** + * 添加openid,最多支持10,000个 + * + * @param openid + */ + public void addUser(String openid) { + this.toUsers.add(openid); + } + public boolean isSendIgnoreReprint() { return sendIgnoreReprint; } /** - * * @param sendIgnoreReprint 文章被判定为转载时,是否继续进行群发操作。 */ public void setSendIgnoreReprint(boolean sendIgnoreReprint) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java index bf1ded1a92..cdf14f79bd 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java @@ -82,7 +82,6 @@ public boolean isSendIgnoreReprint() { } /** - * * @param sendIgnoreReprint 文章被判定为转载时,是否继续进行群发操作。 */ public void setSendIgnoreReprint(boolean sendIgnoreReprint) { @@ -97,7 +96,7 @@ public boolean isSendAll() { } public void setSendAll(boolean sendAll) { - if(sendAll){ + if (sendAll) { this.tagId = null; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java index ec94092cd1..38eef7c8a1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java @@ -6,13 +6,13 @@ /** * 群发时用到的视频素材 - * + * * @author chanjarster */ public class WxMpMassVideo implements Serializable { /** - * + * */ private static final long serialVersionUID = 9153925016061915637L; private String mediaId; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpSemanticQuery.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpSemanticQuery.java index c17f38e99f..f4b1c3da00 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpSemanticQuery.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpSemanticQuery.java @@ -6,7 +6,7 @@ /** * 语义理解查询用对象 - * + *

    * http://mp.weixin.qq.com/wiki/index.php?title=语义理解 * * @author Daniel Qian @@ -14,7 +14,7 @@ public class WxMpSemanticQuery implements Serializable { /** - * + * */ private static final long serialVersionUID = 7685873048199870690L; private String query; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java new file mode 100644 index 0000000000..ac94b457b0 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java @@ -0,0 +1,164 @@ +package me.chanjar.weixin.mp.bean; + +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * 摇一摇周边:获取设备及用户信息接口返回JSON数据接收类 + * Created by rememberber on 2017/6/5. + * + * @author rememberber + */ +public class WxMpShakeInfoResult implements Serializable { + + private Integer errcode; + + private String errmsg; + + private Data data; + + public static WxMpShakeInfoResult fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpShakeInfoResult.class); + } + + public class Data { + + private String page_id; + + private String openid; + + private String poi_id; + + private String brand_userame; + + private BeaconInfo beacon_info; + + public class BeaconInfo { + + private double distance; + + private Integer major; + + private Integer measure_power; + + private Integer minor; + + private Integer rssi; + + private String uuid; + + public double getDistance() { + return distance; + } + + public void setDistance(double distance) { + this.distance = distance; + } + + public Integer getMajor() { + return major; + } + + public void setMajor(Integer major) { + this.major = major; + } + + public Integer getMeasure_power() { + return measure_power; + } + + public void setMeasure_power(Integer measure_power) { + this.measure_power = measure_power; + } + + public Integer getMinor() { + return minor; + } + + public void setMinor(Integer minor) { + this.minor = minor; + } + + public Integer getRssi() { + return rssi; + } + + public void setRssi(Integer rssi) { + this.rssi = rssi; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + } + + public String getPage_id() { + return page_id; + } + + public void setPage_id(String page_id) { + this.page_id = page_id; + } + + public String getOpenid() { + return openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public String getPoi_id() { + return poi_id; + } + + public void setPoi_id(String poi_id) { + this.poi_id = poi_id; + } + + public BeaconInfo getBeacon_info() { + return beacon_info; + } + + public void setBeacon_info(BeaconInfo beacon_info) { + this.beacon_info = beacon_info; + } + + public String getBrand_userame() { + return brand_userame; + } + + public void setBrand_userame(String brand_userame) { + this.brand_userame = brand_userame; + } + } + + public Integer getErrcode() { + return errcode; + } + + public void setErrcode(Integer errcode) { + this.errcode = errcode; + } + + public String getErrmsg() { + return errmsg; + } + + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } + + public Data getData() { + return data; + } + + public void setData(Data data) { + this.data = data; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeQuery.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeQuery.java new file mode 100644 index 0000000000..bb9d326fad --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeQuery.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.mp.bean; + +import com.google.gson.Gson; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by rememberber on 2017/6/5. + * + * @author rememberber + */ +public class WxMpShakeQuery { + + private String ticket; + + private int needPoi; + + public String toJsonString() { + Map map = new HashMap<>(); + map.put("ticket", this.ticket); + map.put("need_poi", this.needPoi); + return new Gson().toJson(map); + } + + public String getTicket() { + return ticket; + } + + public void setTicket(String ticket) { + this.ticket = ticket; + } + + public int getNeedPoi() { + return needPoi; + } + + public void setNeedPoi(int needPoi) { + this.needPoi = needPoi; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpUserQuery.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpUserQuery.java index e97389b8f7..800e03e915 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpUserQuery.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpUserQuery.java @@ -1,189 +1,188 @@ -package me.chanjar.weixin.mp.bean; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.google.gson.Gson; - -/** - * 批量查询用户信息查询参数
    - * Created by LiuJunGuang on 2016/8/31. - * - * @author LiuJunGuang - */ -public class WxMpUserQuery { - private List queryParamList = new ArrayList<>(); - - public WxMpUserQuery() { - super(); - } - - /** - * 语言使用默认(zh_CN) - * - * @param openids - */ - public WxMpUserQuery(List openids) { - super(); - add(openids); - } - - /** - * 添加OpenId列表,语言使用默认(zh_CN) - * - * @param openids - * @return {@link WxMpUserQuery} - */ - public WxMpUserQuery add(List openids) { - for (String openid : openids) { - this.add(openid); - } - return this; - } - - /** - * 添加一个OpenId - * - * @param openid - * @param lang 国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语 - * @return {@link WxMpUserQuery} - */ - public WxMpUserQuery add(String openid, String lang) { - this.queryParamList.add(new WxMpUserQueryParam(openid, lang)); - return this; - } - - /** - * 添加一个OpenId到列表中,并返回本对象 - * - *

    -   * 该方法默认lang = zh_CN
    -   * 
    - * - * @param openid - * @return {@link WxMpUserQuery} - */ - public WxMpUserQuery add(String openid) { - this.queryParamList.add(new WxMpUserQueryParam(openid)); - return this; - } - - /** - * 删除指定的OpenId,语言使用默认(zh_CN) - * - * @param openid - * @return {@link WxMpUserQuery} - */ - public WxMpUserQuery remove(String openid) { - this.queryParamList.remove(new WxMpUserQueryParam(openid)); - return this; - } - - /** - * 删除指定的OpenId - * - * @param openid - * @param lang 国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语 - * @return {@link WxMpUserQuery} - */ - public WxMpUserQuery remove(String openid, String lang) { - this.queryParamList.remove(new WxMpUserQueryParam(openid, lang)); - return this; - } - - /** - * 获取查询参数列表 - * - */ - public List getQueryParamList() { - return this.queryParamList; - } - - public String toJsonString() { - Map map = new HashMap<>(); - map.put("user_list", this.queryParamList); - return new Gson().toJson(map); - } - - // 查询参数封装 - public class WxMpUserQueryParam implements Serializable { - private static final long serialVersionUID = -6863571795702385319L; - private String openid; - private String lang; - - public WxMpUserQueryParam(String openid, String lang) { - super(); - this.openid = openid; - this.lang = lang; - } - - public WxMpUserQueryParam(String openid) { - super(); - this.openid = openid; - this.lang = "zh_CN"; - } - - public WxMpUserQueryParam() { - super(); - } - - public String getOpenid() { - return this.openid; - } - - public void setOpenid(String openid) { - this.openid = openid; - } - - public String getLang() { - return this.lang; - } - - public void setLang(String lang) { - this.lang = lang; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + getOuterType().hashCode(); - result = prime * result + ((this.lang == null) ? 0 : this.lang.hashCode()); - result = prime * result + ((this.openid == null) ? 0 : this.openid.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - WxMpUserQueryParam other = (WxMpUserQueryParam) obj; - if (!getOuterType().equals(other.getOuterType())) - return false; - if (this.lang == null) { - if (other.lang != null) - return false; - } else if (!this.lang.equals(other.lang)) - return false; - if (this.openid == null) { - if (other.openid != null) - return false; - } else if (!this.openid.equals(other.openid)) - return false; - return true; - } - - private WxMpUserQuery getOuterType() { - return WxMpUserQuery.this; - } - - } - -} +package me.chanjar.weixin.mp.bean; + +import com.google.gson.Gson; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 批量查询用户信息查询参数
    + * Created by LiuJunGuang on 2016/8/31. + * + * @author LiuJunGuang + */ +public class WxMpUserQuery { + private List queryParamList = new ArrayList<>(); + + public WxMpUserQuery() { + super(); + } + + /** + * 语言使用默认(zh_CN) + * + * @param openids + */ + public WxMpUserQuery(List openids) { + super(); + add(openids); + } + + /** + * 添加OpenId列表,语言使用默认(zh_CN) + * + * @param openids + * @return {@link WxMpUserQuery} + */ + public WxMpUserQuery add(List openids) { + for (String openid : openids) { + this.add(openid); + } + return this; + } + + /** + * 添加一个OpenId + * + * @param openid + * @param lang 国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语 + * @return {@link WxMpUserQuery} + */ + public WxMpUserQuery add(String openid, String lang) { + this.queryParamList.add(new WxMpUserQueryParam(openid, lang)); + return this; + } + + /** + * 添加一个OpenId到列表中,并返回本对象 + *

    + *

    +   * 该方法默认lang = zh_CN
    +   * 
    + * + * @param openid + * @return {@link WxMpUserQuery} + */ + public WxMpUserQuery add(String openid) { + this.queryParamList.add(new WxMpUserQueryParam(openid)); + return this; + } + + /** + * 删除指定的OpenId,语言使用默认(zh_CN) + * + * @param openid + * @return {@link WxMpUserQuery} + */ + public WxMpUserQuery remove(String openid) { + this.queryParamList.remove(new WxMpUserQueryParam(openid)); + return this; + } + + /** + * 删除指定的OpenId + * + * @param openid + * @param lang 国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语 + * @return {@link WxMpUserQuery} + */ + public WxMpUserQuery remove(String openid, String lang) { + this.queryParamList.remove(new WxMpUserQueryParam(openid, lang)); + return this; + } + + /** + * 获取查询参数列表 + */ + public List getQueryParamList() { + return this.queryParamList; + } + + public String toJsonString() { + Map map = new HashMap<>(); + map.put("user_list", this.queryParamList); + return new Gson().toJson(map); + } + + // 查询参数封装 + public class WxMpUserQueryParam implements Serializable { + private static final long serialVersionUID = -6863571795702385319L; + private String openid; + private String lang; + + public WxMpUserQueryParam(String openid, String lang) { + super(); + this.openid = openid; + this.lang = lang; + } + + public WxMpUserQueryParam(String openid) { + super(); + this.openid = openid; + this.lang = "zh_CN"; + } + + public WxMpUserQueryParam() { + super(); + } + + public String getOpenid() { + return this.openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public String getLang() { + return this.lang; + } + + public void setLang(String lang) { + this.lang = lang; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + getOuterType().hashCode(); + result = prime * result + ((this.lang == null) ? 0 : this.lang.hashCode()); + result = prime * result + ((this.openid == null) ? 0 : this.openid.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + WxMpUserQueryParam other = (WxMpUserQueryParam) obj; + if (!getOuterType().equals(other.getOuterType())) + return false; + if (this.lang == null) { + if (other.lang != null) + return false; + } else if (!this.lang.equals(other.lang)) + return false; + if (this.openid == null) { + if (other.openid != null) + return false; + } else if (!this.openid.equals(other.openid)) + return false; + return true; + } + + private WxMpUserQuery getOuterType() { + return WxMpUserQuery.this; + } + + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleResult.java index 35cae74d5e..fe6627d244 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleResult.java @@ -9,6 +9,7 @@ /** * 图文分析数据接口返回结果对象 + * * @author binarywang(Binary Wang) * Created by Binary Wang on 2016/8/24. */ @@ -109,6 +110,13 @@ public class WxDataCubeArticleResult extends WxDataCubeBaseResult { @SerializedName("user_source") private Integer userSource; + public static List fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson( + JSON_PARSER.parse(json).getAsJsonObject().get("list"), + new TypeToken>() { + }.getType()); + } + public Integer getRefHour() { return this.refHour; } @@ -212,11 +220,4 @@ public Integer getUserSource() { public void setUserSource(Integer userSource) { this.userSource = userSource; } - - public static List fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson( - JSON_PARSER.parse(json).getAsJsonObject().get("list"), - new TypeToken>() { - }.getType()); - } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleTotal.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleTotal.java index d3236be3be..eee6240f7b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleTotal.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleTotal.java @@ -1,15 +1,15 @@ package me.chanjar.weixin.mp.bean.datacube; -import java.util.List; - import com.google.gson.JsonParser; import com.google.gson.annotations.SerializedName; import com.google.gson.reflect.TypeToken; - import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import java.util.List; + /** * 图文分析数据接口返回结果对象 + * * @author binarywang(Binary Wang) * Created by Binary Wang on 2016/8/24. */ @@ -38,6 +38,13 @@ public class WxDataCubeArticleTotal extends WxDataCubeBaseResult { @SerializedName("details") private List details; + public static List fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson( + JSON_PARSER.parse(json).getAsJsonObject().get("list"), + new TypeToken>() { + }.getType()); + } + public String getMsgId() { return this.msgId; } @@ -61,11 +68,4 @@ public List getDetails() { public void setDetails(List details) { this.details = details; } - - public static List fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson( - JSON_PARSER.parse(json).getAsJsonObject().get("list"), - new TypeToken>() { - }.getType()); - } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleTotalDetail.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleTotalDetail.java index 251c5e767c..27f9b8aa12 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleTotalDetail.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleTotalDetail.java @@ -4,6 +4,7 @@ /** * 获取图文群发总数据接口(getarticletotal)中的详细字段 + * * @author binarywang(Binary Wang) * Created by Binary Wang on 2016/8/24. */ @@ -80,114 +81,114 @@ public class WxDataCubeArticleTotalDetail { private Integer addToFavCount; /** - * int_page_from_session_read_user - * 公众号会话阅读人数 - */ + * int_page_from_session_read_user + * 公众号会话阅读人数 + */ @SerializedName("int_page_from_session_read_user") private Integer intPageFromSessionReadUser; /** - * int_page_from_session_read_count - * 公众号会话阅读次数 - */ + * int_page_from_session_read_count + * 公众号会话阅读次数 + */ @SerializedName("int_page_from_session_read_count") private Integer intPageFromSessionReadCount; /** - * int_page_from_hist_msg_read_user - * 历史消息页阅读人数 - */ + * int_page_from_hist_msg_read_user + * 历史消息页阅读人数 + */ @SerializedName("int_page_from_hist_msg_read_user") private Integer intPageFromHistMsgReadUser; /** - * int_page_from_hist_msg_read_count - * 历史消息页阅读次数 - */ + * int_page_from_hist_msg_read_count + * 历史消息页阅读次数 + */ @SerializedName("int_page_from_hist_msg_read_count") private Integer intPageFromHistMsgReadCount; /** - * int_page_from_feed_read_user - * 朋友圈阅读人数 - */ + * int_page_from_feed_read_user + * 朋友圈阅读人数 + */ @SerializedName("int_page_from_feed_read_user") private Integer intPageFromFeedReadUser; /** - * int_page_from_feed_read_count - * 朋友圈阅读次数 - */ + * int_page_from_feed_read_count + * 朋友圈阅读次数 + */ @SerializedName("int_page_from_feed_read_count") private Integer intPageFromFeedReadCount; /** - * int_page_from_friends_read_user - * 好友转发阅读人数 - */ + * int_page_from_friends_read_user + * 好友转发阅读人数 + */ @SerializedName("int_page_from_friends_read_user") private Integer intPageFromFriendsReadUser; /** - * int_page_from_friends_read_count - * 好友转发阅读次数 - */ + * int_page_from_friends_read_count + * 好友转发阅读次数 + */ @SerializedName("int_page_from_friends_read_count") private Integer intPageFromFriendsReadCount; /** - * int_page_from_other_read_user - * 其他场景阅读人数 - */ + * int_page_from_other_read_user + * 其他场景阅读人数 + */ @SerializedName("int_page_from_other_read_user") private Integer intPageFromOtherReadUser; /** - * int_page_from_other_read_count - * 其他场景阅读次数 - */ + * int_page_from_other_read_count + * 其他场景阅读次数 + */ @SerializedName("int_page_from_other_read_count") private Integer intPageFromOtherReadCount; /** - * feed_share_from_session_user - * 公众号会话转发朋友圈人数 - */ + * feed_share_from_session_user + * 公众号会话转发朋友圈人数 + */ @SerializedName("feed_share_from_session_user") private Integer feedShareFromSessionUser; /** - * feed_share_from_session_cnt - * 公众号会话转发朋友圈次数 - */ + * feed_share_from_session_cnt + * 公众号会话转发朋友圈次数 + */ @SerializedName("feed_share_from_session_cnt") private Integer feedShareFromSessionCnt; /** - * feed_share_from_feed_user - * 朋友圈转发朋友圈人数 - */ + * feed_share_from_feed_user + * 朋友圈转发朋友圈人数 + */ @SerializedName("feed_share_from_feed_user") private Integer feedShareFromFeedUser; /** - * feed_share_from_feed_cnt - * 朋友圈转发朋友圈次数 - */ + * feed_share_from_feed_cnt + * 朋友圈转发朋友圈次数 + */ @SerializedName("feed_share_from_feed_cnt") private Integer feedShareFromFeedCnt; /** - * feed_share_from_other_user - * 其他场景转发朋友圈人数 - */ + * feed_share_from_other_user + * 其他场景转发朋友圈人数 + */ @SerializedName("feed_share_from_other_user") private Integer feedShareFromOtherUser; /** - * feed_share_from_other_cnt - * 其他场景转发朋友圈次数 - */ + * feed_share_from_other_cnt + * 其他场景转发朋友圈次数 + */ @SerializedName("feed_share_from_other_cnt") private Integer feedShareFromOtherCnt; @@ -284,7 +285,7 @@ public Integer getIntPageFromSessionReadCount() { } public void setIntPageFromSessionReadCount( - Integer intPageFromSessionReadCount) { + Integer intPageFromSessionReadCount) { this.intPageFromSessionReadCount = intPageFromSessionReadCount; } @@ -301,7 +302,7 @@ public Integer getIntPageFromHistMsgReadCount() { } public void setIntPageFromHistMsgReadCount( - Integer intPageFromHistMsgReadCount) { + Integer intPageFromHistMsgReadCount) { this.intPageFromHistMsgReadCount = intPageFromHistMsgReadCount; } @@ -334,7 +335,7 @@ public Integer getIntPageFromFriendsReadCount() { } public void setIntPageFromFriendsReadCount( - Integer intPageFromFriendsReadCount) { + Integer intPageFromFriendsReadCount) { this.intPageFromFriendsReadCount = intPageFromFriendsReadCount; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeBaseResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeBaseResult.java index a9415d9f9e..25fbcc62a9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeBaseResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeBaseResult.java @@ -5,15 +5,11 @@ /** * 统计接口的共用属性类 + * * @author binarywang(Binary Wang) * Created by Binary Wang on 2016/8/25. */ public class WxDataCubeBaseResult { - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - /** * ref_date * 数据的日期,需在begin_date和end_date之间 @@ -21,6 +17,11 @@ public String toString() { @SerializedName("ref_date") private String refDate; + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + public String getRefDate() { return this.refDate; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeInterfaceResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeInterfaceResult.java index 2088453cee..9606c6f98d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeInterfaceResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeInterfaceResult.java @@ -1,15 +1,15 @@ package me.chanjar.weixin.mp.bean.datacube; -import java.util.List; - import com.google.gson.JsonParser; import com.google.gson.annotations.SerializedName; import com.google.gson.reflect.TypeToken; - import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import java.util.List; + /** * 接口分析数据接口返回结果对象 + * * @author binarywang(Binary Wang) * Created by Binary Wang on 2016/8/30. */ @@ -52,6 +52,13 @@ public class WxDataCubeInterfaceResult extends WxDataCubeBaseResult { @SerializedName("max_time_cost") private Integer maxTimeCost; + public static List fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson( + JSON_PARSER.parse(json).getAsJsonObject().get("list"), + new TypeToken>() { + }.getType()); + } + public Integer getRefHour() { return this.refHour; } @@ -92,11 +99,4 @@ public void setMaxTimeCost(Integer maxTimeCost) { this.maxTimeCost = maxTimeCost; } - public static List fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson( - JSON_PARSER.parse(json).getAsJsonObject().get("list"), - new TypeToken>() { - }.getType()); - } - } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeMsgResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeMsgResult.java index 01e40e806c..b3592190dc 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeMsgResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeMsgResult.java @@ -1,15 +1,15 @@ package me.chanjar.weixin.mp.bean.datacube; -import java.util.List; - import com.google.gson.JsonParser; import com.google.gson.annotations.SerializedName; import com.google.gson.reflect.TypeToken; - import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import java.util.List; + /** * 消息分析数据接口返回结果对象 + * * @author binarywang(Binary Wang) * Created by Binary Wang on 2016/8/29. */ @@ -66,6 +66,13 @@ public class WxDataCubeMsgResult extends WxDataCubeBaseResult { @SerializedName("ori_page_read_user") private Integer oriPageReadUser; + public static List fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson( + JSON_PARSER.parse(json).getAsJsonObject().get("list"), + new TypeToken>() { + }.getType()); + } + public Integer getRefHour() { return this.refHour; } @@ -122,11 +129,4 @@ public void setOriPageReadUser(Integer oriPageReadUser) { this.oriPageReadUser = oriPageReadUser; } - public static List fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson( - JSON_PARSER.parse(json).getAsJsonObject().get("list"), - new TypeToken>() { - }.getType()); - } - } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserCumulate.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserCumulate.java index 40e35ded37..32f8d5f5c0 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserCumulate.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserCumulate.java @@ -25,6 +25,13 @@ public class WxDataCubeUserCumulate implements Serializable { private Integer cumulateUser; + public static List fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson( + JSON_PARSER.parse(json).getAsJsonObject().get("list"), + new TypeToken>() { + }.getType()); + } + public Date getRefDate() { return this.refDate; } @@ -45,11 +52,4 @@ public void setCumulateUser(Integer cumulateUser) { public String toString() { return ToStringUtils.toSimpleString(this); } - - public static List fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson( - JSON_PARSER.parse(json).getAsJsonObject().get("list"), - new TypeToken>() { - }.getType()); - } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserSummary.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserSummary.java index 8f47888512..3b76725cc2 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserSummary.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserSummary.java @@ -28,6 +28,13 @@ public class WxDataCubeUserSummary implements Serializable { private Integer cancelUser; + public static List fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson( + JSON_PARSER.parse(json).getAsJsonObject().get("list"), + new TypeToken>() { + }.getType()); + } + public Date getRefDate() { return this.refDate; } @@ -64,11 +71,4 @@ public void setCancelUser(Integer cancelUser) { public String toString() { return ToStringUtils.toSimpleString(this); } - - public static List fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson( - JSON_PARSER.parse(json).getAsJsonObject().get("list"), - new TypeToken>() { - }.getType()); - } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java index b0dd6ec3a7..4b6e52d85c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java @@ -5,7 +5,7 @@ /** * Created by keungtung on 10/12/2016. */ -public class BaseResp extends AbstractDeviceBean{ +public class BaseResp extends AbstractDeviceBean { @SerializedName("base_info") private BaseInfo baseInfo; @SerializedName("errcode") diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/RespMsg.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/RespMsg.java index f1fdedff94..1932e1d166 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/RespMsg.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/RespMsg.java @@ -6,7 +6,7 @@ * Created by keungtung on 10/12/2016. */ -public class RespMsg extends AbstractDeviceBean{ +public class RespMsg extends AbstractDeviceBean { @SerializedName("ret_code") private Integer retCode; @SerializedName("error_info") diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/TransMsgResp.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/TransMsgResp.java index 8828b25c9e..31525f6bad 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/TransMsgResp.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/TransMsgResp.java @@ -6,7 +6,7 @@ /** * Created by keungtung on 14/12/2016. */ -public class TransMsgResp extends AbstractDeviceBean{ +public class TransMsgResp extends AbstractDeviceBean { private Integer ret; @SerializedName("ret_info") private String retInfo; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceAuthorizeResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceAuthorizeResult.java index dfe8d3b7fc..83ea27c5b2 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceAuthorizeResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceAuthorizeResult.java @@ -7,7 +7,7 @@ /** * Created by keungtung on 10/12/2016. */ -public class WxDeviceAuthorizeResult extends AbstractDeviceBean{ +public class WxDeviceAuthorizeResult extends AbstractDeviceBean { private List resp; public static WxDeviceAuthorizeResult fromJson(String response) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBind.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBind.java index 467f3c42d9..1acf59628a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBind.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBind.java @@ -5,7 +5,7 @@ /** * Created by keungtung on 10/12/2016. */ -public class WxDeviceBind extends AbstractDeviceBean{ +public class WxDeviceBind extends AbstractDeviceBean { private String ticket; @SerializedName("device_id") private String deviceId; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBindResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBindResult.java index 26bdb84c6a..2cbf007835 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBindResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBindResult.java @@ -6,7 +6,7 @@ /** * Created by keungtung on 10/12/2016. */ -public class WxDeviceBindResult extends AbstractDeviceBean{ +public class WxDeviceBindResult extends AbstractDeviceBean { @SerializedName("base_resp") private BaseResp baseResp; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceMsg.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceMsg.java index bed1a8a23a..680209fd71 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceMsg.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceMsg.java @@ -6,7 +6,7 @@ /** * Created by keungtung on 10/12/2016. */ -public class WxDeviceMsg extends AbstractDeviceBean{ +public class WxDeviceMsg extends AbstractDeviceBean { @SerializedName("device_type") private String deviceType; @SerializedName("device_id") diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java index 228351fdab..2c02a6207d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java @@ -1,19 +1,12 @@ package me.chanjar.weixin.mp.bean.kefu; +import me.chanjar.weixin.mp.builder.kefu.*; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import me.chanjar.weixin.mp.builder.kefu.ImageBuilder; -import me.chanjar.weixin.mp.builder.kefu.MpNewsBuilder; -import me.chanjar.weixin.mp.builder.kefu.MusicBuilder; -import me.chanjar.weixin.mp.builder.kefu.NewsBuilder; -import me.chanjar.weixin.mp.builder.kefu.TextBuilder; -import me.chanjar.weixin.mp.builder.kefu.VideoBuilder; -import me.chanjar.weixin.mp.builder.kefu.VoiceBuilder; -import me.chanjar.weixin.mp.builder.kefu.WxCardBuilder; -import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; - /** * 客服消息 * @@ -104,14 +97,6 @@ public String getMsgType() { return this.msgType; } - public String getMpNewsMediaId() { - return this.mpNewsMediaId; - } - - public void setMpNewsMediaId(String mpNewsMediaId) { - this.mpNewsMediaId = mpNewsMediaId; - } - /** *
        * 请使用
    @@ -131,6 +116,14 @@ public void setMsgType(String msgType) {
         this.msgType = msgType;
       }
     
    +  public String getMpNewsMediaId() {
    +    return this.mpNewsMediaId;
    +  }
    +
    +  public void setMpNewsMediaId(String mpNewsMediaId) {
    +    this.mpNewsMediaId = mpNewsMediaId;
    +  }
    +
       public String getContent() {
         return this.content;
       }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfAccountRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfAccountRequest.java
    index b1f0fac8f0..85cdfe5507 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfAccountRequest.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfAccountRequest.java
    @@ -1,12 +1,10 @@
     package me.chanjar.weixin.mp.bean.kefu.request;
     
    -import java.io.Serializable;
    -
    -import org.apache.commons.lang3.builder.ToStringBuilder;
    -
     import com.google.gson.annotations.SerializedName;
    -
     import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
    +import org.apache.commons.lang3.builder.ToStringBuilder;
    +
    +import java.io.Serializable;
     
     public class WxMpKfAccountRequest implements Serializable {
       private static final long serialVersionUID = -5451863610674856927L;
    @@ -16,7 +14,7 @@ public class WxMpKfAccountRequest implements Serializable {
        */
       @SerializedName("kf_account")
       private String kfAccount;
    -  
    +
       /**
        * nickname   客服昵称,最长6个汉字或12个英文字符
        */
    @@ -28,12 +26,16 @@ public class WxMpKfAccountRequest implements Serializable {
        */
       @SerializedName("invite_wx")
       private String inviteWx;
    -  
    +
    +  public static Builder builder() {
    +    return new Builder();
    +  }
    +
       @Override
       public String toString() {
         return ToStringBuilder.reflectionToString(this);
       }
    -  
    +
       public String toJson() {
         return WxMpGsonBuilder.INSTANCE.create().toJson(this);
       }
    @@ -54,10 +56,6 @@ public void setNickName(String nickName) {
         this.nickName = nickName;
       }
     
    -  public static Builder builder() {
    -      return new Builder();
    -  }
    -
       public String getInviteWx() {
         return this.inviteWx;
       }
    @@ -67,39 +65,39 @@ public void setInviteWx(String inviteWx) {
       }
     
       public static class Builder {
    -      private String kfAccount;
    -      private String nickName;
    -      private String inviteWx;
    -
    -      public Builder kfAccount(String kfAccount) {
    -          this.kfAccount = kfAccount;
    -          return this;
    -      }
    -
    -      public Builder nickName(String nickName) {
    -          this.nickName = nickName;
    -          return this;
    -      }
    -
    -      public Builder inviteWx(String inviteWx) {
    -        this.inviteWx = inviteWx;
    -        return this;
    -      }
    -
    -      public Builder from(WxMpKfAccountRequest origin) {
    -          this.kfAccount(origin.kfAccount);
    -          this.nickName(origin.nickName);
    -          this.inviteWx(origin.inviteWx);
    -          return this;
    -      }
    -
    -      public WxMpKfAccountRequest build() {
    -          WxMpKfAccountRequest m = new WxMpKfAccountRequest();
    -          m.kfAccount = this.kfAccount;
    -          m.nickName = this.nickName;
    -          m.inviteWx = this.inviteWx;
    -          return m;
    -      }
    +    private String kfAccount;
    +    private String nickName;
    +    private String inviteWx;
    +
    +    public Builder kfAccount(String kfAccount) {
    +      this.kfAccount = kfAccount;
    +      return this;
    +    }
    +
    +    public Builder nickName(String nickName) {
    +      this.nickName = nickName;
    +      return this;
    +    }
    +
    +    public Builder inviteWx(String inviteWx) {
    +      this.inviteWx = inviteWx;
    +      return this;
    +    }
    +
    +    public Builder from(WxMpKfAccountRequest origin) {
    +      this.kfAccount(origin.kfAccount);
    +      this.nickName(origin.nickName);
    +      this.inviteWx(origin.inviteWx);
    +      return this;
    +    }
    +
    +    public WxMpKfAccountRequest build() {
    +      WxMpKfAccountRequest m = new WxMpKfAccountRequest();
    +      m.kfAccount = this.kfAccount;
    +      m.nickName = this.nickName;
    +      m.inviteWx = this.inviteWx;
    +      return m;
    +    }
       }
     
     }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java
    index 868bf51952..c879e9f63a 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java
    @@ -8,8 +8,8 @@
     
     /**
      * 客服基本信息以及客服在线状态信息
    - * @author Binary Wang
      *
    + * @author Binary Wang
      */
     public class WxMpKfInfo implements Serializable {
       private static final long serialVersionUID = -5877300750666022290L;
    @@ -63,7 +63,7 @@ public class WxMpKfInfo implements Serializable {
       private String inviteStatus;
     
       /**
    -   *  status 客服在线状态,目前为:1、web 在线
    +   * status 客服在线状态,目前为:1、web 在线
        */
       @SerializedName("status")
       private Integer status;
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java
    index 9ec9eeff5b..b5cef947a9 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java
    @@ -5,15 +5,18 @@
     import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
     
     import java.util.List;
    +
     /**
    - *
      * @author Binary Wang
    - *
      */
     public class WxMpKfList {
       @SerializedName("kf_list")
       private List kfList;
     
    +  public static WxMpKfList fromJson(String json) {
    +    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfList.class);
    +  }
    +
       @Override
       public String toString() {
         return ToStringUtils.toSimpleString(this);
    @@ -26,8 +29,4 @@ public List getKfList() {
       public void setKfList(List kfList) {
         this.kfList = kfList;
       }
    -
    -  public static WxMpKfList fromJson(String json) {
    -    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfList.class);
    -  }
     }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java
    index 7c04acb34a..02d249192f 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java
    @@ -19,6 +19,10 @@ public class WxMpKfMsgList {
       @SerializedName("msgid")
       private Long msgId;
     
    +  public static WxMpKfMsgList fromJson(String responseContent) {
    +    return WxMpGsonBuilder.INSTANCE.create().fromJson(responseContent, WxMpKfMsgList.class);
    +  }
    +
       public List getRecords() {
         return this.records;
       }
    @@ -47,8 +51,4 @@ public void setMsgId(Long msgId) {
       public String toString() {
         return ToStringUtils.toSimpleString(this);
       }
    -
    -  public static WxMpKfMsgList fromJson(String responseContent) {
    -    return WxMpGsonBuilder.INSTANCE.create().fromJson(responseContent, WxMpKfMsgList.class);
    -  }
     }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java
    index 0ed9c0b24a..c7ada50081 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java
    @@ -31,7 +31,7 @@ public class WxMpKfMsgRecord {
       @SerializedName("text")
       private String text;
     
    -   /**
    +  /**
        * time	操作时间,unix时间戳
        */
       @SerializedName("time")
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java
    index 9750009583..1f7545cbfa 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java
    @@ -5,15 +5,18 @@
     import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
     
     import java.util.List;
    +
     /**
    - *
      * @author Binary Wang
    - *
      */
     public class WxMpKfOnlineList {
       @SerializedName("kf_online_list")
       private List kfOnlineList;
     
    +  public static WxMpKfOnlineList fromJson(String json) {
    +    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfOnlineList.class);
    +  }
    +
       @Override
       public String toString() {
         return ToStringUtils.toSimpleString(this);
    @@ -26,8 +29,4 @@ public List getKfOnlineList() {
       public void setKfOnlineList(List kfOnlineList) {
         this.kfOnlineList = kfOnlineList;
       }
    -
    -  public static WxMpKfOnlineList fromJson(String json) {
    -    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfOnlineList.class);
    -  }
     }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java
    index da29b4aec9..500fc7577a 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java
    @@ -4,9 +4,7 @@
     import me.chanjar.weixin.common.util.ToStringUtils;
     
     /**
    - *
      * @author Binary Wang
    - *
      */
     public class WxMpKfSession {
       /**
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java
    index 2eb7314325..b0177acdfd 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java
    @@ -5,9 +5,7 @@
     import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
     
     /**
    - *
      * @author Binary Wang
    - *
      */
     public class WxMpKfSessionGetResult {
       /**
    @@ -22,15 +20,15 @@ public class WxMpKfSessionGetResult {
       @SerializedName("createtime")
       private long createTime;
     
    +  public static WxMpKfSessionGetResult fromJson(String json) {
    +    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfSessionGetResult.class);
    +  }
    +
       @Override
       public String toString() {
         return ToStringUtils.toSimpleString(this);
       }
     
    -  public static WxMpKfSessionGetResult fromJson(String json) {
    -    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfSessionGetResult.class);
    -  }
    -
       public String getKfAccount() {
         return this.kfAccount;
       }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java
    index a9a0640e6d..dd03668695 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java
    @@ -7,9 +7,7 @@
     import java.util.List;
     
     /**
    - *
      * @author Binary Wang
    - *
      */
     public class WxMpKfSessionList {
       /**
    @@ -18,16 +16,16 @@ public class WxMpKfSessionList {
       @SerializedName("sessionlist")
       private List kfSessionList;
     
    +  public static WxMpKfSessionList fromJson(String json) {
    +    return WxMpGsonBuilder.INSTANCE.create().fromJson(json,
    +      WxMpKfSessionList.class);
    +  }
    +
       @Override
       public String toString() {
         return ToStringUtils.toSimpleString(this);
       }
     
    -  public static WxMpKfSessionList fromJson(String json) {
    -    return WxMpGsonBuilder.INSTANCE.create().fromJson(json,
    -        WxMpKfSessionList.class);
    -  }
    -
       public List getKfSessionList() {
         return this.kfSessionList;
       }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java
    index 22bcc4da67..562113f191 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java
    @@ -7,9 +7,7 @@
     import java.util.List;
     
     /**
    - *
      * @author Binary Wang
    - *
      */
     public class WxMpKfSessionWaitCaseList {
       /**
    @@ -24,16 +22,16 @@ public class WxMpKfSessionWaitCaseList {
       @SerializedName("waitcaselist")
       private List kfSessionWaitCaseList;
     
    +  public static WxMpKfSessionWaitCaseList fromJson(String json) {
    +    return WxMpGsonBuilder.INSTANCE.create().fromJson(json,
    +      WxMpKfSessionWaitCaseList.class);
    +  }
    +
       @Override
       public String toString() {
         return ToStringUtils.toSimpleString(this);
       }
     
    -  public static WxMpKfSessionWaitCaseList fromJson(String json) {
    -    return WxMpGsonBuilder.INSTANCE.create().fromJson(json,
    -        WxMpKfSessionWaitCaseList.class);
    -  }
    -
       public List getKfSessionWaitCaseList() {
         return this.kfSessionWaitCaseList;
       }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java
    index f67a8cb4fa..a107facaed 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNews.java
    @@ -28,6 +28,11 @@ public boolean isEmpty() {
         return this.articles == null || this.articles.isEmpty();
       }
     
    +  @Override
    +  public String toString() {
    +    return ToStringUtils.toSimpleString(this);
    +  }
    +
       /**
        * 
        * 群发图文消息article
    @@ -79,7 +84,7 @@ public static class WxMpMaterialNewsArticle {
     
         /**
          * 点击图文消息跳转链接
    -    */
    +     */
         private String url;
     
         public String getThumbMediaId() {
    @@ -139,11 +144,11 @@ public void setShowCoverPic(boolean showCoverPic) {
         }
     
         public String getUrl() {
    -        return this.url;
    +      return this.url;
         }
     
         public void setUrl(String url) {
    -        this.url = url;
    +      this.url = url;
         }
     
         public String getThumbUrl() {
    @@ -159,9 +164,4 @@ public String toString() {
           return ToStringUtils.toSimpleString(this);
         }
       }
    -
    -  @Override
    -  public String toString() {
    -    return ToStringUtils.toSimpleString(this);
    -  }
     }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java
    index 2b3a1e5785..ec1d115496 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialUploadResult.java
    @@ -13,6 +13,10 @@ public class WxMpMaterialUploadResult implements Serializable {
       private String mediaId;
       private String url;
     
    +  public static WxMpMaterialUploadResult fromJson(String json) {
    +    return WxMpGsonBuilder.create().fromJson(json, WxMpMaterialUploadResult.class);
    +  }
    +
       public String getMediaId() {
         return this.mediaId;
       }
    @@ -29,10 +33,6 @@ public void setUrl(String url) {
         this.url = url;
       }
     
    -  public static WxMpMaterialUploadResult fromJson(String json) {
    -    return WxMpGsonBuilder.create().fromJson(json, WxMpMaterialUploadResult.class);
    -  }
    -
       @Override
       public String toString() {
         return "WxMpMaterialUploadResult [media_id=" + this.mediaId + ", url=" + this.url + "]";
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialVideoInfoResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialVideoInfoResult.java
    index 06b85b7e9b..be5dd3f844 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialVideoInfoResult.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialVideoInfoResult.java
    @@ -14,6 +14,10 @@ public class WxMpMaterialVideoInfoResult implements Serializable {
       private String description;
       private String downUrl;
     
    +  public static WxMpMaterialVideoInfoResult fromJson(String json) {
    +    return WxMpGsonBuilder.create().fromJson(json, WxMpMaterialVideoInfoResult.class);
    +  }
    +
       public String getTitle() {
         return this.title;
       }
    @@ -38,10 +42,6 @@ public void setDownUrl(String downUrl) {
         this.downUrl = downUrl;
       }
     
    -  public static WxMpMaterialVideoInfoResult fromJson(String json) {
    -    return WxMpGsonBuilder.create().fromJson(json, WxMpMaterialVideoInfoResult.class);
    -  }
    -
       @Override
       public String toString() {
         return "WxMpMaterialVideoInfoResult [title=" + this.title + ", description=" + this.description + ", downUrl=" + this.downUrl + "]";
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java
    index f2c0c4ca51..588e8a9c05 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java
    @@ -25,11 +25,6 @@ public String toString() {
       }
     
       public static class WxMpSelfMenuButton {
    -    @Override
    -    public String toString() {
    -      return ToStringUtils.toSimpleString(this);
    -    }
    -
         /**
          * 
          * 菜单的类型,公众平台官网上能够设置的菜单类型有view(跳转网页)、text(返回文本,下同)、img、photo、video、voice。
    @@ -38,13 +33,11 @@ public String toString() {
          */
         @SerializedName("type")
         private String type;
    -
         /**
          * 菜单名称
          */
         @SerializedName("name")
         private String name;
    -
         /**
          * 
          * 对于不同的菜单类型,value的值意义不同。
    @@ -62,24 +55,31 @@ public String toString() {
          */
         @SerializedName("key")
         private String key;
    -
         /**
          * @see #key
          */
         @SerializedName("url")
         private String url;
    -
         /**
          * @see #key
          */
         @SerializedName("value")
         private String value;
    -
         /**
          * 子菜单信息
          */
         @SerializedName("sub_button")
         private SubButtons subButtons;
    +    /**
    +     * 图文消息的信息
    +     */
    +    @SerializedName("news_info")
    +    private NewsInfo newsInfo;
    +
    +    @Override
    +    public String toString() {
    +      return ToStringUtils.toSimpleString(this);
    +    }
     
         public SubButtons getSubButtons() {
           return subButtons;
    @@ -89,30 +89,6 @@ public void setSubButtons(SubButtons subButtons) {
           this.subButtons = subButtons;
         }
     
    -    public static class SubButtons {
    -      @Override
    -      public String toString() {
    -        return ToStringUtils.toSimpleString(this);
    -      }
    -
    -      @SerializedName("list")
    -      private List subButtons = new ArrayList<>();
    -
    -      public List getSubButtons() {
    -        return subButtons;
    -      }
    -
    -      public void setSubButtons(List subButtons) {
    -        this.subButtons = subButtons;
    -      }
    -    }
    -
    -    /**
    -     * 图文消息的信息
    -     */
    -    @SerializedName("news_info")
    -    private NewsInfo newsInfo;
    -
         public String getType() {
           return type;
         }
    @@ -161,15 +137,33 @@ public void setNewsInfo(NewsInfo newsInfo) {
           this.newsInfo = newsInfo;
         }
     
    -    public static class NewsInfo {
    +    public static class SubButtons {
    +      @SerializedName("list")
    +      private List subButtons = new ArrayList<>();
    +
           @Override
           public String toString() {
             return ToStringUtils.toSimpleString(this);
           }
     
    +      public List getSubButtons() {
    +        return subButtons;
    +      }
    +
    +      public void setSubButtons(List subButtons) {
    +        this.subButtons = subButtons;
    +      }
    +    }
    +
    +    public static class NewsInfo {
           @SerializedName("list")
           private List news = new ArrayList<>();
     
    +      @Override
    +      public String toString() {
    +        return ToStringUtils.toSimpleString(this);
    +      }
    +
           public List getNews() {
             return news;
           }
    @@ -179,54 +173,48 @@ public void setNews(List news) {
           }
     
           public static class NewsInButton {
    -        @Override
    -        public String toString() {
    -          return ToStringUtils.toSimpleString(this);
    -        }
    -
             /**
              * 图文消息的标题
              */
             @SerializedName("title")
             private String title;
    -
             /**
              * 摘要
              */
             @SerializedName("digest")
             private String digest;
    -
             /**
              * 作者
              */
             @SerializedName("author")
             private String author;
    -
             /**
              * show_cover
              * 是否显示封面,0为不显示,1为显示
              */
             @SerializedName("show_cover")
             private Integer showCover;
    -
             /**
              * 封面图片的URL
              */
             @SerializedName("cover_url")
             private String coverUrl;
    -
             /**
              * 正文的URL
              */
             @SerializedName("content_url")
             private String contentUrl;
    -
             /**
              * 原文的URL,若置空则无查看原文入口
              */
             @SerializedName("source_url")
             private String sourceUrl;
     
    +        @Override
    +        public String toString() {
    +          return ToStringUtils.toSimpleString(this);
    +        }
    +
             public String getTitle() {
               return title;
             }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/HardWare.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/HardWare.java
    new file mode 100644
    index 0000000000..32dfcd7e2f
    --- /dev/null
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/HardWare.java
    @@ -0,0 +1,50 @@
    +package me.chanjar.weixin.mp.bean.message;
    +
    +import com.thoughtworks.xstream.annotations.XStreamAlias;
    +import com.thoughtworks.xstream.annotations.XStreamConverter;
    +import me.chanjar.weixin.common.util.ToStringUtils;
    +import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
    +
    +/**
    + * 
    + *  Created by BinaryWang on 2017/5/4.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("HardWare") +public class HardWare { + /** + * 消息展示,目前支持myrank(排行榜) + */ + @XStreamAlias("MessageView") + @XStreamConverter(value = XStreamCDataConverter.class) + private String messageView; + /** + * 消息点击动作,目前支持ranklist(点击跳转排行榜) + */ + @XStreamAlias("MessageAction") + @XStreamConverter(value = XStreamCDataConverter.class) + private String messageAction; + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public String getMessageView() { + return messageView; + } + + public void setMessageView(String messageView) { + this.messageView = messageView; + } + + public String getMessageAction() { + return messageAction; + } + + public void setMessageAction(String messageAction) { + this.messageAction = messageAction; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/ScanCodeInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/ScanCodeInfo.java new file mode 100644 index 0000000000..ddebffdf61 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/ScanCodeInfo.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.mp.bean.message; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; + +/** + *
    + *  Created by BinaryWang on 2017/5/4.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("ScanCodeInfo") +public class ScanCodeInfo { + @XStreamAlias("ScanType") + @XStreamConverter(value = XStreamCDataConverter.class) + private String scanType; + @XStreamAlias("ScanResult") + @XStreamConverter(value = XStreamCDataConverter.class) + private String scanResult; + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + /** + * 扫描类型,一般是qrcode + */ + public String getScanType() { + + return this.scanType; + } + + public void setScanType(String scanType) { + this.scanType = scanType; + } + + /** + * 扫描结果,即二维码对应的字符串信息 + */ + public String getScanResult() { + return this.scanResult; + } + + public void setScanResult(String scanResult) { + this.scanResult = scanResult; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendLocationInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendLocationInfo.java new file mode 100644 index 0000000000..a397ab8193 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendLocationInfo.java @@ -0,0 +1,82 @@ +package me.chanjar.weixin.mp.bean.message; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; + +/** + *
    + *  Created by BinaryWang on 2017/5/4.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("SendLocationInfo") +public class SendLocationInfo { + + @XStreamAlias("Location_X") + @XStreamConverter(value = XStreamCDataConverter.class) + private String locationX; + + @XStreamAlias("Location_Y") + @XStreamConverter(value = XStreamCDataConverter.class) + private String locationY; + + @XStreamAlias("Scale") + @XStreamConverter(value = XStreamCDataConverter.class) + private String scale; + + @XStreamAlias("Label") + @XStreamConverter(value = XStreamCDataConverter.class) + private String label; + + @XStreamAlias("Poiname") + @XStreamConverter(value = XStreamCDataConverter.class) + private String poiname; + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public String getLocationX() { + return this.locationX; + } + + public void setLocationX(String locationX) { + this.locationX = locationX; + } + + public String getLocationY() { + return this.locationY; + } + + public void setLocationY(String locationY) { + this.locationY = locationY; + } + + public String getScale() { + return this.scale; + } + + public void setScale(String scale) { + this.scale = scale; + } + + public String getLabel() { + return this.label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getPoiname() { + return this.poiname; + } + + public void setPoiname(String poiname) { + this.poiname = poiname; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendPicsInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendPicsInfo.java new file mode 100644 index 0000000000..3461355c9a --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/SendPicsInfo.java @@ -0,0 +1,61 @@ +package me.chanjar.weixin.mp.bean.message; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; + +import java.util.ArrayList; +import java.util.List; + +/** + *
    + *  Created by BinaryWang on 2017/5/4.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("SendPicsInfo") +public class SendPicsInfo { + @XStreamAlias("PicList") + protected final List picList = new ArrayList<>(); + @XStreamAlias("Count") + private Long count; + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public Long getCount() { + return this.count; + } + + public void setCount(Long count) { + this.count = count; + } + + public List getPicList() { + return this.picList; + } + + @XStreamAlias("item") + public static class Item { + @XStreamAlias("PicMd5Sum") + @XStreamConverter(value = XStreamCDataConverter.class) + private String picMd5Sum; + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public String getPicMd5Sum() { + return this.picMd5Sum; + } + + public void setPicMd5Sum(String picMd5Sum) { + this.picMd5Sum = picMd5Sum; + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java index 0f1a3ffe62..262399b8f4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java @@ -12,8 +12,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; /** *
    @@ -199,6 +197,129 @@ public class WxMpXmlMessage implements Serializable {
       @XStreamAlias("OuterId")
       private Integer outerId;
     
    +  /**
    +   * 用户删除会员卡后可重新找回,当用户本次操作为找回时,该值为1,否则为0
    +   */
    +  @XStreamAlias("IsRestoreMemberCard")
    +  private String isRestoreMemberCard;
    +
    +  /**
    +   * 
    +   * 领取场景值,用于领取渠道数据统计。可在生成二维码接口及添加Addcard接口中自定义该字段的字符串值。
    +   * 核销卡券时:开发者发起核销时传入的自定义参数,用于进行核销渠道统计
    +   * 另外:
    +   * 官网文档中,微信卡券>>卡券事件推送>>2.7 进入会员卡事件推送 user_view_card
    +   * OuterStr:商户自定义二维码渠道参数,用于标识本次扫码打开会员卡来源来自于某个渠道值的二维码
    +   * 
    + */ + @XStreamAlias("OuterStr") + private String outerStr; + + /** + * 是否转赠退回,0代表不是,1代表是。 + */ + @XStreamAlias("IsReturnBack") + private String isReturnBack; + + /** + * 是否是群转赠,0代表不是,1代表是。 + */ + @XStreamAlias("IsChatRoom") + private String isChatRoom; + + /** + * 核销来源。支持开发者统计API核销(FROM_API)、公众平台核销(FROM_MP)、卡券商户助手核销(FROM_MOBILE_HELPER)(核销员微信号) + */ + @XStreamAlias("ConsumeSource") + private String consumeSource; + + /** + * 门店名称,当前卡券核销的门店名称(只有通过自助核销和买单核销时才会出现该字段) + */ + @XStreamAlias("LocationName") + private String locationName; + + /** + * 核销该卡券核销员的openid(只有通过卡券商户助手核销时才会出现) + */ + @XStreamAlias("StaffOpenId") + private String staffOpenId; + + /** + * 自助核销时,用户输入的验证码 + */ + @XStreamAlias("VerifyCode") + private String verifyCode; + + /** + * 自助核销时,用户输入的备注金额 + */ + @XStreamAlias("RemarkAmount") + private String remarkAmount; + + /** + *
    +   * 官网文档中,微信卡券>>卡券事件推送>>2.10 库存报警事件card_sku_remind
    +   * Detail:报警详细信息
    +   * 
    + */ + @XStreamAlias("Detail") + private String detail; + + /** + *
    +   * 官网文档中,微信卡券>>卡券事件推送>>2.9 会员卡内容更新事件 update_member_card
    +   * ModifyBonus:变动的积分值
    +   * 
    + */ + @XStreamAlias("ModifyBonus") + private String modifyBonus; + + /** + *
    +   * 官网文档中,微信卡券>>卡券事件推送>>2.9 会员卡内容更新事件 update_member_card
    +   * ModifyBalance:变动的余额值
    +   * 
    + */ + @XStreamAlias("ModifyBalance") + private String modifyBalance; + + /** + *
    +   * 官网文档中,微信卡券>>卡券事件推送>>2.6 买单事件推送 User_pay_from_pay_cell
    +   * TransId:微信支付交易订单号(只有使用买单功能核销的卡券才会出现)
    +   * 
    + */ + @XStreamAlias("TransId") + private String transId; + + /** + *
    +   * 官网文档中,微信卡券>>卡券事件推送>>2.6 买单事件推送 User_pay_from_pay_cell
    +   * LocationId:门店ID,当前卡券核销的门店ID(只有通过卡券商户助手和买单核销时才会出现)
    +   * 
    + */ + @XStreamAlias("LocationId") + private String locationId; + + /** + *
    +   * 官网文档中,微信卡券>>卡券事件推送>>2.6 买单事件推送 User_pay_from_pay_cell
    +   * Fee:实付金额,单位为分
    +   * 
    + */ + @XStreamAlias("Fee") + private String fee; + + /** + *
    +   * 官网文档中,微信卡券>>卡券事件推送>>2.6 买单事件推送 User_pay_from_pay_cell
    +   * OriginalFee:应付金额,单位为分
    +   * 
    + */ + @XStreamAlias("OriginalFee") + private String originalFee; + @XStreamAlias("ScanCodeInfo") private ScanCodeInfo scanCodeInfo = new ScanCodeInfo(); @@ -314,11 +435,11 @@ public static WxMpXmlMessage fromXml(InputStream is) { /** * 从加密字符串转换 * - * @param encryptedXml - * @param wxMpConfigStorage - * @param timestamp - * @param nonce - * @param msgSignature + * @param encryptedXml 密文 + * @param wxMpConfigStorage 配置存储器对象 + * @param timestamp 时间戳 + * @param nonce 随机串 + * @param msgSignature 签名串 */ public static WxMpXmlMessage fromEncryptedXml(String encryptedXml, WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce, @@ -413,6 +534,62 @@ public void setFailReason(String failReason) { this.failReason = failReason; } + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public String getModifyBonus() { + return modifyBonus; + } + + public void setModifyBonus(String modifyBonus) { + this.modifyBonus = modifyBonus; + } + + public String getModifyBalance() { + return modifyBalance; + } + + public void setModifyBalance(String modifyBalance) { + this.modifyBalance = modifyBalance; + } + + public String getTransId() { + return transId; + } + + public void setTransId(String transId) { + this.transId = transId; + } + + public String getLocationId() { + return locationId; + } + + public void setLocationId(String locationId) { + this.locationId = locationId; + } + + public String getFee() { + return fee; + } + + public void setFee(String fee) { + this.fee = fee; + } + + public String getOriginalFee() { + return originalFee; + } + + public void setOriginalFee(String originalFee) { + this.originalFee = originalFee; + } + public String getStoreUniqId() { return this.storeUniqId; } @@ -750,28 +927,28 @@ public void setOuterId(Integer outerId) { this.outerId = outerId; } - public WxMpXmlMessage.ScanCodeInfo getScanCodeInfo() { + public ScanCodeInfo getScanCodeInfo() { return this.scanCodeInfo; } - public void setScanCodeInfo(WxMpXmlMessage.ScanCodeInfo scanCodeInfo) { + public void setScanCodeInfo(ScanCodeInfo scanCodeInfo) { this.scanCodeInfo = scanCodeInfo; } - public WxMpXmlMessage.SendPicsInfo getSendPicsInfo() { + public SendPicsInfo getSendPicsInfo() { return this.sendPicsInfo; } - public void setSendPicsInfo(WxMpXmlMessage.SendPicsInfo sendPicsInfo) { + public void setSendPicsInfo(SendPicsInfo sendPicsInfo) { this.sendPicsInfo = sendPicsInfo; } - public WxMpXmlMessage.SendLocationInfo getSendLocationInfo() { + public SendLocationInfo getSendLocationInfo() { return this.sendLocationInfo; } public void setSendLocationInfo( - WxMpXmlMessage.SendLocationInfo sendLocationInfo) { + SendLocationInfo sendLocationInfo) { this.sendLocationInfo = sendLocationInfo; } @@ -807,198 +984,81 @@ public void setFromKfAccount(String fromKfAccount) { this.fromKfAccount = fromKfAccount; } - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); + public String getIsRestoreMemberCard() { + return isRestoreMemberCard; } - @XStreamAlias("HardWare") - public static class HardWare { - /** - * 消息展示,目前支持myrank(排行榜) - */ - @XStreamAlias("MessageView") - @XStreamConverter(value = XStreamCDataConverter.class) - private String messageView; - /** - * 消息点击动作,目前支持ranklist(点击跳转排行榜) - */ - @XStreamAlias("MessageAction") - @XStreamConverter(value = XStreamCDataConverter.class) - private String messageAction; - - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - - public String getMessageView() { - return messageView; - } - - public void setMessageView(String messageView) { - this.messageView = messageView; - } - - public String getMessageAction() { - return messageAction; - } - - public void setMessageAction(String messageAction) { - this.messageAction = messageAction; - } + public void setIsRestoreMemberCard(String isRestoreMemberCard) { + this.isRestoreMemberCard = isRestoreMemberCard; } - @XStreamAlias("ScanCodeInfo") - public static class ScanCodeInfo { - @XStreamAlias("ScanType") - @XStreamConverter(value = XStreamCDataConverter.class) - private String scanType; - @XStreamAlias("ScanResult") - @XStreamConverter(value = XStreamCDataConverter.class) - private String scanResult; - - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - - /** - * 扫描类型,一般是qrcode - */ - public String getScanType() { - - return this.scanType; - } - - public void setScanType(String scanType) { - this.scanType = scanType; - } - - /** - * 扫描结果,即二维码对应的字符串信息 - */ - public String getScanResult() { - return this.scanResult; - } - - public void setScanResult(String scanResult) { - this.scanResult = scanResult; - } - + public String getOuterStr() { + return outerStr; } - @XStreamAlias("SendPicsInfo") - public static class SendPicsInfo { - @XStreamAlias("PicList") - protected final List picList = new ArrayList<>(); - @XStreamAlias("Count") - private Long count; - - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - - public Long getCount() { - return this.count; - } - - public void setCount(Long count) { - this.count = count; - } - - public List getPicList() { - return this.picList; - } - - @XStreamAlias("item") - public static class Item { - @XStreamAlias("PicMd5Sum") - @XStreamConverter(value = XStreamCDataConverter.class) - private String picMd5Sum; - - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - - public String getPicMd5Sum() { - return this.picMd5Sum; - } - - public void setPicMd5Sum(String picMd5Sum) { - this.picMd5Sum = picMd5Sum; - } - } + public void setOuterStr(String outerStr) { + this.outerStr = outerStr; } - @XStreamAlias("SendLocationInfo") - public static class SendLocationInfo { - - @XStreamAlias("Location_X") - @XStreamConverter(value = XStreamCDataConverter.class) - private String locationX; - - @XStreamAlias("Location_Y") - @XStreamConverter(value = XStreamCDataConverter.class) - private String locationY; + public String getIsReturnBack() { + return isReturnBack; + } - @XStreamAlias("Scale") - @XStreamConverter(value = XStreamCDataConverter.class) - private String scale; + public void setIsReturnBack(String isReturnBack) { + this.isReturnBack = isReturnBack; + } - @XStreamAlias("Label") - @XStreamConverter(value = XStreamCDataConverter.class) - private String label; + public String getIsChatRoom() { + return isChatRoom; + } - @XStreamAlias("Poiname") - @XStreamConverter(value = XStreamCDataConverter.class) - private String poiname; + public void setIsChatRoom(String isChatRoom) { + this.isChatRoom = isChatRoom; + } - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } + public String getConsumeSource() { + return this.consumeSource; + } - public String getLocationX() { - return this.locationX; - } + public void setConsumeSource(String consumeSource) { + this.consumeSource = consumeSource; + } - public void setLocationX(String locationX) { - this.locationX = locationX; - } + public String getLocationName() { + return this.locationName; + } - public String getLocationY() { - return this.locationY; - } + public void setLocationName(String locationName) { + this.locationName = locationName; + } - public void setLocationY(String locationY) { - this.locationY = locationY; - } + public String getStaffOpenId() { + return this.staffOpenId; + } - public String getScale() { - return this.scale; - } + public void setStaffOpenId(String staffOpenId) { + this.staffOpenId = staffOpenId; + } - public void setScale(String scale) { - this.scale = scale; - } + public String getVerifyCode() { + return this.verifyCode; + } - public String getLabel() { - return this.label; - } + public void setVerifyCode(String verifyCode) { + this.verifyCode = verifyCode; + } - public void setLabel(String label) { - this.label = label; - } + public String getRemarkAmount() { + return this.remarkAmount; + } - public String getPoiname() { - return this.poiname; - } + public void setRemarkAmount(String remarkAmount) { + this.remarkAmount = remarkAmount; + } - public void setPoiname(String poiname) { - this.poiname = poiname; - } + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutImageMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutImageMessage.java index 62852ca8f1..f3a0740767 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutImageMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutImageMessage.java @@ -16,6 +16,10 @@ public class WxMpXmlOutImageMessage extends WxMpXmlOutMessage { @XStreamConverter(value = XStreamMediaIdConverter.class) private String mediaId; + public WxMpXmlOutImageMessage() { + this.msgType = WxConsts.XML_MSG_IMAGE; + } + public String getMediaId() { return this.mediaId; } @@ -24,8 +28,4 @@ public void setMediaId(String mediaId) { this.mediaId = mediaId; } - public WxMpXmlOutImageMessage() { - this.msgType = WxConsts.XML_MSG_IMAGE; - } - } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java index c0b53d46a3..ad5d5bd5ca 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java @@ -16,66 +16,20 @@ public abstract class WxMpXmlOutMessage implements Serializable { private static final long serialVersionUID = -381382011286216263L; @XStreamAlias("ToUserName") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) protected String toUserName; @XStreamAlias("FromUserName") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) protected String fromUserName; @XStreamAlias("CreateTime") protected Long createTime; @XStreamAlias("MsgType") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) protected String msgType; - public String getToUserName() { - return this.toUserName; - } - - public void setToUserName(String toUserName) { - this.toUserName = toUserName; - } - - public String getFromUserName() { - return this.fromUserName; - } - - public void setFromUserName(String fromUserName) { - this.fromUserName = fromUserName; - } - - public Long getCreateTime() { - return this.createTime; - } - - public void setCreateTime(Long createTime) { - this.createTime = createTime; - } - - public String getMsgType() { - return this.msgType; - } - - public void setMsgType(String msgType) { - this.msgType = msgType; - } - - @SuppressWarnings("unchecked") - public String toXml() { - return XStreamTransformer.toXml((Class) this.getClass(), this); - } - - /** - * 转换成加密的xml格式 - */ - public String toEncryptedXml(WxMpConfigStorage wxMpConfigStorage) { - String plainXml = toXml(); - WxMpCryptUtil pc = new WxMpCryptUtil(wxMpConfigStorage); - return pc.encrypt(plainXml); - } - /** * 获得文本消息builder */ @@ -124,4 +78,50 @@ public static NewsBuilder NEWS() { public static TransferCustomerServiceBuilder TRANSFER_CUSTOMER_SERVICE() { return new TransferCustomerServiceBuilder(); } + + public String getToUserName() { + return this.toUserName; + } + + public void setToUserName(String toUserName) { + this.toUserName = toUserName; + } + + public String getFromUserName() { + return this.fromUserName; + } + + public void setFromUserName(String fromUserName) { + this.fromUserName = fromUserName; + } + + public Long getCreateTime() { + return this.createTime; + } + + public void setCreateTime(Long createTime) { + this.createTime = createTime; + } + + public String getMsgType() { + return this.msgType; + } + + public void setMsgType(String msgType) { + this.msgType = msgType; + } + + @SuppressWarnings("unchecked") + public String toXml() { + return XStreamTransformer.toXml((Class) this.getClass(), this); + } + + /** + * 转换成加密的xml格式 + */ + public String toEncryptedXml(WxMpConfigStorage wxMpConfigStorage) { + String plainXml = toXml(); + WxMpCryptUtil pc = new WxMpCryptUtil(wxMpConfigStorage); + return pc.encrypt(plainXml); + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMusicMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMusicMessage.java index a5b48619a5..c9bd003681 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMusicMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMusicMessage.java @@ -63,23 +63,23 @@ public void setHqMusicUrl(String hqMusicUrl) { public static class Music { @XStreamAlias("Title") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String title; @XStreamAlias("Description") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String description; @XStreamAlias("ThumbMediaId") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String thumbMediaId; @XStreamAlias("MusicUrl") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String musicUrl; @XStreamAlias("HQMusicUrl") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String hqMusicUrl; public String getTitle() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessage.java index 413a6d7c09..1d4fb0c767 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutNewsMessage.java @@ -15,12 +15,10 @@ public class WxMpXmlOutNewsMessage extends WxMpXmlOutMessage { * */ private static final long serialVersionUID = -4604402850905714772L; - - @XStreamAlias("ArticleCount") - protected int articleCount; - @XStreamAlias("Articles") protected final List articles = new ArrayList<>(); + @XStreamAlias("ArticleCount") + protected int articleCount; public WxMpXmlOutNewsMessage() { this.msgType = WxConsts.XML_MSG_NEWS; @@ -44,19 +42,19 @@ public List getArticles() { public static class Item { @XStreamAlias("Title") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String Title; @XStreamAlias("Description") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String Description; @XStreamAlias("PicUrl") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String PicUrl; @XStreamAlias("Url") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String Url; public String getTitle() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutTextMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutTextMessage.java index 0719b1edef..877ed2605c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutTextMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutTextMessage.java @@ -13,7 +13,7 @@ public class WxMpXmlOutTextMessage extends WxMpXmlOutMessage { */ private static final long serialVersionUID = -3972786455288763361L; @XStreamAlias("Content") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String content; public WxMpXmlOutTextMessage() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutTransferKefuMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutTransferKefuMessage.java index b0eece7043..1c5f72d6d9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutTransferKefuMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutTransferKefuMessage.java @@ -28,7 +28,7 @@ public void setTransInfo(TransInfo transInfo) { public static class TransInfo { @XStreamAlias("KfAccount") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String kfAccount; public String getKfAccount() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutVideoMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutVideoMessage.java index 3c042f6d28..adf8849094 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutVideoMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutVideoMessage.java @@ -45,18 +45,18 @@ public void setDescription(String description) { @XStreamAlias("Video") - public static class Video { + public static class Video { @XStreamAlias("MediaId") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String mediaId; @XStreamAlias("Title") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String title; @XStreamAlias("Description") - @XStreamConverter(value=XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataConverter.class) private String description; public String getMediaId() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java index ffb8f0267a..9341fdfbf7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java @@ -13,8 +13,8 @@ * http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口#.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81.E7.BE.A4.E5.8F.91.E7.BB.93.E6.9E.9C * *
    - * @author chanjarster * + * @author chanjarster */ public class WxMpMassSendResult implements Serializable { private static final long serialVersionUID = -4816336807575562818L; @@ -23,6 +23,10 @@ public class WxMpMassSendResult implements Serializable { private String msgId; private String msgDataId; + public static WxMpMassSendResult fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpMassSendResult.class); + } + public String getErrorCode() { return this.errorCode; } @@ -55,10 +59,6 @@ public void setMsgDataId(String msgDataId) { this.msgDataId = msgDataId; } - public static WxMpMassSendResult fromJson(String json) { - return WxMpGsonBuilder.create().fromJson(json, WxMpMassSendResult.class); - } - @Override public String toString() { return ToStringUtils.toSimpleString(this); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java index 6a4f88d804..9862c43cc7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java @@ -9,19 +9,23 @@ * 上传群发用的素材的结果 * 视频和图文消息需要在群发前上传素材 *
    - * @author chanjarster * + * @author chanjarster */ public class WxMpMassUploadResult implements Serializable { /** - * + * */ private static final long serialVersionUID = 6568157943644994029L; private String type; private String mediaId; private long createdAt; + public static WxMpMassUploadResult fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpMassUploadResult.class); + } + public String getType() { return this.type; } @@ -46,10 +50,6 @@ public void setCreatedAt(long createdAt) { this.createdAt = createdAt; } - public static WxMpMassUploadResult fromJson(String json) { - return WxMpGsonBuilder.create().fromJson(json, WxMpMassUploadResult.class); - } - @Override public String toString() { return "WxUploadResult [type=" + this.type + ", media_id=" + this.mediaId + ", created_at=" + this.createdAt + "]"; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java index d38317ce8f..b485710a9f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java @@ -1,13 +1,13 @@ package me.chanjar.weixin.mp.bean.result; -import java.io.Serializable; - import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import java.io.Serializable; + public class WxMpOAuth2AccessToken implements Serializable { /** - * + * */ private static final long serialVersionUID = -1345910558078620805L; @@ -23,6 +23,10 @@ public class WxMpOAuth2AccessToken implements Serializable { private String unionId; + public static WxMpOAuth2AccessToken fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpOAuth2AccessToken.class); + } + public String getRefreshToken() { return this.refreshToken; } @@ -71,19 +75,15 @@ public void setUnionId(String unionId) { this.unionId = unionId; } - public static WxMpOAuth2AccessToken fromJson(String json) { - return WxMpGsonBuilder.create().fromJson(json, WxMpOAuth2AccessToken.class); - } - @Override public String toString() { return "WxMpOAuth2AccessToken{" + - "accessToken='" + this.accessToken + '\'' + - ", expiresTime=" + this.expiresIn + - ", refreshToken='" + this.refreshToken + '\'' + - ", openId='" + this.openId + '\'' + - ", scope='" + this.scope + '\'' + - ", unionId='" + this.unionId + '\'' + - '}'; + "accessToken='" + this.accessToken + '\'' + + ", expiresTime=" + this.expiresIn + + ", refreshToken='" + this.refreshToken + '\'' + + ", openId='" + this.openId + '\'' + + ", scope='" + this.scope + '\'' + + ", unionId='" + this.unionId + '\'' + + '}'; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java index a2917ecc5a..fc7d071332 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java @@ -6,19 +6,23 @@ /** * 换取二维码的Ticket - * + * * @author chanjarster */ public class WxMpQrCodeTicket implements Serializable { - + /** - * + * */ private static final long serialVersionUID = 5777119669111011584L; protected String ticket; protected int expire_seconds = -1; protected String url; + public static WxMpQrCodeTicket fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpQrCodeTicket.class); + } + public String getTicket() { return this.ticket; } @@ -46,10 +50,6 @@ public void setUrl(String url) { this.url = url; } - public static WxMpQrCodeTicket fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpQrCodeTicket.class); - } - @Override public String toString() { return WxMpGsonBuilder.INSTANCE.create().toJson(this); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpSemanticQueryResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpSemanticQueryResult.java index c8a01d3efe..8fd5442c9a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpSemanticQueryResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpSemanticQueryResult.java @@ -6,7 +6,7 @@ /** * 语义理解查询结果对象 - * + *

    * http://mp.weixin.qq.com/wiki/index.php?title=语义理解 * * @author Daniel Qian @@ -14,7 +14,7 @@ public class WxMpSemanticQueryResult implements Serializable { /** - * + * */ private static final long serialVersionUID = 4811088544804441365L; private String query; @@ -24,6 +24,10 @@ public class WxMpSemanticQueryResult implements Serializable { private String answer; private String text; + public static WxMpSemanticQueryResult fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpSemanticQueryResult.class); + } + public String getQuery() { return this.query; } @@ -72,8 +76,4 @@ public void setText(String text) { this.text = text; } - public static WxMpSemanticQueryResult fromJson(String json) { - return WxMpGsonBuilder.create().fromJson(json, WxMpSemanticQueryResult.class); - } - } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java index 7131de5cd4..f2ba9268b6 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java @@ -12,8 +12,8 @@ /** * 微信用户信息 - * @author chanjarster * + * @author chanjarster */ public class WxMpUser implements Serializable { @@ -34,6 +34,18 @@ public class WxMpUser implements Serializable { private Integer groupId; private Long[] tagIds; + public static WxMpUser fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUser.class); + } + + public static List fromJsonList(String json) { + Type collectionType = new TypeToken>() { + }.getType(); + Gson gson = WxMpGsonBuilder.INSTANCE.create(); + JsonObject jsonObject = gson.fromJson(json, JsonObject.class); + return gson.fromJson(jsonObject.get("user_info_list"), collectionType); + } + public Boolean getSubscribe() { return this.subscribe; } @@ -115,7 +127,7 @@ public void setSubscribeTime(Long subscribeTime) { } /** - *只有在将公众号绑定到微信开放平台帐号后,才会出现该字段。 + * 只有在将公众号绑定到微信开放平台帐号后,才会出现该字段。 */ public String getUnionId() { return this.unionId; @@ -158,18 +170,6 @@ public void setTagIds(Long[] tagIds) { this.tagIds = tagIds; } - public static WxMpUser fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUser.class); - } - - public static List fromJsonList(String json) { - Type collectionType = new TypeToken>() { - }.getType(); - Gson gson = WxMpGsonBuilder.INSTANCE.create(); - JsonObject jsonObject = gson.fromJson(json, JsonObject.class); - return gson.fromJson(jsonObject.get("user_info_list"), collectionType); - } - @Override public String toString() { return ToStringUtils.toSimpleString(this); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java index 87ce18cddb..2f630e5ba5 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java @@ -7,8 +7,8 @@ /** * 关注者列表 - * @author chanjarster * + * @author chanjarster */ public class WxMpUserList { @@ -16,37 +16,45 @@ public class WxMpUserList { protected int count = -1; protected List openids = new ArrayList<>(); protected String nextOpenid; + + public static WxMpUserList fromJson(String json) { + return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUserList.class); + } + public long getTotal() { return this.total; } + public void setTotal(long total) { this.total = total; } + public int getCount() { return this.count; } + public void setCount(int count) { this.count = count; } + public List getOpenids() { return this.openids; } + public void setOpenids(List openids) { this.openids = openids; } + public String getNextOpenid() { return this.nextOpenid; } + public void setNextOpenid(String nextOpenid) { this.nextOpenid = nextOpenid; } - public static WxMpUserList fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUserList.class); - } - @Override public String toString() { - return WxMpGsonBuilder.INSTANCE.create().toJson(this); + return WxMpGsonBuilder.INSTANCE.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreBaseInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreBaseInfo.java index 91d52d2ee0..b385fbd0c4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreBaseInfo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreBaseInfo.java @@ -12,200 +12,177 @@ /** * 门店基础信息 + * * @author binarywang(Binary Wang) * Created by Binary Wang on 2016-09-23. */ public class WxMpStoreBaseInfo { - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - - public static WxMpStoreBaseInfo fromJson(String json) { - return WxMpGsonBuilder.create().fromJson(json, WxMpStoreBaseInfo.class); - } - - public String toJson() { - JsonElement base_info = WxMpGsonBuilder.create().toJsonTree(this); - JsonObject jsonObject = new JsonObject(); - jsonObject.add("base_info", base_info); - JsonObject business = new JsonObject(); - business.add("business", jsonObject); - return business.toString(); - } - - public static class WxMpStorePhoto { - /** - * 照片url - */ - @SerializedName("photo_url") - private String photoUrl; - } - /** - * sid - * 商户自己的id,用于后续审核通过收到poi_id 的通知时,做对应关系。请商户自己保证唯一识别性 - */ + * sid + * 商户自己的id,用于后续审核通过收到poi_id 的通知时,做对应关系。请商户自己保证唯一识别性 + */ @SerializedName("sid") private String sid; - /** - * business_name - * 门店名称(仅为商户名,如:国美、麦当劳,不应包含地区、地址、分店名等信息,错误示例:北京国美) - * 不能为空,15个汉字或30个英文字符内 - */ + * business_name + * 门店名称(仅为商户名,如:国美、麦当劳,不应包含地区、地址、分店名等信息,错误示例:北京国美) + * 不能为空,15个汉字或30个英文字符内 + */ @Required @SerializedName("business_name") private String businessName; - /** - * branch_name - * 分店名称(不应包含地区信息,不应与门店名有重复,错误示例:北京王府井店) - * 10个字以内 - */ + * branch_name + * 分店名称(不应包含地区信息,不应与门店名有重复,错误示例:北京王府井店) + * 10个字以内 + */ @Required @SerializedName("branch_name") private String branchName; - /** - * province - * 门店所在的省份(直辖市填城市名,如:北京市) - * 10个字以内 - */ + * province + * 门店所在的省份(直辖市填城市名,如:北京市) + * 10个字以内 + */ @Required @SerializedName("province") private String province; - /** - * city - * 门店所在的城市 - * 10个字以内 - */ + * city + * 门店所在的城市 + * 10个字以内 + */ @Required @SerializedName("city") private String city; - /** - * district - * 门店所在地区 - * 10个字以内 - */ + * district + * 门店所在地区 + * 10个字以内 + */ @Required @SerializedName("district") private String district; - /** - * address - * 门店所在的详细街道地址(不要填写省市信息) - * (东莞等没有“区”行政区划的城市,该字段可不必填写。其余城市必填。) - */ + * address + * 门店所在的详细街道地址(不要填写省市信息) + * (东莞等没有“区”行政区划的城市,该字段可不必填写。其余城市必填。) + */ @Required @SerializedName("address") private String address; - /** - * telephone - * 门店的电话(纯数字,区号、分机号均由“-”隔开) - */ + * telephone + * 门店的电话(纯数字,区号、分机号均由“-”隔开) + */ @Required @SerializedName("telephone") private String telephone; - /** - * categories - * 门店的类型(不同级分类用“,”隔开,如:美食,川菜,火锅。详细分类参见附件:微信门店类目表) - */ + * categories + * 门店的类型(不同级分类用“,”隔开,如:美食,川菜,火锅。详细分类参见附件:微信门店类目表) + */ @Required @SerializedName("categories") private String[] categories; - /** - * offsetType - * 坐标类型,1 为火星坐标(目前只能选1) - */ + * offsetType + * 坐标类型,1 为火星坐标(目前只能选1) + */ @Required @SerializedName("offset_type") private Integer offsetType = 1; - /** - * longitude - * 门店所在地理位置的经度 - */ + * longitude + * 门店所在地理位置的经度 + */ @Required @SerializedName("longitude") private BigDecimal longitude; - /** - * latitude - * 门店所在地理位置的纬度(经纬度均为火星坐标,最好选用腾讯地图标记的坐标) - */ + * latitude + * 门店所在地理位置的纬度(经纬度均为火星坐标,最好选用腾讯地图标记的坐标) + */ @Required @SerializedName("latitude") private BigDecimal latitude; - /** - * photo_list - * 图片列表,url 形式,可以有多张图片,尺寸为 640*340px。必须为上一接口生成的url。 - * 图片内容不允许与门店不相关,不允许为二维码、员工合照(或模特肖像)、营业执照、无门店正门的街景、地图截图、公交地铁站牌、菜单截图等 - */ + * photo_list + * 图片列表,url 形式,可以有多张图片,尺寸为 640*340px。必须为上一接口生成的url。 + * 图片内容不允许与门店不相关,不允许为二维码、员工合照(或模特肖像)、营业执照、无门店正门的街景、地图截图、公交地铁站牌、菜单截图等 + */ @SerializedName("photo_list") private List photos; - /** - * recommend - * 推荐品,餐厅可为推荐菜;酒店为推荐套房;景点为推荐游玩景点等,针对自己行业的推荐内容 - * 200字以内 - */ + * recommend + * 推荐品,餐厅可为推荐菜;酒店为推荐套房;景点为推荐游玩景点等,针对自己行业的推荐内容 + * 200字以内 + */ @SerializedName("recommend") private String recommend; - /** - * special - * 特色服务,如免费wifi,免费停车,送货上门等商户能提供的特色功能或服务 - */ + * special + * 特色服务,如免费wifi,免费停车,送货上门等商户能提供的特色功能或服务 + */ @SerializedName("special") private String special; - /** - * introduction - * 商户简介,主要介绍商户信息等 - * 300字以内 - */ + * introduction + * 商户简介,主要介绍商户信息等 + * 300字以内 + */ @SerializedName("introduction") private String introduction; - /** * open_time - * 营业时间,24 小时制表示,用“-”连接,如 8:00-20:00 - */ + * 营业时间,24 小时制表示,用“-”连接,如 8:00-20:00 + */ @SerializedName("open_time") private String openTime; - /** - * avg_price - * 人均价格,大于0 的整数 - */ + * avg_price + * 人均价格,大于0 的整数 + */ @SerializedName("avg_price") private Integer avgPrice; - /** * 门店是否可用状态。1 表示系统错误、2 表示审核中、3 审核通过、4 审核驳回。当该字段为1、2、4 状态时,poi_id 为空 */ @SerializedName("available_state") private Integer availableState; - /** * 扩展字段是否正在更新中。1 表示扩展字段正在更新中,尚未生效,不允许再次更新; 0 表示扩展字段没有在更新中或更新已生效,可以再次更新 */ @SerializedName("update_status") private Integer updateStatus; - /** * 门店poi id */ @SerializedName("poi_id") private String poiId; + public static WxMpStoreBaseInfo fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpStoreBaseInfo.class); + } + + public static WxMpStoreBaseInfoBuilder builder() { + return new WxMpStoreBaseInfoBuilder(); + } + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public String toJson() { + JsonElement base_info = WxMpGsonBuilder.create().toJsonTree(this); + JsonObject jsonObject = new JsonObject(); + jsonObject.add("base_info", base_info); + JsonObject business = new JsonObject(); + business.add("business", jsonObject); + return business.toString(); + } + public String getSid() { return this.sid; } @@ -374,8 +351,12 @@ public void setPoiId(String poiId) { this.poiId = poiId; } - public static WxMpStoreBaseInfoBuilder builder() { - return new WxMpStoreBaseInfoBuilder(); + public static class WxMpStorePhoto { + /** + * 照片url + */ + @SerializedName("photo_url") + private String photoUrl; } public static class WxMpStoreBaseInfoBuilder { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreInfo.java index 1450bc3cd4..8f0b040191 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreInfo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreInfo.java @@ -4,14 +4,14 @@ import me.chanjar.weixin.common.util.ToStringUtils; public class WxMpStoreInfo { + @SerializedName("base_info") + private WxMpStoreBaseInfo baseInfo; + @Override public String toString() { return ToStringUtils.toSimpleString(this); } - @SerializedName("base_info") - private WxMpStoreBaseInfo baseInfo; - public WxMpStoreBaseInfo getBaseInfo() { return this.baseInfo; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreListResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreListResult.java index f9cc3fbeed..3b2c2fc157 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreListResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/store/WxMpStoreListResult.java @@ -8,44 +8,41 @@ /** * 门店列表结果类 + * * @author binarywang(Binary Wang) * Created by Binary Wang on 2016-09-27. - * */ public class WxMpStoreListResult { - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - - public static WxMpStoreListResult fromJson(String json) { - return WxMpGsonBuilder.create().fromJson(json, WxMpStoreListResult.class); - } - /** * 错误码,0为正常 */ @SerializedName("errcode") private Integer errCode; - /** * 错误信息 */ @SerializedName("errmsg") private String errMsg; - /** * 门店信息列表 */ @SerializedName("business_list") private List businessList; - /** * 门店信息总数 */ @SerializedName("total_count") private Integer totalCount; + public static WxMpStoreListResult fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpStoreListResult.class); + } + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + public Integer getTotalCount() { return this.totalCount; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxTagListUser.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxTagListUser.java index e1307be733..952b764c9c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxTagListUser.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxTagListUser.java @@ -8,42 +8,41 @@ /** * 获取标签下粉丝列表的结果对象 + * * @author binarywang(Binary Wang) * Created by Binary Wang on 2016-09-19. */ public class WxTagListUser { - public static WxTagListUser fromJson(String json) { - return WxMpGsonBuilder.create().fromJson(json,WxTagListUser.class); - } - - public String toJson() { - return WxMpGsonBuilder.create().toJson(this); - } - - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - /** - *"count":2,这次获取的粉丝数量 + * "count":2,这次获取的粉丝数量 */ @SerializedName("count") private Integer count; - /** - *"data" 粉丝列表 + * "data" 粉丝列表 */ @SerializedName("data") private WxTagListUserData data; - /** - *"next_openid" 拉取列表最后一个用户的openid + * "next_openid" 拉取列表最后一个用户的openid */ @SerializedName("next_openid") private String nextOpenid; + public static WxTagListUser fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxTagListUser.class); + } + + public String toJson() { + return WxMpGsonBuilder.create().toJson(this); + } + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + public Integer getCount() { return this.count; } @@ -69,17 +68,17 @@ public void setNextOpenid(String nextOpenid) { } public static class WxTagListUserData { - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - /** * openid 列表 */ @SerializedName("openid") private List openidList; + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + public List getOpenidList() { return this.openidList; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxUserTag.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxUserTag.java index 6554c26153..59d2458fbc 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxUserTag.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxUserTag.java @@ -9,6 +9,7 @@ /** * 用户标签对象 + * * @author binarywang(Binary Wang) * Created by Binary Wang on 2016/9/2. */ @@ -28,6 +29,19 @@ public class WxUserTag { */ private Integer count; + public static WxUserTag fromJson(String json) { + return WxMpGsonBuilder.create().fromJson( + new JsonParser().parse(json).getAsJsonObject().get("tag"), + WxUserTag.class); + } + + public static List listFromJson(String json) { + return WxMpGsonBuilder.create().fromJson( + new JsonParser().parse(json).getAsJsonObject().get("tags"), + new TypeToken>() { + }.getType()); + } + public String getName() { return this.name; } @@ -52,18 +66,6 @@ public void setId(Long id) { this.id = id; } - public static WxUserTag fromJson(String json) { - return WxMpGsonBuilder.create().fromJson( - new JsonParser().parse(json).getAsJsonObject().get("tag"), - WxUserTag.class); - } - - public static List listFromJson(String json) { - return WxMpGsonBuilder.create().fromJson( - new JsonParser().parse(json).getAsJsonObject().get("tags"), - new TypeToken>(){}.getType()); - } - public String toJson() { return WxMpGsonBuilder.create().toJson(this); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplate.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplate.java index 368284f27c..38761f3d4e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplate.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplate.java @@ -18,53 +18,36 @@ public class WxMpTemplate { private static final JsonParser JSON_PARSER = new JsonParser(); - - public static List fromJson(String json) { - return WxMpGsonBuilder.create().fromJson(JSON_PARSER.parse(json).getAsJsonObject().get("template_list"), - new TypeToken>() { - }.getType()); - } - - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - /** * template_id * 模板ID */ @SerializedName("template_id") private String templateId; - /** * title * 模板标题 */ @SerializedName("title") private String title; - /** * primary_industry * 模板所属行业的一级行业 */ @SerializedName("primary_industry") private String primaryIndustry; - /** * deputy_industry * 模板所属行业的二级行业 */ @SerializedName("deputy_industry") private String deputyIndustry; - /** * content * 模板内容 */ @SerializedName("content") private String content; - /** * example * 模板示例 @@ -72,6 +55,17 @@ public String toString() { @SerializedName("example") private String example; + public static List fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(JSON_PARSER.parse(json).getAsJsonObject().get("template_list"), + new TypeToken>() { + }.getType()); + } + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + public String getTemplateId() { return this.templateId; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateIndustry.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateIndustry.java index 6d0db1ab43..63576fc2ce 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateIndustry.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateIndustry.java @@ -22,6 +22,35 @@ public WxMpTemplateIndustry(Industry primaryIndustry, Industry secondIndustry) { this.secondIndustry = secondIndustry; } + public static WxMpTemplateIndustry fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpTemplateIndustry.class); + } + + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + public String toJson() { + return WxMpGsonBuilder.create().toJson(this); + } + + public Industry getPrimaryIndustry() { + return this.primaryIndustry; + } + + public void setPrimaryIndustry(Industry primaryIndustry) { + this.primaryIndustry = primaryIndustry; + } + + public Industry getSecondIndustry() { + return this.secondIndustry; + } + + public void setSecondIndustry(Industry secondIndustry) { + this.secondIndustry = secondIndustry; + } + /** * @author miller * 官方文档中,创建和获取的数据结构不一样。所以采用冗余字段的方式,实现相应的接口 @@ -74,33 +103,4 @@ public void setSecondClass(String secondClass) { this.secondClass = secondClass; } } - - @Override - public String toString() { - return ToStringUtils.toSimpleString(this); - } - - public static WxMpTemplateIndustry fromJson(String json) { - return WxMpGsonBuilder.create().fromJson(json, WxMpTemplateIndustry.class); - } - - public String toJson() { - return WxMpGsonBuilder.create().toJson(this); - } - - public Industry getPrimaryIndustry() { - return this.primaryIndustry; - } - - public void setPrimaryIndustry(Industry primaryIndustry) { - this.primaryIndustry = primaryIndustry; - } - - public Industry getSecondIndustry() { - return this.secondIndustry; - } - - public void setSecondIndustry(Industry secondIndustry) { - this.secondIndustry = secondIndustry; - } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java index f70090ef5b..70034a63b4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java @@ -32,6 +32,7 @@ public class WxMpTemplateMessage implements Serializable { private String url; /** * 模板跳转链接 + * * @see #url */ private MiniProgram miniProgram; @@ -44,6 +45,10 @@ public class WxMpTemplateMessage implements Serializable { public WxMpTemplateMessage() { } + public static WxMpTemplateMessageBuilder builder() { + return new WxMpTemplateMessageBuilder(); + } + public String getToUser() { return this.toUser; } @@ -92,10 +97,6 @@ public String toJson() { return WxMpGsonBuilder.INSTANCE.create().toJson(this); } - public static WxMpTemplateMessageBuilder builder() { - return new WxMpTemplateMessageBuilder(); - } - public static class MiniProgram { private String appid; private String pagePath; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/BaseBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/BaseBuilder.java index 3e40d17836..efd20e0d5b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/BaseBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/BaseBuilder.java @@ -7,7 +7,7 @@ public class BaseBuilder { protected String toUser; @SuppressWarnings("unchecked") - public T toUser(String toUser) { + public T toUser(String toUser) { this.toUser = toUser; return (T) this; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/ImageBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/ImageBuilder.java index 9533f5b351..24d8aabab9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/ImageBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/ImageBuilder.java @@ -8,8 +8,8 @@ *

      * 用法: WxMpKefuMessage m = WxMpKefuMessage.IMAGE().mediaId(...).toUser(...).build();
      * 
    - * @author chanjarster * + * @author chanjarster */ public final class ImageBuilder extends BaseBuilder { private String mediaId; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/MpNewsBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/MpNewsBuilder.java index 615802b31f..b8fac10258 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/MpNewsBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/MpNewsBuilder.java @@ -9,8 +9,8 @@ * 用法: * WxMpKefuMessage m = WxMpKefuMessage.NEWS().mediaId("xxxxx").toUser(...).build(); *
    - * @author Binary Wang * + * @author Binary Wang */ public final class MpNewsBuilder extends BaseBuilder { private String mediaId; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/NewsBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/NewsBuilder.java index 900babb5ba..1626f77e2c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/NewsBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/NewsBuilder.java @@ -12,8 +12,8 @@ * 用法: * WxMpKefuMessage m = WxMpKefuMessage.NEWS().addArticle(article).toUser(...).build(); *
    - * @author chanjarster * + * @author chanjarster */ public final class NewsBuilder extends BaseBuilder { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/TextBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/TextBuilder.java index 9e5f938403..6d9100e94a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/TextBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/TextBuilder.java @@ -8,8 +8,8 @@ *
      * 用法: WxMpKefuMessage m = WxMpKefuMessage.TEXT().content(...).toUser(...).build();
      * 
    - * @author chanjarster * + * @author chanjarster */ public final class TextBuilder extends BaseBuilder { private String content; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/VideoBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/VideoBuilder.java index 13ade68ca5..d7d3772bda 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/VideoBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/VideoBuilder.java @@ -14,8 +14,8 @@ * .toUser(...) * .build(); *
    - * @author chanjarster * + * @author chanjarster */ public final class VideoBuilder extends BaseBuilder { private String mediaId; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/VoiceBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/VoiceBuilder.java index c9cb32b2fa..9fa92f21c8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/VoiceBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/VoiceBuilder.java @@ -8,8 +8,8 @@ *
      * 用法: WxMpKefuMessage m = WxMpKefuMessage.VOICE().mediaId(...).toUser(...).build();
      * 
    - * @author chanjarster * + * @author chanjarster */ public final class VoiceBuilder extends BaseBuilder { private String mediaId; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxCardBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxCardBuilder.java index e600df6cb5..c9eacf0c13 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxCardBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxCardBuilder.java @@ -8,8 +8,8 @@ *
      * 用法: WxMpKefuMessage m = WxMpKefuMessage.WXCARD().cardId(...).toUser(...).build();
      * 
    - * @author mgcnrx11 * + * @author mgcnrx11 */ public final class WxCardBuilder extends BaseBuilder { private String cardId; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/BaseBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/BaseBuilder.java index 60cf675d66..5b199cc52e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/BaseBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/BaseBuilder.java @@ -9,13 +9,13 @@ public abstract class BaseBuilder { protected String fromUserName; @SuppressWarnings("unchecked") - public BuilderType toUser(String touser) { + public BuilderType toUser(String touser) { this.toUserName = touser; return (BuilderType) this; } @SuppressWarnings("unchecked") - public BuilderType fromUser(String fromusername) { + public BuilderType fromUser(String fromusername) { this.fromUserName = fromusername; return (BuilderType) this; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/ImageBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/ImageBuilder.java index 0bf441bf9d..6ce0ce9127 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/ImageBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/ImageBuilder.java @@ -4,6 +4,7 @@ /** * 图片消息builder + * * @author chanjarster */ public final class ImageBuilder extends BaseBuilder { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/NewsBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/NewsBuilder.java index 1936c5f59a..4f9e22e67f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/NewsBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/NewsBuilder.java @@ -7,6 +7,7 @@ /** * 图文消息builder + * * @author chanjarster */ public final class NewsBuilder extends BaseBuilder { @@ -21,7 +22,7 @@ public NewsBuilder addArticle(WxMpXmlOutNewsMessage.Item item) { @Override public WxMpXmlOutNewsMessage build() { WxMpXmlOutNewsMessage m = new WxMpXmlOutNewsMessage(); - for(WxMpXmlOutNewsMessage.Item item : this.articles) { + for (WxMpXmlOutNewsMessage.Item item : this.articles) { m.addArticle(item); } setCommon(m); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TextBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TextBuilder.java index c721a7254c..96674d7426 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TextBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TextBuilder.java @@ -4,8 +4,8 @@ /** * 文本消息builder - * @author chanjarster * + * @author chanjarster */ public final class TextBuilder extends BaseBuilder { private String content; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TransferCustomerServiceBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TransferCustomerServiceBuilder.java index f025c7a816..bc018e8fd3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TransferCustomerServiceBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/TransferCustomerServiceBuilder.java @@ -23,7 +23,7 @@ public TransferCustomerServiceBuilder kfAccount(String kf) { public WxMpXmlOutTransferKefuMessage build() { WxMpXmlOutTransferKefuMessage m = new WxMpXmlOutTransferKefuMessage(); setCommon(m); - if(StringUtils.isNotBlank(this.kfAccount)){ + if (StringUtils.isNotBlank(this.kfAccount)) { WxMpXmlOutTransferKefuMessage.TransInfo transInfo = new WxMpXmlOutTransferKefuMessage.TransInfo(); transInfo.setKfAccount(this.kfAccount); m.setTransInfo(transInfo); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/VideoBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/VideoBuilder.java index d8ac721eb1..e9f7c85b42 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/VideoBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/VideoBuilder.java @@ -4,8 +4,8 @@ /** * 视频消息builder - * @author chanjarster * + * @author chanjarster */ public final class VideoBuilder extends BaseBuilder { @@ -17,10 +17,12 @@ public VideoBuilder title(String title) { this.title = title; return this; } + public VideoBuilder description(String description) { this.description = description; return this; } + public VideoBuilder mediaId(String mediaId) { this.mediaId = mediaId; return this; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/VoiceBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/VoiceBuilder.java index 57d7d31e3e..c9e06bdfaf 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/VoiceBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/VoiceBuilder.java @@ -4,6 +4,7 @@ /** * 语音消息builder + * * @author chanjarster */ public final class VoiceBuilder extends BaseBuilder { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/constant/WxMpEventConstants.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/constant/WxMpEventConstants.java new file mode 100644 index 0000000000..503367cfd7 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/constant/WxMpEventConstants.java @@ -0,0 +1,113 @@ +package me.chanjar.weixin.mp.constant; + +/** + *
    + * 微信公众号事件的相关常量
    + * Created by Binary Wang on 2017-5-10.
    + * @author binarywang(Binary Wang)
    + * 
    + */ +public class WxMpEventConstants { + /** + * 门店审核事件 + */ + public static final String POI_CHECK_NOTIFY = "poi_check_notify"; + + /** + * 接收会员信息事件 + */ + public static final String SUBMIT_MEMBERCARD_USER_INFO = "submit_membercard_user_info"; + + /** + * 微信摇一摇周边>>摇一摇事件通知 + */ + public static final String SHAKEAROUND_USER_SHAKE = "ShakearoundUserShake"; + + + /** + * 卡券相关事件 + */ + public static class Card { + public static final String CARD_PASS_CHECK = "card_pass_check"; + public static final String CARD_NOT_PASS_CHECK = "card_not_pass_check"; + public static final String USER_GET_CARD = "user_get_card"; + public static final String USER_DEL_CARD = "user_del_card"; + public static final String USER_CONSUME_CARD = "user_consume_card"; + public static final String USER_PAY_FROM_PAY_CELL = "user_pay_from_pay_cell"; + public static final String USER_VIEW_CARD = "user_view_card"; + public static final String USER_ENTER_SESSION_FROM_CARD = "user_enter_session_from_card"; + + /** + * 卡券转赠事件 + */ + public static final String USER_GIFTING_CARD = "user_gifting_card"; + + /** + * 库存报警 + */ + public static final String CARD_SKU_REMIND = "card_sku_remind"; + + /** + * 会员卡内容更新事件 + */ + public static final String UPDATE_MEMBER_CARD = "update_member_card"; + + /** + * 券点流水详情事件 + */ + public static final String CARD_PAY_ORDER = "card_pay_order"; + } + + + /** + * 客服相关事件 + */ + public static class CustomerService { + /** + * 客服接入会话 + */ + public static final String KF_CREATE_SESSION = "kf_create_session"; + + /** + * 客服关闭会话 + */ + public static final String KF_CLOSE_SESSION = "kf_close_session"; + + /** + * 客服转接会话 + */ + public static final String KF_SWITCH_SESSION = "kf_switch_session"; + } + + /** + * 微信认证事件 + */ + public static class Qualification { + + /** + * 资质认证成功 + */ + public static final String QUALIFICATION_VERIFY_SUCCESS = "qualification_verify_success"; + /** + * 资质认证失败 + */ + public static final String QUALIFICATION_VERIFY_FAIL = "qualification_verify_fail"; + /** + * 名称认证成功 + */ + public static final String NAMING_VERIFY_SUCCESS = "naming_verify_success"; + /** + * 名称认证失败 + */ + public static final String NAMING_VERIFY_FAIL = "naming_verify_fail"; + /** + * 年审通知 + */ + public static final String ANNUAL_RENEW = "annual_renew"; + /** + * 认证过期失效通知 + */ + public static final String VERIFY_EXPIRED = "verify_expired"; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java index 39165b5c17..d95e8f8f3d 100755 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java @@ -1,41 +1,45 @@ -/** - * 对公众平台发送给公众账号的消息加解密示例代码. - * - * @copyright Copyright (c) 1998-2014 Tencent Inc. - */ - -// ------------------------------------------------------------------------ - -/** - * 针对org.apache.commons.codec.binary.Base64, - * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) - * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi - */ -package me.chanjar.weixin.mp.util.crypto; - -import me.chanjar.weixin.mp.api.WxMpConfigStorage; -import org.apache.commons.codec.binary.Base64; - -public class WxMpCryptUtil extends me.chanjar.weixin.common.util.crypto.WxCryptUtil { - - /** - * 构造函数 - * - * @param wxMpConfigStorage - */ - public WxMpCryptUtil(WxMpConfigStorage wxMpConfigStorage) { - /* - * @param token 公众平台上,开发者设置的token - * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey - * @param appId 公众平台appid - */ - String encodingAesKey = wxMpConfigStorage.getAesKey(); - String token = wxMpConfigStorage.getToken(); - String appId = wxMpConfigStorage.getAppId(); - - this.token = token; - this.appidOrCorpid = appId; - this.aesKey = Base64.decodeBase64(encodingAesKey + "="); - } - -} +/** + * 对公众平台发送给公众账号的消息加解密示例代码. + * + * @copyright Copyright (c) 1998-2014 Tencent Inc. + *

    + * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + */ + +// ------------------------------------------------------------------------ + +/** + * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + */ +package me.chanjar.weixin.mp.util.crypto; + +import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import org.apache.commons.codec.binary.Base64; + +public class WxMpCryptUtil extends me.chanjar.weixin.common.util.crypto.WxCryptUtil { + + /** + * 构造函数 + * + * @param wxMpConfigStorage + */ + public WxMpCryptUtil(WxMpConfigStorage wxMpConfigStorage) { + /* + * @param token 公众平台上,开发者设置的token + * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey + * @param appId 公众平台appid + */ + String encodingAesKey = wxMpConfigStorage.getAesKey(); + String token = wxMpConfigStorage.getToken(); + String appId = wxMpConfigStorage.getAppId(); + + this.token = token; + this.appidOrCorpid = appId; + this.aesKey = Base64.decodeBase64(encodingAesKey + "="); + } + +} 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 9502afe66d..51b7a67764 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialDeleteRequestExecutor.java @@ -1,49 +1,28 @@ package me.chanjar.weixin.mp.util.http; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialDeleteRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialDeleteRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialDeleteRequestExecutor; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; +public abstract class MaterialDeleteRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; -public class MaterialDeleteRequestExecutor implements RequestExecutor { - - - public MaterialDeleteRequestExecutor() { - super(); + public MaterialDeleteRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; } - @Override - public Boolean execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try(CloseableHttpResponse response = httpclient.execute(httpPost)){ - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return true; - } - }finally { - httpPost.releaseConnection(); + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheMaterialDeleteRequestExecutor(requestHttp); + case JODD_HTTP: + return new JoddMaterialDeleteRequestExecutor(requestHttp); + case OK_HTTP: + return new OkhttpMaterialDeleteRequestExecutor(requestHttp); + default: + return null; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java index f61602abdb..24c00fe75a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialNewsInfoRequestExecutor.java @@ -1,52 +1,31 @@ package me.chanjar.weixin.mp.util.http; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; -import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; +import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialNewsInfoRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialNewsInfoRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialNewsInfoRequestExecutor; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; +public abstract class MaterialNewsInfoRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; -public class MaterialNewsInfoRequestExecutor implements RequestExecutor { - - public MaterialNewsInfoRequestExecutor() { - super(); + public MaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; } - @Override - public WxMpMaterialNews execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try(CloseableHttpResponse response = httpclient.execute(httpPost)){ - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); - } - }finally { - httpPost.releaseConnection(); + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheMaterialNewsInfoRequestExecutor(requestHttp); + case JODD_HTTP: + return new JoddMaterialNewsInfoRequestExecutor(requestHttp); + case OK_HTTP: + return new OkhttpMaterialNewsInfoRequestExecutor(requestHttp); + default: + //TODO 需要优化抛出异常 + return null; } - } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java index b06c34a60d..c850d28cf9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java @@ -1,65 +1,30 @@ package me.chanjar.weixin.mp.util.http; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.mp.bean.material.WxMpMaterial; import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.HttpMultipartMode; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.impl.client.CloseableHttpClient; +import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialUploadRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialUploadRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialUploadRequestExecutor; -import java.io.*; -import java.util.Map; +public abstract class MaterialUploadRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; -public class MaterialUploadRequestExecutor implements RequestExecutor { - - @Override - public WxMpMaterialUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, WxMpMaterial material) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig response = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(response); - } - - if (material == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); - } - - File file = material.getFile(); - if (file == null || !file.exists()) { - throw new FileNotFoundException(); - } - - MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); - multipartEntityBuilder - .addBinaryBody("media", file) - .setMode(HttpMultipartMode.RFC6532); - Map form = material.getForm(); - if (material.getForm() != null) { - multipartEntityBuilder.addTextBody("description", WxGsonBuilder.create().toJson(form)); - } - - httpPost.setEntity(multipartEntityBuilder.build()); - httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); + public MaterialUploadRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialUploadResult.fromJson(responseContent); - } - } finally { - httpPost.releaseConnection(); + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheMaterialUploadRequestExecutor(requestHttp); + case JODD_HTTP: + return new JoddMaterialUploadRequestExecutor(requestHttp); + case OK_HTTP: + return new OkhttpMaterialUploadRequestExecutor(requestHttp); + default: + return null; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java index 4eb15e46ac..73948052ff 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVideoInfoRequestExecutor.java @@ -1,50 +1,33 @@ package me.chanjar.weixin.mp.util.http; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -public class MaterialVideoInfoRequestExecutor implements RequestExecutor { - - public MaterialVideoInfoRequestExecutor() { - super(); - } - - @Override - public WxMpMaterialVideoInfoResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try(CloseableHttpResponse response = httpclient.execute(httpPost)){ - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialVideoInfoResult.fromJson(responseContent); - } - }finally { - httpPost.releaseConnection(); - } - } -} + import me.chanjar.weixin.common.util.http.RequestExecutor; + import me.chanjar.weixin.common.util.http.RequestHttp; + + import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; + import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialVideoInfoRequestExecutor; + import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialVideoInfoRequestExecutor; + import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialVideoInfoRequestExecutor; + + +public abstract class MaterialVideoInfoRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; + + public MaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } + + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheMaterialVideoInfoRequestExecutor(requestHttp); + case JODD_HTTP: + return new JoddMaterialVideoInfoRequestExecutor(requestHttp); + case OK_HTTP: + return new OkhttpMaterialVideoInfoRequestExecutor(requestHttp); + default: + return null; + } + } + + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java index ceda65a687..8bf55d03e0 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java @@ -1,67 +1,37 @@ package me.chanjar.weixin.mp.util.http; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; - -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.http.InputStreamResponseHandler; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.util.http.apache.ApacheMaterialVoiceAndImageDownloadRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddMaterialVoiceAndImageDownloadRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMaterialVoiceAndImageDownloadRequestExecutor; -public class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { +import java.io.File; +import java.io.InputStream; +public abstract class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; + protected File tmpDirFile; - public MaterialVoiceAndImageDownloadRequestExecutor() { - super(); - } - public MaterialVoiceAndImageDownloadRequestExecutor(File tmpDirFile) { - super(); + public MaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + this.requestHttp = requestHttp; + this.tmpDirFile = tmpDirFile; } - @Override - public InputStream execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String materialId) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } - Map params = new HashMap<>(); - params.put("media_id", materialId); - httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try (CloseableHttpResponse response = httpclient.execute(httpPost); - InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);){ - // 下载媒体文件出错 - byte[] responseContent = IOUtils.toByteArray(inputStream); - String responseContentString = new String(responseContent, "UTF-8"); - if (responseContentString.length() < 100) { - try { - WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); - if (wxError.getErrorCode() != 0) { - throw new WxErrorException(wxError); - } - } catch (com.google.gson.JsonSyntaxException ex) { - return new ByteArrayInputStream(responseContent); - } - } - return new ByteArrayInputStream(responseContent); - }finally { - httpPost.releaseConnection(); + public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheMaterialVoiceAndImageDownloadRequestExecutor(requestHttp, tmpDirFile); + case JODD_HTTP: + return new JoddMaterialVoiceAndImageDownloadRequestExecutor(requestHttp, tmpDirFile); + case OK_HTTP: + return new OkhttpMaterialVoiceAndImageDownloadRequestExecutor(requestHttp, tmpDirFile); + default: + return null; } } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java index 2129e8a7a9..e187561fc8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MediaImgUploadRequestExecutor.java @@ -1,55 +1,35 @@ package me.chanjar.weixin.mp.util.http; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.HttpMultipartMode; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.impl.client.CloseableHttpClient; +import me.chanjar.weixin.mp.util.http.apache.ApacheMediaImgUploadRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddMediaImgUploadRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpMediaImgUploadRequestExecutor; import java.io.File; -import java.io.IOException; /** * @author miller */ -public class MediaImgUploadRequestExecutor implements RequestExecutor { - @Override - public WxMediaImgUploadResult execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, File data) throws WxErrorException, IOException { - if (data == null) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); - } - - HttpPost httpPost = new HttpPost(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpPost.setConfig(config); - } +public abstract class MediaImgUploadRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; - HttpEntity entity = MultipartEntityBuilder - .create() - .addBinaryBody("media", data) - .setMode(HttpMultipartMode.RFC6532) - .build(); - httpPost.setEntity(entity); - httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); - - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } + public MediaImgUploadRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } - return WxMediaImgUploadResult.fromJson(responseContent); + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheMediaImgUploadRequestExecutor(requestHttp); + case JODD_HTTP: + return new JoddMediaImgUploadRequestExecutor(requestHttp); + case OK_HTTP: + return new OkhttpMediaImgUploadRequestExecutor(requestHttp); + default: + return null; } } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java index 2486ca8090..87c1920cd8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/QrCodeRequestExecutor.java @@ -1,66 +1,38 @@ package me.chanjar.weixin.mp.util.http; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.InputStreamResponseHandler; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; -import org.apache.http.Header; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.entity.ContentType; -import org.apache.http.impl.client.CloseableHttpClient; +import me.chanjar.weixin.mp.util.http.apache.ApacheQrCodeRequestExecutor; +import me.chanjar.weixin.mp.util.http.jodd.JoddQrCodeRequestExecutor; +import me.chanjar.weixin.mp.util.http.okhttp.OkhttpQrCodeRequestExecutor; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URLEncoder; -import java.util.UUID; /** * 获得QrCode图片 请求执行器 - * @author chanjarster * + * @author chanjarster */ -public class QrCodeRequestExecutor implements RequestExecutor { +public abstract class QrCodeRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; - @Override - public File execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, - WxMpQrCodeTicket ticket) throws WxErrorException, IOException { - if (ticket != null) { - if (uri.indexOf('?') == -1) { - uri += '?'; - } - uri += uri.endsWith("?") - ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") - : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); - } - - HttpGet httpGet = new HttpGet(uri); - if (httpProxy != null) { - RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); - httpGet.setConfig(config); - } + public QrCodeRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } - try (CloseableHttpResponse response = httpclient.execute(httpGet); - InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { - Header[] contentTypeHeader = response.getHeaders("Content-Type"); - if (contentTypeHeader != null && contentTypeHeader.length > 0) { - // 出错 - if (ContentType.TEXT_PLAIN.getMimeType().equals(contentTypeHeader[0].getValue())) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - throw new WxErrorException(WxError.fromJson(responseContent)); - } - } - return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); - } finally { - httpGet.releaseConnection(); + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheQrCodeRequestExecutor(requestHttp); + case JODD_HTTP: + return new JoddQrCodeRequestExecutor(requestHttp); + case OK_HTTP: + return new OkhttpQrCodeRequestExecutor(requestHttp); + default: + //TODO 需要优化,最好抛出异常 + return null; } - } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialDeleteRequestExecutor.java new file mode 100644 index 0000000000..be0991d3a2 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialDeleteRequestExecutor.java @@ -0,0 +1,51 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.http.MaterialDeleteRequestExecutor; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMaterialDeleteRequestExecutor extends MaterialDeleteRequestExecutor { + public ApacheMaterialDeleteRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public Boolean execute(String uri, String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return true; + } + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialNewsInfoRequestExecutor.java new file mode 100644 index 0000000000..77d22659ec --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialNewsInfoRequestExecutor.java @@ -0,0 +1,53 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { + public ApacheMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialNews execute(String uri, String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + } + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialUploadRequestExecutor.java new file mode 100644 index 0000000000..474fcb9936 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialUploadRequestExecutor.java @@ -0,0 +1,74 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import me.chanjar.weixin.mp.util.http.MaterialUploadRequestExecutor; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Map; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMaterialUploadRequestExecutor extends MaterialUploadRequestExecutor { + public ApacheMaterialUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig response = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(response); + } + + if (material == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); + } + + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + + MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); + multipartEntityBuilder + .addBinaryBody("media", file) + .setMode(HttpMultipartMode.RFC6532); + Map form = material.getForm(); + if (material.getForm() != null) { + multipartEntityBuilder.addTextBody("description", WxGsonBuilder.create().toJson(form)); + } + + httpPost.setEntity(multipartEntityBuilder.build()); + httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialUploadResult.fromJson(responseContent); + } + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVideoInfoRequestExecutor.java new file mode 100644 index 0000000000..7b81ea863f --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVideoInfoRequestExecutor.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import me.chanjar.weixin.mp.util.http.MaterialVideoInfoRequestExecutor; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMaterialVideoInfoRequestExecutor extends MaterialVideoInfoRequestExecutor { + public ApacheMaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialVideoInfoResult execute(String uri, String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); + } + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVoiceAndImageDownloadRequestExecutor.java new file mode 100644 index 0000000000..87d7b545c6 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMaterialVoiceAndImageDownloadRequestExecutor.java @@ -0,0 +1,63 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.http.MaterialVoiceAndImageDownloadRequestExecutor; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMaterialVoiceAndImageDownloadRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { + public ApacheMaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public InputStream execute(String uri, String materialId) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + // 下载媒体文件出错 + byte[] responseContent = IOUtils.toByteArray(inputStream); + String responseContentString = new String(responseContent, "UTF-8"); + if (responseContentString.length() < 100) { + try { + WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); + if (wxError.getErrorCode() != 0) { + throw new WxErrorException(wxError); + } + } catch (com.google.gson.JsonSyntaxException ex) { + return new ByteArrayInputStream(responseContent); + } + } + return new ByteArrayInputStream(responseContent); + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMediaImgUploadRequestExecutor.java new file mode 100644 index 0000000000..63e278e43c --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheMediaImgUploadRequestExecutor.java @@ -0,0 +1,60 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import me.chanjar.weixin.mp.util.http.MediaImgUploadRequestExecutor; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheMediaImgUploadRequestExecutor extends MediaImgUploadRequestExecutor { + public ApacheMediaImgUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaImgUploadResult execute(String uri, File data) throws WxErrorException, IOException { + if (data == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); + } + + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + HttpEntity entity = MultipartEntityBuilder + .create() + .addBinaryBody("media", data) + .setMode(HttpMultipartMode.RFC6532) + .build(); + httpPost.setEntity(entity); + httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + + return WxMediaImgUploadResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheQrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheQrCodeRequestExecutor.java new file mode 100644 index 0000000000..d7bfe637c5 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/apache/ApacheQrCodeRequestExecutor.java @@ -0,0 +1,65 @@ +package me.chanjar.weixin.mp.util.http.apache; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class ApacheQrCodeRequestExecutor extends QrCodeRequestExecutor { + public ApacheQrCodeRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public File execute(String uri, WxMpQrCodeTicket ticket) throws WxErrorException, IOException { + if (ticket != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") + ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") + : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); + } + + HttpGet httpGet = new HttpGet(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet); + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0) { + // 出错 + if (ContentType.TEXT_PLAIN.getMimeType().equals(contentTypeHeader[0].getValue())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + } + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } finally { + httpGet.releaseConnection(); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialDeleteRequestExecutor.java new file mode 100644 index 0000000000..0344e1cddc --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialDeleteRequestExecutor.java @@ -0,0 +1,43 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.StringPool; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.util.http.MaterialDeleteRequestExecutor; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMaterialDeleteRequestExecutor extends MaterialDeleteRequestExecutor { + public JoddMaterialDeleteRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public Boolean execute(String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return true; + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java new file mode 100644 index 0000000000..a5d5ad1fd3 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialNewsInfoRequestExecutor.java @@ -0,0 +1,46 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.StringPool; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { + public JoddMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialNews execute(String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialUploadRequestExecutor.java new file mode 100644 index 0000000000..ce30323695 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialUploadRequestExecutor.java @@ -0,0 +1,62 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.StringPool; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import me.chanjar.weixin.mp.util.http.MaterialUploadRequestExecutor; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Map; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMaterialUploadRequestExecutor extends MaterialUploadRequestExecutor { + public JoddMaterialUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + if (material == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); + } + + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + request.form("media", file); + Map form = material.getForm(); + if (material.getForm() != null) { + request.form("description", WxGsonBuilder.create().toJson(form)); + } + + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialUploadResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVideoInfoRequestExecutor.java new file mode 100644 index 0000000000..ab4ce6682c --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVideoInfoRequestExecutor.java @@ -0,0 +1,44 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.StringPool; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import me.chanjar.weixin.mp.util.http.MaterialVideoInfoRequestExecutor; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMaterialVideoInfoRequestExecutor extends MaterialVideoInfoRequestExecutor { + public JoddMaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialVideoInfoResult execute(String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java new file mode 100644 index 0000000000..a6317d5a00 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMaterialVoiceAndImageDownloadRequestExecutor.java @@ -0,0 +1,57 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.StringPool; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.http.MaterialVoiceAndImageDownloadRequestExecutor; +import org.apache.commons.io.IOUtils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMaterialVoiceAndImageDownloadRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { + public JoddMaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public InputStream execute(String uri, String materialId) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + request.query("media_id", materialId); + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { + // 下载媒体文件出错 + byte[] responseContent = IOUtils.toByteArray(inputStream); + String responseContentString = new String(responseContent, "UTF-8"); + if (responseContentString.length() < 100) { + try { + WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); + if (wxError.getErrorCode() != 0) { + throw new WxErrorException(wxError); + } + } catch (com.google.gson.JsonSyntaxException ex) { + return new ByteArrayInputStream(responseContent); + } + } + return new ByteArrayInputStream(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMediaImgUploadRequestExecutor.java new file mode 100644 index 0000000000..d0fdbfb856 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddMediaImgUploadRequestExecutor.java @@ -0,0 +1,49 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.StringPool; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import me.chanjar.weixin.mp.util.http.MediaImgUploadRequestExecutor; + +import java.io.File; +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddMediaImgUploadRequestExecutor extends MediaImgUploadRequestExecutor { + public JoddMediaImgUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaImgUploadResult execute(String uri, File data) throws WxErrorException, IOException { + if (data == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("文件对象为空").build()); + } + + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + request.form("media", data); + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + + return WxMediaImgUploadResult.fromJson(responseContent); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddQrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddQrCodeRequestExecutor.java new file mode 100644 index 0000000000..8b15dccf00 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/jodd/JoddQrCodeRequestExecutor.java @@ -0,0 +1,60 @@ +package me.chanjar.weixin.mp.util.http.jodd; + +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.util.MimeTypes; +import jodd.util.StringPool; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class JoddQrCodeRequestExecutor extends QrCodeRequestExecutor { + public JoddQrCodeRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public File execute(String uri, WxMpQrCodeTicket ticket) throws WxErrorException, IOException { + if (ticket != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") + ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") + : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); + } + + HttpRequest request = HttpRequest.get(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + HttpResponse response = request.send(); + response.charset(StringPool.UTF_8); + String contentTypeHeader = response.header("Content-Type"); + if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { + String responseContent = response.bodyText(); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java new file mode 100644 index 0000000000..61d4d18b37 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialDeleteRequestExecutor.java @@ -0,0 +1,53 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import me.chanjar.weixin.mp.util.http.MaterialDeleteRequestExecutor; +import okhttp3.*; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMaterialDeleteRequestExecutor extends MaterialDeleteRequestExecutor { + + + public OkhttpMaterialDeleteRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public Boolean execute(String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).post(requestBody).build(); + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return true; + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java new file mode 100644 index 0000000000..d51fbbe481 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialNewsInfoRequestExecutor.java @@ -0,0 +1,55 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import okhttp3.*; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor { + public OkhttpMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialNews execute(String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).post(requestBody).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java new file mode 100644 index 0000000000..27a9b5bfc7 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialUploadRequestExecutor.java @@ -0,0 +1,72 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import me.chanjar.weixin.mp.util.http.MaterialUploadRequestExecutor; +import okhttp3.*; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Map; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMaterialUploadRequestExecutor extends MaterialUploadRequestExecutor { + public OkhttpMaterialUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + + if (material == null) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法请求,material参数为空").build()); + } + + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); + MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().addFormDataPart("media", null, fileBody); + Map form = material.getForm(); + if (material.getForm() != null) { + bodyBuilder.addFormDataPart("description", WxGsonBuilder.create().toJson(form)); + } + RequestBody body = bodyBuilder.build(); + Request request = new Request.Builder().url(uri).post(body).build(); + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialUploadResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java new file mode 100644 index 0000000000..90c775bac6 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVideoInfoRequestExecutor.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import me.chanjar.weixin.mp.util.http.MaterialVideoInfoRequestExecutor; +import okhttp3.*; + +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMaterialVideoInfoRequestExecutor extends MaterialVideoInfoRequestExecutor { + public OkhttpMaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialVideoInfoResult execute(String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).post(requestBody).build(); + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java new file mode 100644 index 0000000000..336b3a989e --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMaterialVoiceAndImageDownloadRequestExecutor.java @@ -0,0 +1,67 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.http.MaterialVoiceAndImageDownloadRequestExecutor; +import okhttp3.*; +import org.apache.commons.io.IOUtils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMaterialVoiceAndImageDownloadRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { + public OkhttpMaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public InputStream execute(String uri, String materialId) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody requestBody = new FormBody.Builder().add("media_id", materialId).build(); + Request request = new Request.Builder().url(uri).get().post(requestBody).build(); + Response response = client.newCall(request).execute(); + + try (InputStream inputStream = new ByteArrayInputStream(response.body().bytes())) { + + // 下载媒体文件出错 + byte[] responseContent = IOUtils.toByteArray(inputStream); + String responseContentString = new String(responseContent, "UTF-8"); + if (responseContentString.length() < 100) { + try { + WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); + if (wxError.getErrorCode() != 0) { + throw new WxErrorException(wxError); + } + } catch (com.google.gson.JsonSyntaxException ex) { + return new ByteArrayInputStream(responseContent); + } + } + return new ByteArrayInputStream(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java new file mode 100644 index 0000000000..3d8abd394a --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpMediaImgUploadRequestExecutor.java @@ -0,0 +1,56 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import me.chanjar.weixin.mp.util.http.MediaImgUploadRequestExecutor; +import okhttp3.*; + +import java.io.File; +import java.io.IOException; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpMediaImgUploadRequestExecutor extends MediaImgUploadRequestExecutor { + + public OkhttpMediaImgUploadRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaImgUploadResult execute(String uri, File data) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), data); + RequestBody body = new MultipartBody.Builder().addFormDataPart("media", null, fileBody).build(); + Request request = new Request.Builder().url(uri).post(body).build(); + + Response response = client.newCall(request).execute(); + String responseContent = response.body().string(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + + return WxMediaImgUploadResult.fromJson(responseContent); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java new file mode 100644 index 0000000000..f401b021cc --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/okhttp/OkhttpQrCodeRequestExecutor.java @@ -0,0 +1,58 @@ +package me.chanjar.weixin.mp.util.http.okhttp; + +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; + +import okhttp3.*; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +/** + * Created by ecoolper on 2017/5/5. + */ +public class OkhttpQrCodeRequestExecutor extends QrCodeRequestExecutor { + public OkhttpQrCodeRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public File execute(String uri, WxMpQrCodeTicket data) throws WxErrorException, IOException { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(requestHttp.getRequestHttpClient()); + //设置代理 + if (requestHttp.getRequestHttpProxy() != null) { + clientBuilder.proxy(requestHttp.getRequestHttpProxy().getProxy()); + } + //设置授权 + clientBuilder.authenticator(new Authenticator() { + @Override + public Request authenticate(Route route, Response response) throws IOException { + String credential = Credentials.basic(requestHttp.getRequestHttpProxy().getProxyUsername(), requestHttp.getRequestHttpProxy().getProxyPassword()); + return response.request().newBuilder() + .header("Authorization", credential) + .build(); + } + }); + //得到httpClient + OkHttpClient client = clientBuilder.build(); + + Request request = new Request.Builder().url(uri).get().build(); + Response response = client.newCall(request).execute(); + String contentTypeHeader = response.header("Content-Type"); + if ("text/plain".equals(contentTypeHeader)) { + String responseContent = response.body().string(); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + try (InputStream inputStream = new ByteArrayInputStream(response.body().bytes())) { + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpTemplateMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpTemplateMessageGsonAdapter.java index d6e0ff1d65..9668a768a7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpTemplateMessageGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpTemplateMessageGsonAdapter.java @@ -28,7 +28,7 @@ public JsonElement serialize(WxMpTemplateMessage message, Type typeOfSrc, JsonSe messageJson.addProperty("url", message.getUrl()); } - if(message.getMiniProgram() !=null){ + if (message.getMiniProgram() != null) { JsonObject miniProgramJson = new JsonObject(); miniProgramJson.addProperty("appid", message.getMiniProgram().getAppid()); miniProgramJson.addProperty("pagepath", message.getMiniProgram().getPagePath()); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XStreamTransformer.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XStreamTransformer.java index e2c0e0ea00..6835fa47a9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XStreamTransformer.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XStreamTransformer.java @@ -55,13 +55,14 @@ private static void register(Class clz, XStream xStream) { /** * 会自动注册该类及其子类 + * * @param clz 要注册的类 */ private static void registerClass(Class clz) { XStream xstream = XStreamInitializer.getInstance(); xstream.processAnnotations(clz); xstream.processAnnotations(getInnerClasses(clz)); - if(clz.equals(WxMpXmlMessage.class)){ + if (clz.equals(WxMpXmlMessage.class)) { // 操蛋的微信,模板消息推送成功的消息是MsgID,其他消息推送过来是MsgId xstream.aliasField("MsgID", WxMpXmlMessage.class, "msgId"); } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java index da6460878e..fc0f70b776 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java @@ -3,7 +3,7 @@ import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.api.impl.WxMpServiceApacheHttpClientImpl; import org.testng.annotations.*; import java.util.concurrent.ExecutionException; @@ -16,10 +16,10 @@ public class WxMpBusyRetryTest { @DataProvider(name = "getService") public Object[][] getService() { - WxMpService service = new WxMpServiceImpl() { + WxMpService service = new WxMpServiceApacheHttpClientImpl() { @Override - protected synchronized T executeInternal( + public synchronized T executeInternal( RequestExecutor executor, String uri, E data) throws WxErrorException { this.log.info("Executed"); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java index 6bb1e58bff..b175114af1 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java @@ -16,7 +16,9 @@ import java.io.InputStream; import java.util.*; -import static org.junit.Assert.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; /** * 素材管理相关接口的测试 diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java index dac37f266f..8846809001 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java @@ -138,7 +138,7 @@ public void testMenuGet() throws WxErrorException { System.out.println(wxMenu.toJson()); } - @Test(dependsOnMethods = {"testMenuGet"}) + @Test(dependsOnMethods = {"testMenuGet","testMenuCreate"}) public void testMenuDelete() throws WxErrorException { this.wxService.getMenuService().menuDelete(); } @@ -151,18 +151,18 @@ public Object[][] getMenu() { button1.setName("今日歌曲"); button1.setKey("V1001_TODAY_MUSIC"); - WxMenuButton button2 = new WxMenuButton(); - button2.setType(WxConsts.BUTTON_MINIPROGRAM); - button2.setName("小程序"); - button2.setAppId("wx286b93c14bbf93aa"); - button2.setPagePath("pages/lunar/index.html"); - button2.setUrl("http://mp.weixin.qq.com"); +// WxMenuButton button2 = new WxMenuButton(); +// button2.setType(WxConsts.BUTTON_MINIPROGRAM); +// button2.setName("小程序"); +// button2.setAppId("wx286b93c14bbf93aa"); +// button2.setPagePath("pages/lunar/index.html"); +// button2.setUrl("http://mp.weixin.qq.com"); WxMenuButton button3 = new WxMenuButton(); button3.setName("菜单"); menu.getButtons().add(button1); - menu.getButtons().add(button2); +// menu.getButtons().add(button2); menu.getButtons().add(button3); WxMenuButton button31 = new WxMenuButton(); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImplTest.java new file mode 100644 index 0000000000..f608cd19b0 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImplTest.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.test.ApiTestModule; +import me.chanjar.weixin.mp.bean.WxMpShakeInfoResult; +import me.chanjar.weixin.mp.bean.WxMpShakeQuery; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +/** + * 测试摇一摇周边相关的接口 + * + * @author rememberber + */ +@Test(groups = "userAPI") +@Guice(modules = ApiTestModule.class) +public class WxMpShakeServiceImplTest { + @Inject + private WxMpService wxService; + + public void testGetShakeInfo() throws Exception { + WxMpShakeQuery wxMpShakeQuery = new WxMpShakeQuery(); + wxMpShakeQuery.setTicket("b87db7df490e5cbe4f598272f77f46be"); + wxMpShakeQuery.setNeedPoi(1); + WxMpShakeInfoResult wxMpShakeInfoResult = this.wxService.getShakeService().getShakeInfo(wxMpShakeQuery); + + System.out.println(); + } + +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java index e4edca7491..ed5845088b 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImplTest.java @@ -12,7 +12,7 @@ import java.math.BigDecimal; import java.util.List; -import static org.junit.Assert.assertNotNull; +import static org.testng.AssertJUnit.assertNotNull; /** * @author binarywang(Binary Wang) @@ -25,7 +25,7 @@ public class WxMpStoreServiceImplTest { private WxMpService wxMpService; /** - * Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpStoreServiceImpl#add(me.chanjar.weixin.mp.bean.store.WxMpStoreBaseInfo)}. + * Test method for {@link WxMpStoreServiceImpl#add(me.chanjar.weixin.mp.bean.store.WxMpStoreBaseInfo)}. * * @throws WxErrorException */ diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java index 31ad47b6f7..036c534adc 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java @@ -6,7 +6,7 @@ import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.api.impl.WxMpServiceApacheHttpClientImpl; import java.io.IOException; import java.io.InputStream; @@ -19,7 +19,7 @@ public void configure(Binder binder) { try (InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml")) { TestConfigStorage config = this.fromXml(TestConfigStorage.class, is1); config.setAccessTokenLock(new ReentrantLock()); - WxMpService wxService = new WxMpServiceImpl(); + WxMpService wxService = new WxMpServiceApacheHttpClientImpl(); wxService.setWxMpConfigStorage(config); binder.bind(WxMpService.class).toInstance(wxService); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java index 1c1893762f..3e16042d7f 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java @@ -5,7 +5,7 @@ import me.chanjar.weixin.mp.api.WxMpMessageHandler; import me.chanjar.weixin.mp.api.WxMpMessageRouter; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.api.impl.WxMpServiceApacheHttpClientImpl; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; @@ -47,7 +47,7 @@ private static void initWeixin() { .fromXml(is1); wxMpConfigStorage = config; - wxMpService = new WxMpServiceImpl(); + wxMpService = new WxMpServiceApacheHttpClientImpl(); wxMpService.setWxMpConfigStorage(config); WxMpMessageHandler logHandler = new DemoLogHandler(); diff --git a/weixin-java-mp/src/test/resources/logback-test.xml b/weixin-java-mp/src/test/resources/logback-test.xml index ed59510129..8e87c71af2 100644 --- a/weixin-java-mp/src/test/resources/logback-test.xml +++ b/weixin-java-mp/src/test/resources/logback-test.xml @@ -1,16 +1,14 @@ - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %-5level %replace(%caller{1}){'Caller', ''} - %msg%n - + - + diff --git a/weixin-java-mp/src/test/resources/testng.xml b/weixin-java-mp/src/test/resources/testng.xml index a358cf1ceb..d864635569 100644 --- a/weixin-java-mp/src/test/resources/testng.xml +++ b/weixin-java-mp/src/test/resources/testng.xml @@ -1,30 +1,30 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/weixin-java-osgi/pom.xml b/weixin-java-osgi/pom.xml index da00a739c3..91c84d24f3 100644 --- a/weixin-java-osgi/pom.xml +++ b/weixin-java-osgi/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 @@ -119,7 +119,8 @@ ,org.joda.time.format;version="[1.6,2)";resolution:=optional ,org.kxml2.io;resolution:=optional ,org.w3c.dom;resolution:=optional - ,* + ,* + diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index d0d50455f8..4f24b0a9c3 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ weixin-java-parent com.github.binarywang - 2.6.0 + 2.7.0 4.0.0 @@ -19,19 +19,20 @@ weixin-java-common ${project.version} - + + com.github.binarywang + qrcode-utils + org.jodd jodd-http - 3.7 - + - com.github.binarywang - qrcode-utils - 1.0 + ch.qos.logback + logback-classic + test - org.testng testng diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyCoupon.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyCoupon.java index c72ddcb222..c2b4e22e74 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyCoupon.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyCoupon.java @@ -1,6 +1,5 @@ package com.github.binarywang.wxpay.bean; -import com.thoughtworks.xstream.annotations.XStreamAlias; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -12,16 +11,10 @@ * 支付异步通知代金券详细 */ public class WxPayOrderNotifyCoupon implements Serializable { - /** - * @fields serialVersionUID - */ private static final long serialVersionUID = -4165343733538156097L; - @XStreamAlias("coupon_id") private String couponId; - @XStreamAlias("coupon_type") private String couponType; - @XStreamAlias("coupon_fee") private Integer couponFee; public String getCouponId() { diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyResponse.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyResponse.java index 9d960c08e2..e369293195 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyResponse.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyResponse.java @@ -4,7 +4,6 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamConverter; import com.thoughtworks.xstream.annotations.XStreamOmitField; - import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; import me.chanjar.weixin.common.util.xml.XStreamInitializer; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java index 4d5cbbaa31..b44822483b 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java @@ -1,6 +1,7 @@ package com.github.binarywang.wxpay.bean.request; import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.util.SignUtils; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; @@ -28,22 +29,6 @@ * @author binarywang(Binary Wang) */ public abstract class WxPayBaseRequest { - /** - * 检查请求参数内容,包括必填参数以及特殊约束 - */ - protected void checkFields() throws WxErrorException { - //check required fields - BeanUtils.checkRequiredFields(this); - - //check other parameters - this.checkConstraints(); - } - - /** - * 检查约束情况 - */ - protected abstract void checkConstraints(); - /** *

        * 公众账号ID
    @@ -68,7 +53,6 @@ protected void checkFields() throws WxErrorException {
        */
       @XStreamAlias("mch_id")
       protected String mchId;
    -
       /**
        * 
        * 服务商模式下的子商户公众账号ID
    @@ -81,7 +65,6 @@ protected void checkFields() throws WxErrorException {
        */
       @XStreamAlias("sub_appid")
       protected String subAppId;
    -
       /**
        * 
        * 服务商模式下的子商户号
    @@ -128,6 +111,26 @@ public static Integer yuanToFee(String yuan) {
         return new BigDecimal(yuan).setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue();
       }
     
    +  /**
    +   * 检查请求参数内容,包括必填参数以及特殊约束
    +   */
    +  protected void checkFields() throws WxPayException {
    +    //check required fields
    +    try {
    +      BeanUtils.checkRequiredFields(this);
    +    } catch (WxErrorException e) {
    +      throw new WxPayException(e.getError().getErrorMsg());
    +    }
    +
    +    //check other parameters
    +    this.checkConstraints();
    +  }
    +
    +  /**
    +   * 检查约束情况
    +   */
    +  protected abstract void checkConstraints();
    +
       public String getAppid() {
         return this.appid;
       }
    @@ -209,9 +212,10 @@ public String toXML() {
        * 2、补充系统参数,如果未传入则从配置里读取
        * 3、生成签名,并设置进去
        * 
    + * * @param config 支付配置对象,用于读取相应系统配置信息 */ - public void checkAndSign(WxPayConfig config) throws WxErrorException { + public void checkAndSign(WxPayConfig config) throws WxPayException { this.checkFields(); if (StringUtils.isBlank(getAppid())) { @@ -227,7 +231,7 @@ public void checkAndSign(WxPayConfig config) throws WxErrorException { } if (StringUtils.isBlank(getSubMchId())) { - this. setSubMchId(config.getSubMchId()); + this.setSubMchId(config.getSubMchId()); } if (StringUtils.isBlank(getNonceStr())) { diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDefaultRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDefaultRequest.java new file mode 100644 index 0000000000..ff36bfaad7 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDefaultRequest.java @@ -0,0 +1,19 @@ +package com.github.binarywang.wxpay.bean.request; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + *
    + *  支付请求默认对象类
    + *  Created by BinaryWang on 2017/6/18.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxPayDefaultRequest extends WxPayBaseRequest { + @Override + protected void checkConstraints() { + //do nothing + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java index c7fc8c269c..59111da5f8 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java @@ -1,9 +1,9 @@ package com.github.binarywang.wxpay.bean.request; import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.annotation.Required; -import me.chanjar.weixin.common.exception.WxErrorException; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -28,16 +28,6 @@ public class WxPayRefundRequest extends WxPayBaseRequest { private static final String[] REFUND_ACCOUNT = new String[]{"REFUND_SOURCE_RECHARGE_FUNDS", "REFUND_SOURCE_UNSETTLED_FUNDS"}; - - @Override - public void checkAndSign(WxPayConfig config) throws WxErrorException { - if (StringUtils.isBlank(this.getOpUserId())) { - this.setOpUserId(config.getMchId()); - } - - super.checkAndSign(config); - } - /** *
        * 设备号
    @@ -50,7 +40,6 @@ public void checkAndSign(WxPayConfig config) throws WxErrorException {
        */
       @XStreamAlias("device_info")
       private String deviceInfo;
    -
       /**
        * 
        * 微信订单号
    @@ -63,7 +52,6 @@ public void checkAndSign(WxPayConfig config) throws WxErrorException {
        */
       @XStreamAlias("transaction_id")
       private String transactionId;
    -
       /**
        * 
        * 商户订单号
    @@ -76,7 +64,6 @@ public void checkAndSign(WxPayConfig config) throws WxErrorException {
        */
       @XStreamAlias("out_trade_no")
       private String outTradeNo;
    -
       /**
        * 
        * 商户退款单号
    @@ -90,7 +77,6 @@ public void checkAndSign(WxPayConfig config) throws WxErrorException {
       @Required
       @XStreamAlias("out_refund_no")
       private String outRefundNo;
    -
       /**
        * 
        * 订单金额
    @@ -104,7 +90,6 @@ public void checkAndSign(WxPayConfig config) throws WxErrorException {
       @Required
       @XStreamAlias("total_fee")
       private Integer totalFee;
    -
       /**
        * 
        * 退款金额
    @@ -118,7 +103,6 @@ public void checkAndSign(WxPayConfig config) throws WxErrorException {
       @Required
       @XStreamAlias("refund_fee")
       private Integer refundFee;
    -
       /**
        * 
        * 货币种类
    @@ -131,7 +115,6 @@ public void checkAndSign(WxPayConfig config) throws WxErrorException {
        */
       @XStreamAlias("refund_fee_type")
       private String refundFeeType;
    -
       /**
        * 
        * 操作员
    @@ -145,7 +128,6 @@ public void checkAndSign(WxPayConfig config) throws WxErrorException {
       //@Required
       @XStreamAlias("op_user_id")
       private String opUserId;
    -
       /**
        * 
        * 退款资金来源
    @@ -186,6 +168,15 @@ public static Builder newBuilder() {
         return new Builder();
       }
     
    +  @Override
    +  public void checkAndSign(WxPayConfig config) throws WxPayException {
    +    if (StringUtils.isBlank(this.getOpUserId())) {
    +      this.setOpUserId(config.getMchId());
    +    }
    +
    +    super.checkAndSign(config);
    +  }
    +
       public String getDeviceInfo() {
         return this.deviceInfo;
       }
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayShorturlRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayShorturlRequest.java
    index 849d928375..714e07ea43 100644
    --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayShorturlRequest.java
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayShorturlRequest.java
    @@ -24,18 +24,18 @@ public class WxPayShorturlRequest extends WxPayBaseRequest {
       @XStreamAlias("long_url")
       private String longUrl;
     
    -  public String getLongUrl() {
    -    return this.longUrl;
    +  public WxPayShorturlRequest() {
       }
     
    -  public void setLongUrl(String longUrl) {
    +  public WxPayShorturlRequest(String longUrl) {
         this.longUrl = longUrl;
       }
     
    -  public WxPayShorturlRequest() {
    +  public String getLongUrl() {
    +    return this.longUrl;
       }
     
    -  public WxPayShorturlRequest(String longUrl) {
    +  public void setLongUrl(String longUrl) {
         this.longUrl = longUrl;
       }
     
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
    index 48b059d36a..a5560c20df 100644
    --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
    @@ -1,9 +1,9 @@
     package com.github.binarywang.wxpay.bean.request;
     
     import com.github.binarywang.wxpay.config.WxPayConfig;
    +import com.github.binarywang.wxpay.exception.WxPayException;
     import com.thoughtworks.xstream.annotations.XStreamAlias;
     import me.chanjar.weixin.common.annotation.Required;
    -import me.chanjar.weixin.common.exception.WxErrorException;
     import org.apache.commons.lang3.ArrayUtils;
     import org.apache.commons.lang3.StringUtils;
     
    @@ -27,7 +27,7 @@
      */
     @XStreamAlias("xml")
     public class WxPayUnifiedOrderRequest extends WxPayBaseRequest {
    -  private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP"};
    +  private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP","MWEB"};
     
       /**
        * 
    @@ -274,8 +274,33 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest {
       @XStreamAlias("openid")
       private String openid;
     
    -  public static WxUnifiedOrderRequestBuilder builder() {
    -    return new WxUnifiedOrderRequestBuilder();
    +  private WxPayUnifiedOrderRequest(Builder builder) {
    +    setAppid(builder.appid);
    +    setDeviceInfo(builder.deviceInfo);
    +    setMchId(builder.mchId);
    +    setBody(builder.body);
    +    setSubAppId(builder.subAppId);
    +    setSubMchId(builder.subMchId);
    +    setNonceStr(builder.nonceStr);
    +    setSign(builder.sign);
    +    setDetail(builder.detail);
    +    setAttach(builder.attach);
    +    setOutTradeNo(builder.outTradeNo);
    +    setFeeType(builder.feeType);
    +    setTotalFee(builder.totalFee);
    +    setSpbillCreateIp(builder.spbillCreateIp);
    +    setTimeStart(builder.timeStart);
    +    setTimeExpire(builder.timeExpire);
    +    setGoodsTag(builder.goodsTag);
    +    setNotifyURL(builder.notifyURL);
    +    setTradeType(builder.tradeType);
    +    setProductId(builder.productId);
    +    setLimitPay(builder.limitPay);
    +    setOpenid(builder.openid);
    +  }
    +
    +  public static Builder newBuilder() {
    +    return new Builder();
       }
     
       public String getDeviceInfo() {
    @@ -418,10 +443,10 @@ public void setOpenid(String openid) {
     
       @Override
       protected void checkConstraints() {
    -    if (!ArrayUtils.contains(TRADE_TYPES, this.getTradeType())) {
    -      throw new IllegalArgumentException(String.format("trade_type目前必须为%s其中之一,实际值:%s",
    -        Arrays.toString(TRADE_TYPES), this.getTradeType()));
    -    }
    +//    if (!ArrayUtils.contains(TRADE_TYPES, this.getTradeType())) {
    +//      throw new IllegalArgumentException(String.format("trade_type目前必须为%s其中之一,实际值:%s",
    +//        Arrays.toString(TRADE_TYPES), this.getTradeType()));
    +//    }
     
         if ("JSAPI".equals(this.getTradeType()) && this.getOpenid() == null) {
           throw new IllegalArgumentException("当 trade_type是'JSAPI'时未指定openid");
    @@ -433,7 +458,7 @@ protected void checkConstraints() {
       }
     
       @Override
    -  public void checkAndSign(WxPayConfig config) throws WxErrorException {
    +  public void checkAndSign(WxPayConfig config) throws WxPayException {
         if (StringUtils.isBlank(this.getNotifyURL())) {
           this.setNotifyURL(config.getNotifyUrl());
         }
    @@ -445,13 +470,15 @@ public void checkAndSign(WxPayConfig config) throws WxErrorException {
         super.checkAndSign(config);
       }
     
    -  public static class WxUnifiedOrderRequestBuilder {
    +  public static final class Builder {
         private String appid;
    -    private String mchId;
         private String deviceInfo;
    +    private String mchId;
    +    private String body;
    +    private String subAppId;
    +    private String subMchId;
         private String nonceStr;
         private String sign;
    -    private String body;
         private String detail;
         private String attach;
         private String outTradeNo;
    @@ -467,154 +494,121 @@ public static class WxUnifiedOrderRequestBuilder {
         private String limitPay;
         private String openid;
     
    -    public WxUnifiedOrderRequestBuilder appid(String appid) {
    +    private Builder() {
    +    }
    +
    +    public Builder appid(String appid) {
           this.appid = appid;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder mchId(String mchId) {
    +    public Builder deviceInfo(String deviceInfo) {
    +      this.deviceInfo = deviceInfo;
    +      return this;
    +    }
    +
    +    public Builder mchId(String mchId) {
           this.mchId = mchId;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder deviceInfo(String deviceInfo) {
    -      this.deviceInfo = deviceInfo;
    +    public Builder body(String body) {
    +      this.body = body;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder nonceStr(String nonceStr) {
    -      this.nonceStr = nonceStr;
    +    public Builder subAppId(String subAppId) {
    +      this.subAppId = subAppId;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder sign(String sign) {
    -      this.sign = sign;
    +    public Builder subMchId(String subMchId) {
    +      this.subMchId = subMchId;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder body(String body) {
    -      this.body = body;
    +    public Builder nonceStr(String nonceStr) {
    +      this.nonceStr = nonceStr;
    +      return this;
    +    }
    +
    +    public Builder sign(String sign) {
    +      this.sign = sign;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder detail(String detail) {
    +    public Builder detail(String detail) {
           this.detail = detail;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder attach(String attach) {
    +    public Builder attach(String attach) {
           this.attach = attach;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder outTradeNo(String outTradeNo) {
    +    public Builder outTradeNo(String outTradeNo) {
           this.outTradeNo = outTradeNo;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder feeType(String feeType) {
    +    public Builder feeType(String feeType) {
           this.feeType = feeType;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder totalFee(Integer totalFee) {
    +    public Builder totalFee(Integer totalFee) {
           this.totalFee = totalFee;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder spbillCreateIp(String spbillCreateIp) {
    +    public Builder spbillCreateIp(String spbillCreateIp) {
           this.spbillCreateIp = spbillCreateIp;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder timeStart(String timeStart) {
    +    public Builder timeStart(String timeStart) {
           this.timeStart = timeStart;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder timeExpire(String timeExpire) {
    +    public Builder timeExpire(String timeExpire) {
           this.timeExpire = timeExpire;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder goodsTag(String goodsTag) {
    +    public Builder goodsTag(String goodsTag) {
           this.goodsTag = goodsTag;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder notifyURL(String notifyURL) {
    +    public Builder notifyURL(String notifyURL) {
           this.notifyURL = notifyURL;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder tradeType(String tradeType) {
    +    public Builder tradeType(String tradeType) {
           this.tradeType = tradeType;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder productId(String productId) {
    +    public Builder productId(String productId) {
           this.productId = productId;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder limitPay(String limitPay) {
    +    public Builder limitPay(String limitPay) {
           this.limitPay = limitPay;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder openid(String openid) {
    +    public Builder openid(String openid) {
           this.openid = openid;
           return this;
         }
     
    -    public WxUnifiedOrderRequestBuilder from(WxPayUnifiedOrderRequest origin) {
    -      this.appid(origin.appid);
    -      this.mchId(origin.mchId);
    -      this.deviceInfo(origin.deviceInfo);
    -      this.nonceStr(origin.nonceStr);
    -      this.sign(origin.sign);
    -      this.body(origin.body);
    -      this.detail(origin.detail);
    -      this.attach(origin.attach);
    -      this.outTradeNo(origin.outTradeNo);
    -      this.feeType(origin.feeType);
    -      this.totalFee(origin.totalFee);
    -      this.spbillCreateIp(origin.spbillCreateIp);
    -      this.timeStart(origin.timeStart);
    -      this.timeExpire(origin.timeExpire);
    -      this.goodsTag(origin.goodsTag);
    -      this.notifyURL(origin.notifyURL);
    -      this.tradeType(origin.tradeType);
    -      this.productId(origin.productId);
    -      this.limitPay(origin.limitPay);
    -      this.openid(origin.openid);
    -      return this;
    -    }
    -
         public WxPayUnifiedOrderRequest build() {
    -      WxPayUnifiedOrderRequest m = new WxPayUnifiedOrderRequest();
    -      m.appid = this.appid;
    -      m.mchId = this.mchId;
    -      m.deviceInfo = this.deviceInfo;
    -      m.nonceStr = this.nonceStr;
    -      m.sign = this.sign;
    -      m.body = this.body;
    -      m.detail = this.detail;
    -      m.attach = this.attach;
    -      m.outTradeNo = this.outTradeNo;
    -      m.feeType = this.feeType;
    -      m.totalFee = this.totalFee;
    -      m.spbillCreateIp = this.spbillCreateIp;
    -      m.timeStart = this.timeStart;
    -      m.timeExpire = this.timeExpire;
    -      m.goodsTag = this.goodsTag;
    -      m.notifyURL = this.notifyURL;
    -      m.tradeType = this.tradeType;
    -      m.productId = this.productId;
    -      m.limitPay = this.limitPay;
    -      m.openid = this.openid;
    -      return m;
    +      return new WxPayUnifiedOrderRequest(this);
         }
       }
    -
     }
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java
    index 899703c84d..3f07a58199 100644
    --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java
    @@ -1,13 +1,12 @@
     package com.github.binarywang.wxpay.bean.result;
     
    +import com.github.binarywang.wxpay.exception.WxPayException;
     import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
     import com.github.binarywang.wxpay.util.SignUtils;
     import com.google.common.base.Joiner;
     import com.google.common.collect.Maps;
     import com.thoughtworks.xstream.XStream;
     import com.thoughtworks.xstream.annotations.XStreamAlias;
    -import me.chanjar.weixin.common.bean.result.WxError;
    -import me.chanjar.weixin.common.exception.WxErrorException;
     import me.chanjar.weixin.common.util.ToStringUtils;
     import me.chanjar.weixin.common.util.xml.XStreamInitializer;
     import org.apache.commons.lang3.StringUtils;
    @@ -308,12 +307,12 @@ protected Integer getXmlValueAsInt(String... path) {
       /**
        * 校验返回结果签名
        */
    -  public void checkResult(WxPayServiceImpl wxPayService) throws WxErrorException {
    +  public void checkResult(WxPayServiceImpl wxPayService) throws WxPayException {
         //校验返回结果签名
         Map map = toMap();
         if (getSign() != null && !SignUtils.checkSign(map, wxPayService.getConfig().getMchKey())) {
           this.getLogger().debug("校验结果签名失败,参数:{}", map);
    -      throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("参数格式校验错误!").build());
    +      throw new WxPayException("参数格式校验错误!");
         }
     
         //校验结果是否成功
    @@ -336,12 +335,9 @@ public void checkResult(WxPayServiceImpl wxPayService) throws WxErrorException {
             errorMsg.append(",错误详情:").append(getErrCodeDes());
           }
     
    -      WxError error = WxError.newBuilder()
    -        .setErrorCode(-1)
    -        .setErrorMsg(errorMsg.toString())
    -        .build();
    -      this.getLogger().error("\n结果业务代码异常,返回結果:{},\n{}", map, error);
    -      throw new WxErrorException(error);
    +      this.getLogger().error("\n结果业务代码异常,返回結果:{},\n{}",
    +        map, errorMsg.toString());
    +      throw WxPayException.from(this);
         }
       }
     }
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java
    new file mode 100644
    index 0000000000..e469ff4538
    --- /dev/null
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java
    @@ -0,0 +1,305 @@
    +package com.github.binarywang.wxpay.bean.result;
    +
    +import java.io.Serializable;
    +
    +public class WxPayBillBaseResult implements Serializable {
    +  /*
    +   * 交易时间:2017-04-06 01:00:02 公众账号ID: 商户号: 子商户号:0 设备号:WEB 微信订单号: 商户订单号:2017040519091071873216 用户标识: 交易类型:NATIVE
    +   * 交易状态:REFUND 付款银行:CFT 货币种类:CNY 总金额:0.00 企业红包金额:0.00 微信退款单号: 商户退款单号:20170406010000933 退款金额:0.01 企业红包退款金额:0.00
    +   * 退款类型:ORIGINAL 退款状态:SUCCESS 商品名称: 商户数据包: 手续费:0.00000 费率 :0.60%
    +   */
    +  private static final long serialVersionUID = 1L;
    +  /**
    +   * 交易时间
    +   */
    +  private String tradeTime;
    +  /**
    +   * 公众账号ID
    +   */
    +  private String appId;
    +  /**
    +   * 商户号
    +   */
    +  private String mchId;
    +  /**
    +   * 子商户号
    +   */
    +  private String subMchId;
    +  /**
    +   * 设备号
    +   */
    +  private String deviceInfo;
    +  /**
    +   * 微信订单号
    +   */
    +  private String transationId;
    +  /**
    +   * 商户订单号
    +   */
    +  private String outTradeNo;
    +  /**
    +   * 用户标识
    +   */
    +  private String openId;
    +  /**
    +   * 交易类型
    +   */
    +  private String tradeType;
    +  /**
    +   * 交易状态
    +   */
    +  private String tradeState;
    +  /**
    +   * 付款银行
    +   */
    +  private String bankType;
    +  /**
    +   * 货币种类
    +   */
    +  private String feeType;
    +  /**
    +   * 总金额
    +   */
    +  private String totalFee;
    +  /**
    +   * 企业红包金额
    +   */
    +  private String couponFee;
    +  /**
    +   * 微信退款单号
    +   */
    +  private String refundId;
    +  /**
    +   * 商户退款单号
    +   */
    +  private String outRefundNo;
    +  /**
    +   * 退款金额
    +   */
    +  private String settlementRefundFee;
    +  /**
    +   * 企业红包退款金额
    +   */
    +  private String couponRefundFee;
    +  /**
    +   * 退款类型
    +   */
    +  private String refundChannel;
    +  /**
    +   * 退款状态
    +   */
    +  private String refundState;
    +  /**
    +   * 商品名称
    +   */
    +  private String body;
    +  /**
    +   * 商户数据包
    +   */
    +  private String attach;
    +  /**
    +   * 手续费
    +   */
    +  private String poundage;
    +  /**
    +   * 费率
    +   */
    +  private String poundageRate;
    +
    +  public static long getSerialversionuid() {
    +    return serialVersionUID;
    +  }
    +
    +  public String getTradeTime() {
    +    return tradeTime;
    +  }
    +
    +  public void setTradeTime(String tradeTime) {
    +    this.tradeTime = tradeTime;
    +  }
    +
    +  public String getAppId() {
    +    return appId;
    +  }
    +
    +  public void setAppId(String appId) {
    +    this.appId = appId;
    +  }
    +
    +  public String getMchId() {
    +    return mchId;
    +  }
    +
    +  public void setMchId(String mchId) {
    +    this.mchId = mchId;
    +  }
    +
    +  public String getSubMchId() {
    +    return subMchId;
    +  }
    +
    +  public void setSubMchId(String subMchId) {
    +    this.subMchId = subMchId;
    +  }
    +
    +  public String getDeviceInfo() {
    +    return deviceInfo;
    +  }
    +
    +  public void setDeviceInfo(String deviceInfo) {
    +    this.deviceInfo = deviceInfo;
    +  }
    +
    +  public String getTransationId() {
    +    return transationId;
    +  }
    +
    +  public void setTransationId(String transationId) {
    +    this.transationId = transationId;
    +  }
    +
    +  public String getOutTradeNo() {
    +    return outTradeNo;
    +  }
    +
    +  public void setOutTradeNo(String outTradeNo) {
    +    this.outTradeNo = outTradeNo;
    +  }
    +
    +  public String getOpenId() {
    +    return openId;
    +  }
    +
    +  public void setOpenId(String openId) {
    +    this.openId = openId;
    +  }
    +
    +  public String getTradeType() {
    +    return tradeType;
    +  }
    +
    +  public void setTradeType(String tradeType) {
    +    this.tradeType = tradeType;
    +  }
    +
    +  public String getTradeState() {
    +    return tradeState;
    +  }
    +
    +  public void setTradeState(String tradeState) {
    +    this.tradeState = tradeState;
    +  }
    +
    +  public String getBankType() {
    +    return bankType;
    +  }
    +
    +  public void setBankType(String bankType) {
    +    this.bankType = bankType;
    +  }
    +
    +  public String getFeeType() {
    +    return feeType;
    +  }
    +
    +  public void setFeeType(String feeType) {
    +    this.feeType = feeType;
    +  }
    +
    +  public String getTotalFee() {
    +    return totalFee;
    +  }
    +
    +  public void setTotalFee(String totalFee) {
    +    this.totalFee = totalFee;
    +  }
    +
    +  public String getCouponFee() {
    +    return couponFee;
    +  }
    +
    +  public void setCouponFee(String couponFee) {
    +    this.couponFee = couponFee;
    +  }
    +
    +  public String getRefundId() {
    +    return refundId;
    +  }
    +
    +  public void setRefundId(String refundId) {
    +    this.refundId = refundId;
    +  }
    +
    +  public String getOutRefundNo() {
    +    return outRefundNo;
    +  }
    +
    +  public void setOutRefundNo(String outRefundNo) {
    +    this.outRefundNo = outRefundNo;
    +  }
    +
    +  public String getSettlementRefundFee() {
    +    return settlementRefundFee;
    +  }
    +
    +  public void setSettlementRefundFee(String settlementRefundFee) {
    +    this.settlementRefundFee = settlementRefundFee;
    +  }
    +
    +  public String getCouponRefundFee() {
    +    return couponRefundFee;
    +  }
    +
    +  public void setCouponRefundFee(String couponRefundFee) {
    +    this.couponRefundFee = couponRefundFee;
    +  }
    +
    +  public String getRefundChannel() {
    +    return refundChannel;
    +  }
    +
    +  public void setRefundChannel(String refundChannel) {
    +    this.refundChannel = refundChannel;
    +  }
    +
    +  public String getRefundState() {
    +    return refundState;
    +  }
    +
    +  public void setRefundState(String refundState) {
    +    this.refundState = refundState;
    +  }
    +
    +  public String getBody() {
    +    return body;
    +  }
    +
    +  public void setBody(String body) {
    +    this.body = body;
    +  }
    +
    +  public String getAttach() {
    +    return attach;
    +  }
    +
    +  public void setAttach(String attach) {
    +    this.attach = attach;
    +  }
    +
    +  public String getPoundage() {
    +    return poundage;
    +  }
    +
    +  public void setPoundage(String poundage) {
    +    this.poundage = poundage;
    +  }
    +
    +  public String getPoundageRate() {
    +    return poundageRate;
    +  }
    +
    +  public void setPoundageRate(String poundageRate) {
    +    this.poundageRate = poundageRate;
    +  }
    +
    +}
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult.java
    new file mode 100644
    index 0000000000..a7fb25bef2
    --- /dev/null
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillResult.java
    @@ -0,0 +1,83 @@
    +package com.github.binarywang.wxpay.bean.result;
    +
    +import java.io.Serializable;
    +import java.util.List;
    +
    +public class WxPayBillResult implements Serializable {
    +  /**
    +   * 对账返回对象
    +   */
    +  private static final long serialVersionUID = 1L;
    +
    +  private List wxPayBillBaseResultLst;
    +  /**
    +   * 总交易单数
    +   */
    +  private String totalRecord;
    +  /**
    +   * 总交易额
    +   */
    +  private String totalFee;
    +  /**
    +   * 总退款金额
    +   */
    +  private String totalRefundFee;
    +  /**
    +   * 总代金券或立减优惠退款金额
    +   */
    +  private String totalCouponFee;
    +  /**
    +   * 手续费总金额
    +   */
    +  private String totalPoundageFee;
    +
    +  public List getWxPayBillBaseResultLst() {
    +    return wxPayBillBaseResultLst;
    +  }
    +
    +  public void setWxPayBillBaseResultLst(List wxPayBillBaseResultLst) {
    +    this.wxPayBillBaseResultLst = wxPayBillBaseResultLst;
    +  }
    +
    +  public String getTotalRecord() {
    +    return totalRecord;
    +  }
    +
    +  public void setTotalRecord(String totalRecord) {
    +    this.totalRecord = totalRecord;
    +  }
    +
    +  public String getTotalFee() {
    +    return totalFee;
    +  }
    +
    +  public void setTotalFee(String totalFee) {
    +    this.totalFee = totalFee;
    +  }
    +
    +  public String getTotalRefundFee() {
    +    return totalRefundFee;
    +  }
    +
    +  public void setTotalRefundFee(String totalRefundFee) {
    +    this.totalRefundFee = totalRefundFee;
    +  }
    +
    +  public String getTotalCouponFee() {
    +    return totalCouponFee;
    +  }
    +
    +  public void setTotalCouponFee(String totalCouponFee) {
    +    this.totalCouponFee = totalCouponFee;
    +  }
    +
    +  public String getTotalPoundageFee() {
    +    return totalPoundageFee;
    +  }
    +
    +  public void setTotalPoundageFee(String totalPoundageFee) {
    +    this.totalPoundageFee = totalPoundageFee;
    +  }
    +
    +
    +}
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPaySandboxSignKeyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPaySandboxSignKeyResult.java
    new file mode 100644
    index 0000000000..6326f694d3
    --- /dev/null
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPaySandboxSignKeyResult.java
    @@ -0,0 +1,35 @@
    +package com.github.binarywang.wxpay.bean.result;
    +
    +import com.thoughtworks.xstream.annotations.XStreamAlias;
    +
    +/**
    + * 
    + *  Created by BinaryWang on 2017/6/18.
    + * 
    + * + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxPaySandboxSignKeyResult extends WxPayBaseResult { + + /** + *
    +   * 沙箱密钥
    +   * sandbox_signkey
    +   * 否
    +   * 013467007045764
    +   * String(32)
    +   * 返回的沙箱密钥
    +   * 
    + */ + @XStreamAlias("sandbox_signkey") + private String sandboxSignKey; + + public String getSandboxSignKey() { + return sandboxSignKey; + } + + public void setSandboxSignKey(String sandboxSignKey) { + this.sandboxSignKey = sandboxSignKey; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java index f6d82bd184..92c98bda48 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java @@ -25,6 +25,12 @@ public class WxPayUnifiedOrderResult extends WxPayBaseResult { @XStreamAlias("trade_type") private String tradeType; + /** + * mweb_url 支付跳转链接 + */ + @XStreamAlias("mweb_url") + private String mwebUrl; + /** * trade_type为NATIVE时有返回,用于生成二维码,展示给用户进行扫码支付 */ @@ -54,4 +60,12 @@ public String getCodeURL() { public void setCodeURL(String codeURL) { this.codeURL = codeURL; } + + public String getMwebUrl() { + return mwebUrl; + } + + public void setMwebUrl(String mwebUrl) { + this.mwebUrl = mwebUrl; + } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxScanPayNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxScanPayNotifyResult.java index 5bf110688f..cdb94a9b79 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxScanPayNotifyResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxScanPayNotifyResult.java @@ -1,24 +1,24 @@ -package com.github.binarywang.wxpay.bean.result; - -import java.io.Serializable; - -import com.thoughtworks.xstream.annotations.XStreamAlias; - -public class WxScanPayNotifyResult extends WxPayBaseResult implements Serializable{ - private static final long serialVersionUID = 3381324564266118986L; - - /** - * 预支付ID - */ - @XStreamAlias("prepay_id") - private String prepayId; - - public String getPrepayId() { - return prepayId; - } - - public void setPrepayId(String prepayId) { - this.prepayId = prepayId; - } - -} +package com.github.binarywang.wxpay.bean.result; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +import java.io.Serializable; + +public class WxScanPayNotifyResult extends WxPayBaseResult implements Serializable { + private static final long serialVersionUID = 3381324564266118986L; + + /** + * 预支付ID + */ + @XStreamAlias("prepay_id") + private String prepayId; + + public String getPrepayId() { + return prepayId; + } + + public void setPrepayId(String prepayId) { + this.prepayId = prepayId; + } + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java index c03b248264..e6c587a13b 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java @@ -1,10 +1,15 @@ package com.github.binarywang.wxpay.config; +import com.github.binarywang.wxpay.exception.WxPayException; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.http.ssl.SSLContexts; import javax.net.ssl.SSLContext; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; import java.security.KeyStore; /** @@ -22,51 +27,21 @@ public class WxPayConfig { private String tradeType; private SSLContext sslContext; private String keyPath; + private boolean useSandboxEnv = false; - public void setNotifyUrl(String notifyUrl) { - this.notifyUrl = notifyUrl; - } - - public void setTradeType(String tradeType) { - this.tradeType = tradeType; + public String getKeyPath() { + return keyPath; } /** * 设置证书 + * * @param keyPath apiclient_cert.p12的文件的绝对路径 */ public void setKeyPath(String keyPath) { this.keyPath = keyPath; } - public String getKeyPath() { - return keyPath; - } - - public void setAppId(String appId) { - this.appId = appId; - } - - public void setSubAppId(String subAppId) { - this.subAppId = subAppId; - } - - public void setMchId(String mchId) { - this.mchId = mchId; - } - - public void setMchKey(String mchKey) { - this.mchKey = mchKey; - } - - public void setSubMchId(String subMchId) { - this.subMchId = subMchId; - } - - public void setSslContext(SSLContext sslContext) { - this.sslContext = sslContext; - } - /** * 商户号 */ @@ -74,6 +49,10 @@ public String getMchId() { return this.mchId; } + public void setMchId(String mchId) { + this.mchId = mchId; + } + /** * 商户密钥 */ @@ -81,6 +60,10 @@ public String getMchKey() { return this.mchKey; } + public void setMchKey(String mchKey) { + this.mchKey = mchKey; + } + /** * 公众号appid */ @@ -88,6 +71,10 @@ public String getAppId() { return this.appId; } + public void setAppId(String appId) { + this.appId = appId; + } + /** * 服务商模式下的子商户公众账号ID */ @@ -95,6 +82,10 @@ public String getSubAppId() { return this.subAppId; } + public void setSubAppId(String subAppId) { + this.subAppId = subAppId; + } + /** * 服务商模式下的子商户号 */ @@ -102,6 +93,10 @@ public String getSubMchId() { return this.subMchId; } + public void setSubMchId(String subMchId) { + this.subMchId = subMchId; + } + /** * 微信支付异步回掉地址,通知url必须为直接可访问的url,不能携带参数。 */ @@ -109,6 +104,10 @@ public String getNotifyUrl() { return this.notifyUrl; } + public void setNotifyUrl(String notifyUrl) { + this.notifyUrl = notifyUrl; + } + /** * 交易类型 *
    @@ -121,37 +120,69 @@ public String getTradeType() {
         return this.tradeType;
       }
     
    +  public void setTradeType(String tradeType) {
    +    this.tradeType = tradeType;
    +  }
    +
       public SSLContext getSslContext() {
         return this.sslContext;
       }
     
    +  public void setSslContext(SSLContext sslContext) {
    +    this.sslContext = sslContext;
    +  }
    +
       /**
        * 微信支付是否使用仿真测试环境
        * 默认不使用
        */
    -  public boolean useSandboxForWxPay() {
    -    return false;
    +  public boolean useSandbox() {
    +    return this.useSandboxEnv;
       }
     
    -  public SSLContext initSSLContext() {
    -    if (null == mchId) {
    -      throw new IllegalArgumentException("请确保商户号mch_id已设置");
    +  /**
    +   * 设置是否使用沙箱仿真测试环境
    +   */
    +  public void setUseSandboxEnv(boolean useSandboxEnv) {
    +    this.useSandboxEnv = useSandboxEnv;
    +  }
    +
    +  public SSLContext initSSLContext() throws WxPayException {
    +    if (StringUtils.isBlank(mchId)) {
    +      throw new IllegalArgumentException("请确保商户号mchId已设置");
    +    }
    +
    +    if (StringUtils.isBlank(this.keyPath)) {
    +      throw new IllegalArgumentException("请确保证书文件地址keyPath已配置");
         }
     
    -    File file = new File(this.keyPath);
    -    if (!file.exists()) {
    -      throw new RuntimeException("证书文件:【" + file.getPath() + "】不存在!");
    +    InputStream inputStream;
    +    final String prefix = "classpath:";
    +    if (this.keyPath.startsWith(prefix)) {
    +      inputStream = WxPayConfig.class.getResourceAsStream(this.keyPath.replace(prefix, ""));
    +    } else {
    +      try {
    +        File file = new File(this.keyPath);
    +        if (!file.exists()) {
    +          throw new WxPayException("证书文件【" + file.getPath() + "】不存在!");
    +        }
    +
    +        inputStream = new FileInputStream(file);
    +      } catch (IOException e) {
    +        throw new WxPayException("证书文件有问题,请核实!", e);
    +      }
         }
     
         try {
    -      FileInputStream inputStream = new FileInputStream(file);
           KeyStore keystore = KeyStore.getInstance("PKCS12");
           char[] partnerId2charArray = mchId.toCharArray();
           keystore.load(inputStream, partnerId2charArray);
           this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build();
           return this.sslContext;
         } catch (Exception e) {
    -      throw new RuntimeException("证书文件有问题,请核实!", e);
    +      throw new WxPayException("证书文件有问题,请核实!", e);
    +    } finally {
    +      IOUtils.closeQuietly(inputStream);
         }
       }
     }
    diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java
    new file mode 100644
    index 0000000000..948c7a4995
    --- /dev/null
    +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxPayException.java
    @@ -0,0 +1,158 @@
    +package com.github.binarywang.wxpay.exception;
    +
    +import com.github.binarywang.wxpay.bean.result.WxPayBaseResult;
    +import com.google.common.base.Joiner;
    +
    +/**
    + * 
    + * 微信支付异常结果类
    + * Created by Binary Wang on 2017-6-6.
    + * 
    + */ +public class WxPayException extends Exception { + private String customErrorMsg; + /** + * 返回状态码 + */ + private String returnCode; + /** + * 返回信息 + */ + private String returnMsg; + + /** + * 业务结果 + */ + private String resultCode; + + /** + * 错误代码 + */ + private String errCode; + + /** + * 错误代码描述 + */ + private String errCodeDes; + + /** + * 微信支付返回的结果xml字符串 + */ + private String xmlString; + + public WxPayException(String customErrorMsg) { + super(customErrorMsg); + this.customErrorMsg = customErrorMsg; + } + + public WxPayException(String customErrorMsg, Throwable tr) { + super(customErrorMsg, tr); + this.customErrorMsg = customErrorMsg; + } + + private WxPayException(Builder builder) { + super(builder.buildErrorMsg()); + returnCode = builder.returnCode; + returnMsg = builder.returnMsg; + resultCode = builder.resultCode; + errCode = builder.errCode; + errCodeDes = builder.errCodeDes; + xmlString = builder.xmlString; + } + + public static WxPayException from(WxPayBaseResult payBaseResult) { + return WxPayException.newBuilder() + .xmlString(payBaseResult.getXmlString()) + .returnMsg(payBaseResult.getReturnMsg()) + .returnCode(payBaseResult.getReturnCode()) + .resultCode(payBaseResult.getResultCode()) + .errCode(payBaseResult.getErrCode()) + .errCodeDes(payBaseResult.getErrCodeDes()) + .build(); + } + + public String getXmlString() { + return this.xmlString; + } + + public String getReturnCode() { + return this.returnCode; + } + + public String getReturnMsg() { + return this.returnMsg; + } + + public String getResultCode() { + return this.resultCode; + } + + public String getErrCode() { + return this.errCode; + } + + public String getErrCodeDes() { + return this.errCodeDes; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder { + private String returnCode; + private String returnMsg; + private String resultCode; + private String errCode; + private String errCodeDes; + private String xmlString; + + private Builder() { + } + + public Builder returnCode(String returnCode) { + this.returnCode = returnCode; + return this; + } + + public Builder returnMsg(String returnMsg) { + this.returnMsg = returnMsg; + return this; + } + + public Builder resultCode(String resultCode) { + this.resultCode = resultCode; + return this; + } + + public Builder errCode(String errCode) { + this.errCode = errCode; + return this; + } + + public Builder errCodeDes(String errCodeDes) { + this.errCodeDes = errCodeDes; + return this; + } + + public Builder xmlString(String xmlString) { + this.xmlString = xmlString; + return this; + } + + public WxPayException build() { + return new WxPayException(this); + } + + public String buildErrorMsg() { + return Joiner.on(",").skipNulls().join(new String[]{ + returnCode == null ? null : String.format("返回代码:[%s]", returnCode), + returnMsg == null ? null : String.format("返回信息:[%s]", returnMsg), + resultCode == null ? null : String.format("结果代码:[%s]", resultCode), + errCode == null ? null : String.format("错误代码:[%s]", errCode), + errCodeDes == null ? null : String.format("错误详情:[%s]", errCodeDes), + xmlString == null ? null : "微信返回的原始报文:\n" + xmlString, + }); + } + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index e336cd21f3..495ecb5eb9 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -3,7 +3,7 @@ import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.config.WxPayConfig; -import me.chanjar.weixin.common.exception.WxErrorException; +import com.github.binarywang.wxpay.exception.WxPayException; import java.io.File; import java.util.Map; @@ -33,7 +33,7 @@ public interface WxPayService { * @param transactionId 微信订单号 * @param outTradeNo 商户系统内部的订单号,当没提供transactionId时需要传这个。 */ - WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException; + WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxPayException; /** *
    @@ -49,7 +49,7 @@ public interface WxPayService {
        *
        * @param outTradeNo 商户系统内部的订单号
        */
    -  WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorException;
    +  WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException;
     
       /**
        * 统一下单(详见http://com.github.binarywang.wechat.pay.bean.pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
    @@ -58,7 +58,7 @@ public interface WxPayService {
        *
        * @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
        */
    -  WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxErrorException;
    +  WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException;
     
       /**
        * 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数
    @@ -66,7 +66,7 @@ public interface WxPayService {
        *
        * @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
        */
    -  Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException;
    +  Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxPayException;
     
       /**
        * 获取配置
    @@ -88,7 +88,7 @@ public interface WxPayService {
        * @param request 请求对象
        * @return 退款操作结果
        */
    -  WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException;
    +  WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayException;
     
       /**
        * 
    @@ -108,13 +108,13 @@ public interface WxPayService {
        * @return 退款信息
        */
       WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId)
    -    throws WxErrorException;
    +    throws WxPayException;
     
       /**
        * 读取支付结果通知
        * 详见http://com.github.binarywang.wechat.pay.bean.pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
        */
    -  WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException;
    +  WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException;
     
       /**
        * 发送微信红包给个人用户
    @@ -128,7 +128,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
        *
        * @param request 请求对象
        */
    -  WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxErrorException;
    +  WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException;
     
       /**
        * 
    @@ -141,7 +141,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
        *
        * @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890
        */
    -  WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException;
    +  WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException;
     
       /**
        * 
    @@ -155,7 +155,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
        *
        * @param request 请求对象
        */
    -  WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException;
    +  WxEntPayResult entPay(WxEntPayRequest request) throws WxPayException;
     
       /**
        * 
    @@ -167,7 +167,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
        *
        * @param partnerTradeNo 商户订单号
        */
    -  WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException;
    +  WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException;
     
       /**
        * 
    @@ -225,7 +225,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
        * 是否需要证书:不需要
        * 
    */ - void report(WxPayReportRequest request) throws WxErrorException; + void report(WxPayReportRequest request) throws WxPayException; /** *
    @@ -246,7 +246,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
        * @param deviceInfo 设备号	device_info	非必传参数,终端设备号
        * @return 保存到本地的临时文件
        */
    -  File downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException;
    +  WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException;
     
       /**
        * 
    @@ -260,7 +260,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
        * 是否需要证书:不需要。
        * 
    */ - WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxErrorException; + WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException; /** *
    @@ -276,7 +276,7 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
        *  是否需要证书:请求需要双向证书。
        * 
    */ - WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxErrorException; + WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxPayException; /** *
    @@ -288,18 +288,20 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
        *  接口地址:https://api.mch.weixin.qq.com/tools/shorturl
        *  是否需要证书:否
        * 
    + * * @param request 请求对象 */ - String shorturl(WxPayShorturlRequest request) throws WxErrorException; + String shorturl(WxPayShorturlRequest request) throws WxPayException; /** *
        *  转换短链接
        * 
    - * @see WxPayService#shorturl(WxPayShorturlRequest) + * * @param longUrl 需要被压缩的网址 + * @see WxPayService#shorturl(WxPayShorturlRequest) */ - String shorturl(String longUrl) throws WxErrorException; + String shorturl(String longUrl) throws WxPayException; /** *
    @@ -310,18 +312,31 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
        * 接口链接:
        *    https://api.mch.weixin.qq.com/tools/authcodetoopenid
        * 
    + * * @param request 请求对象 * @return openid */ - String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxErrorException; + String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayException; /** *
        * 授权码查询OPENID接口
        * 
    - * @see WxPayService#authcode2Openid(WxPayAuthcode2OpenidRequest) + * * @param authCode 授权码 * @return openid + * @see WxPayService#authcode2Openid(WxPayAuthcode2OpenidRequest) + */ + String authcode2Openid(String authCode) throws WxPayException; + + /** + *
    +   * 获取仿真测试系统的验签密钥
    +   * 请求Url: https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey
    +   * 是否需要证书: 否
    +   * 请求方式: POST
    +   * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_1
    +   * 
    */ - String authcode2Openid(String authCode) throws WxErrorException; + String getSandboxSignKey() throws WxPayException; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java index c26d058392..14c34d0360 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java @@ -4,24 +4,15 @@ import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.util.SignUtils; import com.google.common.collect.Maps; import jodd.http.HttpRequest; import jodd.http.HttpResponse; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; +import jodd.http.net.SSLSocketHttpConnectionProvider; import org.apache.commons.lang3.CharEncoding; import org.apache.commons.lang3.StringUtils; -import org.apache.http.Consts; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.ssl.DefaultHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,6 +20,8 @@ import java.io.File; import java.io.UnsupportedEncodingException; import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Map; /** @@ -53,7 +46,7 @@ public void setConfig(WxPayConfig config) { } private String getPayBaseUrl() { - if (this.getConfig().useSandboxForWxPay()) { + if (this.getConfig().useSandbox()) { return PAY_BASE_URL + "/sandboxnew"; } @@ -61,7 +54,7 @@ private String getPayBaseUrl() { } @Override - public WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException { + public WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/secapi/pay/refund"; @@ -73,7 +66,7 @@ public WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorExcept @Override public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) - throws WxErrorException { + throws WxPayException { WxPayRefundQueryRequest request = new WxPayRefundQueryRequest(); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); request.setTransactionId(StringUtils.trimToNull(transactionId)); @@ -83,7 +76,7 @@ public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeN request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/refundquery"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayRefundQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundQueryResult.class); result.composeRefundRecords(); result.checkResult(this); @@ -91,24 +84,24 @@ public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeN } @Override - public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException { + public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException { try { log.debug("微信支付回调参数详细:{}", xmlData); WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData); log.debug("微信支付回调结果对象:{}", result); result.checkResult(this); return result; - } catch (WxErrorException e) { + } catch (WxPayException e) { log.error(e.getMessage(), e); throw e; } catch (Exception e) { log.error(e.getMessage(), e); - throw new WxErrorException(WxError.newBuilder().setErrorMsg("发生异常" + e.getMessage()).build()); + throw new WxPayException("发生异常," + e.getMessage()); } } @Override - public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxErrorException { + public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendredpack"; @@ -125,7 +118,7 @@ public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throw } @Override - public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException { + public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException { WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest(); request.setMchBillNo(mchBillNo); request.setBillType("MCHT"); @@ -139,16 +132,16 @@ public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorExce } @Override - public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException { + public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxPayException { WxPayOrderQueryRequest request = new WxPayOrderQueryRequest(); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); request.setTransactionId(StringUtils.trimToNull(transactionId)); request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/orderquery"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); if (StringUtils.isBlank(responseContent)) { - throw new WxErrorException(WxError.newBuilder().setErrorMsg("无响应结果").build()); + throw new WxPayException("无响应结果"); } WxPayOrderQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderQueryResult.class); @@ -158,7 +151,7 @@ public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) } @Override - public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorException { + public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException { if (StringUtils.isBlank(outTradeNo)) { throw new IllegalArgumentException("out_trade_no不能为空"); } @@ -168,7 +161,7 @@ public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorExcepti request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/closeorder"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayOrderCloseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderCloseResult.class); result.checkResult(this); @@ -176,18 +169,18 @@ public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorExcepti } @Override - public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxErrorException { + public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/unifiedorder"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayUnifiedOrderResult result = WxPayBaseResult.fromXML(responseContent, WxPayUnifiedOrderResult.class); result.checkResult(this); return result; } @Override - public Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException { + public Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxPayException { WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request); String prepayId = unifiedOrderResult.getPrepayId(); if (StringUtils.isBlank(prepayId)) { @@ -196,22 +189,42 @@ public Map getPayInfo(WxPayUnifiedOrderRequest request) throws W } Map payInfo = new HashMap<>(); - payInfo.put("appId", getConfig().getAppId()); - // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。 - // 但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 - payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); - payInfo.put("nonceStr", String.valueOf(System.currentTimeMillis())); - payInfo.put("package", "prepay_id=" + prepayId); - payInfo.put("signType", "MD5"); if ("NATIVE".equals(request.getTradeType())) { payInfo.put("codeUrl", unifiedOrderResult.getCodeURL()); + } else if ("APP".equals(request.getTradeType())) { + // APP支付绑定的是微信开放平台上的账号,APPID为开放平台上绑定APP后发放的参数 + String appId = getConfig().getAppId(); + Map configMap = new HashMap<>(); + // 此map用于参与调起sdk支付的二次签名,格式全小写,timestamp只能是10位,格式固定,切勿修改 + String partnerid = getConfig().getMchId(); + configMap.put("prepayid", prepayId); + configMap.put("partnerid", partnerid); + configMap.put("package", "Sign=WXPay"); + configMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); + configMap.put("noncestr", String.valueOf(System.currentTimeMillis())); + configMap.put("appid", appId); + // 此map用于客户端与微信服务器交互 + payInfo.put("sign", SignUtils.createSign(configMap, this.getConfig().getMchKey())); + payInfo.put("prepayId", prepayId); + payInfo.put("partnerId", partnerid); + payInfo.put("appId", appId); + payInfo.put("packageValue", "Sign=WXPay"); + payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); + payInfo.put("nonceStr", String.valueOf(System.currentTimeMillis())); + } else if ("JSAPI".equals(request.getTradeType())) { + payInfo.put("appId", unifiedOrderResult.getAppid()); + // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 + payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); + payInfo.put("nonceStr", String.valueOf(System.currentTimeMillis())); + payInfo.put("package", "prepay_id=" + prepayId); + payInfo.put("signType", "MD5"); + payInfo.put("paySign", SignUtils.createSign(payInfo, this.getConfig().getMchKey())); } - payInfo.put("paySign", SignUtils.createSign(payInfo, this.getConfig().getMchKey())); return payInfo; } @Override - public WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException { + public WxEntPayResult entPay(WxEntPayRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/mmpaymkttransfers/promotion/transfers"; @@ -222,7 +235,7 @@ public WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException { } @Override - public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException { + public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException { WxEntPayQueryRequest request = new WxEntPayQueryRequest(); request.setPartnerTradeNo(partnerTradeNo); request.checkAndSign(this.getConfig()); @@ -277,17 +290,17 @@ private byte[] createQrcode(String content, File logoFile, Integer sideLength) { return QrcodeUtils.createQrcode(content, sideLength, logoFile); } - public void report(WxPayReportRequest request) throws WxErrorException { + public void report(WxPayReportRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/payitil/report"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); result.checkResult(this); } @Override - public File downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException { + public WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException { WxPayDownloadBillRequest request = new WxPayDownloadBillRequest(); request.setBillType(billType); request.setBillDate(billDate); @@ -297,28 +310,101 @@ public File downloadBill(String billDate, String billType, String tarType, Strin request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/downloadbill"; - //TODO 返回的内容可能是文件流,也有可能是xml,需要区分对待 - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); + if (responseContent.startsWith("<")) { + WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); + result.checkResult(this); + return null; + } else { + WxPayBillResult wxPayBillResult = billInformationDeal(responseContent); + return wxPayBillResult; + } + } - WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); - result.checkResult(this); - //TODO 待实现,暂时无测试帐号,无法调试 - return null; + private WxPayBillResult billInformationDeal(String responseContent) { + WxPayBillResult wxPayBillResult = new WxPayBillResult(); + + String listStr = ""; + String objStr = ""; + if (responseContent.contains("总交易单数")) { + listStr = responseContent.substring(0, responseContent.indexOf("总交易单数")); + objStr = responseContent.substring(responseContent.indexOf("总交易单数")); + } + + /* + * 交易时间:2017-04-06 01:00:02 公众账号ID: 商户号: 子商户号:0 设备号:WEB 微信订单号: 商户订单号:2017040519091071873216 用户标识: 交易类型:NATIVE + * 交易状态:REFUND 付款银行:CFT 货币种类:CNY 总金额:0.00 企业红包金额:0.00 微信退款单号: 商户退款单号:20170406010000933 退款金额:0.01 企业红包退款金额:0.00 + * 退款类型:ORIGINAL 退款状态:SUCCESS 商品名称: 商户数据包: 手续费:0.00000 费率 :0.60% + */ + + // 参考以上格式进行取值 + + List wxPayBillBaseResultLst = new LinkedList<>(); + String newStr = listStr.replaceAll(",", " "); // 去空格 + String[] tempStr = newStr.split("`"); // 数据分组 + String[] t = tempStr[0].split(" ");// 分组标题 + int j = tempStr.length / t.length; // 计算循环次数 + int k = 1; // 纪录数组下标 + for (int i = 0; i < j; i++) { + WxPayBillBaseResult wxPayBillBaseResult = new WxPayBillBaseResult(); + + wxPayBillBaseResult.setTradeTime(tempStr[k]); + wxPayBillBaseResult.setAppId(tempStr[k + 1]); + wxPayBillBaseResult.setMchId(tempStr[k + 2]); + wxPayBillBaseResult.setSubMchId(tempStr[k + 3]); + wxPayBillBaseResult.setDeviceInfo(tempStr[k + 4]); + wxPayBillBaseResult.setTransationId(tempStr[k + 5]); + wxPayBillBaseResult.setOutTradeNo(tempStr[k + 6]); + wxPayBillBaseResult.setOpenId(tempStr[k + 7]); + wxPayBillBaseResult.setTradeType(tempStr[k + 8]); + wxPayBillBaseResult.setTradeState(tempStr[k + 9]); + wxPayBillBaseResult.setBankType(tempStr[k + 10]); + wxPayBillBaseResult.setFeeType(tempStr[k + 11]); + wxPayBillBaseResult.setTotalFee(tempStr[k + 12]); + wxPayBillBaseResult.setCouponFee(tempStr[k + 13]); + wxPayBillBaseResult.setRefundId(tempStr[k + 14]); + wxPayBillBaseResult.setOutRefundNo(tempStr[k + 15]); + wxPayBillBaseResult.setSettlementRefundFee(tempStr[k + 16]); + wxPayBillBaseResult.setCouponRefundFee(tempStr[k + 17]); + wxPayBillBaseResult.setRefundChannel(tempStr[k + 18]); + wxPayBillBaseResult.setRefundState(tempStr[k + 19]); + wxPayBillBaseResult.setBody(tempStr[k + 20]); + wxPayBillBaseResult.setAttach(tempStr[k + 21]); + wxPayBillBaseResult.setPoundage(tempStr[k + 22]); + wxPayBillBaseResult.setPoundageRate(tempStr[k + 23]); + wxPayBillBaseResultLst.add(wxPayBillBaseResult); + k += t.length; + } + /* + * 总交易单数,总交易额,总退款金额,总代金券或立减优惠退款金额,手续费总金额 `2,`0.02,`0.0,`0.0,`0 + */ + + // 参考以上格式进行取值 + + String totalStr = objStr.replaceAll(",", " "); + String[] totalTempStr = totalStr.split("`"); + wxPayBillResult.setTotalRecord(totalTempStr[1]); + wxPayBillResult.setTotalFee(totalTempStr[2]); + wxPayBillResult.setTotalRefundFee(totalTempStr[3]); + wxPayBillResult.setTotalCouponFee(totalTempStr[4]); + wxPayBillResult.setTotalPoundageFee(totalTempStr[5]); + + return wxPayBillResult; } @Override - public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxErrorException { + public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/micropay"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayMicropayResult result = WxPayBaseResult.fromXML(responseContent, WxPayMicropayResult.class); result.checkResult(this); return result; } @Override - public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxErrorException { + public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/secapi/pay/reverse"; @@ -329,38 +415,56 @@ public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) th } @Override - public String shorturl(WxPayShorturlRequest request) throws WxErrorException { + public String shorturl(WxPayShorturlRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/tools/shorturl"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayShorturlResult result = WxPayBaseResult.fromXML(responseContent, WxPayShorturlResult.class); result.checkResult(this); return result.getShortUrl(); } @Override - public String shorturl(String longUrl) throws WxErrorException { + public String shorturl(String longUrl) throws WxPayException { return this.shorturl(new WxPayShorturlRequest(longUrl)); } @Override - public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxErrorException { + public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/tools/authcodetoopenid"; - String responseContent = this.post(url, request.toXML()); + String responseContent = this.post(url, request.toXML(), true); WxPayAuthcode2OpenidResult result = WxPayBaseResult.fromXML(responseContent, WxPayAuthcode2OpenidResult.class); result.checkResult(this); return result.getOpenid(); } @Override - public String authcode2Openid(String authCode) throws WxErrorException { + public String authcode2Openid(String authCode) throws WxPayException { return this.authcode2Openid(new WxPayAuthcode2OpenidRequest(authCode)); } - private String post(String url, String xmlParam) { + @Override + public String getSandboxSignKey() throws WxPayException { + WxPayDefaultRequest request = new WxPayDefaultRequest(); + request.checkAndSign(this.getConfig()); + + String url = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey"; + String responseContent = this.post(url, request.toXML(), false); + WxPaySandboxSignKeyResult result = WxPayBaseResult.fromXML(responseContent, WxPaySandboxSignKeyResult.class); + result.checkResult(this); + return result.getSandboxSignKey(); + } + + /** + * @param url 请求地址 + * @param xmlParam 请求字符串 + * @param needTransferEncoding 是否需要对结果进行重编码 + * @return 返回请求结果 + */ + private String post(String url, String xmlParam, boolean needTransferEncoding) { String requestString = xmlParam; try { requestString = new String(xmlParam.getBytes(CharEncoding.UTF_8), CharEncoding.ISO_8859_1); @@ -370,47 +474,51 @@ private String post(String url, String xmlParam) { } HttpRequest request = HttpRequest.post(url).body(requestString); - HttpResponse response = request.send(); - String responseString = null; - try { - responseString = new String(response.bodyText().getBytes(CharEncoding.ISO_8859_1), CharEncoding.UTF_8); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } + String responseString = this.getResponseString(request.send()); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, xmlParam, responseString); + this.log.info("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", url, xmlParam, responseString); return responseString; } /** - * 由于暂时未找到使用jodd-http实现证书配置的办法,故而暂时使用httpclient + * ecoolper(20170418),修改为jodd-http方式 */ - private String postWithKey(String url, String requestStr) throws WxErrorException { + private String postWithKey(String url, String requestStr) throws WxPayException { try { SSLContext sslContext = this.getConfig().getSslContext(); if (null == sslContext) { sslContext = this.getConfig().initSSLContext(); } - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, - new String[]{"TLSv1"}, null, new DefaultHostnameVerifier()); + HttpRequest request = HttpRequest + .post(url) + .withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext)) + .bodyText(requestStr); - HttpPost httpPost = new HttpPost(url); + String responseString = this.getResponseString(request.send()); - try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build()) { - httpPost.setEntity(new StringEntity(new String(requestStr.getBytes(CharEncoding.UTF_8), CharEncoding.ISO_8859_1))); - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { - String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8); - this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result); - return result; - } - } finally { - httpPost.releaseConnection(); - } + this.log.info("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", url, requestStr, responseString); + return responseString; } catch (Exception e) { - this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", url, requestStr, e.getMessage()); - throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg(e.getMessage()).build(), e); + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", url, requestStr, e.getMessage()); + throw new WxPayException(e.getMessage()); } } + private String getResponseString(HttpResponse response) { + this.log.debug("【微信服务器响应头信息】:\n{}", response.toString(false)); + + String responseString = response.bodyText(); + + if (StringUtils.isBlank(response.charset())) { + try { + responseString = new String(response.bodyText().getBytes(CharEncoding.ISO_8859_1), CharEncoding.UTF_8); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + return responseString; + } + + } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java index 2a6030f399..33e18c49f3 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java @@ -36,7 +36,7 @@ public static String createSign(Object xmlBean, String signKey) { * @return 签名字符串 */ public static String createSign(Map params, String signKey) { -// if (this.getConfig().useSandboxForWxPay()) { +// if (this.getConfig().useSandbox()) { // //使用仿真测试环境 // //TODO 目前测试发现,以下两行代码都会出问题,所以暂不建议使用仿真测试环境 // signKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456"; @@ -49,11 +49,11 @@ public static String createSign(Map params, String signKey) { for (String key : sortedMap.keySet()) { String value = params.get(key); if (StringUtils.isNotEmpty(value) && !"sign".equals(key) && !"key".equals(key)) { - toSign.append(key + "=" + value + "&"); + toSign.append(key).append("=").append(value).append("&"); } } - toSign.append("key=" + signKey); + toSign.append("key=").append(signKey); return DigestUtils.md5Hex(toSign.toString()).toUpperCase(); } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResultTest.java new file mode 100644 index 0000000000..389b374d9e --- /dev/null +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResultTest.java @@ -0,0 +1,58 @@ +package com.github.binarywang.wxpay.bean.result; + +import org.testng.*; +import org.testng.annotations.*; + +/** + *
    + * Created by Binary Wang on 2017-6-15.
    + * @author Binary Wang
    + * 
    + */ +public class WxPayOrderNotifyResultTest { + @Test + public void testFromXML() throws Exception { + String xmlString = "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " 2\n" + + " \n" + + " 10000\n" + + " 100\n" + + " \n" + + " 10001\n" + + " 200\n" + + ""; + + WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlString); + + Assert.assertEquals(result.getCouponCount().intValue(), 2); + Assert.assertNotNull(result.getCouponList()); + Assert.assertEquals(result.getCouponList().size(), 2); + + Assert.assertEquals(result.getCouponList().get(0).getCouponFee().intValue(), 100); + Assert.assertEquals(result.getCouponList().get(1).getCouponFee().intValue(), 200); + + Assert.assertEquals(result.getCouponList().get(0).getCouponType(), "CASH"); + Assert.assertEquals(result.getCouponList().get(1).getCouponType(), "NO_CASH"); + + Assert.assertEquals(result.getCouponList().get(0).getCouponId(), "10000"); + Assert.assertEquals(result.getCouponList().get(1).getCouponId(), "10001"); + } + +} diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java new file mode 100644 index 0000000000..83bcbf2c17 --- /dev/null +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java @@ -0,0 +1,24 @@ +package com.github.binarywang.wxpay.config; + +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +/** + *
    + *  Created by BinaryWang on 2017/6/18.
    + * 
    + * + * @author Binary Wang + */ +public class WxPayConfigTest { + private WxPayConfig payConfig = new WxPayConfig(); + + @Test + public void testInitSSLContext() throws Exception { + payConfig.setMchId("123"); + payConfig.setKeyPath("classpath:/abc.p12"); + payConfig.initSSLContext(); + } + +} diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java index 93b0b8b552..995aa8275b 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImplTest.java @@ -3,16 +3,15 @@ import com.github.binarywang.utils.qrcode.QrcodeUtils; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; +import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.testbase.ApiTestModule; import com.github.binarywang.wxpay.testbase.XmlWxPayConfig; import com.google.inject.Inject; -import me.chanjar.weixin.common.exception.WxErrorException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.*; -import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; @@ -35,7 +34,7 @@ public class WxPayServiceImplTest { @Test public void testGetPayInfo() throws Exception { - Map payInfo = this.payService.getPayInfo(WxPayUnifiedOrderRequest.builder() + Map payInfo = this.payService.getPayInfo(WxPayUnifiedOrderRequest.newBuilder() .body("我去") .totalFee(1) .spbillCreateIp("111111") @@ -49,8 +48,9 @@ public void testGetPayInfo() throws Exception { @Test public void testDownloadBill() throws Exception { - File file = this.payService.downloadBill("20170101", "ALL", "GZIP", "1111111"); - assertNotNull(file); + WxPayBillResult wxPayBillResult = this.payService.downloadBill("20170101", "ALL", "GZIP", "1111111"); + //前一天没有账单记录返回null + assertNotNull(wxPayBillResult); //必填字段为空时,抛出异常 this.payService.downloadBill("", "", "", null); } @@ -133,9 +133,9 @@ public void testQueryRedpack() throws Exception { * Test method for {@link WxPayService#unifiedOrder(WxPayUnifiedOrderRequest)}. */ @Test - public void testUnifiedOrder() throws WxErrorException { + public void testUnifiedOrder() throws WxPayException { WxPayUnifiedOrderResult result = this.payService - .unifiedOrder(WxPayUnifiedOrderRequest.builder() + .unifiedOrder(WxPayUnifiedOrderRequest.newBuilder() .body("我去") .totalFee(1) .spbillCreateIp("111111") @@ -151,7 +151,7 @@ public void testUnifiedOrder() throws WxErrorException { * Test method for {@link WxPayService#queryOrder(java.lang.String, java.lang.String)} . */ @Test - public void testQueryOrder() throws WxErrorException { + public void testQueryOrder() throws WxPayException { this.logger.info(this.payService.queryOrder("11212121", null).toString()); this.logger.info(this.payService.queryOrder(null, "11111").toString()); } @@ -160,7 +160,7 @@ public void testQueryOrder() throws WxErrorException { * Test method for {@link WxPayService#closeOrder(java.lang.String)} . */ @Test - public void testCloseOrder() throws WxErrorException { + public void testCloseOrder() throws WxPayException { this.logger.info(this.payService.closeOrder("11212121").toString()); } @@ -168,7 +168,7 @@ public void testCloseOrder() throws WxErrorException { * Test method for {@link WxPayService#entPay(WxEntPayRequest)}. */ @Test - public void testEntPay() throws WxErrorException { + public void testEntPay() throws WxPayException { WxEntPayRequest request = new WxEntPayRequest(); this.logger.info(this.payService.entPay(request).toString()); } @@ -177,7 +177,7 @@ public void testEntPay() throws WxErrorException { * Test method for {@link WxPayService#queryEntPay(java.lang.String)}. */ @Test - public void testQueryEntPay() throws WxErrorException { + public void testQueryEntPay() throws WxPayException { this.logger.info(this.payService.queryEntPay("11212121").toString()); } @@ -264,4 +264,11 @@ public void testAuthcode2Openid() throws Exception { this.logger.info(result); } + @Test + public void testGetSandboxSignKey() throws Exception { + final String signKey = this.payService.getSandboxSignKey(); + assertNotNull(signKey); + this.logger.info(signKey); + } + } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/XmlWxPayConfig.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/XmlWxPayConfig.java index a10f36f3bc..d029590ad3 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/XmlWxPayConfig.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/XmlWxPayConfig.java @@ -2,13 +2,6 @@ import com.github.binarywang.wxpay.config.WxPayConfig; import com.thoughtworks.xstream.annotations.XStreamAlias; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.http.ssl.SSLContexts; - -import javax.net.ssl.SSLContext; -import java.io.File; -import java.io.FileInputStream; -import java.security.KeyStore; @XStreamAlias("xml") public class XmlWxPayConfig extends WxPayConfig { @@ -23,9 +16,9 @@ public void setOpenid(String openid) { } @Override - public boolean useSandboxForWxPay() { + public boolean useSandbox() { //沙箱环境不成熟,有问题无法使用,暂时屏蔽掉 - // return true; +// return true; return false; } } diff --git a/weixin-java-pay/src/test/resources/.gitignore b/weixin-java-pay/src/test/resources/.gitignore new file mode 100644 index 0000000000..edd25bc776 --- /dev/null +++ b/weixin-java-pay/src/test/resources/.gitignore @@ -0,0 +1 @@ +*.p12