diff --git a/.gitignore b/.gitignore index f50d5eb3..d97b22b7 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ sonar-project.properties !/.mvn/wrapper/maven-wrapper.jar *.versionsBackup + +# STS +.factorypath diff --git a/contribution.md b/contribution.md index 093614d3..abf1791f 100644 --- a/contribution.md +++ b/contribution.md @@ -8,10 +8,10 @@ - (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。 ### PR方式贡献代码步骤 -* 在 GitHub 上 `fork` 到自己的仓库,如 `my_user/weixin-java-tools`,然后 `clone` 到本地,并设置用户信息。 +* 在 GitHub 上 `fork` 到自己的仓库,如 `my_user/WxJava`,然后 `clone` 到本地,并设置用户信息。 ```bash -$ git clone git@github.com:my_user/weixin-java-tools.git +$ git clone git@github.com:my_user/WxJava.git $ cd weixin-java-tools $ git config user.name "yourname" $ git config user.email "your email" @@ -27,7 +27,7 @@ $ git push * 定期使用项目仓库内容更新自己仓库内容。 ```bash -$ git remote add upstream https://github.com/wechat-group/weixin-java-tools +$ git remote add upstream https://github.com/Wechat-Group/WxJava $ git fetch upstream $ git checkout develop $ git rebase upstream/develop diff --git a/pom.xml b/pom.xml index 64eaac2d..961b9eab 100644 --- a/pom.xml +++ b/pom.xml @@ -5,12 +5,12 @@ xmlns="http://maven.apache.org/POM/4.0.0"> 4.0.0 com.github.binarywang - weixin-java-parent - 3.2.0 + wx-java + 3.3.0 pom - Weixin Java Tools - Parent + WxJava - Weixin/Wechat Java SDK 微信开发Java SDK - https://github.com/wechat-group/weixin-java-tools + https://github.com/Wechat-Group/WxJava @@ -85,6 +85,11 @@ 007gzs@gmail.com https://github.com/007gzs + + Howard Liu + liuxinghao1988@gmail.com + https://github.com/howardliu-cn + @@ -166,7 +171,7 @@ com.thoughtworks.xstream xstream - 1.4.9 + 1.4.10 diff --git a/quality-checks/google_checks.xml b/quality-checks/google_checks.xml index b1b2a46f..0b331f4e 100644 --- a/quality-checks/google_checks.xml +++ b/quality-checks/google_checks.xml @@ -140,14 +140,6 @@ - - - - - - - diff --git a/readme.md b/readme.md index b77918d9..4a8261c2 100644 --- a/readme.md +++ b/readme.md @@ -3,9 +3,9 @@ [![码云Gitee](https://gitee.com/binary/weixin-java-tools/badge/star.svg?theme=blue)](https://gitee.com/binary/weixin-java-tools) [![Github](http://github-svg-buttons.herokuapp.com/star.svg?user=Wechat-Group&repo=WxJava&style=flat&background=1081C1)](https://github.com/Wechat-Group/WxJava) [![GitHub release](https://img.shields.io/github/release/Wechat-Group/WxJava.svg)](https://github.com/Wechat-Group/WxJava/releases) -[![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/weixin-java-parent.svg)](http://mvnrepository.com/artifact/com.github.binarywang/weixin-java-parent) +[![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](http://mvnrepository.com/artifact/com.github.binarywang/wx-java) [![Build Status](https://travis-ci.org/Wechat-Group/WxJava.svg?branch=develop)](https://travis-ci.org/Wechat-Group/WxJava) -[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=weixin-java-tools) +[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=WxJava-weixin-java-tools) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) --------------------------------- @@ -13,8 +13,7 @@ --------------------------------- ### 重要信息 - -1. **2018-09-24 发布 [【3.2.0正式版】](https://github.com/Wechat-Group/WxJava/releases)**! +1. **2018-12-23 项目更名为WxJava,并发布 [【3.3.0正式版】](https://github.com/Wechat-Group/WxJava/releases)**! 1. 新手重要提示:本项目仅是一个SDK开发工具包,未提供Web实现,建议使用maven或gradle引用本项目即可使用本SDK提供的各种功能,详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码;另外微信开发新手请务必阅读[【开发文档 Wiki 首页】](https://github.com/Wechat-Group/WxJava/wiki)的常见问题部分,可以少走很多弯路,节省不少时间。 --------------------------------- @@ -152,3 +151,4 @@ 1. [qsjia (QSJia)](http://github.com/qsjia) 1. [webcreazy (webcreazy)](http://github.com/webcreazy) 1. [cwivan (鱼丸Cwivan)](http://github.com/cwivan) +1. [howardliu-cn (看山)](https://github.com/howardliu-cn) diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index c1bfa3bc..4ba901c5 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,12 +6,12 @@ 4.0.0 com.github.binarywang - weixin-java-parent - 3.2.0 + wx-java + 3.3.0 weixin-java-common - Weixin Java Tools - Common + WxJava - Common 微信开发Java SDK公共模块 @@ -114,6 +114,11 @@ assertj-guava test + + org.dom4j + dom4j + 2.0.0 + 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 a1e3c073..c4bac2a8 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 @@ -250,6 +250,15 @@ public class WxConsts { */ public static final String CARD_PAY_ORDER = "card_pay_order"; + /** + * 小程序审核事件:审核通过 + */ + public static final String WEAPP_AUDIT_SUCCESS = "weapp_audit_success"; + + /** + * 小程序审核事件:审核不通过 + */ + public static final String WEAPP_AUDIT_FAIL = "weapp_audit_fail"; } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java index c0f57c83..d7ac36c7 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java @@ -76,7 +76,7 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec } } } catch (InterruptedException e) { - e.printStackTrace(); + Thread.currentThread().interrupt(); } } }); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java index 17d8ab9f..0b9f689b 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java @@ -2,10 +2,8 @@ package me.chanjar.weixin.common.bean; import java.io.Serializable; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import lombok.Data; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; /** * 卡券Api签名. @@ -37,6 +35,6 @@ public class WxCardApiSignature implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenu.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenu.java index 8b43646a..ab000733 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenu.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenu.java @@ -7,9 +7,6 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import lombok.Data; import me.chanjar.weixin.common.util.json.WxGsonBuilder; @@ -49,7 +46,7 @@ public class WxMenu implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return this.toJson(); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java index 5e0b9db9..114e267d 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java @@ -4,11 +4,9 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import com.google.gson.annotations.SerializedName; import lombok.Data; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; /** * menu button. @@ -83,7 +81,7 @@ public class WxMenuButton implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java index 632279b9..49d4e891 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java @@ -2,11 +2,9 @@ package me.chanjar.weixin.common.bean.menu; import java.io.Serializable; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import com.google.gson.annotations.SerializedName; import lombok.Data; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; /** * menu rule. @@ -31,6 +29,6 @@ public class WxMenuRule implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxGsonBuilder.create().toJson(this); } } 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 d6ffd50c..a62bf3c6 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 @@ -2,9 +2,6 @@ package me.chanjar.weixin.common.bean.result; import java.io.Serializable; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import lombok.Data; import me.chanjar.weixin.common.util.json.WxGsonBuilder; @@ -28,7 +25,7 @@ public class WxMediaUploadResult implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxCpErrorMsgEnum.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxCpErrorMsgEnum.java index 0ae58062..56af9cef 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxCpErrorMsgEnum.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxCpErrorMsgEnum.java @@ -794,8 +794,7 @@ public enum WxCpErrorMsgEnum { * 通过错误代码查找其中文含义. */ public static String findMsgByCode(int code) { - WxCpErrorMsgEnum[] values = WxCpErrorMsgEnum.values(); - for (WxCpErrorMsgEnum value : values) { + for (WxCpErrorMsgEnum value : WxCpErrorMsgEnum.values()) { if (value.code == code) { return value.msg; } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java index fc9b624f..731592ea 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java @@ -64,6 +64,11 @@ public class WxError implements Serializable { if (msg != null) { wxError.setErrorMsg(msg); } + } else if (type == WxType.MiniApp) { + final String msg = WxMaErrorMsgEnum.findMsgByCode(wxError.getErrorCode()); + if (msg != null) { + wxError.setErrorMsg(msg); + } } return wxError; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java new file mode 100644 index 00000000..3423bb2e --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java @@ -0,0 +1,253 @@ +package me.chanjar.weixin.common.error; + +import lombok.Getter; + +/** + * 微信小程序错误码 + * + * @author biggates + */ +@Getter +public enum WxMaErrorMsgEnum { + /** + *
+   * 获取 access_token 时 AppSecret 错误,
+   * 或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的小程序调用接口
+   * 对应操作:sendCustomerMessage
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
+   * 
+ */ + CODE_40001(40001, "access_token 无效或 AppSecret 错误"), + /** + *
+   * 不合法的凭证类型
+   * 对应操作:sendCustomerMessage
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
+   * 
+ */ + CODE_40002(40002, "不合法的凭证类型"), + /** + *
+   * touser不是正确的openid.
+   * 对应操作:sendCustomerMessage, sendUniformMessage
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
+   * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
+   * 
+ */ + CODE_40003(40003, "openid 不正确"), + /** + *
+   * 无效媒体文件类型
+   * 对应操作:uploadTempMedia
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/uploadTempMedia.html
+   * 
+ */ + CODE_40004(40004, "无效媒体文件类型"), + /** + *
+   * 无效媒体文件 ID.
+   * 对应操作:getTempMedia
+   * 对应地址:
+   * GET https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/getTempMedia.html
+   * 
+ */ + CODE_40007(40007, "无效媒体文件 ID"), + /** + *
+   * appid不正确,或者不符合绑定关系要求.
+   * 对应操作:sendUniformMessage
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
+   * 
+ */ + CODE_40013(40013, "appid不正确,或者不符合绑定关系要求"), + /** + *
+   * template_id 不正确.
+   * 对应操作:sendUniformMessage, sendTemplateMessage
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
+   * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html
+   * 
+ */ + CODE_40037(40037, "template_id 不正确"), + /** + *
+   * form_id不正确,或者过期.
+   * 对应操作:sendUniformMessage, sendTemplateMessage
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
+   * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html
+   * 
+ */ + CODE_41028(41028, "form_id 不正确,或者过期"), + /** + *
+   * code 或 template_id 不正确.
+   * 对应操作:code2Session, sendUniformMessage, sendTemplateMessage
+   * 对应地址:
+   * GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/code2Session.html
+   * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
+   * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html
+   * 
+ */ + CODE_41029(41029, "请求的参数不正确"), + /** + *
+   * form_id 已被使用,或者所传page页面不存在,或者小程序没有发布
+   * 对应操作:sendUniformMessage, getWXACodeUnlimit
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
+   * POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
+   *  https://developers.weixin.qq.com/miniprogram/dev/api/open-api/qr-code/getWXACodeUnlimit.html
+   * 
+ */ + CODE_41030(41030, "请求的参数不正确"), + /** + *
+   * 调用分钟频率受限.
+   * 对应操作:getWXACodeUnlimit, sendUniformMessage, sendTemplateMessage
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
+   * POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
+   * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/qr-code/getWXACodeUnlimit.html
+   * 
+ */ + CODE_45009(45009, "调用分钟频率受限"), + /** + *
+   * 频率限制,每个用户每分钟100次.
+   * 对应操作:code2Session
+   * 对应地址:
+   * GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/code2Session.html
+   * 
+ */ + CODE_45011(45011, "频率限制,每个用户每分钟100次"), + /** + *
+   * 回复时间超过限制.
+   * 对应操作:sendCustomerMessage
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
+   * 
+ */ + CODE_45015(45015, "回复时间超过限制"), + /** + *
+   * 接口调用超过限额, 或生成码个数总和到达最大个数限制.
+   * 对应操作:createWXAQRCode, sendTemplateMessage
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=ACCESS_TOKEN
+   * POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/qr-code/getWXACode.html
+   * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html
+   * 
+ */ + CODE_45029(45029, "接口调用超过限额"), + /** + *
+   * 客服接口下行条数超过上限.
+   * 对应操作:sendCustomerMessage
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
+   * 
+ */ + CODE_45047(45047, "客服接口下行条数超过上限"), + /** + *
+   * command字段取值不对
+   * 对应操作:customerTyping
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/customerTyping.html
+   * 
+ */ + CODE_45072(45072, "command字段取值不对"), + /** + *
+   * 下发输入状态,需要之前30秒内跟用户有过消息交互.
+   * 对应操作:customerTyping
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/customerTyping.html
+   */
+  CODE_45080(45080, "下发输入状态,需要之前30秒内跟用户有过消息交互"),
+  /**
+   * 
+   * 已经在输入状态,不可重复下发.
+   * 对应操作:customerTyping
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/customerTyping.html
+   * 
+ */ + CODE_45081(45081, "已经在输入状态,不可重复下发"), + /** + *
+   * API 功能未授权,请确认小程序已获得该接口.
+   * 对应操作:sendCustomerMessage
+   * 对应地址:
+   * POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
+   * 
+ */ + CODE_48001(48001, "API 功能未授权"), + /** + *
+   * 内容含有违法违规内容.
+   * 对应操作:imgSecCheck, msgSecCheck
+   * 对应地址:
+   * POST https://api.weixin.qq.com/wxa/img_sec_check?access_token=ACCESS_TOKEN
+   * POST https://api.weixin.qq.com/wxa/msg_sec_check?access_token=ACCESS_TOKEN
+   * 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/imgSecCheck.html
+   * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/msgSecCheck.html
+   * 
+ */ + CODE_87014(87014, "内容含有违法违规内容"); + + private int code; + private String msg; + + WxMaErrorMsgEnum(int code, String msg) { + this.code = code; + this.msg = msg; + } + + /** + *
+   * 通过错误代码查找其中文含义.
+   */
+  public static String findMsgByCode(int code) {
+    for (WxMaErrorMsgEnum value : WxMaErrorMsgEnum.values()) {
+      if (value.code == code) {
+        return value.msg;
+      }
+    }
+
+    return null;
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMpErrorMsgEnum.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMpErrorMsgEnum.java
index 3882252b..7e478606 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMpErrorMsgEnum.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMpErrorMsgEnum.java
@@ -642,8 +642,7 @@ public enum WxMpErrorMsgEnum {
    * 通过错误代码查找其中文含义.
    */
   public static String findMsgByCode(int code) {
-    WxMpErrorMsgEnum[] values = WxMpErrorMsgEnum.values();
-    for (WxMpErrorMsgEnum value : values) {
+    for (WxMpErrorMsgEnum value : WxMpErrorMsgEnum.values()) {
       if (value.code == code) {
         return value.msg;
       }
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 bf2e7358..2472cb44 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
@@ -196,6 +196,7 @@ public class StandardSessionManager implements WxSessionManager, InternalSession
               Thread.sleep(StandardSessionManager.this.backgroundProcessorDelay * 1000L);
               backgroundProcess();
             } catch (InterruptedException e) {
+              Thread.currentThread().interrupt();
               StandardSessionManager.this.log.error("SessionManagerImpl.backgroundProcess error", e);
             }
           }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java
index 9ea33b12..fc3579d4 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java
@@ -1,12 +1,14 @@
 package me.chanjar.weixin.common.util;
 
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.codec.binary.Hex;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.codec.binary.Hex;
+
+import lombok.extern.slf4j.Slf4j;
 
 /**
  * 
@@ -27,9 +29,9 @@ public class SignUtils {
   public static String createHmacSha256Sign(String message, String key) {
     try {
       Mac sha256 = Mac.getInstance("HmacSHA256");
-      SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256");
+      SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
       sha256.init(secretKeySpec);
-      byte[] bytes = sha256.doFinal(message.getBytes());
+      byte[] bytes = sha256.doFinal(message.getBytes(StandardCharsets.UTF_8));
       return Hex.encodeHexString(bytes).toUpperCase();
     } catch (NoSuchAlgorithmException | InvalidKeyException e) {
       SignUtils.log.error(e.getMessage(), e);
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java
new file mode 100644
index 00000000..cd3a7a98
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java
@@ -0,0 +1,96 @@
+package me.chanjar.weixin.common.util;
+
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.Node;
+import org.dom4j.io.SAXReader;
+import org.dom4j.tree.DefaultText;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * 
+ * XML转换工具类.
+ * Created by Binary Wang on 2018/11/4.
+ * 
+ * + * @author Binary Wang + */ +public class XmlUtils { + + public static Map xml2Map(String xmlString) { + Map map = new HashMap<>(16); + try { + SAXReader saxReader = new SAXReader(); + Document doc = saxReader.read(new StringReader(xmlString)); + Element root = doc.getRootElement(); + List elements = root.elements(); + for (Element element : elements) { + map.put(element.getName(), element2MapOrString(element)); + } + } catch (DocumentException e) { + throw new RuntimeException(e); + } + + return map; + } + + private static Object element2MapOrString(Element element) { + Map result = Maps.newHashMap(); + + final List content = element.content(); + if (content.size() <= 1) { + return element.getText(); + } + + final Set names = names(content); + if (names.size() == 1) { + // 说明是个列表,各个子对象是相同的name + List list = Lists.newArrayList(); + for (Node node : content) { + if (node instanceof DefaultText) { + continue; + } + + if (node instanceof Element) { + list.add(element2MapOrString((Element) node)); + } + } + + result.put(names.iterator().next(), list); + } else { + for (Node node : content) { + if (node instanceof DefaultText) { + continue; + } + + if (node instanceof Element) { + result.put(node.getName(), element2MapOrString((Element) node)); + } + } + } + + return result; + } + + private static Set names(List nodes) { + Set names = Sets.newHashSet(); + for (Node node : nodes) { + if (node instanceof DefaultText) { + continue; + } + names.add(node.getName()); + } + + return names; + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/PKCS7Encoder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/PKCS7Encoder.java index 8ce94cba..efe7867b 100755 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/PKCS7Encoder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/PKCS7Encoder.java @@ -1,22 +1,22 @@ -/** +/* * 对公众平台发送给公众账号的消息加解密示例代码. * * @copyright Copyright (c) 1998-2014 Tencent Inc. */ -// ------------------------------------------------------------------------ - package me.chanjar.weixin.common.util.crypto; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Arrays; /** - * 提供基于PKCS7算法的加解 + * 提供基于PKCS7算法的加解. + * + * @author tencent */ public class PKCS7Encoder { - - private static final Charset CHARSET = Charset.forName("utf-8"); + private static final Charset CHARSET = StandardCharsets.UTF_8; private static final int BLOCK_SIZE = 32; /** @@ -28,20 +28,17 @@ public class PKCS7Encoder { public static byte[] encode(int count) { // 计算需要填充的位数 int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); - if (amountToPad == 0) { - amountToPad = BLOCK_SIZE; - } // 获得补位所用的字符 char padChr = chr(amountToPad); - String tmp = new String(); + StringBuilder tmp = new StringBuilder(); for (int index = 0; index < amountToPad; index++) { - tmp += padChr; + tmp.append(padChr); } - return tmp.getBytes(CHARSET); + return tmp.toString().getBytes(CHARSET); } /** - * 删除解密后明文的补位字符 + * 删除解密后明文的补位字符. * * @param decrypted 解密后的明文 * @return 删除补位字符后的明文 @@ -55,12 +52,12 @@ public class PKCS7Encoder { } /** - * 将数字转化成ASCII码对应的字符,用于对明文进行补码 + * 将数字转化成ASCII码对应的字符,用于对明文进行补码. * * @param a 需要转化的数字 * @return 转化得到的字符 */ - public static char chr(int a) { + private static char chr(int a) { byte target = (byte) (a & 0xFF); return (char) target; } 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 f16d3bd3..cded0c98 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,21 +1,21 @@ package me.chanjar.weixin.common.util.crypto; -import org.apache.commons.codec.binary.Base64; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.InputSource; - +import java.io.StringReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Random; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; 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.nio.charset.StandardCharsets; -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; /** *
@@ -25,6 +25,8 @@ import java.util.Random;
  * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
  * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
  * 
+ * + * @author Tencent */ public class WxCryptUtil { @@ -35,7 +37,9 @@ public class WxCryptUtil { @Override protected DocumentBuilder initialValue() { try { - return DocumentBuilderFactory.newInstance().newDocumentBuilder(); + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setExpandEntityReferences(false); + return factory.newDocumentBuilder(); } catch (ParserConfigurationException exc) { throw new IllegalArgumentException(exc); } @@ -164,8 +168,7 @@ public class WxCryptUtil { ByteGroup byteCollector = new ByteGroup(); byte[] randomStringBytes = randomStr.getBytes(CHARSET); byte[] plainTextBytes = plainText.getBytes(CHARSET); - byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder( - plainTextBytes.length); + byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length); byte[] appIdBytes = this.appidOrCorpid.getBytes(CHARSET); // randomStr + networkBytesOrder + text + appid @@ -252,7 +255,7 @@ public class WxCryptUtil { throw new RuntimeException(e); } - String xmlContent, from_appid; + String xmlContent, fromAppid; try { // 去除补位字符 byte[] bytes = PKCS7Encoder.decode(original); @@ -264,14 +267,14 @@ public class WxCryptUtil { xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET); - from_appid = new String( + fromAppid = new String( Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); } catch (Exception e) { throw new RuntimeException(e); } // appid不相同的情况 - if (!from_appid.equals(this.appidOrCorpid)) { + if (!fromAppid.equals(this.appidOrCorpid)) { throw new RuntimeException("AppID不正确"); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java index 990e1620..5e344acf 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java @@ -1,13 +1,16 @@ package me.chanjar.weixin.common.util.http; +import java.io.File; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; 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; - /** - * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File + * 下载媒体文件请求执行器. + * 请求的参数是String, 返回的结果是File * 视频文件不支持下载 * * @author Daniel Qian @@ -21,6 +24,11 @@ public abstract class BaseMediaDownloadRequestExecutor implements RequestE this.tmpDirFile = tmpDirFile; } + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java index ceaeffbd..0d685188 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java @@ -58,7 +58,7 @@ public class HttpResponseProxy { private String getFileName(CloseableHttpResponse response) throws WxErrorException { Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); if (contentDispositionHeader == null || contentDispositionHeader.length == 0) { - throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build()); + throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build()); } return this.extractFileNameFromContentString(contentDispositionHeader[0].getValue()); @@ -76,7 +76,7 @@ public class HttpResponseProxy { private String extractFileNameFromContentString(String content) throws WxErrorException { if (content == null || content.length() == 0) { - throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build()); + throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build()); } Matcher m = PATTERN.matcher(content); @@ -84,7 +84,7 @@ public class HttpResponseProxy { return m.group(1); } - throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build()); + throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).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 6b883ce7..10ef3602 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,14 +1,17 @@ package me.chanjar.weixin.common.util.http; +import java.io.File; +import java.io.IOException; + import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.error.WxErrorException; 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; - /** - * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String + * 上传媒体文件请求执行器. + * 请求的参数是File, 返回的结果是String * * @author Daniel Qian */ @@ -19,6 +22,11 @@ public abstract class MediaUploadRequestExecutor implements RequestExecuto this.requestHttp = requestHttp; } + @Override + public void execute(String uri, File data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: 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 a5a9423f..feef02de 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,11 +1,11 @@ package me.chanjar.weixin.common.util.http; -import me.chanjar.weixin.common.error.WxErrorException; - import java.io.IOException; +import me.chanjar.weixin.common.error.WxErrorException; + /** - * http请求执行器 + * http请求执行器. * * @param 返回值类型 * @param 请求参数类型 @@ -14,8 +14,25 @@ import java.io.IOException; public interface RequestExecutor { /** + * 执行http请求. + * * @param uri uri * @param data 数据 + * @return 响应结果 + * @throws WxErrorException 自定义异常 + * @throws IOException io异常 */ T execute(String uri, E data) throws WxErrorException, IOException; + + + /** + * 执行http请求. + * + * @param uri uri + * @param data 数据 + * @param handler http响应处理器 + * @throws WxErrorException 自定义异常 + * @throws IOException io异常 + */ + void execute(String uri, E data, ResponseHandler handler) throws WxErrorException, IOException; } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java index efd9f99b..b7bc850f 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java @@ -2,21 +2,30 @@ package me.chanjar.weixin.common.util.http; /** * Created by ecoolper on 2017/4/22. + * + * @author ecoolper */ public interface RequestHttp { /** - * 返回httpClient + * 返回httpClient. * + * @return 返回httpClient */ H getRequestHttpClient(); /** - * 返回httpProxy + * 返回httpProxy. * + * @return 返回httpProxy */ P getRequestHttpProxy(); + /** + * 返回HttpType. + * + * @return HttpType + */ HttpType getRequestType(); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ResponseHandler.java new file mode 100644 index 00000000..15717642 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ResponseHandler.java @@ -0,0 +1,19 @@ +package me.chanjar.weixin.common.util.http; + +/** + *
+ * http请求响应回调处理接口.
+ * Created by Binary Wang on 2018/12/8.
+ * 
+ * + * @param 返回值类型 + * @author Binary Wang + */ +public interface ResponseHandler { + /** + * 响应结果处理. + * + * @param t 要处理的对象 + */ + void handle(T t); +} 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 e72acc90..6d8b52a8 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,11 +1,15 @@ package me.chanjar.weixin.common.util.http; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; 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 + * 简单的GET请求执行器. + * 请求的参数是String, 返回的结果也是String * * @author Daniel Qian */ @@ -16,6 +20,11 @@ public abstract class SimpleGetRequestExecutor implements RequestExecutor< this.requestHttp = requestHttp; } + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: 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 2932f247..97a368ea 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,5 +1,8 @@ package me.chanjar.weixin.common.util.http; +import java.io.IOException; + +import me.chanjar.weixin.common.error.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; @@ -17,6 +20,11 @@ public abstract class SimplePostRequestExecutor implements RequestExecutor this.requestHttp = requestHttp; } + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/URIUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/URIUtil.java index 7e42aba7..4e45c65d 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/URIUtil.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/URIUtil.java @@ -1,9 +1,9 @@ package me.chanjar.weixin.common.util.http; -import org.apache.commons.lang3.StringUtils; +import java.nio.charset.StandardCharsets; -import java.io.UnsupportedEncodingException; +import org.apache.commons.lang3.StringUtils; public class URIUtil { @@ -16,27 +16,22 @@ public class URIUtil { int l = input.length(); StringBuilder o = new StringBuilder(l * 3); - try { - for (int i = 0; i < l; i++) { - String e = input.substring(i, i + 1); - if (ALLOWED_CHARS.indexOf(e) == -1) { - byte[] b = e.getBytes("utf-8"); - o.append(getHex(b)); - continue; - } - o.append(e); + for (int i = 0; i < l; i++) { + String e = input.substring(i, i + 1); + if (!ALLOWED_CHARS.contains(e)) { + byte[] b = e.getBytes(StandardCharsets.UTF_8); + o.append(getHex(b)); + continue; } - return o.toString(); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); + o.append(e); } - return input; + return o.toString(); } - private static String getHex(byte buf[]) { + private static String getHex(byte[] buf) { StringBuilder o = new StringBuilder(buf.length * 3); - for (int i = 0; i < buf.length; i++) { - int n = buf[i] & 0xff; + for (byte aBuf : buf) { + int n = aBuf & 0xff; o.append("%"); if (n < 0x10) { o.append("0"); 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 index 658ea4af..3951758d 100644 --- 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 @@ -1,16 +1,17 @@ package me.chanjar.weixin.common.util.http.apache; -import me.chanjar.weixin.common.error.WxError; -import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import java.io.IOException; + import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; -import java.io.IOException; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; /** * Created by ecoolper on 2017/5/4. 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 index 033add1a..fe5472f3 100644 --- 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 @@ -1,5 +1,9 @@ package me.chanjar.weixin.common.util.http.apache; +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHost; import org.apache.http.annotation.NotThreadSafe; @@ -25,10 +29,6 @@ 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

@@ -292,6 +292,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { } } } catch (InterruptedException ignore) { + Thread.currentThread().interrupt(); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java index 2ce87508..779a844a 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java @@ -25,7 +25,6 @@ import me.chanjar.weixin.common.util.http.RequestHttp; * Created by ecoolper on 2017/5/5. */ public class ApacheMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor { - public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { super(requestHttp, tmpDirFile); } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java index d4cea91d..5c72744c 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java @@ -1,5 +1,8 @@ package me.chanjar.weixin.common.util.http.apache; +import java.io.IOException; +import java.io.InputStream; + import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; @@ -7,18 +10,20 @@ import org.apache.http.client.HttpResponseException; import org.apache.http.client.ResponseHandler; import org.apache.http.util.EntityUtils; -import java.io.IOException; -import java.io.InputStream; - +/** + * 输入流响应处理器. + * + * @author Daniel Qian + */ public class InputStreamResponseHandler implements ResponseHandler { - public static final ResponseHandler INSTANCE = new InputStreamResponseHandler(); + private static final int STATUS_CODE_300 = 300; @Override public InputStream handleResponse(final HttpResponse response) throws IOException { final StatusLine statusLine = response.getStatusLine(); final HttpEntity entity = response.getEntity(); - if (statusLine.getStatusCode() >= 300) { + if (statusLine.getStatusCode() >= STATUS_CODE_300) { EntityUtils.consume(entity); throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); } 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 7c7d92f0..97740efb 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 @@ -7,9 +7,13 @@ import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +/** + * . + * @author chanjarster + */ public class WxGsonBuilder { - public static final GsonBuilder INSTANCE = new GsonBuilder(); + private static final GsonBuilder INSTANCE = new GsonBuilder(); static { INSTANCE.disableHtmlEscaping(); 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 d97062ee..639fcf08 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 @@ -8,47 +8,47 @@ import com.thoughtworks.xstream.core.util.QuickWriter; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; import com.thoughtworks.xstream.io.xml.XppDriver; -import com.thoughtworks.xstream.security.NullPermission; -import com.thoughtworks.xstream.security.PrimitiveTypePermission; public class XStreamInitializer { - - public static XStream getInstance() { - XStream xstream = new XStream(new PureJavaReflectionProvider(), new XppDriver() { - - @Override - public HierarchicalStreamWriter createWriter(Writer out) { - return new PrettyPrintWriter(out, getNameCoder()) { - protected String PREFIX_CDATA = ""; - protected String PREFIX_MEDIA_ID = ""; - protected String SUFFIX_MEDIA_ID = ""; - - @Override - protected void writeText(QuickWriter writer, String text) { - if (text.startsWith(this.PREFIX_CDATA) && text.endsWith(this.SUFFIX_CDATA)) { - writer.write(text); - } else if (text.startsWith(this.PREFIX_MEDIA_ID) && text.endsWith(this.SUFFIX_MEDIA_ID)) { - writer.write(text); - } else { - super.writeText(writer, text); - } - + private static final XppDriver XPP_DRIVER = new XppDriver() { + @Override + public HierarchicalStreamWriter createWriter(Writer out) { + return new PrettyPrintWriter(out, getNameCoder()) { + private static final String PREFIX_CDATA = ""; + private static final String PREFIX_MEDIA_ID = ""; + private static final String SUFFIX_MEDIA_ID = ""; + + @Override + protected void writeText(QuickWriter writer, String text) { + if (text.startsWith(PREFIX_CDATA) && text.endsWith(SUFFIX_CDATA)) { + writer.write(text); + } else if (text.startsWith(PREFIX_MEDIA_ID) && text.endsWith(SUFFIX_MEDIA_ID)) { + writer.write(text); + } else { + super.writeText(writer, text); } - @Override - public String encodeNode(String name) { - //防止将_转换成__ - return name; - } - }; - } - }); + } + @Override + public String encodeNode(String name) { + //防止将_转换成__ + return name; + } + }; + } + }; + + public static XStream getInstance() { + XStream xstream = new XStream(new PureJavaReflectionProvider(), XPP_DRIVER); xstream.ignoreUnknownElements(); xstream.setMode(XStream.NO_REFERENCES); - xstream.addPermission(NullPermission.NULL); - xstream.addPermission(PrimitiveTypePermission.PRIMITIVES); + XStream.setupDefaultSecurity(xstream); + xstream.allowTypesByWildcard(new String[]{ + "me.chanjar.weixin.**", "cn.binarywang.wx.**", "com.github.binarywang.**" + }); + xstream.setClassLoader(Thread.currentThread().getContextClassLoader()); return xstream; } diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/DataUtilsTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/DataUtilsTest.java index af348809..f5732d9a 100644 --- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/DataUtilsTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/DataUtilsTest.java @@ -1,8 +1,7 @@ package me.chanjar.weixin.common.util; -import org.testng.annotations.Test; +import org.testng.annotations.*; -import static org.assertj.core.api.Assertions.assertThat; import static org.testng.Assert.*; /** @@ -18,6 +17,6 @@ public class DataUtilsTest { public void testHandleDataWithSecret() { String data = "js_code=001tZveq0SMoiq1AEXeq0ECJeq0tZveZ&secret=5681022fa1643845392367ea88888888&grant_type=authorization_code&appid=wxe156d4848d999999"; final String s = DataUtils.handleDataWithSecret(data); - assertThat(s).contains("&secret=******&"); + assertTrue(s.contains("&secret=******&")); } } diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/XmlUtilsTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/XmlUtilsTest.java new file mode 100644 index 00000000..1afd1c1d --- /dev/null +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/XmlUtilsTest.java @@ -0,0 +1,78 @@ +package me.chanjar.weixin.common.util; + +import java.util.List; +import java.util.Map; + +import org.testng.annotations.*; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + *
+ *
+ * Created by Binary Wang on 2018/11/4.
+ * 
+ * + * @author Binary Wang + */ +public class XmlUtilsTest { + + @Test + public void testXml2Map() { + String xml = "\n" + + "\n" + + "2\n" + + "\n" + + "\n" + + "1\n" + + "0\n" + + "2\n" + + "\n" + + "1\n" + + "1\n" + + "1\n" + + "1\n" + + "\n" + + "\n" + + "2\n" + + "0\n" + + "2\n" + + "\n" + + "1\n" + + "1\n" + + "1\n" + + "1\n" + + "\n" + + "\n" + + "2\n" + + "\n" + + ""; + + final Map map = XmlUtils.xml2Map(xml); + assertThat(map).isNotNull(); + final Map copyrightCheckResult = (Map) map.get("CopyrightCheckResult"); + List> resultList = (List>) ((Map) copyrightCheckResult.get("ResultList")).get("item"); + assertThat(copyrightCheckResult).isNotNull(); + + assertThat(copyrightCheckResult.get("Count")).isEqualTo("2"); + assertThat(copyrightCheckResult.get("CheckState")).isEqualTo("2"); + + assertThat(resultList.get(0).get("ArticleIdx")).isEqualTo("1"); + assertThat(resultList.get(0).get("UserDeclareState")).isEqualTo("0"); + assertThat(resultList.get(0).get("AuditState")).isEqualTo("2"); + assertThat(resultList.get(0).get("OriginalArticleUrl")).isEqualTo("Url_1"); + assertThat(resultList.get(0).get("OriginalArticleType")).isEqualTo("1"); + assertThat(resultList.get(0).get("CanReprint")).isEqualTo("1"); + assertThat(resultList.get(0).get("NeedReplaceContent")).isEqualTo("1"); + assertThat(resultList.get(0).get("NeedShowReprintSource")).isEqualTo("1"); + + assertThat(resultList.get(1).get("ArticleIdx")).isEqualTo("2"); + assertThat(resultList.get(1).get("UserDeclareState")).isEqualTo("0"); + assertThat(resultList.get(1).get("AuditState")).isEqualTo("2"); + assertThat(resultList.get(1).get("OriginalArticleUrl")).isEqualTo("Url_2"); + assertThat(resultList.get(1).get("OriginalArticleType")).isEqualTo("1"); + assertThat(resultList.get(1).get("CanReprint")).isEqualTo("1"); + assertThat(resultList.get(1).get("NeedReplaceContent")).isEqualTo("1"); + assertThat(resultList.get(1).get("NeedShowReprintSource")).isEqualTo("1"); + } +} 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 b13fee5f..06f9d7ba 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,5 +1,11 @@ package me.chanjar.weixin.common.util.crypto; +import java.io.IOException; +import java.io.StringReader; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + import org.testng.annotations.*; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -7,12 +13,6 @@ import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.io.StringReader; - import static org.testng.Assert.*; @Test @@ -39,6 +39,7 @@ public class WxCryptUtilTest { System.out.println(encryptedXml); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setExpandEntityReferences(false); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document document = documentBuilder.parse(new InputSource(new StringReader(encryptedXml))); @@ -81,6 +82,7 @@ public class WxCryptUtilTest { WxCryptUtil pc = new WxCryptUtil(this.token, this.encodingAesKey, this.appId); String afterEncrpt = pc.encrypt(this.replyMsg); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setExpandEntityReferences(false); DocumentBuilder db = dbf.newDocumentBuilder(); StringReader sr = new StringReader(afterEncrpt); InputSource is = new InputSource(sr); diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index cba66067..a1808f2d 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -6,13 +6,13 @@ 4.0.0 com.github.binarywang - weixin-java-parent - 3.2.0 + wx-java + 3.3.0 weixin-java-cp - Weixin Java Tools - CP - 微信企业号Java SDK + WxJava - CP + 微信企业号/企业微信 Java SDK diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java new file mode 100644 index 00000000..2c24701d --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java @@ -0,0 +1,48 @@ +package me.chanjar.weixin.cp.api; + +import java.util.List; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.bean.WxCpChat; + +/** + * 群聊服务 + * + * @author gaigeshen + */ +public interface WxCpChatService { + + /** + * 创建群聊会话,注意:刚创建的群,如果没有下发消息,在企业微信不会出现该群。 + * + * @param name 群聊名,最多50个utf8字符,超过将截断 + * @param owner 指定群主的id。如果不指定,系统会随机从userlist中选一人作为群主 + * @param users 群成员id列表。至少2人,至多500人 + * @param chatId 群聊的唯一标志,不能与已有的群重复;字符串类型,最长32个字符。只允许字符0-9及字母a-zA-Z。如果不填,系统会随机生成群id + * @return 创建群聊会话的结果,群聊的唯一标志 + * @throws WxErrorException 发生异常 + */ + String chatCreate(String name, String owner, List users, String chatId) throws WxErrorException; + + /** + * 修改群聊会话 + * + * @param chatId 群聊id + * @param name 新的群聊名。若不需更新,请忽略此参数(null or empty)。最多50个utf8字符,超过将截断 + * @param owner 新群主的id。若不需更新,请忽略此参数(null or empty) + * @param usersToAdd 添加成员的id列表,若不需要更新,则传递空对象或者空集合 + * @param usersToDelete 踢出成员的id列表,若不需要更新,则传递空对象或者空集合 + * @throws WxErrorException 发生异常 + */ + void chatUpdate(String chatId, String name, String owner, List usersToAdd, List usersToDelete) throws WxErrorException; + + /** + * 获取群聊会话 + * + * @param chatId 群聊编号 + * @return 群聊会话 + * @throws WxErrorException 发生异常 + */ + WxCpChat chatGet(String chatId) throws WxErrorException; + +} 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 index 45da3c0d..8a8ca054 100644 --- 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 @@ -1,10 +1,10 @@ package me.chanjar.weixin.cp.api; +import java.util.List; + import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.bean.WxCpDepart; -import java.util.List; - /** *
  *  部门管理接口
@@ -17,42 +17,47 @@ public interface WxCpDepartmentService {
 
   /**
    * 
-   * 部门管理接口 - 创建部门
+   * 部门管理接口 - 创建部门.
    * 最多支持创建500个部门
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
    * 
* * @param depart 部门 * @return 部门id + * @throws WxErrorException 异常 */ Integer create(WxCpDepart depart) throws WxErrorException; /** *
-   * 部门管理接口 - 查询部门
+   * 部门管理接口 - 查询部门.
    * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E5.88.97.E8.A1.A8
    * 
+ * * @param id 部门id。获取指定部门及其下的子部门。非必需,可为null + * @throws WxErrorException 异常 */ - List list(Integer id) throws WxErrorException; + List list(Long id) throws WxErrorException; /** *
-   * 部门管理接口 - 修改部门名
+   * 部门管理接口 - 修改部门名.
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
    * 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
    * 
* * @param group 要更新的group,group的id,name必须设置 + * @throws WxErrorException 异常 */ void update(WxCpDepart group) throws WxErrorException; /** *
-   * 部门管理接口 - 删除部门
+   * 部门管理接口 - 删除部门.
    * 
* * @param departId 部门id + * @throws WxErrorException 异常 */ - void delete(Integer departId) throws WxErrorException; + void delete(Long 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 index 19e6de44..31ce6b59 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java @@ -19,6 +19,7 @@ public interface WxCpMediaService { String MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; String MEDIA_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type="; String IMG_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg"; + String JSSDK_MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk"; /** *
@@ -59,6 +60,21 @@ public interface WxCpMediaService {
    */
   File download(String mediaId) throws WxErrorException;
 
+  /**
+   * 
+   * 获取高清语音素材.
+   * 可以使用本接口获取从JSSDK的uploadVoice接口上传的临时语音素材,格式为speex,16K采样率。该音频比上文的临时素材获取接口(格式为amr,8K采样率)更加清晰,适合用作语音识别等对音质要求较高的业务。
+   * 请求方式:GET(HTTPS)
+   * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
+   * 仅企业微信2.4及以上版本支持。
+   * 文档地址:https://work.weixin.qq.com/api/doc#90000/90135/90255
+   * 
+ * + * @param mediaId 媒体id + * @return 保存到本地的临时文件 + */ + File getJssdkFile(String mediaId) throws WxErrorException; + /** *
    * 上传图片.
@@ -69,7 +85,7 @@ public interface WxCpMediaService {
    * 
* * @param file 上传的文件对象 - * @return 返回图片url + * @return 返回图片url */ String uploadImg(File file) 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 3e33c4eb..afda991b 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 @@ -7,7 +7,8 @@ import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.cp.bean.*; +import me.chanjar.weixin.cp.bean.WxCpMessage; +import me.chanjar.weixin.cp.bean.WxCpMessageSendResult; import me.chanjar.weixin.cp.config.WxCpConfigStorage; /** @@ -241,13 +242,20 @@ public interface WxCpService { * 获取用户相关接口的服务类对象 */ WxCpUserService getUserService(); + + /** + * 获取群聊服务 + * + * @return 群聊服务 + */ + WxCpChatService getChatService(); WxCpAgentService getAgentService(); /** * http请求对象 */ - RequestHttp getRequestHttp(); + RequestHttp getRequestHttp(); void setUserService(WxCpUserService userService); 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 index 9f931725..310a1efa 100644 --- 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 @@ -38,7 +38,7 @@ public interface WxCpUserService { * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 */ - List listByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + List listByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException; /** *
@@ -51,7 +51,7 @@ public interface WxCpUserService {
    * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员
    * @param status     非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加
    */
-  List listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException;
+  List listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException;
 
   /**
    * 新建用户.
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java
index e4914134..3a977b81 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java
@@ -1,9 +1,11 @@
 package me.chanjar.weixin.cp.api.impl;
 
-import com.google.gson.Gson;
+import java.util.List;
+
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
+
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.cp.api.WxCpAgentService;
@@ -11,8 +13,6 @@ import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.bean.WxCpAgent;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
-import java.util.List;
-
 
 /**
  * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
new file mode 100644
index 00000000..b8e894fb
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
@@ -0,0 +1,83 @@
+package me.chanjar.weixin.cp.api.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.google.gson.JsonParser;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+import me.chanjar.weixin.cp.api.WxCpChatService;
+import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.bean.WxCpChat;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * 群聊服务实现
+ *
+ * @author gaigeshen
+ */
+public class WxCpChatServiceImpl implements WxCpChatService { 
+
+  private final WxCpService internalService;
+  
+  /**
+   * 创建群聊服务实现的实例
+   * 
+   * @param internalService 企业微信的服务
+   */
+  public WxCpChatServiceImpl(WxCpService internalService) {
+    this.internalService = internalService;
+  }
+
+  @Override
+  public String chatCreate(String name, String owner, List users, String chatId) throws WxErrorException {
+    Map data = new HashMap<>(4);
+    if (StringUtils.isNotBlank(name)) {
+      data.put("name", name);
+    }
+    if (StringUtils.isNotBlank(owner)) {
+      data.put("owner", owner);
+    }
+    if (users != null) {
+      data.put("userlist", users);
+    }
+    if (StringUtils.isNotBlank(chatId)) {
+      data.put("chatid", chatId);
+    }
+    String result = internalService.post("https://qyapi.weixin.qq.com/cgi-bin/appchat/create", WxGsonBuilder.create().toJson(data));
+    return new JsonParser().parse(result).getAsJsonObject().get("chatid").getAsString();
+  }
+
+  @Override
+  public void chatUpdate(String chatId, String name, String owner, List usersToAdd, List usersToDelete) throws WxErrorException {
+    Map data = new HashMap<>(5);
+    if (StringUtils.isNotBlank(chatId)) {
+      data.put("chatid", chatId);
+    }
+    if (StringUtils.isNotBlank(name)) {
+      data.put("name", name);
+    }
+    if (StringUtils.isNotBlank(owner)) {
+      data.put("owner", owner);
+    }
+    if (usersToAdd != null && !usersToAdd.isEmpty()) {
+      data.put("add_user_list", usersToAdd);
+    }
+    if (usersToDelete != null && !usersToDelete.isEmpty()) {
+      data.put("del_user_list", usersToDelete);
+    }
+    internalService.post("https://qyapi.weixin.qq.com/cgi-bin/appchat/update", WxGsonBuilder.create().toJson(data));
+  }
+
+  @Override
+  public WxCpChat chatGet(String chatId) throws WxErrorException {
+    String result = internalService.get("https://qyapi.weixin.qq.com/cgi-bin/appchat/get?chatid=" + chatId, null);
+    return WxCpGsonBuilder.create().fromJson(
+        new JsonParser().parse(result).getAsJsonObject().getAsJsonObject("chat_info").toString(), WxCpChat.class);
+  }
+
+}
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
index 66452199..5d623b2a 100644
--- 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
@@ -1,5 +1,7 @@
 package me.chanjar.weixin.cp.api.impl;
 
+import java.util.List;
+
 import com.google.gson.JsonElement;
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
@@ -10,8 +12,6 @@ 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;
-
 /**
  * 
  *  部门管理接口
@@ -42,13 +42,13 @@ public class WxCpDepartmentServiceImpl implements WxCpDepartmentService {
   }
 
   @Override
-  public void delete(Integer departId) throws WxErrorException {
+  public void delete(Long departId) throws WxErrorException {
     String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId;
     this.mainService.get(url, null);
   }
 
   @Override
-  public List list(Integer id) throws WxErrorException {
+  public List list(Long id) throws WxErrorException {
     String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list";
     if (id != null) {
       url += "?id=" + id;
@@ -56,7 +56,7 @@ public class WxCpDepartmentServiceImpl implements WxCpDepartmentService {
 
     String responseContent = this.mainService.get(url, null);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
-    return WxCpGsonBuilder.INSTANCE.create()
+    return WxCpGsonBuilder.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
index c3dc4774..7a3dc444 100644
--- 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
@@ -48,6 +48,14 @@ public class WxCpMediaServiceImpl implements WxCpMediaService {
       MEDIA_GET_URL, "media_id=" + mediaId);
   }
 
+  @Override
+  public File getJssdkFile(String mediaId) throws WxErrorException {
+    return this.mainService.execute(
+      BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(),
+        this.mainService.getWxCpConfigStorage().getTmpDirFile()),
+      JSSDK_MEDIA_GET_URL, "media_id=" + mediaId);
+  }
+
   @Override
   public String uploadImg(File file) throws WxErrorException {
     final WxMediaUploadResult result = this.mainService
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
index 8f0375f3..3507de07 100644
--- 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
@@ -1,6 +1,5 @@
 package me.chanjar.weixin.cp.api.impl;
 
-import com.google.gson.GsonBuilder;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
@@ -11,6 +10,7 @@ import me.chanjar.weixin.common.util.json.GsonHelper;
 import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.bean.WxCpUserDetail;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
 /**
  * 
@@ -87,6 +87,6 @@ public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service {
     JsonObject param = new JsonObject();
     param.addProperty("user_ticket", userTicket);
     String responseText = this.mainService.post(url, param.toString());
-    return new GsonBuilder().create().fromJson(responseText, WxCpUserDetail.class);
+    return WxCpGsonBuilder.create().fromJson(responseText, WxCpUserDetail.class);
   }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java
index 0c66e0ef..f0c15109 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java
@@ -1,9 +1,16 @@
 package me.chanjar.weixin.cp.api.impl;
 
+import java.io.File;
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
+
 import me.chanjar.weixin.common.bean.WxJsapiSignature;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -17,19 +24,24 @@ 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.api.WxCpAgentService;
+import me.chanjar.weixin.cp.api.WxCpChatService;
+import me.chanjar.weixin.cp.api.WxCpDepartmentService;
+import me.chanjar.weixin.cp.api.WxCpMediaService;
+import me.chanjar.weixin.cp.api.WxCpMenuService;
+import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
+import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.api.WxCpTagService;
+import me.chanjar.weixin.cp.api.WxCpUserService;
+import me.chanjar.weixin.cp.bean.WxCpMessage;
+import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
 import me.chanjar.weixin.cp.config.WxCpConfigStorage;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.IOException;
 
 public abstract class WxCpServiceAbstractImpl implements WxCpService, RequestHttp {
   protected final Logger log = LoggerFactory.getLogger(this.getClass());
 
   private WxCpUserService userService = new WxCpUserServiceImpl(this);
+  private WxCpChatService chatService = new WxCpChatServiceImpl(this);
   private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this);
   private WxCpMediaService mediaService = new WxCpMediaServiceImpl(this);
   private WxCpMenuService menuService = new WxCpMenuServiceImpl(this);
@@ -184,7 +196,7 @@ public abstract class WxCpServiceAbstractImpl implements WxCpService, Requ
             this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
             Thread.sleep(sleepMillis);
           } catch (InterruptedException e1) {
-            throw new RuntimeException(e1);
+            Thread.currentThread().interrupt();
           }
         } else {
           throw e;
@@ -334,7 +346,12 @@ public abstract class WxCpServiceAbstractImpl implements WxCpService, Requ
   }
 
   @Override
-  public RequestHttp getRequestHttp() {
+  public WxCpChatService getChatService() {
+    return chatService;
+  }
+
+  @Override
+  public RequestHttp getRequestHttp() {
     return this;
   }
 
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
index aa8260b1..22bb0fcf 100644
--- 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
@@ -1,6 +1,12 @@
 package me.chanjar.weixin.cp.api.impl;
 
-import com.google.gson.*;
+import java.util.List;
+
+import com.google.gson.JsonArray;
+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.error.WxErrorException;
 import me.chanjar.weixin.cp.api.WxCpService;
@@ -11,8 +17,6 @@ import me.chanjar.weixin.cp.bean.WxCpTagGetResult;
 import me.chanjar.weixin.cp.bean.WxCpUser;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
-import java.util.List;
-
 /**
  * 
  *  标签管理接口
@@ -57,7 +61,7 @@ public class WxCpTagServiceImpl implements WxCpTagService {
     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()
+    return WxCpGsonBuilder.create()
       .fromJson(
         tmpJsonElement.getAsJsonObject().get("taglist"),
         new TypeToken>() {
@@ -70,7 +74,7 @@ public class WxCpTagServiceImpl implements WxCpTagService {
     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()
+    return WxCpGsonBuilder.create()
       .fromJson(
         tmpJsonElement.getAsJsonObject().get("userlist"),
         new TypeToken>() {
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java
index 68224b1e..84a16f34 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java
@@ -76,7 +76,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {
   }
 
   @Override
-  public List listByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException {
+  public List listByDepartment(Long 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) {
@@ -90,7 +90,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {
 
     String responseContent = this.mainService.get(url, params);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
-    return WxCpGsonBuilder.INSTANCE.create()
+    return WxCpGsonBuilder.create()
       .fromJson(tmpJsonElement.getAsJsonObject().get("userlist"),
         new TypeToken>() {
         }.getType()
@@ -98,7 +98,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {
   }
 
   @Override
-  public List listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException {
+  public List listSimpleByDepartment(Long 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) {
@@ -112,7 +112,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {
 
     String responseContent = this.mainService.get(url, params);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
-    return WxCpGsonBuilder.INSTANCE.create()
+    return WxCpGsonBuilder.create()
       .fromJson(
         tmpJsonElement.getAsJsonObject().get("userlist"),
         new TypeToken>() {
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgent.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgent.java
index b70571f0..18dfb346 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgent.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgent.java
@@ -1,5 +1,8 @@
 package me.chanjar.weixin.cp.bean;
 
+import java.io.Serializable;
+import java.util.List;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
@@ -7,9 +10,6 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * 
  * 企业号应用信息.
@@ -80,12 +80,14 @@ public class WxCpAgent implements Serializable {
 
   @Data
   public static class Users implements Serializable {
+    private static final long serialVersionUID = 8801100463558788565L;
     @SerializedName("user")
     private List users;
   }
 
   @Data
   public class User implements Serializable {
+    private static final long serialVersionUID = 7287632514385508024L;
     @SerializedName("userid")
     private String userId;
   }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpChat.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpChat.java
new file mode 100644
index 00000000..1f593e47
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpChat.java
@@ -0,0 +1,20 @@
+package me.chanjar.weixin.cp.bean;
+
+import java.util.List;
+
+import lombok.Data;
+
+/**
+ * 群聊
+ *
+ * @author gaigeshen
+ */
+@Data
+public class WxCpChat {
+  
+  private String id;
+  private String name;
+  private String owner;
+  private List users;
+
+}
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 2890ce61..dc71e027 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,10 +1,10 @@
 package me.chanjar.weixin.cp.bean;
 
+import java.io.Serializable;
+
 import lombok.Data;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
-import java.io.Serializable;
-
 /**
  * 微信部门.
  *
@@ -14,9 +14,9 @@ import java.io.Serializable;
 public class WxCpDepart implements Serializable {
 
   private static final long serialVersionUID = -5028321625140879571L;
-  private Integer id;
+  private Long id;
   private String name;
-  private Integer parentId;
+  private Long parentId;
   private Long order;
 
   public static WxCpDepart fromJson(String json) {
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpInviteResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpInviteResult.java
index f6ff4634..871e4839 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpInviteResult.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpInviteResult.java
@@ -5,8 +5,6 @@ import java.util.Collections;
 import java.util.List;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 
 import com.google.common.base.Splitter;
 import com.google.gson.annotations.SerializedName;
@@ -25,11 +23,11 @@ public class WxCpInviteResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxCpGsonBuilder.create().toJson(this);
   }
 
   public static WxCpInviteResult fromJson(String json) {
-    return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpInviteResult.class);
+    return WxCpGsonBuilder.create().fromJson(json, WxCpInviteResult.class);
   }
 
   @SerializedName("errcode")
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 58fc9830..d28c178c 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
@@ -1,16 +1,23 @@
 package me.chanjar.weixin.cp.bean;
 
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
 import lombok.Data;
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
 import me.chanjar.weixin.cp.bean.article.NewArticle;
-import me.chanjar.weixin.cp.bean.messagebuilder.*;
+import me.chanjar.weixin.cp.bean.messagebuilder.FileBuilder;
+import me.chanjar.weixin.cp.bean.messagebuilder.ImageBuilder;
+import me.chanjar.weixin.cp.bean.messagebuilder.MpnewsBuilder;
+import me.chanjar.weixin.cp.bean.messagebuilder.NewsBuilder;
+import me.chanjar.weixin.cp.bean.messagebuilder.TextBuilder;
+import me.chanjar.weixin.cp.bean.messagebuilder.TextCardBuilder;
+import me.chanjar.weixin.cp.bean.messagebuilder.VideoBuilder;
+import me.chanjar.weixin.cp.bean.messagebuilder.VoiceBuilder;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * 消息.
  *
@@ -114,7 +121,7 @@ public class WxCpMessage implements Serializable {
   }
 
   public String toJson() {
-    return WxCpGsonBuilder.INSTANCE.create().toJson(this);
+    return WxCpGsonBuilder.create().toJson(this);
   }
 
 }
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
index 9d0a85b6..d850adeb 100644
--- 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
@@ -5,8 +5,6 @@ import java.util.Collections;
 import java.util.List;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 
 import com.google.common.base.Splitter;
 import com.google.gson.annotations.SerializedName;
@@ -25,11 +23,11 @@ public class WxCpMessageSendResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxCpGsonBuilder.create().toJson(this);
   }
 
   public static WxCpMessageSendResult fromJson(String json) {
-    return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpMessageSendResult.class);
+    return WxCpGsonBuilder.create().fromJson(json, WxCpMessageSendResult.class);
   }
 
   @SerializedName("errcode")
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 360ddd28..f6b9fa02 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,14 +1,15 @@
 package me.chanjar.weixin.cp.bean;
 
+import java.io.Serializable;
+
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
-import java.io.Serializable;
-
 /**
  * Created by Daniel Qian.
+ * @author Daniel Qian
  */
 @Data
 @AllArgsConstructor
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
index 67d90978..037740ca 100644
--- 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
@@ -5,8 +5,6 @@ import java.util.Collections;
 import java.util.List;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 
 import com.google.common.base.Splitter;
 import com.google.gson.annotations.SerializedName;
@@ -25,11 +23,11 @@ public class WxCpTagAddOrRemoveUsersResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxCpGsonBuilder.create().toJson(this);
   }
 
   public static WxCpTagAddOrRemoveUsersResult fromJson(String json) {
-    return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpTagAddOrRemoveUsersResult.class);
+    return WxCpGsonBuilder.create().fromJson(json, WxCpTagAddOrRemoveUsersResult.class);
   }
 
   @SerializedName("errcode")
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 f3d5aa22..233d4576 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
@@ -50,11 +50,11 @@ public class WxCpUser implements Serializable {
   }
 
   public static WxCpUser fromJson(String json) {
-    return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpUser.class);
+    return WxCpGsonBuilder.create().fromJson(json, WxCpUser.class);
   }
 
   public String toJson() {
-    return WxCpGsonBuilder.INSTANCE.create().toJson(this);
+    return WxCpGsonBuilder.create().toJson(this);
   }
 
   @Data
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 abb880d2..3fc2137f 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java
@@ -3,12 +3,11 @@ package me.chanjar.weixin.cp.bean;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
@@ -18,6 +17,7 @@ import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
 import me.chanjar.weixin.cp.config.WxCpConfigStorage;
 import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 import me.chanjar.weixin.cp.util.xml.XStreamTransformer;
 
 /**
@@ -370,7 +370,7 @@ public class WxCpXmlMessage implements Serializable {
   public static WxCpXmlMessage fromEncryptedXml(InputStream is, WxCpConfigStorage wxCpConfigStorage,
                                                 String timestamp, String nonce, String msgSignature) {
     try {
-      return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxCpConfigStorage, timestamp, nonce, msgSignature);
+      return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), wxCpConfigStorage, timestamp, nonce, msgSignature);
     } catch (IOException e) {
       throw new RuntimeException(e);
     }
@@ -378,7 +378,7 @@ public class WxCpXmlMessage implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxCpGsonBuilder.create().toJson(this);
   }
 
   @Data
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java
index 707188a2..1b9f8a61 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java
@@ -2,11 +2,9 @@ package me.chanjar.weixin.cp.config;
 
 import java.io.File;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
 /**
  * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
@@ -203,7 +201,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxCpGsonBuilder.create().toJson(this);
   }
 
   @Override
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java
index 99e4fd45..6b778be6 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java
@@ -1,5 +1,18 @@
 package me.chanjar.weixin.cp.message;
 
+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;
+
+import org.apache.commons.lang3.StringUtils;
+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;
@@ -11,18 +24,6 @@ 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.apache.commons.lang3.StringUtils;
-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;
 
 /**
  * 
@@ -195,6 +196,7 @@ public class WxCpMessageRouter {
               sessionEndAccess(wxMessage);
             } catch (InterruptedException e) {
               WxCpMessageRouter.this.log.error("Error happened when wait task finish", e);
+              Thread.currentThread().interrupt();
             } catch (ExecutionException e) {
               WxCpMessageRouter.this.log.error("Error happened when wait task finish", e);
             }
@@ -207,12 +209,11 @@ public class WxCpMessageRouter {
 
 
   /**
-   * 处理微信消息
+   * 处理微信消息.
    *
-   * @param wxMessage
    */
   public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) {
-    return this.route(wxMessage, new HashMap());
+    return this.route(wxMessage, new HashMap(2));
   }
 
   protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) {
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java
new file mode 100644
index 00000000..0e97181a
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java
@@ -0,0 +1,77 @@
+/*
+ * 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 me.chanjar.weixin.cp.util.json;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+import me.chanjar.weixin.common.util.json.GsonHelper;
+import me.chanjar.weixin.cp.bean.WxCpChat;
+
+/**
+ * 群聊适配器
+ *
+ * @author gaigeshen
+ */
+public class WxCpChatGsonAdapter implements JsonSerializer, JsonDeserializer {
+
+  @Override
+  public JsonElement serialize(WxCpChat chat, Type typeOfSrc, JsonSerializationContext context) {
+    JsonObject json = new JsonObject();
+    if (chat.getId() != null) { 
+      json.addProperty("chatid", chat.getId());
+    }
+    if (chat.getName() != null) {
+      json.addProperty("name", chat.getName());
+    } 
+    if (chat.getOwner() != null) {
+      json.addProperty("owner", chat.getOwner());
+    }
+    if (chat.getUsers() != null) {
+      JsonArray users = new JsonArray();
+      for (String user : chat.getUsers()) {
+        users.add(user);
+      }
+      json.add("userlist", users);
+    }
+    return json;
+  }
+
+  @Override
+  public WxCpChat deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+    JsonObject chatJson = json.getAsJsonObject();
+
+    WxCpChat chat = new WxCpChat();
+    chat.setId(GsonHelper.getAsString(chatJson.get("chatid")));
+    chat.setName(GsonHelper.getAsString(chatJson.get("name")));
+    chat.setOwner(GsonHelper.getAsString(chatJson.get("owner")));
+    
+    JsonArray usersJson = chatJson.getAsJsonArray("userlist");
+    if (usersJson != null) {
+      List users = new ArrayList<>(usersJson.size());
+      chat.setUsers(users);
+      for (JsonElement userJson : usersJson) {
+        users.add(userJson.getAsString());
+      }
+    }
+    
+    return chat;
+  }
+
+}
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 a5a11d24..a999d7b2 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
@@ -8,31 +8,43 @@
  */
 package me.chanjar.weixin.cp.util.json;
 
-import com.google.gson.*;
+import java.lang.reflect.Type;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
 import me.chanjar.weixin.common.util.json.GsonHelper;
 import me.chanjar.weixin.cp.bean.WxCpDepart;
 
-import java.lang.reflect.Type;
-
 /**
+ * WxCpDepart的gson适配器.
+ *
  * @author Daniel Qian
  */
 public class WxCpDepartGsonAdapter implements JsonSerializer, JsonDeserializer {
+  private static final String ID = "id";
+  private static final String NAME = "name";
+  private static final String PARENT_ID = "parentid";
+  private static final String ORDER = "order";
 
   @Override
   public JsonElement serialize(WxCpDepart group, Type typeOfSrc, JsonSerializationContext context) {
     JsonObject json = new JsonObject();
     if (group.getId() != null) {
-      json.addProperty("id", group.getId());
+      json.addProperty(ID, group.getId());
     }
     if (group.getName() != null) {
-      json.addProperty("name", group.getName());
+      json.addProperty(NAME, group.getName());
     }
     if (group.getParentId() != null) {
-      json.addProperty("parentid", group.getParentId());
+      json.addProperty(PARENT_ID, group.getParentId());
     }
     if (group.getOrder() != null) {
-      json.addProperty("order", String.valueOf(group.getOrder()));
+      json.addProperty(ORDER, String.valueOf(group.getOrder()));
     }
     return json;
   }
@@ -42,17 +54,17 @@ public class WxCpDepartGsonAdapter implements JsonSerializer, JsonDe
     throws JsonParseException {
     WxCpDepart depart = new WxCpDepart();
     JsonObject departJson = json.getAsJsonObject();
-    if (departJson.get("id") != null && !departJson.get("id").isJsonNull()) {
-      depart.setId(GsonHelper.getAsInteger(departJson.get("id")));
+    if (departJson.get(ID) != null && !departJson.get(ID).isJsonNull()) {
+      depart.setId(GsonHelper.getAsLong(departJson.get(ID)));
     }
-    if (departJson.get("name") != null && !departJson.get("name").isJsonNull()) {
-      depart.setName(GsonHelper.getAsString(departJson.get("name")));
+    if (departJson.get(NAME) != null && !departJson.get(NAME).isJsonNull()) {
+      depart.setName(GsonHelper.getAsString(departJson.get(NAME)));
     }
-    if (departJson.get("order") != null && !departJson.get("order").isJsonNull()) {
-      depart.setOrder(GsonHelper.getAsLong(departJson.get("order")));
+    if (departJson.get(ORDER) != null && !departJson.get(ORDER).isJsonNull()) {
+      depart.setOrder(GsonHelper.getAsLong(departJson.get(ORDER)));
     }
-    if (departJson.get("parentid") != null && !departJson.get("parentid").isJsonNull()) {
-      depart.setParentId(GsonHelper.getAsInteger(departJson.get("parentid")));
+    if (departJson.get(PARENT_ID) != null && !departJson.get(PARENT_ID).isJsonNull()) {
+      depart.setParentId(GsonHelper.getAsLong(departJson.get(PARENT_ID)));
     }
     return depart;
   }
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 f4dc691e..654d5511 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
@@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder;
 import me.chanjar.weixin.common.bean.menu.WxMenu;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.util.json.WxErrorAdapter;
+import me.chanjar.weixin.cp.bean.WxCpChat;
 import me.chanjar.weixin.cp.bean.WxCpDepart;
 import me.chanjar.weixin.cp.bean.WxCpMessage;
 import me.chanjar.weixin.cp.bean.WxCpTag;
@@ -15,11 +16,12 @@ import me.chanjar.weixin.cp.bean.WxCpUser;
  */
 public class WxCpGsonBuilder {
 
-  public static final GsonBuilder INSTANCE = new GsonBuilder();
+  private static final GsonBuilder INSTANCE = new GsonBuilder();
 
   static {
     INSTANCE.disableHtmlEscaping();
     INSTANCE.registerTypeAdapter(WxCpMessage.class, new WxCpMessageGsonAdapter());
+    INSTANCE.registerTypeAdapter(WxCpChat.class, new WxCpChatGsonAdapter());
     INSTANCE.registerTypeAdapter(WxCpDepart.class, new WxCpDepartGsonAdapter());
     INSTANCE.registerTypeAdapter(WxCpUser.class, new WxCpUserGsonAdapter());
     INSTANCE.registerTypeAdapter(WxError.class, new WxErrorAdapter());
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java
new file mode 100644
index 00000000..8317a45e
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java
@@ -0,0 +1,46 @@
+package me.chanjar.weixin.cp.api.impl;
+
+import java.util.Arrays;
+
+import me.chanjar.weixin.cp.bean.WxCpChat;
+import org.testng.Assert;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import com.google.inject.Inject;
+
+import me.chanjar.weixin.cp.api.ApiTestModule;
+import me.chanjar.weixin.cp.api.WxCpService;
+
+/**
+ * 测试群聊服务
+ *
+ * @author gaigeshen
+ */
+@Guice(modules = ApiTestModule.class)
+public class WxCpChatServiceImplTest {
+
+  @Inject
+  private WxCpService wxCpService;
+  
+  @Test
+  public void create() throws Exception {
+    wxCpService.getChatService().chatCreate("测试群聊", "gaige_shen", Arrays.asList("gaige_shen", "ZhangXiaoMing"), "mychatid");
+  }
+
+  @Test
+  public void get() throws Exception {
+    WxCpChat chat = wxCpService.getChatService().chatGet("mychatid");
+    System.out.println(chat);
+    Assert.assertEquals(chat.getName(), "测试群聊");
+  }
+
+  @Test
+  public void update() throws Exception {
+    wxCpService.getChatService().chatUpdate("mychatid",  "", "", Arrays.asList("ZhengWuYao"), null);
+    WxCpChat chat = wxCpService.getChatService().chatGet("mychatid");
+    System.out.println(chat);
+    Assert.assertEquals(chat.getUsers().size(), 3);
+  }
+
+}
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
index 9a19564c..097a6ee7 100644
--- 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
@@ -1,15 +1,15 @@
 package me.chanjar.weixin.cp.api.impl;
 
+import java.util.List;
+
+import org.testng.annotations.*;
+
 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.WxCpDepart;
-import org.testng.annotations.*;
-
-import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.testng.Assert.*;
 
 /**
  * 
@@ -29,7 +29,7 @@ public class WxCpDepartmentServiceImplTest {
   public void testCreate() throws Exception {
     WxCpDepart cpDepart = new WxCpDepart();
     cpDepart.setName("子部门" + System.currentTimeMillis());
-    cpDepart.setParentId(1);
+    cpDepart.setParentId(1L);
     cpDepart.setOrder(1L);
     Integer departId = this.wxCpService.getDepartmentService().create(cpDepart);
     System.out.println(departId);
@@ -45,7 +45,7 @@ public class WxCpDepartmentServiceImplTest {
   }
 
   @Test(dataProvider = "departIds")
-  public void testList(Integer id) throws Exception {
+  public void testList(Long id) throws Exception {
     System.out.println("=================获取部门");
     List departList = this.wxCpService.getDepartmentService().list(id);
     assertThat(departList).isNotEmpty();
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
index d7242a77..70873c49 100644
--- 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
@@ -36,7 +36,8 @@ public class WxCpMediaServiceImplTest {
   public Object[][] mediaData() {
     return new Object[][]{
       new Object[]{WxConsts.MediaFileType.IMAGE, TestConstants.FILE_JPG, "mm.jpeg"},
-      new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_MP3, "mm.mp3"},//{"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"}
+      //new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_MP3, "mm.mp3"},
+      // {"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"}
       new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_AMR, "mm.amr"},
       new Object[]{WxConsts.MediaFileType.VIDEO, TestConstants.FILE_MP4, "mm.mp4"},
       new Object[]{WxConsts.MediaFileType.FILE, TestConstants.FILE_JPG, "mm.jpeg"}
@@ -47,8 +48,9 @@ public class WxCpMediaServiceImplTest {
   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());
+      assertThat(res).isNotNull();
+      assertThat(res.getType()).isNotEmpty();
+      assertThat(res.getCreatedAt()).isGreaterThan(0);
       assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null);
 
       if (res.getMediaId() != null) {
@@ -70,9 +72,9 @@ public class WxCpMediaServiceImplTest {
   }
 
   @Test(dependsOnMethods = {"testUploadMedia"}, dataProvider = "downloadMedia")
-  public void testDownloadMedia(String media_id) throws WxErrorException {
-    File file = this.wxService.getMediaService().download(media_id);
-    assertNotNull(file);
+  public void testDownload(String mediaId) throws WxErrorException {
+    File file = this.wxService.getMediaService().download(mediaId);
+    assertThat(file).isNotNull();
     System.out.println(file);
   }
 
@@ -82,4 +84,11 @@ public class WxCpMediaServiceImplTest {
     String res = this.wxService.getMediaService().uploadImg(new File(url.getFile()));
     assertThat(res).isNotEmpty();
   }
+
+  @Test
+  public void testGetJssdkFile() throws WxErrorException {
+    File file = this.wxService.getMediaService().getJssdkFile("....");
+    assertThat(file).isNotNull();
+    System.out.println(file);
+  }
 }
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java
index 6b671120..f473fe6b 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java
@@ -74,7 +74,7 @@ public class WxCpUserServiceImplTest {
 
   @Test
   public void testListByDepartment() throws Exception {
-    List users = this.wxCpService.getUserService().listByDepartment(1, true, 0);
+    List users = this.wxCpService.getUserService().listByDepartment(1L, true, 0);
     assertNotEquals(users.size(), 0);
     for (WxCpUser user : users) {
       System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE));
@@ -83,7 +83,7 @@ public class WxCpUserServiceImplTest {
 
   @Test
   public void testListSimpleByDepartment() throws Exception {
-    List users = this.wxCpService.getUserService().listSimpleByDepartment(1, true, 0);
+    List users = this.wxCpService.getUserService().listSimpleByDepartment(1L, 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-miniapp/pom.xml b/weixin-java-miniapp/pom.xml
index 45614761..0e0c45e2 100644
--- a/weixin-java-miniapp/pom.xml
+++ b/weixin-java-miniapp/pom.xml
@@ -6,11 +6,11 @@
   4.0.0
   
     com.github.binarywang
-    weixin-java-parent
-    3.2.0
+    wx-java
+    3.3.0
   
   weixin-java-miniapp
-  Weixin Java Tools - MiniApp
+  WxJava - MiniApp
   微信小程序Java SDK
 
   
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaJsapiService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaJsapiService.java
index 156fcbc1..f81b7c6c 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaJsapiService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaJsapiService.java
@@ -15,7 +15,26 @@ public interface WxMaJsapiService {
   /**
    * 获得jsapi_ticket的url
    */
-  String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
+  String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
+
+  /**
+   * 获得卡券api_ticket,不强制刷新api_ticket
+   *
+   * @see #getJsapiTicket(boolean)
+   */
+  String getCardApiTicket() throws WxErrorException;
+
+  /**
+   * 
+   * 获得卡券api_ticket
+   * 获得时会检查apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
+   *
+   * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
+   * 
+ * + * @param forceRefresh 强制刷新 + */ + String getCardApiTicket(boolean forceRefresh) throws WxErrorException; /** * 获得jsapi_ticket,不强制刷新jsapi_ticket diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java index 29037374..f2c9e8f1 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java @@ -1,10 +1,10 @@ package cn.binarywang.wx.miniapp.api; +import java.io.File; + import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor; import me.chanjar.weixin.common.error.WxErrorException; -import java.io.File; - /** *
  * 二维码相关操作接口.
@@ -32,24 +32,87 @@ public interface WxMaQrcodeService {
    *
    * @param path  不能为空,最大长度 128 字节
    * @param width 默认430 二维码的宽度
+   * @return 文件内容字节数组
+   * @throws WxErrorException 异常
+   */
+  byte[] createQrcodeBytes(String path, int width) throws WxErrorException;
+
+  /**
+   * 接口C: 获取小程序页面二维码.
+   * 
+   * 适用于需要的码数量较少的业务场景
+   * 通过该接口,仅能生成已发布的小程序的二维码。
+   * 可以在开发者工具预览时生成开发版的带参二维码。
+   * 带参二维码只有 100000 个,请谨慎调用。
+   * 
+ * + * @param path 不能为空,最大长度 128 字节 + * @param width 默认430 二维码的宽度 + * @return 文件对象 + * @throws WxErrorException 异常 */ File createQrcode(String path, int width) throws WxErrorException; + /** + * 接口C: 获取小程序页面二维码. + *
+   * 适用于需要的码数量较少的业务场景
+   * 通过该接口,仅能生成已发布的小程序的二维码。
+   * 可以在开发者工具预览时生成开发版的带参二维码。
+   * 带参二维码只有 100000 个,请谨慎调用。
+   * 
+ * + * @param path 不能为空,最大长度 128 字节 + * @return 文件对象 + * @throws WxErrorException 异常 + */ File createQrcode(String path) throws WxErrorException; /** * 接口A: 获取小程序码. * - * @param path 不能为空,最大长度 128 字节 - * @param width 默认430 二维码的宽度 - * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 - * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} - * @param is_hyaline 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码 + * @param path 不能为空,最大长度 128 字节 + * @param width 默认430 二维码的宽度 + * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} + * @param isHyaline 是否需要透明底色, isHyaline 为true时,生成透明底色的小程序码 + * @return 文件内容字节数组 + * @throws WxErrorException 异常 + */ + byte[] createWxaCodeBytes(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) + throws WxErrorException; + + /** + * 接口A: 获取小程序码. + * + * @param path 不能为空,最大长度 128 字节 + * @param width 默认430 二维码的宽度 + * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} + * @param isHyaline 是否需要透明底色, isHyaline 为true时,生成透明底色的小程序码 + * @return 文件对象 + * @throws WxErrorException 异常 */ - File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean is_hyaline) throws WxErrorException; + File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) + throws WxErrorException; + /** + * 接口A: 获取小程序码. + * + * @param path 不能为空,最大长度 128 字节 + * @param width 默认430 二维码的宽度 + * @return 文件对象 + * @throws WxErrorException 异常 + */ File createWxaCode(String path, int width) throws WxErrorException; + /** + * 接口A: 获取小程序码. + * + * @param path 不能为空,最大长度 128 字节 + * @return 文件对象 + * @throws WxErrorException 异常 + */ File createWxaCode(String path) throws WxErrorException; /** @@ -61,15 +124,56 @@ public interface WxMaQrcodeService { * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode *
* - * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~, + * 其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + * @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 + * @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} + * @param isHyaline 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码 + * @return 文件内容字节数组 + * @throws WxErrorException 异常 + */ + byte[] createWxaCodeUnlimitBytes(String scene, String page, int width, boolean autoColor, + WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException; + + /** + * 接口B: 获取小程序码(永久有效、数量暂无限制). + *
+   * 通过该接口生成的小程序码,永久有效,数量暂无限制。
+   * 用户扫描该码进入小程序后,将统一打开首页,开发者需在对应页面根据获取的码中 scene 字段的值,再做处理逻辑。
+   * 使用如下代码可以获取到二维码中的 scene 字段的值。
+   * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode
+   * 
+ * + * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~, + * 其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) * @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 * @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} * @param isHyaline 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码 + * @return 文件对象 + * @throws WxErrorException 异常 */ - File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException; + File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, + WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException; + /** + * 接口B: 获取小程序码(永久有效、数量暂无限制). + *
+   * 通过该接口生成的小程序码,永久有效,数量暂无限制。
+   * 用户扫描该码进入小程序后,将统一打开首页,开发者需在对应页面根据获取的码中 scene 字段的值,再做处理逻辑。
+   * 使用如下代码可以获取到二维码中的 scene 字段的值。
+   * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode
+   * 
+ * + * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~, + * 其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + * @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 + * @return 文件对象 + * @throws WxErrorException 异常 + */ File createWxaCodeUnlimit(String scene, String page) throws WxErrorException; } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaRunService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaRunService.java new file mode 100644 index 00000000..fe764d69 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaRunService.java @@ -0,0 +1,24 @@ +package cn.binarywang.wx.miniapp.api; + +import java.util.List; + +import cn.binarywang.wx.miniapp.bean.WxMaRunStepInfo; + +/** + * 微信运动相关操作接口. + * + * @author Binary Wang + */ +public interface WxMaRunService { + + /** + * 解密分享敏感数据. + * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/werun/wx.getWeRunData.html + * + * @param sessionKey 会话密钥 + * @param encryptedData 消息密文 + * @param ivStr 加密算法的初始向量 + */ + List getRunStepInfo(String sessionKey, String encryptedData, String ivStr); + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSecCheckService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSecCheckService.java new file mode 100644 index 00000000..842d0662 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSecCheckService.java @@ -0,0 +1,43 @@ +package cn.binarywang.wx.miniapp.api; + +import java.io.File; + +import me.chanjar.weixin.common.error.WxErrorException; + +/** + *
+ * 内容安全相关接口.
+ * Created by Binary Wang on 2018/11/24.
+ * 
+ * + * @author Binary Wang + */ +public interface WxMaSecCheckService { + + String IMG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/img_sec_check"; + + String MSG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/msg_sec_check"; + + /** + *
+   * 校验一张图片是否含有违法违规内容.
+   * 应用场景举例:
+   * 1)图片智能鉴黄:涉及拍照的工具类应用(如美拍,识图类应用)用户拍照上传检测;电商类商品上架图片检测;媒体类用户文章里的图片检测等;
+   * 2)敏感人脸识别:用户头像;媒体类用户文章里的图片检测;社交类用户上传的图片检测等。频率限制:单个 appId 调用上限为 1000 次/分钟,100,000 次/天
+   * 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/imgSecCheck.html
+   * 
+ */ + boolean checkImage(File file) throws WxErrorException; + + /** + *
+   * 检查一段文本是否含有违法违规内容。
+   * 应用场景举例:
+   * 用户个人资料违规文字检测;
+   * 媒体新闻类用户发表文章,评论内容检测;
+   * 游戏类用户编辑上传的素材(如答题类小游戏用户上传的问题及答案)检测等。 频率限制:单个 appId 调用上限为 4000 次/分钟,2,000,000 次/天*
+   * 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/msgSecCheck.html
+   * 
+ */ + boolean checkMessage(String msgString); +} 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 index 0904d606..efa53939 100644 --- 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 @@ -1,7 +1,5 @@ package cn.binarywang.wx.miniapp.api; -import java.io.File; - import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.binarywang.wx.miniapp.config.WxMaConfig; import me.chanjar.weixin.common.error.WxErrorException; @@ -20,17 +18,6 @@ public interface WxMaService { String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session"; - String IMG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/img_sec_check"; - - /** - *
-   * 校验一张图片是否含有违法违规内容.
-   * 应用场景举例:1)图片智能鉴黄:涉及拍照的工具类应用(如美拍,识图类应用)用户拍照上传检测;电商类商品上架图片检测;媒体类用户文章里的图片检测等;2)敏感人脸识别:用户头像;媒体类用户文章里的图片检测;社交类用户上传的图片检测等。频率限制:单个 appId 调用上限为 1000 次/分钟,100,000 次/天
-   * 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/imgSecCheck.html
-   * 
- */ - boolean imgSecCheck(File file) throws WxErrorException; - /** * 获取登录后的session信息. * @@ -152,33 +139,51 @@ public interface WxMaService { WxMaTemplateService getTemplateService(); /** - * 数据分析相关查询服务 + * 数据分析相关查询服务. * * @return WxMaAnalysisService */ WxMaAnalysisService getAnalysisService(); /** - * 返回代码操作相关的 API + * 返回代码操作相关的 API. * * @return WxMaCodeService */ WxMaCodeService getCodeService(); /** - * 返回jsapi操作相关的 API服务类对象 + * 返回jsapi操作相关的 API服务类对象. * * @return WxMaJsapiService */ WxMaJsapiService getJsapiService(); /** - * 小程序修改服务器地址、成员管理 API + * 小程序修改服务器地址、成员管理 API. * * @return WxMaSettingService */ WxMaSettingService getSettingService(); + /** + * 返回分享相关查询服务. + * @return WxMaShareService + */ + WxMaShareService getShareService(); + + /** + * 返回微信运动相关接口服务对象. + * @return WxMaShareService + */ + WxMaRunService getRunService(); + + /** + * 返回内容安全相关接口服务对象. + * @return WxMaShareService + */ + WxMaSecCheckService getSecCheckService(); + /** * 初始化http请求对象. */ diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaShareService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaShareService.java new file mode 100644 index 00000000..8c6030e5 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaShareService.java @@ -0,0 +1,21 @@ +package cn.binarywang.wx.miniapp.api; + +import cn.binarywang.wx.miniapp.bean.WxMaShareInfo; + +/** + * 分享信息相关操作接口. + * + * @author zhfish + */ +public interface WxMaShareService { + + /** + * 解密分享敏感数据. + * + * @param sessionKey 会话密钥 + * @param encryptedData 消息密文 + * @param ivStr 加密算法的初始向量 + */ + WxMaShareInfo getShareInfo(String sessionKey, String encryptedData, String ivStr); + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImpl.java index 8164db8b..770e58ae 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImpl.java @@ -28,6 +28,32 @@ public class WxMaJsapiServiceImpl implements WxMaJsapiService { this.wxMaService = wxMaService; } + public String getCardApiTicket() throws WxErrorException { + return getCardApiTicket(false); + } + + public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { + Lock lock = this.wxMaService.getWxMaConfig().getCardApiTicketLock(); + try { + lock.lock(); + if (forceRefresh) { + this.wxMaService.getWxMaConfig().expireCardApiTicket(); + } + + if (this.wxMaService.getWxMaConfig().isCardApiTicketExpired()) { + String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL + "?type=wx_card", 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.wxMaService.getWxMaConfig().updateCardApiTicket(jsapiTicket, expiresInSeconds); + } + } finally { + lock.unlock(); + } + return this.wxMaService.getWxMaConfig().getJsapiTicket(); + } + @Override public String getJsapiTicket() throws WxErrorException { return getJsapiTicket(false); @@ -43,7 +69,7 @@ public class WxMaJsapiServiceImpl implements WxMaJsapiService { } if (this.wxMaService.getWxMaConfig().isJsapiTicketExpired()) { - String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL, null); + String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL + "?type=jsapi", null); JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java index 277418e7..8e7d6b17 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java @@ -1,16 +1,17 @@ package cn.binarywang.wx.miniapp.api.impl; +import java.io.File; + import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor; import cn.binarywang.wx.miniapp.bean.WxMaQrcode; -import cn.binarywang.wx.miniapp.bean.WxMaWxcode; +import cn.binarywang.wx.miniapp.bean.WxaCode; import cn.binarywang.wx.miniapp.bean.WxaCodeUnlimit; -import cn.binarywang.wx.miniapp.util.http.QrCodeRequestExecutor; +import cn.binarywang.wx.miniapp.util.QrcodeBytesRequestExecutor; +import cn.binarywang.wx.miniapp.util.QrcodeRequestExecutor; import me.chanjar.weixin.common.error.WxErrorException; -import java.io.File; - /** * @author Binary Wang */ @@ -21,10 +22,16 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { this.wxMaService = wxMaService; } + @Override + public byte[] createQrcodeBytes(String path, int width) throws WxErrorException { + final QrcodeBytesRequestExecutor executor = new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp()); + return this.wxMaService.execute(executor, CREATE_QRCODE_URL, new WxMaQrcode(path, width)); + } + @Override public File createQrcode(String path, int width) throws WxErrorException { - return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), - CREATE_QRCODE_URL, new WxMaQrcode(path, width)); + final QrcodeRequestExecutor executor = new QrcodeRequestExecutor(this.wxMaService.getRequestHttp()); + return this.wxMaService.execute(executor, CREATE_QRCODE_URL, new WxMaQrcode(path, width)); } @Override @@ -33,15 +40,29 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { } @Override - public File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException { - WxMaWxcode wxMaWxcode = new WxMaWxcode(); - wxMaWxcode.setPath(path); - wxMaWxcode.setWidth(width); - wxMaWxcode.setAutoColor(autoColor); - wxMaWxcode.setLineColor(lineColor); - wxMaWxcode.setHyaline(isHyaline); - return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), - GET_WXACODE_URL, wxMaWxcode); + public byte[] createWxaCodeBytes(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) + throws WxErrorException { + final QrcodeBytesRequestExecutor executor = new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp()); + return this.wxMaService.execute(executor, GET_WXACODE_URL, WxaCode.builder() + .path(path) + .width(width) + .autoColor(autoColor) + .lineColor(lineColor) + .isHyaline(isHyaline) + .build()); + } + + @Override + public File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) + throws WxErrorException { + final QrcodeRequestExecutor executor = new QrcodeRequestExecutor(this.wxMaService.getRequestHttp()); + return this.wxMaService.execute(executor, GET_WXACODE_URL, WxaCode.builder() + .path(path) + .width(width) + .autoColor(autoColor) + .lineColor(lineColor) + .isHyaline(isHyaline) + .build()); } @Override @@ -51,12 +72,27 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { @Override public File createWxaCode(String path) throws WxErrorException { - return this.createWxaCode(path, 430, true, null, false); + return this.createWxaCode(path, 430); } @Override - public File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) - throws WxErrorException { + public byte[] createWxaCodeUnlimitBytes(String scene, String page, int width, boolean autoColor, + WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException { + return this.wxMaService.execute(new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp()), + GET_WXACODE_UNLIMIT_URL, + this.buildWxaCodeUnlimit(scene, page, width, autoColor, lineColor, isHyaline)); + } + + @Override + public File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, + WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException { + return this.wxMaService.execute(new QrcodeRequestExecutor(this.wxMaService.getRequestHttp()), + GET_WXACODE_UNLIMIT_URL, + this.buildWxaCodeUnlimit(scene, page, width, autoColor, lineColor, isHyaline)); + } + + private WxaCodeUnlimit buildWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, + WxMaCodeLineColor lineColor, boolean isHyaline) { WxaCodeUnlimit wxaCodeUnlimit = new WxaCodeUnlimit(); wxaCodeUnlimit.setScene(scene); wxaCodeUnlimit.setPage(page); @@ -64,8 +100,8 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { wxaCodeUnlimit.setAutoColor(autoColor); wxaCodeUnlimit.setLineColor(lineColor); wxaCodeUnlimit.setHyaline(isHyaline); - return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), - GET_WXACODE_UNLIMIT_URL, wxaCodeUnlimit); + + return wxaCodeUnlimit; } @Override diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaRunServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaRunServiceImpl.java new file mode 100644 index 00000000..9ddad0d3 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaRunServiceImpl.java @@ -0,0 +1,29 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import java.util.List; + +import cn.binarywang.wx.miniapp.api.WxMaRunService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaRunStepInfo; +import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; + +/** + *
+ *
+ * Created by Binary Wang on 2018/11/4.
+ * 
+ * + * @author Binary Wang + */ +public class WxMaRunServiceImpl implements WxMaRunService { + private WxMaService service; + + public WxMaRunServiceImpl(WxMaService service) { + this.service = service; + } + + @Override + public List getRunStepInfo(String sessionKey, String encryptedData, String ivStr) { + return WxMaRunStepInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImpl.java new file mode 100644 index 00000000..1dab0a82 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImpl.java @@ -0,0 +1,48 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import java.io.File; + +import cn.binarywang.wx.miniapp.api.WxMaSecCheckService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import com.google.gson.JsonObject; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; + +/** + *
+ *
+ * Created by Binary Wang on 2018/11/24.
+ * 
+ * + * @author Binary Wang + */ +public class WxMaSecCheckServiceImpl implements WxMaSecCheckService { + private WxMaService service; + + public WxMaSecCheckServiceImpl(WxMaService service) { + this.service = service; + } + + @Override + public boolean checkImage(File file) throws WxErrorException { + //这里只是借用MediaUploadRequestExecutor,并不使用其返回值WxMediaUploadResult + WxMediaUploadResult result = this.service.execute(MediaUploadRequestExecutor + .create(this.service.getRequestHttp()), IMG_SEC_CHECK_URL, file); + return result != null; + } + + @Override + public boolean checkMessage(String msgString) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("content", msgString); + try { + this.service.post(MSG_SEC_CHECK_URL, jsonObject.toString()); + } catch (WxErrorException e) { + return false; + } + + return true; + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java index 9c8ac82d..280a052e 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java @@ -1,6 +1,5 @@ package cn.binarywang.wx.miniapp.api.impl; -import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -12,8 +11,6 @@ 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 cn.binarywang.wx.miniapp.api.WxMaAnalysisService; import cn.binarywang.wx.miniapp.api.WxMaCodeService; @@ -21,22 +18,24 @@ import cn.binarywang.wx.miniapp.api.WxMaJsapiService; import cn.binarywang.wx.miniapp.api.WxMaMediaService; import cn.binarywang.wx.miniapp.api.WxMaMsgService; import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; +import cn.binarywang.wx.miniapp.api.WxMaRunService; +import cn.binarywang.wx.miniapp.api.WxMaSecCheckService; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.WxMaSettingService; +import cn.binarywang.wx.miniapp.api.WxMaShareService; import cn.binarywang.wx.miniapp.api.WxMaTemplateService; import cn.binarywang.wx.miniapp.api.WxMaUserService; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.binarywang.wx.miniapp.config.WxMaConfig; import com.google.common.base.Joiner; import com.google.gson.Gson; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.DataUtils; import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.common.util.http.HttpType; -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.common.util.http.SimpleGetRequestExecutor; @@ -49,9 +48,8 @@ import static cn.binarywang.wx.miniapp.constant.WxMaConstants.ErrorCode.*; /** * @author Binary Wang */ +@Slf4j public class WxMaServiceImpl implements WxMaService, RequestHttp { - private final Logger log = LoggerFactory.getLogger(this.getClass()); - private CloseableHttpClient httpClient; private HttpHost httpProxy; private WxMaConfig wxMaConfig; @@ -65,6 +63,9 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp this.maxRetryTimes) { - this.log.warn("重试达到最大次数【{}】", maxRetryTimes); + log.warn("重试达到最大次数【{}】", maxRetryTimes); //最后一次重试失败后,直接抛出异常,不再等待 throw new RuntimeException("微信服务端异常,超出重试次数"); } @@ -215,10 +209,10 @@ public class WxMaServiceImpl implements WxMaService, RequestHttpBinary Wang + */ +@Data +public class WxMaRunStepInfo implements Serializable { + private static final JsonParser JSON_PARSER = new JsonParser(); + private static final long serialVersionUID = -7496372171398607044L; + + /** + * 时间戳,表示数据对应的时间. + */ + private Long timestamp; + + /** + * 微信运动步数. + */ + private Integer step; + + public static List fromJson(String json) { + JsonObject jsonObject = JSON_PARSER.parse(json).getAsJsonObject(); + return WxMaGsonBuilder.create().fromJson(jsonObject.get("stepInfoList").toString(), + new TypeToken>() { + }.getType()); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaShareInfo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaShareInfo.java new file mode 100644 index 00000000..91aff519 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaShareInfo.java @@ -0,0 +1,20 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author zhfish + */ +@Data +public class WxMaShareInfo implements Serializable { + private static final long serialVersionUID = -8053613683499632226L; + + private String openGId; + + public static WxMaShareInfo fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxMaShareInfo.class); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcode.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxaCode.java similarity index 62% rename from weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcode.java rename to weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxaCode.java index e538a1bb..2d94f05c 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcode.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxaCode.java @@ -1,36 +1,48 @@ package cn.binarywang.wx.miniapp.bean; +import java.io.Serializable; + import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; - -import java.io.Serializable; +import lombok.NoArgsConstructor; /** + * 小程序码. * * @author Element * @date 2017/7/27 */ @Data @EqualsAndHashCode(callSuper = false) -public class WxMaWxcode extends AbstractWxMaQrcodeWrapper implements Serializable { +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxaCode extends AbstractWxMaQrcodeWrapper implements Serializable { private static final long serialVersionUID = 1287399621649210322L; private String path; + + @Builder.Default private int width = 430; @SerializedName("auto_color") + @Builder.Default private boolean autoColor = true; @SerializedName("is_hyaline") + @Builder.Default private boolean isHyaline = false; @SerializedName("line_color") + @Builder.Default private WxMaCodeLineColor lineColor = new WxMaCodeLineColor("0", "0", "0"); - public static WxMaWxcode fromJson(String json) { - return WxMaGsonBuilder.create().fromJson(json, WxMaWxcode.class); + public static WxaCode fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxaCode.class); } } 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 index 915cffdd..49a80cc4 100644 --- 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 @@ -1,10 +1,10 @@ package cn.binarywang.wx.miniapp.config; +import java.util.concurrent.locks.Lock; + import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; -import java.util.concurrent.locks.Lock; - /** * 小程序配置 * @@ -57,6 +57,28 @@ public interface WxMaConfig { */ void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); + /** + * 卡券api_ticket. + */ + String getCardApiTicket(); + + Lock getCardApiTicketLock(); + + boolean isCardApiTicketExpired(); + + /** + * 强制将卡券api ticket过期掉. + */ + void expireCardApiTicket(); + + /** + * 应该是线程安全的. + * + * @param apiTicket 新的卡券api ticket值 + * @param expiresInSeconds 过期时间,以秒为单位 + */ + void updateCardApiTicket(String apiTicket, int expiresInSeconds); + String getAppid(); String getSecret(); 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 index d8e286af..a0e53262 100644 --- 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 @@ -4,9 +4,7 @@ import java.io.File; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; @@ -32,8 +30,14 @@ public class WxMaInMemoryConfig implements WxMaConfig { protected volatile String jsapiTicket; protected volatile long jsapiTicketExpiresTime; + //微信卡券的ticket单独缓存 + protected volatile String cardApiTicket; + protected volatile long cardApiTicketExpiresTime; + + protected Lock accessTokenLock = new ReentrantLock(); protected Lock jsapiTicketLock = new ReentrantLock(); + protected Lock cardApiTicketLock = new ReentrantLock(); /** * 临时文件目录 @@ -103,6 +107,34 @@ public class WxMaInMemoryConfig implements WxMaConfig { this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; } + + @Override + public String getCardApiTicket() { + return this.cardApiTicket; + } + + @Override + public Lock getCardApiTicketLock() { + return this.cardApiTicketLock; + } + + @Override + public boolean isCardApiTicketExpired() { + return System.currentTimeMillis() > this.cardApiTicketExpiresTime; + } + + @Override + public void expireCardApiTicket() { + this.cardApiTicketExpiresTime = 0; + } + + @Override + public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { + this.cardApiTicket = cardApiTicket; + // 预留200秒的时间 + this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + } + @Override public void expireAccessToken() { this.expiresTime = 0; @@ -191,7 +223,7 @@ public class WxMaInMemoryConfig implements WxMaConfig { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMaGsonBuilder.create().toJson(this); } @Override diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeBytesRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeBytesRequestExecutor.java new file mode 100644 index 00000000..5421aea3 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeBytesRequestExecutor.java @@ -0,0 +1,66 @@ +package cn.binarywang.wx.miniapp.util; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +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 cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; + +/** + * @author Binary Wang + */ +public class QrcodeBytesRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; + + public QrcodeBytesRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } + + @Override + public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + + @Override + public byte[] execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + httpPost.setConfig( + RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build() + ); + } + + httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson())); + + try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); + final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0 + && ContentType.APPLICATION_JSON.getMimeType() + .equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + + return IOUtils.toByteArray(inputStream); + } finally { + httpPost.releaseConnection(); + } + } +} 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/QrcodeRequestExecutor.java similarity index 71% rename from weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java rename to weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeRequestExecutor.java index cb8097db..672f97a0 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeRequestExecutor.java @@ -1,13 +1,10 @@ -package cn.binarywang.wx.miniapp.util.http; +package cn.binarywang.wx.miniapp.util; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; -import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper; -import me.chanjar.weixin.common.error.WxError; -import me.chanjar.weixin.common.error.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; @@ -17,33 +14,44 @@ 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; +import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.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.ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; /** * @author Binary Wang */ -public class QrCodeRequestExecutor implements RequestExecutor { +public class QrcodeRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; - public QrCodeRequestExecutor(RequestHttp requestHttp) { + public QrcodeRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } @Override - public File execute(String uri, AbstractWxMaQrcodeWrapper ticket) throws WxErrorException, IOException { + public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + + @Override + public File execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper) 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.toJson())); - try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); - InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson())); + + try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); + final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) { Header[] contentTypeHeader = response.getHeaders("Content-Type"); if (contentTypeHeader != null && contentTypeHeader.length > 0 && ContentType.APPLICATION_JSON.getMimeType() diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java index ae2e8d8f..e73fec42 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java @@ -7,6 +7,9 @@ import org.testng.annotations.*; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.test.ApiTestModule; import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxErrorException; + +import static org.assertj.core.api.Assertions.assertThat; /** * @author Binary Wang @@ -18,21 +21,38 @@ public class WxMaQrcodeServiceImplTest { private WxMaService wxService; @Test - public void testCreateQrCode() throws Exception { + public void testCreateQrcode() throws Exception { final File qrCode = this.wxService.getQrcodeService().createQrcode("111", 122); - System.out.println(qrCode); + assertThat(qrCode).isNotNull(); } @Test public void testCreateWxaCode() throws Exception { final File wxCode = this.wxService.getQrcodeService().createWxaCode("111", 122); - System.out.println(wxCode); + assertThat(wxCode).isNotNull(); } @Test public void testCreateWxaCodeUnlimit() throws Exception { final File wxCode = this.wxService.getQrcodeService().createWxaCodeUnlimit("111", null); - System.out.println(wxCode); + assertThat(wxCode).isNotNull(); } + @Test + public void testCreateQrcodeBytes() throws WxErrorException { + final byte[] qrCode = this.wxService.getQrcodeService().createQrcodeBytes("111", 122); + assertThat(qrCode).isNotNull(); + } + + @Test + public void testCreateWxaCodeBytes() throws WxErrorException { + final byte[] wxCode = this.wxService.getQrcodeService().createWxaCodeBytes("111", 122, true, null, false); + assertThat(wxCode).isNotNull(); + } + + @Test + public void testCreateWxaCodeUnlimitBytes() throws WxErrorException { + final byte[] wxCode = this.wxService.getQrcodeService().createWxaCodeUnlimitBytes("111", null, 122, true, null, false); + assertThat(wxCode).isNotNull(); + } } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImplTest.java new file mode 100644 index 00000000..df9ccaa8 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImplTest.java @@ -0,0 +1,51 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import java.io.File; + +import org.testng.annotations.*; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxErrorException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.testng.Assert.*; + +/** + *
+ *
+ * Created by Binary Wang on 2018/11/24.
+ * 
+ * + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaSecCheckServiceImplTest { + @Inject + private WxMaService wxService; + + @Test + public void testCheckImage() throws WxErrorException { + boolean result = this.wxService.getSecCheckService() + .checkImage(new File(ClassLoader.getSystemResource("tmp.png").getFile())); + assertTrue(result); + } + + @DataProvider + public Object[][] secData() { + return new Object[][]{ + {"特3456书yuuo莞6543李zxcz蒜7782法fgnv级", false}, + {"完2347全dfji试3726测asad感3847知qwez到", false}, + {"hello world!", true} + }; + } + + @Test(dataProvider = "secData") + public void testCheckMessage(String msg, boolean result) { + assertThat(this.wxService.getSecCheckService() + .checkMessage(msg)) + .isEqualTo(result); + } +} 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 index dcefc68c..1f87c7e4 100644 --- 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 @@ -33,9 +33,4 @@ public class WxMaServiceImplTest { assertTrue(StringUtils.isNotBlank(after)); } - @Test - public void testImgSecCheck() throws WxErrorException { - boolean result = this.wxService.imgSecCheck(new File(ClassLoader.getSystemResource("tmp.png").getFile())); - assertTrue(result); - } } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaShareServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaShareServiceImplTest.java new file mode 100644 index 00000000..abd92bb7 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaShareServiceImplTest.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.WxMaPhoneNumberInfo; +import cn.binarywang.wx.miniapp.bean.WxMaShareInfo; +import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import cn.binarywang.wx.miniapp.test.TestConfig; +import com.google.common.collect.ImmutableMap; +import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxErrorException; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +/** + * 测试分享相关的接口 + * + * @author zhfish + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaShareServiceImplTest { + + @Inject + private WxMaService wxService; + + @Test + public void testGetSessionKey() throws Exception { + assertNotNull(this.wxService.getUserService().getSessionInfo("aaa")); + } + + /** + * TODO 测试数据有问题,需要替换为正确的数据 + */ + @Test + public void testGetShareInfo() { + WxMaShareInfo shareInfo = this.wxService.getShareService().getShareInfo("tiihtNczf5v6AKRyjwEUhQ==", + "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew==", + "r7BXXKkLb8qrSNn05n0qiA=="); + assertNotNull(shareInfo); + System.out.println(shareInfo.toString()); + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaRunStepInfoTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaRunStepInfoTest.java new file mode 100644 index 00000000..ef09e073 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaRunStepInfoTest.java @@ -0,0 +1,43 @@ +package cn.binarywang.wx.miniapp.bean; + +import java.util.List; + +import org.testng.annotations.*; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.testng.Assert.*; + +/** + *
+ *
+ * Created by Binary Wang on 2018/11/4.
+ * 
+ * + * @author Binary Wang + */ +public class WxMaRunStepInfoTest { + + @Test + public void testFromJson() { + // 数据来源:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/werun/wx.getWeRunData.html + String json = "{\n" + + " \"stepInfoList\": [\n" + + " {\n" + + " \"timestamp\": 1445866601,\n" + + " \"step\": 100\n" + + " },\n" + + " {\n" + + " \"timestamp\": 1445876601,\n" + + " \"step\": 120\n" + + " }\n" + + " ]\n" + + "}"; + + final List stepInfoList = WxMaRunStepInfo.fromJson(json); + assertThat(stepInfoList).isNotEmpty(); + assertThat(stepInfoList.get(0).getStep()).isEqualTo(100); + assertThat(stepInfoList.get(0).getTimestamp()).isEqualTo(1445866601); + assertThat(stepInfoList.get(1).getStep()).isEqualTo(120); + assertThat(stepInfoList.get(1).getTimestamp()).isEqualTo(1445876601); + } +} diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 8441e4cd..90cb71c8 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -6,11 +6,11 @@ 4.0.0 com.github.binarywang - weixin-java-parent - 3.2.0 + wx-java + 3.3.0 weixin-java-mp - Weixin Java Tools - MP + WxJava - MP 微信公众号Java SDK @@ -36,6 +36,11 @@ testng test + + org.mockito + mockito-all + test + com.google.inject guice diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java index 1e9c8e02..74b905d6 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.AiLangType; +import me.chanjar.weixin.mp.enums.AiLangType; import java.io.File; 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 1ad01eea..af6cefcf 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 @@ -21,8 +21,8 @@ public interface WxMpCardService { String CARD_CODE_CONSUME = "https://api.weixin.qq.com/card/code/consume"; String CARD_CODE_MARK = "https://api.weixin.qq.com/card/code/mark"; String CARD_TEST_WHITELIST = "https://api.weixin.qq.com/card/testwhitelist/set"; - String CARD_QRCODE_CREAET = "https://api.weixin.qq.com/card/qrcode/create"; - String CARD_LANDING_PAGE_CREAET = "https://api.weixin.qq.com/card/landingpage/create"; + String CARD_QRCODE_CREATE = "https://api.weixin.qq.com/card/qrcode/create"; + String CARD_LANDING_PAGE_CREATE = "https://api.weixin.qq.com/card/landingpage/create"; /** * 将用户的卡券设置为失效状态 */ 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 ea21c80b..d51ea88b 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,13 +1,14 @@ package me.chanjar.weixin.mp.api; -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; - import java.io.File; import java.util.concurrent.locks.Lock; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.mp.enums.TicketType; + /** - * 微信客户端配置存储 + * 微信客户端配置存储. * * @author chanjarster */ @@ -20,62 +21,45 @@ public interface WxMpConfigStorage { boolean isAccessTokenExpired(); /** - * 强制将access token过期掉 + * 强制将access token过期掉. */ void expireAccessToken(); /** - * 应该是线程安全的 + * 应该是线程安全的. * * @param accessToken 要更新的WxAccessToken对象 */ void updateAccessToken(WxAccessToken accessToken); /** - * 应该是线程安全的 + * 应该是线程安全的. * * @param accessToken 新的accessToken值 * @param expiresInSeconds 过期时间,以秒为单位 */ void updateAccessToken(String accessToken, int expiresInSeconds); - String getJsapiTicket(); - - Lock getJsapiTicketLock(); - - boolean isJsapiTicketExpired(); - - /** - * 强制将jsapi ticket过期掉 - */ - void expireJsapiTicket(); - - /** - * 应该是线程安全的 - * - * @param jsapiTicket 新的jsapi ticket值 - * @param expiresInSeconds 过期时间,以秒为单位 - */ - void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); - - String getCardApiTicket(); + String getTicket(TicketType type); - Lock getCardApiTicketLock(); + Lock getTicketLock(TicketType type); - boolean isCardApiTicketExpired(); + boolean isTicketExpired(TicketType type); /** - * 强制将卡券api ticket过期掉 + * 强制将ticket过期掉. */ - void expireCardApiTicket(); + void expireTicket(TicketType type); /** + * 更新ticket. * 应该是线程安全的 * - * @param cardApiTicket 新的cardApi ticket值 + * @param type ticket类型 + * @param ticket 新的ticket值 * @param expiresInSeconds 过期时间,以秒为单位 */ - void updateCardApiTicket(String cardApiTicket, int expiresInSeconds); + void updateTicket(TicketType type, String ticket, int expiresInSeconds); String getAppId(); @@ -102,14 +86,14 @@ public interface WxMpConfigStorage { File getTmpDirFile(); /** - * http client builder + * http client builder. * * @return ApacheHttpClientBuilder */ ApacheHttpClientBuilder getApacheHttpClientBuilder(); /** - * 是否自动刷新token + * 是否自动刷新token. */ boolean autoRefreshToken(); 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 eb15cd0f..4f24b167 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 @@ -1,21 +1,24 @@ package me.chanjar.weixin.mp.api; import java.io.File; +import java.io.Serializable; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - +import lombok.Data; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.mp.enums.TicketType; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 + * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化. * * @author chanjarster */ -public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { +@Data +public class WxMpInMemoryConfigStorage implements WxMpConfigStorage, Serializable { + private static final long serialVersionUID = -6646519023303395185L; protected volatile String appId; protected volatile String secret; @@ -35,34 +38,21 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { protected volatile String jsapiTicket; protected volatile long jsapiTicketExpiresTime; + protected volatile String sdkTicket; + protected volatile long sdkTicketExpiresTime; + protected volatile String cardApiTicket; protected volatile long cardApiTicketExpiresTime; protected Lock accessTokenLock = new ReentrantLock(); protected Lock jsapiTicketLock = new ReentrantLock(); + protected Lock sdkTicketLock = new ReentrantLock(); protected Lock cardApiTicketLock = 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; - } - @Override public boolean isAccessTokenExpired() { return System.currentTimeMillis() > this.expiresTime; @@ -85,206 +75,103 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { } @Override - public String getJsapiTicket() { - return this.jsapiTicket; - } - - public void setJsapiTicket(String jsapiTicket) { - this.jsapiTicket = jsapiTicket; - } - - @Override - public Lock getJsapiTicketLock() { - return this.jsapiTicketLock; - } - - @Override - public boolean isJsapiTicketExpired() { - return System.currentTimeMillis() > this.jsapiTicketExpiresTime; - } - - @Override - public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { - this.jsapiTicket = jsapiTicket; - // 预留200秒的时间 - this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; - } - - @Override - public void expireJsapiTicket() { - this.jsapiTicketExpiresTime = 0; - } - - /** - * 卡券api_ticket - */ - @Override - public String getCardApiTicket() { - return this.cardApiTicket; - } - - public void setCardApiTicket(String cardApiTicket) { - this.cardApiTicket = cardApiTicket; - } - - @Override - public Lock getCardApiTicketLock() { - return this.cardApiTicketLock; - } - - @Override - public boolean isCardApiTicketExpired() { - return System.currentTimeMillis() > this.cardApiTicketExpiresTime; - } - - @Override - public synchronized void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { - this.cardApiTicket = cardApiTicket; - // 预留200秒的时间 - this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; - } - - @Override - public void expireCardApiTicket() { - this.cardApiTicketExpiresTime = 0; - } - - @Override - public String getAppId() { - return this.appId; - } - - public void setAppId(String appId) { - this.appId = appId; - } - - @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 String getTemplateId() { - return this.templateId; - } - - public void setTemplateId(String templateId) { - this.templateId = templateId; - } - - @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 getOauth2redirectUri() { - return this.oauth2redirectUri; - } - - public void setOauth2redirectUri(String oauth2redirectUri) { - this.oauth2redirectUri = oauth2redirectUri; - } - - @Override - public String getHttpProxyHost() { - return this.httpProxyHost; - } - - public void setHttpProxyHost(String httpProxyHost) { - this.httpProxyHost = httpProxyHost; - } - - @Override - public int getHttpProxyPort() { - return this.httpProxyPort; - } - - public void setHttpProxyPort(int httpProxyPort) { - this.httpProxyPort = httpProxyPort; - } - - @Override - public String getHttpProxyUsername() { - return this.httpProxyUsername; - } - - public void setHttpProxyUsername(String httpProxyUsername) { - this.httpProxyUsername = httpProxyUsername; - } - - @Override - public String getHttpProxyPassword() { - return this.httpProxyPassword; - } - - public void setHttpProxyPassword(String httpProxyPassword) { - this.httpProxyPassword = httpProxyPassword; + public String getTicket(TicketType type) { + switch (type) { + case SDK: + return this.sdkTicket; + case JSAPI: + return this.jsapiTicket; + case WX_CARD: + return this.cardApiTicket; + default: + return null; + } + } + + public void setTicket(TicketType type, String ticket) { + switch (type) { + case JSAPI: + this.jsapiTicket = ticket; + break; + case WX_CARD: + this.cardApiTicket = ticket; + break; + case SDK: + this.sdkTicket = ticket; + break; + default: + } + } + + @Override + public Lock getTicketLock(TicketType type) { + switch (type) { + case SDK: + return this.sdkTicketLock; + case JSAPI: + return this.jsapiTicketLock; + case WX_CARD: + return this.cardApiTicketLock; + default: + return null; + } + } + + @Override + public boolean isTicketExpired(TicketType type) { + switch (type) { + case SDK: + return System.currentTimeMillis() > this.sdkTicketExpiresTime; + case JSAPI: + return System.currentTimeMillis() > this.jsapiTicketExpiresTime; + case WX_CARD: + return System.currentTimeMillis() > this.cardApiTicketExpiresTime; + default: + return false; + } + } + + @Override + public synchronized void updateTicket(TicketType type, String ticket, int expiresInSeconds) { + switch (type) { + case JSAPI: + this.jsapiTicket = ticket; + // 预留200秒的时间 + this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + break; + case WX_CARD: + this.cardApiTicket = ticket; + // 预留200秒的时间 + this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + break; + case SDK: + this.sdkTicket = ticket; + // 预留200秒的时间 + this.sdkTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + break; + default: + } + } + + @Override + public void expireTicket(TicketType type) { + switch (type) { + case JSAPI: + this.jsapiTicketExpiresTime = 0; + break; + case WX_CARD: + this.cardApiTicketExpiresTime = 0; + break; + case SDK: + this.sdkTicketExpiresTime = 0; + break; + default: + } } @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); - } - - @Override - public File getTmpDirFile() { - return this.tmpDirFile; - } - - public void setTmpDirFile(File tmpDirFile) { - this.tmpDirFile = tmpDirFile; - } - - @Override - public ApacheHttpClientBuilder getApacheHttpClientBuilder() { - return this.apacheHttpClientBuilder; - } - - public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { - this.apacheHttpClientBuilder = apacheHttpClientBuilder; - } - - public long getJsapiTicketExpiresTime() { - return this.jsapiTicketExpiresTime; - } - - public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) { - this.jsapiTicketExpiresTime = jsapiTicketExpiresTime; - } - - public long getCardApiTicketExpiresTime() { - return this.cardApiTicketExpiresTime; - } - - public void setCardApiTicketExpiresTime(long cardApiTicketExpiresTime) { - this.cardApiTicketExpiresTime = cardApiTicketExpiresTime; + return WxMpGsonBuilder.create().toJson(this); } @Override 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 e20d1e3f..b1ff3f1f 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 @@ -1,51 +1,45 @@ package me.chanjar.weixin.mp.api; +import me.chanjar.weixin.mp.enums.TicketType; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; /** - * 基于Redis的微信配置provider + * 基于Redis的微信配置provider. + * *
  *    使用说明:本实现仅供参考,并不完整,
  *    比如为减少项目依赖,未加入redis分布式锁的实现,如有需要请自行实现。
  * 
+ * * @author nickwong */ @SuppressWarnings("hiding") public class WxMpInRedisConfigStorage extends WxMpInMemoryConfigStorage { - - private final static String ACCESS_TOKEN_KEY = "wechat_access_token_"; - - private final static String JSAPI_TICKET_KEY = "wechat_jsapi_ticket_"; - - private final static String CARDAPI_TICKET_KEY = "wechat_cardapi_ticket_"; + private static final String ACCESS_TOKEN_KEY = "wx:access_token:"; /** - * 使用连接池保证线程安全 + * 使用连接池保证线程安全. */ protected final JedisPool jedisPool; private String accessTokenKey; - private String jsapiTicketKey; - - private String cardapiTicketKey; - public WxMpInRedisConfigStorage(JedisPool jedisPool) { this.jedisPool = jedisPool; } /** - * 每个公众号生成独有的存储key - * - * @param appId + * 每个公众号生成独有的存储key. */ @Override public void setAppId(String appId) { super.setAppId(appId); this.accessTokenKey = ACCESS_TOKEN_KEY.concat(appId); - this.jsapiTicketKey = JSAPI_TICKET_KEY.concat(appId); - this.cardapiTicketKey = CARDAPI_TICKET_KEY.concat(appId); + } + + private String getTicketRedisKey(TicketType type) { + return String.format("wx:ticket:key:%s:%s", this.appId, type.getCode()); } @Override @@ -77,58 +71,31 @@ public class WxMpInRedisConfigStorage extends WxMpInMemoryConfigStorage { } @Override - public String getJsapiTicket() { - try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.get(this.jsapiTicketKey); - } - } - - @Override - public boolean isJsapiTicketExpired() { - try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.ttl(this.jsapiTicketKey) < 2; - } - } - - @Override - public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { + public String getTicket(TicketType type) { try (Jedis jedis = this.jedisPool.getResource()) { - jedis.setex(this.jsapiTicketKey, expiresInSeconds - 200, jsapiTicket); + return jedis.get(this.getTicketRedisKey(type)); } } @Override - public void expireJsapiTicket() { + public boolean isTicketExpired(TicketType type) { try (Jedis jedis = this.jedisPool.getResource()) { - jedis.expire(this.jsapiTicketKey, 0); + return jedis.ttl(this.getTicketRedisKey(type)) < 2; } } @Override - public String getCardApiTicket() { + public synchronized void updateTicket(TicketType type, String jsapiTicket, int expiresInSeconds) { try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.get(this.cardapiTicketKey); + jedis.setex(this.getTicketRedisKey(type), expiresInSeconds - 200, jsapiTicket); } } @Override - public boolean isCardApiTicketExpired() { + public void expireTicket(TicketType type) { try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.ttl(this.cardapiTicketKey) < 2; + jedis.expire(this.getTicketRedisKey(type), 0); } } - @Override - public synchronized void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.setex(this.cardapiTicketKey, expiresInSeconds - 200, cardApiTicket); - } - } - - @Override - public void expireCardApiTicket() { - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.expire(this.cardapiTicketKey, 0); - } - } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java index d9bbdfbc..b0719804 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java @@ -1,13 +1,20 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.card.CardUpdateResult; import me.chanjar.weixin.mp.bean.card.MemberCardActivateUserFormRequest; import me.chanjar.weixin.mp.bean.card.MemberCardActivateUserFormResult; +import me.chanjar.weixin.mp.bean.card.MemberCardUpdateRequest; import me.chanjar.weixin.mp.bean.card.WxMpCardCreateResult; -import me.chanjar.weixin.mp.bean.membercard.*; +import me.chanjar.weixin.mp.bean.membercard.ActivatePluginParam; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardActivatedMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardCreateMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateResult; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult; /** - * 会员卡相关接口 + * 会员卡相关接口. * * @author YuJian(mgcnrx11 @ gmail.com) * @author yuanqixun @@ -20,35 +27,38 @@ public interface WxMpMemberCardService { String MEMBER_CARD_USER_INFO_GET = "https://api.weixin.qq.com/card/membercard/userinfo/get"; String MEMBER_CARD_UPDATE_USER = "https://api.weixin.qq.com/card/membercard/updateuser"; /** - * 会员卡激活之微信开卡接口(wx_activate=true情况调用) + * 会员卡激活之微信开卡接口(wx_activate=true情况调用). */ String MEMBER_CARD_ACTIVATEUSERFORM = "https://api.weixin.qq.com/card/membercard/activateuserform/set"; /** - * 得到WxMpService + * 获取会员卡开卡插件参数. + */ + String MEMBER_CARD_ACTIVATE_URL = "https://api.weixin.qq.com/card/membercard/activate/geturl"; + + /** + * 会员卡信息更新. + */ + String MEMBER_CARD_UPDATE = "https://api.weixin.qq.com/card/update"; + + + /** + * 得到WxMpService. */ WxMpService getWxMpService(); /** - * 会员卡创建接口 - * - * @param createJson - * @return - * @throws WxErrorException + * 会员卡创建接口. */ WxMpCardCreateResult createMemberCard(String createJson) throws WxErrorException; /** - * 会员卡创建接口 - * - * @param createMessageMessage - * @return WxMpCardCreateResult - * @throws WxErrorException + * 会员卡创建接口. */ WxMpCardCreateResult createMemberCard(WxMpMemberCardCreateMessage createMessageMessage) throws WxErrorException; /** - * 会员卡激活接口 + * 会员卡激活接口. * * @param activatedMessage 激活所需参数 * @return 返回json字符串 @@ -57,7 +67,7 @@ public interface WxMpMemberCardService { String activateMemberCard(WxMpMemberCardActivatedMessage activatedMessage) throws WxErrorException; /** - * 拉取会员信息接口 + * 拉取会员信息接口. * * @param cardId 会员卡的CardId,微信分配 * @param code 领取会员的会员卡Code @@ -67,10 +77,10 @@ public interface WxMpMemberCardService { WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) throws WxErrorException; /** - * 当会员持卡消费后,支持开发者调用该接口更新会员信息。会员卡交易后的每次信息变更需通过该接口通知微信,便于后续消息通知及其他扩展功能。 - *

- * 1.开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。同时传入add_bonus和bonus时 - * add_bonus作为积分变动消息中的变量值,而bonus作为卡面上的总积分额度显示。余额变动同理。 + * 当会员持卡消费后,支持开发者调用该接口更新会员信息. + * 会员卡交易后的每次信息变更需通过该接口通知微信,便于后续消息通知及其他扩展功能。 + * 1.开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。 + * 同时传入add_bonus和bonus时 add_bonus作为积分变动消息中的变量值,而bonus作为卡面上的总积分额度显示。余额变动同理。 * 2.开发者可以传入is_notify_bonus控制特殊的积分对账变动不发送消息,余额变动同理。 * * @param updateUserMessage 更新会员信息所需字段消息 @@ -80,12 +90,17 @@ public interface WxMpMemberCardService { WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessage updateUserMessage) throws WxErrorException; /** - * 设置会员卡激活的字段(会员卡设置:wx_activate=true 时需要) - * - * @param userFormRequest - * @return - * @throws WxErrorException + * 设置会员卡激活的字段(会员卡设置:wx_activate=true 时需要). */ MemberCardActivateUserFormResult setActivateUserForm(MemberCardActivateUserFormRequest userFormRequest) throws WxErrorException; + /** + * 获取会员卡开卡插件参数(跳转型开卡组件需要参数). + */ + ActivatePluginParam getActivatePluginParam(String cardId, String outStr) throws WxErrorException; + + /** + * 更新会员卡信息. + */ + CardUpdateResult updateCardInfo(MemberCardUpdateRequest memberCardUpdateRequest) throws WxErrorException; } 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 8350593a..e85a2b65 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,5 +1,18 @@ package me.chanjar.weixin.mp.api; +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; + +import org.apache.commons.lang3.StringUtils; +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; @@ -10,18 +23,6 @@ import me.chanjar.weixin.common.session.WxSessionManager; 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.apache.commons.lang3.StringUtils; -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; /** *

@@ -155,11 +156,12 @@ public class WxMpMessageRouter {
   public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map context) {
     return route(wxMessage, context, null);
   }
+
   /**
    * 处理微信消息
    */
   public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map context, WxMpService wxMpService) {
-    if(wxMpService == null){
+    if (wxMpService == null) {
       wxMpService = this.wxMpService;
     }
     final WxMpService mpService = wxMpService;
@@ -214,7 +216,10 @@ public class WxMpMessageRouter {
               WxMpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUser());
               // 异步操作结束,session访问结束
               sessionEndAccess(wxMessage);
-            } catch (InterruptedException | ExecutionException e) {
+            } catch (InterruptedException e) {
+              WxMpMessageRouter.this.log.error("Error happened when wait task finish", e);
+              Thread.currentThread().interrupt();
+            } catch (ExecutionException e) {
               WxMpMessageRouter.this.log.error("Error happened when wait task finish", e);
             }
           }
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 c4212aff..fead289a 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
@@ -10,76 +10,79 @@ import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo;
 import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
 import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
 import me.chanjar.weixin.mp.bean.result.WxMpUser;
+import me.chanjar.weixin.mp.enums.TicketType;
 
 /**
- * 微信API的Service
+ * 微信公众号API的Service.
+ *
+ * @author chanjarster
  */
 public interface WxMpService {
   /**
-   * 获取access_token
+   * 获取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
+   * 获得各种类型的ticket.
    */
-  String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
+  String GET_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=";
   /**
-   * 长链接转短链接接口
+   * 长链接转短链接接口.
    */
   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
+   * 用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
+   * 刷新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获取用户信息
+   * 用oauth2获取用户信息.
    */
   String OAUTH2_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s";
   /**
-   * 验证oauth2的access token是否有效
+   * 验证oauth2的access token是否有效.
    */
   String OAUTH2_VALIDATE_TOKEN_URL = "https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s";
   /**
-   * 获取微信服务器IP地址
+   * 获取微信服务器IP地址.
    */
   String GET_CALLBACK_IP_URL = "https://api.weixin.qq.com/cgi-bin/getcallbackip";
   /**
-   * 第三方使用网站应用授权登录的url
+   * 第三方使用网站应用授权登录的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连接
+   * 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&connect_redirect=1#wechat_redirect";
 
   /**
-   * 获取公众号的自动回复规则
+   * 获取公众号的自动回复规则.
    */
   String GET_CURRENT_AUTOREPLY_INFO_URL = "https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info";
 
   /**
-   * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零
+   * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零.
    */
   String CLEAR_QUOTA_URL = "https://api.weixin.qq.com/cgi-bin/clear_quota";
 
   /**
    * 
-   * 验证消息的确来自微信服务器
+   * 验证消息的确来自微信服务器.
    * 详情请见: 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 + * 获取access_token, 不强制刷新access_token. * * @see #getAccessToken(boolean) */ @@ -87,7 +90,7 @@ public interface WxMpService { /** *
-   * 获取access_token,本方法线程安全
+   * 获取access_token,本方法线程安全.
    * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
    *
    * 另:本service的所有方法都会在access_token过期时调用此方法
@@ -102,7 +105,24 @@ public interface WxMpService {
   String getAccessToken(boolean forceRefresh) throws WxErrorException;
 
   /**
-   * 获得jsapi_ticket,不强制刷新jsapi_ticket
+   * 获得ticket,不强制刷新ticket.
+   *
+   * @see #getTicket(TicketType, boolean)
+   */
+  String getTicket(TicketType type) throws WxErrorException;
+
+  /**
+   * 
+   * 获得ticket.
+   * 获得时会检查 Token是否过期,如果过期了,那么就刷新一下,否则就什么都不干
+   * 
+ * + * @param forceRefresh 强制刷新 + */ + String getTicket(TicketType type, boolean forceRefresh) throws WxErrorException; + + /** + * 获得jsapi_ticket,不强制刷新jsapi_ticket. * * @see #getJsapiTicket(boolean) */ @@ -110,7 +130,7 @@ public interface WxMpService { /** *
-   * 获得jsapi_ticket
+   * 获得jsapi_ticket.
    * 获得时会检查jsapiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
    *
    * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
@@ -122,7 +142,7 @@ public interface WxMpService {
 
   /**
    * 
-   * 创建调用jsapi时所需要的签名
+   * 创建调用jsapi时所需要的签名.
    *
    * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
    * 
@@ -131,7 +151,7 @@ public interface WxMpService { /** *
-   * 长链接转短链接接口
+   * 长链接转短链接接口.
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=长链接转短链接接口
    * 
*/ @@ -139,7 +159,7 @@ public interface WxMpService { /** *
-   * 语义查询接口
+   * 语义查询接口.
    * 详情请见:http://mp.weixin.qq.com/wiki/index.php?title=语义理解
    * 
*/ @@ -147,7 +167,7 @@ public interface WxMpService { /** *
-   * 构造第三方使用网站应用授权登录的url
+   * 构造第三方使用网站应用授权登录的url.
    * 详情请见: 网站应用微信登录开发指南
    * URL格式为:https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
    * 
@@ -161,7 +181,7 @@ public interface WxMpService { /** *
-   * 构造oauth2授权的url连接
+   * 构造oauth2授权的url连接.
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息
    * 
* @@ -172,7 +192,7 @@ public interface WxMpService { /** *
-   * 用code换取oauth2的access token
+   * 用code换取oauth2的access token.
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息
    * 
*/ @@ -180,14 +200,14 @@ public interface WxMpService { /** *
-   * 刷新oauth2的access token
+   * 刷新oauth2的access token.
    * 
*/ WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException; /** *
-   * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以
+   * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以.
    * 
* * @param lang zh_CN, zh_TW, en @@ -196,7 +216,7 @@ public interface WxMpService { /** *
-   * 验证oauth2的access token是否有效
+   * 验证oauth2的access token是否有效.
    * 
*/ boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken); @@ -211,7 +231,7 @@ public interface WxMpService { /** *
-   * 获取公众号的自动回复规则
+   * 获取公众号的自动回复规则.
    * http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751299&token=&lang=zh_CN
    * 开发者可以通过该接口,获取公众号当前使用的自动回复规则,包括关注后自动回复、消息自动回复(60分钟内触发一次)、关键词自动回复。
    * 请注意:
@@ -240,12 +260,12 @@ public interface WxMpService {
   void clearQuota(String appid) throws WxErrorException;
 
   /**
-   * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求
+   * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求.
    */
   String get(String url, String queryParam) throws WxErrorException;
 
   /**
-   * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求
+   * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求.
    */
   String post(String url, String postData) throws WxErrorException;
 
@@ -260,7 +280,7 @@ public interface WxMpService {
 
   /**
    * 
-   * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试
+   * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试.
    * @param retrySleepMillis 默认:1000ms
    * 
*/ @@ -268,131 +288,131 @@ public interface WxMpService { /** *
-   * 设置当微信系统响应系统繁忙时,最大重试次数
+   * 设置当微信系统响应系统繁忙时,最大重试次数.
    * 默认:5次
    * 
*/ void setMaxRetryTimes(int maxRetryTimes); /** - * 获取WxMpConfigStorage 对象 + * 获取WxMpConfigStorage 对象. * * @return WxMpConfigStorage */ WxMpConfigStorage getWxMpConfigStorage(); /** - * 注入 {@link WxMpConfigStorage} 的实现 + * 注入 {@link WxMpConfigStorage} 的实现. */ void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider); /** - * 返回客服接口方法实现类,以方便调用其各个接口 + * 返回客服接口方法实现类,以方便调用其各个接口. * * @return WxMpKefuService */ WxMpKefuService getKefuService(); /** - * 返回素材相关接口方法的实现类对象,以方便调用其各个接口 + * 返回素材相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpMaterialService */ WxMpMaterialService getMaterialService(); /** - * 返回菜单相关接口方法的实现类对象,以方便调用其各个接口 + * 返回菜单相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpMenuService */ WxMpMenuService getMenuService(); /** - * 返回用户相关接口方法的实现类对象,以方便调用其各个接口 + * 返回用户相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpUserService */ WxMpUserService getUserService(); /** - * 返回用户标签相关接口方法的实现类对象,以方便调用其各个接口 + * 返回用户标签相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpUserTagService */ WxMpUserTagService getUserTagService(); /** - * 返回二维码相关接口方法的实现类对象,以方便调用其各个接口 + * 返回二维码相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpQrcodeService */ WxMpQrcodeService getQrcodeService(); /** - * 返回卡券相关接口方法的实现类对象,以方便调用其各个接口 + * 返回卡券相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpCardService */ WxMpCardService getCardService(); /** - * 返回数据分析统计相关接口方法的实现类对象,以方便调用其各个接口 + * 返回数据分析统计相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpDataCubeService */ WxMpDataCubeService getDataCubeService(); /** - * 返回用户黑名单管理相关接口方法的实现类对象,以方便调用其各个接口 + * 返回用户黑名单管理相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpUserBlacklistService */ WxMpUserBlacklistService getBlackListService(); /** - * 返回门店管理相关接口方法的实现类对象,以方便调用其各个接口 + * 返回门店管理相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpStoreService */ WxMpStoreService getStoreService(); /** - * 返回模板消息相关接口方法的实现类对象,以方便调用其各个接口 + * 返回模板消息相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpTemplateMsgService */ WxMpTemplateMsgService getTemplateMsgService(); /** - * 返回一次性订阅消息相关接口方法的实现类对象,以方便调用其各个接口 + * 返回一次性订阅消息相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpSubscribeMsgService */ WxMpSubscribeMsgService getSubscribeMsgService(); /** - * 返回硬件平台相关接口方法的实现类对象,以方便调用其各个接口 + * 返回硬件平台相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpDeviceService */ WxMpDeviceService getDeviceService(); /** - * 返回摇一摇周边相关接口方法的实现类对象,以方便调用其各个接口 + * 返回摇一摇周边相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpShakeService */ WxMpShakeService getShakeService(); /** - * 返回会员卡相关接口方法的实现类对象,以方便调用其各个接口 + * 返回会员卡相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpMemberCardService */ WxMpMemberCardService getMemberCardService(); /** - * 初始化http请求对象 + * 初始化http请求对象. */ void initHttp(); @@ -402,21 +422,21 @@ public interface WxMpService { RequestHttp getRequestHttp(); /** - * 返回群发消息相关接口方法的实现类对象,以方便调用其各个接口 + * 返回群发消息相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpMassMessageService */ WxMpMassMessageService getMassMessageService(); /** - * 返回AI开放接口方法的实现类对象,以方便调用其各个接口 + * 返回AI开放接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpAiOpenService */ WxMpAiOpenService getAiOpenService(); /** - * 返回WIFI接口方法的实现类对象,以方便调用其各个接口 + * 返回WIFI接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpWifiService */ 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 7523a9f3..71b6b170 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 @@ -1,18 +1,24 @@ package me.chanjar.weixin.mp.api; +import java.util.List; + import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.bean.WxMpUserQuery; +import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid; import me.chanjar.weixin.mp.bean.result.WxMpUser; import me.chanjar.weixin.mp.bean.result.WxMpUserList; -import java.util.List; - /** - * 用户管理相关操作接口 + * 用户管理相关操作接口. * * @author Binary Wang */ public interface WxMpUserService { + String USER_INFO_BATCH_GET_URL = "https://api.weixin.qq.com/cgi-bin/user/info/batchget"; + String USER_GET_URL = "https://api.weixin.qq.com/cgi-bin/user/get"; + String USER_INFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info"; + String USER_INFO_UPDATE_REMARK_URL = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark"; + String USER_CHANGE_OPENID_URL = "http://api.weixin.qq.com/cgi-bin/changeopenid"; /** *
@@ -61,9 +67,9 @@ public interface WxMpUserService {
    * 接口地址:https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=ACCESS_TOKEN
    * 
* - * @param openids 用户openid列表 + * @param openidList 用户openid列表 */ - List userInfoList(List openids) throws WxErrorException; + List userInfoList(List openidList) throws WxErrorException; /** *
@@ -90,4 +96,17 @@ public interface WxMpUserService {
    * @param nextOpenid 可选,第一个拉取的OPENID,null为从头开始拉取
    */
   WxMpUserList userList(String nextOpenid) throws WxErrorException;
+
+  /**
+   * 
+   * 微信公众号主体变更迁移用户 openid
+   * 详情请见: http://kf.qq.com/faq/170221aUnmmU170221eUZJNf.html
+   * http请求方式: POST
+   * 接口地址:https://api.weixin.qq.com/cgi-bin/changeopenid?access_token=ACCESS_TOKEN
+   * 
+ * + * @param fromAppid 原公众号的 appid + * @param openidList 需要转换的openid,这些必须是旧账号目前关注的才行,否则会出错;一次最多100个 + */ + List changeOpenid(String fromAppid, List openidList) throws WxErrorException; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java index 09d21bac..f7204616 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java @@ -1,5 +1,12 @@ package me.chanjar.weixin.mp.api.impl; +import java.io.IOException; +import java.util.concurrent.locks.Lock; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -12,21 +19,41 @@ import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.DataUtils; 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.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.common.util.http.URIUtil; +import me.chanjar.weixin.mp.api.WxMpAiOpenService; +import me.chanjar.weixin.mp.api.WxMpCardService; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.api.WxMpDataCubeService; +import me.chanjar.weixin.mp.api.WxMpDeviceService; +import me.chanjar.weixin.mp.api.WxMpKefuService; +import me.chanjar.weixin.mp.api.WxMpMassMessageService; +import me.chanjar.weixin.mp.api.WxMpMaterialService; +import me.chanjar.weixin.mp.api.WxMpMemberCardService; +import me.chanjar.weixin.mp.api.WxMpMenuService; +import me.chanjar.weixin.mp.api.WxMpQrcodeService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.WxMpShakeService; +import me.chanjar.weixin.mp.api.WxMpStoreService; +import me.chanjar.weixin.mp.api.WxMpSubscribeMsgService; +import me.chanjar.weixin.mp.api.WxMpTemplateMsgService; +import me.chanjar.weixin.mp.api.WxMpUserBlacklistService; +import me.chanjar.weixin.mp.api.WxMpUserService; +import me.chanjar.weixin.mp.api.WxMpUserTagService; +import me.chanjar.weixin.mp.api.WxMpWifiService; import me.chanjar.weixin.mp.bean.WxMpSemanticQuery; import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo; import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult; import me.chanjar.weixin.mp.bean.result.WxMpUser; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.concurrent.locks.Lock; +import me.chanjar.weixin.mp.enums.TicketType; /** + * 基础实现类. + * * @author someone */ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestHttp { @@ -71,31 +98,42 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH } @Override - public String getJsapiTicket() throws WxErrorException { - return getJsapiTicket(false); + public String getTicket(TicketType type) throws WxErrorException { + return this.getTicket(type, false); } @Override - public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { - Lock lock = this.getWxMpConfigStorage().getJsapiTicketLock(); + public String getTicket(TicketType type, boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMpConfigStorage().getTicketLock(type); try { lock.lock(); if (forceRefresh) { - this.getWxMpConfigStorage().expireJsapiTicket(); + this.getWxMpConfigStorage().expireTicket(type); } - 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(); + if (this.getWxMpConfigStorage().isTicketExpired(type)) { + String responseContent = execute(SimpleGetRequestExecutor.create(this), + WxMpService.GET_TICKET_URL + type.getCode(), null); + JsonObject tmpJsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.getWxMpConfigStorage().updateJsapiTicket(jsapiTicket, expiresInSeconds); + this.getWxMpConfigStorage().updateTicket(type, jsapiTicket, expiresInSeconds); } } finally { lock.unlock(); } - return this.getWxMpConfigStorage().getJsapiTicket(); + + return this.getWxMpConfigStorage().getTicket(type); + } + + @Override + public String getJsapiTicket() throws WxErrorException { + return this.getJsapiTicket(false); + } + + @Override + public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { + return this.getTicket(TicketType.JSAPI, forceRefresh); } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java index f492e467..b97da0a8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java @@ -5,7 +5,7 @@ import com.google.gson.JsonParser; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.AiLangType; +import me.chanjar.weixin.mp.enums.AiLangType; import me.chanjar.weixin.mp.api.WxMpAiOpenService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.util.requestexecuter.voice.VoiceUploadRequestExecutor; 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 bc1a0724..bfd58856 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,6 +1,18 @@ package me.chanjar.weixin.mp.api.impl; -import com.google.gson.*; +import java.util.Arrays; +import java.util.concurrent.locks.Lock; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +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.error.WxError; @@ -14,24 +26,20 @@ import me.chanjar.weixin.mp.bean.card.WxMpCardLandingPageCreateRequest; import me.chanjar.weixin.mp.bean.card.WxMpCardLandingPageCreateResult; import me.chanjar.weixin.mp.bean.card.WxMpCardQrcodeCreateResult; import me.chanjar.weixin.mp.bean.result.WxMpCardResult; +import me.chanjar.weixin.mp.enums.TicketType; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.commons.lang3.StringUtils; -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. + * + * @author BinaryWang */ public class WxMpCardServiceImpl implements WxMpCardService { - private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class); private WxMpService wxMpService; - private static final Gson GSON = new Gson(); + private static final Gson GSON = WxMpGsonBuilder.create(); public WxMpCardServiceImpl(WxMpService wxMpService) { this.wxMpService = wxMpService; @@ -43,7 +51,7 @@ public class WxMpCardServiceImpl implements WxMpCardService { } /** - * 获得卡券api_ticket,不强制刷新卡券api_ticket + * 获得卡券api_ticket,不强制刷新卡券api_ticket. * * @return 卡券api_ticket * @see #getCardApiTicket(boolean) @@ -55,7 +63,7 @@ public class WxMpCardServiceImpl implements WxMpCardService { /** *
-   * 获得卡券api_ticket
+   * 获得卡券api_ticket.
    * 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
    *
    * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
@@ -68,26 +76,28 @@ public class WxMpCardServiceImpl implements WxMpCardService {
    */
   @Override
   public String getCardApiTicket(boolean forceRefresh) throws WxErrorException {
-    Lock lock = getWxMpService().getWxMpConfigStorage().getCardApiTicketLock();
+    final TicketType type = TicketType.WX_CARD;
+    Lock lock = getWxMpService().getWxMpConfigStorage().getTicketLock(type);
     try {
       lock.lock();
 
       if (forceRefresh) {
-        this.getWxMpService().getWxMpConfigStorage().expireCardApiTicket();
+        this.getWxMpService().getWxMpConfigStorage().expireTicket(type);
       }
 
-      if (this.getWxMpService().getWxMpConfigStorage().isCardApiTicketExpired()) {
-        String responseContent = this.wxMpService.execute(SimpleGetRequestExecutor.create(this.getWxMpService().getRequestHttp()), CARD_GET_TICKET, null);
+      if (this.getWxMpService().getWxMpConfigStorage().isTicketExpired(type)) {
+        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.getWxMpService().getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds);
+        this.getWxMpService().getWxMpConfigStorage().updateTicket(type, cardApiTicket, expiresInSeconds);
       }
     } finally {
       lock.unlock();
     }
-    return this.getWxMpService().getWxMpConfigStorage().getCardApiTicket();
+    return this.getWxMpService().getWxMpConfigStorage().getTicket(type);
   }
 
   /**
@@ -141,7 +151,7 @@ public class WxMpCardServiceImpl implements WxMpCardService {
   }
 
   /**
-   * 卡券Code查询
+   * 卡券Code查询.
    *
    * @param cardId       卡券ID代表一类卡券
    * @param code         单张卡券的唯一标准
@@ -156,7 +166,7 @@ public class WxMpCardServiceImpl implements WxMpCardService {
     param.addProperty("check_consume", checkConsume);
     String responseContent = this.wxMpService.post(CARD_CODE_GET, param.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement,
+    return WxMpGsonBuilder.create().fromJson(tmpJsonElement,
       new TypeToken() {
       }.getType());
   }
@@ -213,7 +223,7 @@ public class WxMpCardServiceImpl implements WxMpCardService {
     param.addProperty("is_mark", isMark);
     String responseContent = this.getWxMpService().post(CARD_CODE_MARK, param.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
-    WxMpCardResult cardResult = WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement,
+    WxMpCardResult cardResult = WxMpGsonBuilder.create().fromJson(tmpJsonElement,
       new TypeToken() {
       }.getType());
     if (!"0".equals(cardResult.getErrorCode())) {
@@ -241,11 +251,11 @@ public class WxMpCardServiceImpl implements WxMpCardService {
   }
 
   /**
-   * 添加测试白名单
+   * 添加测试白名单.
    *
    * @param openid 用户的openid
-   * @return
    */
+  @Override
   public String addTestWhiteList(String openid) throws WxErrorException {
     JsonArray array = new JsonArray();
     array.add(openid);
@@ -256,25 +266,21 @@ public class WxMpCardServiceImpl implements WxMpCardService {
   }
 
   /**
-   * 创建卡券二维码
-   *
-   * @param cardId
-   * @param outerStr
-   * @return
+   * 创建卡券二维码.
    */
+  @Override
   public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr) throws WxErrorException {
     return createQrcodeCard(cardId, outerStr, 0);
   }
 
   /**
-   * 创建卡券二维码
+   * 创建卡券二维码.
    *
    * @param cardId    卡券编号
    * @param outerStr  二维码标识
    * @param expiresIn 失效时间,单位秒,不填默认365天
-   * @return
-   * @throws WxErrorException
    */
+  @Override
   public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("action_name", "QR_CARD");
@@ -287,42 +293,35 @@ public class WxMpCardServiceImpl implements WxMpCardService {
     cardJson.addProperty("outer_str", outerStr);
     actionInfoJson.add("card", cardJson);
     jsonObject.add("action_info", actionInfoJson);
-    String response = this.wxMpService.post(CARD_QRCODE_CREAET, GSON.toJson(jsonObject));
-    return WxMpCardQrcodeCreateResult.fromJson(response);
+    return WxMpCardQrcodeCreateResult.fromJson(this.wxMpService.post(CARD_QRCODE_CREATE, GSON.toJson(jsonObject)));
   }
 
   /**
-   * 创建卡券货架接口
-   *
-   * @param request
-   * @return
-   * @throws WxErrorException
+   * 创建卡券货架接口.
    */
   @Override
   public WxMpCardLandingPageCreateResult createLandingPage(WxMpCardLandingPageCreateRequest request) throws WxErrorException {
-    String response = this.wxMpService.post(CARD_LANDING_PAGE_CREAET, GSON.toJson(request));
+    String response = this.wxMpService.post(CARD_LANDING_PAGE_CREATE, GSON.toJson(request));
     return WxMpCardLandingPageCreateResult.fromJson(response);
   }
 
   /**
-   * 将用户的卡券设置为失效状态
+   * 将用户的卡券设置为失效状态.
    * 详见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025272&anchor=9
    *
    * @param cardId 卡券编号
    * @param code   用户会员卡号
    * @param reason 设置为失效的原因
-   * @return
-   * @throws WxErrorException
    */
   @Override
   public String unavailableCardCode(String cardId, String code, String reason) throws WxErrorException {
-    if (StringUtils.isAnyBlank(cardId, code, reason))
+    if (StringUtils.isAnyBlank(cardId, code, reason)) {
       throw new WxErrorException(WxError.builder().errorCode(41012).errorMsg("参数不完整").build());
+    }
     JsonObject jsonRequest = new JsonObject();
     jsonRequest.addProperty("card_id", cardId);
     jsonRequest.addProperty("code", code);
     jsonRequest.addProperty("reason", reason);
-    String response = this.wxMpService.post(CARD_CODE_UNAVAILABLE, GSON.toJson(jsonRequest));
-    return response;
+    return this.wxMpService.post(CARD_CODE_UNAVAILABLE, GSON.toJson(jsonRequest));
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java
index 3c4d0ab5..9bdc11b3 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java
@@ -1,23 +1,43 @@
 package me.chanjar.weixin.mp.api.impl;
 
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
 import com.google.gson.Gson;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import me.chanjar.weixin.mp.api.WxMpMemberCardService;
 import me.chanjar.weixin.mp.api.WxMpService;
-import me.chanjar.weixin.mp.bean.card.*;
+import me.chanjar.weixin.mp.bean.card.AdvancedInfo;
+import me.chanjar.weixin.mp.bean.card.BaseInfo;
+import me.chanjar.weixin.mp.bean.card.CardUpdateResult;
+import me.chanjar.weixin.mp.bean.card.DateInfo;
+import me.chanjar.weixin.mp.bean.card.MemberCard;
+import me.chanjar.weixin.mp.bean.card.MemberCardActivateUserFormRequest;
+import me.chanjar.weixin.mp.bean.card.MemberCardActivateUserFormResult;
+import me.chanjar.weixin.mp.bean.card.MemberCardCreateRequest;
+import me.chanjar.weixin.mp.bean.card.MemberCardUpdateRequest;
+import me.chanjar.weixin.mp.bean.card.WxMpCardCreateResult;
 import me.chanjar.weixin.mp.bean.card.enums.BusinessServiceType;
 import me.chanjar.weixin.mp.bean.card.enums.CardColor;
 import me.chanjar.weixin.mp.bean.card.enums.DateInfoType;
-import me.chanjar.weixin.mp.bean.membercard.*;
+import me.chanjar.weixin.mp.bean.membercard.ActivatePluginParam;
+import me.chanjar.weixin.mp.bean.membercard.ActivatePluginParamResult;
+import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardActivatedMessage;
+import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardCreateMessage;
+import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateMessage;
+import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateResult;
+import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * 会员卡相关接口的实现类
@@ -25,62 +45,47 @@ import org.slf4j.LoggerFactory;
  * @author YuJian(mgcnrx11 @ gmail.com)
  * @version 2017/7/8
  */
+@Slf4j
 public class WxMpMemberCardServiceImpl implements WxMpMemberCardService {
-
-  private final Logger log = LoggerFactory.getLogger(WxMpMemberCardServiceImpl.class);
-
   private WxMpService wxMpService;
 
-  private static final Gson GSON = new Gson();
+  private static final Gson GSON = WxMpGsonBuilder.create();
 
   WxMpMemberCardServiceImpl(WxMpService wxMpService) {
     this.wxMpService = wxMpService;
   }
 
-  /**
-   * 得到WxMpService
-   */
   @Override
   public WxMpService getWxMpService() {
     return this.wxMpService;
   }
 
-  /**
-   * 会员卡创建接口
-   *
-   * @param createJson 创建json
-   * @return 调用返回的JSON字符串。
-   * @throws WxErrorException 接口调用失败抛出的异常
-   */
   @Override
   public WxMpCardCreateResult createMemberCard(String createJson) throws WxErrorException {
-    WxMpMemberCardCreateMessage createMessage = WxGsonBuilder.create().fromJson(createJson, WxMpMemberCardCreateMessage.class);
+    WxMpMemberCardCreateMessage createMessage = WxGsonBuilder.create()
+      .fromJson(createJson, WxMpMemberCardCreateMessage.class);
     return createMemberCard(createMessage);
   }
 
-  /**
-   * 会员卡创建接口
-   *
-   * @param createMessageMessage 创建所需参数
-   * @return WxMpCardCreateResult。
-   * @throws WxErrorException 接口调用失败抛出的异常
-   */
   @Override
-  public WxMpCardCreateResult createMemberCard(WxMpMemberCardCreateMessage createMessageMessage) throws WxErrorException {
+  public WxMpCardCreateResult createMemberCard(WxMpMemberCardCreateMessage createMessageMessage)
+    throws WxErrorException {
     //校验请求对象合法性
     WxMpCardCreateResult validResult = validCheck(createMessageMessage);
-    if (!validResult.isSuccess())
+    if (!validResult.isSuccess()) {
       return validResult;
+    }
+
     String response = this.wxMpService.post(MEMBER_CARD_CREAET, GSON.toJson(createMessageMessage));
     return WxMpCardCreateResult.fromJson(response);
   }
 
-  private WxMpCardCreateResult validCheck(WxMpMemberCardCreateMessage createMessageMessage) throws WxErrorException {
+  private WxMpCardCreateResult validCheck(WxMpMemberCardCreateMessage createMessageMessage) {
     if (createMessageMessage == null) {
       return WxMpCardCreateResult.failure("对象不能为空");
     }
     MemberCardCreateRequest cardCreateRequest = createMessageMessage.getCardCreateRequest();
-    if (createMessageMessage == null) {
+    if (cardCreateRequest == null) {
       return WxMpCardCreateResult.failure("会员卡对象不能为空");
     }
     String cardType = cardCreateRequest.getCardType();
@@ -93,17 +98,11 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService {
       return WxMpCardCreateResult.failure("会员卡特权说明不能为空:prerogative");
     }
     //卡片激活规则
-    if (!memberCard.isAutoActivate() && !memberCard.isWxActivate() && StringUtils.isEmpty(memberCard.getActivateUrl())) {
+    if (!memberCard.isAutoActivate() && !memberCard.isWxActivate()
+      && StringUtils.isEmpty(memberCard.getActivateUrl())) {
       return WxMpCardCreateResult.failure("会员卡激活方式为接口激活,activate_url不能为空");
     }
 
-    //积分支持
-//    if(memberCard.isSupplyBonus() && StringUtils.isEmpty(memberCard.getBonusUrl())){
-//      return WxMpCardCreateResult.failure("会员卡支持积分,bonus_url不能为空");
-//    }
-//    if(memberCard.isSupplyBonus() && memberCard.getBonusRule() == null){
-//      return WxMpCardCreateResult.failure("会员卡支持积分,bonus_rule不能为空");
-//    }
     BaseInfo baseInfo = memberCard.getBaseInfo();
     if (baseInfo == null) {
       return WxMpCardCreateResult.failure("会员卡基本信息对象base_info不能为空");
@@ -176,16 +175,24 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService {
     }
 
     //固定时长
-    if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TERM && (dateInfo.getFixedTerm() == null || dateInfo.getFixedBeginTerm() == null)) {
-      return WxMpCardCreateResult.failure("会员卡基本信息的使用日期为:" + dateInfoType.getDescription() + ",fixedTerm和fixedBeginTerm不能为空");
+    if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TERM
+      && (dateInfo.getFixedTerm() == null || dateInfo.getFixedBeginTerm() == null)) {
+      return WxMpCardCreateResult.failure(String.format("会员卡基本信息的使用日期为:%s,fixedTerm和fixedBeginTerm不能为空",
+        dateInfoType.getDescription()));
     }
 
     //固定期限
-    if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TIME_RANGE && (dateInfo.getBeginTimestamp() == null || dateInfo.getEndTimestamp() == null)) {
-      return WxMpCardCreateResult.failure("会员卡基本信息的使用日期为:" + dateInfoType.getDescription() + ",beginTimestamp 和 endTimestamp 不能为空");
+    if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TIME_RANGE
+      && (dateInfo.getBeginTimestamp() == null || dateInfo.getEndTimestamp() == null)) {
+      return WxMpCardCreateResult.failure(String.format("会员卡基本信息的使用日期为:%s,beginTimestamp 和 endTimestamp 不能为空",
+        dateInfoType.getDescription()));
     }
-    if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TIME_RANGE && (dateInfo.getBeginTimestamp() < System.currentTimeMillis() || dateInfo.getEndTimestamp() < System.currentTimeMillis() || dateInfo.getBeginTimestamp() > dateInfo.getEndTimestamp())) {
-      return WxMpCardCreateResult.failure("会员卡基本信息的使用日期为:" + dateInfoType.getDescription() + ",beginTimestamp和endTimestamp的值不合法,请检查");
+    if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TIME_RANGE
+      && (dateInfo.getBeginTimestamp() * 1000 < System.currentTimeMillis()
+      || dateInfo.getEndTimestamp() * 1000 < System.currentTimeMillis()
+      || dateInfo.getBeginTimestamp() > dateInfo.getEndTimestamp())) {
+      return WxMpCardCreateResult.failure(String.format("会员卡基本信息的使用日期为:%s,beginTimestamp和endTimestamp的值不合法,请检查",
+        dateInfoType.getDescription()));
     }
 
     if (!baseInfo.isUseAllLocations() && StringUtils.isBlank(baseInfo.getLocationIdList())) {
@@ -197,9 +204,8 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService {
     if (advancedInfo != null) {
       if (advancedInfo.getBusinessServiceList() != null) {
         for (String bs : advancedInfo.getBusinessServiceList()) {
-          BusinessServiceType businessServiceType = null;
           try {
-            businessServiceType = BusinessServiceType.valueOf(bs);
+            BusinessServiceType.valueOf(bs);
           } catch (IllegalArgumentException ex) {
             return WxMpCardCreateResult.failure("会员卡高级信息的商户服务:" + bs + " 不合法");
           }
@@ -210,26 +216,11 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService {
     return WxMpCardCreateResult.success();
   }
 
-  /**
-   * 会员卡激活接口
-   *
-   * @param activatedMessage 激活所需参数
-   * @return WxMpCardCreateResult。
-   * @throws WxErrorException 接口调用失败抛出的异常
-   */
   @Override
   public String activateMemberCard(WxMpMemberCardActivatedMessage activatedMessage) throws WxErrorException {
     return this.wxMpService.post(MEMBER_CARD_ACTIVATE, GSON.toJson(activatedMessage));
   }
 
-  /**
-   * 拉取会员信息接口
-   *
-   * @param cardId 会员卡的CardId,微信分配
-   * @param code   领取会员的会员卡Code
-   * @return 会员信息的结果对象
-   * @throws WxErrorException 接口调用失败抛出的异常
-   */
   @Override
   public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
@@ -237,24 +228,13 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService {
     jsonObject.addProperty("code", code);
 
     String responseContent = this.getWxMpService().post(MEMBER_CARD_USER_INFO_GET, jsonObject.toString());
-    log.debug("{}",responseContent);
+    log.debug("{}", responseContent);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement,
+    return WxMpGsonBuilder.create().fromJson(tmpJsonElement,
       new TypeToken() {
       }.getType());
   }
 
-  /**
-   * 当会员持卡消费后,支持开发者调用该接口更新会员信息。会员卡交易后的每次信息变更需通过该接口通知微信,便于后续消息通知及其他扩展功能。
-   * 

- * 1.开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。同时传入add_bonus和bonus时 - * add_bonus作为积分变动消息中的变量值,而bonus作为卡面上的总积分额度显示。余额变动同理。 - * 2.开发者可以传入is_notify_bonus控制特殊的积分对账变动不发送消息,余额变动同理。 - * - * @param updateUserMessage 更新会员信息所需字段消息 - * @return 调用返回的JSON字符串。 - * @throws WxErrorException 接口调用失败抛出的异常 - */ @Override public WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessage updateUserMessage) throws WxErrorException { @@ -262,22 +242,90 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService { String responseContent = this.getWxMpService().post(MEMBER_CARD_UPDATE_USER, GSON.toJson(updateUserMessage)); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, + return WxMpGsonBuilder.create().fromJson(tmpJsonElement, new TypeToken() { }.getType()); } - /** - * 设置会员卡激活的字段(会员卡设置:wx_activate=true 时需要) - * - * @param userFormRequest - * @return - * @throws WxErrorException - */ @Override public MemberCardActivateUserFormResult setActivateUserForm(MemberCardActivateUserFormRequest userFormRequest) throws WxErrorException { String responseContent = this.getWxMpService().post(MEMBER_CARD_ACTIVATEUSERFORM, GSON.toJson(userFormRequest)); return MemberCardActivateUserFormResult.fromJson(responseContent); } + @Override + public ActivatePluginParam getActivatePluginParam(String cardId, String outStr) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("card_id", cardId); + params.addProperty("outer_str", outStr); + String response = this.wxMpService.post(MEMBER_CARD_ACTIVATE_URL, GSON.toJson(params)); + ActivatePluginParamResult result = GSON.fromJson(response, ActivatePluginParamResult.class); + if (0 == result.getErrcode()) { + String url = result.getUrl(); + try { + String decodedUrl = URLDecoder.decode(url, "UTF-8"); + Map resultMap = parseRequestUrl(decodedUrl); + ActivatePluginParam activatePluginParam = new ActivatePluginParam(); + activatePluginParam.setEncryptCardId(resultMap.get("encrypt_card_id")); + activatePluginParam.setOuterStr(resultMap.get("outer_str")); + activatePluginParam.setBiz(resultMap.get("biz") + "=="); + return activatePluginParam; + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + return null; + } + + @Override + public CardUpdateResult updateCardInfo(MemberCardUpdateRequest memberCardUpdateRequest) throws WxErrorException { + String response = this.wxMpService.post(MEMBER_CARD_UPDATE, GSON.toJson(memberCardUpdateRequest)); + CardUpdateResult result = GSON.fromJson(response, CardUpdateResult.class); + return result; + } + + private static String truncateUrlPage(String strURL) { + String strAllParam = null; + String[] arrSplit; + arrSplit = strURL.split("[?]"); + if (strURL.length() > 1) { + if (arrSplit.length > 1) { + if (arrSplit[1] != null) { + strAllParam = arrSplit[1]; + } + } + } + + return strAllParam; + } + + public static Map parseRequestUrl(String url) { + Map mapRequest = new HashMap<>(16); + + String[] arrSplit; + + String strUrlParam = truncateUrlPage(url); + if (strUrlParam == null) { + return mapRequest; + } + arrSplit = strUrlParam.split("[&]"); + for (String strSplit : arrSplit) { + String[] arrSplitEqual; + arrSplitEqual = strSplit.split("[=]"); + + //解析出键值 + if (arrSplitEqual.length > 1) { + //正确解析 + mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]); + + } else { + if (!"".equals(arrSplitEqual[0])) { + //只有参数没有值,不加入 + mapRequest.put(arrSplitEqual[0], ""); + } + } + } + return mapRequest; + } + } 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 561d7c04..a6ba958e 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 @@ -1,16 +1,16 @@ package me.chanjar.weixin.mp.api.impl; -import com.google.gson.Gson; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.google.gson.JsonObject; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpUserBlacklistService; import me.chanjar.weixin.mp.bean.result.WxMpUserBlacklistGetResult; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** * @author miller @@ -37,14 +37,15 @@ public class WxMpUserBlacklistServiceImpl implements WxMpUserBlacklistService { Map map = new HashMap<>(); map.put("openid_list", openidList); String url = API_BLACKLIST_PREFIX + "/batchblacklist"; - this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, new Gson().toJson(map)); + this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, + WxMpGsonBuilder.create().toJson(map)); } @Override public void pullFromBlacklist(List openidList) throws WxErrorException { - Map map = new HashMap<>(); + Map map = new HashMap<>(2); map.put("openid_list", openidList); String url = API_BLACKLIST_PREFIX + "/batchunblacklist"; - this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, new Gson().toJson(map)); + this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, WxMpGsonBuilder.create().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 def801e4..d8c8943d 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 @@ -1,20 +1,26 @@ package me.chanjar.weixin.mp.api.impl; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.gson.JsonArray; import com.google.gson.JsonObject; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpUserService; import me.chanjar.weixin.mp.bean.WxMpUserQuery; +import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid; import me.chanjar.weixin.mp.bean.result.WxMpUser; import me.chanjar.weixin.mp.bean.result.WxMpUserList; - -import java.util.List; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** * Created by Binary Wang on 2016/7/21. + * + * @author BinaryWang */ public class WxMpUserServiceImpl implements WxMpUserService { - private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/user"; private WxMpService wxMpService; public WxMpUserServiceImpl(WxMpService wxMpService) { @@ -23,11 +29,10 @@ public class WxMpUserServiceImpl implements WxMpUserService { @Override public void userUpdateRemark(String openid, String remark) throws WxErrorException { - String url = API_URL_PREFIX + "/info/updateremark"; JsonObject json = new JsonObject(); json.addProperty("openid", openid); json.addProperty("remark", remark); - this.wxMpService.post(url, json.toString()); + this.wxMpService.post(USER_INFO_UPDATE_REMARK_URL, json.toString()); } @Override @@ -37,32 +42,38 @@ public class WxMpUserServiceImpl implements WxMpUserService { @Override 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, + String responseContent = this.wxMpService.get(USER_INFO_URL, "openid=" + openid + "&lang=" + lang); return WxMpUser.fromJson(responseContent); } @Override - 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); + public WxMpUserList userList(String nextOpenid) throws WxErrorException { + String responseContent = this.wxMpService.get(USER_GET_URL, + nextOpenid == null ? null : "next_openid=" + nextOpenid); return WxMpUserList.fromJson(responseContent); } @Override - public List userInfoList(List openids) + public List changeOpenid(String fromAppid, List openidList) throws WxErrorException { + Map map = new HashMap<>(); + map.put("from_appid", fromAppid); + map.put("openid_list", openidList); + String responseContent = this.wxMpService.post(USER_CHANGE_OPENID_URL, WxMpGsonBuilder.create().toJson(map)); + + return WxMpChangeOpenid.fromJsonList(responseContent); + } + + @Override + public List userInfoList(List openidList) throws WxErrorException { - return this.userInfoList(new WxMpUserQuery(openids)); + return this.userInfoList(new WxMpUserQuery(openidList)); } @Override public List userInfoList(WxMpUserQuery userQuery) throws WxErrorException { - String url = API_URL_PREFIX + "/info/batchget"; - String responseContent = this.wxMpService.post(url, - userQuery.toJsonString()); + String responseContent = this.wxMpService.post(USER_INFO_BATCH_GET_URL, userQuery.toJsonString()); return WxMpUser.fromJsonList(responseContent); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCard.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCard.java index 622dca9e..71e419a7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCard.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCard.java @@ -3,19 +3,17 @@ package me.chanjar.weixin.mp.bean; import java.io.Serializable; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 微信卡券 + * 微信卡券. * * @author YuJian * @version 15/11/11 */ @Data -public class WxMpCard implements Serializable{ +public class WxMpCard implements Serializable { private static final long serialVersionUID = 9214301870017772921L; private String cardId; @@ -30,6 +28,6 @@ public class WxMpCard implements Serializable{ @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } 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 5dd8c2ad..a2b35b7c 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 @@ -4,9 +4,6 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import lombok.Data; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -26,7 +23,7 @@ public class WxMpMassNews implements Serializable { } public String toJson() { - return WxMpGsonBuilder.INSTANCE.create().toJson(this); + return WxMpGsonBuilder.create().toJson(this); } public boolean isEmpty() { @@ -35,7 +32,7 @@ public class WxMpMassNews implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } /** @@ -85,7 +82,7 @@ public class WxMpMassNews implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(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 742b0165..ce1d77b6 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 @@ -51,7 +51,7 @@ public class WxMpMassOpenIdsMessage implements Serializable { } public String toJson() { - return WxMpGsonBuilder.INSTANCE.create().toJson(this); + return WxMpGsonBuilder.create().toJson(this); } /** diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassPreviewMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassPreviewMessage.java index 512c454c..dca743c9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassPreviewMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassPreviewMessage.java @@ -36,6 +36,6 @@ public class WxMpMassPreviewMessage implements Serializable { } public String toJson() { - return WxMpGsonBuilder.INSTANCE.create().toJson(this); + return WxMpGsonBuilder.create().toJson(this); } } 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 9487124c..0a72814a 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 @@ -54,7 +54,7 @@ public class WxMpMassTagMessage implements Serializable { } public String toJson() { - return WxMpGsonBuilder.INSTANCE.create().toJson(this); + return WxMpGsonBuilder.create().toJson(this); } public void setSendAll(boolean sendAll) { 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 d536ff98..2271e353 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 @@ -19,6 +19,6 @@ public class WxMpMassVideo implements Serializable { private String description; public String toJson() { - return WxMpGsonBuilder.INSTANCE.create().toJson(this); + return WxMpGsonBuilder.create().toJson(this); } } 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 index 313cfaba..4cd64300 100644 --- 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 @@ -22,7 +22,7 @@ public class WxMpShakeInfoResult implements Serializable { private ShakeInfoData data; public static WxMpShakeInfoResult fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpShakeInfoResult.class); + return WxMpGsonBuilder.create().fromJson(json, WxMpShakeInfoResult.class); } @Data diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Abstract.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Abstract.java index 985cdb0a..11e4f3a3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Abstract.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Abstract.java @@ -1,33 +1,35 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 封面摘要 - * author:yuanqixun + * 封面摘要. + * @author yuanqixun * date:2018-08-25 00:35 */ @Data public class Abstract implements Serializable { + private static final long serialVersionUID = -2612656133201770573L; /** - * 摘要 + * 摘要. */ @SerializedName("abstract") private String abstractInfo; /** - * 封面图片列表,仅支持填入一 个封面图片链接, 上传图片接口 上传获取图片获得链接,填写 非CDN链接会报错,并在此填入。 建议图片尺寸像素850*350 + * 封面图片列表. + * 仅支持填入一 个封面图片链接, 上传图片接口 上传获取图片获得链接,填写 非CDN链接会报错,并在此填入。 建议图片尺寸像素850*350 */ @SerializedName("icon_url_list") private String iconUrlList; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/AdvancedInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/AdvancedInfo.java index 73fd0135..f127c8ec 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/AdvancedInfo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/AdvancedInfo.java @@ -1,23 +1,22 @@ package me.chanjar.weixin.mp.bean.card; -import com.google.gson.annotations.SerializedName; -import lombok.Data; -import me.chanjar.weixin.mp.bean.card.enums.BusinessServiceType; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import java.io.Serializable; import java.util.ArrayList; import java.util.List; -//子对象列表 + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.bean.card.enums.BusinessServiceType; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 微信会员卡高级字段信息 - * author:yuanqixun + * 微信会员卡高级字段信息. + * @author yuanqixun * date:2018-08-25 00:36 */ @Data public class AdvancedInfo implements Serializable { + private static final long serialVersionUID = -8470424140133771841L; // public AdvancedInfo(){ // useCondition = new UseCondition(); @@ -27,50 +26,56 @@ public class AdvancedInfo implements Serializable { // } /** - * 使用门槛(条件),若不填写使用条件则在券面拼写 :无最低消费限制,全场通用,不限品类;并在使用说明显示: 可与其他优惠共享 + * 使用门槛(条件). + * 若不填写使用条件则在券面拼写 :无最低消费限制,全场通用,不限品类;并在使用说明显示: 可与其他优惠共享 */ @SerializedName("use_condition") private UseCondition useCondition; /** - * 封面摘要 + * 封面摘要. */ @SerializedName("abstract") private Abstract abstractInfo; /** - * 图文列表,显示在详情内页 ,优惠券券开发者须至少传入 一组图文列表 + * 图文列表. + * 显示在详情内页 ,优惠券券开发者须至少传入 一组图文列表 */ @SerializedName("text_image_list") private List textImageList; /** - * 商家服务类型,数组类型:BIZ_SERVICE_DELIVER 外卖服务; BIZ_SERVICE_FREE_PARK 停车位; BIZ_SERVICE_WITH_PET 可带宠物; BIZ_SERVICE_FREE_WIFI 免费wifi, 可多选 + * 商家服务类型. + * 数组类型:BIZ_SERVICE_DELIVER 外卖服务; BIZ_SERVICE_FREE_PARK 停车位; BIZ_SERVICE_WITH_PET 可带宠物; BIZ_SERVICE_FREE_WIFI 免费wifi, 可多选 */ @SerializedName("business_service") private List businessServiceList; /** - * 使用时段限制 + * 使用时段限制. */ @SerializedName("time_limit") private TimeLimit timeLimit; /** - * 是否可以分享朋友 + * 是否可以分享朋友. */ @SerializedName("share_friends") private Boolean shareFriends; public void addBusinessService(BusinessServiceType businessServiceType) { if (businessServiceType != null) { - if (businessServiceList == null) - businessServiceList = new ArrayList(); + if (businessServiceList == null){ + businessServiceList = new ArrayList<>(); + } + businessServiceList.add(businessServiceType.name()); } } + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BaseInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BaseInfo.java index bdd0b359..c968b599 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BaseInfo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BaseInfo.java @@ -1,196 +1,198 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; -//子对象列表 +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 微信会员卡基本信息 - * author:yuanqixun + * 微信会员卡基本信息. + * @author yuanqixun * date:2018-08-25 00:36 */ @Data public class BaseInfo implements Serializable { /** - * 卡券的商户logo,建议像素为300*300。 + * 卡券的商户logo,建议像素为300*300. */ @SerializedName("logo_url") private String logoUrl; /** - * Code展示类型,"CODE_TYPE_TEXT" 文本 "CODE_TYPE_BARCODE" 一维码 "CODE_TYPE_QRCODE" 二维码 "CODE_TYPE_ONLY_QRCODE" 仅显示二维码 "CODE_TYPE_ONLY_BARCODE" 仅显示一维码 "CODE_TYPE_NONE" 不显示任何码型 + * Code展示类型. + * "CODE_TYPE_TEXT" 文本 "CODE_TYPE_BARCODE" 一维码 "CODE_TYPE_QRCODE" 二维码 "CODE_TYPE_ONLY_QRCODE" 仅显示二维码 "CODE_TYPE_ONLY_BARCODE" 仅显示一维码 "CODE_TYPE_NONE" 不显示任何码型 */ @SerializedName("code_type") private String codeType = "CODE_TYPE_QRCODE"; /** - * 支付功能结构体,swipe_card结构 + * 支付功能结构体,swipe_card结构. */ @SerializedName("pay_info") private PayInfo payInfo; /** - * 是否设置该会员卡中部的按钮同时支持微信支付刷卡和会员卡二维码 + * 是否设置该会员卡中部的按钮同时支持微信支付刷卡和会员卡二维码. */ @SerializedName("is_pay_and_qrcode") private boolean isPayAndQrcode; /** - * 商户名字,字数上限为12个汉字 + * 商户名字,字数上限为12个汉字. */ @SerializedName("brand_name") private String brandName; /** - * 卡券名,字数上限为9个汉字 (建议涵盖卡券属性、服务及金额)。 + * 卡券名,字数上限为9个汉字 (建议涵盖卡券属性、服务及金额). */ @SerializedName("title") private String title; /** - * 券颜色,按色彩规范标注填写Color010-Color100 + * 券颜色,按色彩规范标注填写Color010-Color100. */ @SerializedName("color") private String color; /** - * 卡券使用提醒,字数上限为16个汉字 + * 卡券使用提醒,字数上限为16个汉字. */ @SerializedName("notice") private String notice; /** - * 卡券使用说明,字数上限为1024个汉字。 + * 卡券使用说明,字数上限为1024个汉字. */ @SerializedName("description") private String description; /** - * 商品信息 + * 商品信息. */ @SerializedName("sku") private Sku sku; /** - * 使用日期,有效期的信息。 + * 使用日期,有效期的信息. */ @SerializedName("date_info") private DateInfo dateInfo; /** - * 是否自定义Code码,填写true或false,默认为false 通常自有优惠码系统的开发者选择自定义Code码,详情见 是否自定义code + * 是否自定义Code码,填写true或false. + * 默认为false 通常自有优惠码系统的开发者选择自定义Code码,详情见 是否自定义code */ @SerializedName("use_custom_code") private boolean useCustomCode; /** - * 是否指定用户领取,填写true或false。默认为false + * 是否指定用户领取,填写true或false。默认为false. */ @SerializedName("bind_openid") private boolean bindOpenid; /** - * 客服电话 + * 客服电话. */ @SerializedName("service_phone") private String servicePhone; /** - * 门店位置ID,调用 POI门店管理接口 获取门店位置ID。 + * 门店位置ID,调用 POI门店管理接口 获取门店位置ID. */ @SerializedName("location_id_list") private String locationIdList; /** - * 会员卡是否支持全部门店,填写后商户门店更新时会自动同步至卡券 + * 会员卡是否支持全部门店,填写后商户门店更新时会自动同步至卡券. */ @SerializedName("use_all_locations") private boolean useAllLocations = true; /** - * 卡券中部居中的按钮,仅在卡券激活后且可用状态 时显示 + * 卡券中部居中的按钮,仅在卡券激活后且可用状态 时显示. */ @SerializedName("center_title") private String centerTitle; /** - * 显示在入口下方的提示语,仅在卡券激活后且可用状态时显示 + * 显示在入口下方的提示语,仅在卡券激活后且可用状态时显示. */ @SerializedName("center_sub_title") private String centerSubTitle; /** - * 顶部居中的url,仅在卡券激活后且可用状态时显示 + * 顶部居中的url,仅在卡券激活后且可用状态时显示. */ @SerializedName("center_url") private String centerUrl; /** - * 自定义跳转外链的入口名字 + * 自定义跳转外链的入口名字. */ @SerializedName("custom_url_name") private String customUrlName; /** - * 自定义跳转的URL + * 自定义跳转的URL. */ @SerializedName("custom_url") private String customUrl; /** - * 显示在入口右侧的提示语 + * 显示在入口右侧的提示语. */ @SerializedName("custom_url_sub_title") private String customUrlSubTitle; /** - * 营销场景的自定义入口名称 + * 营销场景的自定义入口名称. */ @SerializedName("promotion_url_name") private String promotionUrlName; /** - * 入口跳转外链的地址链接 + * 入口跳转外链的地址链接. */ @SerializedName("promotion_url") private String promotionUrl; /** - * 显示在营销入口右侧的提示语 + * 显示在营销入口右侧的提示语. */ @SerializedName("promotion_url_sub_title") private String promotionUrlSubTitle; /** - * 每人可领券的数量限制,建议会员卡每人限领一张 + * 每人可领券的数量限制,建议会员卡每人限领一张. */ @SerializedName("get_limit") private Integer getLimit = 1; /** - * 卡券领取页面是否可分享,默认为true + * 卡券领取页面是否可分享,默认为true. */ @SerializedName("can_share") private boolean canShare; /** - * 卡券是否可转赠,默认为true + * 卡券是否可转赠,默认为true. */ @SerializedName("can_give_friend") private boolean canGiveFriend; /** - * 用户点击进入会员卡时推送事件,填写true为用户点击进入会员卡时推送事件,默认为false。详情见 进入会员卡事件推送 + * 用户点击进入会员卡时推送事件. + * 填写true为用户点击进入会员卡时推送事件,默认为false。详情见 进入会员卡事件推送 */ @SerializedName("need_push_on_view") private boolean needPushOnView; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BaseInfoUpdate.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BaseInfoUpdate.java new file mode 100644 index 00000000..e7681dec --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BaseInfoUpdate.java @@ -0,0 +1,166 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * 微信会员卡基本信息更新 + * @author yuanqixun + * date:2018-08-25 00:36 + */ +@Data +public class BaseInfoUpdate implements Serializable { + + /** + * 需要审核:卡券名,字数上限为9个汉字 (建议涵盖卡券属性、服务及金额). + */ + @SerializedName("title") + private String title; + + /** + * 卡券的商户logo,建议像素为300*300. + */ + @SerializedName("logo_url") + private String logoUrl; + + /** + * 卡券使用提醒,字数上限为16个汉字. + */ + @SerializedName("notice") + private String notice; + + /** + * 需要审核:卡券使用说明,字数上限为1024个汉字. + */ + @SerializedName("description") + private String description; + + /** + * 客服电话. + */ + @SerializedName("service_phone") + private String servicePhone; + + /** + * 券颜色,按色彩规范标注填写Color010-Color100. + */ + @SerializedName("color") + private String color; + + /** + * 门店位置ID,调用 POI门店管理接口 获取门店位置ID. + */ + @SerializedName("location_id_list") + private String locationIdList; + + /** + * 会员卡是否支持全部门店,填写后商户门店更新时会自动同步至卡券. + */ + @SerializedName("use_all_locations") + private Boolean useAllLocations; + + /** + * 卡券中部居中的按钮,仅在卡券激活后且可用状态 时显示. + */ + @SerializedName("center_title") + private String centerTitle; + + /** + * 显示在入口下方的提示语,仅在卡券激活后且可用状态时显示. + */ + @SerializedName("center_sub_title") + private String centerSubTitle; + + /** + * 顶部居中的url,仅在卡券激活后且可用状态时显示. + */ + @SerializedName("center_url") + private String centerUrl; + + /** + * 自定义跳转外链的入口名字. + */ + @SerializedName("custom_url_name") + private String customUrlName; + + /** + * 自定义跳转的URL. + */ + @SerializedName("custom_url") + private String customUrl; + + /** + * 显示在入口右侧的提示语. + */ + @SerializedName("custom_url_sub_title") + private String customUrlSubTitle; + + /** + * 营销场景的自定义入口名称. + */ + @SerializedName("promotion_url_name") + private String promotionUrlName; + + /** + * 入口跳转外链的地址链接. + */ + @SerializedName("promotion_url") + private String promotionUrl; + + /** + * 显示在营销入口右侧的提示语. + */ + @SerializedName("promotion_url_sub_title") + private String promotionUrlSubTitle; + + /** + * Code展示类型. + * "CODE_TYPE_TEXT" 文本 "CODE_TYPE_BARCODE" 一维码 "CODE_TYPE_QRCODE" 二维码 "CODE_TYPE_ONLY_QRCODE" 仅显示二维码 "CODE_TYPE_ONLY_BARCODE" 仅显示一维码 "CODE_TYPE_NONE" 不显示任何码型 + */ + @SerializedName("code_type") + private String codeType; + + /** + * 支付功能结构体,swipe_card结构. + */ + @SerializedName("pay_info") + private PayInfo payInfo; + + /** + * 是否设置该会员卡中部的按钮同时支持微信支付刷卡和会员卡二维码. + */ + @SerializedName("is_pay_and_qrcode") + private Boolean isPayAndQrcode; + + /** + * 每人可领券的数量限制,建议会员卡每人限领一张. + */ + @SerializedName("get_limit") + private Integer getLimit; + + /** + * 卡券领取页面是否可分享,默认为true. + */ + @SerializedName("can_share") + private Boolean canShare; + + /** + * 卡券是否可转赠,默认为true. + */ + @SerializedName("can_give_friend") + private Boolean canGiveFriend; + + /** + * 使用日期,有效期的信息. + */ + @SerializedName("date_info") + private DateInfo dateInfo; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BonusRule.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BonusRule.java index 9b12d597..ea668ad0 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BonusRule.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/BonusRule.java @@ -1,69 +1,70 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 积分规则 - * author:yuanqixun + * 积分规则. + * @author yuanqixun * date:2018-08-25 00:33 */ @Data public class BonusRule implements Serializable { + private static final long serialVersionUID = -8698218402074475078L; /** - * 消费金额,以分为单位。 + * 消费金额,以分为单位. */ @SerializedName("cost_money_unit") private Integer costMoneyUnit; /** - * 对应增加的积分 + * 对应增加的积分. */ @SerializedName("increase_bonus") private Integer increaseBonus; /** - * 用户单次可获取的积分上限 + * 用户单次可获取的积分上限. */ @SerializedName("max_increase_bonus") private Integer maxIncreaseBonus; /** - * 初始设置积分 + * 初始设置积分. */ @SerializedName("init_increase_bonus") private Integer initIncreaseBonus; /** - * 每使用积分 + * 每使用积分. */ @SerializedName("cost_bonus_unit") private Integer costBonusUnit; /** - * 抵扣xx元,这里以分为单位) + * 抵扣xx元,这里以分为单位). */ @SerializedName("reduce_money") private Integer reduceMoney; /** - * 抵扣条件,满xx元(这里以分为单位)可用。 + * 抵扣条件,满xx元(这里以分为单位)可用. */ @SerializedName("least_moneyto_use_bonus") private Integer leastMoneytoUseBonus; /** - * 抵扣条件,单笔最多使用xx积分。 + * 抵扣条件,单笔最多使用xx积分. */ @SerializedName("max_reduce_bonus") private Integer maxReduceBonus; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CardUpdateResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CardUpdateResult.java new file mode 100644 index 00000000..42df19ff --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CardUpdateResult.java @@ -0,0 +1,23 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +/** + * @author yqx + * @date 2018/11/07 + */ +@Data +public class CardUpdateResult { + + private int errcode; + + private String errmsg; + + /** + * 此次更新是否需要提审,true为需要,false为不需要。 + */ + @SerializedName("send_check") + private boolean sendCheck; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomCell1.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomCell1.java index bfacd079..8789eca4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomCell1.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomCell1.java @@ -1,39 +1,40 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 自定义会员信息类目 - * author:yuanqixun + * 自定义会员信息类目. + * @author yuanqixun * date:2018-08-25 00:34 */ @Data public class CustomCell1 implements Serializable { + private static final long serialVersionUID = -6446192667149800447L; /** - * 入口名称 + * 入口名称. */ @SerializedName("name") private String name; /** - * 入口右侧提示语,6个汉字内。 + * 入口右侧提示语,6个汉字内. */ @SerializedName("tips") private String tips; /** - * 入口跳转链接。 + * 入口跳转链接. */ @SerializedName("url") private String url; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomField.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomField.java index da7df64b..df9c2e6f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomField.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CustomField.java @@ -1,19 +1,19 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 自定义会员信息类目 - * author:yuanqixun + * 自定义会员信息类目. + * @author yuanqixun * date:2018-08-25 00:34 */ @Data public class CustomField implements Serializable { + private static final long serialVersionUID = -5364412812328198195L; /** * 半自定义名称,当开发者变更这类类目信息的value值时 可以选择触发系统模板消息通知用户。 FIELD_NAME_TYPE_LEVEL 等级 FIELD_NAME_TYPE_COUPON 优惠券 FIELD_NAME_TYPE_STAMP 印花 FIELD_NAME_TYPE_DISCOUNT 折扣 FIELD_NAME_TYPE_ACHIEVEMEN 成就 FIELD_NAME_TYPE_MILEAGE 里程 FIELD_NAME_TYPE_SET_POINTS 集点 FIELD_NAME_TYPE_TIMS 次数 @@ -37,7 +37,8 @@ public class CustomField implements Serializable { return nameType; } + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DateInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DateInfo.java index a4296650..a3fac522 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DateInfo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DateInfo.java @@ -1,51 +1,57 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 使用日期,有效期的信息 - * author:yuanqixun + * 使用日期,有效期的信息. + * @author yuanqixun * date:2018-08-25 00:31 */ @Data public class DateInfo implements Serializable { + private static final long serialVersionUID = 2734999880412106549L; /** - * 使用时间的类型,支持固定时长有效类型 固定日期有效类型 永久有效类型:DATE_TYPE_FIX_TERM_RANGE、DATE_TYPE_FIX_TERM 、DATE_TYPE_PERMANENT + * 使用时间的类型. + * 支持固定时长有效类型 固定日期有效类型 永久有效类型:DATE_TYPE_FIX_TERM_RANGE、DATE_TYPE_FIX_TERM 、DATE_TYPE_PERMANENT */ @SerializedName("type") private String type = "DATE_TYPE_PERMANENT"; /** - * 起用时间,type为DATE_TYPE_FIX_TIME_RANGE时专用, 表示起用时间。从1970年1月1日00:00:00至起用时间的秒数 ( 东八区时间,UTC+8,单位为秒 ) + * 起用时间. + * type为DATE_TYPE_FIX_TIME_RANGE时专用, 表示起用时间。从1970年1月1日00:00:00至起用时间的秒数 ( 东八区时间,UTC+8,单位为秒 ) */ @SerializedName("begin_timestamp") private Long beginTimestamp; /** - * 结束时间,type为DATE_TYPE_FIX_TERM_RANGE时专用,表示结束时间 ( 东八区时间,UTC+8,单位为秒 ) + * 结束时间. + * type为DATE_TYPE_FIX_TERM_RANGE时专用,表示结束时间 ( 东八区时间,UTC+8,单位为秒 ) */ @SerializedName("end_timestamp") private Long endTimestamp; /** - * 自领取后多少天内有效,type为DATE_TYPE_FIX_TERM时专用,表示自领取后多少天内有效,领取后当天有效填写0(单位为天) + * 自领取后多少天内有效. + * type为DATE_TYPE_FIX_TERM时专用,表示自领取后多少天内有效,领取后当天有效填写0(单位为天) */ @SerializedName("fixed_term") private Integer fixedTerm; /** - * 自领取后多少天开始生效,type为DATE_TYPE_FIX_TERM时专用,表示自领取后多少天开始生效。(单位为天) + * 自领取后多少天开始生效. + * type为DATE_TYPE_FIX_TERM时专用,表示自领取后多少天开始生效。(单位为天) */ @SerializedName("fixed_begin_term") private Integer fixedBeginTerm; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCard.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCard.java index 48e28eff..b8b81399 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCard.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCard.java @@ -1,152 +1,156 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +/** + * . + * @author yuanqixun + */ @Data public final class MemberCard implements Serializable { + private static final long serialVersionUID = 2922028551810647622L; /** - * 会员卡背景图 + * 会员卡背景图. */ @SerializedName("background_pic_url") private String backgroundPicUrl; /** - * 基本信息 + * 基本信息. */ @SerializedName("base_info") private BaseInfo baseInfo; /** - * 特权说明 + * 特权说明. */ @SerializedName("prerogative") private String prerogative; /** - * 自动激活 + * 自动激活. */ @SerializedName("auto_activate") private boolean autoActivate; /** - * 是否一键开卡 + * 是否一键开卡. */ @SerializedName("wx_activate") private boolean wxActivate; /** - * 显示积分 + * 显示积分. */ @SerializedName("supply_bonus") private boolean supplyBonus; /** - * 查看积分外链,设置跳转外链查看积分详情。仅适用于积分无法通过激活接口同步的情况下使用该字段。 + * 查看积分外链,设置跳转外链查看积分详情。仅适用于积分无法通过激活接口同步的情况下使用该字段. */ @SerializedName("bonus_url") private String bonusUrl; /** - * 支持储值 + * 支持储值. */ @SerializedName("supply_balance") private boolean supplyBalance; /** - * 余额外链,仅适用于余额无法通过激活接口同步的情况下使用该字段。 + * 余额外链,仅适用于余额无法通过激活接口同步的情况下使用该字段. */ @SerializedName("balance_url") private String balanceUrl; /** - * 自定义会员类目1,会员卡激活后显示 + * 自定义会员类目1,会员卡激活后显示. */ @SerializedName("custom_field1") private CustomField customField1; /** - * 自定义会员类目2 + * 自定义会员类目2. */ @SerializedName("custom_field2") private CustomField customField2; /** - * 自定义会员类目3 + * 自定义会员类目3. */ @SerializedName("custom_field3") private CustomField customField3; /** - * 积分清零规则 + * 积分清零规则. */ @SerializedName("bonus_cleared") private String bonusCleared; /** - * 积分规则 + * 积分规则. */ @SerializedName("bonus_rules") private String bonusRules; /** - * 储值规则 + * 储值规则. */ @SerializedName("balance_rules") private String balanceRules; /** - * 激活会员卡的url + * 激活会员卡的url. */ @SerializedName("activate_url") private String activateUrl; /** - * 激活会原卡url对应的小程序user_name,仅可跳转该公众号绑定的小程序 + * 激活会原卡url对应的小程序user_name,仅可跳转该公众号绑定的小程序. */ @SerializedName("activate_app_brand_user_name") private String activateAppBrandUserName; /** - * 激活会原卡url对应的小程序path + * 激活会原卡url对应的小程序path. */ @SerializedName("activate_app_brand_pass") private String activateAppBrandPass; /** - * 自定义会员信息类目,会员卡激活后显示。 + * 自定义会员信息类目,会员卡激活后显示. */ @SerializedName("custom_cell1") private CustomCell1 customCell1; /** - * 积分规则,JSON结构积分规则 。 + * 积分规则,JSON结构积分规则. */ @SerializedName("bonus_rule") private BonusRule bonusRule; /** - * 折扣,该会员卡享受的折扣优惠,填10就是九折。 + * 折扣,该会员卡享受的折扣优惠,填10就是九折. */ private Integer discount; /** - * 创建优惠券特有的高级字段 + * 创建优惠券特有的高级字段. */ @SerializedName("advanced_info") private AdvancedInfo advancedInfo; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } public static MemberCard fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson(json, MemberCard.class); + return WxMpGsonBuilder.create().fromJson(json, MemberCard.class); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardActivateUserFormResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardActivateUserFormResult.java index c961676d..381feda1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardActivateUserFormResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardActivateUserFormResult.java @@ -1,11 +1,9 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import lombok.Data; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; @Data public class MemberCardActivateUserFormResult implements Serializable { @@ -22,7 +20,7 @@ public class MemberCardActivateUserFormResult implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardCreateRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardCreateRequest.java index 7e4139cb..b15cf225 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardCreateRequest.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardCreateRequest.java @@ -1,11 +1,10 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @Data public class MemberCardCreateRequest implements Serializable { @@ -15,7 +14,8 @@ public class MemberCardCreateRequest implements Serializable { @SerializedName("member_card") private MemberCard memberCard; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUpdate.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUpdate.java new file mode 100644 index 00000000..f1f9f91c --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUpdate.java @@ -0,0 +1,141 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * 会员卡更新对象 + * @author yuanqixun + */ +@Data +public final class MemberCardUpdate implements Serializable { + + //以下字段顺序根据微信官方文档顺序相同,不能传入非文档之外的字段 + //https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1466494654_K9rNz + + /** + * 基本信息. + */ + @SerializedName("base_info") + private BaseInfoUpdate baseInfo; + + /** + * 会员卡背景图. + */ + @SerializedName("background_pic_url") + private String backgroundPicUrl; + + /** + * 是否支持积分,仅支持从false变为true,默认为false + */ + @SerializedName("supply_bonus") + private Boolean supplyBonus; + + /** + * 积分清零规则. + */ + @SerializedName("bonus_cleared") + private String bonusCleared; + + /** + * 积分规则. + */ + @SerializedName("bonus_rules") + private String bonusRules; + + /** + * 查看积分外链,设置跳转外链查看积分详情。仅适用于积分无法通过激活接口同步的情况下使用该字段. + */ + @SerializedName("bonus_url") + private String bonusUrl; + + /** + * 余额外链,仅适用于余额无法通过激活接口同步的情况下使用该字段. + */ + @SerializedName("balance_url") + private String balanceUrl; + + /** + * 是否支持储值,仅支持从false变为true,默认为fals e 该字段须开通储值功能后方可使用, 详情见: 获取特殊权限 + */ + @SerializedName("supply_balance") + private Boolean supplyBalance; + + /** + * 储值规则. + */ + @SerializedName("balance_rules") + private String balanceRules; + + /** + * 特权说明. + */ + @SerializedName("prerogative") + private String prerogative; + + /** + * 自动激活. + */ + @SerializedName("auto_activate") + private Boolean autoActivate; + + /** + * 是否一键开卡. + */ + @SerializedName("wx_activate") + private Boolean wxActivate; + + /** + * 激活会员卡的url. + */ + @SerializedName("activate_url") + private String activateUrl; + + /** + * 自定义会员类目1,会员卡激活后显示. + */ + @SerializedName("custom_field1") + private CustomField customField1; + + /** + * 自定义会员类目2. + */ + @SerializedName("custom_field2") + private CustomField customField2; + + /** + * 自定义会员类目3. + */ + @SerializedName("custom_field3") + private CustomField customField3; + + /** + * 自定义会员信息类目,会员卡激活后显示. + */ + @SerializedName("custom_cell1") + private CustomCell1 customCell1; + + /** + * 积分规则,JSON结构积分规则. + */ + @SerializedName("bonus_rule") + private BonusRule bonusRule; + + /** + * 折扣,该会员卡享受的折扣优惠,填10就是九折. + */ + private Integer discount; + + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } + + public static MemberCardUpdate fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, MemberCardUpdate.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUpdateRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUpdateRequest.java new file mode 100644 index 00000000..37807a06 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUpdateRequest.java @@ -0,0 +1,21 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +@Data +public class MemberCardUpdateRequest implements Serializable { + @SerializedName("card_id") + private String cardId; + + @SerializedName("member_card") + private MemberCardUpdate memberCardUpdate; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserForm.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserForm.java index 14ef9f37..1087af38 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserForm.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserForm.java @@ -1,24 +1,25 @@ package me.chanjar.weixin.mp.bean.card; -import com.google.gson.annotations.SerializedName; -import lombok.Data; -import me.chanjar.weixin.mp.bean.card.enums.CardWechatFieldType; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.StringUtils; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.bean.card.enums.CardWechatFieldType; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + /** - * 用户表单对象 + * 用户表单对象. * * @author yuanqixun * @date 2018-08-30 */ @Data public class MemberCardUserForm implements Serializable { + private static final long serialVersionUID = -1142881966808073662L; /** * 当前结构(required_form或者optional_form )内的字段是否允许用户激活后再次修改, @@ -49,44 +50,48 @@ public class MemberCardUserForm implements Serializable { /** * 添加富文本类型字段 * - * @param fieldType */ public void addRichField(MemberCardUserFormRichField field) { - if (field == null) + if (field == null) { return; - if (richFieldList == null) + } + if (richFieldList == null) { richFieldList = new ArrayList<>(); + } richFieldList.add(field); } /** * 添加微信选项类型字段 * - * @param fieldType */ public void addWechatField(CardWechatFieldType fieldType) { - if (fieldType == null) + if (fieldType == null) { return; - if (wechatFieldIdList == null) + } + if (wechatFieldIdList == null) { wechatFieldIdList = new ArrayList<>(); + } wechatFieldIdList.add(fieldType.name()); } /** * 添加文本类型字段 * - * @param fieldType */ public void addCustomField(String field) { - if (StringUtils.isBlank(field)) + if (StringUtils.isBlank(field)) { return; - if (customFieldList == null) + } + if (customFieldList == null) { customFieldList = new ArrayList<>(); + } customFieldList.add(field); } + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserFormRichField.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserFormRichField.java index 6605f9b6..e109ebc6 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserFormRichField.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/MemberCardUserFormRichField.java @@ -1,16 +1,15 @@ package me.chanjar.weixin.mp.bean.card; +import java.util.ArrayList; +import java.util.List; + import com.google.gson.annotations.SerializedName; import lombok.Data; import me.chanjar.weixin.mp.bean.card.enums.CardRichFieldType; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.util.ArrayList; -import java.util.List; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 富文本字段 + * 富文本字段. * * @author yuanqixun * @date 2018-08-30 @@ -31,12 +30,14 @@ public class MemberCardUserFormRichField { private List valueList; public void add(String value) { - if (valueList == null) + if (valueList == null) { valueList = new ArrayList(); + } valueList.add(value); } + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/PayInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/PayInfo.java index 61fa8ccd..c16c55c9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/PayInfo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/PayInfo.java @@ -1,15 +1,14 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 支付功能 - * author:yuanqixun + * 支付功能. + * @author yuanqixun * date:2018-08-25 00:33 */ @Data @@ -21,7 +20,8 @@ public class PayInfo implements Serializable { @SerializedName("swipe_card") private SwipeCard swipeCard; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Sku.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Sku.java index 12db088d..504d56bf 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Sku.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Sku.java @@ -1,15 +1,14 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 商品信息 - * author:yuanqixun + * 商品信息. + * @author yuanqixun * date:2018-08-25 00:32 */ @Data @@ -21,7 +20,8 @@ public class Sku implements Serializable { @SerializedName("quantity") private Integer quantity = 100000000; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/SwipeCard.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/SwipeCard.java index fa176942..2e50a3cb 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/SwipeCard.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/SwipeCard.java @@ -1,15 +1,14 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 刷卡功能 - * author:yuanqixun + * 刷卡功能. + * @author yuanqixun * date:2018-08-25 00:33 */ @Data @@ -21,7 +20,8 @@ public class SwipeCard implements Serializable { @SerializedName("is_swipe_card") private boolean isSwipeCard; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TextImageList.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TextImageList.java index 5836d956..f974d1e4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TextImageList.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TextImageList.java @@ -1,15 +1,14 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 图文列表 - * author:yuanqixun + * 图文列表. + * @author yuanqixun * date:2018-08-25 00:35 */ @Data @@ -22,12 +21,13 @@ public class TextImageList implements Serializable { private String imageUrl; /** - * 图文描述 + * 图文描述. */ @SerializedName("text") private String text; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TimeLimit.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TimeLimit.java index 4c0d17d5..92bacfe1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TimeLimit.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/TimeLimit.java @@ -1,16 +1,14 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; -//子对象列表 +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * 使用时段限制 - * author:yuanqixun + * 使用时段限制. + * @author yuanqixun * date:2018-08-25 00:34 */ @Data @@ -46,7 +44,8 @@ public class TimeLimit implements Serializable { @SerializedName("end_minute") private Integer endMinute; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/UseCondition.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/UseCondition.java index ff8fa830..a62066df 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/UseCondition.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/UseCondition.java @@ -1,16 +1,15 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; //子对象列表 /** * 使用门槛 - * author:yuanqixun + * @author yuanqixun * date:2018-08-25 00:35 */ @Data @@ -46,7 +45,8 @@ public class UseCondition implements Serializable { @SerializedName("can_use_with_other_discount") private boolean canUseWithOtherDiscount; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardCreateResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardCreateResult.java index 24875d4e..60aded5a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardCreateResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardCreateResult.java @@ -1,13 +1,15 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; +/** + * . + * @author yuanqixun + */ @Data public class WxMpCardCreateResult implements Serializable { private static final long serialVersionUID = -128818731449449537L; @@ -40,7 +42,7 @@ public class WxMpCardCreateResult implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateRequest.java index 6a55a26a..162cbd0a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateRequest.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateRequest.java @@ -1,15 +1,14 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + +import org.apache.commons.lang3.StringUtils; + import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.annotations.SerializedName; import lombok.Data; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; @Data public class WxMpCardLandingPageCreateRequest implements Serializable { @@ -45,8 +44,9 @@ public class WxMpCardLandingPageCreateRequest implements Serializable { public void addCard(String cardId, String thumbUrl) { if (StringUtils.isNoneBlank(cardId, thumbUrl)) { - if (cardList == null) + if (cardList == null) { cardList = new JsonArray(); + } JsonObject cardJson = new JsonObject(); cardJson.addProperty("card_id", cardId); cardJson.addProperty("thumb_url", thumbUrl); @@ -60,7 +60,7 @@ public class WxMpCardLandingPageCreateRequest implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateResult.java index f99b5f18..8d7c4960 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardLandingPageCreateResult.java @@ -1,12 +1,10 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; @Data public class WxMpCardLandingPageCreateResult implements Serializable { @@ -33,7 +31,7 @@ public class WxMpCardLandingPageCreateResult implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardQrcodeCreateResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardQrcodeCreateResult.java index 46fb6323..d0140f35 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardQrcodeCreateResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardQrcodeCreateResult.java @@ -1,12 +1,10 @@ package me.chanjar.weixin.mp.bean.card; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; @Data public class WxMpCardQrcodeCreateResult implements Serializable { @@ -33,7 +31,7 @@ public class WxMpCardQrcodeCreateResult implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(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 3901c61f..39198821 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 @@ -1,13 +1,13 @@ package me.chanjar.weixin.mp.bean.datacube; +import java.util.List; + import com.google.gson.annotations.SerializedName; import com.google.gson.reflect.TypeToken; import lombok.Data; import lombok.EqualsAndHashCode; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import java.util.List; - /** * 图文分析数据接口返回结果对象 *

@@ -114,7 +114,7 @@ public class WxDataCubeArticleResult extends WxDataCubeBaseResult { private Integer userSource; public static List fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson( + return WxMpGsonBuilder.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 bef0e66d..722b6c25 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,13 +1,13 @@ package me.chanjar.weixin.mp.bean.datacube; +import java.util.List; + import com.google.gson.annotations.SerializedName; import com.google.gson.reflect.TypeToken; import lombok.Data; import lombok.EqualsAndHashCode; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import java.util.List; - /** * 图文分析数据接口返回结果对象. * Created by Binary Wang on 2016/8/24. @@ -41,7 +41,7 @@ public class WxDataCubeArticleTotal extends WxDataCubeBaseResult { private List details; public static List fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson( + return WxMpGsonBuilder.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/WxDataCubeBaseResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeBaseResult.java index ee2a7d93..f86035c6 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 @@ -2,12 +2,10 @@ package me.chanjar.weixin.mp.bean.datacube; import java.io.Serializable; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import com.google.gson.JsonParser; import com.google.gson.annotations.SerializedName; import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** *

@@ -31,7 +29,7 @@ public abstract class WxDataCubeBaseResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
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 b151c008..0207d288 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
@@ -56,7 +56,7 @@ public class WxDataCubeInterfaceResult extends WxDataCubeBaseResult {
   private Integer maxTimeCost;
 
   public static List fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(
+    return WxMpGsonBuilder.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 1e7e1f58..b8796009 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
@@ -69,7 +69,7 @@ public class WxDataCubeMsgResult extends WxDataCubeBaseResult {
   private Integer oriPageReadUser;
 
   public static List fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(
+    return WxMpGsonBuilder.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 5275e140..f26ac125 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
@@ -4,9 +4,7 @@ import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
+import com.google.gson.GsonBuilder;
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
 import lombok.Data;
@@ -31,7 +29,7 @@ public class WxDataCubeUserCumulate implements Serializable {
   private Integer cumulateUser;
 
   public static List fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(
+    return WxMpGsonBuilder.create().fromJson(
       JSON_PARSER.parse(json).getAsJsonObject().get("list"),
       new TypeToken>() {
       }.getType());
@@ -39,6 +37,6 @@ public class WxDataCubeUserCumulate implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 }
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 06d93821..4d28c7b9 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
@@ -4,9 +4,7 @@ import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
+import com.google.gson.GsonBuilder;
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
 import lombok.Data;
@@ -33,7 +31,7 @@ public class WxDataCubeUserSummary implements Serializable {
   private Integer cancelUser;
 
   public static List fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(
+    return WxMpGsonBuilder.create().fromJson(
       JSON_PARSER.parse(json).getAsJsonObject().get("list"),
       new TypeToken>() {
       }.getType());
@@ -41,6 +39,6 @@ public class WxDataCubeUserSummary implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 }
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 9e12a5bb..2b554abc 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
@@ -1,11 +1,9 @@
 package me.chanjar.weixin.mp.bean.device;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * @author keungtung.
@@ -26,6 +24,6 @@ public class WxDeviceMsg extends AbstractDeviceBean {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceQrCodeResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceQrCodeResult.java
index 0e0d96f4..81635481 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceQrCodeResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceQrCodeResult.java
@@ -24,7 +24,7 @@ public class WxDeviceQrCodeResult extends AbstractDeviceBean {
   private BaseResp baseResp;
 
   public static WxDeviceQrCodeResult fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxDeviceQrCodeResult.class);
+    return WxMpGsonBuilder.create().fromJson(json, WxDeviceQrCodeResult.class);
   }
 
 }
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 2b243252..92c298a6 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
@@ -117,7 +117,7 @@ public class WxMpKefuMessage implements Serializable {
   }
 
   public String toJson() {
-    return WxMpGsonBuilder.INSTANCE.create().toJson(this);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
   @Data
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 f20c34d7..01633192 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
@@ -43,7 +43,7 @@ public class WxMpKfAccountRequest implements Serializable {
   }
 
   public String toJson() {
-    return WxMpGsonBuilder.INSTANCE.create().toJson(this);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java
index 6cc00f5c..38b25461 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java
@@ -2,9 +2,6 @@ package me.chanjar.weixin.mp.bean.kefu.request;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
@@ -32,11 +29,11 @@ public class WxMpKfSessionRequest implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return this.toJson();
   }
 
   public String toJson() {
-    return WxMpGsonBuilder.INSTANCE.create().toJson(this);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
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 76f25d9b..f14feb29 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
@@ -2,12 +2,10 @@ package me.chanjar.weixin.mp.bean.kefu.result;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.Expose;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * 客服基本信息以及客服在线状态信息
@@ -81,7 +79,7 @@ public class WxMpKfInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
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 d7ac2043..cadfc8c7 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
@@ -3,9 +3,6 @@ package me.chanjar.weixin.mp.bean.kefu.result;
 import java.io.Serializable;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
@@ -21,12 +18,12 @@ public class WxMpKfList implements Serializable {
   private List kfList;
 
   public static WxMpKfList fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfList.class);
+    return WxMpGsonBuilder.create().fromJson(json, WxMpKfList.class);
   }
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
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 01b262dd..af5559ea 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
@@ -3,9 +3,6 @@ package me.chanjar.weixin.mp.bean.kefu.result;
 import java.io.Serializable;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
@@ -29,11 +26,11 @@ public class WxMpKfMsgList implements Serializable {
   private Long msgId;
 
   public static WxMpKfMsgList fromJson(String responseContent) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(responseContent, WxMpKfMsgList.class);
+    return WxMpGsonBuilder.create().fromJson(responseContent, WxMpKfMsgList.class);
   }
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 }
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 fc3a1471..325c66aa 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
@@ -2,11 +2,9 @@ package me.chanjar.weixin.mp.bean.kefu.result;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  *
@@ -49,7 +47,7 @@ public class WxMpKfMsgRecord implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
   public String getWorker() {
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 e1e8c298..7f7b7db8 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
@@ -3,9 +3,7 @@ package me.chanjar.weixin.mp.bean.kefu.result;
 import java.io.Serializable;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
+import com.google.gson.GsonBuilder;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
@@ -21,12 +19,12 @@ public class WxMpKfOnlineList implements Serializable {
   private List kfOnlineList;
 
   public static WxMpKfOnlineList fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfOnlineList.class);
+    return WxMpGsonBuilder.create().fromJson(json, WxMpKfOnlineList.class);
   }
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
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 c5e9b02a..3f4d49d2 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
@@ -2,11 +2,9 @@ package me.chanjar.weixin.mp.bean.kefu.result;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * @author Binary Wang
@@ -43,7 +41,7 @@ public class WxMpKfSession implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
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 628bd7c4..2b833aa2 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
@@ -2,9 +2,7 @@ package me.chanjar.weixin.mp.bean.kefu.result;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
+import com.google.gson.GsonBuilder;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
@@ -29,12 +27,12 @@ public class WxMpKfSessionGetResult implements Serializable {
   private long createTime;
 
   public static WxMpKfSessionGetResult fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfSessionGetResult.class);
+    return WxMpGsonBuilder.create().fromJson(json, WxMpKfSessionGetResult.class);
   }
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
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 4aacdd1e..37708a2b 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
@@ -3,9 +3,6 @@ package me.chanjar.weixin.mp.bean.kefu.result;
 import java.io.Serializable;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
@@ -24,13 +21,13 @@ public class WxMpKfSessionList implements Serializable {
   private List kfSessionList;
 
   public static WxMpKfSessionList fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(json,
+    return WxMpGsonBuilder.create().fromJson(json,
       WxMpKfSessionList.class);
   }
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
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 69b5b915..2fb0ea56 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
@@ -3,9 +3,6 @@ package me.chanjar.weixin.mp.bean.kefu.result;
 import java.io.Serializable;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
@@ -30,13 +27,13 @@ public class WxMpKfSessionWaitCaseList implements Serializable {
   private List kfSessionWaitCaseList;
 
   public static WxMpKfSessionWaitCaseList fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(json,
+    return WxMpGsonBuilder.create().fromJson(json,
       WxMpKfSessionWaitCaseList.class);
   }
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialCountResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialCountResult.java
index ba457e79..721b31fc 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialCountResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialCountResult.java
@@ -2,10 +2,8 @@ package me.chanjar.weixin.mp.bean.material;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * @author codepiano
@@ -21,7 +19,7 @@ public class WxMpMaterialCountResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialFileBatchGetResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialFileBatchGetResult.java
index 3d6e9353..ebad06bf 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialFileBatchGetResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialFileBatchGetResult.java
@@ -4,10 +4,8 @@ import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * @author codepiano
@@ -22,7 +20,7 @@ public class WxMpMaterialFileBatchGetResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
   @Data
@@ -34,7 +32,7 @@ public class WxMpMaterialFileBatchGetResult implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
   }
 }
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 16f787a3..e2f27d9e 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
@@ -5,21 +5,20 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
+ * 图文素材.
+ *
  * @author codepiano
  */
 @Data
 public class WxMpMaterialNews implements Serializable {
   private static final long serialVersionUID = -3283203652013494976L;
 
-  private Date createdTime;
-  private Date updatedTime;
+  private Date createTime;
+  private Date updateTime;
 
   private List articles = new ArrayList<>();
 
@@ -32,7 +31,7 @@ public class WxMpMaterialNews implements Serializable {
   }
 
   public String toJson() {
-    return WxMpGsonBuilder.INSTANCE.create().toJson(this);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
   public boolean isEmpty() {
@@ -46,7 +45,7 @@ public class WxMpMaterialNews implements Serializable {
 
   /**
    * 
-   * 群发图文消息article
+   * 群发图文消息article.
    * 1. thumbMediaId  (必填) 图文消息的封面图片素材id(必须是永久mediaID)
    * 2. author          图文消息的作者
    * 3. title           (必填) 图文消息的标题
@@ -55,8 +54,8 @@ public class WxMpMaterialNews implements Serializable {
    * 6. digest          图文消息的描述
    * 7. showCoverPic  是否显示封面,true为显示,false为不显示
    * 8. url           点击图文消息跳转链接
-   * 9. need_open_comment(新增字段)	否	Uint32	是否打开评论,0不打开,1打开
-   * 10. only_fans_can_comment(新增字段)	否	Uint32	是否粉丝才可评论,0所有人可评论,1粉丝才可评论
+   * 9. need_open_comment(新增字段) 否 Uint32 是否打开评论,0不打开,1打开
+   * 10. only_fans_can_comment(新增字段) 否 Uint32 是否粉丝才可评论,0所有人可评论,1粉丝才可评论
    * 
* * @author chanjarster @@ -64,58 +63,58 @@ public class WxMpMaterialNews implements Serializable { @Data public static class WxMpMaterialNewsArticle { /** - * (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得 + * (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得. */ private String thumbMediaId; /** - * 图文消息的封面url + * 图文消息的封面url. */ private String thumbUrl; /** - * 图文消息的作者 + * 图文消息的作者. */ private String author; /** - * (必填) 图文消息的标题 + * (必填) 图文消息的标题. */ private String title; /** - * 在图文消息页面点击“阅读原文”后的页面链接 + * 在图文消息页面点击“阅读原文”后的页面链接. */ private String contentSourceUrl; /** - * (必填) 图文消息页面的内容,支持HTML标签 + * (必填) 图文消息页面的内容,支持HTML标签. */ private String content; /** - * 图文消息的描述 + * 图文消息的描述. */ private String digest; /** - * 是否显示封面,true为显示,false为不显示 + * 是否显示封面,true为显示,false为不显示. */ private boolean showCoverPic; /** - * 点击图文消息跳转链接 + * 点击图文消息跳转链接. */ private String url; /** * need_open_comment - * 是否打开评论,0不打开,1打开 + * 是否打开评论,0不打开,1打开. */ private Boolean needOpenComment; /** * only_fans_can_comment - * 是否粉丝才可评论,0所有人可评论,1粉丝才可评论 + * 是否粉丝才可评论,0所有人可评论,1粉丝才可评论. */ private Boolean onlyFansCanComment; @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNewsBatchGetResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNewsBatchGetResult.java index 47e6cb53..894709ac 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNewsBatchGetResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/material/WxMpMaterialNewsBatchGetResult.java @@ -4,10 +4,8 @@ import java.io.Serializable; import java.util.Date; import java.util.List; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @Data public class WxMpMaterialNewsBatchGetResult implements Serializable { @@ -19,7 +17,7 @@ public class WxMpMaterialNewsBatchGetResult implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } @Data @@ -30,7 +28,7 @@ public class WxMpMaterialNewsBatchGetResult implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(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 15744ce5..0d133a76 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 @@ -2,9 +2,6 @@ package me.chanjar.weixin.mp.bean.material; import java.io.Serializable; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import lombok.Data; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -22,7 +19,7 @@ public class WxMpMaterialUploadResult implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/ActivatePluginParam.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/ActivatePluginParam.java new file mode 100644 index 00000000..526ff5cc --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/ActivatePluginParam.java @@ -0,0 +1,22 @@ +package me.chanjar.weixin.mp.bean.membercard; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +/** + * @author yqx + * @date 2018/9/19 + */ +@Data +public class ActivatePluginParam { + + @SerializedName("encrypt_card_id") + String encryptCardId; + + @SerializedName("outer_str") + String outerStr; + + @SerializedName("biz") + String biz; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/ActivatePluginParamResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/ActivatePluginParamResult.java new file mode 100644 index 00000000..4f060557 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/ActivatePluginParamResult.java @@ -0,0 +1,18 @@ +package me.chanjar.weixin.mp.bean.membercard; + +import lombok.Data; + +/** + * @author yqx + * @date 2018/9/19 + */ +@Data +public class ActivatePluginParamResult { + + private int errcode; + + private String errmsg; + + private String url; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardCreateMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardCreateMessage.java index bd8fccb4..d8842c73 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardCreateMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardCreateMessage.java @@ -1,13 +1,11 @@ package me.chanjar.weixin.mp.bean.membercard; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import lombok.Data; import me.chanjar.weixin.mp.bean.card.MemberCardCreateRequest; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import java.io.Serializable; @Data public final class WxMpMemberCardCreateMessage implements Serializable { @@ -15,11 +13,12 @@ public final class WxMpMemberCardCreateMessage implements Serializable { @SerializedName("card") private MemberCardCreateRequest cardCreateRequest; + @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } public static WxMpMemberCardCreateMessage fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpMemberCardCreateMessage.class); + return WxMpGsonBuilder.create().fromJson(json, WxMpMemberCardCreateMessage.class); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java index 96b8212d..7b9dfb49 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUpdateResult.java @@ -2,9 +2,6 @@ package me.chanjar.weixin.mp.bean.membercard; import java.io.Serializable; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import lombok.Data; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -34,10 +31,10 @@ public class WxMpMemberCardUpdateResult implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } public static WxMpMemberCardUpdateResult fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpMemberCardUpdateResult.class); + return WxMpGsonBuilder.create().fromJson(json, WxMpMemberCardUpdateResult.class); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java index 705dba78..fca7da92 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/membercard/WxMpMemberCardUserInfoResult.java @@ -2,9 +2,6 @@ package me.chanjar.weixin.mp.bean.membercard; import java.io.Serializable; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import lombok.Data; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -47,11 +44,11 @@ public class WxMpMemberCardUserInfoResult implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxMpGsonBuilder.create().toJson(this); } public static WxMpMemberCardUserInfoResult fromJson(String json) { - return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpMemberCardUserInfoResult.class); + return WxMpGsonBuilder.create().fromJson(json, WxMpMemberCardUserInfoResult.class); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResult.java index 2c370eaf..8fb937ce 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResult.java @@ -2,12 +2,10 @@ package me.chanjar.weixin.mp.bean.menu; import java.io.Serializable; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - import com.google.gson.annotations.SerializedName; import lombok.Data; import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** *
@@ -32,7 +30,7 @@ public class WxMpGetSelfMenuInfoResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java
index e36a2b23..f94c59e2 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java
@@ -3,14 +3,12 @@ package me.chanjar.weixin.mp.bean.menu;
 import java.io.Serializable;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.common.bean.menu.WxMenuButton;
 import me.chanjar.weixin.common.bean.menu.WxMenuRule;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * 
@@ -36,7 +34,7 @@ public class WxMpMenu implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return this.toJson();
   }
 
   public String toJson() {
@@ -56,7 +54,7 @@ public class WxMpMenu implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
 
   }
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 b9d8e941..4789b470 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
@@ -4,11 +4,9 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * 
@@ -29,7 +27,7 @@ public class WxMpSelfMenuInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
   @Data
@@ -89,7 +87,7 @@ public class WxMpSelfMenuInfo implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
 
     @Data
@@ -101,7 +99,7 @@ public class WxMpSelfMenuInfo implements Serializable {
 
       @Override
       public String toString() {
-        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+        return WxMpGsonBuilder.create().toJson(this);
       }
     }
 
@@ -114,7 +112,7 @@ public class WxMpSelfMenuInfo implements Serializable {
 
       @Override
       public String toString() {
-        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+        return WxMpGsonBuilder.create().toJson(this);
       }
 
       @Data
@@ -160,7 +158,7 @@ public class WxMpSelfMenuInfo implements Serializable {
 
         @Override
         public String toString() {
-          return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+          return WxMpGsonBuilder.create().toJson(this);
         }
 
       }
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
index f29321d4..a75c98e0 100644
--- 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
@@ -2,13 +2,11 @@ package me.chanjar.weixin.mp.bean.message;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * 
@@ -19,7 +17,7 @@ import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
  */
 @XStreamAlias("HardWare")
 @Data
-public class HardWare implements Serializable{
+public class HardWare implements Serializable {
   private static final long serialVersionUID = -1295785297354896461L;
 
   /**
@@ -37,6 +35,6 @@ public class HardWare implements Serializable{
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 }
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
index 2af977ca..f53b44c4 100644
--- 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
@@ -2,13 +2,11 @@ package me.chanjar.weixin.mp.bean.message;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * 
@@ -38,7 +36,7 @@ public class ScanCodeInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
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
index 5d725557..09f1776b 100644
--- 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
@@ -2,13 +2,11 @@ package me.chanjar.weixin.mp.bean.message;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * 
@@ -44,6 +42,6 @@ public class SendLocationInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 }
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
index 318e7cee..a01e6659 100644
--- 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
@@ -4,13 +4,11 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * 
@@ -32,7 +30,7 @@ public class SendPicsInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
   @XStreamAlias("item")
@@ -46,7 +44,7 @@ public class SendPicsInfo implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
 
   }
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 ae476331..368f70e3 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
@@ -3,19 +3,21 @@ package me.chanjar.weixin.mp.bean.message;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.api.WxConsts;
+import me.chanjar.weixin.common.util.XmlUtils;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
 import me.chanjar.weixin.mp.api.WxMpConfigStorage;
 import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 import me.chanjar.weixin.mp.util.xml.XStreamTransformer;
 
 /**
@@ -34,6 +36,11 @@ import me.chanjar.weixin.mp.util.xml.XStreamTransformer;
 public class WxMpXmlMessage implements Serializable {
   private static final long serialVersionUID = -3586245291677274914L;
 
+  /**
+   * 使用dom4j解析的存放所有xml属性和值的map.
+   */
+  private Map allFieldsMap;
+
   ///////////////////////
   // 以下都是微信推送过来的消息的xml的element所对应的属性
   ///////////////////////
@@ -129,6 +136,10 @@ public class WxMpXmlMessage implements Serializable {
   @XStreamConverter(value = XStreamCDataConverter.class)
   private String recognition;
 
+  @XStreamAlias("UnionId")
+  @XStreamConverter(value = XStreamCDataConverter.class)
+  private String unionId;
+
   ///////////////////////////////////////
   // 群发消息返回的结果
   ///////////////////////////////////////
@@ -435,6 +446,8 @@ public class WxMpXmlMessage implements Serializable {
 
   /**
    * 审核结果,成功succ 或失败fail.
+   *
+   * 在商品审核结果推送时,verify_ok表示审核通过,verify_not_pass表示审核未通过。
    */
   @XStreamAlias("Result")
   private String result;
@@ -541,10 +554,89 @@ public class WxMpXmlMessage implements Serializable {
   @XStreamAlias("DeviceStatus")
   private Integer deviceStatus;
 
+  ///////////////////////////////////////
+  // 小程序 审核事件
+  ///////////////////////////////////////
+  /**
+   * 审核成功时的时间(整形),时间戳
+   */
+  @XStreamAlias("SuccTime")
+  private Long succTime;
+
+  /**
+   * 审核失败的原因
+   */
+  @XStreamAlias("Reason")
+  private String reason;
+
+  ///////////////////////////////////////
+  // 扫一扫事件推送
+  ///////////////////////////////////////
+  /**
+   * 商品编码标准
+   */
+  @XStreamAlias("KeyStandard")
+  private String keyStandard;
+  /**
+   * 商品编码内容
+   */
+  @XStreamAlias("KeyStr")
+  private String keyStr;
+
+  /**
+   * 用户在微信内设置的国家
+   */
+  @XStreamAlias("Country")
+  private String country;
+
+  /**
+   * 用户在微信内设置的省份
+   */
+  @XStreamAlias("Province")
+  private String province;
+
+  /**
+   * 用户在微信内设置的城市
+   */
+  @XStreamAlias("City")
+  private String city;
+
+  /**
+   * 用户的性别,1为男性,2为女性,0代表未知
+   */
+  @XStreamAlias("Sex")
+  private String sex;
+
+  /**
+   * 打开商品主页的场景,1为扫码,2为其他打开场景(如会话、收藏或朋友圈)
+   */
+  @XStreamAlias("Scene")
+  private String scene;
+
+  /**
+   * 调用“获取商品二维码接口”时传入的extinfo,为标识参数
+   */
+  @XStreamAlias("ExtInfo")
+  private String extInfo;
+
+  /**
+   * 用户的实时地理位置信息(目前只精确到省一级),可在国家统计局网站查到对应明细: http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/201504/t20150415_712722.html
+   */
+  @XStreamAlias("RegionCode")
+  private String regionCode;
+
+  /**
+   * 审核未通过的原因。
+   */
+  @XStreamAlias("ReasonMsg")
+  private String reasonMsg;
+
   public static WxMpXmlMessage fromXml(String xml) {
     //修改微信变态的消息内容格式,方便解析
     xml = xml.replace("", "");
-    return XStreamTransformer.fromXml(WxMpXmlMessage.class, xml);
+    final WxMpXmlMessage xmlMessage = XStreamTransformer.fromXml(WxMpXmlMessage.class, xml);
+    xmlMessage.setAllFieldsMap(XmlUtils.xml2Map(xml));
+    return xmlMessage;
   }
 
   public static WxMpXmlMessage fromXml(InputStream is) {
@@ -571,7 +663,7 @@ public class WxMpXmlMessage implements Serializable {
   public static WxMpXmlMessage fromEncryptedXml(InputStream is, WxMpConfigStorage wxMpConfigStorage, String timestamp,
                                                 String nonce, String msgSignature) {
     try {
-      return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage, timestamp, nonce, msgSignature);
+      return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), wxMpConfigStorage, timestamp, nonce, msgSignature);
     } catch (IOException e) {
       throw new RuntimeException(e);
     }
@@ -610,7 +702,7 @@ public class WxMpXmlMessage implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java
index 7cbf9b7f..c6acc080 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCardResult.java
@@ -2,11 +2,9 @@ package me.chanjar.weixin.mp.bean.result;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
 import me.chanjar.weixin.mp.bean.WxMpCard;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * 卡券查询Code,核销Code接口返回结果
@@ -32,7 +30,7 @@ public class WxMpCardResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpChangeOpenid.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpChangeOpenid.java
new file mode 100644
index 00000000..203aa97f
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpChangeOpenid.java
@@ -0,0 +1,34 @@
+package me.chanjar.weixin.mp.bean.result;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.reflect.TypeToken;
+import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+
+import java.io.Serializable;
+import java.lang.reflect.Type;
+import java.util.List;
+
+/**
+ * 主体变更迁移用户 openid 返回.
+ *
+ * @author 007gzs
+ */
+@Data
+public class WxMpChangeOpenid implements Serializable {
+  private static final long serialVersionUID = -8132023284876534743L;
+  private String oriOpenid;
+  private String newOpenid;
+  private String errMsg;
+  public static WxMpChangeOpenid fromJson(String json) {
+    return WxMpGsonBuilder.create().fromJson(json, WxMpChangeOpenid.class);
+  }
+  public static List fromJsonList(String json) {
+    Type collectionType = new TypeToken>() {
+    }.getType();
+    Gson gson = WxMpGsonBuilder.create();
+    JsonObject jsonObject = gson.fromJson(json, JsonObject.class);
+    return gson.fromJson(jsonObject.get("result_list"), collectionType);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java
index d68fcacf..d702eeaf 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpCurrentAutoReplyInfo.java
@@ -4,9 +4,6 @@ import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.JsonAdapter;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
@@ -28,7 +25,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
   public static WxMpCurrentAutoReplyInfo fromJson(String json) {
@@ -58,7 +55,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
 
     @SerializedName("rule_name")
@@ -85,7 +82,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
 
     private String type;
@@ -102,7 +99,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
 
     private List list;
@@ -115,7 +112,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
 
     @SerializedName("cover_url")
@@ -139,7 +136,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
 
     private String type;
@@ -155,7 +152,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
 
     private List list;
@@ -167,7 +164,7 @@ public class WxMpCurrentAutoReplyInfo implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
 
     private String type;
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 392cc046..d18b7134 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
@@ -2,9 +2,6 @@ package me.chanjar.weixin.mp.bean.result;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
@@ -34,7 +31,7 @@ public class WxMpMassSendResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(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 98410891..03613dcb 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
@@ -2,9 +2,6 @@ package me.chanjar.weixin.mp.bean.result;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
@@ -30,7 +27,7 @@ public class WxMpMassUploadResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
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 33fa172d..24b87d7a 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
@@ -2,9 +2,6 @@ package me.chanjar.weixin.mp.bean.result;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
@@ -37,6 +34,6 @@ public class WxMpOAuth2AccessToken implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 }
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 ee78096b..cd2d1994 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
@@ -22,11 +22,11 @@ public class WxMpQrCodeTicket implements Serializable {
   protected String url;
 
   public static WxMpQrCodeTicket fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpQrCodeTicket.class);
+    return WxMpGsonBuilder.create().fromJson(json, WxMpQrCodeTicket.class);
   }
 
   @Override
   public String toString() {
-    return WxMpGsonBuilder.INSTANCE.create().toJson(this);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 }
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 818c4c5f..4d22fab9 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
@@ -4,9 +4,6 @@ import java.io.Serializable;
 import java.lang.reflect.Type;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
 import com.google.gson.reflect.TypeToken;
@@ -76,20 +73,20 @@ public class WxMpUser implements Serializable {
 
 
   public static WxMpUser fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUser.class);
+    return WxMpGsonBuilder.create().fromJson(json, WxMpUser.class);
   }
 
   public static List fromJsonList(String json) {
     Type collectionType = new TypeToken>() {
     }.getType();
-    Gson gson = WxMpGsonBuilder.INSTANCE.create();
+    Gson gson = WxMpGsonBuilder.create();
     JsonObject jsonObject = gson.fromJson(json, JsonObject.class);
     return gson.fromJson(jsonObject.get("user_info_list"), collectionType);
   }
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserBlacklistGetResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserBlacklistGetResult.java
index 83e1e244..40e2a716 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserBlacklistGetResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserBlacklistGetResult.java
@@ -20,11 +20,11 @@ public class WxMpUserBlacklistGetResult implements Serializable {
   protected String nextOpenid;
 
   public static WxMpUserBlacklistGetResult fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUserBlacklistGetResult.class);
+    return WxMpGsonBuilder.create().fromJson(json, WxMpUserBlacklistGetResult.class);
   }
 
   @Override
   public String toString() {
-    return WxMpGsonBuilder.INSTANCE.create().toJson(this);
+    return WxMpGsonBuilder.create().toJson(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 5f816456..e6c8d654 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
@@ -22,11 +22,11 @@ public class WxMpUserList implements Serializable {
   protected String nextOpenid;
 
   public static WxMpUserList fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUserList.class);
+    return WxMpGsonBuilder.create().fromJson(json, WxMpUserList.class);
   }
 
   @Override
   public String toString() {
-    return WxMpGsonBuilder.INSTANCE.create().toJson(this);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/shake/WxMpShakeAroundPageAddResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/shake/WxMpShakeAroundPageAddResult.java
index 632fe4f3..f80cfe52 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/shake/WxMpShakeAroundPageAddResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/shake/WxMpShakeAroundPageAddResult.java
@@ -13,7 +13,7 @@ public class WxMpShakeAroundPageAddResult implements Serializable {
   private String errorMsg;
   private Integer pageId;
   public static WxMpShakeAroundPageAddResult fromJson(String json) {
-    JsonObject jsonObject = WxMpGsonBuilder.INSTANCE.create().fromJson(json, JsonObject.class);
+    JsonObject jsonObject = WxMpGsonBuilder.create().fromJson(json, JsonObject.class);
     WxMpShakeAroundPageAddResult result = new WxMpShakeAroundPageAddResult();
     result.setErrorCode(GsonHelper.getInteger(jsonObject, "errcode"));
     result.setErrorMsg(GsonHelper.getString(jsonObject, "errmsg"));
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/shake/WxMpShakeAroundRelationSearchResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/shake/WxMpShakeAroundRelationSearchResult.java
index 2b7269e5..71dbd8d8 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/shake/WxMpShakeAroundRelationSearchResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/shake/WxMpShakeAroundRelationSearchResult.java
@@ -12,7 +12,7 @@ public class WxMpShakeAroundRelationSearchResult implements Serializable {
   private String errmsg;
   private WxMpShakeAcoundRelationSearch data;
   public static WxMpShakeAroundRelationSearchResult fromJson(String json) {
-    return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpShakeAroundRelationSearchResult.class);
+    return WxMpGsonBuilder.create().fromJson(json, WxMpShakeAroundRelationSearchResult.class);
   }
   @Data
   public static class WxMpShakeAcoundRelationSearch implements Serializable{
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 03f814af..d2249765 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
@@ -4,9 +4,6 @@ import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.annotations.SerializedName;
@@ -179,7 +176,7 @@ public class WxMpStoreBaseInfo implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return this.toJson();
   }
 
   public String toJson() {
@@ -195,7 +192,7 @@ public class WxMpStoreBaseInfo implements Serializable {
   public static class WxMpStorePhoto implements Serializable {
     private static final long serialVersionUID = -2942447907614186861L;
     /**
-     * 照片url
+     * 照片url.
      */
     @SerializedName("photo_url")
     private String photoUrl;
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 3002e190..58a9efd2 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
@@ -2,17 +2,17 @@ package me.chanjar.weixin.mp.bean.store;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
+ * .
+ *
  * @author BinaryWang
  */
 @Data
-public class WxMpStoreInfo implements Serializable{
+public class WxMpStoreInfo implements Serializable {
   private static final long serialVersionUID = 7300598931768355461L;
 
   @SerializedName("base_info")
@@ -20,6 +20,6 @@ public class WxMpStoreInfo implements Serializable{
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 }
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 079b5c1c..6841297c 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
@@ -3,9 +3,6 @@ package me.chanjar.weixin.mp.bean.store;
 import java.io.Serializable;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
@@ -49,7 +46,7 @@ public class WxMpStoreListResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java
index b6f1eef5..51c312d3 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java
@@ -66,7 +66,7 @@ public class WxMpSubscribeMessage {
 
 
   public String toJson() {
-    return WxMpGsonBuilder.INSTANCE.create().toJson(this);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
   @Data
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 d6606cf1..8ee62813 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
@@ -3,9 +3,6 @@ package me.chanjar.weixin.mp.bean.tag;
 import java.io.Serializable;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
@@ -48,7 +45,7 @@ public class WxTagListUser implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return this.toJson();
   }
 
   @Data
@@ -63,7 +60,7 @@ public class WxTagListUser implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
   }
 }
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 77251df2..83782f66 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
@@ -3,9 +3,6 @@ package me.chanjar.weixin.mp.bean.tag;
 import java.io.Serializable;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
 import lombok.Data;
@@ -57,6 +54,6 @@ public class WxUserTag implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return this.toJson();
   }
 }
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 5ccd89fd..2b3d45a7 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
@@ -3,9 +3,6 @@ package me.chanjar.weixin.mp.bean.template;
 import java.io.Serializable;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.google.gson.JsonParser;
 import com.google.gson.annotations.SerializedName;
 import com.google.gson.reflect.TypeToken;
@@ -70,7 +67,7 @@ public class WxMpTemplate implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
 }
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 40bfd18a..4507cacb 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
@@ -3,9 +3,6 @@ package me.chanjar.weixin.mp.bean.template;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
@@ -33,7 +30,7 @@ public class WxMpTemplateIndustry implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
   public String toJson() {
@@ -65,7 +62,7 @@ public class WxMpTemplateIndustry implements Serializable {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxMpGsonBuilder.create().toJson(this);
     }
 
   }
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 cb70893a..f04f8c91 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
@@ -55,6 +55,7 @@ public class WxMpTemplateMessage implements Serializable {
   /**
    * 模板数据.
    */
+  @Builder.Default
   private List data = new ArrayList<>();
 
   public WxMpTemplateMessage addData(WxMpTemplateData datum) {
@@ -66,7 +67,7 @@ public class WxMpTemplateMessage implements Serializable {
   }
 
   public String toJson() {
-    return WxMpGsonBuilder.INSTANCE.create().toJson(this);
+    return WxMpGsonBuilder.create().toJson(this);
   }
 
   @Data
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/AiLangType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java
similarity index 84%
rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/AiLangType.java
rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java
index 54b61b1e..b37772b0 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/AiLangType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java
@@ -1,4 +1,4 @@
-package me.chanjar.weixin.mp;
+package me.chanjar.weixin.mp.enums;
 
 import lombok.Getter;
 
@@ -13,11 +13,11 @@ import lombok.Getter;
 @Getter
 public enum AiLangType {
   /**
-   * 中文 汉语
+   * 中文 汉语.
    */
   zh_CN("zh_CN"),
   /**
-   * 英文 英语
+   * 英文 英语.
    */
   en_US("en_US");
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/TicketType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/TicketType.java
new file mode 100644
index 00000000..02de06f6
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/TicketType.java
@@ -0,0 +1,35 @@
+package me.chanjar.weixin.mp.enums;
+
+import lombok.Getter;
+
+/**
+ * 
+ * ticket类型枚举
+ * Created by Binary Wang on 2018/11/18.
+ * 
+ * + * @author Binary Wang + */ +@Getter +public enum TicketType { + /** + * jsapi + */ + JSAPI("jsapi"), + /** + * sdk + */ + SDK("2"), + /** + * 微信卡券 + */ + WX_CARD("wx_card"); + /** + * type代码 + */ + private String code; + + TicketType(String code) { + this.code = code; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCardResultGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCardResultGsonAdapter.java index 9d786649..7e476acb 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCardResultGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCardResultGsonAdapter.java @@ -26,7 +26,7 @@ public class WxMpCardResultGsonAdapter implements JsonDeserializer() { }.getType()); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpChangeOpenidGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpChangeOpenidGsonAdapter.java new file mode 100644 index 00000000..430726ca --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpChangeOpenidGsonAdapter.java @@ -0,0 +1,25 @@ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid; + +import java.lang.reflect.Type; + +public class WxMpChangeOpenidGsonAdapter implements JsonDeserializer { + + @Override + public WxMpChangeOpenid deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject o = json.getAsJsonObject(); + WxMpChangeOpenid changeOpenid = new WxMpChangeOpenid(); + changeOpenid.setOriOpenid(GsonHelper.getString(o, "ori_openid")); + changeOpenid.setNewOpenid(GsonHelper.getString(o, "new_openid")); + changeOpenid.setErrMsg(GsonHelper.getString(o, "err_msg")); + return changeOpenid; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java index 524e1531..a4357e91 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java @@ -16,7 +16,7 @@ import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; public class WxMpGsonBuilder { - public static final GsonBuilder INSTANCE = new GsonBuilder(); + private static final GsonBuilder INSTANCE = new GsonBuilder(); static { INSTANCE.disableHtmlEscaping(); @@ -25,6 +25,7 @@ public class WxMpGsonBuilder { INSTANCE.registerTypeAdapter(WxMpMassTagMessage.class, new WxMpMassTagMessageGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpMassOpenIdsMessage.class, new WxMpMassOpenIdsMessageGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpUser.class, new WxMpUserGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpChangeOpenid.class, new WxMpChangeOpenidGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpUserList.class, new WxUserListGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpMassVideo.class, new WxMpMassVideoAdapter()); INSTANCE.registerTypeAdapter(WxMpMassSendResult.class, new WxMpMassSendResultAdapter()); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java index 6d307c47..c406360f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsGsonAdapter.java @@ -21,14 +21,14 @@ public class WxMpMaterialNewsGsonAdapter implements JsonSerializer { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public MaterialDeleteOkhttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + @Override public Boolean execute(String uri, String materialId) throws WxErrorException, IOException { logger.debug("MaterialDeleteOkhttpRequestExecutor is running"); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java index a185b54d..b1fd2ca9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java @@ -1,7 +1,11 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; public abstract class MaterialDeleteRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; @@ -10,6 +14,11 @@ public abstract class MaterialDeleteRequestExecutor implements RequestExec this.requestHttp = requestHttp; } + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java index 62ef709a..a636ed26 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java @@ -1,7 +1,11 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; public abstract class MaterialNewsInfoRequestExecutor implements RequestExecutor { @@ -11,6 +15,11 @@ public abstract class MaterialNewsInfoRequestExecutor implements RequestEx this.requestHttp = requestHttp; } + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java index c279be32..4e518669 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java @@ -1,7 +1,11 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; import me.chanjar.weixin.mp.bean.material.WxMpMaterial; import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; @@ -15,6 +19,11 @@ public abstract class MaterialUploadRequestExecutor implements RequestExec this.requestHttp = requestHttp; } + @Override + public void execute(String uri, WxMpMaterial data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java index b09fd75a..ee057592 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java @@ -1,30 +1,37 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; - 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 java.io.IOException; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; 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 MaterialVideoInfoApacheHttpRequestExecutor(requestHttp); - case JODD_HTTP: - return new MaterialVideoInfoJoddHttpRequestExecutor(requestHttp); - case OK_HTTP: - return new MaterialVideoInfoOkhttpRequestExecutor(requestHttp); - default: - return null; - } - } - - } + this.requestHttp = requestHttp; + } + + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new MaterialVideoInfoApacheHttpRequestExecutor(requestHttp); + case JODD_HTTP: + return new MaterialVideoInfoJoddHttpRequestExecutor(requestHttp); + case OK_HTTP: + return new MaterialVideoInfoOkhttpRequestExecutor(requestHttp); + default: + return null; + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java index c11c41cc..c00ac148 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java @@ -1,13 +1,15 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.RequestHttp; - import java.io.File; +import java.io.IOException; import java.io.InputStream; -public abstract class MaterialVoiceAndImageDownloadRequestExecutor - implements RequestExecutor { +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; + +public abstract class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; protected File tmpDirFile; @@ -16,6 +18,11 @@ public abstract class MaterialVoiceAndImageDownloadRequestExecutor this.tmpDirFile = tmpDirFile; } + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java index c937fbe5..18678f87 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java @@ -1,11 +1,14 @@ package me.chanjar.weixin.mp.util.requestexecuter.media; +import java.io.File; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; -import java.io.File; - /** * @author miller */ @@ -16,6 +19,11 @@ public abstract class MediaImgUploadRequestExecutor implements RequestExec this.requestHttp = requestHttp; } + @Override + public void execute(String uri, File data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java index 7c666cd0..ca4f6e6d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java @@ -1,15 +1,17 @@ package me.chanjar.weixin.mp.util.requestexecuter.qrcode; +import java.io.File; +import java.io.IOException; + import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; -import java.io.File; - /** - * 获得QrCode图片 请求执行器 + * 获得QrCode图片 请求执行器. * * @author chanjarster */ @@ -20,6 +22,11 @@ public abstract class QrCodeRequestExecutor implements RequestExecutor handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) throws WxErrorException { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java index 34c7ae21..32bab9f6 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java @@ -1,9 +1,12 @@ package me.chanjar.weixin.mp.util.requestexecuter.voice; +import java.io.File; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; - -import java.io.File; +import me.chanjar.weixin.common.util.http.ResponseHandler; /** *
@@ -19,6 +22,11 @@ public abstract class VoiceUploadRequestExecutor implements RequestExecuto
     this.requestHttp = requestHttp;
   }
 
+  @Override
+  public void execute(String uri, File data, ResponseHandler handler) throws WxErrorException, IOException {
+    handler.handle(this.execute(uri, data));
+  }
+
   public static RequestExecutor create(RequestHttp requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java
deleted file mode 100644
index ffcd232c..00000000
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package me.chanjar.weixin.mp.api;
-
-import com.google.inject.Inject;
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.mp.api.test.ApiTestModule;
-import org.apache.commons.lang3.StringUtils;
-import org.testng.*;
-import org.testng.annotations.*;
-
-/**
- * 基础API测试
- *
- * @author chanjarster
- */
-@Test(groups = "baseAPI")
-@Guice(modules = ApiTestModule.class)
-public class WxMpBaseAPITest {
-
-  @Inject
-  protected WxMpService wxService;
-
-  public void testRefreshAccessToken() throws WxErrorException {
-    WxMpConfigStorage configStorage = this.wxService.getWxMpConfigStorage();
-    String before = configStorage.getAccessToken();
-    this.wxService.getAccessToken(false);
-
-    String after = configStorage.getAccessToken();
-    Assert.assertNotEquals(before, after);
-    Assert.assertTrue(StringUtils.isNotBlank(after));
-  }
-
-  public void testJsapiTicket() throws WxErrorException {
-    String jsapiTicket = this.wxService.getJsapiTicket(false);
-    System.out.println(jsapiTicket);
-    Assert.assertNotNull(jsapiTicket);
-  }
-
-}
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImplTest.java
index f10f9888..1e61c1fa 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImplTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImplTest.java
@@ -2,7 +2,7 @@ package me.chanjar.weixin.mp.api.impl;
 
 import com.google.inject.Inject;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.mp.AiLangType;
+import me.chanjar.weixin.mp.enums.AiLangType;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.test.ApiTestModule;
 import org.testng.annotations.Guice;
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImplTest.java
index 67d7ce6f..fbdb7cea 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImplTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImplTest.java
@@ -2,6 +2,7 @@ package me.chanjar.weixin.mp.api.impl;
 
 import com.google.inject.Inject;
 import me.chanjar.weixin.mp.api.WxMpCardService;
+import me.chanjar.weixin.mp.api.WxMpMemberCardService;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.test.ApiTestModule;
 import me.chanjar.weixin.mp.bean.card.*;
@@ -22,12 +23,12 @@ public class WxMpMemberCardServiceImplTest {
 
   @Inject
   protected WxMpService wxService;
-  private String cardId = "p2iQk1g2d03JXhVRDY5fZRVr236A";
+  private String cardId = "p2iQk1uwOUYlzHm4s-UYdZnABW88";
   private String code = "435223630779";
   private String openId = "o2iQk1u5X-XIJkatmAK1Q8VVuS90";
 
   @Test
-  public void createMemberCard()throws Exception{
+  public void createMemberCard() throws Exception {
 //    String json = "{\"card\":{\"card_type\":\"MEMBER_CARD\",\"member_card\":{\"advanced_info\":{\"business_service\":\"BIZ_SERVICE_FREE_PARK,BIZ_SERVICE_WITH_PET,BIZ_SERVICE_FREE_WIFI\",\"text_image_list\":[{\"image_url\":\"http://mmbiz.qpic.cn/mmbiz_jpg/upuF1LhUF8LjCLCFcQicgEiazFeonwDllGkENppDhyqhR8bz5BiaJkPT7e6bPVcfBx5cAOLro2N3U989n8WJltkjQ/0\",\"text\":\"8月8日随机免单\"}]},\"auto_activate\":false,\"background_pic_url\":\"http://mmbiz.qpic.cn/mmbiz_jpg/upuF1LhUF8LjCLCFcQicgEiazFeonwDllGl6ibk4v5iaJDAbs7dGJU7iclOJ6nh7Hnz6ZsfDL8tGEeQVJyuhKsMFxUQ/0\",\"base_info\":{\"bind_openid\":false,\"brand_name\":\"商户名称\",\"can_give_friend\":false,\"can_share\":false,\"center_sub_title\":\"点击进入\",\"center_title\":\"商城首页\",\"center_url\":\"http://www.baidu.com\",\"code_type\":\"CODE_TYPE_QRCODE\",\"color\":\"Color090\",\"date_info\":{\"type\":\"DATE_TYPE_PERMANENT\"},\"description\":\"使用须知\",\"need_push_on_view\":false,\"notice\":\"测试会员卡\",\"service_phone\":\"4008803016\",\"title\":\"终生铂金卡\",\"use_all_locations\":true,\"use_custom_code\":false},\"prerogative\":\"享有特权说明\",\"supply_balance\":true,\"supply_bonus\":true,\"wx_activate\":false}}}";
 //    WxMpMemberCardCreateMessage createMessage = WxMpMemberCardCreateMessage.fromJson(json);
 
@@ -105,10 +106,11 @@ public class WxMpMemberCardServiceImplTest {
 
   /**
    * 测试添加测试openid白名单
+   *
    * @throws Exception
    */
   @Test
-  public void testAddTestWhiteList()throws Exception {
+  public void testAddTestWhiteList() throws Exception {
     WxMpCardService cardService = this.wxService.getCardService();
     String response = cardService.addTestWhiteList(openId);
     System.out.println(response);
@@ -116,28 +118,38 @@ public class WxMpMemberCardServiceImplTest {
 
   /**
    * 测试创建会员卡投放二维码
+   *
    * @throws Exception
    */
   @Test
-  public void testCreateQrcodeMemberCard()throws Exception{
+  public void testCreateQrcodeMemberCard() throws Exception {
     WxMpCardService cardService = this.wxService.getCardService();
-    WxMpCardQrcodeCreateResult response = cardService.createQrcodeCard(cardId,"test");
+    WxMpCardQrcodeCreateResult response = cardService.createQrcodeCard(cardId, "test");
     System.out.println(response);
   }
 
   /**
    * 测试创建货架接口
+   *
    * @throws Exception
    */
   @Test
-  public void testCreateLandingPage()throws Exception{
+  public void testCreateLandingPage() throws Exception {
     WxMpCardService cardService = this.wxService.getCardService();
     WxMpCardLandingPageCreateRequest request = new WxMpCardLandingPageCreateRequest();
     request.setBanner("http://mmbiz.qpic.cn/mmbiz_jpg/upuF1LhUF8LjCLCFcQicgEiazFeonwDllGl6ibk4v5iaJDAbs7dGJU7iclOJ6nh7Hnz6ZsfDL8tGEeQVJyuhKsMFxUQ/0");
     request.setTitle("会员卡1");
     request.setScene(CardSceneType.SCENE_H5.name());
-    request.addCard(cardId,"http://mmbiz.qpic.cn/mmbiz_jpg/upuF1LhUF8LjCLCFcQicgEiazFeonwDllGl6ibk4v5iaJDAbs7dGJU7iclOJ6nh7Hnz6ZsfDL8tGEeQVJyuhKsMFxUQ/0");
+    request.addCard(cardId, "http://mmbiz.qpic.cn/mmbiz_jpg/upuF1LhUF8LjCLCFcQicgEiazFeonwDllGl6ibk4v5iaJDAbs7dGJU7iclOJ6nh7Hnz6ZsfDL8tGEeQVJyuhKsMFxUQ/0");
     WxMpCardLandingPageCreateResult response = cardService.createLandingPage(request);
     System.out.println(response);
   }
+
+  @Test
+  public void testGetActivateUrl() throws Exception {
+    WxMpMemberCardService memberCardService = this.wxService.getMemberCardService();
+    ActivatePluginParam response = memberCardService.getActivatePluginParam(cardId, "test");
+    System.out.println(response);
+
+  }
 }
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java
index e9999f57..7c36930b 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java
@@ -1,14 +1,18 @@
 package me.chanjar.weixin.mp.api.impl;
 
+import org.apache.commons.lang3.StringUtils;
+import org.testng.*;
+import org.testng.annotations.*;
+
 import com.google.inject.Inject;
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpConfigStorage;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.test.ApiTestModule;
 import me.chanjar.weixin.mp.api.test.TestConfigStorage;
 import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo;
-import org.testng.*;
-import org.testng.annotations.*;
+import me.chanjar.weixin.mp.enums.TicketType;
 
 import static org.testng.Assert.*;
 
@@ -40,4 +44,19 @@ public class WxMpServiceImplTest {
     System.out.println(qrConnectUrl);
   }
 
+  public void testGetTicket() throws WxErrorException {
+    String ticket = this.wxService.getTicket(TicketType.SDK, false);
+    System.out.println(ticket);
+    Assert.assertNotNull(ticket);
+  }
+
+  public void testRefreshAccessToken() throws WxErrorException {
+    WxMpConfigStorage configStorage = this.wxService.getWxMpConfigStorage();
+    String before = configStorage.getAccessToken();
+    this.wxService.getAccessToken(false);
+
+    String after = configStorage.getAccessToken();
+    Assert.assertNotEquals(before, after);
+    Assert.assertTrue(StringUtils.isNotBlank(after));
+  }
 }
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java
index 0a4cd21a..fa73b8f4 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java
@@ -1,5 +1,16 @@
 package me.chanjar.weixin.mp.api.impl;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import me.chanjar.weixin.mp.api.WxMpUserService;
+import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.testng.*;
+import org.testng.annotations.*;
+
 import com.google.inject.Inject;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpService;
@@ -8,11 +19,9 @@ import me.chanjar.weixin.mp.api.test.TestConfigStorage;
 import me.chanjar.weixin.mp.bean.WxMpUserQuery;
 import me.chanjar.weixin.mp.bean.result.WxMpUser;
 import me.chanjar.weixin.mp.bean.result.WxMpUserList;
-import org.testng.*;
-import org.testng.annotations.*;
 
-import java.util.ArrayList;
-import java.util.List;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 /**
  * 测试用户相关的接口
@@ -20,7 +29,7 @@ import java.util.List;
  * @author chanjarster
  * @author Binary Wang
  */
-@Test(groups = "userAPI")
+@Test
 @Guice(modules = ApiTestModule.class)
 public class WxMpUserServiceImplTest {
 
@@ -68,10 +77,56 @@ public class WxMpUserServiceImplTest {
   public void testUserList() throws WxErrorException {
     WxMpUserList wxMpUserList = this.wxService.getUserService().userList(null);
     Assert.assertNotNull(wxMpUserList);
-    Assert.assertFalse(wxMpUserList.getCount() == -1);
-    Assert.assertFalse(wxMpUserList.getTotal() == -1);
-    Assert.assertFalse(wxMpUserList.getOpenids().size() == -1);
+    Assert.assertNotEquals(-1, wxMpUserList.getCount());
+    Assert.assertNotEquals(-1, wxMpUserList.getTotal());
+    Assert.assertNotEquals(-1, wxMpUserList.getOpenids().size());
     System.out.println(wxMpUserList);
   }
 
+  public void testChangeOpenid() throws WxErrorException {
+    List openids = new ArrayList<>();
+    openids.add(this.configProvider.getOpenid());
+    List wxMpChangeOpenidList = this.wxService.getUserService()
+      .changeOpenid("原公众号appid", openids);
+    Assert.assertNotNull(wxMpChangeOpenidList);
+    Assert.assertEquals(1, wxMpChangeOpenidList.size());
+    WxMpChangeOpenid wxMpChangeOpenid = wxMpChangeOpenidList.get(0);
+    Assert.assertNotNull(wxMpChangeOpenid);
+    Assert.assertEquals(this.configProvider.getOpenid(), wxMpChangeOpenid.getOriOpenid());
+    System.out.println(wxMpChangeOpenid);
+  }
+
+  public static class MockTest {
+    private WxMpService wxService = mock(WxMpService.class);
+    @Test
+    public void testMockChangeOpenid() throws WxErrorException {
+      List openids = new ArrayList<>();
+      openids.add("oEmYbwN-n24jxvk4Sox81qedINkQ");
+      openids.add("oEmYbwH9uVd4RKJk7ZZg6SzL6tTo");
+      String fromAppid = "old_appid";
+      Map map = new HashMap<>();
+      map.put("from_appid", fromAppid);
+      map.put("openid_list", openids);
+
+      String returnJson = "{\"errcode\": 0,\"errmsg\": \"ok\",\"result_list\": [{\"ori_openid\": \"oEmYbwN-n24jxvk4Sox81qedINkQ\",\"new_openid\": \"o2FwqwI9xCsVadFah_HtpPfaR-X4\",\"err_msg\": \"ok\"},{\"ori_openid\": \"oEmYbwH9uVd4RKJk7ZZg6SzL6tTo\",\"err_msg\": \"ori_openid error\"}]}";
+      when(wxService.post(WxMpUserService.USER_CHANGE_OPENID_URL, WxMpGsonBuilder.create().toJson(map))).thenReturn(returnJson);
+      List wxMpChangeOpenidList = this.wxService.getUserService()
+        .changeOpenid(fromAppid, openids);
+      Assert.assertNotNull(wxMpChangeOpenidList);
+      Assert.assertEquals(2, wxMpChangeOpenidList.size());
+      WxMpChangeOpenid wxMpChangeOpenid = wxMpChangeOpenidList.get(0);
+      Assert.assertNotNull(wxMpChangeOpenid);
+      Assert.assertEquals("oEmYbwN-n24jxvk4Sox81qedINkQ", wxMpChangeOpenid.getOriOpenid());
+      Assert.assertEquals("o2FwqwI9xCsVadFah_HtpPfaR-X4", wxMpChangeOpenid.getNewOpenid());
+      Assert.assertEquals("ok", wxMpChangeOpenid.getErrMsg());
+      wxMpChangeOpenid = wxMpChangeOpenidList.get(1);
+      Assert.assertNotNull(wxMpChangeOpenid);
+      Assert.assertEquals("oEmYbwH9uVd4RKJk7ZZg6SzL6tTo", wxMpChangeOpenid.getOriOpenid());
+      Assert.assertNull(wxMpChangeOpenid.getNewOpenid());
+      Assert.assertEquals("ori_openid error", wxMpChangeOpenid.getErrMsg());
+      System.out.println(wxMpChangeOpenid);
+    }
+
+  }
+
 }
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java
index 2224329b..50bb0ac0 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java
@@ -1,9 +1,13 @@
 package me.chanjar.weixin.mp.bean.message;
 
 import me.chanjar.weixin.common.api.WxConsts;
-import org.testng.annotations.*;
+import org.testng.annotations.Test;
 
-import static org.testng.Assert.*;
+import java.util.List;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.testng.Assert.assertEquals;
 
 @Test
 public class WxMpXmlMessageTest {
@@ -39,7 +43,7 @@ public class WxMpXmlMessageTest {
       + " "
       + ""
       + ""
-      + " 1\n"
+      + " 1"
       + " "
       + "  "
       + "   "
@@ -47,12 +51,22 @@ public class WxMpXmlMessageTest {
       + " "
       + ""
       + ""
-      + "  \n"
-      + "  \n"
-      + "  \n"
-      + "  \n"
-      + "  \n"
+      + "  "
+      + "  "
+      + "  "
+      + "  "
+      + "  "
       + ""
+      + ""
+      + ""
+      + ""
+      + ""
+      + ""
+      + "1"
+      + "2"
+      + ""
+      + ""
+      + ""
       + "";
     WxMpXmlMessage wxMessage = WxMpXmlMessage.fromXml(xml);
     assertEquals(wxMessage.getToUser(), "toUser");
@@ -87,6 +101,16 @@ public class WxMpXmlMessageTest {
     assertEquals(wxMessage.getSendLocationInfo().getScale(), "15");
     assertEquals(wxMessage.getSendLocationInfo().getLabel(), " 广州市海珠区客村艺苑路 106号");
     assertEquals(wxMessage.getSendLocationInfo().getPoiName(), "wo de poi");
+    assertEquals(wxMessage.getKeyStandard(), "ean13");
+    assertEquals(wxMessage.getKeyStr(), "6901481811083");
+    assertEquals(wxMessage.getCountry(), "中国");
+    assertEquals(wxMessage.getProvince(), "广东");
+    assertEquals(wxMessage.getCity(), "揭阳");
+    assertEquals(wxMessage.getSex(), "1");
+    assertEquals(wxMessage.getScene(), "2");
+    assertEquals(wxMessage.getExtInfo(), "123");
+    assertEquals(wxMessage.getRegionCode(), "440105");
+    assertEquals(wxMessage.getReasonMsg(), "");
   }
 
   public void testFromXml2() {
@@ -170,4 +194,86 @@ public class WxMpXmlMessageTest {
     assertEquals(wxMessage.getSendLocationInfo().getPoiName(), "wo de poi");
   }
 
+  public void testFromXml_MASSSENDJOBFINISH() {
+    //xml样例来自 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1481187827_i0l21
+    String xml = "\n" +
+      "\n" +
+      "\n" +
+      "1481013459\n" +
+      "\n" +
+      "\n" +
+      "1000001625\n" +
+      "\n" +
+      "0\n" +
+      "0\n" +
+      "0\n" +
+      "0\n" +
+      "\n" +
+      "2\n" +
+      "\n" +
+      "\n" +
+      "1\n" +
+      "0\n" +
+      "2\n" +
+      "\n" +
+      "1\n" +
+      "1\n" +
+      "1\n" +
+      "1\n" +
+      "\n" +
+      "\n" +
+      "2\n" +
+      "0\n" +
+      "2\n" +
+      "\n" +
+      "1\n" +
+      "1\n" +
+      "1\n" +
+      "1\n" +
+      "\n" +
+      "\n" +
+      "2\n" +
+      "\n" +
+      "";
+    WxMpXmlMessage wxMessage = WxMpXmlMessage.fromXml(xml);
+    assertEquals(wxMessage.getToUser(), "gh_4d00ed8d6399");
+    assertEquals(wxMessage.getFromUser(), "oV5CrjpxgaGXNHIQigzNlgLTnwic");
+    assertEquals(wxMessage.getCreateTime(), new Long(1481013459));
+    assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.EVENT);
+    assertEquals(wxMessage.getEvent(), "MASSSENDJOBFINISH");
+    assertEquals(wxMessage.getMsgId(), new Long(1000001625L));
+    assertEquals(wxMessage.getStatus(), "err(30003)");
+    assertEquals(wxMessage.getTotalCount(), new Integer(0));
+    assertEquals(wxMessage.getFilterCount(), new Integer(0));
+    assertEquals(wxMessage.getSentCount(), new Integer(0));
+    assertEquals(wxMessage.getErrorCount(), new Integer(0));
+
+    final Map allFields = wxMessage.getAllFieldsMap();
+    assertThat(allFields).isNotNull();
+    final Map copyrightCheckResult = (Map) allFields.get("CopyrightCheckResult");
+    List> resultList = (List>) ((Map) copyrightCheckResult
+      .get("ResultList")).get("item");
+    assertThat(copyrightCheckResult).isNotNull();
+
+    assertThat(copyrightCheckResult.get("Count")).isEqualTo("2");
+    assertThat(copyrightCheckResult.get("CheckState")).isEqualTo("2");
+
+    assertThat(resultList.get(0).get("ArticleIdx")).isEqualTo("1");
+    assertThat(resultList.get(0).get("UserDeclareState")).isEqualTo("0");
+    assertThat(resultList.get(0).get("AuditState")).isEqualTo("2");
+    assertThat(resultList.get(0).get("OriginalArticleUrl")).isEqualTo("Url_1");
+    assertThat(resultList.get(0).get("OriginalArticleType")).isEqualTo("1");
+    assertThat(resultList.get(0).get("CanReprint")).isEqualTo("1");
+    assertThat(resultList.get(0).get("NeedReplaceContent")).isEqualTo("1");
+    assertThat(resultList.get(0).get("NeedShowReprintSource")).isEqualTo("1");
+
+    assertThat(resultList.get(1).get("ArticleIdx")).isEqualTo("2");
+    assertThat(resultList.get(1).get("UserDeclareState")).isEqualTo("0");
+    assertThat(resultList.get(1).get("AuditState")).isEqualTo("2");
+    assertThat(resultList.get(1).get("OriginalArticleUrl")).isEqualTo("Url_2");
+    assertThat(resultList.get(1).get("OriginalArticleType")).isEqualTo("1");
+    assertThat(resultList.get(1).get("CanReprint")).isEqualTo("1");
+    assertThat(resultList.get(1).get("NeedReplaceContent")).isEqualTo("1");
+    assertThat(resultList.get(1).get("NeedShowReprintSource")).isEqualTo("1");
+  }
 }
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java
index 257e5332..30d36920 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java
@@ -1,18 +1,19 @@
 package me.chanjar.weixin.mp.demo;
 
+import java.io.InputStream;
+import java.util.concurrent.locks.ReentrantLock;
+
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
 import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
 
-import java.io.InputStream;
-import java.util.concurrent.locks.ReentrantLock;
-
 /**
  * @author Daniel Qian
  */
 @XStreamAlias("xml")
 class WxMpDemoInMemoryConfigStorage extends WxMpInMemoryConfigStorage {
+  private static final long serialVersionUID = -3706236839197109704L;
 
   public static WxMpDemoInMemoryConfigStorage fromXml(InputStream is) {
     XStream xstream = XStreamInitializer.getInstance();
@@ -24,10 +25,4 @@ class WxMpDemoInMemoryConfigStorage extends WxMpInMemoryConfigStorage {
     return wxMpDemoInMemoryConfigStorage;
   }
 
-  @Override
-  public String toString() {
-    return "SimpleWxConfigProvider [appId=" + this.appId + ", secret=" + this.secret + ", accessToken=" + this.accessToken
-      + ", expiresTime=" + this.expiresTime + ", token=" + this.token + ", aesKey=" + this.aesKey + ", templateId=" + this.templateId + "]";
-  }
-
 }
diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml
index 1c055eb0..3507ad53 100644
--- a/weixin-java-open/pom.xml
+++ b/weixin-java-open/pom.xml
@@ -7,11 +7,11 @@
   4.0.0
   
     com.github.binarywang
-    weixin-java-parent
-    3.2.0
+    wx-java
+    3.3.0
   
   weixin-java-open
-  Weixin Java Tools - Open
+  WxJava - Open
   微信开放平台Java SDK
   
     
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java
index 7c1b8465..69a3aeba 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java
@@ -25,6 +25,10 @@ public interface WxOpenComponentService {
   String API_SET_AUTHORIZER_OPTION_URL = "https://api.weixin.qq.com/cgi-bin/component/api_set_authorizer_option";
 
   String COMPONENT_LOGIN_PAGE_URL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=%s&pre_auth_code=%s&redirect_uri=%s";
+  /**
+   * 手机端打开授权链接
+   */
+  String COMPONENT_MOBILE_LOGIN_PAGE_URL = "https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&no_scan=1&auth_type=3&component_appid=%s&pre_auth_code=%s&redirect_uri=%s&auth_type=xxx&biz_appid=xxx$#wechat_redirect";
   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&component_appid=%s#wechat_redirect";
 
   /**
@@ -66,6 +70,26 @@ public interface WxOpenComponentService {
    */
   String getPreAuthUrl(String redirectURI, String authType, String bizAppid) throws WxErrorException;
 
+  /**
+   * 获取预授权链接(手机端预授权)
+   *
+   * @param redirectURI
+   * @return
+   * @throws WxErrorException
+   */
+  String getMobilePreAuthUrl(String redirectURI) throws WxErrorException;
+
+  /**
+   * 获取预授权链接(手机端预授权)
+   *
+   * @param redirectURI
+   * @param authType
+   * @param bizAppid
+   * @return
+   * @throws WxErrorException
+   */
+  String getMobilePreAuthUrl(String redirectURI, String authType, String bizAppid) throws WxErrorException;
+
   String route(WxOpenXmlMessage wxMessage) throws WxErrorException;
 
   /**
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java
index 2cb82ff7..7d688d31 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java
@@ -219,7 +219,7 @@ public interface WxOpenMaService extends WxMaService {
    * @return
    * @throws WxErrorException
    */
-  String bindTester(String wechatid) throws WxErrorException;
+  WxOpenResult bindTester(String wechatid) throws WxErrorException;
 
   /**
    * 解除绑定小程序体验者
@@ -228,7 +228,7 @@ public interface WxOpenMaService extends WxMaService {
    * @return
    * @throws WxErrorException
    */
-  String unbindTester(String wechatid) throws WxErrorException;
+  WxOpenResult unbindTester(String wechatid) throws WxErrorException;
 
   /**
    * 获得体验者列表
@@ -248,7 +248,7 @@ public interface WxOpenMaService extends WxMaService {
    * @return
    * @throws WxErrorException
    */
-  String codeCommit(Long templateId, String userVersion, String userDesc, WxMaOpenCommitExtInfo extInfo) throws WxErrorException;
+  WxOpenResult codeCommit(Long templateId, String userVersion, String userDesc, WxMaOpenCommitExtInfo extInfo) throws WxErrorException;
 
   /**
    * 获取体验小程序的体验二维码
@@ -294,16 +294,15 @@ public interface WxOpenMaService extends WxMaService {
    * @return
    * @throws WxErrorException
    */
-  String getAuditStatus(Long auditid) throws WxErrorException;
+  WxOpenMaQueryAuditResult getAuditStatus(Long auditid) throws WxErrorException;
 
   /**
    * 查询最新一次提交的审核状态(仅供第三方代小程序调用)
    *
-   * @param auditid
    * @return
    * @throws WxErrorException
    */
-  String getLatestAuditStatus(Long auditid) throws WxErrorException;
+  WxOpenMaQueryAuditResult getLatestAuditStatus() throws WxErrorException;
 
   /**
    * 发布已通过审核的小程序(仅供第三方代小程序调用)
@@ -311,7 +310,7 @@ public interface WxOpenMaService extends WxMaService {
    * @return
    * @throws WxErrorException
    */
-  String releaesAudited() throws WxErrorException;
+  WxOpenResult releaesAudited() throws WxErrorException;
 
   /**
    * 11. 小程序版本回退(仅供第三方代小程序调用)
@@ -319,7 +318,7 @@ public interface WxOpenMaService extends WxMaService {
    * @return
    * @throws WxErrorException
    */
-  String revertCodeReleaes() throws WxErrorException;
+  WxOpenResult revertCodeReleaes() throws WxErrorException;
 
   /**
    * 15. 小程序审核撤回
@@ -330,6 +329,21 @@ public interface WxOpenMaService extends WxMaService {
    * @return
    * @throws WxErrorException
    */
-  String undoCodeAudit() throws WxErrorException;
-  
+  WxOpenResult undoCodeAudit() throws WxErrorException;
+
+  /**
+   * 查询当前设置的最低基础库版本及各版本用户占比 (仅供第三方代小程序调用)
+   * @return
+   * @throws WxErrorException
+   */
+  String getSupportVersion() throws WxErrorException;
+
+  /**
+   * 设置最低基础库版本(仅供第三方代小程序调用)
+   * @param version
+   * @return
+   * @throws WxErrorException
+   */
+  String setSupportVersion(String version) throws WxErrorException;
+
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java
index 2fd53dc5..93155690 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java
@@ -181,25 +181,50 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService {
     return getPreAuthUrl(redirectURI, null, null);
   }
 
-  @Override
   public String getPreAuthUrl(String redirectURI, String authType, String bizAppid) throws WxErrorException {
+    return createPreAuthUrl(redirectURI, authType, bizAppid, false);
+  }
+
+  public String getMobilePreAuthUrl(String redirectURI) throws WxErrorException {
+    return getMobilePreAuthUrl(redirectURI, null, null);
+  }
+
+  public String getMobilePreAuthUrl(String redirectURI, String authType, String bizAppid) throws WxErrorException {
+    return createPreAuthUrl(redirectURI, authType, bizAppid, true);
+  }
+
+  /**
+   * 创建预授权链接
+   *
+   * @param redirectURI
+   * @param authType
+   * @param bizAppid
+   * @param isMobile    是否移动端预授权
+   * @return
+   * @throws WxErrorException
+   */
+  private String createPreAuthUrl(String redirectURI, String authType, String bizAppid, boolean isMobile) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId());
     String responseContent = post(API_CREATE_PREAUTHCODE_URL, jsonObject.toString());
     jsonObject = WxGsonBuilder.create().fromJson(responseContent, JsonObject.class);
 
-    StringBuilder preAuthUrl = new StringBuilder(String.format(COMPONENT_LOGIN_PAGE_URL,
+    StringBuilder preAuthUrl = new StringBuilder(String.format((isMobile ? COMPONENT_MOBILE_LOGIN_PAGE_URL : COMPONENT_LOGIN_PAGE_URL),
       getWxOpenConfigStorage().getComponentAppId(),
       jsonObject.get("pre_auth_code").getAsString(),
       URIUtil.encodeURIComponent(redirectURI)));
+    String preAuthUrlStr = preAuthUrl.toString();
     if (StringUtils.isNotEmpty(authType)) {
-      preAuthUrl.append("&auth_type=").append(authType);
+      preAuthUrlStr = preAuthUrlStr.replace("&auth_type=xxx", "&auth_type=" + authType);
+    } else {
+      preAuthUrlStr = preAuthUrlStr.replace("&auth_type=xxx", "");
     }
     if (StringUtils.isNotEmpty(bizAppid)) {
-      preAuthUrl.append("&biz_appid=").append(bizAppid);
+      preAuthUrlStr = preAuthUrlStr.replace("&biz_appid=xxx", "&biz_appid=" + bizAppid);
+    } else {
+      preAuthUrlStr = preAuthUrlStr.replace("&biz_appid=xxx", "");
     }
-
-    return preAuthUrl.toString();
+    return preAuthUrlStr;
   }
 
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
index a340be81..570721f1 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
@@ -7,16 +7,15 @@ import java.util.Map;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import cn.binarywang.wx.miniapp.config.WxMaConfig;
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.mp.api.WxMpConfigStorage;
+import me.chanjar.weixin.mp.enums.TicketType;
 import me.chanjar.weixin.open.api.WxOpenConfigStorage;
 import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken;
 import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken;
+import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
 
 /**
  * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
@@ -324,6 +323,90 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage {
       wxOpenConfigStorage.updateAuthorizerAccessToken(appId, accessToken, expiresInSeconds);
     }
 
+    @Override
+    public String getTicket(TicketType type) {
+      switch (type) {
+        case JSAPI: {
+          return wxOpenConfigStorage.getJsapiTicket(appId);
+        }
+        case WX_CARD: {
+          return wxOpenConfigStorage.getCardApiTicket(appId);
+        }
+        default: {
+          // do nothing
+        }
+      }
+      return null;
+    }
+
+    @Override
+    public Lock getTicketLock(TicketType type) {
+      switch (type) {
+        case JSAPI: {
+          return this.jsapiTicketLock;
+        }
+        case WX_CARD: {
+          return this.cardApiTicketLock;
+        }
+        default: {
+          // do nothing
+        }
+      }
+      return null;
+    }
+
+    @Override
+    public boolean isTicketExpired(TicketType type) {
+      switch (type) {
+        case JSAPI: {
+          return wxOpenConfigStorage.isJsapiTicketExpired(appId);
+        }
+        case WX_CARD: {
+          return wxOpenConfigStorage.isCardApiTicketExpired(appId);
+        }
+        default: {
+          // do nothing
+        }
+      }
+
+      return false;
+    }
+
+    @Override
+    public void expireTicket(TicketType type) {
+      switch (type) {
+        case JSAPI: {
+          wxOpenConfigStorage.expireJsapiTicket(appId);
+          break;
+        }
+        case WX_CARD: {
+          wxOpenConfigStorage.expireCardApiTicket(appId);
+          break;
+        }
+        default: {
+          // do nothing
+        }
+      }
+    }
+
+    @Override
+    public void updateTicket(TicketType type, String ticket, int expiresInSeconds) {
+      switch (type) {
+        case JSAPI: {
+          wxOpenConfigStorage.updateJsapiTicket(appId, ticket, expiresInSeconds);
+          break;
+        }
+        case WX_CARD: {
+          wxOpenConfigStorage.updateCardApiTicket(appId, ticket, expiresInSeconds);
+          break;
+        }
+        default: {
+          // do nothing
+        }
+      }
+
+    }
+
     @Override
     public String getAppid() {
       return this.appId;
@@ -359,9 +442,6 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage {
       wxOpenConfigStorage.expireJsapiTicket(appId);
     }
 
-    /**
-     * 卡券api_ticket
-     */
     @Override
     public String getCardApiTicket() {
       return wxOpenConfigStorage.getCardApiTicket(appId);
@@ -450,7 +530,7 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage {
 
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxOpenGsonBuilder.create().toJson(this);
     }
 
     @Override
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java
index 2cdfcc45..623338d0 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java
@@ -146,11 +146,11 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
    * @throws WxErrorException
    */
   @Override
-  public String bindTester(String wechatid) throws WxErrorException {
+  public WxOpenResult bindTester(String wechatid) throws WxErrorException {
     JsonObject paramJson = new JsonObject();
     paramJson.addProperty("wechatid", wechatid);
     String response = post(API_BIND_TESTER, GSON.toJson(paramJson));
-    return response;
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
   }
 
   /**
@@ -161,11 +161,11 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
    * @throws WxErrorException
    */
   @Override
-  public String unbindTester(String wechatid) throws WxErrorException {
+  public WxOpenResult unbindTester(String wechatid) throws WxErrorException {
     JsonObject paramJson = new JsonObject();
     paramJson.addProperty("wechatid", wechatid);
     String response = post(API_UNBIND_TESTER, GSON.toJson(paramJson));
-    return response;
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
   }
 
   /**
@@ -193,7 +193,7 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
    * @throws WxErrorException
    */
   @Override
-  public String codeCommit(Long templateId, String userVersion, String userDesc, WxMaOpenCommitExtInfo extInfo) throws WxErrorException {
+  public WxOpenResult codeCommit(Long templateId, String userVersion, String userDesc, WxMaOpenCommitExtInfo extInfo) throws WxErrorException {
     JsonObject params = new JsonObject();
     params.addProperty("template_id", templateId);
     params.addProperty("user_version", userVersion);
@@ -201,7 +201,7 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
     //注意:ext_json必须是字符串类型
     params.addProperty("ext_json", GSON.toJson(extInfo));
     String response = post(API_CODE_COMMIT, GSON.toJson(params));
-    return response;
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
   }
 
   /**
@@ -265,24 +265,23 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
    * @throws WxErrorException
    */
   @Override
-  public String getAuditStatus(Long auditid) throws WxErrorException {
+  public WxOpenMaQueryAuditResult getAuditStatus(Long auditid) throws WxErrorException {
     JsonObject params = new JsonObject();
     params.addProperty("auditid", auditid);
     String response = post(API_GET_AUDIT_STATUS, GSON.toJson(params));
-    return response;
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenMaQueryAuditResult.class);
   }
 
   /**
    * 8. 查询最新一次提交的审核状态(仅供第三方代小程序调用)
    *
-   * @param auditid
    * @return
    * @throws WxErrorException
    */
   @Override
-  public String getLatestAuditStatus(Long auditid) throws WxErrorException {
+  public WxOpenMaQueryAuditResult getLatestAuditStatus() throws WxErrorException {
     String response = get(API_GET_LATEST_AUDIT_STATUS, null);
-    return response;
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenMaQueryAuditResult.class);
   }
 
   /**
@@ -295,10 +294,10 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
    * @throws WxErrorException
    */
   @Override
-  public String releaesAudited() throws WxErrorException {
+  public WxOpenResult releaesAudited() throws WxErrorException {
     JsonObject params = new JsonObject();
     String response = post(API_RELEASE, GSON.toJson(params));
-    return response;
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
   }
 
   /**
@@ -308,9 +307,9 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
    * @throws WxErrorException
    */
   @Override
-  public String revertCodeReleaes() throws WxErrorException {
+  public WxOpenResult revertCodeReleaes() throws WxErrorException {
     String response = get(API_REVERT_CODE_RELEASE, null);
-    return response;
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
   }
 
   /**
@@ -323,8 +322,36 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
    * @throws WxErrorException
    */
   @Override
-  public String undoCodeAudit() throws WxErrorException {
+  public WxOpenResult undoCodeAudit() throws WxErrorException {
     String response = get(API_UNDO_CODE_AUDIT, null);
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+  }
+
+  /**
+   * 查询当前设置的最低基础库版本及各版本用户占比 (仅供第三方代小程序调用)
+   *
+   * @return
+   * @throws WxErrorException
+   */
+  @Override
+  public String getSupportVersion() throws WxErrorException {
+    JsonObject params = new JsonObject();
+    String response = post(API_GET_WEAPP_SUPPORT_VERSION, GSON.toJson(params));
+    return response;
+  }
+
+  /**
+   * 设置最低基础库版本(仅供第三方代小程序调用)
+   *
+   * @param version
+   * @return
+   * @throws WxErrorException
+   */
+  @Override
+  public String setSupportVersion(String version) throws WxErrorException {
+    JsonObject params = new JsonObject();
+    params.addProperty("version", version);
+    String response = post(API_SET_WEAPP_SUPPORT_VERSION, GSON.toJson(params));
     return response;
   }
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceAbstractImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceAbstractImpl.java
index 49497264..65dfef6e 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceAbstractImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceAbstractImpl.java
@@ -1,5 +1,10 @@
 package me.chanjar.weixin.open.api.impl;
 
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
@@ -7,17 +12,13 @@ import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.open.api.WxOpenComponentService;
 import me.chanjar.weixin.open.api.WxOpenConfigStorage;
 import me.chanjar.weixin.open.api.WxOpenService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
 
 /**
  * @author 007
  */
 public abstract class WxOpenServiceAbstractImpl implements WxOpenService, RequestHttp {
-  protected final Logger log = LoggerFactory.getLogger(this.getClass());
-  protected WxOpenComponentService wxOpenComponentService = new WxOpenComponentServiceImpl(this);
+  private final Logger log = LoggerFactory.getLogger(this.getClass());
+  private WxOpenComponentService wxOpenComponentService = new WxOpenComponentServiceImpl(this);
   private WxOpenConfigStorage wxOpenConfigStorage;
 
   @Override
@@ -37,7 +38,7 @@ public abstract class WxOpenServiceAbstractImpl implements WxOpenService,
   }
 
   /**
-   * 初始化 RequestHttp
+   * 初始化 RequestHttp.
    */
   public abstract void initHttp();
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaCategory.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaCategory.java
index 88ca63ae..9c5fc4cc 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaCategory.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaCategory.java
@@ -1,20 +1,20 @@
 package me.chanjar.weixin.open.bean.ma;
 
+import java.io.Serializable;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-import java.io.Serializable;
+import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
 
 /**
- * 微信小程序分类目录
+ * 微信小程序分类目录.
  *
  * @author yqx
  * @date 2018/9/13
  */
 @Data
 public class WxOpenMaCategory implements Serializable {
+  private static final long serialVersionUID = -700005096619889630L;
 
   @SerializedName("first_class")
   private String firstClass;
@@ -34,7 +34,8 @@ public class WxOpenMaCategory implements Serializable {
   @SerializedName("third_id")
   private Integer thirdId;
 
+  @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxOpenGsonBuilder.create().toJson(this);
   }
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java
index f3819452..a6ba9945 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java
@@ -3,6 +3,7 @@ package me.chanjar.weixin.open.bean.message;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
 
 import org.apache.commons.io.IOUtils;
 
@@ -99,7 +100,7 @@ public class WxOpenXmlMessage implements Serializable {
   public static WxOpenXmlMessage fromEncryptedXml(InputStream is, WxOpenConfigStorage wxOpenConfigStorage,
                                                   String timestamp, String nonce, String msgSignature) {
     try {
-      return fromEncryptedXml(IOUtils.toString(is, "UTF-8"),
+      return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8),
         wxOpenConfigStorage, timestamp, nonce, msgSignature);
     } catch (IOException e) {
       throw new RuntimeException(e);
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaCategoryListResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaCategoryListResult.java
index af113f16..b5919e02 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaCategoryListResult.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaCategoryListResult.java
@@ -1,13 +1,12 @@
 package me.chanjar.weixin.open.bean.result;
 
+import java.util.List;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 import me.chanjar.weixin.open.bean.ma.WxOpenMaCategory;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-import java.io.Serializable;
-import java.util.List;
+import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
 
 /**
  * 微信开放平台小程序分类目录列表返回
@@ -16,16 +15,16 @@ import java.util.List;
  * @date 2018/9/12
  */
 @Data
-public class WxOpenMaCategoryListResult implements Serializable {
-
-  private String errcode;
-  private String errmsg;
+@EqualsAndHashCode(callSuper = true)
+public class WxOpenMaCategoryListResult extends WxOpenResult {
+  private static final long serialVersionUID = 4549360618179745721L;
 
   @SerializedName("category_list")
   List categoryList;
 
+  @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxOpenGsonBuilder.create().toJson(this);
   }
 
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaDomainResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaDomainResult.java
index 79775e4b..2d782ee5 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaDomainResult.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaDomainResult.java
@@ -1,22 +1,21 @@
 package me.chanjar.weixin.open.bean.result;
 
+import java.util.List;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-
-import java.io.Serializable;
-import java.util.List;
+import lombok.EqualsAndHashCode;
 
 /**
- * 微信开放平台小程序域名设置返回对象
+ * 微信开放平台小程序域名设置返回对象.
  *
  * @author yqx
  * @date 2018/9/12
  */
 @Data
-public class WxOpenMaDomainResult implements Serializable {
-
-  private String errcode;
-  private String errmsg;
+@EqualsAndHashCode(callSuper = true)
+public class WxOpenMaDomainResult extends WxOpenResult {
+  private static final long serialVersionUID = 3406315629639573330L;
 
   @SerializedName("requestdomain")
   List requestdomainList;
@@ -29,5 +28,5 @@ public class WxOpenMaDomainResult implements Serializable {
 
   @SerializedName("downloaddomain")
   List downloaddomainList;
-  
+
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaPageListResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaPageListResult.java
index b4c34fb2..1e854138 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaPageListResult.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaPageListResult.java
@@ -1,30 +1,29 @@
 package me.chanjar.weixin.open.bean.result;
 
+import java.util.List;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-import java.io.Serializable;
-import java.util.List;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
 
 /**
- * 微信开放平台小程序第三方提交代码的页面配置列表
+ * 微信开放平台小程序第三方提交代码的页面配置列表.
  *
  * @author yqx
  * @date 2018/9/12
  */
 @Data
-public class WxOpenMaPageListResult implements Serializable {
-
-  private String errcode;
-  private String errmsg;
+@EqualsAndHashCode(callSuper = true)
+public class WxOpenMaPageListResult extends WxOpenResult {
+  private static final long serialVersionUID = 6982848180319905444L;
 
   @SerializedName("page_list")
   List pageList;
 
+  @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxOpenGsonBuilder.create().toJson(this);
   }
 
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaQueryAuditResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaQueryAuditResult.java
new file mode 100644
index 00000000..41a761d6
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaQueryAuditResult.java
@@ -0,0 +1,32 @@
+package me.chanjar.weixin.open.bean.result;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * .
+ * @author yqx
+ * @date 2018/10/3
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class WxOpenMaQueryAuditResult extends WxOpenResult {
+  private static final long serialVersionUID = 8022192589710319473L;
+
+  /**
+   * 审核编号.
+   */
+  @SerializedName("auditid")
+  Long auditId;
+
+  /**
+   * 审核状态:2-审核中,0-审核通过,1-审核失败.
+   */
+  Integer status;
+
+  /**
+   * 审核失败原因.
+   */
+  String reason;
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaSubmitAuditResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaSubmitAuditResult.java
index 77f150c2..69774e8e 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaSubmitAuditResult.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaSubmitAuditResult.java
@@ -2,23 +2,21 @@ package me.chanjar.weixin.open.bean.result;
 
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-
-import java.io.Serializable;
+import lombok.EqualsAndHashCode;
 
 /**
- * 微信开放平台小程序发布代码审核结果
+ * 微信开放平台小程序发布代码审核结果.
  *
  * @author yqx
  * @date 2018/9/12
  */
 @Data
-public class WxOpenMaSubmitAuditResult implements Serializable {
-
-  private String errcode;
-  private String errmsg;
+@EqualsAndHashCode(callSuper = true)
+public class WxOpenMaSubmitAuditResult extends WxOpenResult {
+  private static final long serialVersionUID = 7431725910039734365L;
 
   /**
-   * 审核编号
+   * 审核编号.
    */
   @SerializedName("auditid")
   Long auditId;
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaTesterListResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaTesterListResult.java
index 91c4af2a..014381ea 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaTesterListResult.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaTesterListResult.java
@@ -1,31 +1,30 @@
 package me.chanjar.weixin.open.bean.result;
 
+import java.util.List;
+
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 import me.chanjar.weixin.open.bean.ma.WxOpenMaMember;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-import java.io.Serializable;
-import java.util.List;
+import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
 
 /**
- * 微信开放平台小程序体验者列表返回
+ * 微信开放平台小程序体验者列表返回.
  *
  * @author yqx
  * @date 2018/9/12
  */
 @Data
-public class WxOpenMaTesterListResult implements Serializable {
-
-  private String errcode;
-  private String errmsg;
+@EqualsAndHashCode(callSuper = false)
+public class WxOpenMaTesterListResult extends WxOpenResult {
+  private static final long serialVersionUID = -613936397557067111L;
 
   @SerializedName("members")
   List membersList;
 
+  @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxOpenGsonBuilder.create().toJson(this);
   }
 
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenResult.java
new file mode 100644
index 00000000..6b1d10ba
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenResult.java
@@ -0,0 +1,33 @@
+package me.chanjar.weixin.open.bean.result;
+
+import java.io.Serializable;
+
+import org.apache.commons.lang3.StringUtils;
+
+import lombok.Data;
+import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
+
+/**
+ * 基础的微信开放平台请求结果.
+ *
+ * @author yqx
+ * @date 2018/10/1
+ */
+@Data
+public class WxOpenResult implements Serializable {
+  private static final long serialVersionUID = 2101652152604850904L;
+  protected String errcode;
+  protected String errmsg;
+
+  /**
+   * 请求是否成功.
+   */
+  public boolean isSuccess() {
+    return StringUtils.equalsIgnoreCase(errcode, "0");
+  }
+
+  @Override
+  public String toString() {
+    return WxOpenGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerInfoResultGsonAdapter.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerInfoResultGsonAdapter.java
index 1cef0ff4..112ec9f4 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerInfoResultGsonAdapter.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerInfoResultGsonAdapter.java
@@ -1,13 +1,17 @@
 package me.chanjar.weixin.open.util.json;
 
-import com.google.gson.*;
+import java.lang.reflect.Type;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
 import com.google.gson.reflect.TypeToken;
 import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo;
 import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizerInfo;
 import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult;
 
-import java.lang.reflect.Type;
-
 /**
  * @author 007
  */
@@ -17,12 +21,12 @@ public class WxOpenAuthorizerInfoResultGsonAdapter implements JsonDeserializer() {
       }.getType());
 
     authorizerInfoResult.setAuthorizationInfo(authorizationInfo);
-    WxOpenAuthorizerInfo authorizerInfo = WxOpenGsonBuilder.INSTANCE.create().fromJson(jsonObject.get("authorizer_info"),
+    WxOpenAuthorizerInfo authorizerInfo = WxOpenGsonBuilder.create().fromJson(jsonObject.get("authorizer_info"),
       new TypeToken() {
       }.getType());
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenGsonBuilder.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenGsonBuilder.java
index 2b390ade..703aff12 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenGsonBuilder.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenGsonBuilder.java
@@ -15,7 +15,7 @@ import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult;
  */
 public class WxOpenGsonBuilder {
 
-  public static final GsonBuilder INSTANCE = new GsonBuilder();
+  private static final GsonBuilder INSTANCE = new GsonBuilder();
 
   static {
     INSTANCE.disableHtmlEscaping();
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenQueryAuthResultGsonAdapter.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenQueryAuthResultGsonAdapter.java
index 8868d0fe..78791603 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenQueryAuthResultGsonAdapter.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenQueryAuthResultGsonAdapter.java
@@ -1,12 +1,16 @@
 package me.chanjar.weixin.open.util.json;
 
-import com.google.gson.*;
+import java.lang.reflect.Type;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
 import com.google.gson.reflect.TypeToken;
 import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo;
 import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult;
 
-import java.lang.reflect.Type;
-
 /**
  * @author 007
  */
@@ -16,7 +20,7 @@ public class WxOpenQueryAuthResultGsonAdapter implements JsonDeserializer() {
       }.getType());
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeRequestExecutor.java
index 55766d99..3c6b842d 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeRequestExecutor.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/requestexecuter/ma/MaQrCodeRequestExecutor.java
@@ -1,15 +1,17 @@
 package me.chanjar.weixin.open.util.requestexecuter.ma;
 
+import java.io.File;
+import java.io.IOException;
+
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.ResponseHandler;
 import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam;
 
-import java.io.File;
-
 /**
- * 获得小程序体验QrCode图片 请求执行器
+ * 获得小程序体验QrCode图片 请求执行器.
  *
  * @author yqx
  * @date 2018-09-13
@@ -21,6 +23,11 @@ public abstract class MaQrCodeRequestExecutor implements RequestExecutor handler) throws WxErrorException, IOException {
+    handler.handle(this.execute(uri, data));
+  }
+
   public static RequestExecutor create(RequestHttp requestHttp) throws WxErrorException {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
diff --git a/weixin-java-osgi/pom.xml b/weixin-java-osgi/pom.xml
index 693d5309..107a78b4 100644
--- a/weixin-java-osgi/pom.xml
+++ b/weixin-java-osgi/pom.xml
@@ -5,14 +5,14 @@
   4.0.0
   
     com.github.binarywang
-    weixin-java-parent
+    wx-java
     2.6.0
   
 
   weixin-java-osgi
   bundle
-  Weixin Java Tools - OSGI
-  微信公众号Java SDK OSGI
+  WxJava - OSGI
+  微信Java开发SDK OSGI模块
 
   
     
diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
index b348a9b9..9f6b3cd7 100644
--- a/weixin-java-pay/pom.xml
+++ b/weixin-java-pay/pom.xml
@@ -3,14 +3,14 @@
          xmlns="http://maven.apache.org/POM/4.0.0"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   
-    weixin-java-parent
     com.github.binarywang
-    3.2.0
+    wx-java
+    3.3.0
   
   4.0.0
 
   weixin-java-pay
-  Weixin Java Tools - PAY
+  WxJava - PAY
   微信支付 Java SDK
 
   
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryResult.java
index 90bafc78..cab25062 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponInfoQueryResult.java
@@ -74,15 +74,15 @@ public class WxPayCouponInfoQueryResult extends BaseWxPayResult {
   /**
    * 
    * 字段名:代金券使用门槛.
-   * 变量名:coupon_mininum
+   * 变量名:coupon_minimum 微信文档有误
    * 是否必填:是
    * 示例值:10
    * 类型:Unsinged int
    * 说明:代金券使用最低限额,单位是分
    * 
*/ - @XStreamAlias("coupon_mininum") - private Integer couponMininum; + @XStreamAlias("coupon_minimum") + private Integer couponMinimum; /** *
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryResult.java
index c4bbc705..f3e91d03 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/coupon/WxPayCouponStockQueryResult.java
@@ -9,7 +9,7 @@ import lombok.NoArgsConstructor;
 
 /**
  * 
- * 查询代金券批次响应结果类
+ * 查询代金券批次响应结果类.
  * Created by Binary Wang on 2017-7-15.
  * 
* @@ -21,9 +21,10 @@ import lombok.NoArgsConstructor; @AllArgsConstructor @XStreamAlias("xml") public class WxPayCouponStockQueryResult extends BaseWxPayResult { + private static final long serialVersionUID = 4644274730788451926L; /** *
-   * 字段名:设备号
+   * 字段名:设备号.
    * 变量名:device_info
    * 是否必填:否
    * 示例值:123456sb
@@ -36,7 +37,7 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
 
   /**
    * 
-   * 字段名:代金券批次ID
+   * 字段名:代金券批次ID.
    * 变量名:coupon_stock_id
    * 是否必填:是
    * 示例值:1757
@@ -49,7 +50,7 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
 
   /**
    * 
-   * 字段名:代金券名称
+   * 字段名:代金券名称.
    * 变量名:coupon_name
    * 是否必填:否
    * 示例值:测试代金券
@@ -62,7 +63,7 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
 
   /**
    * 
-   * 字段名:代金券面额
+   * 字段名:代金券面额.
    * 变量名:coupon_value
    * 是否必填:是
    * 示例值:5
@@ -75,7 +76,7 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
 
   /**
    * 
-   * 字段名:代金券使用最低限额
+   * 字段名:代金券使用最低限额.
    * 变量名:coupon_mininumn
    * 是否必填:否
    * 示例值:10
@@ -84,11 +85,11 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
    * 
*/ @XStreamAlias("coupon_mininumn") - private Integer couponMininumn; + private Integer couponMinimum; /** *
-   * 字段名:代金券批次状态
+   * 字段名:代金券批次状态.
    * 变量名:coupon_stock_status
    * 是否必填:是
    * 示例值:4
@@ -101,7 +102,7 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
 
   /**
    * 
-   * 字段名:代金券数量
+   * 字段名:代金券数量.
    * 变量名:coupon_total
    * 是否必填:是
    * 示例值:100
@@ -114,7 +115,7 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
 
   /**
    * 
-   * 字段名:代金券最大领取数量
+   * 字段名:代金券最大领取数量.
    * 变量名:max_quota
    * 是否必填:否
    * 示例值:1
@@ -127,7 +128,7 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
 
   /**
    * 
-   * 字段名:代金券已经发送的数量
+   * 字段名:代金券已经发送的数量.
    * 变量名:is_send_num
    * 是否必填:否
    * 示例值:0
@@ -140,7 +141,7 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
 
   /**
    * 
-   * 字段名:生效开始时间
+   * 字段名:生效开始时间.
    * 变量名:begin_time
    * 是否必填:是
    * 示例值:1943787483
@@ -153,7 +154,7 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
 
   /**
    * 
-   * 字段名:生效结束时间
+   * 字段名:生效结束时间.
    * 变量名:end_time
    * 是否必填:是
    * 示例值:1943787490
@@ -166,7 +167,7 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
 
   /**
    * 
-   * 字段名:创建时间
+   * 字段名:创建时间.
    * 变量名:create_time
    * 是否必填:是
    * 示例值:1943787420
@@ -179,7 +180,7 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
 
   /**
    * 
-   * 字段名:代金券预算额度
+   * 字段名:代金券预算额度.
    * 变量名:coupon_budget
    * 是否必填:否
    * 示例值:500
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryRequest.java
index 987677a3..21de8fca 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryRequest.java
@@ -1,8 +1,5 @@
 package com.github.binarywang.wxpay.bean.entpay;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.AllArgsConstructor;
@@ -11,6 +8,7 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import me.chanjar.weixin.common.annotation.Required;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
 /**
  * 
@@ -50,7 +48,7 @@ public class EntPayQueryRequest extends BaseWxPayRequest {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxGsonBuilder.create().toJson(this);
   }
 
   @Override
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryResult.java
index e3cdba3b..e9f6d221 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayQueryResult.java
@@ -22,55 +22,61 @@ public class EntPayQueryResult extends BaseWxPayResult {
   private static final long serialVersionUID = 3948485732447456947L;
 
   /**
-   * 商户订单号
+   * 商户订单号.
    */
   @XStreamAlias("partner_trade_no")
   private String partnerTradeNo;
 
   /**
-   * 付款单号
+   * 付款单号.
    */
   @XStreamAlias("detail_id")
   private String detailId;
 
   /**
-   * 转账状态
+   * 转账状态.
    */
   @XStreamAlias("status")
   private String status;
 
   /**
-   * 失败原因
+   * 失败原因.
    */
   @XStreamAlias("reason")
   private String reason;
 
   /**
-   * 收款用户openid
+   * 收款用户openid.
    */
   @XStreamAlias("openid")
   private String openid;
 
   /**
-   * 收款用户姓名
+   * 收款用户姓名.
    */
   @XStreamAlias("transfer_name")
   private String transferName;
 
   /**
-   * 付款金额
+   * 付款金额.
    */
   @XStreamAlias("payment_amount")
   private Integer paymentAmount;
 
   /**
-   * 转账时间
+   * 发起转账的时间.
    */
   @XStreamAlias("transfer_time")
   private String transferTime;
 
   /**
-   * 付款描述
+   * 企业付款成功时间.
+   */
+  @XStreamAlias("payment_time")
+  private String paymentTime;
+
+  /**
+   * 付款描述.
    */
   @XStreamAlias("desc")
   private String desc;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayRequest.java
index 285b66ba..fd04fb83 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/entpay/EntPayRequest.java
@@ -1,8 +1,5 @@
 package com.github.binarywang.wxpay.bean.entpay;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.AllArgsConstructor;
@@ -11,6 +8,7 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import me.chanjar.weixin.common.annotation.Required;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
 /**
  * 
@@ -193,7 +191,7 @@ public class EntPayRequest extends BaseWxPayRequest {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxGsonBuilder.create().toJson(this);
   }
 
   @Override
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyCoupon.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyCoupon.java
index cb1d6c24..c8ea11d7 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyCoupon.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyCoupon.java
@@ -4,11 +4,9 @@ import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
 /**
  * 支付异步通知代金券详细.
@@ -40,6 +38,6 @@ public class WxPayOrderNotifyCoupon implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxGsonBuilder.create().toJson(this);
   }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java
index 9fc9cebe..433342f9 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java
@@ -3,17 +3,18 @@ package com.github.binarywang.wxpay.bean.notify;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
+import com.github.binarywang.wxpay.constant.WxPayConstants;
 import com.github.binarywang.wxpay.converter.WxPayOrderNotifyResultConverter;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.util.SignUtils;
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
 
 /**
@@ -284,7 +285,17 @@ public class WxPayOrderNotifyResult extends BaseWxPayResult {
    */
   @XStreamAlias("version")
   private String version;
-
+  
+  @Override
+  public void checkResult(WxPayService wxPayService, String signType, boolean checkSuccess) throws WxPayException {
+    //防止伪造成功通知
+    if (WxPayConstants.ResultCode.SUCCESS.equals(getReturnCode()) && getSign() == null) {
+      throw new WxPayException("伪造的通知!");
+    }
+    
+    super.checkResult(wxPayService, signType, checkSuccess);
+  }
+  
   /**
    * From xml wx pay order notify result.
    *
@@ -314,6 +325,6 @@ public class WxPayOrderNotifyResult extends BaseWxPayResult {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxGsonBuilder.create().toJson(this);
   }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
index f738984a..513dbfa8 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
@@ -1,15 +1,15 @@
 package com.github.binarywang.wxpay.bean.notify;
 
 import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
 import javax.crypto.Cipher;
 import javax.crypto.spec.SecretKeySpec;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 
 import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
+import com.github.binarywang.wxpay.constant.WxPayConstants;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
@@ -17,11 +17,12 @@ import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
 
 /**
  * 
- *  退款结果通知对象
+ *  退款结果通知对象.
  *  Created by BinaryWang on 2017/8/27.
  * 
* @@ -36,7 +37,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ private static final long serialVersionUID = 4651725860079259186L; /** - * 从xml字符串创建bean对象 + * 从xml字符串创建bean对象. * * @param xmlString xml字符串 * @param mchKey 商户密钥 @@ -45,14 +46,19 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ */ public static WxPayRefundNotifyResult fromXML(String xmlString, String mchKey) throws WxPayException { WxPayRefundNotifyResult result = BaseWxPayResult.fromXML(xmlString, WxPayRefundNotifyResult.class); + if (WxPayConstants.ResultCode.FAIL.equals(result.getReturnCode())) { + return result; + } + String reqInfoString = result.getReqInfoString(); try { final String keyMd5String = DigestUtils.md5Hex(mchKey).toLowerCase(); - SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(), "AES"); + SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(StandardCharsets.UTF_8), "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, key); - result.setReqInfo(ReqInfo.fromXML(new String(cipher.doFinal(Base64.decodeBase64(reqInfoString))))); + result.setReqInfo(ReqInfo.fromXML(new String(cipher.doFinal(Base64.decodeBase64(reqInfoString)), + StandardCharsets.UTF_8))); } catch (Exception e) { throw new WxPayException("解密退款通知加密信息时出错", e); } @@ -62,7 +68,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ /** *
-   * 字段名:加密信息
+   * 字段名:加密信息.
    * 变量名:req_info
    * 是否必填:是
    * 类型:String(1024)
@@ -83,7 +89,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
   public static class ReqInfo {
     @Override
     public String toString() {
-      return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+      return WxGsonBuilder.create().toJson(this);
     }
 
     /**
@@ -210,7 +216,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
      * 是否必填:否
      * 类型: String(20)
      * 示例值:20160725152626
-     * 描述:-
+     * 
*/ @XStreamAlias("success_time") private String successTime; @@ -255,10 +261,10 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ private String refundRequestSource; /** - * From xml req info. + * 从xml字符串构造ReqInfo对象. * - * @param xmlString the xml string - * @return the req info + * @param xmlString xml字符串 + * @return ReqInfo对象 */ public static ReqInfo fromXML(String xmlString) { XStream xstream = XStreamInitializer.getInstance(); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java index 9e405aa0..164c30b3 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java @@ -19,6 +19,9 @@ public class WxPayAppOrderResult { private String prepayId; private String partnerId; private String appId; + /** + * 由于package为java保留关键字,因此改为packageValue. 前端使用时记得要更改为package + */ private String packageValue; private String timeStamp; private String nonceStr; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java index 12f8e43b..04cf893f 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java @@ -20,7 +20,7 @@ public class WxPayMpOrderResult { private String timeStamp; private String nonceStr; /** - * 由于package为java保留关键字,因此改为packageValue. + * 由于package为java保留关键字,因此改为packageValue. 前端使用时记得要更改为package */ @XStreamAlias("package") private String packageValue; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java index 3824e159..b39e76fd 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java @@ -4,8 +4,6 @@ import java.io.Serializable; import java.math.BigDecimal; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.exception.WxPayException; @@ -15,6 +13,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import lombok.Data; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.BeanUtils; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.common.util.xml.XStreamInitializer; import static com.github.binarywang.wxpay.constant.WxPayConstants.SignType.ALL_SIGN_TYPES; @@ -178,7 +177,7 @@ public abstract class BaseWxPayRequest implements Serializable { @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + return WxGsonBuilder.create().toJson(this); } /** diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java index 6b81aeed..5ff1c76a 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayQueryCommentRequest.java @@ -84,8 +84,4 @@ public class WxPayQueryCommentRequest extends BaseWxPayRequest { protected void checkConstraints() throws WxPayException { } - @Override - protected String[] getIgnoredParamsForSign() { - return new String[]{"limit","sign_type"}; - } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayReportRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayReportRequest.java index 494ac1f3..3e5364c5 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayReportRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayReportRequest.java @@ -25,9 +25,11 @@ import me.chanjar.weixin.common.annotation.Required; @AllArgsConstructor @XStreamAlias("xml") public class WxPayReportRequest extends BaseWxPayRequest { + private static final long serialVersionUID = 2667579776376527663L; + /** *
-   * 设备号
+   * 设备号.
    * device_info
    * 否
    * String(32)
@@ -40,7 +42,7 @@ public class WxPayReportRequest extends BaseWxPayRequest {
 
   /**
    * 
-   * 接口URL
+   * 接口URL.
    * interface_url
    * 是
    * String(127)
@@ -57,7 +59,7 @@ public class WxPayReportRequest extends BaseWxPayRequest {
   private String interfaceUrl;
   /**
    * 
-   * 接口耗时
+   * 接口耗时.
    * execute_time
    * 是
    * Int
@@ -70,7 +72,7 @@ public class WxPayReportRequest extends BaseWxPayRequest {
   private Integer executeTime;
   /**
    * 
-   * 返回状态码
+   * 返回状态码.
    * return_code
    * 是
    * String(16)
@@ -83,7 +85,7 @@ public class WxPayReportRequest extends BaseWxPayRequest {
   private String returnCode;
   /**
    * 
-   * 返回信息
+   * 返回信息.
    * return_msg
    * 否
    * String(128)
@@ -95,7 +97,7 @@ public class WxPayReportRequest extends BaseWxPayRequest {
   private String returnMsg;
   /**
    * 
-   * 业务结果
+   * 业务结果.
    * result_code
    * 是
    * String(16)
@@ -108,7 +110,7 @@ public class WxPayReportRequest extends BaseWxPayRequest {
   private String resultCode;
   /**
    * 
-   * 错误代码
+   * 错误代码.
    * err_code
    * 否
    * String(32)
@@ -120,7 +122,7 @@ public class WxPayReportRequest extends BaseWxPayRequest {
   private String errCode;
   /**
    * 
-   * 错误代码描述
+   * 错误代码描述.
    * err_code_des
    * 否
    * String(128)
@@ -132,7 +134,7 @@ public class WxPayReportRequest extends BaseWxPayRequest {
   private String errCodeDes;
   /**
    * 
-   * 商户订单号
+   * 商户订单号.
    * out_trade_no
    * 否
    * String(32)
@@ -144,7 +146,7 @@ public class WxPayReportRequest extends BaseWxPayRequest {
   private String outTradeNo;
   /**
    * 
-   * 访问接口IP
+   * 访问接口IP.
    * user_ip
    * 是
    * String(16)
@@ -157,7 +159,7 @@ public class WxPayReportRequest extends BaseWxPayRequest {
   private String userIp;
   /**
    * 
-   * 商户上报时间
+   * 商户上报时间.
    * time
    * 否
    * String(14)
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java
index 4b868a95..efa04d17 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java
@@ -102,11 +102,26 @@ public class WxPaySendRedpackRequest extends BaseWxPayRequest {
 
   /**
    * wxappid.
-   * 微信分配的公众账号ID(企业号corpid即为此appId)。接口传入的所有appid应该为公众号的appid(在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)
+   * 微信分配的公众账号ID(企业号corpid即为此appId)。
+   * 接口传入的所有appid应该为公众号的appid(在mp.weixin.qq.com申请的),
+   * 不能为APP的appid(在open.weixin.qq.com申请的)
    */
   @XStreamAlias("wxappid")
   private String wxAppid;
 
+  /**
+   * 触达用户appid.
+   * 
+   * msgappid
+   * wx28b16568a629bb33
+   * String(32)
+   * 服务商模式下触达用户时的appid(可填服务商自己的appid或子商户的appid),
+   * 服务商模式下必填,服务商模式下填入的子商户appid必须在微信支付商户平台中先录入,否则会校验不过。
+   * 
+ */ + @XStreamAlias("msgappid") + private String msgAppid; + /** *
    * scene_id.
@@ -153,7 +168,6 @@ public class WxPaySendRedpackRequest extends BaseWxPayRequest {
   @XStreamAlias("consume_mch_id")
   private String consumeMchId;
 
-
   @Override
   protected void checkConstraints() {
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java
index ad014fc2..b0233ded 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java
@@ -1,26 +1,23 @@
 package com.github.binarywang.wxpay.bean.result;
 
 import java.io.ByteArrayInputStream;
-import java.io.IOException;
 import java.io.Serializable;
 import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
 import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
 
+import com.github.binarywang.wxpay.constant.WxPayConstants;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.util.SignUtils;
@@ -30,6 +27,7 @@ import com.google.common.collect.Maps;
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.Data;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
 
 /**
@@ -149,7 +147,7 @@ public abstract class BaseWxPayResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxGsonBuilder.create().toJson(this);
   }
 
   /**
@@ -189,13 +187,13 @@ public abstract class BaseWxPayResult implements Serializable {
     }
 
     try {
-      this.xmlDoc = DocumentBuilderFactory
-        .newInstance()
-        .newDocumentBuilder()
-        .parse(new ByteArrayInputStream(this.xmlString.getBytes("UTF-8")));
+      final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+      factory.setExpandEntityReferences(false);
+      this.xmlDoc = factory.newDocumentBuilder()
+        .parse(new ByteArrayInputStream(this.xmlString.getBytes(StandardCharsets.UTF_8)));
       return xmlDoc;
-    } catch (SAXException | IOException | ParserConfigurationException e) {
-      throw new RuntimeException("非法的xml文本内容:" + this.xmlString);
+    } catch (Exception e) {
+      throw new RuntimeException("非法的xml文本内容:\n" + this.xmlString, e);
     }
 
   }
@@ -253,7 +251,7 @@ public abstract class BaseWxPayResult implements Serializable {
 
     //校验结果是否成功
     if (checkSuccess) {
-      List successStrings = Lists.newArrayList("SUCCESS", "");
+      List successStrings = Lists.newArrayList(WxPayConstants.ResultCode.SUCCESS, "");
       if (!successStrings.contains(StringUtils.trimToEmpty(getReturnCode()).toUpperCase())
         || !successStrings.contains(StringUtils.trimToEmpty(getResultCode()).toUpperCase())) {
         StringBuilder errorMsg = new StringBuilder();
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/WxPayBillInfo.java
similarity index 78%
rename from weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillBaseResult.java
rename to weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBillInfo.java
index a9b3e46c..f77d49e7 100644
--- 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/WxPayBillInfo.java
@@ -2,11 +2,9 @@ package com.github.binarywang.wxpay.bean.result;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
 /**
  * 交易时间:2017-04-06 01:00:02 公众账号ID: 商户号: 子商户号:0 设备号:WEB 微信订单号: 商户订单号:2017040519091071873216 用户标识: 交易类型:NATIVE
@@ -17,12 +15,12 @@ import lombok.NoArgsConstructor;
  */
 @Data
 @NoArgsConstructor
-public class WxPayBillBaseResult implements Serializable {
+public class WxPayBillInfo implements Serializable {
   private static final long serialVersionUID = 2226245109137435453L;
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxGsonBuilder.create().toJson(this);
   }
 
   /**
@@ -38,7 +36,7 @@ public class WxPayBillBaseResult implements Serializable {
    */
   private String mchId;
   /**
-   * 子商户号.
+   * 特约商户号.
    */
   private String subMchId;
   /**
@@ -74,11 +72,11 @@ public class WxPayBillBaseResult implements Serializable {
    */
   private String feeType;
   /**
-   * 总金额.
+   * 应结订单金额.
    */
   private String totalFee;
   /**
-   * 企业红包金额.
+   * 代金券金额.
    */
   private String couponFee;
   /**
@@ -94,7 +92,7 @@ public class WxPayBillBaseResult implements Serializable {
    */
   private String settlementRefundFee;
   /**
-   * 企业红包退款金额.
+   * 充值券退款金额.
    */
   private String couponRefundFee;
   /**
@@ -121,5 +119,24 @@ public class WxPayBillBaseResult implements Serializable {
    * 费率.
    */
   private String poundageRate;
-
+  /**
+   * 订单金额.
+   */
+  private String totalAmount;
+  /**
+   * 申请退款金额.
+   */
+  private String appliedRefundAmount;
+  /**
+   * 费率备注.
+   */
+  private String feeRemark;
+  /**
+   * 退款申请时间
+   */
+  private String refundTime;
+  /**
+   * 退款成功时间
+   */
+  private String refundSuccessTime;
 }
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
index a8f9f7c5..e568a77d 100644
--- 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
@@ -1,52 +1,380 @@
 package com.github.binarywang.wxpay.bean.result;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
 /**
- * The type Wx pay bill result.
+ * 微信对账单结果类.
  *
- * @author BinaryWang
+ * @author DDLeEHi
  */
 @Data
 @NoArgsConstructor
 public class WxPayBillResult implements Serializable {
+  private static final String TOTAL_DEAL_COUNT = "总交易单数";
   private static final long serialVersionUID = -7687458652694204070L;
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxGsonBuilder.create().toJson(this);
   }
 
   /**
-   * 对账返回对象.
+   * 对账明细列表.
    */
-  private List wxPayBillBaseResultLst;
+  private List billInfoList;
   /**
    * 总交易单数.
    */
   private String totalRecord;
   /**
-   * 总交易额.
+   * 应结订单总金额.
    */
   private String totalFee;
   /**
-   * 总退款金额.
+   * 退款总金额.
    */
   private String totalRefundFee;
   /**
-   * 总代金券或立减优惠退款金额.
+   * 充值券退款总金额.
    */
   private String totalCouponFee;
   /**
    * 手续费总金额.
    */
   private String totalPoundageFee;
+  /**
+   * 订单总金额.
+   */
+  private String totalAmount;
+  /**
+   * 申请退款总金额.
+   */
+  private String totalAppliedRefundFee;
+
+  /**
+   * 根据账单类型,从原始对账单字符串里构造出WxPayBillResult对象
+   *
+   * @param responseContent 原始对账单字符串
+   * @param billType        账单类型
+   * @return WxPayBillResult对象
+   */
+  public static WxPayBillResult fromRawBillResultString(String responseContent, String billType) {
+    switch (billType) {
+      case "ALL":{
+        return fromRawBillResultString(responseContent);
+      }
+      case "SUCCESS":{
+        return fromRawBillResultStringToSuccess(responseContent);
+      }
+      case "REFUND" :{
+        return fromRawBillResultStringToRefund(responseContent);
+      }
+      case "RECHARGE_REFUND" :{
+        return fromRawBillResultStringToRechargeRefund(responseContent);
+      }
+      default: {
+        return null;
+      }
+    }
+  }
+
+  /**
+   * 从原始对账单字符串里构造出WxPayBillResult对象,用于构建当日所有订单信息
+   */
+  private static WxPayBillResult fromRawBillResultString(String responseContent) {
+    String listStr = "";
+    String objStr = "";
+    if (responseContent.contains(TOTAL_DEAL_COUNT)) {
+      listStr = responseContent.substring(0, responseContent.indexOf(TOTAL_DEAL_COUNT));
+      objStr = responseContent.substring(responseContent.indexOf(TOTAL_DEAL_COUNT));
+    }
+
+    List results = new ArrayList<>();
+    // 去空格
+    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++) {
+      WxPayBillInfo result = new WxPayBillInfo();
+      result.setTradeTime(tempStr[k].trim());
+      result.setAppId(tempStr[k + 1].trim());
+      result.setMchId(tempStr[k + 2].trim());
+      result.setSubMchId(tempStr[k + 3].trim());
+      result.setDeviceInfo(tempStr[k + 4].trim());
+      result.setTransactionId(tempStr[k + 5].trim());
+      result.setOutTradeNo(tempStr[k + 6].trim());
+      result.setOpenId(tempStr[k + 7].trim());
+      result.setTradeType(tempStr[k + 8].trim());
+      result.setTradeState(tempStr[k + 9].trim());
+      result.setBankType(tempStr[k + 10].trim());
+      result.setFeeType(tempStr[k + 11].trim());
+      result.setTotalFee(tempStr[k + 12].trim());
+      result.setCouponFee(tempStr[k + 13].trim());
+      result.setRefundId(tempStr[k + 14].trim());
+      result.setOutRefundNo(tempStr[k + 15].trim());
+      result.setSettlementRefundFee(tempStr[k + 16].trim());
+      result.setCouponRefundFee(tempStr[k + 17].trim());
+      result.setRefundChannel(tempStr[k + 18].trim());
+      result.setRefundState(tempStr[k + 19].trim());
+      result.setBody(tempStr[k + 20].trim());
+      result.setAttach(tempStr[k + 21].trim());
+      result.setPoundage(tempStr[k + 22].trim());
+      result.setPoundageRate(tempStr[k + 23].trim());
+      results.add(result);
+      k += t.length;
+    }
+
+    WxPayBillResult billResult = new WxPayBillResult();
+    billResult.setBillInfoList(results);
+
+    /*
+     * 总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额 `2,`0.02,`0.0,`0.0,`0
+     * 参考以上格式进行取值
+     */
+    String[] totalTempStr = objStr.replaceAll(",", " ").split("`");
+    billResult.setTotalRecord(totalTempStr[1].trim());
+    billResult.setTotalFee(totalTempStr[2].trim());
+    billResult.setTotalRefundFee(totalTempStr[3].trim());
+    billResult.setTotalCouponFee(totalTempStr[4].trim());
+    billResult.setTotalPoundageFee(totalTempStr[5].trim());
+    return billResult;
+  }
+
+  /**
+   * 从原始对账单字符串里构造出WxPayBillResult对象,用于构建当日成功支付的订单
+   */
+  private static WxPayBillResult fromRawBillResultStringToSuccess(String responseContent) {
+    String listStr = "";
+    String objStr = "";
+    if (responseContent.contains(TOTAL_DEAL_COUNT)) {
+      listStr = responseContent.substring(0, responseContent.indexOf(TOTAL_DEAL_COUNT));
+      objStr = responseContent.substring(responseContent.indexOf(TOTAL_DEAL_COUNT));
+    }
+
+    List results = new ArrayList<>();
+    // 去空格
+    String newStr = listStr.replaceAll(",", " ");
+    // 数据分组
+    String[] tempStr = newStr.split("`");
+    // 分组标题
+    String[] t = tempStr[0].split(" ");
+    // 计算循环次数
+    int j = tempStr.length / t.length;
+    // 纪录数组下标
+    int k = 1;
+    // 交易时间,公众账号ID,商户号,子商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,总金额,代金券或立减优惠金额,商品名称,商户数据包,手续费,费率
+    for (int i = 0; i < j; i++) {
+      WxPayBillInfo result = new WxPayBillInfo();
+      result.setTradeTime(tempStr[k].trim());
+      result.setAppId(tempStr[k + 1].trim());
+      result.setMchId(tempStr[k + 2].trim());
+      result.setSubMchId(tempStr[k + 3].trim());
+      result.setDeviceInfo(tempStr[k + 4].trim());
+      result.setTransactionId(tempStr[k + 5].trim());
+      result.setOutTradeNo(tempStr[k + 6].trim());
+      result.setOpenId(tempStr[k + 7].trim());
+      result.setTradeType(tempStr[k + 8].trim());
+      result.setTradeState(tempStr[k + 9].trim());
+      result.setBankType(tempStr[k + 10].trim());
+      result.setFeeType(tempStr[k + 11].trim());
+      result.setTotalFee(tempStr[k + 12].trim());
+      result.setCouponFee(tempStr[k + 13].trim());
+      result.setBody(tempStr[k + 14].trim());
+      result.setAttach(tempStr[k + 15].trim());
+      result.setPoundage(tempStr[k + 16].trim());
+      result.setPoundageRate(tempStr[k + 17].trim());
+      results.add(result);
+      k += t.length;
+    }
+
+    WxPayBillResult billResult = new WxPayBillResult();
+    billResult.setBillInfoList(results);
 
+    /*
+     * 总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额 `2,`0.02,`0.0,`0.0,`0
+     * 参考以上格式进行取值
+     */
+    String[] totalTempStr = objStr.replaceAll(",", " ").split("`");
+    billResult.setTotalRecord(totalTempStr[1].trim());
+    billResult.setTotalFee(totalTempStr[2].trim());
+    billResult.setTotalRefundFee(totalTempStr[3].trim());
+    billResult.setTotalCouponFee(totalTempStr[4].trim());
+    billResult.setTotalPoundageFee(totalTempStr[5].trim());
+    return billResult;
+  }
+
+  /**
+   * 从原始对账单字符串里构造出WxPayBillResult对象,用于构建当日退款的订单
+   */
+  private static WxPayBillResult fromRawBillResultStringToRefund(String responseContent) {
+    String listStr = "";
+    String objStr = "";
+    if (responseContent.contains(TOTAL_DEAL_COUNT)) {
+      listStr = responseContent.substring(0, responseContent.indexOf(TOTAL_DEAL_COUNT));
+      objStr = responseContent.substring(responseContent.indexOf(TOTAL_DEAL_COUNT));
+    }
+
+    List results = new ArrayList<>();
+    // 去空格
+    String newStr = listStr.replaceAll(",", " ");
+    // 数据分组
+    String[] tempStr = newStr.split("`");
+    // 分组标题
+    String[] t = tempStr[0].split(" ");
+    // 计算循环次数
+    int j = tempStr.length / t.length;
+    // 纪录数组下标
+    int k = 1;
+    // 交易时间,公众账号ID,商户号,子商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,总金额,代金券或立减优惠金额,
+    // 退款申请时间,退款成功时间,微信退款单号,商户退款单号,退款金额,代金券或立减优惠退款金额,退款类型,退款状态,商品名称,商户数据包,手续费,费率
+    for (int i = 0; i < j; i++) {
+      WxPayBillInfo result = new WxPayBillInfo();
+      result.setTradeTime(tempStr[k].trim());
+      result.setAppId(tempStr[k + 1].trim());
+      result.setMchId(tempStr[k + 2].trim());
+      result.setSubMchId(tempStr[k + 3].trim());
+      result.setDeviceInfo(tempStr[k + 4].trim());
+      result.setTransactionId(tempStr[k + 5].trim());
+      result.setOutTradeNo(tempStr[k + 6].trim());
+      result.setOpenId(tempStr[k + 7].trim());
+      result.setTradeType(tempStr[k + 8].trim());
+      result.setTradeState(tempStr[k + 9].trim());
+      result.setBankType(tempStr[k + 10].trim());
+      result.setFeeType(tempStr[k + 11].trim());
+      result.setTotalFee(tempStr[k + 12].trim());
+      result.setCouponFee(tempStr[k + 13].trim());
+      result.setRefundTime(tempStr[k + 14].trim());
+      result.setRefundSuccessTime(tempStr[k + 15].trim());
+      result.setRefundId(tempStr[k + 16].trim());
+      result.setOutRefundNo(tempStr[k + 17].trim());
+      result.setSettlementRefundFee(tempStr[k + 18].trim());
+      result.setCouponRefundFee(tempStr[k + 19].trim());
+      result.setRefundChannel(tempStr[k + 20].trim());
+      result.setRefundState(tempStr[k + 21].trim());
+      result.setBody(tempStr[k + 22].trim());
+      result.setAttach(tempStr[k + 23].trim());
+      result.setPoundage(tempStr[k + 24].trim());
+      result.setPoundageRate(tempStr[k + 25].trim());
+      results.add(result);
+      k += t.length;
+    }
+
+    WxPayBillResult billResult = new WxPayBillResult();
+    billResult.setBillInfoList(results);
+
+    /*
+     * 总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额 `2,`0.02,`0.0,`0.0,`0
+     * 参考以上格式进行取值
+     */
+    String[] totalTempStr = objStr.replaceAll(",", " ").split("`");
+    billResult.setTotalRecord(totalTempStr[1].trim());
+    billResult.setTotalFee(totalTempStr[2].trim());
+    billResult.setTotalRefundFee(totalTempStr[3].trim());
+    billResult.setTotalCouponFee(totalTempStr[4].trim());
+    billResult.setTotalPoundageFee(totalTempStr[5].trim());
+    billResult.setTotalAmount(get(totalTempStr, 6));
+    billResult.setTotalAppliedRefundFee(get(totalTempStr, 7));
+
+    return billResult;
+  }
+
+  /**
+   * 从原始对账单字符串里构造出WxPayBillResult对象,用于构建当日充值退款订单
+   */
+  private static WxPayBillResult fromRawBillResultStringToRechargeRefund(String responseContent) {
+    String listStr = "";
+    String objStr = "";
+    if (responseContent.contains(TOTAL_DEAL_COUNT)) {
+      listStr = responseContent.substring(0, responseContent.indexOf(TOTAL_DEAL_COUNT));
+      objStr = responseContent.substring(responseContent.indexOf(TOTAL_DEAL_COUNT));
+    }
+
+    List results = new ArrayList<>();
+    // 去空格
+    String newStr = listStr.replaceAll(",", " ");
+    // 数据分组
+    String[] tempStr = newStr.split("`");
+    // 分组标题
+    String[] t = tempStr[0].split(" ");
+    // 计算循环次数
+    int j = tempStr.length / t.length;
+    // 纪录数组下标
+    int k = 1;
+    // 交易时间,公众账号ID,商户号,子商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,应结订单金额,代金券金额,
+    // 退款申请时间,退款成功时间,微信退款单号,商户退款单号,退款金额,充值券退款金额,退款类型,退款状态,商品名称,商户数据包,返还手续费,费率,订单金额,申请退款金额
+    for (int i = 0; i < j; i++) {
+      WxPayBillInfo result = new WxPayBillInfo();
+      result.setTradeTime(tempStr[k].trim());
+      result.setAppId(tempStr[k + 1].trim());
+      result.setMchId(tempStr[k + 2].trim());
+      result.setSubMchId(tempStr[k + 3].trim());
+      result.setDeviceInfo(tempStr[k + 4].trim());
+      result.setTransactionId(tempStr[k + 5].trim());
+      result.setOutTradeNo(tempStr[k + 6].trim());
+      result.setOpenId(tempStr[k + 7].trim());
+      result.setTradeType(tempStr[k + 8].trim());
+      result.setTradeState(tempStr[k + 9].trim());
+      result.setBankType(tempStr[k + 10].trim());
+      result.setFeeType(tempStr[k + 11].trim());
+      result.setTotalFee(tempStr[k + 12].trim());
+      result.setCouponFee(tempStr[k + 13].trim());
+      result.setRefundTime(tempStr[k + 14].trim());
+      result.setRefundSuccessTime(tempStr[k + 15].trim());
+      result.setRefundId(tempStr[k + 16].trim());
+      result.setOutRefundNo(tempStr[k + 17].trim());
+      result.setSettlementRefundFee(tempStr[k + 18].trim());
+      result.setCouponRefundFee(tempStr[k + 19].trim());
+      result.setRefundChannel(tempStr[k + 20].trim());
+      result.setRefundState(tempStr[k + 21].trim());
+      result.setBody(tempStr[k + 22].trim());
+      result.setAttach(tempStr[k + 23].trim());
+      result.setPoundage(tempStr[k + 24].trim());
+      result.setPoundageRate(tempStr[k + 25].trim());
+      result.setTotalAmount(get(tempStr, k + 26, t.length));
+      result.setAppliedRefundAmount(get(tempStr, k + 27, t.length));
+      results.add(result);
+      k += t.length;
+    }
+
+    WxPayBillResult billResult = new WxPayBillResult();
+    billResult.setBillInfoList(results);
+
+    /*
+     * 总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额 `2,`0.02,`0.0,`0.0,`0
+     * 参考以上格式进行取值
+     */
+    String[] totalTempStr = objStr.replaceAll(",", " ").split("`");
+    billResult.setTotalRecord(totalTempStr[1].trim());
+    billResult.setTotalFee(totalTempStr[2].trim());
+    billResult.setTotalRefundFee(totalTempStr[3].trim());
+    billResult.setTotalCouponFee(totalTempStr[4].trim());
+    billResult.setTotalPoundageFee(totalTempStr[5].trim());
+    billResult.setTotalAmount(get(totalTempStr, 6));
+    billResult.setTotalAppliedRefundFee(get(totalTempStr, 7));
+
+    return billResult;
+  }
+
+  private static String get(String[] array, int idx) {
+    return get(array, idx, array.length);
+  }
+
+  private static String get(String[] array, int idx, int length) {
+    if (length > idx) {
+      return array[idx].trim();
+    }
+    return null;
+  }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowBaseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowBaseResult.java
index dc631314..75ee1509 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowBaseResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowBaseResult.java
@@ -1,11 +1,10 @@
 package com.github.binarywang.wxpay.bean.result;
 
+import java.io.Serializable;
+
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-import java.io.Serializable;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
 /**
  * 记账时间:2018-02-01 04:21:23 微信支付业务单号:50000305742018020103387128253 资金流水单号:1900009231201802015884652186 业务名称:退款
@@ -20,19 +19,19 @@ public class WxPayFundFlowBaseResult implements Serializable {
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxGsonBuilder.create().toJson(this);
   }
 
   /**
-   * 记账时间
+   * 记账时间.
    */
   private String BillingTime;
   /**
-   * 微信支付业务单号
+   * 微信支付业务单号.
    */
   private String bizTransactionId;
   /**
-   * 资金流水单号
+   * 资金流水单号.
    */
   private String fundFlowId;
   /**
@@ -40,31 +39,31 @@ public class WxPayFundFlowBaseResult implements Serializable {
    */
   private String bizName;
   /**
-   * 业务类型
+   * 业务类型.
    */
   private String bizType;
   /**
-   * 收支类型
+   * 收支类型.
    */
   private String financialType;
   /**
-   * 收支金额(元)
+   * 收支金额(元).
    */
   private String financialFee;
   /**
-   * 账户结余(元)
+   * 账户结余(元).
    */
   private String AccountBalance;
   /**
-   * 资金变更提交申请人
+   * 资金变更提交申请人.
    */
   private String fundApplicant;
   /**
-   * 备注
+   * 备注.
    */
   private String memo;
   /**
-   * 业务凭证号
+   * 业务凭证号.
    */
   private String bizVoucherId;
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowResult.java
index ba325504..7b789ca0 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowResult.java
@@ -3,11 +3,9 @@ package com.github.binarywang.wxpay.bean.result;
 import java.io.Serializable;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
 /**
  * 
@@ -19,16 +17,16 @@ import lombok.NoArgsConstructor;
  */
 @Data
 @NoArgsConstructor
-public class WxPayFundFlowResult implements Serializable{
+public class WxPayFundFlowResult implements Serializable {
   private static final long serialVersionUID = 8371500036495349207L;
 
   @Override
   public String toString() {
-    return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
+    return WxGsonBuilder.create().toJson(this);
   }
 
   /**
-   * 资金流水返回对象
+   * 资金流水返回对象.
    */
   private List wxPayFundFlowBaseResultList;
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResult.java
index c54c5368..c7534b79 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryResult.java
@@ -1,10 +1,15 @@
 package com.github.binarywang.wxpay.bean.result;
 
+import java.io.Serializable;
+import java.util.List;
+
 import com.google.common.collect.Lists;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
-import lombok.*;
-
-import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
 
 /**
  * 
@@ -26,7 +31,8 @@ import java.util.List;
 @NoArgsConstructor
 @XStreamAlias("xml")
 public class WxPayOrderQueryResult extends BaseWxPayResult {
-
+  private static final long serialVersionUID = 8241891654782412789L;
+  
   /**
    * 
    * 字段名:营销详情.
@@ -41,7 +47,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private String promotionDetail;
 
   /**
-   * 
设备号
+   * 
+   * 设备号.
    * device_info
    * 否
    * String(32)
@@ -53,7 +60,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private String deviceInfo;
 
   /**
-   * 
用户标识
+   * 
+   * 用户标识.
    * openid
    * 是
    * String(128)
@@ -65,7 +73,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private String openid;
 
   /**
-   * 
是否关注公众账号
+   * 
+   * 是否关注公众账号.
    * is_subscribe
    * 否
    * String(1)
@@ -77,7 +86,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private String isSubscribe;
 
   /**
-   * 
交易类型
+   * 
+   * 交易类型.
    * trade_type
    * 是
    * String(16)
@@ -89,7 +99,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private String tradeType;
 
   /**
-   * 
交易状态
+   * 
+   * 交易状态.
    * trade_state
    * 是
    * String(32)
@@ -101,7 +112,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private String tradeState;
 
   /**
-   * 
付款银行
+   * 
+   * 付款银行.
    * bank_type
    * 是
    * String(16)
@@ -113,7 +125,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private String bankType;
 
   /**
-   * 
订单金额
+   * 
+   * 订单金额.
    * total_fee
    * 是
    * Int
@@ -125,7 +138,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private Integer totalFee;
 
   /**
-   * 
应结订单金额
+   * 
+   * 应结订单金额.
    * settlement_total_fee
    * 否
    * Int
@@ -137,7 +151,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private Integer settlementTotalFee;
 
   /**
-   * 
货币种类
+   * 
+   * 货币种类.
    * fee_type
    * 否
    * String(8)
@@ -149,7 +164,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private String feeType;
 
   /**
-   * 
现金支付金额
+   * 
+   * 现金支付金额.
    * cash_fee
    * 是
    * Int
@@ -161,7 +177,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private Integer cashFee;
 
   /**
-   * 
现金支付货币类型
+   * 
+   * 现金支付货币类型.
    * cash_fee_type
    * 否
    * String(16)
@@ -173,7 +190,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private String cashFeeType;
 
   /**
-   * 
代金券金额
+   * 
+   * 代金券金额.
    * coupon_fee
    * 否
    * Int
@@ -185,7 +203,7 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private Integer couponFee;
 
   /**
-   * 
代金券使用数量
+   * 
代金券使用数量.
    * coupon_count
    * 否
    * Int
@@ -198,7 +216,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
 
   private List coupons;
   /**
-   * 
微信支付订单号
+   * 
+   * 微信支付订单号.
    * transaction_id
    * 是
    * String(32)
@@ -209,7 +228,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   @XStreamAlias("transaction_id")
   private String transactionId;
   /**
-   * 
商户订单号
+   * 
+   * 商户订单号.
    * out_trade_no
    * 是
    * String(32)
@@ -220,7 +240,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   @XStreamAlias("out_trade_no")
   private String outTradeNo;
   /**
-   * 
附加数据
+   * 
+   * 附加数据.
    * attach
    * 否
    * String(128)
@@ -231,7 +252,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   @XStreamAlias("attach")
   private String attach;
   /**
-   * 
支付完成时间
+   * 
+   * 支付完成时间.
    * time_end
    * 是
    * String(14)
@@ -242,7 +264,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   @XStreamAlias("time_end")
   private String timeEnd;
   /**
-   * 
交易状态描述
+   * 
+   * 交易状态描述.
    * trade_state_desc
    * 是
    * String(256)
@@ -254,7 +277,7 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   private String tradeStateDesc;
 
   /**
-   * 通过xml组装coupons属性内容
+   * 通过xml组装coupons属性内容.
    */
   public void composeCoupons() {
     if (this.couponCount != null && this.couponCount > 0) {
@@ -273,9 +296,12 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
   @Data
   @Builder(builderMethodName = "newBuilder")
   @AllArgsConstructor
-  public static class Coupon {
+  public static class Coupon implements Serializable {
+    private static final long serialVersionUID = -954000582332155081L;
+
     /**
-     * 
代金券类型
+     * 
+     * 代金券类型.
      * coupon_type_$n
      * 否
      * String
@@ -288,7 +314,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
     private String couponType;
 
     /**
-     * 
代金券ID
+     * 
+     * 代金券ID.
      * coupon_id_$n
      * 否
      * String(20)
@@ -299,7 +326,8 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
     private String couponId;
 
     /**
-     * 
单个代金券支付金额
+     * 
+     * 单个代金券支付金额.
      * coupon_fee_$n
      * 否
      * Int
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResult.java
index 18ce1fc8..b60011ba 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResult.java
@@ -119,7 +119,7 @@ public class WxPayRefundResult extends BaseWxPayResult implements Serializable {
   /**
    * 组装生成退款代金券信息.
    */
-  public void composeRefundCoupons() {
+  private void composeRefundCoupons() {
     List coupons = Lists.newArrayList();
     Integer refundCount = this.getCouponRefundCount();
     if (refundCount == null) {
@@ -139,4 +139,10 @@ public class WxPayRefundResult extends BaseWxPayResult implements Serializable {
 
     this.setRefundCoupons(coupons);
   }
+
+  public static WxPayRefundResult fromXML(String xml) {
+    WxPayRefundResult result = BaseWxPayResult.fromXML(xml, WxPayRefundResult.class);
+    result.composeRefundCoupons();
+    return result;
+  }
 }
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 e35d0b25..f8d915f8 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
@@ -88,6 +88,13 @@ public class WxPayConfig {
    * 默认不使用
    */
   private boolean useSandboxEnv = false;
+
+  /**
+   * 是否将接口请求日志信息保存到threadLocal中.
+   * 默认不保存
+   */
+  private boolean ifSaveApiData = false;
+
   private String httpProxyHost;
   private Integer httpProxyPort;
   private String httpProxyUsername;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java
index 01753c0e..76f823cc 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java
@@ -1,11 +1,12 @@
 package com.github.binarywang.wxpay.constant;
 
-import com.google.common.collect.Lists;
-import org.apache.commons.lang3.time.FastDateFormat;
-
 import java.text.Format;
 import java.util.List;
 
+import org.apache.commons.lang3.time.FastDateFormat;
+
+import com.google.common.collect.Lists;
+
 /**
  * 
  * 微信支付常量类
@@ -19,7 +20,7 @@ public class WxPayConstants {
   /**
    * 拉取订单评价数据接口的参数中日期格式.
    */
-  public static final Format QUERY_COMMENT_DATE_FORMAT =  FastDateFormat.getInstance("yyyyMMddHHmmss");
+  public static final Format QUERY_COMMENT_DATE_FORMAT = FastDateFormat.getInstance("yyyyMMddHHmmss");
 
   /**
    * 校验用户姓名选项,企业付款时使用.
@@ -89,7 +90,7 @@ public class WxPayConstants {
     public static final String APP = "APP";
 
     /**
-     * 公众号支付.
+     * 公众号支付/小程序支付.
      */
     public static final String JSAPI = "JSAPI";
 
@@ -108,7 +109,7 @@ public class WxPayConstants {
   /**
    * 账户类型
    */
-  public static class AccountType{
+  public static class AccountType {
     /**
      * 基本账户
      */
@@ -272,49 +273,4 @@ public class WxPayConstants {
      */
     public static final String CHANGE = "CHANGE";
   }
-
-  /**
-   * 关闭订单结果错误代码.
-   */
-  public static class OrderCloseResultErrorCode {
-    /**
-     * 订单已支付.
-     */
-    public static final String ORDER_PAID = "ORDERPAID";
-
-    /**
-     * 系统错误.
-     */
-    public static final String SYSTEM_ERROR = "SYSTEMERROR";
-
-    /**
-     * 订单不存在.
-     */
-    public static final String ORDER_NOT_EXIST = "ORDERNOTEXIST";
-
-    /**
-     * 订单已关闭.
-     */
-    public static final String ORDER_CLOSED = "ORDERCLOSED";
-
-    /**
-     * 签名错误.
-     */
-    public static final String SIGN_ERROR = "SIGNERROR";
-
-    /**
-     * 未使用POST传递参数.
-     */
-    public static final String REQUIRE_POST_METHOD = "REQUIRE_POST_METHOD";
-
-    /**
-     * XML格式错误.
-     */
-    public static final String XML_FORMAT_ERROR = "XML_FORMAT_ERROR";
-
-    /**
-     * 订单状态错误.
-     */
-    public static final String TRADE_STATE_ERROR = "TRADE_STATE_ERROR";
-  }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayErrorCode.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayErrorCode.java
new file mode 100644
index 00000000..0cb7568f
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayErrorCode.java
@@ -0,0 +1,495 @@
+package com.github.binarywang.wxpay.constant;
+
+/**
+ * 
+ * 微信支付错误码
+ * Created by Binary Wang on 2018/11/18.
+ * 
+ * + * @author Binary Wang + */ +public class WxPayErrorCode { + /** + * 统一下单接口的错误码. + * https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1 + */ + public static class UnifiedOrder { + /** + *
+     * 描述:商户无此接口权限.
+     * 原因:商户未开通此接口权限
+     * 解决方案:请商户前往申请此接口权限
+     * 
+ */ + public static final String NOAUTH = "NOAUTH"; + /** + *
+     * 描述:余额不足.
+     * 原因:用户帐号余额不足
+     * 解决方案:用户帐号余额不足,请用户充值或更换支付卡后再支付
+     * 
+ */ + public static final String NOTENOUGH = "NOTENOUGH"; + /** + *
+     * 描述:商户订单已支付.
+     * 原因:商户订单已支付,无需重复操作
+     * 解决方案:商户订单已支付,无需更多操作
+     * 
+ */ + public static final String ORDERPAID = "ORDERPAID"; + /** + *
+     * 描述:订单已关闭.
+     * 原因:当前订单已关闭,无法支付
+     * 解决方案:当前订单已关闭,请重新下单
+     * 
+ */ + public static final String ORDERCLOSED = "ORDERCLOSED"; + /** + *
+     * 描述:系统错误.
+     * 原因:系统超时
+     * 解决方案:系统异常,请用相同参数重新调用
+     * 
+ */ + public static final String SYSTEMERROR = "SYSTEMERROR"; + /** + *
+     * 描述:APPID不存在.
+     * 原因:参数中缺少APPID
+     * 解决方案:请检查APPID是否正确
+     * 
+ */ + public static final String APPID_NOT_EXIST = "APPID_NOT_EXIST"; + /** + *
+     * 描述:MCHID不存在.
+     * 原因:参数中缺少MCHID
+     * 解决方案:请检查MCHID是否正确
+     * 
+ */ + public static final String MCHID_NOT_EXIST = "MCHID_NOT_EXIST"; + /** + *
+     * 描述:appid和mch_id不匹配.
+     * 原因:appid和mch_id不匹配
+     * 解决方案:请确认appid和mch_id是否匹配
+     * 
+ */ + public static final String APPID_MCHID_NOT_MATCH = "APPID_MCHID_NOT_MATCH"; + /** + *
+     * 描述:缺少参数.
+     * 原因:缺少必要的请求参数
+     * 解决方案:请检查参数是否齐全
+     * 
+ */ + public static final String LACK_PARAMS = "LACK_PARAMS"; + /** + *
+     * 描述:商户订单号重复.
+     * 原因:同一笔交易不能多次提交
+     * 解决方案:请核实商户订单号是否重复提交
+     * 
+ */ + public static final String OUT_TRADE_NO_USED = "OUT_TRADE_NO_USED"; + /** + *
+     * 描述:签名错误.
+     * 原因:参数签名结果不正确
+     * 解决方案:请检查签名参数和方法是否都符合签名算法要求
+     * 
+ */ + public static final String SIGNERROR = "SIGNERROR"; + /** + *
+     * 描述:XML格式错误.
+     * 原因:XML格式错误
+     * 解决方案:请检查XML参数格式是否正确
+     * 
+ */ + public static final String XML_FORMAT_ERROR = "XML_FORMAT_ERROR"; + /** + *
+     * 描述:请使用post方法.
+     * 原因:未使用post传递参数
+     * 解决方案:请检查请求参数是否通过post方法提交
+     * 
+ */ + public static final String REQUIRE_POST_METHOD = "REQUIRE_POST_METHOD"; + /** + *
+     * 描述:post数据为空.
+     * 原因:post数据不能为空
+     * 解决方案:请检查post数据是否为空
+     * 
+ */ + public static final String POST_DATA_EMPTY = "POST_DATA_EMPTY"; + /** + *
+     * 描述:编码格式错误.
+     * 原因:未使用指定编码格式
+     * 解决方案:请使用UTF-8编码格式
+     * 
+ */ + public static final String NOT_UTF8 = "NOT_UTF8"; + } + + /** + * 关闭订单. + * https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_3&index=5 + */ + public static class OrderClose { + /** + * 订单已支付. + */ + public static final String ORDER_PAID = "ORDERPAID"; + + /** + * 系统错误. + */ + public static final String SYSTEM_ERROR = "SYSTEMERROR"; + + /** + * 订单不存在. + */ + public static final String ORDER_NOT_EXIST = "ORDERNOTEXIST"; + + /** + * 订单已关闭. + */ + public static final String ORDER_CLOSED = "ORDERCLOSED"; + + /** + * 签名错误. + */ + public static final String SIGN_ERROR = "SIGNERROR"; + + /** + * 未使用POST传递参数. + */ + public static final String REQUIRE_POST_METHOD = "REQUIRE_POST_METHOD"; + + /** + * XML格式错误. + */ + public static final String XML_FORMAT_ERROR = "XML_FORMAT_ERROR"; + + /** + * 订单状态错误. + */ + public static final String TRADE_STATE_ERROR = "TRADE_STATE_ERROR"; + } + + /** + * 退款申请. + * https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_4&index=6 + */ + public static class Refund { + /** + *
+     * 描述:接口返回错误.
+     * 原因:系统超时等
+     * 解决方案:请不要更换商户退款单号,请使用相同参数再次调用API。
+     * 
+ */ + public static final String SYSTEMERROR = "SYSTEMERROR"; + /** + *
+     * 描述:退款业务流程错误,需要商户触发重试来解决.
+     * 原因:并发情况下,业务被拒绝,商户重试即可解决
+     * 解决方案:请不要更换商户退款单号,请使用相同参数再次调用API。
+     * 
+ */ + public static final String BIZERR_NEED_RETRY = "BIZERR_NEED_RETRY"; + /** + *
+     * 描述:订单已经超过退款期限.
+     * 原因:订单已经超过可退款的最大期限(支付后一年内可退款)
+     * 解决方案:请选择其他方式自行退款
+     * 
+ */ + public static final String TRADE_OVERDUE = "TRADE_OVERDUE"; + /** + *
+     * 描述:业务错误.
+     * 原因:申请退款业务发生错误
+     * 解决方案:该错误都会返回具体的错误原因,请根据实际返回做相应处理。
+     * 
+ */ + public static final String ERROR = "ERROR"; + /** + *
+     * 描述:退款请求失败.
+     * 原因:用户帐号注销
+     * 解决方案:此状态代表退款申请失败,商户可自行处理退款。
+     * 
+ */ + public static final String USER_ACCOUNT_ABNORMAL = "USER_ACCOUNT_ABNORMAL"; + /** + *
+     * 描述:无效请求过多.
+     * 原因:连续错误请求数过多被系统短暂屏蔽
+     * 解决方案:请检查业务是否正常,确认业务正常后请在1分钟后再来重试
+     * 
+ */ + public static final String INVALID_REQ_TOO_MUCH = "INVALID_REQ_TOO_MUCH"; + /** + *
+     * 描述:余额不足.
+     * 原因:商户可用退款余额不足
+     * 解决方案:此状态代表退款申请失败,商户可根据具体的错误提示做相应的处理。
+     * 
+ */ + public static final String NOTENOUGH = "NOTENOUGH"; + /** + *
+     * 描述:无效transaction_id.
+     * 原因:请求参数未按指引进行填写
+     * 解决方案:请求参数错误,检查原交易号是否存在或发起支付交易接口返回失败
+     * 
+ */ + public static final String INVALID_TRANSACTIONID = "INVALID_TRANSACTIONID"; + /** + *
+     * 描述:参数错误.
+     * 原因:请求参数未按指引进行填写
+     * 解决方案:请求参数错误,请重新检查再调用退款申请
+     * 
+ */ + public static final String PARAM_ERROR = "PARAM_ERROR"; + /** + *
+     * 描述:APPID不存在.
+     * 原因:参数中缺少APPID
+     * 解决方案:请检查APPID是否正确
+     * 
+ */ + public static final String APPID_NOT_EXIST = "APPID_NOT_EXIST"; + /** + *
+     * 描述:MCHID不存在.
+     * 原因:参数中缺少MCHID
+     * 解决方案:请检查MCHID是否正确
+     * 
+ */ + public static final String MCHID_NOT_EXIST = "MCHID_NOT_EXIST"; + /** + *
+     * 描述:订单号不存在.
+     * 原因:缺少有效的订单号
+     * 解决方案:请检查你的订单号是否正确且是否已支付,未支付的订单不能发起退款
+     * 
+ */ + public static final String ORDERNOTEXIST = "ORDERNOTEXIST"; + /** + *
+     * 描述:请使用post方法.
+     * 原因:未使用post传递参数
+     * 解决方案:请检查请求参数是否通过post方法提交
+     * 
+ */ + public static final String REQUIRE_POST_METHOD = "REQUIRE_POST_METHOD"; + /** + *
+     * 描述:签名错误.
+     * 原因:参数签名结果不正确
+     * 解决方案:请检查签名参数和方法是否都符合签名算法要求
+     * 
+ */ + public static final String SIGNERROR = "SIGNERROR"; + /** + *
+     * 描述:XML格式错误.
+     * 原因:XML格式错误
+     * 解决方案:请检查XML参数格式是否正确
+     * 
+ */ + public static final String XML_FORMAT_ERROR = "XML_FORMAT_ERROR"; + /** + *
+     * 描述:频率限制.
+     * 原因:2个月之前的订单申请退款有频率限制
+     * 解决方案:该笔退款未受理,请降低频率后重试
+     * 
+ */ + public static final String FREQUENCY_LIMITED = "FREQUENCY_LIMITED"; + } + + /** + * 退款查询. + * https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_4&index=7 + */ + public static class RefundQuery { + /** + *
+     * 描述:接口返回错误.
+     * 原因:系统超时
+     * 解决方案:请尝试再次掉调用API。
+     * 
+ */ + public static final String SYSTEMERROR = "SYSTEMERROR"; + + /** + *
+     * 描述:退款订单查询失败.
+     * 原因:订单号错误或订单状态不正确
+     * 解决方案:请检查订单号是否有误以及订单状态是否正确,如:未支付、已支付未退款
+     * 
+ */ + public static final String REFUNDNOTEXIST = "REFUNDNOTEXIST"; + + /** + *
+     * 描述:无效transaction_id.
+     * 原因:请求参数未按指引进行填写
+     * 解决方案:请求参数错误,检查原交易号是否存在或发起支付交易接口返回失败
+     * 
+ */ + public static final String INVALID_TRANSACTIONID = "INVALID_TRANSACTIONID"; + + /** + *
+     * 描述:参数错误.
+     * 原因:请求参数未按指引进行填写
+     * 解决方案:请求参数错误,请检查参数再调用退款申请
+     * 
+ */ + public static final String PARAM_ERROR = "PARAM_ERROR"; + + /** + *
+     * 描述:APPID不存在.
+     * 原因:参数中缺少APPID
+     * 解决方案:请检查APPID是否正确
+     * 
+ */ + public static final String APPID_NOT_EXIST = "APPID_NOT_EXIST"; + + /** + *
+     * 描述:MCHID不存在.
+     * 原因:参数中缺少MCHID
+     * 解决方案:请检查MCHID是否正确
+     * 
+ */ + public static final String MCHID_NOT_EXIST = "MCHID_NOT_EXIST"; + + /** + *
+     * 描述:请使用post方法.
+     * 原因:未使用post传递参数
+     * 解决方案:请检查请求参数是否通过post方法提交
+     * 
+ */ + public static final String REQUIRE_POST_METHOD = "REQUIRE_POST_METHOD"; + + /** + *
+     * 描述:签名错误.
+     * 原因:参数签名结果不正确
+     * 解决方案:请检查签名参数和方法是否都符合签名算法要求
+     * 
+ */ + public static final String SIGNERROR = "SIGNERROR"; + + /** + *
+     * 描述:XML格式错误.
+     * 原因:XML格式错误
+     * 解决方案:请检查XML参数格式是否正确
+     * 
+ */ + public static final String XML_FORMAT_ERROR = "XML_FORMAT_ERROR"; + } + + /** + * 下载对账单. + * https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_4&index=8 + */ + public static class DownloadBill { + /** + *
+     * 描述:下载失败.
+     * 原因:系统超时
+     * 解决方案:请尝试再次查询。
+     * 
+ */ + public static final String SYSTEMERROR = "SYSTEMERROR"; + + /** + *
+     * 描述:参数错误.
+     * 原因:请求参数未按指引进行填写
+     * 解决方案:参数错误,请重新检查
+     * 
+ */ + public static final String INVALID_BILL_TYPE = "invalid bill_type"; + + /** + *
+     * 描述:参数错误.
+     * 原因:请求参数未按指引进行填写
+     * 解决方案:参数错误,请重新检查
+     * 
+ */ + public static final String DATA_FORMAT_ERROR = "data format error"; + + /** + *
+     * 描述:参数错误.
+     * 原因:请求参数未按指引进行填写
+     * 解决方案:参数错误,请重新检查
+     * 
+ */ + public static final String MISSING_PARAMETER = "missing parameter"; + + /** + *
+     * 描述:参数错误.
+     * 原因:请求参数未按指引进行填写
+     * 解决方案:参数错误,请重新检查
+     * 
+ */ + public static final String SIGN_ERROR = "SIGN ERROR"; + + /** + *
+     * 描述:账单不存在.
+     * 原因:当前商户号没有已成交的订单,不生成对账单
+     * 解决方案:请检查当前商户号在指定日期内是否有成功的交易。
+     * 
+ */ + public static final String NO_Bill_Exist = "NO Bill Exist"; + + /** + *
+     * 描述:账单未生成.
+     * 原因:当前商户号没有已成交的订单或对账单尚未生成
+     * 解决方案:请先检查当前商户号在指定日期内是否有成功的交易,如指定日期有交易则表示账单正在生成中,请在上午10点以后再下载。
+     * 
+ */ + public static final String BILL_CREATING = "Bill Creating"; + + /** + *
+     * 描述:账单压缩失败.
+     * 原因:账单压缩失败,请稍后重试
+     * 解决方案:账单压缩失败,请稍后重试
+     * 
+ */ + public static final String COMPRESSG_ZIP_ERROR = "CompressGZip Error"; + + /** + *
+     * 描述:账单解压失败.
+     * 原因:账单解压失败,请稍后重试
+     * 解决方案:账单解压失败,请稍后重试
+     * 
+ */ + public static final String UN_COMPRESSG_ZIP_ERROR = "UnCompressGZip Error"; + + + } +} 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 7e2dff7b..e8bb1079 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 @@ -388,6 +388,47 @@ public interface WxPayService { */ void report(WxPayReportRequest request) throws WxPayException; + /** + *
+   * 下载对账单.
+   * 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。
+   * 注意:
+   * 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中,跟原支付单订单号一致,bill_type为REVOKED;
+   * 2、微信在次日9点启动生成前一天的对账单,建议商户10点后再获取;
+   * 3、对账单中涉及金额的字段单位为“元”。
+   * 4、对账单接口只能下载三个月以内的账单。
+   * 接口链接:https://api.mch.weixin.qq.com/pay/downloadbill
+   * 详情请见: 下载对账单
+   * 
+ * + * @param billDate 对账单日期 bill_date 下载对账单的日期,格式:20140603 + * @param billType 账单类型 bill_type ALL,返回当日所有订单信息,默认值,SUCCESS,返回当日成功支付的订单,REFUND,返回当日退款订单 + * @param tarType 压缩账单 tar_type 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。 + * @param deviceInfo 设备号 device_info 非必传参数,终端设备号 + * @return 对账内容原始字符串 + * @throws WxPayException the wx pay exception + */ + String downloadRawBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException; + + /** + *
+   * 下载对账单(适合于需要自定义子商户号和子商户appid的情形).
+   * 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。
+   * 注意:
+   * 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中,跟原支付单订单号一致,bill_type为REVOKED;
+   * 2、微信在次日9点启动生成前一天的对账单,建议商户10点后再获取;
+   * 3、对账单中涉及金额的字段单位为“元”。
+   * 4、对账单接口只能下载三个月以内的账单。
+   * 接口链接:https://api.mch.weixin.qq.com/pay/downloadbill
+   * 详情请见: 下载对账单
+   * 
+ * + * @param request 下载对账单请求 + * @return 对账内容原始字符串 + * @throws WxPayException the wx pay exception + */ + String downloadRawBill(WxPayDownloadBillRequest request) throws WxPayException; + /** *
    * 下载对账单.
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
index 591b4a24..ec57e745 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
@@ -49,7 +49,6 @@ import com.github.binarywang.wxpay.bean.request.WxPayShorturlRequest;
 import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
 import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
 import com.github.binarywang.wxpay.bean.result.WxPayAuthcode2OpenidResult;
-import com.github.binarywang.wxpay.bean.result.WxPayBillBaseResult;
 import com.github.binarywang.wxpay.bean.result.WxPayBillResult;
 import com.github.binarywang.wxpay.bean.result.WxPayCommonResult;
 import com.github.binarywang.wxpay.bean.result.WxPayFundFlowBaseResult;
@@ -90,14 +89,16 @@ import static com.github.binarywang.wxpay.constant.WxPayConstants.TarType;
  */
 public abstract class BaseWxPayServiceImpl implements WxPayService {
   private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com";
+  private static final String TOTAL_FUND_COUNT = "资金流水总笔数";
+
   /**
    * The Log.
    */
-  protected final Logger log = LoggerFactory.getLogger(this.getClass());
+  final Logger log = LoggerFactory.getLogger(this.getClass());
   /**
    * The constant wxApiData.
    */
-  protected static ThreadLocal wxApiData = new ThreadLocal<>();
+  static ThreadLocal wxApiData = new ThreadLocal<>();
 
   private EntPayService entPayService = new EntPayServiceImpl(this);
 
@@ -141,8 +142,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
 
     String url = this.getPayBaseUrl() + "/secapi/pay/refund";
     String responseContent = this.post(url, request.toXML(), true);
-    WxPayRefundResult result = BaseWxPayResult.fromXML(responseContent, WxPayRefundResult.class);
-    result.composeRefundCoupons();
+    WxPayRefundResult result = WxPayRefundResult.fromXML(responseContent);
     result.checkResult(this, request.getSignType(), true);
     return result;
   }
@@ -342,7 +342,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
         configMap.put("appid", appId);
 
         final WxPayAppOrderResult result = WxPayAppOrderResult.builder()
-          .sign(SignUtils.createSign(configMap, null, this.getConfig().getMchKey(), null))
+          .sign(SignUtils.createSign(configMap, request.getSignType(), this.getConfig().getMchKey(), null))
           .prepayId(prepayId)
           .partnerId(partnerId)
           .appId(appId)
@@ -419,7 +419,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
       configMap.put("noncestr", nonceStr);
       configMap.put("appid", appId);
       // 此map用于客户端与微信服务器交互
-      payInfo.put("sign", SignUtils.createSign(configMap, null, this.getConfig().getMchKey(), null));
+      payInfo.put("sign", SignUtils.createSign(configMap, request.getSignType(), this.getConfig().getMchKey(), null));
       payInfo.put("prepayId", prepayId);
       payInfo.put("partnerId", partnerId);
       payInfo.put("appId", appId);
@@ -432,8 +432,8 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
       payInfo.put("timeStamp", timestamp);
       payInfo.put("nonceStr", nonceStr);
       payInfo.put("package", "prepay_id=" + prepayId);
-      payInfo.put("signType", SignType.MD5);
-      payInfo.put("paySign", SignUtils.createSign(payInfo, null, this.getConfig().getMchKey(), null));
+      payInfo.put("signType", request.getSignType());
+      payInfo.put("paySign", SignUtils.createSign(payInfo, request.getSignType(), this.getConfig().getMchKey(), null));
     }
 
     return payInfo;
@@ -457,7 +457,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
     params.put("time_stamp", String.valueOf(System.currentTimeMillis() / 1000));
     params.put("nonce_str", String.valueOf(System.currentTimeMillis()));
 
-    String sign = SignUtils.createSign(params, null, this.getConfig().getMchKey(), null);
+    String sign = SignUtils.createSign(params, SignType.MD5, this.getConfig().getMchKey(), null);
     params.put("sign", sign);
 
     for (String key : params.keySet()) {
@@ -493,22 +493,40 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   }
 
   @Override
-  public WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException {
-    if (!BillType.ALL.equals(billType)) {
-      throw new WxPayException("目前仅支持ALL类型的对账单下载");
-    }
+  public String downloadRawBill(String billDate, String billType, String tarType, String deviceInfo)
+    throws WxPayException {
+    return this.downloadRawBill(this.buildDownloadBillRequest(billDate, billType, tarType, deviceInfo));
+  }
+
+  @Override
+  public WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo)
+    throws WxPayException {
+    return this.downloadBill(this.buildDownloadBillRequest(billDate, billType, tarType, deviceInfo));
+  }
 
+  private WxPayDownloadBillRequest buildDownloadBillRequest(String billDate, String billType, String tarType,
+                                                            String deviceInfo) {
     WxPayDownloadBillRequest request = new WxPayDownloadBillRequest();
     request.setBillType(billType);
     request.setBillDate(billDate);
     request.setTarType(tarType);
     request.setDeviceInfo(deviceInfo);
-
-    return this.downloadBill(request);
+    return request;
   }
 
   @Override
   public WxPayBillResult downloadBill(WxPayDownloadBillRequest request) throws WxPayException {
+    String responseContent = this.downloadRawBill(request);
+
+    if (StringUtils.isEmpty(responseContent)) {
+      return null;
+    }
+
+    return this.handleBill(request.getBillType(), responseContent);
+  }
+
+  @Override
+  public String downloadRawBill(WxPayDownloadBillRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
 
     String url = this.getPayBaseUrl() + "/pay/downloadbill";
@@ -522,19 +540,14 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
         throw WxPayException.from(BaseWxPayResult.fromXML(responseContent, WxPayCommonResult.class));
       }
     }
-
-    return this.handleBill(request.getBillType(), responseContent);
+    return responseContent;
   }
 
   private WxPayBillResult handleBill(String billType, String responseContent) {
-    if (!BillType.ALL.equals(billType)) {
-      return null;
-    }
-
-    return this.handleAllBill(responseContent);
+    return WxPayBillResult.fromRawBillResultString(responseContent, billType);
   }
 
-  private String handleGzipBill(String url, String requestStr) throws WxPayException {
+  private String handleGzipBill(String url, String requestStr) {
     try {
       byte[] responseBytes = this.postForBytes(url, requestStr, false);
       Path tempDirectory = Files.createTempDirectory("bill");
@@ -558,80 +571,6 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
     return null;
   }
 
-  private WxPayBillResult handleAllBill(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].trim());
-      wxPayBillBaseResult.setAppId(tempStr[k + 1].trim());
-      wxPayBillBaseResult.setMchId(tempStr[k + 2].trim());
-      wxPayBillBaseResult.setSubMchId(tempStr[k + 3].trim());
-      wxPayBillBaseResult.setDeviceInfo(tempStr[k + 4].trim());
-      wxPayBillBaseResult.setTransactionId(tempStr[k + 5].trim());
-      wxPayBillBaseResult.setOutTradeNo(tempStr[k + 6].trim());
-      wxPayBillBaseResult.setOpenId(tempStr[k + 7].trim());
-      wxPayBillBaseResult.setTradeType(tempStr[k + 8].trim());
-      wxPayBillBaseResult.setTradeState(tempStr[k + 9].trim());
-      wxPayBillBaseResult.setBankType(tempStr[k + 10].trim());
-      wxPayBillBaseResult.setFeeType(tempStr[k + 11].trim());
-      wxPayBillBaseResult.setTotalFee(tempStr[k + 12].trim());
-      wxPayBillBaseResult.setCouponFee(tempStr[k + 13].trim());
-      wxPayBillBaseResult.setRefundId(tempStr[k + 14].trim());
-      wxPayBillBaseResult.setOutRefundNo(tempStr[k + 15].trim());
-      wxPayBillBaseResult.setSettlementRefundFee(tempStr[k + 16].trim());
-      wxPayBillBaseResult.setCouponRefundFee(tempStr[k + 17].trim());
-      wxPayBillBaseResult.setRefundChannel(tempStr[k + 18].trim());
-      wxPayBillBaseResult.setRefundState(tempStr[k + 19].trim());
-      wxPayBillBaseResult.setBody(tempStr[k + 20].trim());
-      wxPayBillBaseResult.setAttach(tempStr[k + 21].trim());
-      wxPayBillBaseResult.setPoundage(tempStr[k + 22].trim());
-      wxPayBillBaseResult.setPoundageRate(tempStr[k + 23].trim());
-      wxPayBillBaseResultLst.add(wxPayBillBaseResult);
-      k += t.length;
-    }
-    wxPayBillResult.setWxPayBillBaseResultLst(wxPayBillBaseResultLst);
-
-    /*
-     * 总交易单数,总交易额,总退款金额,总代金券或立减优惠退款金额,手续费总金额 `2,`0.02,`0.0,`0.0,`0
-     * 参考以上格式进行取值
-     */
-    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 WxPayFundFlowResult downloadFundFlow(String billDate, String accountType, String tarType) throws WxPayException {
 
@@ -695,9 +634,9 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
     String listStr = "";
     String objStr = "";
 
-    if (StringUtils.isNotBlank(responseContent) && responseContent.contains("资金流水总笔数")) {
-      listStr = responseContent.substring(0, responseContent.indexOf("资金流水总笔数"));
-      objStr = responseContent.substring(responseContent.indexOf("资金流水总笔数"));
+    if (StringUtils.isNotBlank(responseContent) && responseContent.contains(TOTAL_FUND_COUNT)) {
+      listStr = responseContent.substring(0, responseContent.indexOf(TOTAL_FUND_COUNT));
+      objStr = responseContent.substring(responseContent.indexOf(TOTAL_FUND_COUNT));
     }
     /*
      * 记账时间:2018-02-01 04:21:23 微信支付业务单号:50000305742018020103387128253 资金流水单号:1900009231201802015884652186 业务名称:退款
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java
index 5be2113b..d694f42e 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java
@@ -3,6 +3,7 @@ package com.github.binarywang.wxpay.service.impl;
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.security.PublicKey;
@@ -126,7 +127,7 @@ public class EntPayServiceImpl implements EntPayService {
           .getPublicKey((SubjectPublicKeyInfo) reader.readObject());
 
         cipher.init(Cipher.ENCRYPT_MODE, publicKey);
-        byte[] encrypt = cipher.doFinal(srcString.getBytes());
+        byte[] encrypt = cipher.doFinal(srcString.getBytes(StandardCharsets.UTF_8));
         return Base64.encodeBase64String(encrypt);
       }
     } catch (Exception e) {
@@ -138,7 +139,7 @@ public class EntPayServiceImpl implements EntPayService {
     try {
       String publicKeyStr = this.getPublicKey();
       Path tmpFile = Files.createTempFile("payToBank", ".pem");
-      Files.write(tmpFile, publicKeyStr.getBytes());
+      Files.write(tmpFile, publicKeyStr.getBytes(StandardCharsets.UTF_8));
       return tmpFile.toFile();
     } catch (Exception e) {
       throw new WxPayException("生成加密公钥文件时发生异常", e);
@@ -162,7 +163,7 @@ public class EntPayServiceImpl implements EntPayService {
       "p7kM7BoaY2goFgYAe4DsI8Fh33dCOiKyVwIDAQAB\n" +
       "-----END RSA PUBLIC KEY-----";
     Path tmpFile = Files.createTempFile("payToBank", ".pem");
-    Files.write(tmpFile, key.getBytes());
+    Files.write(tmpFile, key.getBytes(StandardCharsets.UTF_8));
     System.out.println(new EntPayServiceImpl(null).encryptRSA(tmpFile.toFile(), "111111"));
   }
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
index 753652f4..df9a82fb 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
@@ -1,8 +1,9 @@
 package com.github.binarywang.wxpay.service.impl;
 
-import com.github.binarywang.wxpay.bean.WxPayApiData;
-import com.github.binarywang.wxpay.exception.WxPayException;
-import jodd.util.Base64;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import javax.net.ssl.SSLContext;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpHost;
 import org.apache.http.auth.AuthScope;
@@ -20,9 +21,9 @@ import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
 
-import javax.net.ssl.SSLContext;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.StandardCharsets;
+import com.github.binarywang.wxpay.bean.WxPayApiData;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import jodd.util.Base64;
 
 /**
  * 
@@ -65,7 +66,9 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
         try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
           String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
           this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, responseString);
-          wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
+          if (this.getConfig().isIfSaveApiData()) {
+            wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
+          }
           return responseString;
         }
       } finally {
@@ -73,7 +76,9 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
       }
     } catch (Exception e) {
       this.log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage());
-      wxApiData.set(new WxPayApiData(url, requestStr, null, e.getMessage()));
+      if (this.getConfig().isIfSaveApiData()) {
+        wxApiData.set(new WxPayApiData(url, requestStr, null, e.getMessage()));
+      }
       throw new WxPayException(e.getMessage(), e);
     }
   }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
index 1c7b315d..a5988099 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
@@ -30,7 +30,9 @@ public class WxPayServiceJoddHttpImpl extends BaseWxPayServiceImpl {
       byte[] responseBytes = request.send().bodyBytes();
       final String responseString = Base64.encodeToString(responseBytes);
       this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据(Base64编码后)】:{}", url, requestStr, responseString);
-      wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
+      if (this.getConfig().isIfSaveApiData()) {
+        wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
+      }
       return responseBytes;
     } catch (Exception e) {
       this.log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage());
@@ -46,7 +48,9 @@ public class WxPayServiceJoddHttpImpl extends BaseWxPayServiceImpl {
       String responseString = this.getResponseString(request.send());
 
       this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, responseString);
-      wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
+      if (this.getConfig().isIfSaveApiData()) {
+        wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
+      }
       return responseString;
     } catch (Exception e) {
       this.log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage());
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 2883c8b1..47129872 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
@@ -52,7 +52,7 @@ public class SignUtils {
    */
   @Deprecated
   public static String createSign(Map params, String signKey) {
-    return createSign(params, null, signKey, new String[0]);
+    return createSign(params, SignType.MD5, signKey, new String[0]);
   }
 
   /**
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
index 4b99b769..ba7ed545 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
@@ -1,19 +1,20 @@
 package com.github.binarywang.wxpay.bean.notify;
 
-import com.github.binarywang.wxpay.config.WxPayConfig;
-import com.github.binarywang.wxpay.exception.WxPayException;
-import com.github.binarywang.wxpay.testbase.ApiTestModule;
-import org.apache.commons.codec.binary.Base64;
-import org.testng.annotations.Guice;
-import org.testng.annotations.Test;
-
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
 import javax.crypto.Cipher;
 import javax.crypto.spec.SecretKeySpec;
 import javax.inject.Inject;
-import java.math.BigInteger;
-import java.security.MessageDigest;
 
-import static org.testng.Assert.assertNotNull;
+import org.apache.commons.codec.binary.Base64;
+import org.testng.annotations.*;
+
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.testbase.ApiTestModule;
+
+import static org.testng.Assert.*;
 
 /**
  * 
@@ -71,10 +72,10 @@ public class WxPayRefundNotifyResultTest {
 
     Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
     final MessageDigest md5 = MessageDigest.getInstance("MD5");
-    md5.update(this.wxPayConfig.getMchKey().getBytes());
+    md5.update(this.wxPayConfig.getMchKey().getBytes(StandardCharsets.UTF_8));
     final String keyMd5String = new BigInteger(1, md5.digest()).toString(16).toLowerCase();
-    SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(), "AES");
+    SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(StandardCharsets.UTF_8), "AES");
     cipher.init(Cipher.ENCRYPT_MODE, key);
-    System.out.println(Base64.encodeBase64String(cipher.doFinal(xml.getBytes())));
+    System.out.println(Base64.encodeBase64String(cipher.doFinal(xml.getBytes(StandardCharsets.UTF_8))));
   }
 }
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResultTest.java
index f4f87f40..730bd37a 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResultTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayRefundResultTest.java
@@ -13,11 +13,8 @@ import static org.assertj.core.api.Assertions.assertThat;
  */
 public class WxPayRefundResultTest {
 
-  /**
-   * Test compose refund coupons.
-   */
   @Test
-  public void testComposeRefundCoupons() {
+  public void testFromXML() {
     /*
       该xml字符串来自于官方文档示例,稍加改造,加上代金卷
       refund_channel 是个什么鬼,官方文档只字不提
@@ -43,8 +40,7 @@ public class WxPayRefundResultTest {
       "   2 \n" +
       "";
 
-    WxPayRefundResult result = WxPayRefundResult.fromXML(xmlString, WxPayRefundResult.class);
-    result.composeRefundCoupons();
+    WxPayRefundResult result = WxPayRefundResult.fromXML(xmlString);
 
     assertThat(result.getRefundCoupons()).isNotEmpty();
     assertThat(result.getRefundCoupons().get(0).getCouponRefundId()).isEqualTo("123");