| @@ -53,3 +53,6 @@ sonar-project.properties | |||||
| !/.mvn/wrapper/maven-wrapper.jar | !/.mvn/wrapper/maven-wrapper.jar | ||||
| *.versionsBackup | *.versionsBackup | ||||
| # STS | |||||
| .factorypath | |||||
| @@ -8,10 +8,10 @@ | |||||
| - (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。 | - (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。 | ||||
| ### PR方式贡献代码步骤 | ### PR方式贡献代码步骤 | ||||
| * 在 GitHub 上 `fork` 到自己的仓库,如 `my_user/weixin-java-tools`,然后 `clone` 到本地,并设置用户信息。 | |||||
| * 在 GitHub 上 `fork` 到自己的仓库,如 `my_user/WxJava`,然后 `clone` 到本地,并设置用户信息。 | |||||
| ```bash | ```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 | $ cd weixin-java-tools | ||||
| $ git config user.name "yourname" | $ git config user.name "yourname" | ||||
| $ git config user.email "your email" | $ git config user.email "your email" | ||||
| @@ -27,7 +27,7 @@ $ git push | |||||
| * 定期使用项目仓库内容更新自己仓库内容。 | * 定期使用项目仓库内容更新自己仓库内容。 | ||||
| ```bash | ```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 fetch upstream | ||||
| $ git checkout develop | $ git checkout develop | ||||
| $ git rebase upstream/develop | $ git rebase upstream/develop | ||||
| @@ -5,12 +5,12 @@ | |||||
| xmlns="http://maven.apache.org/POM/4.0.0"> | xmlns="http://maven.apache.org/POM/4.0.0"> | ||||
| <modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
| <groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
| <artifactId>weixin-java-parent</artifactId> | |||||
| <version>3.2.0</version> | |||||
| <artifactId>wx-java</artifactId> | |||||
| <version>3.3.0</version> | |||||
| <packaging>pom</packaging> | <packaging>pom</packaging> | ||||
| <name>Weixin Java Tools - Parent</name> | |||||
| <name>WxJava - Weixin/Wechat Java SDK</name> | |||||
| <description>微信开发Java SDK</description> | <description>微信开发Java SDK</description> | ||||
| <url>https://github.com/wechat-group/weixin-java-tools</url> | |||||
| <url>https://github.com/Wechat-Group/WxJava</url> | |||||
| <licenses> | <licenses> | ||||
| <license> | <license> | ||||
| @@ -85,6 +85,11 @@ | |||||
| <email>007gzs@gmail.com</email> | <email>007gzs@gmail.com</email> | ||||
| <url>https://github.com/007gzs</url> | <url>https://github.com/007gzs</url> | ||||
| </developer> | </developer> | ||||
| <developer> | |||||
| <name>Howard Liu</name> | |||||
| <email>liuxinghao1988@gmail.com</email> | |||||
| <url>https://github.com/howardliu-cn</url> | |||||
| </developer> | |||||
| </developers> | </developers> | ||||
| <scm> | <scm> | ||||
| @@ -166,7 +171,7 @@ | |||||
| <dependency> | <dependency> | ||||
| <groupId>com.thoughtworks.xstream</groupId> | <groupId>com.thoughtworks.xstream</groupId> | ||||
| <artifactId>xstream</artifactId> | <artifactId>xstream</artifactId> | ||||
| <version>1.4.9</version> | |||||
| <version>1.4.10</version> | |||||
| </dependency> | </dependency> | ||||
| <!-- 由于guava较新的21.0版本需要jdk8,故而此处采用较低版本 --> | <!-- 由于guava较新的21.0版本需要jdk8,故而此处采用较低版本 --> | ||||
| <dependency> | <dependency> | ||||
| @@ -140,14 +140,6 @@ | |||||
| </module> | </module> | ||||
| <module name="OverloadMethodsDeclarationOrder"/> | <module name="OverloadMethodsDeclarationOrder"/> | ||||
| <module name="VariableDeclarationUsageDistance"/> | <module name="VariableDeclarationUsageDistance"/> | ||||
| <module name="CustomImportOrder"> | |||||
| <property name="customImportOrderRules" | |||||
| value="SPECIAL_IMPORTS###STANDARD_JAVA_PACKAGE###THIRD_PARTY_PACKAGE###STATIC"/> | |||||
| <property name="specialImportsRegExp" value="^javax\."/> | |||||
| <property name="standardPackageRegExp" value="^java\."/> | |||||
| <property name="sortImportsInGroupAlphabetically" value="true"/> | |||||
| <property name="separateLineBetweenGroups" value="false"/> | |||||
| </module> | |||||
| <module name="MethodParamPad"/> | <module name="MethodParamPad"/> | ||||
| <module name="ParenPad"/> | <module name="ParenPad"/> | ||||
| <module name="OperatorWrap"> | <module name="OperatorWrap"> | ||||
| @@ -3,9 +3,9 @@ | |||||
| [](https://gitee.com/binary/weixin-java-tools) | [](https://gitee.com/binary/weixin-java-tools) | ||||
| [](https://github.com/Wechat-Group/WxJava) | [](https://github.com/Wechat-Group/WxJava) | ||||
| [](https://github.com/Wechat-Group/WxJava/releases) | [](https://github.com/Wechat-Group/WxJava/releases) | ||||
| [](http://mvnrepository.com/artifact/com.github.binarywang/weixin-java-parent) | |||||
| [](http://mvnrepository.com/artifact/com.github.binarywang/wx-java) | |||||
| [](https://travis-ci.org/Wechat-Group/WxJava) | [](https://travis-ci.org/Wechat-Group/WxJava) | ||||
| [](https://www.jetbrains.com/?from=weixin-java-tools) | |||||
| [](https://www.jetbrains.com/?from=WxJava-weixin-java-tools) | |||||
| [](https://opensource.org/licenses/Apache-2.0) | [](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)的常见问题部分,可以少走很多弯路,节省不少时间。 | 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. [qsjia (QSJia)](http://github.com/qsjia) | ||||
| 1. [webcreazy (webcreazy)](http://github.com/webcreazy) | 1. [webcreazy (webcreazy)](http://github.com/webcreazy) | ||||
| 1. [cwivan (鱼丸Cwivan)](http://github.com/cwivan) | 1. [cwivan (鱼丸Cwivan)](http://github.com/cwivan) | ||||
| 1. [howardliu-cn (看山)](https://github.com/howardliu-cn) | |||||
| @@ -6,12 +6,12 @@ | |||||
| <modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
| <parent> | <parent> | ||||
| <groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
| <artifactId>weixin-java-parent</artifactId> | |||||
| <version>3.2.0</version> | |||||
| <artifactId>wx-java</artifactId> | |||||
| <version>3.3.0</version> | |||||
| </parent> | </parent> | ||||
| <artifactId>weixin-java-common</artifactId> | <artifactId>weixin-java-common</artifactId> | ||||
| <name>Weixin Java Tools - Common</name> | |||||
| <name>WxJava - Common</name> | |||||
| <description>微信开发Java SDK公共模块</description> | <description>微信开发Java SDK公共模块</description> | ||||
| <dependencies> | <dependencies> | ||||
| @@ -114,6 +114,11 @@ | |||||
| <artifactId>assertj-guava</artifactId> | <artifactId>assertj-guava</artifactId> | ||||
| <scope>test</scope> | <scope>test</scope> | ||||
| </dependency> | </dependency> | ||||
| <dependency> | |||||
| <groupId>org.dom4j</groupId> | |||||
| <artifactId>dom4j</artifactId> | |||||
| <version>2.0.0</version> | |||||
| </dependency> | |||||
| </dependencies> | </dependencies> | ||||
| <build> | <build> | ||||
| @@ -250,6 +250,15 @@ public class WxConsts { | |||||
| */ | */ | ||||
| public static final String CARD_PAY_ORDER = "card_pay_order"; | 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"; | |||||
| } | } | ||||
| @@ -76,7 +76,7 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec | |||||
| } | } | ||||
| } | } | ||||
| } catch (InterruptedException e) { | } catch (InterruptedException e) { | ||||
| e.printStackTrace(); | |||||
| Thread.currentThread().interrupt(); | |||||
| } | } | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -2,10 +2,8 @@ package me.chanjar.weixin.common.bean; | |||||
| import java.io.Serializable; | import java.io.Serializable; | ||||
| import org.apache.commons.lang3.builder.ToStringBuilder; | |||||
| import org.apache.commons.lang3.builder.ToStringStyle; | |||||
| import lombok.Data; | import lombok.Data; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
| /** | /** | ||||
| * 卡券Api签名. | * 卡券Api签名. | ||||
| @@ -37,6 +35,6 @@ public class WxCardApiSignature implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return WxGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| } | } | ||||
| @@ -7,9 +7,6 @@ import java.nio.charset.StandardCharsets; | |||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||
| import java.util.List; | import java.util.List; | ||||
| import org.apache.commons.lang3.builder.ToStringBuilder; | |||||
| import org.apache.commons.lang3.builder.ToStringStyle; | |||||
| import lombok.Data; | import lombok.Data; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
| @@ -49,7 +46,7 @@ public class WxMenu implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return this.toJson(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -4,11 +4,9 @@ import java.io.Serializable; | |||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||
| import java.util.List; | 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 com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | import lombok.Data; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
| /** | /** | ||||
| * menu button. | * menu button. | ||||
| @@ -83,7 +81,7 @@ public class WxMenuButton implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return WxGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| } | } | ||||
| @@ -2,11 +2,9 @@ package me.chanjar.weixin.common.bean.menu; | |||||
| import java.io.Serializable; | 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 com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | import lombok.Data; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
| /** | /** | ||||
| * menu rule. | * menu rule. | ||||
| @@ -31,6 +29,6 @@ public class WxMenuRule implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return WxGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| } | } | ||||
| @@ -2,9 +2,6 @@ package me.chanjar.weixin.common.bean.result; | |||||
| import java.io.Serializable; | import java.io.Serializable; | ||||
| import org.apache.commons.lang3.builder.ToStringBuilder; | |||||
| import org.apache.commons.lang3.builder.ToStringStyle; | |||||
| import lombok.Data; | import lombok.Data; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
| @@ -28,7 +25,7 @@ public class WxMediaUploadResult implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return WxGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| } | } | ||||
| @@ -794,8 +794,7 @@ public enum WxCpErrorMsgEnum { | |||||
| * 通过错误代码查找其中文含义. | * 通过错误代码查找其中文含义. | ||||
| */ | */ | ||||
| public static String findMsgByCode(int code) { | public static String findMsgByCode(int code) { | ||||
| WxCpErrorMsgEnum[] values = WxCpErrorMsgEnum.values(); | |||||
| for (WxCpErrorMsgEnum value : values) { | |||||
| for (WxCpErrorMsgEnum value : WxCpErrorMsgEnum.values()) { | |||||
| if (value.code == code) { | if (value.code == code) { | ||||
| return value.msg; | return value.msg; | ||||
| } | } | ||||
| @@ -64,6 +64,11 @@ public class WxError implements Serializable { | |||||
| if (msg != null) { | if (msg != null) { | ||||
| wxError.setErrorMsg(msg); | wxError.setErrorMsg(msg); | ||||
| } | } | ||||
| } else if (type == WxType.MiniApp) { | |||||
| final String msg = WxMaErrorMsgEnum.findMsgByCode(wxError.getErrorCode()); | |||||
| if (msg != null) { | |||||
| wxError.setErrorMsg(msg); | |||||
| } | |||||
| } | } | ||||
| return wxError; | return wxError; | ||||
| @@ -0,0 +1,253 @@ | |||||
| package me.chanjar.weixin.common.error; | |||||
| import lombok.Getter; | |||||
| /** | |||||
| * 微信小程序错误码 | |||||
| * | |||||
| * @author <a href="https://github.com/biggates">biggates</a> | |||||
| */ | |||||
| @Getter | |||||
| public enum WxMaErrorMsgEnum { | |||||
| /** | |||||
| * <pre> | |||||
| * 获取 access_token 时 AppSecret 错误, | |||||
| * 或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的小程序调用接口 | |||||
| * 对应操作:<code>sendCustomerMessage</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_40001(40001, "access_token 无效或 AppSecret 错误"), | |||||
| /** | |||||
| * <pre> | |||||
| * 不合法的凭证类型 | |||||
| * 对应操作:<code>sendCustomerMessage</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_40002(40002, "不合法的凭证类型"), | |||||
| /** | |||||
| * <pre> | |||||
| * touser不是正确的openid. | |||||
| * 对应操作:<code>sendCustomerMessage</code>, <code>sendUniformMessage</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_40003(40003, "openid 不正确"), | |||||
| /** | |||||
| * <pre> | |||||
| * 无效媒体文件类型 | |||||
| * 对应操作:<code>uploadTempMedia</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_40004(40004, "无效媒体文件类型"), | |||||
| /** | |||||
| * <pre> | |||||
| * 无效媒体文件 ID. | |||||
| * 对应操作:<code>getTempMedia</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_40007(40007, "无效媒体文件 ID"), | |||||
| /** | |||||
| * <pre> | |||||
| * appid不正确,或者不符合绑定关系要求. | |||||
| * 对应操作:<code>sendUniformMessage</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_40013(40013, "appid不正确,或者不符合绑定关系要求"), | |||||
| /** | |||||
| * <pre> | |||||
| * template_id 不正确. | |||||
| * 对应操作:<code>sendUniformMessage</code>, <code>sendTemplateMessage</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/uniform-message/sendUniformMessage.html | |||||
| * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html | |||||
| * </pre> | |||||
| */ | |||||
| CODE_40037(40037, "template_id 不正确"), | |||||
| /** | |||||
| * <pre> | |||||
| * form_id不正确,或者过期. | |||||
| * 对应操作:<code>sendUniformMessage</code>, <code>sendTemplateMessage</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/uniform-message/sendUniformMessage.html | |||||
| * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html | |||||
| * </pre> | |||||
| */ | |||||
| CODE_41028(41028, "form_id 不正确,或者过期"), | |||||
| /** | |||||
| * <pre> | |||||
| * code 或 template_id 不正确. | |||||
| * 对应操作:<code>code2Session</code>, <code>sendUniformMessage</code>, <code>sendTemplateMessage</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_41029(41029, "请求的参数不正确"), | |||||
| /** | |||||
| * <pre> | |||||
| * form_id 已被使用,或者所传page页面不存在,或者小程序没有发布 | |||||
| * 对应操作:<code>sendUniformMessage</coce>, <code>getWXACodeUnlimit</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_41030(41030, "请求的参数不正确"), | |||||
| /** | |||||
| * <pre> | |||||
| * 调用分钟频率受限. | |||||
| * 对应操作:<code>getWXACodeUnlimit</code>, <code>sendUniformMessage</code>, <code>sendTemplateMessage</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_45009(45009, "调用分钟频率受限"), | |||||
| /** | |||||
| * <pre> | |||||
| * 频率限制,每个用户每分钟100次. | |||||
| * 对应操作:<code>code2Session</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_45011(45011, "频率限制,每个用户每分钟100次"), | |||||
| /** | |||||
| * <pre> | |||||
| * 回复时间超过限制. | |||||
| * 对应操作:<code>sendCustomerMessage</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_45015(45015, "回复时间超过限制"), | |||||
| /** | |||||
| * <pre> | |||||
| * 接口调用超过限额, 或生成码个数总和到达最大个数限制. | |||||
| * 对应操作:<code>createWXAQRCode</code>, <code>sendTemplateMessage</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_45029(45029, "接口调用超过限额"), | |||||
| /** | |||||
| * <pre> | |||||
| * 客服接口下行条数超过上限. | |||||
| * 对应操作:<code>sendCustomerMessage</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_45047(45047, "客服接口下行条数超过上限"), | |||||
| /** | |||||
| * <pre> | |||||
| * command字段取值不对 | |||||
| * 对应操作:<code>customerTyping</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_45072(45072, "command字段取值不对"), | |||||
| /** | |||||
| * <pre> | |||||
| * 下发输入状态,需要之前30秒内跟用户有过消息交互. | |||||
| * 对应操作:<code>customerTyping</code> | |||||
| * 对应地址: | |||||
| * 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秒内跟用户有过消息交互"), | |||||
| /** | |||||
| * <pre> | |||||
| * 已经在输入状态,不可重复下发. | |||||
| * 对应操作:<code>customerTyping</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_45081(45081, "已经在输入状态,不可重复下发"), | |||||
| /** | |||||
| * <pre> | |||||
| * API 功能未授权,请确认小程序已获得该接口. | |||||
| * 对应操作:<code>sendCustomerMessage</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_48001(48001, "API 功能未授权"), | |||||
| /** | |||||
| * <pre> | |||||
| * 内容含有违法违规内容. | |||||
| * 对应操作:<code>imgSecCheck</code>, <code>msgSecCheck</code> | |||||
| * 对应地址: | |||||
| * 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 | |||||
| * </pre> | |||||
| */ | |||||
| CODE_87014(87014, "内容含有违法违规内容"); | |||||
| private int code; | |||||
| private String msg; | |||||
| WxMaErrorMsgEnum(int code, String msg) { | |||||
| this.code = code; | |||||
| this.msg = msg; | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 通过错误代码查找其中文含义. | |||||
| */ | |||||
| public static String findMsgByCode(int code) { | |||||
| for (WxMaErrorMsgEnum value : WxMaErrorMsgEnum.values()) { | |||||
| if (value.code == code) { | |||||
| return value.msg; | |||||
| } | |||||
| } | |||||
| return null; | |||||
| } | |||||
| } | |||||
| @@ -642,8 +642,7 @@ public enum WxMpErrorMsgEnum { | |||||
| * 通过错误代码查找其中文含义. | * 通过错误代码查找其中文含义. | ||||
| */ | */ | ||||
| public static String findMsgByCode(int code) { | public static String findMsgByCode(int code) { | ||||
| WxMpErrorMsgEnum[] values = WxMpErrorMsgEnum.values(); | |||||
| for (WxMpErrorMsgEnum value : values) { | |||||
| for (WxMpErrorMsgEnum value : WxMpErrorMsgEnum.values()) { | |||||
| if (value.code == code) { | if (value.code == code) { | ||||
| return value.msg; | return value.msg; | ||||
| } | } | ||||
| @@ -196,6 +196,7 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
| Thread.sleep(StandardSessionManager.this.backgroundProcessorDelay * 1000L); | Thread.sleep(StandardSessionManager.this.backgroundProcessorDelay * 1000L); | ||||
| backgroundProcess(); | backgroundProcess(); | ||||
| } catch (InterruptedException e) { | } catch (InterruptedException e) { | ||||
| Thread.currentThread().interrupt(); | |||||
| StandardSessionManager.this.log.error("SessionManagerImpl.backgroundProcess error", e); | StandardSessionManager.this.log.error("SessionManagerImpl.backgroundProcess error", e); | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,12 +1,14 @@ | |||||
| package me.chanjar.weixin.common.util; | 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.InvalidKeyException; | ||||
| import java.security.NoSuchAlgorithmException; | 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; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -27,9 +29,9 @@ public class SignUtils { | |||||
| public static String createHmacSha256Sign(String message, String key) { | public static String createHmacSha256Sign(String message, String key) { | ||||
| try { | try { | ||||
| Mac sha256 = Mac.getInstance("HmacSHA256"); | 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); | sha256.init(secretKeySpec); | ||||
| byte[] bytes = sha256.doFinal(message.getBytes()); | |||||
| byte[] bytes = sha256.doFinal(message.getBytes(StandardCharsets.UTF_8)); | |||||
| return Hex.encodeHexString(bytes).toUpperCase(); | return Hex.encodeHexString(bytes).toUpperCase(); | ||||
| } catch (NoSuchAlgorithmException | InvalidKeyException e) { | } catch (NoSuchAlgorithmException | InvalidKeyException e) { | ||||
| SignUtils.log.error(e.getMessage(), e); | SignUtils.log.error(e.getMessage(), e); | ||||
| @@ -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; | |||||
| /** | |||||
| * <pre> | |||||
| * XML转换工具类. | |||||
| * Created by Binary Wang on 2018/11/4. | |||||
| * </pre> | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| public class XmlUtils { | |||||
| public static Map<String, Object> xml2Map(String xmlString) { | |||||
| Map<String, Object> map = new HashMap<>(16); | |||||
| try { | |||||
| SAXReader saxReader = new SAXReader(); | |||||
| Document doc = saxReader.read(new StringReader(xmlString)); | |||||
| Element root = doc.getRootElement(); | |||||
| List<Element> 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<String, Object> result = Maps.newHashMap(); | |||||
| final List<Node> content = element.content(); | |||||
| if (content.size() <= 1) { | |||||
| return element.getText(); | |||||
| } | |||||
| final Set<String> names = names(content); | |||||
| if (names.size() == 1) { | |||||
| // 说明是个列表,各个子对象是相同的name | |||||
| List<Object> 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<String> names(List<Node> nodes) { | |||||
| Set<String> names = Sets.newHashSet(); | |||||
| for (Node node : nodes) { | |||||
| if (node instanceof DefaultText) { | |||||
| continue; | |||||
| } | |||||
| names.add(node.getName()); | |||||
| } | |||||
| return names; | |||||
| } | |||||
| } | |||||
| @@ -1,22 +1,22 @@ | |||||
| /** | |||||
| /* | |||||
| * 对公众平台发送给公众账号的消息加解密示例代码. | * 对公众平台发送给公众账号的消息加解密示例代码. | ||||
| * | * | ||||
| * @copyright Copyright (c) 1998-2014 Tencent Inc. | * @copyright Copyright (c) 1998-2014 Tencent Inc. | ||||
| */ | */ | ||||
| // ------------------------------------------------------------------------ | |||||
| package me.chanjar.weixin.common.util.crypto; | package me.chanjar.weixin.common.util.crypto; | ||||
| import java.nio.charset.Charset; | import java.nio.charset.Charset; | ||||
| import java.nio.charset.StandardCharsets; | |||||
| import java.util.Arrays; | import java.util.Arrays; | ||||
| /** | /** | ||||
| * 提供基于PKCS7算法的加解 | |||||
| * 提供基于PKCS7算法的加解. | |||||
| * | |||||
| * @author tencent | |||||
| */ | */ | ||||
| public class PKCS7Encoder { | 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; | private static final int BLOCK_SIZE = 32; | ||||
| /** | /** | ||||
| @@ -28,20 +28,17 @@ public class PKCS7Encoder { | |||||
| public static byte[] encode(int count) { | public static byte[] encode(int count) { | ||||
| // 计算需要填充的位数 | // 计算需要填充的位数 | ||||
| int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); | int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); | ||||
| if (amountToPad == 0) { | |||||
| amountToPad = BLOCK_SIZE; | |||||
| } | |||||
| // 获得补位所用的字符 | // 获得补位所用的字符 | ||||
| char padChr = chr(amountToPad); | char padChr = chr(amountToPad); | ||||
| String tmp = new String(); | |||||
| StringBuilder tmp = new StringBuilder(); | |||||
| for (int index = 0; index < amountToPad; index++) { | for (int index = 0; index < amountToPad; index++) { | ||||
| tmp += padChr; | |||||
| tmp.append(padChr); | |||||
| } | } | ||||
| return tmp.getBytes(CHARSET); | |||||
| return tmp.toString().getBytes(CHARSET); | |||||
| } | } | ||||
| /** | /** | ||||
| * 删除解密后明文的补位字符 | |||||
| * 删除解密后明文的补位字符. | |||||
| * | * | ||||
| * @param decrypted 解密后的明文 | * @param decrypted 解密后的明文 | ||||
| * @return 删除补位字符后的明文 | * @return 删除补位字符后的明文 | ||||
| @@ -55,12 +52,12 @@ public class PKCS7Encoder { | |||||
| } | } | ||||
| /** | /** | ||||
| * 将数字转化成ASCII码对应的字符,用于对明文进行补码 | |||||
| * 将数字转化成ASCII码对应的字符,用于对明文进行补码. | |||||
| * | * | ||||
| * @param a 需要转化的数字 | * @param a 需要转化的数字 | ||||
| * @return 转化得到的字符 | * @return 转化得到的字符 | ||||
| */ | */ | ||||
| public static char chr(int a) { | |||||
| private static char chr(int a) { | |||||
| byte target = (byte) (a & 0xFF); | byte target = (byte) (a & 0xFF); | ||||
| return (char) target; | return (char) target; | ||||
| } | } | ||||
| @@ -1,21 +1,21 @@ | |||||
| package me.chanjar.weixin.common.util.crypto; | 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.Cipher; | ||||
| import javax.crypto.spec.IvParameterSpec; | import javax.crypto.spec.IvParameterSpec; | ||||
| import javax.crypto.spec.SecretKeySpec; | import javax.crypto.spec.SecretKeySpec; | ||||
| import javax.xml.parsers.DocumentBuilder; | import javax.xml.parsers.DocumentBuilder; | ||||
| import javax.xml.parsers.DocumentBuilderFactory; | import javax.xml.parsers.DocumentBuilderFactory; | ||||
| import javax.xml.parsers.ParserConfigurationException; | 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; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -25,6 +25,8 @@ import java.util.Random; | |||||
| * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) | * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) | ||||
| * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi | * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| * @author Tencent | |||||
| */ | */ | ||||
| public class WxCryptUtil { | public class WxCryptUtil { | ||||
| @@ -35,7 +37,9 @@ public class WxCryptUtil { | |||||
| @Override | @Override | ||||
| protected DocumentBuilder initialValue() { | protected DocumentBuilder initialValue() { | ||||
| try { | try { | ||||
| return DocumentBuilderFactory.newInstance().newDocumentBuilder(); | |||||
| final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); | |||||
| factory.setExpandEntityReferences(false); | |||||
| return factory.newDocumentBuilder(); | |||||
| } catch (ParserConfigurationException exc) { | } catch (ParserConfigurationException exc) { | ||||
| throw new IllegalArgumentException(exc); | throw new IllegalArgumentException(exc); | ||||
| } | } | ||||
| @@ -164,8 +168,7 @@ public class WxCryptUtil { | |||||
| ByteGroup byteCollector = new ByteGroup(); | ByteGroup byteCollector = new ByteGroup(); | ||||
| byte[] randomStringBytes = randomStr.getBytes(CHARSET); | byte[] randomStringBytes = randomStr.getBytes(CHARSET); | ||||
| byte[] plainTextBytes = plainText.getBytes(CHARSET); | byte[] plainTextBytes = plainText.getBytes(CHARSET); | ||||
| byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder( | |||||
| plainTextBytes.length); | |||||
| byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length); | |||||
| byte[] appIdBytes = this.appidOrCorpid.getBytes(CHARSET); | byte[] appIdBytes = this.appidOrCorpid.getBytes(CHARSET); | ||||
| // randomStr + networkBytesOrder + text + appid | // randomStr + networkBytesOrder + text + appid | ||||
| @@ -252,7 +255,7 @@ public class WxCryptUtil { | |||||
| throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
| } | } | ||||
| String xmlContent, from_appid; | |||||
| String xmlContent, fromAppid; | |||||
| try { | try { | ||||
| // 去除补位字符 | // 去除补位字符 | ||||
| byte[] bytes = PKCS7Encoder.decode(original); | byte[] bytes = PKCS7Encoder.decode(original); | ||||
| @@ -264,14 +267,14 @@ public class WxCryptUtil { | |||||
| xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), | xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), | ||||
| CHARSET); | CHARSET); | ||||
| from_appid = new String( | |||||
| fromAppid = new String( | |||||
| Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); | Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); | ||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
| } | } | ||||
| // appid不相同的情况 | // appid不相同的情况 | ||||
| if (!from_appid.equals(this.appidOrCorpid)) { | |||||
| if (!fromAppid.equals(this.appidOrCorpid)) { | |||||
| throw new RuntimeException("AppID不正确"); | throw new RuntimeException("AppID不正确"); | ||||
| } | } | ||||
| @@ -1,13 +1,16 @@ | |||||
| package me.chanjar.weixin.common.util.http; | 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.apache.ApacheMediaDownloadRequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaDownloadRequestExecutor; | import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaDownloadRequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaDownloadRequestExecutor; | import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaDownloadRequestExecutor; | ||||
| import java.io.File; | |||||
| /** | /** | ||||
| * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File | |||||
| * 下载媒体文件请求执行器. | |||||
| * 请求的参数是String, 返回的结果是File | |||||
| * 视频文件不支持下载 | * 视频文件不支持下载 | ||||
| * | * | ||||
| * @author Daniel Qian | * @author Daniel Qian | ||||
| @@ -21,6 +24,11 @@ public abstract class BaseMediaDownloadRequestExecutor<H, P> implements RequestE | |||||
| this.tmpDirFile = tmpDirFile; | this.tmpDirFile = tmpDirFile; | ||||
| } | } | ||||
| @Override | |||||
| public void execute(String uri, String data, ResponseHandler<File> handler) throws WxErrorException, IOException { | |||||
| handler.handle(this.execute(uri, data)); | |||||
| } | |||||
| public static RequestExecutor<File, String> create(RequestHttp requestHttp, File tmpDirFile) { | public static RequestExecutor<File, String> create(RequestHttp requestHttp, File tmpDirFile) { | ||||
| switch (requestHttp.getRequestType()) { | switch (requestHttp.getRequestType()) { | ||||
| case APACHE_HTTP: | case APACHE_HTTP: | ||||
| @@ -58,7 +58,7 @@ public class HttpResponseProxy { | |||||
| private String getFileName(CloseableHttpResponse response) throws WxErrorException { | private String getFileName(CloseableHttpResponse response) throws WxErrorException { | ||||
| Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); | Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); | ||||
| if (contentDispositionHeader == null || contentDispositionHeader.length == 0) { | 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()); | return this.extractFileNameFromContentString(contentDispositionHeader[0].getValue()); | ||||
| @@ -76,7 +76,7 @@ public class HttpResponseProxy { | |||||
| private String extractFileNameFromContentString(String content) throws WxErrorException { | private String extractFileNameFromContentString(String content) throws WxErrorException { | ||||
| if (content == null || content.length() == 0) { | 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); | Matcher m = PATTERN.matcher(content); | ||||
| @@ -84,7 +84,7 @@ public class HttpResponseProxy { | |||||
| return m.group(1); | return m.group(1); | ||||
| } | } | ||||
| throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build()); | |||||
| throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build()); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,14 +1,17 @@ | |||||
| package me.chanjar.weixin.common.util.http; | 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.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.apache.ApacheMediaUploadRequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaUploadRequestExecutor; | import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaUploadRequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaUploadRequestExecutor; | import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaUploadRequestExecutor; | ||||
| import java.io.File; | |||||
| /** | /** | ||||
| * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String | |||||
| * 上传媒体文件请求执行器. | |||||
| * 请求的参数是File, 返回的结果是String | |||||
| * | * | ||||
| * @author Daniel Qian | * @author Daniel Qian | ||||
| */ | */ | ||||
| @@ -19,6 +22,11 @@ public abstract class MediaUploadRequestExecutor<H, P> implements RequestExecuto | |||||
| this.requestHttp = requestHttp; | this.requestHttp = requestHttp; | ||||
| } | } | ||||
| @Override | |||||
| public void execute(String uri, File data, ResponseHandler<WxMediaUploadResult> handler) throws WxErrorException, IOException { | |||||
| handler.handle(this.execute(uri, data)); | |||||
| } | |||||
| public static RequestExecutor<WxMediaUploadResult, File> create(RequestHttp requestHttp) { | public static RequestExecutor<WxMediaUploadResult, File> create(RequestHttp requestHttp) { | ||||
| switch (requestHttp.getRequestType()) { | switch (requestHttp.getRequestType()) { | ||||
| case APACHE_HTTP: | case APACHE_HTTP: | ||||
| @@ -1,11 +1,11 @@ | |||||
| package me.chanjar.weixin.common.util.http; | package me.chanjar.weixin.common.util.http; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | |||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | |||||
| /** | /** | ||||
| * http请求执行器 | |||||
| * http请求执行器. | |||||
| * | * | ||||
| * @param <T> 返回值类型 | * @param <T> 返回值类型 | ||||
| * @param <E> 请求参数类型 | * @param <E> 请求参数类型 | ||||
| @@ -14,8 +14,25 @@ import java.io.IOException; | |||||
| public interface RequestExecutor<T, E> { | public interface RequestExecutor<T, E> { | ||||
| /** | /** | ||||
| * 执行http请求. | |||||
| * | |||||
| * @param uri uri | * @param uri uri | ||||
| * @param data 数据 | * @param data 数据 | ||||
| * @return 响应结果 | |||||
| * @throws WxErrorException 自定义异常 | |||||
| * @throws IOException io异常 | |||||
| */ | */ | ||||
| T execute(String uri, E data) throws WxErrorException, IOException; | 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<T> handler) throws WxErrorException, IOException; | |||||
| } | } | ||||
| @@ -2,21 +2,30 @@ package me.chanjar.weixin.common.util.http; | |||||
| /** | /** | ||||
| * Created by ecoolper on 2017/4/22. | * Created by ecoolper on 2017/4/22. | ||||
| * | |||||
| * @author ecoolper | |||||
| */ | */ | ||||
| public interface RequestHttp<H, P> { | public interface RequestHttp<H, P> { | ||||
| /** | /** | ||||
| * 返回httpClient | |||||
| * 返回httpClient. | |||||
| * | * | ||||
| * @return 返回httpClient | |||||
| */ | */ | ||||
| H getRequestHttpClient(); | H getRequestHttpClient(); | ||||
| /** | /** | ||||
| * 返回httpProxy | |||||
| * 返回httpProxy. | |||||
| * | * | ||||
| * @return 返回httpProxy | |||||
| */ | */ | ||||
| P getRequestHttpProxy(); | P getRequestHttpProxy(); | ||||
| /** | |||||
| * 返回HttpType. | |||||
| * | |||||
| * @return HttpType | |||||
| */ | |||||
| HttpType getRequestType(); | HttpType getRequestType(); | ||||
| } | } | ||||
| @@ -0,0 +1,19 @@ | |||||
| package me.chanjar.weixin.common.util.http; | |||||
| /** | |||||
| * <pre> | |||||
| * http请求响应回调处理接口. | |||||
| * Created by Binary Wang on 2018/12/8. | |||||
| * </pre> | |||||
| * | |||||
| * @param <T> 返回值类型 | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| public interface ResponseHandler<T> { | |||||
| /** | |||||
| * 响应结果处理. | |||||
| * | |||||
| * @param t 要处理的对象 | |||||
| */ | |||||
| void handle(T t); | |||||
| } | |||||
| @@ -1,11 +1,15 @@ | |||||
| package me.chanjar.weixin.common.util.http; | 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.apache.ApacheHttpClientSimpleGetRequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimpleGetRequestExecutor; | import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimpleGetRequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimpleGetRequestExecutor; | import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimpleGetRequestExecutor; | ||||
| /** | /** | ||||
| * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String | |||||
| * 简单的GET请求执行器. | |||||
| * 请求的参数是String, 返回的结果也是String | |||||
| * | * | ||||
| * @author Daniel Qian | * @author Daniel Qian | ||||
| */ | */ | ||||
| @@ -16,6 +20,11 @@ public abstract class SimpleGetRequestExecutor<H, P> implements RequestExecutor< | |||||
| this.requestHttp = requestHttp; | this.requestHttp = requestHttp; | ||||
| } | } | ||||
| @Override | |||||
| public void execute(String uri, String data, ResponseHandler<String> handler) throws WxErrorException, IOException { | |||||
| handler.handle(this.execute(uri, data)); | |||||
| } | |||||
| public static RequestExecutor<String, String> create(RequestHttp requestHttp) { | public static RequestExecutor<String, String> create(RequestHttp requestHttp) { | ||||
| switch (requestHttp.getRequestType()) { | switch (requestHttp.getRequestType()) { | ||||
| case APACHE_HTTP: | case APACHE_HTTP: | ||||
| @@ -1,5 +1,8 @@ | |||||
| package me.chanjar.weixin.common.util.http; | 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.apache.ApacheSimplePostRequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimplePostRequestExecutor; | import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimplePostRequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimplePostRequestExecutor; | import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimplePostRequestExecutor; | ||||
| @@ -17,6 +20,11 @@ public abstract class SimplePostRequestExecutor<H, P> implements RequestExecutor | |||||
| this.requestHttp = requestHttp; | this.requestHttp = requestHttp; | ||||
| } | } | ||||
| @Override | |||||
| public void execute(String uri, String data, ResponseHandler<String> handler) throws WxErrorException, IOException { | |||||
| handler.handle(this.execute(uri, data)); | |||||
| } | |||||
| public static RequestExecutor<String, String> create(RequestHttp requestHttp) { | public static RequestExecutor<String, String> create(RequestHttp requestHttp) { | ||||
| switch (requestHttp.getRequestType()) { | switch (requestHttp.getRequestType()) { | ||||
| case APACHE_HTTP: | case APACHE_HTTP: | ||||
| @@ -1,9 +1,9 @@ | |||||
| package me.chanjar.weixin.common.util.http; | 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 { | public class URIUtil { | ||||
| @@ -16,27 +16,22 @@ public class URIUtil { | |||||
| int l = input.length(); | int l = input.length(); | ||||
| StringBuilder o = new StringBuilder(l * 3); | 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); | 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("%"); | o.append("%"); | ||||
| if (n < 0x10) { | if (n < 0x10) { | ||||
| o.append("0"); | o.append("0"); | ||||
| @@ -1,16 +1,17 @@ | |||||
| package me.chanjar.weixin.common.util.http.apache; | 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.HttpHost; | ||||
| import org.apache.http.client.config.RequestConfig; | import org.apache.http.client.config.RequestConfig; | ||||
| import org.apache.http.client.methods.CloseableHttpResponse; | import org.apache.http.client.methods.CloseableHttpResponse; | ||||
| import org.apache.http.client.methods.HttpGet; | import org.apache.http.client.methods.HttpGet; | ||||
| import org.apache.http.impl.client.CloseableHttpClient; | 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. | * Created by ecoolper on 2017/5/4. | ||||
| @@ -1,5 +1,9 @@ | |||||
| package me.chanjar.weixin.common.util.http.apache; | 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.commons.lang3.StringUtils; | ||||
| import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
| import org.apache.http.annotation.NotThreadSafe; | import org.apache.http.annotation.NotThreadSafe; | ||||
| @@ -25,10 +29,6 @@ import org.apache.http.protocol.HttpContext; | |||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
| import java.io.IOException; | |||||
| import java.util.concurrent.TimeUnit; | |||||
| import java.util.concurrent.atomic.AtomicBoolean; | |||||
| /** | /** | ||||
| * httpclient 连接管理器 自带DNS解析. | * httpclient 连接管理器 自带DNS解析. | ||||
| * <p>大部分代码拷贝自:DefaultApacheHttpClientBuilder</p> | * <p>大部分代码拷贝自:DefaultApacheHttpClientBuilder</p> | ||||
| @@ -292,6 +292,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||||
| } | } | ||||
| } | } | ||||
| } catch (InterruptedException ignore) { | } catch (InterruptedException ignore) { | ||||
| Thread.currentThread().interrupt(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -25,7 +25,6 @@ import me.chanjar.weixin.common.util.http.RequestHttp; | |||||
| * Created by ecoolper on 2017/5/5. | * Created by ecoolper on 2017/5/5. | ||||
| */ | */ | ||||
| public class ApacheMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor<CloseableHttpClient, HttpHost> { | public class ApacheMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor<CloseableHttpClient, HttpHost> { | ||||
| public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { | public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { | ||||
| super(requestHttp, tmpDirFile); | super(requestHttp, tmpDirFile); | ||||
| } | } | ||||
| @@ -1,5 +1,8 @@ | |||||
| package me.chanjar.weixin.common.util.http.apache; | 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.HttpEntity; | ||||
| import org.apache.http.HttpResponse; | import org.apache.http.HttpResponse; | ||||
| import org.apache.http.StatusLine; | 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.client.ResponseHandler; | ||||
| import org.apache.http.util.EntityUtils; | import org.apache.http.util.EntityUtils; | ||||
| import java.io.IOException; | |||||
| import java.io.InputStream; | |||||
| /** | |||||
| * 输入流响应处理器. | |||||
| * | |||||
| * @author Daniel Qian | |||||
| */ | |||||
| public class InputStreamResponseHandler implements ResponseHandler<InputStream> { | public class InputStreamResponseHandler implements ResponseHandler<InputStream> { | ||||
| public static final ResponseHandler<InputStream> INSTANCE = new InputStreamResponseHandler(); | public static final ResponseHandler<InputStream> INSTANCE = new InputStreamResponseHandler(); | ||||
| private static final int STATUS_CODE_300 = 300; | |||||
| @Override | @Override | ||||
| public InputStream handleResponse(final HttpResponse response) throws IOException { | public InputStream handleResponse(final HttpResponse response) throws IOException { | ||||
| final StatusLine statusLine = response.getStatusLine(); | final StatusLine statusLine = response.getStatusLine(); | ||||
| final HttpEntity entity = response.getEntity(); | final HttpEntity entity = response.getEntity(); | ||||
| if (statusLine.getStatusCode() >= 300) { | |||||
| if (statusLine.getStatusCode() >= STATUS_CODE_300) { | |||||
| EntityUtils.consume(entity); | EntityUtils.consume(entity); | ||||
| throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); | throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); | ||||
| } | } | ||||
| @@ -7,9 +7,13 @@ import me.chanjar.weixin.common.bean.menu.WxMenu; | |||||
| import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
| import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
| /** | |||||
| * . | |||||
| * @author chanjarster | |||||
| */ | |||||
| public class WxGsonBuilder { | public class WxGsonBuilder { | ||||
| public static final GsonBuilder INSTANCE = new GsonBuilder(); | |||||
| private static final GsonBuilder INSTANCE = new GsonBuilder(); | |||||
| static { | static { | ||||
| INSTANCE.disableHtmlEscaping(); | INSTANCE.disableHtmlEscaping(); | ||||
| @@ -8,47 +8,47 @@ import com.thoughtworks.xstream.core.util.QuickWriter; | |||||
| import com.thoughtworks.xstream.io.HierarchicalStreamWriter; | import com.thoughtworks.xstream.io.HierarchicalStreamWriter; | ||||
| import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; | import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; | ||||
| import com.thoughtworks.xstream.io.xml.XppDriver; | import com.thoughtworks.xstream.io.xml.XppDriver; | ||||
| import com.thoughtworks.xstream.security.NullPermission; | |||||
| import com.thoughtworks.xstream.security.PrimitiveTypePermission; | |||||
| public class XStreamInitializer { | 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 = "<![CDATA["; | |||||
| protected String SUFFIX_CDATA = "]]>"; | |||||
| protected String PREFIX_MEDIA_ID = "<MediaId>"; | |||||
| protected String SUFFIX_MEDIA_ID = "</MediaId>"; | |||||
| @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 = "<![CDATA["; | |||||
| private static final String SUFFIX_CDATA = "]]>"; | |||||
| private static final String PREFIX_MEDIA_ID = "<MediaId>"; | |||||
| private static final String SUFFIX_MEDIA_ID = "</MediaId>"; | |||||
| @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.ignoreUnknownElements(); | ||||
| xstream.setMode(XStream.NO_REFERENCES); | 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()); | xstream.setClassLoader(Thread.currentThread().getContextClassLoader()); | ||||
| return xstream; | return xstream; | ||||
| } | } | ||||
| @@ -1,8 +1,7 @@ | |||||
| package me.chanjar.weixin.common.util; | 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.*; | import static org.testng.Assert.*; | ||||
| /** | /** | ||||
| @@ -18,6 +17,6 @@ public class DataUtilsTest { | |||||
| public void testHandleDataWithSecret() { | public void testHandleDataWithSecret() { | ||||
| String data = "js_code=001tZveq0SMoiq1AEXeq0ECJeq0tZveZ&secret=5681022fa1643845392367ea88888888&grant_type=authorization_code&appid=wxe156d4848d999999"; | String data = "js_code=001tZveq0SMoiq1AEXeq0ECJeq0tZveZ&secret=5681022fa1643845392367ea88888888&grant_type=authorization_code&appid=wxe156d4848d999999"; | ||||
| final String s = DataUtils.handleDataWithSecret(data); | final String s = DataUtils.handleDataWithSecret(data); | ||||
| assertThat(s).contains("&secret=******&"); | |||||
| assertTrue(s.contains("&secret=******&")); | |||||
| } | } | ||||
| } | } | ||||
| @@ -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; | |||||
| /** | |||||
| * <pre> | |||||
| * | |||||
| * Created by Binary Wang on 2018/11/4. | |||||
| * </pre> | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| public class XmlUtilsTest { | |||||
| @Test | |||||
| public void testXml2Map() { | |||||
| String xml = "<xml>\n" + | |||||
| "<CopyrightCheckResult>\n" + | |||||
| "<Count>2</Count>\n" + | |||||
| "<ResultList>\n" + | |||||
| "<item>\n" + | |||||
| "<ArticleIdx>1</ArticleIdx>\n" + | |||||
| "<UserDeclareState>0</UserDeclareState>\n" + | |||||
| "<AuditState>2</AuditState>\n" + | |||||
| "<OriginalArticleUrl><![CDATA[Url_1]]></OriginalArticleUrl>\n" + | |||||
| "<OriginalArticleType>1</OriginalArticleType>\n" + | |||||
| "<CanReprint>1</CanReprint>\n" + | |||||
| "<NeedReplaceContent>1</NeedReplaceContent>\n" + | |||||
| "<NeedShowReprintSource>1</NeedShowReprintSource>\n" + | |||||
| "</item>\n" + | |||||
| "<item>\n" + | |||||
| "<ArticleIdx>2</ArticleIdx>\n" + | |||||
| "<UserDeclareState>0</UserDeclareState>\n" + | |||||
| "<AuditState>2</AuditState>\n" + | |||||
| "<OriginalArticleUrl><![CDATA[Url_2]]></OriginalArticleUrl>\n" + | |||||
| "<OriginalArticleType>1</OriginalArticleType>\n" + | |||||
| "<CanReprint>1</CanReprint>\n" + | |||||
| "<NeedReplaceContent>1</NeedReplaceContent>\n" + | |||||
| "<NeedShowReprintSource>1</NeedShowReprintSource>\n" + | |||||
| "</item>\n" + | |||||
| "</ResultList>\n" + | |||||
| "<CheckState>2</CheckState>\n" + | |||||
| "</CopyrightCheckResult>\n" + | |||||
| "</xml>"; | |||||
| final Map<String, Object> map = XmlUtils.xml2Map(xml); | |||||
| assertThat(map).isNotNull(); | |||||
| final Map<String, Object> copyrightCheckResult = (Map<String, Object>) map.get("CopyrightCheckResult"); | |||||
| List<Map<String, Object>> resultList = (List<Map<String, Object>>) ((Map<String, Object>) 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"); | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,11 @@ | |||||
| package me.chanjar.weixin.common.util.crypto; | 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.testng.annotations.*; | ||||
| import org.w3c.dom.Document; | import org.w3c.dom.Document; | ||||
| import org.w3c.dom.Element; | import org.w3c.dom.Element; | ||||
| @@ -7,12 +13,6 @@ import org.w3c.dom.NodeList; | |||||
| import org.xml.sax.InputSource; | import org.xml.sax.InputSource; | ||||
| import org.xml.sax.SAXException; | 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.*; | import static org.testng.Assert.*; | ||||
| @Test | @Test | ||||
| @@ -39,6 +39,7 @@ public class WxCryptUtilTest { | |||||
| System.out.println(encryptedXml); | System.out.println(encryptedXml); | ||||
| DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); | DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); | ||||
| documentBuilderFactory.setExpandEntityReferences(false); | |||||
| DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); | DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); | ||||
| Document document = documentBuilder.parse(new InputSource(new StringReader(encryptedXml))); | 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); | WxCryptUtil pc = new WxCryptUtil(this.token, this.encodingAesKey, this.appId); | ||||
| String afterEncrpt = pc.encrypt(this.replyMsg); | String afterEncrpt = pc.encrypt(this.replyMsg); | ||||
| DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); | ||||
| dbf.setExpandEntityReferences(false); | |||||
| DocumentBuilder db = dbf.newDocumentBuilder(); | DocumentBuilder db = dbf.newDocumentBuilder(); | ||||
| StringReader sr = new StringReader(afterEncrpt); | StringReader sr = new StringReader(afterEncrpt); | ||||
| InputSource is = new InputSource(sr); | InputSource is = new InputSource(sr); | ||||
| @@ -6,13 +6,13 @@ | |||||
| <modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
| <parent> | <parent> | ||||
| <groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
| <artifactId>weixin-java-parent</artifactId> | |||||
| <version>3.2.0</version> | |||||
| <artifactId>wx-java</artifactId> | |||||
| <version>3.3.0</version> | |||||
| </parent> | </parent> | ||||
| <artifactId>weixin-java-cp</artifactId> | <artifactId>weixin-java-cp</artifactId> | ||||
| <name>Weixin Java Tools - CP</name> | |||||
| <description>微信企业号Java SDK</description> | |||||
| <name>WxJava - CP</name> | |||||
| <description>微信企业号/企业微信 Java SDK</description> | |||||
| <dependencies> | <dependencies> | ||||
| <dependency> | <dependency> | ||||
| @@ -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<String> 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<String> usersToAdd, List<String> usersToDelete) throws WxErrorException; | |||||
| /** | |||||
| * 获取群聊会话 | |||||
| * | |||||
| * @param chatId 群聊编号 | |||||
| * @return 群聊会话 | |||||
| * @throws WxErrorException 发生异常 | |||||
| */ | |||||
| WxCpChat chatGet(String chatId) throws WxErrorException; | |||||
| } | |||||
| @@ -1,10 +1,10 @@ | |||||
| package me.chanjar.weixin.cp.api; | package me.chanjar.weixin.cp.api; | ||||
| import java.util.List; | |||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.cp.bean.WxCpDepart; | import me.chanjar.weixin.cp.bean.WxCpDepart; | ||||
| import java.util.List; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 部门管理接口 | * 部门管理接口 | ||||
| @@ -17,42 +17,47 @@ public interface WxCpDepartmentService { | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 部门管理接口 - 创建部门 | |||||
| * 部门管理接口 - 创建部门. | |||||
| * 最多支持创建500个部门 | * 最多支持创建500个部门 | ||||
| * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口 | * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口 | ||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * @param depart 部门 | * @param depart 部门 | ||||
| * @return 部门id | * @return 部门id | ||||
| * @throws WxErrorException 异常 | |||||
| */ | */ | ||||
| Integer create(WxCpDepart depart) throws WxErrorException; | Integer create(WxCpDepart depart) throws WxErrorException; | ||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 部门管理接口 - 查询部门 | |||||
| * 部门管理接口 - 查询部门. | |||||
| * 详情请见: 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 | * 详情请见: 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 | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| * @param id 部门id。获取指定部门及其下的子部门。非必需,可为null | * @param id 部门id。获取指定部门及其下的子部门。非必需,可为null | ||||
| * @throws WxErrorException 异常 | |||||
| */ | */ | ||||
| List<WxCpDepart> list(Integer id) throws WxErrorException; | |||||
| List<WxCpDepart> list(Long id) throws WxErrorException; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 部门管理接口 - 修改部门名 | |||||
| * 部门管理接口 - 修改部门名. | |||||
| * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口 | * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口 | ||||
| * 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误 | * 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误 | ||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * @param group 要更新的group,group的id,name必须设置 | * @param group 要更新的group,group的id,name必须设置 | ||||
| * @throws WxErrorException 异常 | |||||
| */ | */ | ||||
| void update(WxCpDepart group) throws WxErrorException; | void update(WxCpDepart group) throws WxErrorException; | ||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 部门管理接口 - 删除部门 | |||||
| * 部门管理接口 - 删除部门. | |||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * @param departId 部门id | * @param departId 部门id | ||||
| * @throws WxErrorException 异常 | |||||
| */ | */ | ||||
| void delete(Integer departId) throws WxErrorException; | |||||
| void delete(Long departId) throws WxErrorException; | |||||
| } | } | ||||
| @@ -19,6 +19,7 @@ public interface WxCpMediaService { | |||||
| String MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; | 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 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 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"; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -59,6 +60,21 @@ public interface WxCpMediaService { | |||||
| */ | */ | ||||
| File download(String mediaId) throws WxErrorException; | File download(String mediaId) throws WxErrorException; | ||||
| /** | |||||
| * <pre> | |||||
| * 获取高清语音素材. | |||||
| * 可以使用本接口获取从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 | |||||
| * </pre> | |||||
| * | |||||
| * @param mediaId 媒体id | |||||
| * @return 保存到本地的临时文件 | |||||
| */ | |||||
| File getJssdkFile(String mediaId) throws WxErrorException; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 上传图片. | * 上传图片. | ||||
| @@ -69,7 +85,7 @@ public interface WxCpMediaService { | |||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * @param file 上传的文件对象 | * @param file 上传的文件对象 | ||||
| * @return 返回图片url | |||||
| * @return 返回图片url | |||||
| */ | */ | ||||
| String uploadImg(File file) throws WxErrorException; | String uploadImg(File file) throws WxErrorException; | ||||
| } | } | ||||
| @@ -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.MediaUploadRequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | import me.chanjar.weixin.common.util.http.RequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.RequestHttp; | 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; | import me.chanjar.weixin.cp.config.WxCpConfigStorage; | ||||
| /** | /** | ||||
| @@ -241,13 +242,20 @@ public interface WxCpService { | |||||
| * 获取用户相关接口的服务类对象 | * 获取用户相关接口的服务类对象 | ||||
| */ | */ | ||||
| WxCpUserService getUserService(); | WxCpUserService getUserService(); | ||||
| /** | |||||
| * 获取群聊服务 | |||||
| * | |||||
| * @return 群聊服务 | |||||
| */ | |||||
| WxCpChatService getChatService(); | |||||
| WxCpAgentService getAgentService(); | WxCpAgentService getAgentService(); | ||||
| /** | /** | ||||
| * http请求对象 | * http请求对象 | ||||
| */ | */ | ||||
| RequestHttp getRequestHttp(); | |||||
| RequestHttp<?, ?> getRequestHttp(); | |||||
| void setUserService(WxCpUserService userService); | void setUserService(WxCpUserService userService); | ||||
| @@ -38,7 +38,7 @@ public interface WxCpUserService { | |||||
| * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | ||||
| * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | ||||
| */ | */ | ||||
| List<WxCpUser> listByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; | |||||
| List<WxCpUser> listByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -51,7 +51,7 @@ public interface WxCpUserService { | |||||
| * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | ||||
| * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | ||||
| */ | */ | ||||
| List<WxCpUser> listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; | |||||
| List<WxCpUser> listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException; | |||||
| /** | /** | ||||
| * 新建用户. | * 新建用户. | ||||
| @@ -1,9 +1,11 @@ | |||||
| package me.chanjar.weixin.cp.api.impl; | 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.JsonObject; | ||||
| import com.google.gson.JsonParser; | import com.google.gson.JsonParser; | ||||
| import com.google.gson.reflect.TypeToken; | import com.google.gson.reflect.TypeToken; | ||||
| import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.cp.api.WxCpAgentService; | 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.bean.WxCpAgent; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
| import java.util.List; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -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<String> users, String chatId) throws WxErrorException { | |||||
| Map<String, Object> 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<String> usersToAdd, List<String> usersToDelete) throws WxErrorException { | |||||
| Map<String, Object> 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); | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,7 @@ | |||||
| package me.chanjar.weixin.cp.api.impl; | package me.chanjar.weixin.cp.api.impl; | ||||
| import java.util.List; | |||||
| import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonParser; | import com.google.gson.JsonParser; | ||||
| import com.google.gson.reflect.TypeToken; | 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.bean.WxCpDepart; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
| import java.util.List; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 部门管理接口 | * 部门管理接口 | ||||
| @@ -42,13 +42,13 @@ public class WxCpDepartmentServiceImpl implements WxCpDepartmentService { | |||||
| } | } | ||||
| @Override | @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; | String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId; | ||||
| this.mainService.get(url, null); | this.mainService.get(url, null); | ||||
| } | } | ||||
| @Override | @Override | ||||
| public List<WxCpDepart> list(Integer id) throws WxErrorException { | |||||
| public List<WxCpDepart> list(Long id) throws WxErrorException { | |||||
| String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; | String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; | ||||
| if (id != null) { | if (id != null) { | ||||
| url += "?id=" + id; | url += "?id=" + id; | ||||
| @@ -56,7 +56,7 @@ public class WxCpDepartmentServiceImpl implements WxCpDepartmentService { | |||||
| String responseContent = this.mainService.get(url, null); | String responseContent = this.mainService.get(url, null); | ||||
| JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | ||||
| return WxCpGsonBuilder.INSTANCE.create() | |||||
| return WxCpGsonBuilder.create() | |||||
| .fromJson(tmpJsonElement.getAsJsonObject().get("department"), | .fromJson(tmpJsonElement.getAsJsonObject().get("department"), | ||||
| new TypeToken<List<WxCpDepart>>() { | new TypeToken<List<WxCpDepart>>() { | ||||
| }.getType() | }.getType() | ||||
| @@ -48,6 +48,14 @@ public class WxCpMediaServiceImpl implements WxCpMediaService { | |||||
| MEDIA_GET_URL, "media_id=" + mediaId); | 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 | @Override | ||||
| public String uploadImg(File file) throws WxErrorException { | public String uploadImg(File file) throws WxErrorException { | ||||
| final WxMediaUploadResult result = this.mainService | final WxMediaUploadResult result = this.mainService | ||||
| @@ -1,6 +1,5 @@ | |||||
| package me.chanjar.weixin.cp.api.impl; | package me.chanjar.weixin.cp.api.impl; | ||||
| import com.google.gson.GsonBuilder; | |||||
| import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||
| import com.google.gson.JsonParser; | 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.WxCpOAuth2Service; | ||||
| import me.chanjar.weixin.cp.api.WxCpService; | import me.chanjar.weixin.cp.api.WxCpService; | ||||
| import me.chanjar.weixin.cp.bean.WxCpUserDetail; | import me.chanjar.weixin.cp.bean.WxCpUserDetail; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -87,6 +87,6 @@ public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { | |||||
| JsonObject param = new JsonObject(); | JsonObject param = new JsonObject(); | ||||
| param.addProperty("user_ticket", userTicket); | param.addProperty("user_ticket", userTicket); | ||||
| String responseText = this.mainService.post(url, param.toString()); | String responseText = this.mainService.post(url, param.toString()); | ||||
| return new GsonBuilder().create().fromJson(responseText, WxCpUserDetail.class); | |||||
| return WxCpGsonBuilder.create().fromJson(responseText, WxCpUserDetail.class); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,9 +1,16 @@ | |||||
| package me.chanjar.weixin.cp.api.impl; | 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.JsonArray; | ||||
| import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||
| import com.google.gson.JsonParser; | import com.google.gson.JsonParser; | ||||
| import me.chanjar.weixin.common.bean.WxJsapiSignature; | import me.chanjar.weixin.common.bean.WxJsapiSignature; | ||||
| import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | 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.RequestHttp; | ||||
| import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; | 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 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<H, P> implements WxCpService, RequestHttp<H, P> { | public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, RequestHttp<H, P> { | ||||
| protected final Logger log = LoggerFactory.getLogger(this.getClass()); | protected final Logger log = LoggerFactory.getLogger(this.getClass()); | ||||
| private WxCpUserService userService = new WxCpUserServiceImpl(this); | private WxCpUserService userService = new WxCpUserServiceImpl(this); | ||||
| private WxCpChatService chatService = new WxCpChatServiceImpl(this); | |||||
| private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this); | private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this); | ||||
| private WxCpMediaService mediaService = new WxCpMediaServiceImpl(this); | private WxCpMediaService mediaService = new WxCpMediaServiceImpl(this); | ||||
| private WxCpMenuService menuService = new WxCpMenuServiceImpl(this); | private WxCpMenuService menuService = new WxCpMenuServiceImpl(this); | ||||
| @@ -184,7 +196,7 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ | |||||
| this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); | this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); | ||||
| Thread.sleep(sleepMillis); | Thread.sleep(sleepMillis); | ||||
| } catch (InterruptedException e1) { | } catch (InterruptedException e1) { | ||||
| throw new RuntimeException(e1); | |||||
| Thread.currentThread().interrupt(); | |||||
| } | } | ||||
| } else { | } else { | ||||
| throw e; | throw e; | ||||
| @@ -334,7 +346,12 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ | |||||
| } | } | ||||
| @Override | @Override | ||||
| public RequestHttp getRequestHttp() { | |||||
| public WxCpChatService getChatService() { | |||||
| return chatService; | |||||
| } | |||||
| @Override | |||||
| public RequestHttp<?, ?> getRequestHttp() { | |||||
| return this; | return this; | ||||
| } | } | ||||
| @@ -1,6 +1,12 @@ | |||||
| package me.chanjar.weixin.cp.api.impl; | 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 com.google.gson.reflect.TypeToken; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.cp.api.WxCpService; | 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.bean.WxCpUser; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
| import java.util.List; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 标签管理接口 | * 标签管理接口 | ||||
| @@ -57,7 +61,7 @@ public class WxCpTagServiceImpl implements WxCpTagService { | |||||
| String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; | String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; | ||||
| String responseContent = this.mainService.get(url, null); | String responseContent = this.mainService.get(url, null); | ||||
| JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | ||||
| return WxCpGsonBuilder.INSTANCE.create() | |||||
| return WxCpGsonBuilder.create() | |||||
| .fromJson( | .fromJson( | ||||
| tmpJsonElement.getAsJsonObject().get("taglist"), | tmpJsonElement.getAsJsonObject().get("taglist"), | ||||
| new TypeToken<List<WxCpTag>>() { | new TypeToken<List<WxCpTag>>() { | ||||
| @@ -70,7 +74,7 @@ public class WxCpTagServiceImpl implements WxCpTagService { | |||||
| String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; | String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; | ||||
| String responseContent = this.mainService.get(url, null); | String responseContent = this.mainService.get(url, null); | ||||
| JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | ||||
| return WxCpGsonBuilder.INSTANCE.create() | |||||
| return WxCpGsonBuilder.create() | |||||
| .fromJson( | .fromJson( | ||||
| tmpJsonElement.getAsJsonObject().get("userlist"), | tmpJsonElement.getAsJsonObject().get("userlist"), | ||||
| new TypeToken<List<WxCpUser>>() { | new TypeToken<List<WxCpUser>>() { | ||||
| @@ -76,7 +76,7 @@ public class WxCpUserServiceImpl implements WxCpUserService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| public List<WxCpUser> listByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { | |||||
| public List<WxCpUser> listByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException { | |||||
| String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; | String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; | ||||
| String params = ""; | String params = ""; | ||||
| if (fetchChild != null) { | if (fetchChild != null) { | ||||
| @@ -90,7 +90,7 @@ public class WxCpUserServiceImpl implements WxCpUserService { | |||||
| String responseContent = this.mainService.get(url, params); | String responseContent = this.mainService.get(url, params); | ||||
| JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | ||||
| return WxCpGsonBuilder.INSTANCE.create() | |||||
| return WxCpGsonBuilder.create() | |||||
| .fromJson(tmpJsonElement.getAsJsonObject().get("userlist"), | .fromJson(tmpJsonElement.getAsJsonObject().get("userlist"), | ||||
| new TypeToken<List<WxCpUser>>() { | new TypeToken<List<WxCpUser>>() { | ||||
| }.getType() | }.getType() | ||||
| @@ -98,7 +98,7 @@ public class WxCpUserServiceImpl implements WxCpUserService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| public List<WxCpUser> listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { | |||||
| public List<WxCpUser> listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException { | |||||
| String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; | String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; | ||||
| String params = ""; | String params = ""; | ||||
| if (fetchChild != null) { | if (fetchChild != null) { | ||||
| @@ -112,7 +112,7 @@ public class WxCpUserServiceImpl implements WxCpUserService { | |||||
| String responseContent = this.mainService.get(url, params); | String responseContent = this.mainService.get(url, params); | ||||
| JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | ||||
| return WxCpGsonBuilder.INSTANCE.create() | |||||
| return WxCpGsonBuilder.create() | |||||
| .fromJson( | .fromJson( | ||||
| tmpJsonElement.getAsJsonObject().get("userlist"), | tmpJsonElement.getAsJsonObject().get("userlist"), | ||||
| new TypeToken<List<WxCpUser>>() { | new TypeToken<List<WxCpUser>>() { | ||||
| @@ -1,5 +1,8 @@ | |||||
| package me.chanjar.weixin.cp.bean; | package me.chanjar.weixin.cp.bean; | ||||
| import java.io.Serializable; | |||||
| import java.util.List; | |||||
| import com.google.gson.annotations.SerializedName; | import com.google.gson.annotations.SerializedName; | ||||
| import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||
| import lombok.Builder; | import lombok.Builder; | ||||
| @@ -7,9 +10,6 @@ import lombok.Data; | |||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
| import java.io.Serializable; | |||||
| import java.util.List; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 企业号应用信息. | * 企业号应用信息. | ||||
| @@ -80,12 +80,14 @@ public class WxCpAgent implements Serializable { | |||||
| @Data | @Data | ||||
| public static class Users implements Serializable { | public static class Users implements Serializable { | ||||
| private static final long serialVersionUID = 8801100463558788565L; | |||||
| @SerializedName("user") | @SerializedName("user") | ||||
| private List<User> users; | private List<User> users; | ||||
| } | } | ||||
| @Data | @Data | ||||
| public class User implements Serializable { | public class User implements Serializable { | ||||
| private static final long serialVersionUID = 7287632514385508024L; | |||||
| @SerializedName("userid") | @SerializedName("userid") | ||||
| private String userId; | private String userId; | ||||
| } | } | ||||
| @@ -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<String> users; | |||||
| } | |||||
| @@ -1,10 +1,10 @@ | |||||
| package me.chanjar.weixin.cp.bean; | package me.chanjar.weixin.cp.bean; | ||||
| import java.io.Serializable; | |||||
| import lombok.Data; | import lombok.Data; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | 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 { | public class WxCpDepart implements Serializable { | ||||
| private static final long serialVersionUID = -5028321625140879571L; | private static final long serialVersionUID = -5028321625140879571L; | ||||
| private Integer id; | |||||
| private Long id; | |||||
| private String name; | private String name; | ||||
| private Integer parentId; | |||||
| private Long parentId; | |||||
| private Long order; | private Long order; | ||||
| public static WxCpDepart fromJson(String json) { | public static WxCpDepart fromJson(String json) { | ||||
| @@ -5,8 +5,6 @@ import java.util.Collections; | |||||
| import java.util.List; | import java.util.List; | ||||
| import org.apache.commons.lang3.StringUtils; | 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.common.base.Splitter; | ||||
| import com.google.gson.annotations.SerializedName; | import com.google.gson.annotations.SerializedName; | ||||
| @@ -25,11 +23,11 @@ public class WxCpInviteResult implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return WxCpGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| public static WxCpInviteResult fromJson(String json) { | public static WxCpInviteResult fromJson(String json) { | ||||
| return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpInviteResult.class); | |||||
| return WxCpGsonBuilder.create().fromJson(json, WxCpInviteResult.class); | |||||
| } | } | ||||
| @SerializedName("errcode") | @SerializedName("errcode") | ||||
| @@ -1,16 +1,23 @@ | |||||
| package me.chanjar.weixin.cp.bean; | package me.chanjar.weixin.cp.bean; | ||||
| import java.io.Serializable; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| import lombok.Data; | import lombok.Data; | ||||
| import me.chanjar.weixin.common.api.WxConsts; | import me.chanjar.weixin.common.api.WxConsts; | ||||
| import me.chanjar.weixin.cp.bean.article.MpnewsArticle; | import me.chanjar.weixin.cp.bean.article.MpnewsArticle; | ||||
| import me.chanjar.weixin.cp.bean.article.NewArticle; | 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 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() { | public String toJson() { | ||||
| return WxCpGsonBuilder.INSTANCE.create().toJson(this); | |||||
| return WxCpGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| } | } | ||||
| @@ -5,8 +5,6 @@ import java.util.Collections; | |||||
| import java.util.List; | import java.util.List; | ||||
| import org.apache.commons.lang3.StringUtils; | 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.common.base.Splitter; | ||||
| import com.google.gson.annotations.SerializedName; | import com.google.gson.annotations.SerializedName; | ||||
| @@ -25,11 +23,11 @@ public class WxCpMessageSendResult implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return WxCpGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| public static WxCpMessageSendResult fromJson(String json) { | public static WxCpMessageSendResult fromJson(String json) { | ||||
| return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpMessageSendResult.class); | |||||
| return WxCpGsonBuilder.create().fromJson(json, WxCpMessageSendResult.class); | |||||
| } | } | ||||
| @SerializedName("errcode") | @SerializedName("errcode") | ||||
| @@ -1,14 +1,15 @@ | |||||
| package me.chanjar.weixin.cp.bean; | package me.chanjar.weixin.cp.bean; | ||||
| import java.io.Serializable; | |||||
| import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
| import java.io.Serializable; | |||||
| /** | /** | ||||
| * Created by Daniel Qian. | * Created by Daniel Qian. | ||||
| * @author Daniel Qian | |||||
| */ | */ | ||||
| @Data | @Data | ||||
| @AllArgsConstructor | @AllArgsConstructor | ||||
| @@ -5,8 +5,6 @@ import java.util.Collections; | |||||
| import java.util.List; | import java.util.List; | ||||
| import org.apache.commons.lang3.StringUtils; | 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.common.base.Splitter; | ||||
| import com.google.gson.annotations.SerializedName; | import com.google.gson.annotations.SerializedName; | ||||
| @@ -25,11 +23,11 @@ public class WxCpTagAddOrRemoveUsersResult implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return WxCpGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| public static WxCpTagAddOrRemoveUsersResult fromJson(String json) { | public static WxCpTagAddOrRemoveUsersResult fromJson(String json) { | ||||
| return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpTagAddOrRemoveUsersResult.class); | |||||
| return WxCpGsonBuilder.create().fromJson(json, WxCpTagAddOrRemoveUsersResult.class); | |||||
| } | } | ||||
| @SerializedName("errcode") | @SerializedName("errcode") | ||||
| @@ -50,11 +50,11 @@ public class WxCpUser implements Serializable { | |||||
| } | } | ||||
| public static WxCpUser fromJson(String json) { | public static WxCpUser fromJson(String json) { | ||||
| return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpUser.class); | |||||
| return WxCpGsonBuilder.create().fromJson(json, WxCpUser.class); | |||||
| } | } | ||||
| public String toJson() { | public String toJson() { | ||||
| return WxCpGsonBuilder.INSTANCE.create().toJson(this); | |||||
| return WxCpGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| @Data | @Data | ||||
| @@ -3,12 +3,11 @@ package me.chanjar.weixin.cp.bean; | |||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.io.InputStream; | import java.io.InputStream; | ||||
| import java.io.Serializable; | import java.io.Serializable; | ||||
| import java.nio.charset.StandardCharsets; | |||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||
| import java.util.List; | import java.util.List; | ||||
| import org.apache.commons.io.IOUtils; | 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.XStreamAlias; | ||||
| import com.thoughtworks.xstream.annotations.XStreamConverter; | 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.common.util.xml.XStreamCDataConverter; | ||||
| import me.chanjar.weixin.cp.config.WxCpConfigStorage; | import me.chanjar.weixin.cp.config.WxCpConfigStorage; | ||||
| import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; | import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||||
| import me.chanjar.weixin.cp.util.xml.XStreamTransformer; | 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, | public static WxCpXmlMessage fromEncryptedXml(InputStream is, WxCpConfigStorage wxCpConfigStorage, | ||||
| String timestamp, String nonce, String msgSignature) { | String timestamp, String nonce, String msgSignature) { | ||||
| try { | 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) { | } catch (IOException e) { | ||||
| throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
| } | } | ||||
| @@ -378,7 +378,7 @@ public class WxCpXmlMessage implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return WxCpGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| @Data | @Data | ||||
| @@ -2,11 +2,9 @@ package me.chanjar.weixin.cp.config; | |||||
| import java.io.File; | 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.bean.WxAccessToken; | ||||
| import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||||
| /** | /** | ||||
| * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 | * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 | ||||
| @@ -203,7 +201,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return WxCpGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| @Override | @Override | ||||
| @@ -1,5 +1,18 @@ | |||||
| package me.chanjar.weixin.cp.message; | 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.WxErrorExceptionHandler; | ||||
| import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; | import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; | ||||
| import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; | 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.api.WxCpService; | ||||
| import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | ||||
| import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | 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; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -195,6 +196,7 @@ public class WxCpMessageRouter { | |||||
| sessionEndAccess(wxMessage); | sessionEndAccess(wxMessage); | ||||
| } catch (InterruptedException e) { | } catch (InterruptedException e) { | ||||
| WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); | WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); | ||||
| Thread.currentThread().interrupt(); | |||||
| } catch (ExecutionException e) { | } catch (ExecutionException e) { | ||||
| WxCpMessageRouter.this.log.error("Error happened when wait task finish", 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) { | public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) { | ||||
| return this.route(wxMessage, new HashMap<String, Object>()); | |||||
| return this.route(wxMessage, new HashMap<String, Object>(2)); | |||||
| } | } | ||||
| protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) { | protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) { | ||||
| @@ -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<WxCpChat>, JsonDeserializer<WxCpChat> { | |||||
| @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<String> users = new ArrayList<>(usersJson.size()); | |||||
| chat.setUsers(users); | |||||
| for (JsonElement userJson : usersJson) { | |||||
| users.add(userJson.getAsString()); | |||||
| } | |||||
| } | |||||
| return chat; | |||||
| } | |||||
| } | |||||
| @@ -8,31 +8,43 @@ | |||||
| */ | */ | ||||
| package me.chanjar.weixin.cp.util.json; | 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.common.util.json.GsonHelper; | ||||
| import me.chanjar.weixin.cp.bean.WxCpDepart; | import me.chanjar.weixin.cp.bean.WxCpDepart; | ||||
| import java.lang.reflect.Type; | |||||
| /** | /** | ||||
| * WxCpDepart的gson适配器. | |||||
| * | |||||
| * @author Daniel Qian | * @author Daniel Qian | ||||
| */ | */ | ||||
| public class WxCpDepartGsonAdapter implements JsonSerializer<WxCpDepart>, JsonDeserializer<WxCpDepart> { | public class WxCpDepartGsonAdapter implements JsonSerializer<WxCpDepart>, JsonDeserializer<WxCpDepart> { | ||||
| 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 | @Override | ||||
| public JsonElement serialize(WxCpDepart group, Type typeOfSrc, JsonSerializationContext context) { | public JsonElement serialize(WxCpDepart group, Type typeOfSrc, JsonSerializationContext context) { | ||||
| JsonObject json = new JsonObject(); | JsonObject json = new JsonObject(); | ||||
| if (group.getId() != null) { | if (group.getId() != null) { | ||||
| json.addProperty("id", group.getId()); | |||||
| json.addProperty(ID, group.getId()); | |||||
| } | } | ||||
| if (group.getName() != null) { | if (group.getName() != null) { | ||||
| json.addProperty("name", group.getName()); | |||||
| json.addProperty(NAME, group.getName()); | |||||
| } | } | ||||
| if (group.getParentId() != null) { | if (group.getParentId() != null) { | ||||
| json.addProperty("parentid", group.getParentId()); | |||||
| json.addProperty(PARENT_ID, group.getParentId()); | |||||
| } | } | ||||
| if (group.getOrder() != null) { | if (group.getOrder() != null) { | ||||
| json.addProperty("order", String.valueOf(group.getOrder())); | |||||
| json.addProperty(ORDER, String.valueOf(group.getOrder())); | |||||
| } | } | ||||
| return json; | return json; | ||||
| } | } | ||||
| @@ -42,17 +54,17 @@ public class WxCpDepartGsonAdapter implements JsonSerializer<WxCpDepart>, JsonDe | |||||
| throws JsonParseException { | throws JsonParseException { | ||||
| WxCpDepart depart = new WxCpDepart(); | WxCpDepart depart = new WxCpDepart(); | ||||
| JsonObject departJson = json.getAsJsonObject(); | 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; | return depart; | ||||
| } | } | ||||
| @@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder; | |||||
| import me.chanjar.weixin.common.bean.menu.WxMenu; | import me.chanjar.weixin.common.bean.menu.WxMenu; | ||||
| import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
| import me.chanjar.weixin.common.util.json.WxErrorAdapter; | 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.WxCpDepart; | ||||
| import me.chanjar.weixin.cp.bean.WxCpMessage; | import me.chanjar.weixin.cp.bean.WxCpMessage; | ||||
| import me.chanjar.weixin.cp.bean.WxCpTag; | import me.chanjar.weixin.cp.bean.WxCpTag; | ||||
| @@ -15,11 +16,12 @@ import me.chanjar.weixin.cp.bean.WxCpUser; | |||||
| */ | */ | ||||
| public class WxCpGsonBuilder { | public class WxCpGsonBuilder { | ||||
| public static final GsonBuilder INSTANCE = new GsonBuilder(); | |||||
| private static final GsonBuilder INSTANCE = new GsonBuilder(); | |||||
| static { | static { | ||||
| INSTANCE.disableHtmlEscaping(); | INSTANCE.disableHtmlEscaping(); | ||||
| INSTANCE.registerTypeAdapter(WxCpMessage.class, new WxCpMessageGsonAdapter()); | INSTANCE.registerTypeAdapter(WxCpMessage.class, new WxCpMessageGsonAdapter()); | ||||
| INSTANCE.registerTypeAdapter(WxCpChat.class, new WxCpChatGsonAdapter()); | |||||
| INSTANCE.registerTypeAdapter(WxCpDepart.class, new WxCpDepartGsonAdapter()); | INSTANCE.registerTypeAdapter(WxCpDepart.class, new WxCpDepartGsonAdapter()); | ||||
| INSTANCE.registerTypeAdapter(WxCpUser.class, new WxCpUserGsonAdapter()); | INSTANCE.registerTypeAdapter(WxCpUser.class, new WxCpUserGsonAdapter()); | ||||
| INSTANCE.registerTypeAdapter(WxError.class, new WxErrorAdapter()); | INSTANCE.registerTypeAdapter(WxError.class, new WxErrorAdapter()); | ||||
| @@ -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); | |||||
| } | |||||
| } | |||||
| @@ -1,15 +1,15 @@ | |||||
| package me.chanjar.weixin.cp.api.impl; | package me.chanjar.weixin.cp.api.impl; | ||||
| import java.util.List; | |||||
| import org.testng.annotations.*; | |||||
| import com.google.inject.Inject; | import com.google.inject.Inject; | ||||
| import me.chanjar.weixin.cp.api.ApiTestModule; | import me.chanjar.weixin.cp.api.ApiTestModule; | ||||
| import me.chanjar.weixin.cp.api.WxCpService; | import me.chanjar.weixin.cp.api.WxCpService; | ||||
| import me.chanjar.weixin.cp.bean.WxCpDepart; | 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.assertj.core.api.Assertions.assertThat; | ||||
| import static org.testng.Assert.*; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -29,7 +29,7 @@ public class WxCpDepartmentServiceImplTest { | |||||
| public void testCreate() throws Exception { | public void testCreate() throws Exception { | ||||
| WxCpDepart cpDepart = new WxCpDepart(); | WxCpDepart cpDepart = new WxCpDepart(); | ||||
| cpDepart.setName("子部门" + System.currentTimeMillis()); | cpDepart.setName("子部门" + System.currentTimeMillis()); | ||||
| cpDepart.setParentId(1); | |||||
| cpDepart.setParentId(1L); | |||||
| cpDepart.setOrder(1L); | cpDepart.setOrder(1L); | ||||
| Integer departId = this.wxCpService.getDepartmentService().create(cpDepart); | Integer departId = this.wxCpService.getDepartmentService().create(cpDepart); | ||||
| System.out.println(departId); | System.out.println(departId); | ||||
| @@ -45,7 +45,7 @@ public class WxCpDepartmentServiceImplTest { | |||||
| } | } | ||||
| @Test(dataProvider = "departIds") | @Test(dataProvider = "departIds") | ||||
| public void testList(Integer id) throws Exception { | |||||
| public void testList(Long id) throws Exception { | |||||
| System.out.println("=================获取部门"); | System.out.println("=================获取部门"); | ||||
| List<WxCpDepart> departList = this.wxCpService.getDepartmentService().list(id); | List<WxCpDepart> departList = this.wxCpService.getDepartmentService().list(id); | ||||
| assertThat(departList).isNotEmpty(); | assertThat(departList).isNotEmpty(); | ||||
| @@ -36,7 +36,8 @@ public class WxCpMediaServiceImplTest { | |||||
| public Object[][] mediaData() { | public Object[][] mediaData() { | ||||
| return new Object[][]{ | return new Object[][]{ | ||||
| new Object[]{WxConsts.MediaFileType.IMAGE, TestConstants.FILE_JPG, "mm.jpeg"}, | 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.VOICE, TestConstants.FILE_AMR, "mm.amr"}, | ||||
| new Object[]{WxConsts.MediaFileType.VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, | new Object[]{WxConsts.MediaFileType.VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, | ||||
| new Object[]{WxConsts.MediaFileType.FILE, TestConstants.FILE_JPG, "mm.jpeg"} | 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 { | public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { | ||||
| try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)) { | try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)) { | ||||
| WxMediaUploadResult res = this.wxService.getMediaService().upload(mediaType, fileType, inputStream); | 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); | assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null); | ||||
| if (res.getMediaId() != null) { | if (res.getMediaId() != null) { | ||||
| @@ -70,9 +72,9 @@ public class WxCpMediaServiceImplTest { | |||||
| } | } | ||||
| @Test(dependsOnMethods = {"testUploadMedia"}, dataProvider = "downloadMedia") | @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); | System.out.println(file); | ||||
| } | } | ||||
| @@ -82,4 +84,11 @@ public class WxCpMediaServiceImplTest { | |||||
| String res = this.wxService.getMediaService().uploadImg(new File(url.getFile())); | String res = this.wxService.getMediaService().uploadImg(new File(url.getFile())); | ||||
| assertThat(res).isNotEmpty(); | assertThat(res).isNotEmpty(); | ||||
| } | } | ||||
| @Test | |||||
| public void testGetJssdkFile() throws WxErrorException { | |||||
| File file = this.wxService.getMediaService().getJssdkFile("...."); | |||||
| assertThat(file).isNotNull(); | |||||
| System.out.println(file); | |||||
| } | |||||
| } | } | ||||
| @@ -74,7 +74,7 @@ public class WxCpUserServiceImplTest { | |||||
| @Test | @Test | ||||
| public void testListByDepartment() throws Exception { | public void testListByDepartment() throws Exception { | ||||
| List<WxCpUser> users = this.wxCpService.getUserService().listByDepartment(1, true, 0); | |||||
| List<WxCpUser> users = this.wxCpService.getUserService().listByDepartment(1L, true, 0); | |||||
| assertNotEquals(users.size(), 0); | assertNotEquals(users.size(), 0); | ||||
| for (WxCpUser user : users) { | for (WxCpUser user : users) { | ||||
| System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); | System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); | ||||
| @@ -83,7 +83,7 @@ public class WxCpUserServiceImplTest { | |||||
| @Test | @Test | ||||
| public void testListSimpleByDepartment() throws Exception { | public void testListSimpleByDepartment() throws Exception { | ||||
| List<WxCpUser> users = this.wxCpService.getUserService().listSimpleByDepartment(1, true, 0); | |||||
| List<WxCpUser> users = this.wxCpService.getUserService().listSimpleByDepartment(1L, true, 0); | |||||
| assertNotEquals(users.size(), 0); | assertNotEquals(users.size(), 0); | ||||
| for (WxCpUser user : users) { | for (WxCpUser user : users) { | ||||
| System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); | System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); | ||||
| @@ -6,11 +6,11 @@ | |||||
| <modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
| <parent> | <parent> | ||||
| <groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
| <artifactId>weixin-java-parent</artifactId> | |||||
| <version>3.2.0</version> | |||||
| <artifactId>wx-java</artifactId> | |||||
| <version>3.3.0</version> | |||||
| </parent> | </parent> | ||||
| <artifactId>weixin-java-miniapp</artifactId> | <artifactId>weixin-java-miniapp</artifactId> | ||||
| <name>Weixin Java Tools - MiniApp</name> | |||||
| <name>WxJava - MiniApp</name> | |||||
| <description>微信小程序Java SDK</description> | <description>微信小程序Java SDK</description> | ||||
| <dependencies> | <dependencies> | ||||
| @@ -15,7 +15,26 @@ public interface WxMaJsapiService { | |||||
| /** | /** | ||||
| * 获得jsapi_ticket的url | * 获得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; | |||||
| /** | |||||
| * <pre> | |||||
| * 获得卡券api_ticket | |||||
| * 获得时会检查apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干 | |||||
| * | |||||
| * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN | |||||
| * </pre> | |||||
| * | |||||
| * @param forceRefresh 强制刷新 | |||||
| */ | |||||
| String getCardApiTicket(boolean forceRefresh) throws WxErrorException; | |||||
| /** | /** | ||||
| * 获得jsapi_ticket,不强制刷新jsapi_ticket | * 获得jsapi_ticket,不强制刷新jsapi_ticket | ||||
| @@ -1,10 +1,10 @@ | |||||
| package cn.binarywang.wx.miniapp.api; | package cn.binarywang.wx.miniapp.api; | ||||
| import java.io.File; | |||||
| import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor; | import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import java.io.File; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 二维码相关操作接口. | * 二维码相关操作接口. | ||||
| @@ -32,24 +32,87 @@ public interface WxMaQrcodeService { | |||||
| * | * | ||||
| * @param path 不能为空,最大长度 128 字节 | * @param path 不能为空,最大长度 128 字节 | ||||
| * @param width 默认430 二维码的宽度 | * @param width 默认430 二维码的宽度 | ||||
| * @return 文件内容字节数组 | |||||
| * @throws WxErrorException 异常 | |||||
| */ | |||||
| byte[] createQrcodeBytes(String path, int width) throws WxErrorException; | |||||
| /** | |||||
| * 接口C: 获取小程序页面二维码. | |||||
| * <pre> | |||||
| * 适用于需要的码数量较少的业务场景 | |||||
| * 通过该接口,仅能生成已发布的小程序的二维码。 | |||||
| * 可以在开发者工具预览时生成开发版的带参二维码。 | |||||
| * 带参二维码只有 100000 个,请谨慎调用。 | |||||
| * </pre> | |||||
| * | |||||
| * @param path 不能为空,最大长度 128 字节 | |||||
| * @param width 默认430 二维码的宽度 | |||||
| * @return 文件对象 | |||||
| * @throws WxErrorException 异常 | |||||
| */ | */ | ||||
| File createQrcode(String path, int width) throws WxErrorException; | File createQrcode(String path, int width) throws WxErrorException; | ||||
| /** | |||||
| * 接口C: 获取小程序页面二维码. | |||||
| * <pre> | |||||
| * 适用于需要的码数量较少的业务场景 | |||||
| * 通过该接口,仅能生成已发布的小程序的二维码。 | |||||
| * 可以在开发者工具预览时生成开发版的带参二维码。 | |||||
| * 带参二维码只有 100000 个,请谨慎调用。 | |||||
| * </pre> | |||||
| * | |||||
| * @param path 不能为空,最大长度 128 字节 | |||||
| * @return 文件对象 | |||||
| * @throws WxErrorException 异常 | |||||
| */ | |||||
| File createQrcode(String path) throws WxErrorException; | File createQrcode(String path) throws WxErrorException; | ||||
| /** | /** | ||||
| * 接口A: 获取小程序码. | * 接口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; | File createWxaCode(String path, int width) throws WxErrorException; | ||||
| /** | |||||
| * 接口A: 获取小程序码. | |||||
| * | |||||
| * @param path 不能为空,最大长度 128 字节 | |||||
| * @return 文件对象 | |||||
| * @throws WxErrorException 异常 | |||||
| */ | |||||
| File createWxaCode(String path) throws WxErrorException; | File createWxaCode(String path) throws WxErrorException; | ||||
| /** | /** | ||||
| @@ -61,15 +124,56 @@ public interface WxMaQrcodeService { | |||||
| * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode | * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode | ||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * @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: 获取小程序码(永久有效、数量暂无限制). | |||||
| * <pre> | |||||
| * 通过该接口生成的小程序码,永久有效,数量暂无限制。 | |||||
| * 用户扫描该码进入小程序后,将统一打开首页,开发者需在对应页面根据获取的码中 scene 字段的值,再做处理逻辑。 | |||||
| * 使用如下代码可以获取到二维码中的 scene 字段的值。 | |||||
| * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode | |||||
| * </pre> | |||||
| * | |||||
| * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~, | |||||
| * 其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) | |||||
| * @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 | * @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 | ||||
| * @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 | * @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 | ||||
| * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 | * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 | ||||
| * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} | * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} | ||||
| * @param isHyaline 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码 | * @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: 获取小程序码(永久有效、数量暂无限制). | |||||
| * <pre> | |||||
| * 通过该接口生成的小程序码,永久有效,数量暂无限制。 | |||||
| * 用户扫描该码进入小程序后,将统一打开首页,开发者需在对应页面根据获取的码中 scene 字段的值,再做处理逻辑。 | |||||
| * 使用如下代码可以获取到二维码中的 scene 字段的值。 | |||||
| * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode | |||||
| * </pre> | |||||
| * | |||||
| * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~, | |||||
| * 其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) | |||||
| * @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 | |||||
| * @return 文件对象 | |||||
| * @throws WxErrorException 异常 | |||||
| */ | |||||
| File createWxaCodeUnlimit(String scene, String page) throws WxErrorException; | File createWxaCodeUnlimit(String scene, String page) throws WxErrorException; | ||||
| } | } | ||||
| @@ -0,0 +1,24 @@ | |||||
| package cn.binarywang.wx.miniapp.api; | |||||
| import java.util.List; | |||||
| import cn.binarywang.wx.miniapp.bean.WxMaRunStepInfo; | |||||
| /** | |||||
| * 微信运动相关操作接口. | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| public interface WxMaRunService { | |||||
| /** | |||||
| * 解密分享敏感数据. | |||||
| * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/werun/wx.getWeRunData.html | |||||
| * | |||||
| * @param sessionKey 会话密钥 | |||||
| * @param encryptedData 消息密文 | |||||
| * @param ivStr 加密算法的初始向量 | |||||
| */ | |||||
| List<WxMaRunStepInfo> getRunStepInfo(String sessionKey, String encryptedData, String ivStr); | |||||
| } | |||||
| @@ -0,0 +1,43 @@ | |||||
| package cn.binarywang.wx.miniapp.api; | |||||
| import java.io.File; | |||||
| import me.chanjar.weixin.common.error.WxErrorException; | |||||
| /** | |||||
| * <pre> | |||||
| * 内容安全相关接口. | |||||
| * Created by Binary Wang on 2018/11/24. | |||||
| * </pre> | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| 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"; | |||||
| /** | |||||
| * <pre> | |||||
| * 校验一张图片是否含有违法违规内容. | |||||
| * 应用场景举例: | |||||
| * 1)图片智能鉴黄:涉及拍照的工具类应用(如美拍,识图类应用)用户拍照上传检测;电商类商品上架图片检测;媒体类用户文章里的图片检测等; | |||||
| * 2)敏感人脸识别:用户头像;媒体类用户文章里的图片检测;社交类用户上传的图片检测等。频率限制:单个 appId 调用上限为 1000 次/分钟,100,000 次/天 | |||||
| * 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/imgSecCheck.html | |||||
| * </pre> | |||||
| */ | |||||
| boolean checkImage(File file) throws WxErrorException; | |||||
| /** | |||||
| * <pre> | |||||
| * 检查一段文本是否含有违法违规内容。 | |||||
| * 应用场景举例: | |||||
| * 用户个人资料违规文字检测; | |||||
| * 媒体新闻类用户发表文章,评论内容检测; | |||||
| * 游戏类用户编辑上传的素材(如答题类小游戏用户上传的问题及答案)检测等。 频率限制:单个 appId 调用上限为 4000 次/分钟,2,000,000 次/天* | |||||
| * 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/msgSecCheck.html | |||||
| * </pre> | |||||
| */ | |||||
| boolean checkMessage(String msgString); | |||||
| } | |||||
| @@ -1,7 +1,5 @@ | |||||
| package cn.binarywang.wx.miniapp.api; | package cn.binarywang.wx.miniapp.api; | ||||
| import java.io.File; | |||||
| import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | ||||
| import cn.binarywang.wx.miniapp.config.WxMaConfig; | import cn.binarywang.wx.miniapp.config.WxMaConfig; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | 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 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"; | |||||
| /** | |||||
| * <pre> | |||||
| * 校验一张图片是否含有违法违规内容. | |||||
| * 应用场景举例:1)图片智能鉴黄:涉及拍照的工具类应用(如美拍,识图类应用)用户拍照上传检测;电商类商品上架图片检测;媒体类用户文章里的图片检测等;2)敏感人脸识别:用户头像;媒体类用户文章里的图片检测;社交类用户上传的图片检测等。频率限制:单个 appId 调用上限为 1000 次/分钟,100,000 次/天 | |||||
| * 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/imgSecCheck.html | |||||
| * </pre> | |||||
| */ | |||||
| boolean imgSecCheck(File file) throws WxErrorException; | |||||
| /** | /** | ||||
| * 获取登录后的session信息. | * 获取登录后的session信息. | ||||
| * | * | ||||
| @@ -152,33 +139,51 @@ public interface WxMaService { | |||||
| WxMaTemplateService getTemplateService(); | WxMaTemplateService getTemplateService(); | ||||
| /** | /** | ||||
| * 数据分析相关查询服务 | |||||
| * 数据分析相关查询服务. | |||||
| * | * | ||||
| * @return WxMaAnalysisService | * @return WxMaAnalysisService | ||||
| */ | */ | ||||
| WxMaAnalysisService getAnalysisService(); | WxMaAnalysisService getAnalysisService(); | ||||
| /** | /** | ||||
| * 返回代码操作相关的 API | |||||
| * 返回代码操作相关的 API. | |||||
| * | * | ||||
| * @return WxMaCodeService | * @return WxMaCodeService | ||||
| */ | */ | ||||
| WxMaCodeService getCodeService(); | WxMaCodeService getCodeService(); | ||||
| /** | /** | ||||
| * 返回jsapi操作相关的 API服务类对象 | |||||
| * 返回jsapi操作相关的 API服务类对象. | |||||
| * | * | ||||
| * @return WxMaJsapiService | * @return WxMaJsapiService | ||||
| */ | */ | ||||
| WxMaJsapiService getJsapiService(); | WxMaJsapiService getJsapiService(); | ||||
| /** | /** | ||||
| * 小程序修改服务器地址、成员管理 API | |||||
| * 小程序修改服务器地址、成员管理 API. | |||||
| * | * | ||||
| * @return WxMaSettingService | * @return WxMaSettingService | ||||
| */ | */ | ||||
| WxMaSettingService getSettingService(); | WxMaSettingService getSettingService(); | ||||
| /** | |||||
| * 返回分享相关查询服务. | |||||
| * @return WxMaShareService | |||||
| */ | |||||
| WxMaShareService getShareService(); | |||||
| /** | |||||
| * 返回微信运动相关接口服务对象. | |||||
| * @return WxMaShareService | |||||
| */ | |||||
| WxMaRunService getRunService(); | |||||
| /** | |||||
| * 返回内容安全相关接口服务对象. | |||||
| * @return WxMaShareService | |||||
| */ | |||||
| WxMaSecCheckService getSecCheckService(); | |||||
| /** | /** | ||||
| * 初始化http请求对象. | * 初始化http请求对象. | ||||
| */ | */ | ||||
| @@ -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); | |||||
| } | |||||
| @@ -28,6 +28,32 @@ public class WxMaJsapiServiceImpl implements WxMaJsapiService { | |||||
| this.wxMaService = wxMaService; | 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 | @Override | ||||
| public String getJsapiTicket() throws WxErrorException { | public String getJsapiTicket() throws WxErrorException { | ||||
| return getJsapiTicket(false); | return getJsapiTicket(false); | ||||
| @@ -43,7 +69,7 @@ public class WxMaJsapiServiceImpl implements WxMaJsapiService { | |||||
| } | } | ||||
| if (this.wxMaService.getWxMaConfig().isJsapiTicketExpired()) { | 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); | JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); | ||||
| JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); | JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); | ||||
| String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); | String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); | ||||
| @@ -1,16 +1,17 @@ | |||||
| package cn.binarywang.wx.miniapp.api.impl; | package cn.binarywang.wx.miniapp.api.impl; | ||||
| import java.io.File; | |||||
| import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; | import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; | ||||
| import cn.binarywang.wx.miniapp.api.WxMaService; | import cn.binarywang.wx.miniapp.api.WxMaService; | ||||
| import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor; | import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor; | ||||
| import cn.binarywang.wx.miniapp.bean.WxMaQrcode; | 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.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 me.chanjar.weixin.common.error.WxErrorException; | ||||
| import java.io.File; | |||||
| /** | /** | ||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| @@ -21,10 +22,16 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { | |||||
| this.wxMaService = wxMaService; | 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 | @Override | ||||
| public File createQrcode(String path, int width) throws WxErrorException { | 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 | @Override | ||||
| @@ -33,15 +40,29 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { | |||||
| } | } | ||||
| @Override | @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 | @Override | ||||
| @@ -51,12 +72,27 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { | |||||
| @Override | @Override | ||||
| public File createWxaCode(String path) throws WxErrorException { | public File createWxaCode(String path) throws WxErrorException { | ||||
| return this.createWxaCode(path, 430, true, null, false); | |||||
| return this.createWxaCode(path, 430); | |||||
| } | } | ||||
| @Override | @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 wxaCodeUnlimit = new WxaCodeUnlimit(); | ||||
| wxaCodeUnlimit.setScene(scene); | wxaCodeUnlimit.setScene(scene); | ||||
| wxaCodeUnlimit.setPage(page); | wxaCodeUnlimit.setPage(page); | ||||
| @@ -64,8 +100,8 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { | |||||
| wxaCodeUnlimit.setAutoColor(autoColor); | wxaCodeUnlimit.setAutoColor(autoColor); | ||||
| wxaCodeUnlimit.setLineColor(lineColor); | wxaCodeUnlimit.setLineColor(lineColor); | ||||
| wxaCodeUnlimit.setHyaline(isHyaline); | wxaCodeUnlimit.setHyaline(isHyaline); | ||||
| return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), | |||||
| GET_WXACODE_UNLIMIT_URL, wxaCodeUnlimit); | |||||
| return wxaCodeUnlimit; | |||||
| } | } | ||||
| @Override | @Override | ||||
| @@ -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; | |||||
| /** | |||||
| * <pre> | |||||
| * | |||||
| * Created by Binary Wang on 2018/11/4. | |||||
| * </pre> | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| public class WxMaRunServiceImpl implements WxMaRunService { | |||||
| private WxMaService service; | |||||
| public WxMaRunServiceImpl(WxMaService service) { | |||||
| this.service = service; | |||||
| } | |||||
| @Override | |||||
| public List<WxMaRunStepInfo> getRunStepInfo(String sessionKey, String encryptedData, String ivStr) { | |||||
| return WxMaRunStepInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)); | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| /** | |||||
| * <pre> | |||||
| * | |||||
| * Created by Binary Wang on 2018/11/24. | |||||
| * </pre> | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| 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; | |||||
| } | |||||
| } | |||||
| @@ -1,6 +1,5 @@ | |||||
| package cn.binarywang.wx.miniapp.api.impl; | package cn.binarywang.wx.miniapp.api.impl; | ||||
| import java.io.File; | |||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.util.HashMap; | import java.util.HashMap; | ||||
| import java.util.Map; | 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.client.methods.HttpGet; | ||||
| import org.apache.http.impl.client.BasicResponseHandler; | import org.apache.http.impl.client.BasicResponseHandler; | ||||
| import org.apache.http.impl.client.CloseableHttpClient; | 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.WxMaAnalysisService; | ||||
| import cn.binarywang.wx.miniapp.api.WxMaCodeService; | 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.WxMaMediaService; | ||||
| import cn.binarywang.wx.miniapp.api.WxMaMsgService; | import cn.binarywang.wx.miniapp.api.WxMaMsgService; | ||||
| import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; | 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.WxMaService; | ||||
| import cn.binarywang.wx.miniapp.api.WxMaSettingService; | 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.WxMaTemplateService; | ||||
| import cn.binarywang.wx.miniapp.api.WxMaUserService; | import cn.binarywang.wx.miniapp.api.WxMaUserService; | ||||
| import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | ||||
| import cn.binarywang.wx.miniapp.config.WxMaConfig; | import cn.binarywang.wx.miniapp.config.WxMaConfig; | ||||
| import com.google.common.base.Joiner; | import com.google.common.base.Joiner; | ||||
| import com.google.gson.Gson; | import com.google.gson.Gson; | ||||
| import lombok.extern.slf4j.Slf4j; | |||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | 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.WxError; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.common.util.DataUtils; | import me.chanjar.weixin.common.util.DataUtils; | ||||
| import me.chanjar.weixin.common.util.crypto.SHA1; | import me.chanjar.weixin.common.util.crypto.SHA1; | ||||
| import me.chanjar.weixin.common.util.http.HttpType; | 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.RequestExecutor; | ||||
| import me.chanjar.weixin.common.util.http.RequestHttp; | import me.chanjar.weixin.common.util.http.RequestHttp; | ||||
| import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | ||||
| @@ -49,9 +48,8 @@ import static cn.binarywang.wx.miniapp.constant.WxMaConstants.ErrorCode.*; | |||||
| /** | /** | ||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| @Slf4j | |||||
| public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpClient, HttpHost> { | public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpClient, HttpHost> { | ||||
| private final Logger log = LoggerFactory.getLogger(this.getClass()); | |||||
| private CloseableHttpClient httpClient; | private CloseableHttpClient httpClient; | ||||
| private HttpHost httpProxy; | private HttpHost httpProxy; | ||||
| private WxMaConfig wxMaConfig; | private WxMaConfig wxMaConfig; | ||||
| @@ -65,6 +63,9 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
| private WxMaCodeService codeService = new WxMaCodeServiceImpl(this); | private WxMaCodeService codeService = new WxMaCodeServiceImpl(this); | ||||
| private WxMaSettingService settingService = new WxMaSettingServiceImpl(this); | private WxMaSettingService settingService = new WxMaSettingServiceImpl(this); | ||||
| private WxMaJsapiService jsapiService = new WxMaJsapiServiceImpl(this); | private WxMaJsapiService jsapiService = new WxMaJsapiServiceImpl(this); | ||||
| private WxMaShareService shareService = new WxMaShareServiceImpl(this); | |||||
| private WxMaRunService runService = new WxMaRunServiceImpl(this); | |||||
| private WxMaSecCheckService secCheckService = new WxMaSecCheckServiceImpl(this); | |||||
| private int retrySleepMillis = 1000; | private int retrySleepMillis = 1000; | ||||
| private int maxRetryTimes = 5; | private int maxRetryTimes = 5; | ||||
| @@ -149,13 +150,6 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
| return this.getWxMaConfig().getAccessToken(); | return this.getWxMaConfig().getAccessToken(); | ||||
| } | } | ||||
| @Override | |||||
| public boolean imgSecCheck(File file) throws WxErrorException { | |||||
| //这里只是借用MediaUploadRequestExecutor,并不使用其返回值WxMediaUploadResult | |||||
| WxMediaUploadResult result = this.execute(MediaUploadRequestExecutor.create(this.getRequestHttp()), IMG_SEC_CHECK_URL, file); | |||||
| return result != null; | |||||
| } | |||||
| @Override | @Override | ||||
| public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException { | public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException { | ||||
| final WxMaConfig config = getWxMaConfig(); | final WxMaConfig config = getWxMaConfig(); | ||||
| @@ -205,7 +199,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
| return this.executeInternal(executor, uri, data); | return this.executeInternal(executor, uri, data); | ||||
| } catch (WxErrorException e) { | } catch (WxErrorException e) { | ||||
| if (retryTimes + 1 > this.maxRetryTimes) { | if (retryTimes + 1 > this.maxRetryTimes) { | ||||
| this.log.warn("重试达到最大次数【{}】", maxRetryTimes); | |||||
| log.warn("重试达到最大次数【{}】", maxRetryTimes); | |||||
| //最后一次重试失败后,直接抛出异常,不再等待 | //最后一次重试失败后,直接抛出异常,不再等待 | ||||
| throw new RuntimeException("微信服务端异常,超出重试次数"); | throw new RuntimeException("微信服务端异常,超出重试次数"); | ||||
| } | } | ||||
| @@ -215,10 +209,10 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
| if (error.getErrorCode() == -1) { | if (error.getErrorCode() == -1) { | ||||
| int sleepMillis = this.retrySleepMillis * (1 << retryTimes); | int sleepMillis = this.retrySleepMillis * (1 << retryTimes); | ||||
| try { | try { | ||||
| this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); | |||||
| log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); | |||||
| Thread.sleep(sleepMillis); | Thread.sleep(sleepMillis); | ||||
| } catch (InterruptedException e1) { | } catch (InterruptedException e1) { | ||||
| throw new RuntimeException(e1); | |||||
| Thread.currentThread().interrupt(); | |||||
| } | } | ||||
| } else { | } else { | ||||
| throw e; | throw e; | ||||
| @@ -226,7 +220,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
| } | } | ||||
| } while (retryTimes++ < this.maxRetryTimes); | } while (retryTimes++ < this.maxRetryTimes); | ||||
| this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); | |||||
| log.warn("重试达到最大次数【{}】", this.maxRetryTimes); | |||||
| throw new RuntimeException("微信服务端异常,超出重试次数"); | throw new RuntimeException("微信服务端异常,超出重试次数"); | ||||
| } | } | ||||
| @@ -242,7 +236,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
| try { | try { | ||||
| T result = executor.execute(uriWithAccessToken, data); | T result = executor.execute(uriWithAccessToken, data); | ||||
| this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result); | |||||
| log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result); | |||||
| return result; | return result; | ||||
| } catch (WxErrorException e) { | } catch (WxErrorException e) { | ||||
| WxError error = e.getError(); | WxError error = e.getError(); | ||||
| @@ -260,12 +254,12 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
| } | } | ||||
| if (error.getErrorCode() != 0) { | if (error.getErrorCode() != 0) { | ||||
| this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error); | |||||
| log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error); | |||||
| throw new WxErrorException(error, e); | throw new WxErrorException(error, e); | ||||
| } | } | ||||
| return null; | return null; | ||||
| } catch (IOException e) { | } catch (IOException e) { | ||||
| this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage()); | |||||
| log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage()); | |||||
| throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
| } | } | ||||
| } | } | ||||
| @@ -335,4 +329,19 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
| public WxMaSettingService getSettingService() { | public WxMaSettingService getSettingService() { | ||||
| return this.settingService; | return this.settingService; | ||||
| } | } | ||||
| @Override | |||||
| public WxMaShareService getShareService() { | |||||
| return this.shareService; | |||||
| } | |||||
| @Override | |||||
| public WxMaRunService getRunService() { | |||||
| return this.runService; | |||||
| } | |||||
| @Override | |||||
| public WxMaSecCheckService getSecCheckService() { | |||||
| return this.secCheckService; | |||||
| } | |||||
| } | } | ||||
| @@ -0,0 +1,23 @@ | |||||
| package cn.binarywang.wx.miniapp.api.impl; | |||||
| import cn.binarywang.wx.miniapp.api.WxMaService; | |||||
| import cn.binarywang.wx.miniapp.api.WxMaShareService; | |||||
| import cn.binarywang.wx.miniapp.bean.WxMaShareInfo; | |||||
| import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; | |||||
| /** | |||||
| * @author zhfish | |||||
| */ | |||||
| public class WxMaShareServiceImpl implements WxMaShareService { | |||||
| private WxMaService service; | |||||
| public WxMaShareServiceImpl(WxMaService service) { | |||||
| this.service = service; | |||||
| } | |||||
| @Override | |||||
| public WxMaShareInfo getShareInfo(String sessionKey, String encryptedData, String ivStr) { | |||||
| return WxMaShareInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)); | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,9 @@ | |||||
| package cn.binarywang.wx.miniapp.api.impl; | package cn.binarywang.wx.miniapp.api.impl; | ||||
| import java.util.HashMap; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import cn.binarywang.wx.miniapp.api.WxMaService; | import cn.binarywang.wx.miniapp.api.WxMaService; | ||||
| import cn.binarywang.wx.miniapp.api.WxMaTemplateService; | import cn.binarywang.wx.miniapp.api.WxMaTemplateService; | ||||
| import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateAddResult; | import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateAddResult; | ||||
| @@ -10,15 +14,11 @@ import me.chanjar.weixin.common.error.WxError; | |||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
| import java.util.HashMap; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| public class WxMaTemplateServiceImpl implements WxMaTemplateService { | public class WxMaTemplateServiceImpl implements WxMaTemplateService { | ||||
| private WxMaService wxMaService; | private WxMaService wxMaService; | ||||
| public WxMaTemplateServiceImpl(WxMaService wxMaService){ | |||||
| public WxMaTemplateServiceImpl(WxMaService wxMaService) { | |||||
| this.wxMaService = wxMaService; | this.wxMaService = wxMaService; | ||||
| } | } | ||||
| @@ -31,9 +31,9 @@ public class WxMaTemplateServiceImpl implements WxMaTemplateService { | |||||
| String responseText = this.wxMaService.post(TEMPLATE_LIBRARY_LIST_URL, WxGsonBuilder.create().toJson(params)); | String responseText = this.wxMaService.post(TEMPLATE_LIBRARY_LIST_URL, WxGsonBuilder.create().toJson(params)); | ||||
| WxError wxError = WxError.fromJson(responseText); | WxError wxError = WxError.fromJson(responseText); | ||||
| if(wxError.getErrorCode() == 0){ | |||||
| if (wxError.getErrorCode() == 0) { | |||||
| return WxMaTemplateLibraryListResult.fromJson(responseText); | return WxMaTemplateLibraryListResult.fromJson(responseText); | ||||
| }else { | |||||
| } else { | |||||
| throw new WxErrorException(wxError); | throw new WxErrorException(wxError); | ||||
| } | } | ||||
| } | } | ||||
| @@ -46,9 +46,9 @@ public class WxMaTemplateServiceImpl implements WxMaTemplateService { | |||||
| String responseText = this.wxMaService.post(TEMPLATE_LIBRARY_KEYWORD_URL, WxGsonBuilder.create().toJson(params)); | String responseText = this.wxMaService.post(TEMPLATE_LIBRARY_KEYWORD_URL, WxGsonBuilder.create().toJson(params)); | ||||
| WxError wxError = WxError.fromJson(responseText); | WxError wxError = WxError.fromJson(responseText); | ||||
| if(wxError.getErrorCode() == 0){ | |||||
| if (wxError.getErrorCode() == 0) { | |||||
| return WxMaTemplateLibraryGetResult.fromJson(responseText); | return WxMaTemplateLibraryGetResult.fromJson(responseText); | ||||
| }else { | |||||
| } else { | |||||
| throw new WxErrorException(wxError); | throw new WxErrorException(wxError); | ||||
| } | } | ||||
| } | } | ||||
| @@ -62,9 +62,9 @@ public class WxMaTemplateServiceImpl implements WxMaTemplateService { | |||||
| String responseText = this.wxMaService.post(TEMPLATE_ADD_URL, WxGsonBuilder.create().toJson(params)); | String responseText = this.wxMaService.post(TEMPLATE_ADD_URL, WxGsonBuilder.create().toJson(params)); | ||||
| WxError wxError = WxError.fromJson(responseText); | WxError wxError = WxError.fromJson(responseText); | ||||
| if(wxError.getErrorCode() == 0){ | |||||
| if (wxError.getErrorCode() == 0) { | |||||
| return WxMaTemplateAddResult.fromJson(responseText); | return WxMaTemplateAddResult.fromJson(responseText); | ||||
| }else { | |||||
| } else { | |||||
| throw new WxErrorException(wxError); | throw new WxErrorException(wxError); | ||||
| } | } | ||||
| } | } | ||||
| @@ -78,9 +78,9 @@ public class WxMaTemplateServiceImpl implements WxMaTemplateService { | |||||
| String responseText = this.wxMaService.post(TEMPLATE_LIST_URL, WxGsonBuilder.create().toJson(params)); | String responseText = this.wxMaService.post(TEMPLATE_LIST_URL, WxGsonBuilder.create().toJson(params)); | ||||
| WxError wxError = WxError.fromJson(responseText); | WxError wxError = WxError.fromJson(responseText); | ||||
| if(wxError.getErrorCode() == 0){ | |||||
| if (wxError.getErrorCode() == 0) { | |||||
| return WxMaTemplateListResult.fromJson(responseText); | return WxMaTemplateListResult.fromJson(responseText); | ||||
| }else { | |||||
| } else { | |||||
| throw new WxErrorException(wxError); | throw new WxErrorException(wxError); | ||||
| } | } | ||||
| } | } | ||||
| @@ -92,9 +92,9 @@ public class WxMaTemplateServiceImpl implements WxMaTemplateService { | |||||
| String responseText = this.wxMaService.post(TEMPLATE_DEL_URL, WxGsonBuilder.create().toJson(params)); | String responseText = this.wxMaService.post(TEMPLATE_DEL_URL, WxGsonBuilder.create().toJson(params)); | ||||
| WxError wxError = WxError.fromJson(responseText); | WxError wxError = WxError.fromJson(responseText); | ||||
| if(wxError.getErrorCode() == 0){ | |||||
| if (wxError.getErrorCode() == 0) { | |||||
| return true; | return true; | ||||
| }else { | |||||
| } else { | |||||
| throw new WxErrorException(wxError); | throw new WxErrorException(wxError); | ||||
| } | } | ||||
| } | } | ||||
| @@ -6,8 +6,6 @@ import java.io.Serializable; | |||||
| import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||
| import org.apache.commons.io.IOUtils; | import org.apache.commons.io.IOUtils; | ||||
| import org.apache.commons.lang3.builder.ToStringBuilder; | |||||
| import org.apache.commons.lang3.builder.ToStringStyle; | |||||
| import cn.binarywang.wx.miniapp.config.WxMaConfig; | import cn.binarywang.wx.miniapp.config.WxMaConfig; | ||||
| import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; | import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; | ||||
| @@ -168,7 +166,7 @@ public class WxMaMessage implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return this.toJson(); | |||||
| } | } | ||||
| public String toJson() { | public String toJson() { | ||||
| @@ -0,0 +1,38 @@ | |||||
| package cn.binarywang.wx.miniapp.bean; | |||||
| import java.io.Serializable; | |||||
| import java.util.List; | |||||
| import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||||
| import com.google.gson.JsonObject; | |||||
| import com.google.gson.JsonParser; | |||||
| import com.google.gson.reflect.TypeToken; | |||||
| import lombok.Data; | |||||
| /** | |||||
| * 微信运动步数信息. | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| @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<WxMaRunStepInfo> fromJson(String json) { | |||||
| JsonObject jsonObject = JSON_PARSER.parse(json).getAsJsonObject(); | |||||
| return WxMaGsonBuilder.create().fromJson(jsonObject.get("stepInfoList").toString(), | |||||
| new TypeToken<List<WxMaRunStepInfo>>() { | |||||
| }.getType()); | |||||
| } | |||||
| } | |||||
| @@ -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); | |||||
| } | |||||
| } | |||||
| @@ -1,36 +1,48 @@ | |||||
| package cn.binarywang.wx.miniapp.bean; | package cn.binarywang.wx.miniapp.bean; | ||||
| import java.io.Serializable; | |||||
| import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | ||||
| import com.google.gson.annotations.SerializedName; | import com.google.gson.annotations.SerializedName; | ||||
| import lombok.AllArgsConstructor; | |||||
| import lombok.Builder; | |||||
| import lombok.Data; | import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | import lombok.EqualsAndHashCode; | ||||
| import java.io.Serializable; | |||||
| import lombok.NoArgsConstructor; | |||||
| /** | /** | ||||
| * 小程序码. | |||||
| * | * | ||||
| * @author Element | * @author Element | ||||
| * @date 2017/7/27 | * @date 2017/7/27 | ||||
| */ | */ | ||||
| @Data | @Data | ||||
| @EqualsAndHashCode(callSuper = false) | @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 static final long serialVersionUID = 1287399621649210322L; | ||||
| private String path; | private String path; | ||||
| @Builder.Default | |||||
| private int width = 430; | private int width = 430; | ||||
| @SerializedName("auto_color") | @SerializedName("auto_color") | ||||
| @Builder.Default | |||||
| private boolean autoColor = true; | private boolean autoColor = true; | ||||
| @SerializedName("is_hyaline") | @SerializedName("is_hyaline") | ||||
| @Builder.Default | |||||
| private boolean isHyaline = false; | private boolean isHyaline = false; | ||||
| @SerializedName("line_color") | @SerializedName("line_color") | ||||
| @Builder.Default | |||||
| private WxMaCodeLineColor lineColor = new WxMaCodeLineColor("0", "0", "0"); | 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); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,10 +1,10 @@ | |||||
| package cn.binarywang.wx.miniapp.config; | package cn.binarywang.wx.miniapp.config; | ||||
| import java.util.concurrent.locks.Lock; | |||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
| import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | 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); | 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 getAppid(); | ||||
| String getSecret(); | String getSecret(); | ||||
| @@ -4,9 +4,7 @@ import java.io.File; | |||||
| import java.util.concurrent.locks.Lock; | import java.util.concurrent.locks.Lock; | ||||
| import java.util.concurrent.locks.ReentrantLock; | 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.bean.WxAccessToken; | ||||
| import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | ||||
| @@ -32,8 +30,14 @@ public class WxMaInMemoryConfig implements WxMaConfig { | |||||
| protected volatile String jsapiTicket; | protected volatile String jsapiTicket; | ||||
| protected volatile long jsapiTicketExpiresTime; | protected volatile long jsapiTicketExpiresTime; | ||||
| //微信卡券的ticket单独缓存 | |||||
| protected volatile String cardApiTicket; | |||||
| protected volatile long cardApiTicketExpiresTime; | |||||
| protected Lock accessTokenLock = new ReentrantLock(); | protected Lock accessTokenLock = new ReentrantLock(); | ||||
| protected Lock jsapiTicketLock = 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; | 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 | @Override | ||||
| public void expireAccessToken() { | public void expireAccessToken() { | ||||
| this.expiresTime = 0; | this.expiresTime = 0; | ||||
| @@ -191,7 +223,7 @@ public class WxMaInMemoryConfig implements WxMaConfig { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
| return WxMaGsonBuilder.create().toJson(this); | |||||
| } | } | ||||
| @Override | @Override | ||||
| @@ -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 <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| public class QrcodeBytesRequestExecutor implements RequestExecutor<byte[], AbstractWxMaQrcodeWrapper> { | |||||
| protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp; | |||||
| public QrcodeBytesRequestExecutor(RequestHttp requestHttp) { | |||||
| this.requestHttp = requestHttp; | |||||
| } | |||||
| @Override | |||||
| public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler<byte[]> 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(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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.Header; | ||||
| import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
| import org.apache.http.client.config.RequestConfig; | 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.entity.StringEntity; | ||||
| import org.apache.http.impl.client.CloseableHttpClient; | 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 <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| public class QrCodeRequestExecutor implements RequestExecutor<File, AbstractWxMaQrcodeWrapper> { | |||||
| public class QrcodeRequestExecutor implements RequestExecutor<File, AbstractWxMaQrcodeWrapper> { | |||||
| protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp; | protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp; | ||||
| public QrCodeRequestExecutor(RequestHttp requestHttp) { | |||||
| public QrcodeRequestExecutor(RequestHttp requestHttp) { | |||||
| this.requestHttp = requestHttp; | this.requestHttp = requestHttp; | ||||
| } | } | ||||
| @Override | @Override | ||||
| public File execute(String uri, AbstractWxMaQrcodeWrapper ticket) throws WxErrorException, IOException { | |||||
| public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler<File> 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); | HttpPost httpPost = new HttpPost(uri); | ||||
| if (requestHttp.getRequestHttpProxy() != null) { | if (requestHttp.getRequestHttpProxy() != null) { | ||||
| httpPost.setConfig( | httpPost.setConfig( | ||||
| RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build() | 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"); | Header[] contentTypeHeader = response.getHeaders("Content-Type"); | ||||
| if (contentTypeHeader != null && contentTypeHeader.length > 0 | if (contentTypeHeader != null && contentTypeHeader.length > 0 | ||||
| && ContentType.APPLICATION_JSON.getMimeType() | && ContentType.APPLICATION_JSON.getMimeType() | ||||
| @@ -7,6 +7,9 @@ import org.testng.annotations.*; | |||||
| import cn.binarywang.wx.miniapp.api.WxMaService; | import cn.binarywang.wx.miniapp.api.WxMaService; | ||||
| import cn.binarywang.wx.miniapp.test.ApiTestModule; | import cn.binarywang.wx.miniapp.test.ApiTestModule; | ||||
| import com.google.inject.Inject; | import com.google.inject.Inject; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | |||||
| import static org.assertj.core.api.Assertions.assertThat; | |||||
| /** | /** | ||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| @@ -18,21 +21,38 @@ public class WxMaQrcodeServiceImplTest { | |||||
| private WxMaService wxService; | private WxMaService wxService; | ||||
| @Test | @Test | ||||
| public void testCreateQrCode() throws Exception { | |||||
| public void testCreateQrcode() throws Exception { | |||||
| final File qrCode = this.wxService.getQrcodeService().createQrcode("111", 122); | final File qrCode = this.wxService.getQrcodeService().createQrcode("111", 122); | ||||
| System.out.println(qrCode); | |||||
| assertThat(qrCode).isNotNull(); | |||||
| } | } | ||||
| @Test | @Test | ||||
| public void testCreateWxaCode() throws Exception { | public void testCreateWxaCode() throws Exception { | ||||
| final File wxCode = this.wxService.getQrcodeService().createWxaCode("111", 122); | final File wxCode = this.wxService.getQrcodeService().createWxaCode("111", 122); | ||||
| System.out.println(wxCode); | |||||
| assertThat(wxCode).isNotNull(); | |||||
| } | } | ||||
| @Test | @Test | ||||
| public void testCreateWxaCodeUnlimit() throws Exception { | public void testCreateWxaCodeUnlimit() throws Exception { | ||||
| final File wxCode = this.wxService.getQrcodeService().createWxaCodeUnlimit("111", null); | 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(); | |||||
| } | |||||
| } | } | ||||
| @@ -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.*; | |||||
| /** | |||||
| * <pre> | |||||
| * | |||||
| * Created by Binary Wang on 2018/11/24. | |||||
| * </pre> | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| @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); | |||||
| } | |||||
| } | |||||
| @@ -33,9 +33,4 @@ public class WxMaServiceImplTest { | |||||
| assertTrue(StringUtils.isNotBlank(after)); | assertTrue(StringUtils.isNotBlank(after)); | ||||
| } | } | ||||
| @Test | |||||
| public void testImgSecCheck() throws WxErrorException { | |||||
| boolean result = this.wxService.imgSecCheck(new File(ClassLoader.getSystemResource("tmp.png").getFile())); | |||||
| assertTrue(result); | |||||
| } | |||||
| } | } | ||||
| @@ -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()); | |||||
| } | |||||
| } | |||||
| @@ -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.*; | |||||
| /** | |||||
| * <pre> | |||||
| * | |||||
| * Created by Binary Wang on 2018/11/4. | |||||
| * </pre> | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| 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<WxMaRunStepInfo> 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); | |||||
| } | |||||
| } | |||||