mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-03-10 00:13:40 +08:00
Merge branch 'develop'
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -53,3 +53,6 @@ sonar-project.properties
|
||||
|
||||
!/.mvn/wrapper/maven-wrapper.jar
|
||||
*.versionsBackup
|
||||
|
||||
# STS
|
||||
.factorypath
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
- (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。
|
||||
|
||||
### PR方式贡献代码步骤
|
||||
* 在 GitHub 上 `fork` 到自己的仓库,如 `my_user/weixin-java-tools`,然后 `clone` 到本地,并设置用户信息。
|
||||
* 在 GitHub 上 `fork` 到自己的仓库,如 `my_user/WxJava`,然后 `clone` 到本地,并设置用户信息。
|
||||
|
||||
```bash
|
||||
$ git clone git@github.com:my_user/weixin-java-tools.git
|
||||
$ git clone git@github.com:my_user/WxJava.git
|
||||
$ cd weixin-java-tools
|
||||
$ git config user.name "yourname"
|
||||
$ git config user.email "your email"
|
||||
@@ -27,7 +27,7 @@ $ git push
|
||||
* 定期使用项目仓库内容更新自己仓库内容。
|
||||
|
||||
```bash
|
||||
$ git remote add upstream https://github.com/wechat-group/weixin-java-tools
|
||||
$ git remote add upstream https://github.com/Wechat-Group/WxJava
|
||||
$ git fetch upstream
|
||||
$ git checkout develop
|
||||
$ git rebase upstream/develop
|
||||
|
||||
15
pom.xml
15
pom.xml
@@ -5,12 +5,12 @@
|
||||
xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<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>
|
||||
<name>Weixin Java Tools - Parent</name>
|
||||
<name>WxJava - Weixin/Wechat Java SDK</name>
|
||||
<description>微信开发Java SDK</description>
|
||||
<url>https://github.com/wechat-group/weixin-java-tools</url>
|
||||
<url>https://github.com/Wechat-Group/WxJava</url>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
@@ -85,6 +85,11 @@
|
||||
<email>007gzs@gmail.com</email>
|
||||
<url>https://github.com/007gzs</url>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Howard Liu</name>
|
||||
<email>liuxinghao1988@gmail.com</email>
|
||||
<url>https://github.com/howardliu-cn</url>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
@@ -166,7 +171,7 @@
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
<version>1.4.9</version>
|
||||
<version>1.4.10</version>
|
||||
</dependency>
|
||||
<!-- 由于guava较新的21.0版本需要jdk8,故而此处采用较低版本 -->
|
||||
<dependency>
|
||||
|
||||
@@ -140,14 +140,6 @@
|
||||
</module>
|
||||
<module name="OverloadMethodsDeclarationOrder"/>
|
||||
<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="ParenPad"/>
|
||||
<module name="OperatorWrap">
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
[](https://gitee.com/binary/weixin-java-tools)
|
||||
[](https://github.com/Wechat-Group/WxJava)
|
||||
[](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://www.jetbrains.com/?from=weixin-java-tools)
|
||||
[](https://www.jetbrains.com/?from=WxJava-weixin-java-tools)
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
|
||||
---------------------------------
|
||||
@@ -13,8 +13,7 @@
|
||||
---------------------------------
|
||||
|
||||
### 重要信息
|
||||
|
||||
1. **2018-09-24 发布 [【3.2.0正式版】](https://github.com/Wechat-Group/WxJava/releases)**!
|
||||
1. **2018-12-23 项目更名为WxJava,并发布 [【3.3.0正式版】](https://github.com/Wechat-Group/WxJava/releases)**!
|
||||
1. 新手重要提示:本项目仅是一个SDK开发工具包,未提供Web实现,建议使用maven或gradle引用本项目即可使用本SDK提供的各种功能,详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码;另外微信开发新手请务必阅读[【开发文档 Wiki 首页】](https://github.com/Wechat-Group/WxJava/wiki)的常见问题部分,可以少走很多弯路,节省不少时间。
|
||||
|
||||
---------------------------------
|
||||
@@ -152,3 +151,4 @@
|
||||
1. [qsjia (QSJia)](http://github.com/qsjia)
|
||||
1. [webcreazy (webcreazy)](http://github.com/webcreazy)
|
||||
1. [cwivan (鱼丸Cwivan)](http://github.com/cwivan)
|
||||
1. [howardliu-cn (看山)](https://github.com/howardliu-cn)
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<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>
|
||||
|
||||
<artifactId>weixin-java-common</artifactId>
|
||||
<name>Weixin Java Tools - Common</name>
|
||||
<name>WxJava - Common</name>
|
||||
<description>微信开发Java SDK公共模块</description>
|
||||
|
||||
<dependencies>
|
||||
@@ -114,6 +114,11 @@
|
||||
<artifactId>assertj-guava</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -250,6 +250,15 @@ public class WxConsts {
|
||||
*/
|
||||
public static final String CARD_PAY_ORDER = "card_pay_order";
|
||||
|
||||
/**
|
||||
* 小程序审核事件:审核通过
|
||||
*/
|
||||
public static final String WEAPP_AUDIT_SUCCESS = "weapp_audit_success";
|
||||
|
||||
/**
|
||||
* 小程序审核事件:审核不通过
|
||||
*/
|
||||
public static final String WEAPP_AUDIT_FAIL = "weapp_audit_fail";
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,10 +2,8 @@ package me.chanjar.weixin.common.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
|
||||
/**
|
||||
* 卡券Api签名.
|
||||
@@ -37,6 +35,6 @@ public class WxCardApiSignature implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return WxGsonBuilder.create().toJson(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,6 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
|
||||
@@ -49,7 +46,7 @@ public class WxMenu implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return this.toJson();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,11 +4,9 @@ import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
|
||||
/**
|
||||
* menu button.
|
||||
@@ -83,7 +81,7 @@ public class WxMenuButton implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return WxGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@ package me.chanjar.weixin.common.bean.menu;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
|
||||
/**
|
||||
* menu rule.
|
||||
@@ -31,6 +29,6 @@ public class WxMenuRule implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return WxGsonBuilder.create().toJson(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,6 @@ package me.chanjar.weixin.common.bean.result;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
|
||||
@@ -28,7 +25,7 @@ public class WxMediaUploadResult implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return WxGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -794,8 +794,7 @@ public enum WxCpErrorMsgEnum {
|
||||
* 通过错误代码查找其中文含义.
|
||||
*/
|
||||
public static String findMsgByCode(int code) {
|
||||
WxCpErrorMsgEnum[] values = WxCpErrorMsgEnum.values();
|
||||
for (WxCpErrorMsgEnum value : values) {
|
||||
for (WxCpErrorMsgEnum value : WxCpErrorMsgEnum.values()) {
|
||||
if (value.code == code) {
|
||||
return value.msg;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,11 @@ public class WxError implements Serializable {
|
||||
if (msg != null) {
|
||||
wxError.setErrorMsg(msg);
|
||||
}
|
||||
} else if (type == WxType.MiniApp) {
|
||||
final String msg = WxMaErrorMsgEnum.findMsgByCode(wxError.getErrorCode());
|
||||
if (msg != null) {
|
||||
wxError.setErrorMsg(msg);
|
||||
}
|
||||
}
|
||||
|
||||
return wxError;
|
||||
|
||||
@@ -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) {
|
||||
WxMpErrorMsgEnum[] values = WxMpErrorMsgEnum.values();
|
||||
for (WxMpErrorMsgEnum value : values) {
|
||||
for (WxMpErrorMsgEnum value : WxMpErrorMsgEnum.values()) {
|
||||
if (value.code == code) {
|
||||
return value.msg;
|
||||
}
|
||||
|
||||
@@ -196,6 +196,7 @@ public class StandardSessionManager implements WxSessionManager, InternalSession
|
||||
Thread.sleep(StandardSessionManager.this.backgroundProcessorDelay * 1000L);
|
||||
backgroundProcess();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
StandardSessionManager.this.log.error("SessionManagerImpl.backgroundProcess error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package me.chanjar.weixin.common.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -27,9 +29,9 @@ public class SignUtils {
|
||||
public static String createHmacSha256Sign(String message, String key) {
|
||||
try {
|
||||
Mac sha256 = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256");
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
|
||||
sha256.init(secretKeySpec);
|
||||
byte[] bytes = sha256.doFinal(message.getBytes());
|
||||
byte[] bytes = sha256.doFinal(message.getBytes(StandardCharsets.UTF_8));
|
||||
return Hex.encodeHexString(bytes).toUpperCase();
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
||||
SignUtils.log.error(e.getMessage(), e);
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
package me.chanjar.weixin.common.util.crypto;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 提供基于PKCS7算法的加解
|
||||
* 提供基于PKCS7算法的加解.
|
||||
*
|
||||
* @author tencent
|
||||
*/
|
||||
public class PKCS7Encoder {
|
||||
|
||||
private static final Charset CHARSET = Charset.forName("utf-8");
|
||||
private static final Charset CHARSET = StandardCharsets.UTF_8;
|
||||
private static final int BLOCK_SIZE = 32;
|
||||
|
||||
/**
|
||||
@@ -28,20 +28,17 @@ public class PKCS7Encoder {
|
||||
public static byte[] encode(int count) {
|
||||
// 计算需要填充的位数
|
||||
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
|
||||
if (amountToPad == 0) {
|
||||
amountToPad = BLOCK_SIZE;
|
||||
}
|
||||
// 获得补位所用的字符
|
||||
char padChr = chr(amountToPad);
|
||||
String tmp = new String();
|
||||
StringBuilder tmp = new StringBuilder();
|
||||
for (int index = 0; index < amountToPad; index++) {
|
||||
tmp += padChr;
|
||||
tmp.append(padChr);
|
||||
}
|
||||
return tmp.getBytes(CHARSET);
|
||||
return tmp.toString().getBytes(CHARSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除解密后明文的补位字符
|
||||
* 删除解密后明文的补位字符.
|
||||
*
|
||||
* @param decrypted 解密后的明文
|
||||
* @return 删除补位字符后的明文
|
||||
@@ -55,12 +52,12 @@ public class PKCS7Encoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数字转化成ASCII码对应的字符,用于对明文进行补码
|
||||
* 将数字转化成ASCII码对应的字符,用于对明文进行补码.
|
||||
*
|
||||
* @param a 需要转化的数字
|
||||
* @return 转化得到的字符
|
||||
*/
|
||||
public static char chr(int a) {
|
||||
private static char chr(int a) {
|
||||
byte target = (byte) (a & 0xFF);
|
||||
return (char) target;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
package me.chanjar.weixin.common.util.crypto;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -25,6 +25,8 @@ import java.util.Random;
|
||||
* 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
|
||||
* 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
|
||||
* </pre>
|
||||
*
|
||||
* @author Tencent
|
||||
*/
|
||||
public class WxCryptUtil {
|
||||
|
||||
@@ -35,7 +37,9 @@ public class WxCryptUtil {
|
||||
@Override
|
||||
protected DocumentBuilder initialValue() {
|
||||
try {
|
||||
return DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setExpandEntityReferences(false);
|
||||
return factory.newDocumentBuilder();
|
||||
} catch (ParserConfigurationException exc) {
|
||||
throw new IllegalArgumentException(exc);
|
||||
}
|
||||
@@ -164,8 +168,7 @@ public class WxCryptUtil {
|
||||
ByteGroup byteCollector = new ByteGroup();
|
||||
byte[] randomStringBytes = randomStr.getBytes(CHARSET);
|
||||
byte[] plainTextBytes = plainText.getBytes(CHARSET);
|
||||
byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(
|
||||
plainTextBytes.length);
|
||||
byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length);
|
||||
byte[] appIdBytes = this.appidOrCorpid.getBytes(CHARSET);
|
||||
|
||||
// randomStr + networkBytesOrder + text + appid
|
||||
@@ -252,7 +255,7 @@ public class WxCryptUtil {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
String xmlContent, from_appid;
|
||||
String xmlContent, fromAppid;
|
||||
try {
|
||||
// 去除补位字符
|
||||
byte[] bytes = PKCS7Encoder.decode(original);
|
||||
@@ -264,14 +267,14 @@ public class WxCryptUtil {
|
||||
|
||||
xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength),
|
||||
CHARSET);
|
||||
from_appid = new String(
|
||||
fromAppid = new String(
|
||||
Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// appid不相同的情况
|
||||
if (!from_appid.equals(this.appidOrCorpid)) {
|
||||
if (!fromAppid.equals(this.appidOrCorpid)) {
|
||||
throw new RuntimeException("AppID不正确");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package me.chanjar.weixin.common.util.http;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.http.apache.ApacheMediaDownloadRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaDownloadRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaDownloadRequestExecutor;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File
|
||||
* 下载媒体文件请求执行器.
|
||||
* 请求的参数是String, 返回的结果是File
|
||||
* 视频文件不支持下载
|
||||
*
|
||||
* @author Daniel Qian
|
||||
@@ -21,6 +24,11 @@ public abstract class BaseMediaDownloadRequestExecutor<H, P> implements RequestE
|
||||
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) {
|
||||
switch (requestHttp.getRequestType()) {
|
||||
case APACHE_HTTP:
|
||||
|
||||
@@ -58,7 +58,7 @@ public class HttpResponseProxy {
|
||||
private String getFileName(CloseableHttpResponse response) throws WxErrorException {
|
||||
Header[] contentDispositionHeader = response.getHeaders("Content-disposition");
|
||||
if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
|
||||
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build());
|
||||
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build());
|
||||
}
|
||||
|
||||
return this.extractFileNameFromContentString(contentDispositionHeader[0].getValue());
|
||||
@@ -76,7 +76,7 @@ public class HttpResponseProxy {
|
||||
|
||||
private String extractFileNameFromContentString(String content) throws WxErrorException {
|
||||
if (content == null || content.length() == 0) {
|
||||
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build());
|
||||
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build());
|
||||
}
|
||||
|
||||
Matcher m = PATTERN.matcher(content);
|
||||
@@ -84,7 +84,7 @@ public class HttpResponseProxy {
|
||||
return m.group(1);
|
||||
}
|
||||
|
||||
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build());
|
||||
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package me.chanjar.weixin.common.util.http;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.http.apache.ApacheMediaUploadRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaUploadRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaUploadRequestExecutor;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String
|
||||
* 上传媒体文件请求执行器.
|
||||
* 请求的参数是File, 返回的结果是String
|
||||
*
|
||||
* @author Daniel Qian
|
||||
*/
|
||||
@@ -19,6 +22,11 @@ public abstract class MediaUploadRequestExecutor<H, P> implements RequestExecuto
|
||||
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) {
|
||||
switch (requestHttp.getRequestType()) {
|
||||
case APACHE_HTTP:
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package me.chanjar.weixin.common.util.http;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
|
||||
/**
|
||||
* http请求执行器
|
||||
* http请求执行器.
|
||||
*
|
||||
* @param <T> 返回值类型
|
||||
* @param <E> 请求参数类型
|
||||
@@ -14,8 +14,25 @@ import java.io.IOException;
|
||||
public interface RequestExecutor<T, E> {
|
||||
|
||||
/**
|
||||
* 执行http请求.
|
||||
*
|
||||
* @param uri uri
|
||||
* @param data 数据
|
||||
* @return 响应结果
|
||||
* @throws WxErrorException 自定义异常
|
||||
* @throws IOException io异常
|
||||
*/
|
||||
T execute(String uri, E data) throws WxErrorException, IOException;
|
||||
|
||||
|
||||
/**
|
||||
* 执行http请求.
|
||||
*
|
||||
* @param uri uri
|
||||
* @param data 数据
|
||||
* @param handler http响应处理器
|
||||
* @throws WxErrorException 自定义异常
|
||||
* @throws IOException io异常
|
||||
*/
|
||||
void execute(String uri, E data, ResponseHandler<T> handler) throws WxErrorException, IOException;
|
||||
}
|
||||
|
||||
@@ -2,21 +2,30 @@ package me.chanjar.weixin.common.util.http;
|
||||
|
||||
/**
|
||||
* Created by ecoolper on 2017/4/22.
|
||||
*
|
||||
* @author ecoolper
|
||||
*/
|
||||
public interface RequestHttp<H, P> {
|
||||
|
||||
/**
|
||||
* 返回httpClient
|
||||
* 返回httpClient.
|
||||
*
|
||||
* @return 返回httpClient
|
||||
*/
|
||||
H getRequestHttpClient();
|
||||
|
||||
/**
|
||||
* 返回httpProxy
|
||||
* 返回httpProxy.
|
||||
*
|
||||
* @return 返回httpProxy
|
||||
*/
|
||||
P getRequestHttpProxy();
|
||||
|
||||
/**
|
||||
* 返回HttpType.
|
||||
*
|
||||
* @return HttpType
|
||||
*/
|
||||
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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientSimpleGetRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimpleGetRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimpleGetRequestExecutor;
|
||||
|
||||
/**
|
||||
* 简单的GET请求执行器,请求的参数是String, 返回的结果也是String
|
||||
* 简单的GET请求执行器.
|
||||
* 请求的参数是String, 返回的结果也是String
|
||||
*
|
||||
* @author Daniel Qian
|
||||
*/
|
||||
@@ -16,6 +20,11 @@ public abstract class SimpleGetRequestExecutor<H, P> implements RequestExecutor<
|
||||
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) {
|
||||
switch (requestHttp.getRequestType()) {
|
||||
case APACHE_HTTP:
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package me.chanjar.weixin.common.util.http;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.http.apache.ApacheSimplePostRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimplePostRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimplePostRequestExecutor;
|
||||
@@ -17,6 +20,11 @@ public abstract class SimplePostRequestExecutor<H, P> implements RequestExecutor
|
||||
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) {
|
||||
switch (requestHttp.getRequestType()) {
|
||||
case APACHE_HTTP:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package me.chanjar.weixin.common.util.http;
|
||||
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class URIUtil {
|
||||
|
||||
@@ -16,27 +16,22 @@ public class URIUtil {
|
||||
|
||||
int l = input.length();
|
||||
StringBuilder o = new StringBuilder(l * 3);
|
||||
try {
|
||||
for (int i = 0; i < l; i++) {
|
||||
String e = input.substring(i, i + 1);
|
||||
if (ALLOWED_CHARS.indexOf(e) == -1) {
|
||||
byte[] b = e.getBytes("utf-8");
|
||||
o.append(getHex(b));
|
||||
continue;
|
||||
}
|
||||
o.append(e);
|
||||
for (int i = 0; i < l; i++) {
|
||||
String e = input.substring(i, i + 1);
|
||||
if (!ALLOWED_CHARS.contains(e)) {
|
||||
byte[] b = e.getBytes(StandardCharsets.UTF_8);
|
||||
o.append(getHex(b));
|
||||
continue;
|
||||
}
|
||||
return o.toString();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
o.append(e);
|
||||
}
|
||||
return input;
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
private static String getHex(byte buf[]) {
|
||||
private static String getHex(byte[] buf) {
|
||||
StringBuilder o = new StringBuilder(buf.length * 3);
|
||||
for (int i = 0; i < buf.length; i++) {
|
||||
int n = buf[i] & 0xff;
|
||||
for (byte aBuf : buf) {
|
||||
int n = aBuf & 0xff;
|
||||
o.append("%");
|
||||
if (n < 0x10) {
|
||||
o.append("0");
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package me.chanjar.weixin.common.util.http.apache;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.http.RequestHttp;
|
||||
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
import java.io.IOException;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.http.RequestHttp;
|
||||
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
|
||||
|
||||
/**
|
||||
* Created by ecoolper on 2017/5/4.
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package me.chanjar.weixin.common.util.http.apache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.annotation.NotThreadSafe;
|
||||
@@ -25,10 +29,6 @@ import org.apache.http.protocol.HttpContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* httpclient 连接管理器 自带DNS解析.
|
||||
* <p>大部分代码拷贝自:DefaultApacheHttpClientBuilder</p>
|
||||
@@ -292,6 +292,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder {
|
||||
}
|
||||
}
|
||||
} 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.
|
||||
*/
|
||||
public class ApacheMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor<CloseableHttpClient, HttpHost> {
|
||||
|
||||
public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
|
||||
super(requestHttp, tmpDirFile);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package me.chanjar.weixin.common.util.http.apache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.StatusLine;
|
||||
@@ -7,18 +10,20 @@ import org.apache.http.client.HttpResponseException;
|
||||
import org.apache.http.client.ResponseHandler;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* 输入流响应处理器.
|
||||
*
|
||||
* @author Daniel Qian
|
||||
*/
|
||||
public class InputStreamResponseHandler implements ResponseHandler<InputStream> {
|
||||
|
||||
public static final ResponseHandler<InputStream> INSTANCE = new InputStreamResponseHandler();
|
||||
private static final int STATUS_CODE_300 = 300;
|
||||
|
||||
@Override
|
||||
public InputStream handleResponse(final HttpResponse response) throws IOException {
|
||||
final StatusLine statusLine = response.getStatusLine();
|
||||
final HttpEntity entity = response.getEntity();
|
||||
if (statusLine.getStatusCode() >= 300) {
|
||||
if (statusLine.getStatusCode() >= STATUS_CODE_300) {
|
||||
EntityUtils.consume(entity);
|
||||
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
|
||||
}
|
||||
|
||||
@@ -7,9 +7,13 @@ import me.chanjar.weixin.common.bean.menu.WxMenu;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
|
||||
|
||||
/**
|
||||
* .
|
||||
* @author chanjarster
|
||||
*/
|
||||
public class WxGsonBuilder {
|
||||
|
||||
public static final GsonBuilder INSTANCE = new GsonBuilder();
|
||||
private static final GsonBuilder INSTANCE = new GsonBuilder();
|
||||
|
||||
static {
|
||||
INSTANCE.disableHtmlEscaping();
|
||||
|
||||
@@ -8,47 +8,47 @@ import com.thoughtworks.xstream.core.util.QuickWriter;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
|
||||
import com.thoughtworks.xstream.io.xml.XppDriver;
|
||||
import com.thoughtworks.xstream.security.NullPermission;
|
||||
import com.thoughtworks.xstream.security.PrimitiveTypePermission;
|
||||
|
||||
public class XStreamInitializer {
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeNode(String name) {
|
||||
//防止将_转换成__
|
||||
return name;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
XStream xstream = new XStream(new PureJavaReflectionProvider(), XPP_DRIVER);
|
||||
xstream.ignoreUnknownElements();
|
||||
xstream.setMode(XStream.NO_REFERENCES);
|
||||
xstream.addPermission(NullPermission.NULL);
|
||||
xstream.addPermission(PrimitiveTypePermission.PRIMITIVES);
|
||||
XStream.setupDefaultSecurity(xstream);
|
||||
xstream.allowTypesByWildcard(new String[]{
|
||||
"me.chanjar.weixin.**", "cn.binarywang.wx.**", "com.github.binarywang.**"
|
||||
});
|
||||
|
||||
xstream.setClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
return xstream;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package me.chanjar.weixin.common.util;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.*;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
@@ -18,6 +17,6 @@ public class DataUtilsTest {
|
||||
public void testHandleDataWithSecret() {
|
||||
String data = "js_code=001tZveq0SMoiq1AEXeq0ECJeq0tZveZ&secret=5681022fa1643845392367ea88888888&grant_type=authorization_code&appid=wxe156d4848d999999";
|
||||
final String s = DataUtils.handleDataWithSecret(data);
|
||||
assertThat(s).contains("&secret=******&");
|
||||
assertTrue(s.contains("&secret=******&"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.testng.annotations.*;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -7,12 +13,6 @@ import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
@Test
|
||||
@@ -39,6 +39,7 @@ public class WxCryptUtilTest {
|
||||
System.out.println(encryptedXml);
|
||||
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
documentBuilderFactory.setExpandEntityReferences(false);
|
||||
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
Document document = documentBuilder.parse(new InputSource(new StringReader(encryptedXml)));
|
||||
|
||||
@@ -81,6 +82,7 @@ public class WxCryptUtilTest {
|
||||
WxCryptUtil pc = new WxCryptUtil(this.token, this.encodingAesKey, this.appId);
|
||||
String afterEncrpt = pc.encrypt(this.replyMsg);
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
dbf.setExpandEntityReferences(false);
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
StringReader sr = new StringReader(afterEncrpt);
|
||||
InputSource is = new InputSource(sr);
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<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>
|
||||
|
||||
<artifactId>weixin-java-cp</artifactId>
|
||||
<name>Weixin Java Tools - CP</name>
|
||||
<description>微信企业号Java SDK</description>
|
||||
<name>WxJava - CP</name>
|
||||
<description>微信企业号/企业微信 Java SDK</description>
|
||||
|
||||
<dependencies>
|
||||
<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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.bean.WxCpDepart;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 部门管理接口
|
||||
@@ -17,42 +17,47 @@ public interface WxCpDepartmentService {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 部门管理接口 - 创建部门
|
||||
* 部门管理接口 - 创建部门.
|
||||
* 最多支持创建500个部门
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
|
||||
* </pre>
|
||||
*
|
||||
* @param depart 部门
|
||||
* @return 部门id
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
Integer create(WxCpDepart depart) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <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
|
||||
* </pre>
|
||||
*
|
||||
* @param id 部门id。获取指定部门及其下的子部门。非必需,可为null
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
List<WxCpDepart> list(Integer id) throws WxErrorException;
|
||||
List<WxCpDepart> list(Long id) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 部门管理接口 - 修改部门名
|
||||
* 部门管理接口 - 修改部门名.
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
|
||||
* 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
|
||||
* </pre>
|
||||
*
|
||||
* @param group 要更新的group,group的id,name必须设置
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
void update(WxCpDepart group) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 部门管理接口 - 删除部门
|
||||
* 部门管理接口 - 删除部门.
|
||||
* </pre>
|
||||
*
|
||||
* @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_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=";
|
||||
String IMG_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg";
|
||||
String JSSDK_MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk";
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -59,6 +60,21 @@ public interface WxCpMediaService {
|
||||
*/
|
||||
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>
|
||||
* 上传图片.
|
||||
@@ -69,7 +85,7 @@ public interface WxCpMediaService {
|
||||
* </pre>
|
||||
*
|
||||
* @param file 上传的文件对象
|
||||
* @return 返回图片url
|
||||
* @return 返回图片url
|
||||
*/
|
||||
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.RequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.RequestHttp;
|
||||
import me.chanjar.weixin.cp.bean.*;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
|
||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||
|
||||
/**
|
||||
@@ -241,13 +242,20 @@ public interface WxCpService {
|
||||
* 获取用户相关接口的服务类对象
|
||||
*/
|
||||
WxCpUserService getUserService();
|
||||
|
||||
/**
|
||||
* 获取群聊服务
|
||||
*
|
||||
* @return 群聊服务
|
||||
*/
|
||||
WxCpChatService getChatService();
|
||||
|
||||
WxCpAgentService getAgentService();
|
||||
|
||||
/**
|
||||
* http请求对象
|
||||
*/
|
||||
RequestHttp getRequestHttp();
|
||||
RequestHttp<?, ?> getRequestHttp();
|
||||
|
||||
void setUserService(WxCpUserService userService);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public interface WxCpUserService {
|
||||
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员
|
||||
* @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>
|
||||
@@ -51,7 +51,7 @@ public interface WxCpUserService {
|
||||
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员
|
||||
* @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;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.api.WxCpAgentService;
|
||||
@@ -11,8 +13,6 @@ import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpAgent;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* <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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
@@ -10,8 +12,6 @@ import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpDepart;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 部门管理接口
|
||||
@@ -42,13 +42,13 @@ public class WxCpDepartmentServiceImpl implements WxCpDepartmentService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Integer departId) throws WxErrorException {
|
||||
public void delete(Long departId) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId;
|
||||
this.mainService.get(url, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<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";
|
||||
if (id != null) {
|
||||
url += "?id=" + id;
|
||||
@@ -56,7 +56,7 @@ public class WxCpDepartmentServiceImpl implements WxCpDepartmentService {
|
||||
|
||||
String responseContent = this.mainService.get(url, null);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return WxCpGsonBuilder.INSTANCE.create()
|
||||
return WxCpGsonBuilder.create()
|
||||
.fromJson(tmpJsonElement.getAsJsonObject().get("department"),
|
||||
new TypeToken<List<WxCpDepart>>() {
|
||||
}.getType()
|
||||
|
||||
@@ -48,6 +48,14 @@ public class WxCpMediaServiceImpl implements WxCpMediaService {
|
||||
MEDIA_GET_URL, "media_id=" + mediaId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getJssdkFile(String mediaId) throws WxErrorException {
|
||||
return this.mainService.execute(
|
||||
BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(),
|
||||
this.mainService.getWxCpConfigStorage().getTmpDirFile()),
|
||||
JSSDK_MEDIA_GET_URL, "media_id=" + mediaId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadImg(File file) throws WxErrorException {
|
||||
final WxMediaUploadResult result = this.mainService
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
@@ -11,6 +10,7 @@ import me.chanjar.weixin.common.util.json.GsonHelper;
|
||||
import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpUserDetail;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -87,6 +87,6 @@ public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service {
|
||||
JsonObject param = new JsonObject();
|
||||
param.addProperty("user_ticket", userTicket);
|
||||
String responseText = this.mainService.post(url, param.toString());
|
||||
return new GsonBuilder().create().fromJson(responseText, WxCpUserDetail.class);
|
||||
return WxCpGsonBuilder.create().fromJson(responseText, WxCpUserDetail.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
@@ -17,19 +24,24 @@ import me.chanjar.weixin.common.util.http.RequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.RequestHttp;
|
||||
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
|
||||
import me.chanjar.weixin.cp.api.*;
|
||||
import me.chanjar.weixin.cp.bean.*;
|
||||
import me.chanjar.weixin.cp.api.WxCpAgentService;
|
||||
import me.chanjar.weixin.cp.api.WxCpChatService;
|
||||
import me.chanjar.weixin.cp.api.WxCpDepartmentService;
|
||||
import me.chanjar.weixin.cp.api.WxCpMediaService;
|
||||
import me.chanjar.weixin.cp.api.WxCpMenuService;
|
||||
import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.api.WxCpTagService;
|
||||
import me.chanjar.weixin.cp.api.WxCpUserService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
|
||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, RequestHttp<H, P> {
|
||||
protected final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private WxCpUserService userService = new WxCpUserServiceImpl(this);
|
||||
private WxCpChatService chatService = new WxCpChatServiceImpl(this);
|
||||
private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this);
|
||||
private WxCpMediaService mediaService = new WxCpMediaServiceImpl(this);
|
||||
private WxCpMenuService menuService = new WxCpMenuServiceImpl(this);
|
||||
@@ -184,7 +196,7 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
|
||||
this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
|
||||
Thread.sleep(sleepMillis);
|
||||
} catch (InterruptedException e1) {
|
||||
throw new RuntimeException(e1);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
@@ -334,7 +346,12 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestHttp getRequestHttp() {
|
||||
public WxCpChatService getChatService() {
|
||||
return chatService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestHttp<?, ?> getRequestHttp() {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import com.google.gson.*;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
@@ -11,8 +17,6 @@ import me.chanjar.weixin.cp.bean.WxCpTagGetResult;
|
||||
import me.chanjar.weixin.cp.bean.WxCpUser;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 标签管理接口
|
||||
@@ -57,7 +61,7 @@ public class WxCpTagServiceImpl implements WxCpTagService {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list";
|
||||
String responseContent = this.mainService.get(url, null);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return WxCpGsonBuilder.INSTANCE.create()
|
||||
return WxCpGsonBuilder.create()
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("taglist"),
|
||||
new TypeToken<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 responseContent = this.mainService.get(url, null);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return WxCpGsonBuilder.INSTANCE.create()
|
||||
return WxCpGsonBuilder.create()
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("userlist"),
|
||||
new TypeToken<List<WxCpUser>>() {
|
||||
|
||||
@@ -76,7 +76,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {
|
||||
}
|
||||
|
||||
@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 params = "";
|
||||
if (fetchChild != null) {
|
||||
@@ -90,7 +90,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {
|
||||
|
||||
String responseContent = this.mainService.get(url, params);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return WxCpGsonBuilder.INSTANCE.create()
|
||||
return WxCpGsonBuilder.create()
|
||||
.fromJson(tmpJsonElement.getAsJsonObject().get("userlist"),
|
||||
new TypeToken<List<WxCpUser>>() {
|
||||
}.getType()
|
||||
@@ -98,7 +98,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {
|
||||
}
|
||||
|
||||
@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 params = "";
|
||||
if (fetchChild != null) {
|
||||
@@ -112,7 +112,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {
|
||||
|
||||
String responseContent = this.mainService.get(url, params);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return WxCpGsonBuilder.INSTANCE.create()
|
||||
return WxCpGsonBuilder.create()
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("userlist"),
|
||||
new TypeToken<List<WxCpUser>>() {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
@@ -7,9 +10,6 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 企业号应用信息.
|
||||
@@ -80,12 +80,14 @@ public class WxCpAgent implements Serializable {
|
||||
|
||||
@Data
|
||||
public static class Users implements Serializable {
|
||||
private static final long serialVersionUID = 8801100463558788565L;
|
||||
@SerializedName("user")
|
||||
private List<User> users;
|
||||
}
|
||||
|
||||
@Data
|
||||
public class User implements Serializable {
|
||||
private static final long serialVersionUID = 7287632514385508024L;
|
||||
@SerializedName("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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 微信部门.
|
||||
*
|
||||
@@ -14,9 +14,9 @@ import java.io.Serializable;
|
||||
public class WxCpDepart implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5028321625140879571L;
|
||||
private Integer id;
|
||||
private Long id;
|
||||
private String name;
|
||||
private Integer parentId;
|
||||
private Long parentId;
|
||||
private Long order;
|
||||
|
||||
public static WxCpDepart fromJson(String json) {
|
||||
|
||||
@@ -5,8 +5,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
@@ -25,11 +23,11 @@ public class WxCpInviteResult implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return WxCpGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
public static WxCpInviteResult fromJson(String json) {
|
||||
return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpInviteResult.class);
|
||||
return WxCpGsonBuilder.create().fromJson(json, WxCpInviteResult.class);
|
||||
}
|
||||
|
||||
@SerializedName("errcode")
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
|
||||
import me.chanjar.weixin.cp.bean.article.NewArticle;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.*;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.FileBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.ImageBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.MpnewsBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.NewsBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.TextBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.TextCardBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.VideoBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.VoiceBuilder;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息.
|
||||
*
|
||||
@@ -114,7 +121,7 @@ public class WxCpMessage implements Serializable {
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return WxCpGsonBuilder.INSTANCE.create().toJson(this);
|
||||
return WxCpGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
@@ -25,11 +23,11 @@ public class WxCpMessageSendResult implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return WxCpGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
public static WxCpMessageSendResult fromJson(String json) {
|
||||
return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpMessageSendResult.class);
|
||||
return WxCpGsonBuilder.create().fromJson(json, WxCpMessageSendResult.class);
|
||||
}
|
||||
|
||||
@SerializedName("errcode")
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Created by Daniel Qian.
|
||||
* @author Daniel Qian
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
|
||||
@@ -5,8 +5,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
@@ -25,11 +23,11 @@ public class WxCpTagAddOrRemoveUsersResult implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return WxCpGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
public static WxCpTagAddOrRemoveUsersResult fromJson(String json) {
|
||||
return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpTagAddOrRemoveUsersResult.class);
|
||||
return WxCpGsonBuilder.create().fromJson(json, WxCpTagAddOrRemoveUsersResult.class);
|
||||
}
|
||||
|
||||
@SerializedName("errcode")
|
||||
|
||||
@@ -50,11 +50,11 @@ public class WxCpUser implements Serializable {
|
||||
}
|
||||
|
||||
public static WxCpUser fromJson(String json) {
|
||||
return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpUser.class);
|
||||
return WxCpGsonBuilder.create().fromJson(json, WxCpUser.class);
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return WxCpGsonBuilder.INSTANCE.create().toJson(this);
|
||||
return WxCpGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
@Data
|
||||
|
||||
@@ -3,12 +3,11 @@ package me.chanjar.weixin.cp.bean;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import com.thoughtworks.xstream.annotations.XStreamConverter;
|
||||
@@ -18,6 +17,7 @@ import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
|
||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
import me.chanjar.weixin.cp.util.xml.XStreamTransformer;
|
||||
|
||||
/**
|
||||
@@ -370,7 +370,7 @@ public class WxCpXmlMessage implements Serializable {
|
||||
public static WxCpXmlMessage fromEncryptedXml(InputStream is, WxCpConfigStorage wxCpConfigStorage,
|
||||
String timestamp, String nonce, String msgSignature) {
|
||||
try {
|
||||
return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxCpConfigStorage, timestamp, nonce, msgSignature);
|
||||
return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), wxCpConfigStorage, timestamp, nonce, msgSignature);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -378,7 +378,7 @@ public class WxCpXmlMessage implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return WxCpGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,9 @@ package me.chanjar.weixin.cp.config;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
/**
|
||||
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
|
||||
@@ -203,7 +201,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return WxCpGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
package me.chanjar.weixin.cp.message;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import me.chanjar.weixin.common.api.WxErrorExceptionHandler;
|
||||
import me.chanjar.weixin.common.api.WxMessageDuplicateChecker;
|
||||
import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker;
|
||||
@@ -11,18 +24,6 @@ import me.chanjar.weixin.common.util.LogExceptionHandler;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -195,6 +196,7 @@ public class WxCpMessageRouter {
|
||||
sessionEndAccess(wxMessage);
|
||||
} catch (InterruptedException e) {
|
||||
WxCpMessageRouter.this.log.error("Error happened when wait task finish", e);
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (ExecutionException e) {
|
||||
WxCpMessageRouter.this.log.error("Error happened when wait task finish", e);
|
||||
}
|
||||
@@ -207,12 +209,11 @@ public class WxCpMessageRouter {
|
||||
|
||||
|
||||
/**
|
||||
* 处理微信消息
|
||||
* 处理微信消息.
|
||||
*
|
||||
* @param wxMessage
|
||||
*/
|
||||
public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) {
|
||||
return this.route(wxMessage, new HashMap<String, Object>());
|
||||
return this.route(wxMessage, new HashMap<String, Object>(2));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
import com.google.gson.*;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import me.chanjar.weixin.common.util.json.GsonHelper;
|
||||
import me.chanjar.weixin.cp.bean.WxCpDepart;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* WxCpDepart的gson适配器.
|
||||
*
|
||||
* @author Daniel Qian
|
||||
*/
|
||||
public class WxCpDepartGsonAdapter implements JsonSerializer<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
|
||||
public JsonElement serialize(WxCpDepart group, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject json = new JsonObject();
|
||||
if (group.getId() != null) {
|
||||
json.addProperty("id", group.getId());
|
||||
json.addProperty(ID, group.getId());
|
||||
}
|
||||
if (group.getName() != null) {
|
||||
json.addProperty("name", group.getName());
|
||||
json.addProperty(NAME, group.getName());
|
||||
}
|
||||
if (group.getParentId() != null) {
|
||||
json.addProperty("parentid", group.getParentId());
|
||||
json.addProperty(PARENT_ID, group.getParentId());
|
||||
}
|
||||
if (group.getOrder() != null) {
|
||||
json.addProperty("order", String.valueOf(group.getOrder()));
|
||||
json.addProperty(ORDER, String.valueOf(group.getOrder()));
|
||||
}
|
||||
return json;
|
||||
}
|
||||
@@ -42,17 +54,17 @@ public class WxCpDepartGsonAdapter implements JsonSerializer<WxCpDepart>, JsonDe
|
||||
throws JsonParseException {
|
||||
WxCpDepart depart = new WxCpDepart();
|
||||
JsonObject departJson = json.getAsJsonObject();
|
||||
if (departJson.get("id") != null && !departJson.get("id").isJsonNull()) {
|
||||
depart.setId(GsonHelper.getAsInteger(departJson.get("id")));
|
||||
if (departJson.get(ID) != null && !departJson.get(ID).isJsonNull()) {
|
||||
depart.setId(GsonHelper.getAsLong(departJson.get(ID)));
|
||||
}
|
||||
if (departJson.get("name") != null && !departJson.get("name").isJsonNull()) {
|
||||
depart.setName(GsonHelper.getAsString(departJson.get("name")));
|
||||
if (departJson.get(NAME) != null && !departJson.get(NAME).isJsonNull()) {
|
||||
depart.setName(GsonHelper.getAsString(departJson.get(NAME)));
|
||||
}
|
||||
if (departJson.get("order") != null && !departJson.get("order").isJsonNull()) {
|
||||
depart.setOrder(GsonHelper.getAsLong(departJson.get("order")));
|
||||
if (departJson.get(ORDER) != null && !departJson.get(ORDER).isJsonNull()) {
|
||||
depart.setOrder(GsonHelper.getAsLong(departJson.get(ORDER)));
|
||||
}
|
||||
if (departJson.get("parentid") != null && !departJson.get("parentid").isJsonNull()) {
|
||||
depart.setParentId(GsonHelper.getAsInteger(departJson.get("parentid")));
|
||||
if (departJson.get(PARENT_ID) != null && !departJson.get(PARENT_ID).isJsonNull()) {
|
||||
depart.setParentId(GsonHelper.getAsLong(departJson.get(PARENT_ID)));
|
||||
}
|
||||
return depart;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder;
|
||||
import me.chanjar.weixin.common.bean.menu.WxMenu;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.util.json.WxErrorAdapter;
|
||||
import me.chanjar.weixin.cp.bean.WxCpChat;
|
||||
import me.chanjar.weixin.cp.bean.WxCpDepart;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpTag;
|
||||
@@ -15,11 +16,12 @@ import me.chanjar.weixin.cp.bean.WxCpUser;
|
||||
*/
|
||||
public class WxCpGsonBuilder {
|
||||
|
||||
public static final GsonBuilder INSTANCE = new GsonBuilder();
|
||||
private static final GsonBuilder INSTANCE = new GsonBuilder();
|
||||
|
||||
static {
|
||||
INSTANCE.disableHtmlEscaping();
|
||||
INSTANCE.registerTypeAdapter(WxCpMessage.class, new WxCpMessageGsonAdapter());
|
||||
INSTANCE.registerTypeAdapter(WxCpChat.class, new WxCpChatGsonAdapter());
|
||||
INSTANCE.registerTypeAdapter(WxCpDepart.class, new WxCpDepartGsonAdapter());
|
||||
INSTANCE.registerTypeAdapter(WxCpUser.class, new WxCpUserGsonAdapter());
|
||||
INSTANCE.registerTypeAdapter(WxError.class, new WxErrorAdapter());
|
||||
|
||||
@@ -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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.testng.annotations.*;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import me.chanjar.weixin.cp.api.ApiTestModule;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpDepart;
|
||||
import org.testng.annotations.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -29,7 +29,7 @@ public class WxCpDepartmentServiceImplTest {
|
||||
public void testCreate() throws Exception {
|
||||
WxCpDepart cpDepart = new WxCpDepart();
|
||||
cpDepart.setName("子部门" + System.currentTimeMillis());
|
||||
cpDepart.setParentId(1);
|
||||
cpDepart.setParentId(1L);
|
||||
cpDepart.setOrder(1L);
|
||||
Integer departId = this.wxCpService.getDepartmentService().create(cpDepart);
|
||||
System.out.println(departId);
|
||||
@@ -45,7 +45,7 @@ public class WxCpDepartmentServiceImplTest {
|
||||
}
|
||||
|
||||
@Test(dataProvider = "departIds")
|
||||
public void testList(Integer id) throws Exception {
|
||||
public void testList(Long id) throws Exception {
|
||||
System.out.println("=================获取部门");
|
||||
List<WxCpDepart> departList = this.wxCpService.getDepartmentService().list(id);
|
||||
assertThat(departList).isNotEmpty();
|
||||
|
||||
@@ -36,7 +36,8 @@ public class WxCpMediaServiceImplTest {
|
||||
public Object[][] mediaData() {
|
||||
return new Object[][]{
|
||||
new Object[]{WxConsts.MediaFileType.IMAGE, TestConstants.FILE_JPG, "mm.jpeg"},
|
||||
new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_MP3, "mm.mp3"},//{"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"}
|
||||
//new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_MP3, "mm.mp3"},
|
||||
// {"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"}
|
||||
new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_AMR, "mm.amr"},
|
||||
new Object[]{WxConsts.MediaFileType.VIDEO, TestConstants.FILE_MP4, "mm.mp4"},
|
||||
new Object[]{WxConsts.MediaFileType.FILE, TestConstants.FILE_JPG, "mm.jpeg"}
|
||||
@@ -47,8 +48,9 @@ public class WxCpMediaServiceImplTest {
|
||||
public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException {
|
||||
try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)) {
|
||||
WxMediaUploadResult res = this.wxService.getMediaService().upload(mediaType, fileType, inputStream);
|
||||
assertNotNull(res.getType());
|
||||
assertNotNull(res.getCreatedAt());
|
||||
assertThat(res).isNotNull();
|
||||
assertThat(res.getType()).isNotEmpty();
|
||||
assertThat(res.getCreatedAt()).isGreaterThan(0);
|
||||
assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null);
|
||||
|
||||
if (res.getMediaId() != null) {
|
||||
@@ -70,9 +72,9 @@ public class WxCpMediaServiceImplTest {
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = {"testUploadMedia"}, dataProvider = "downloadMedia")
|
||||
public void testDownloadMedia(String media_id) throws WxErrorException {
|
||||
File file = this.wxService.getMediaService().download(media_id);
|
||||
assertNotNull(file);
|
||||
public void testDownload(String mediaId) throws WxErrorException {
|
||||
File file = this.wxService.getMediaService().download(mediaId);
|
||||
assertThat(file).isNotNull();
|
||||
System.out.println(file);
|
||||
}
|
||||
|
||||
@@ -82,4 +84,11 @@ public class WxCpMediaServiceImplTest {
|
||||
String res = this.wxService.getMediaService().uploadImg(new File(url.getFile()));
|
||||
assertThat(res).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetJssdkFile() throws WxErrorException {
|
||||
File file = this.wxService.getMediaService().getJssdkFile("....");
|
||||
assertThat(file).isNotNull();
|
||||
System.out.println(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class WxCpUserServiceImplTest {
|
||||
|
||||
@Test
|
||||
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);
|
||||
for (WxCpUser user : users) {
|
||||
System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE));
|
||||
@@ -83,7 +83,7 @@ public class WxCpUserServiceImplTest {
|
||||
|
||||
@Test
|
||||
public void testListSimpleByDepartment() throws Exception {
|
||||
List<WxCpUser> users = this.wxCpService.getUserService().listSimpleByDepartment(1, true, 0);
|
||||
List<WxCpUser> users = this.wxCpService.getUserService().listSimpleByDepartment(1L, true, 0);
|
||||
assertNotEquals(users.size(), 0);
|
||||
for (WxCpUser user : users) {
|
||||
System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE));
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<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>
|
||||
<artifactId>weixin-java-miniapp</artifactId>
|
||||
<name>Weixin Java Tools - MiniApp</name>
|
||||
<name>WxJava - MiniApp</name>
|
||||
<description>微信小程序Java SDK</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -15,7 +15,26 @@ public interface WxMaJsapiService {
|
||||
/**
|
||||
* 获得jsapi_ticket的url
|
||||
*/
|
||||
String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
|
||||
String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
|
||||
|
||||
/**
|
||||
* 获得卡券api_ticket,不强制刷新api_ticket
|
||||
*
|
||||
* @see #getJsapiTicket(boolean)
|
||||
*/
|
||||
String getCardApiTicket() throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <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
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.binarywang.wx.miniapp.api;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 二维码相关操作接口.
|
||||
@@ -32,24 +32,87 @@ public interface WxMaQrcodeService {
|
||||
*
|
||||
* @param path 不能为空,最大长度 128 字节
|
||||
* @param width 默认430 二维码的宽度
|
||||
* @return 文件内容字节数组
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
byte[] createQrcodeBytes(String path, int width) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 接口C: 获取小程序页面二维码.
|
||||
* <pre>
|
||||
* 适用于需要的码数量较少的业务场景
|
||||
* 通过该接口,仅能生成已发布的小程序的二维码。
|
||||
* 可以在开发者工具预览时生成开发版的带参二维码。
|
||||
* 带参二维码只有 100000 个,请谨慎调用。
|
||||
* </pre>
|
||||
*
|
||||
* @param path 不能为空,最大长度 128 字节
|
||||
* @param width 默认430 二维码的宽度
|
||||
* @return 文件对象
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* 接口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 异常
|
||||
*/
|
||||
File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean is_hyaline) 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 isHyaline)
|
||||
throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 接口A: 获取小程序码.
|
||||
*
|
||||
* @param path 不能为空,最大长度 128 字节
|
||||
* @param width 默认430 二维码的宽度
|
||||
* @return 文件对象
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
File createWxaCode(String path, int width) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 接口A: 获取小程序码.
|
||||
*
|
||||
* @param path 不能为空,最大长度 128 字节
|
||||
* @return 文件对象
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
File createWxaCode(String path) throws WxErrorException;
|
||||
|
||||
/**
|
||||
@@ -61,15 +124,56 @@ public interface WxMaQrcodeService {
|
||||
* 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode
|
||||
* </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 异常
|
||||
*/
|
||||
File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) 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 width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
|
||||
* @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
|
||||
* @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}
|
||||
* @param isHyaline 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码
|
||||
* @return 文件对象
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor,
|
||||
WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 接口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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
@@ -20,17 +18,6 @@ public interface WxMaService {
|
||||
|
||||
String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session";
|
||||
|
||||
String IMG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/img_sec_check";
|
||||
|
||||
/**
|
||||
* <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信息.
|
||||
*
|
||||
@@ -152,33 +139,51 @@ public interface WxMaService {
|
||||
WxMaTemplateService getTemplateService();
|
||||
|
||||
/**
|
||||
* 数据分析相关查询服务
|
||||
* 数据分析相关查询服务.
|
||||
*
|
||||
* @return WxMaAnalysisService
|
||||
*/
|
||||
WxMaAnalysisService getAnalysisService();
|
||||
|
||||
/**
|
||||
* 返回代码操作相关的 API
|
||||
* 返回代码操作相关的 API.
|
||||
*
|
||||
* @return WxMaCodeService
|
||||
*/
|
||||
WxMaCodeService getCodeService();
|
||||
|
||||
/**
|
||||
* 返回jsapi操作相关的 API服务类对象
|
||||
* 返回jsapi操作相关的 API服务类对象.
|
||||
*
|
||||
* @return WxMaJsapiService
|
||||
*/
|
||||
WxMaJsapiService getJsapiService();
|
||||
|
||||
/**
|
||||
* 小程序修改服务器地址、成员管理 API
|
||||
* 小程序修改服务器地址、成员管理 API.
|
||||
*
|
||||
* @return WxMaSettingService
|
||||
*/
|
||||
WxMaSettingService getSettingService();
|
||||
|
||||
/**
|
||||
* 返回分享相关查询服务.
|
||||
* @return WxMaShareService
|
||||
*/
|
||||
WxMaShareService getShareService();
|
||||
|
||||
/**
|
||||
* 返回微信运动相关接口服务对象.
|
||||
* @return WxMaShareService
|
||||
*/
|
||||
WxMaRunService getRunService();
|
||||
|
||||
/**
|
||||
* 返回内容安全相关接口服务对象.
|
||||
* @return WxMaShareService
|
||||
*/
|
||||
WxMaSecCheckService getSecCheckService();
|
||||
|
||||
/**
|
||||
* 初始化http请求对象.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
public String getCardApiTicket() throws WxErrorException {
|
||||
return getCardApiTicket(false);
|
||||
}
|
||||
|
||||
public String getCardApiTicket(boolean forceRefresh) throws WxErrorException {
|
||||
Lock lock = this.wxMaService.getWxMaConfig().getCardApiTicketLock();
|
||||
try {
|
||||
lock.lock();
|
||||
if (forceRefresh) {
|
||||
this.wxMaService.getWxMaConfig().expireCardApiTicket();
|
||||
}
|
||||
|
||||
if (this.wxMaService.getWxMaConfig().isCardApiTicketExpired()) {
|
||||
String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL + "?type=wx_card", null);
|
||||
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
|
||||
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
|
||||
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
|
||||
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
|
||||
this.wxMaService.getWxMaConfig().updateCardApiTicket(jsapiTicket, expiresInSeconds);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return this.wxMaService.getWxMaConfig().getJsapiTicket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJsapiTicket() throws WxErrorException {
|
||||
return getJsapiTicket(false);
|
||||
@@ -43,7 +69,7 @@ public class WxMaJsapiServiceImpl implements WxMaJsapiService {
|
||||
}
|
||||
|
||||
if (this.wxMaService.getWxMaConfig().isJsapiTicketExpired()) {
|
||||
String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL, null);
|
||||
String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL + "?type=jsapi", null);
|
||||
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
|
||||
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
|
||||
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package cn.binarywang.wx.miniapp.api.impl;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaQrcodeService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaQrcode;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaWxcode;
|
||||
import cn.binarywang.wx.miniapp.bean.WxaCode;
|
||||
import cn.binarywang.wx.miniapp.bean.WxaCodeUnlimit;
|
||||
import cn.binarywang.wx.miniapp.util.http.QrCodeRequestExecutor;
|
||||
import cn.binarywang.wx.miniapp.util.QrcodeBytesRequestExecutor;
|
||||
import cn.binarywang.wx.miniapp.util.QrcodeRequestExecutor;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@@ -21,10 +22,16 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService {
|
||||
this.wxMaService = wxMaService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] createQrcodeBytes(String path, int width) throws WxErrorException {
|
||||
final QrcodeBytesRequestExecutor executor = new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp());
|
||||
return this.wxMaService.execute(executor, CREATE_QRCODE_URL, new WxMaQrcode(path, width));
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createQrcode(String path, int width) throws WxErrorException {
|
||||
return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()),
|
||||
CREATE_QRCODE_URL, new WxMaQrcode(path, width));
|
||||
final QrcodeRequestExecutor executor = new QrcodeRequestExecutor(this.wxMaService.getRequestHttp());
|
||||
return this.wxMaService.execute(executor, CREATE_QRCODE_URL, new WxMaQrcode(path, width));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,15 +40,29 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException {
|
||||
WxMaWxcode wxMaWxcode = new WxMaWxcode();
|
||||
wxMaWxcode.setPath(path);
|
||||
wxMaWxcode.setWidth(width);
|
||||
wxMaWxcode.setAutoColor(autoColor);
|
||||
wxMaWxcode.setLineColor(lineColor);
|
||||
wxMaWxcode.setHyaline(isHyaline);
|
||||
return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()),
|
||||
GET_WXACODE_URL, wxMaWxcode);
|
||||
public byte[] createWxaCodeBytes(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline)
|
||||
throws WxErrorException {
|
||||
final QrcodeBytesRequestExecutor executor = new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp());
|
||||
return this.wxMaService.execute(executor, GET_WXACODE_URL, WxaCode.builder()
|
||||
.path(path)
|
||||
.width(width)
|
||||
.autoColor(autoColor)
|
||||
.lineColor(lineColor)
|
||||
.isHyaline(isHyaline)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline)
|
||||
throws WxErrorException {
|
||||
final QrcodeRequestExecutor executor = new QrcodeRequestExecutor(this.wxMaService.getRequestHttp());
|
||||
return this.wxMaService.execute(executor, GET_WXACODE_URL, WxaCode.builder()
|
||||
.path(path)
|
||||
.width(width)
|
||||
.autoColor(autoColor)
|
||||
.lineColor(lineColor)
|
||||
.isHyaline(isHyaline)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,12 +72,27 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService {
|
||||
|
||||
@Override
|
||||
public File createWxaCode(String path) throws WxErrorException {
|
||||
return this.createWxaCode(path, 430, true, null, false);
|
||||
return this.createWxaCode(path, 430);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline)
|
||||
throws WxErrorException {
|
||||
public byte[] createWxaCodeUnlimitBytes(String scene, String page, int width, boolean autoColor,
|
||||
WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException {
|
||||
return this.wxMaService.execute(new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp()),
|
||||
GET_WXACODE_UNLIMIT_URL,
|
||||
this.buildWxaCodeUnlimit(scene, page, width, autoColor, lineColor, isHyaline));
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor,
|
||||
WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException {
|
||||
return this.wxMaService.execute(new QrcodeRequestExecutor(this.wxMaService.getRequestHttp()),
|
||||
GET_WXACODE_UNLIMIT_URL,
|
||||
this.buildWxaCodeUnlimit(scene, page, width, autoColor, lineColor, isHyaline));
|
||||
}
|
||||
|
||||
private WxaCodeUnlimit buildWxaCodeUnlimit(String scene, String page, int width, boolean autoColor,
|
||||
WxMaCodeLineColor lineColor, boolean isHyaline) {
|
||||
WxaCodeUnlimit wxaCodeUnlimit = new WxaCodeUnlimit();
|
||||
wxaCodeUnlimit.setScene(scene);
|
||||
wxaCodeUnlimit.setPage(page);
|
||||
@@ -64,8 +100,8 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService {
|
||||
wxaCodeUnlimit.setAutoColor(autoColor);
|
||||
wxaCodeUnlimit.setLineColor(lineColor);
|
||||
wxaCodeUnlimit.setHyaline(isHyaline);
|
||||
return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()),
|
||||
GET_WXACODE_UNLIMIT_URL, wxaCodeUnlimit);
|
||||
|
||||
return wxaCodeUnlimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -12,8 +11,6 @@ import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.BasicResponseHandler;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaAnalysisService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaCodeService;
|
||||
@@ -21,22 +18,24 @@ import cn.binarywang.wx.miniapp.api.WxMaJsapiService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaMediaService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaMsgService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaQrcodeService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaRunService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaSecCheckService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaSettingService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaShareService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaTemplateService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaUserService;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.DataUtils;
|
||||
import me.chanjar.weixin.common.util.crypto.SHA1;
|
||||
import me.chanjar.weixin.common.util.http.HttpType;
|
||||
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.RequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.RequestHttp;
|
||||
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
|
||||
@@ -49,9 +48,8 @@ import static cn.binarywang.wx.miniapp.constant.WxMaConstants.ErrorCode.*;
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpClient, HttpHost> {
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private CloseableHttpClient httpClient;
|
||||
private HttpHost httpProxy;
|
||||
private WxMaConfig wxMaConfig;
|
||||
@@ -65,6 +63,9 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
|
||||
private WxMaCodeService codeService = new WxMaCodeServiceImpl(this);
|
||||
private WxMaSettingService settingService = new WxMaSettingServiceImpl(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 maxRetryTimes = 5;
|
||||
@@ -149,13 +150,6 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
|
||||
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
|
||||
public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException {
|
||||
final WxMaConfig config = getWxMaConfig();
|
||||
@@ -205,7 +199,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
|
||||
return this.executeInternal(executor, uri, data);
|
||||
} catch (WxErrorException e) {
|
||||
if (retryTimes + 1 > this.maxRetryTimes) {
|
||||
this.log.warn("重试达到最大次数【{}】", maxRetryTimes);
|
||||
log.warn("重试达到最大次数【{}】", maxRetryTimes);
|
||||
//最后一次重试失败后,直接抛出异常,不再等待
|
||||
throw new RuntimeException("微信服务端异常,超出重试次数");
|
||||
}
|
||||
@@ -215,10 +209,10 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
|
||||
if (error.getErrorCode() == -1) {
|
||||
int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
|
||||
try {
|
||||
this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
|
||||
log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
|
||||
Thread.sleep(sleepMillis);
|
||||
} catch (InterruptedException e1) {
|
||||
throw new RuntimeException(e1);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
@@ -226,7 +220,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
|
||||
}
|
||||
} while (retryTimes++ < this.maxRetryTimes);
|
||||
|
||||
this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
|
||||
log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
|
||||
throw new RuntimeException("微信服务端异常,超出重试次数");
|
||||
}
|
||||
|
||||
@@ -242,7 +236,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
|
||||
|
||||
try {
|
||||
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;
|
||||
} catch (WxErrorException e) {
|
||||
WxError error = e.getError();
|
||||
@@ -260,12 +254,12 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return null;
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
@@ -335,4 +329,19 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
|
||||
public WxMaSettingService getSettingService() {
|
||||
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;
|
||||
|
||||
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.WxMaTemplateService;
|
||||
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.util.json.WxGsonBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class WxMaTemplateServiceImpl implements WxMaTemplateService {
|
||||
|
||||
private WxMaService wxMaService;
|
||||
|
||||
public WxMaTemplateServiceImpl(WxMaService wxMaService){
|
||||
public WxMaTemplateServiceImpl(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));
|
||||
WxError wxError = WxError.fromJson(responseText);
|
||||
if(wxError.getErrorCode() == 0){
|
||||
if (wxError.getErrorCode() == 0) {
|
||||
return WxMaTemplateLibraryListResult.fromJson(responseText);
|
||||
}else {
|
||||
} else {
|
||||
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));
|
||||
WxError wxError = WxError.fromJson(responseText);
|
||||
if(wxError.getErrorCode() == 0){
|
||||
if (wxError.getErrorCode() == 0) {
|
||||
return WxMaTemplateLibraryGetResult.fromJson(responseText);
|
||||
}else {
|
||||
} else {
|
||||
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));
|
||||
WxError wxError = WxError.fromJson(responseText);
|
||||
if(wxError.getErrorCode() == 0){
|
||||
if (wxError.getErrorCode() == 0) {
|
||||
return WxMaTemplateAddResult.fromJson(responseText);
|
||||
}else {
|
||||
} else {
|
||||
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));
|
||||
WxError wxError = WxError.fromJson(responseText);
|
||||
if(wxError.getErrorCode() == 0){
|
||||
if (wxError.getErrorCode() == 0) {
|
||||
return WxMaTemplateListResult.fromJson(responseText);
|
||||
}else {
|
||||
} else {
|
||||
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));
|
||||
WxError wxError = WxError.fromJson(responseText);
|
||||
if(wxError.getErrorCode() == 0){
|
||||
if (wxError.getErrorCode() == 0) {
|
||||
return true;
|
||||
}else {
|
||||
} else {
|
||||
throw new WxErrorException(wxError);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import java.io.Serializable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
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.util.crypt.WxMaCryptUtils;
|
||||
@@ -168,7 +166,7 @@ public class WxMaMessage implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return this.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;
|
||||
|
||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 小程序码.
|
||||
*
|
||||
* @author Element
|
||||
* @date 2017/7/27
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class WxMaWxcode extends AbstractWxMaQrcodeWrapper implements Serializable {
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WxaCode extends AbstractWxMaQrcodeWrapper implements Serializable {
|
||||
private static final long serialVersionUID = 1287399621649210322L;
|
||||
|
||||
private String path;
|
||||
|
||||
@Builder.Default
|
||||
private int width = 430;
|
||||
|
||||
@SerializedName("auto_color")
|
||||
@Builder.Default
|
||||
private boolean autoColor = true;
|
||||
|
||||
@SerializedName("is_hyaline")
|
||||
@Builder.Default
|
||||
private boolean isHyaline = false;
|
||||
|
||||
@SerializedName("line_color")
|
||||
@Builder.Default
|
||||
private WxMaCodeLineColor lineColor = new WxMaCodeLineColor("0", "0", "0");
|
||||
|
||||
public static WxMaWxcode fromJson(String json) {
|
||||
return WxMaGsonBuilder.create().fromJson(json, WxMaWxcode.class);
|
||||
public static WxaCode fromJson(String json) {
|
||||
return WxMaGsonBuilder.create().fromJson(json, WxaCode.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.binarywang.wx.miniapp.config;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
/**
|
||||
* 小程序配置
|
||||
*
|
||||
@@ -57,6 +57,28 @@ public interface WxMaConfig {
|
||||
*/
|
||||
void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
|
||||
|
||||
/**
|
||||
* 卡券api_ticket.
|
||||
*/
|
||||
String getCardApiTicket();
|
||||
|
||||
Lock getCardApiTicketLock();
|
||||
|
||||
boolean isCardApiTicketExpired();
|
||||
|
||||
/**
|
||||
* 强制将卡券api ticket过期掉.
|
||||
*/
|
||||
void expireCardApiTicket();
|
||||
|
||||
/**
|
||||
* 应该是线程安全的.
|
||||
*
|
||||
* @param apiTicket 新的卡券api ticket值
|
||||
* @param expiresInSeconds 过期时间,以秒为单位
|
||||
*/
|
||||
void updateCardApiTicket(String apiTicket, int expiresInSeconds);
|
||||
|
||||
String getAppid();
|
||||
|
||||
String getSecret();
|
||||
|
||||
@@ -4,9 +4,7 @@ import java.io.File;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
|
||||
|
||||
@@ -32,8 +30,14 @@ public class WxMaInMemoryConfig implements WxMaConfig {
|
||||
protected volatile String jsapiTicket;
|
||||
protected volatile long jsapiTicketExpiresTime;
|
||||
|
||||
//微信卡券的ticket单独缓存
|
||||
protected volatile String cardApiTicket;
|
||||
protected volatile long cardApiTicketExpiresTime;
|
||||
|
||||
|
||||
protected Lock accessTokenLock = new ReentrantLock();
|
||||
protected Lock jsapiTicketLock = new ReentrantLock();
|
||||
protected Lock cardApiTicketLock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* 临时文件目录
|
||||
@@ -103,6 +107,34 @@ public class WxMaInMemoryConfig implements WxMaConfig {
|
||||
this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getCardApiTicket() {
|
||||
return this.cardApiTicket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock getCardApiTicketLock() {
|
||||
return this.cardApiTicketLock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCardApiTicketExpired() {
|
||||
return System.currentTimeMillis() > this.cardApiTicketExpiresTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expireCardApiTicket() {
|
||||
this.cardApiTicketExpiresTime = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) {
|
||||
this.cardApiTicket = cardApiTicket;
|
||||
// 预留200秒的时间
|
||||
this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expireAccessToken() {
|
||||
this.expiresTime = 0;
|
||||
@@ -191,7 +223,7 @@ public class WxMaInMemoryConfig implements WxMaConfig {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
|
||||
return WxMaGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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.HttpHost;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
@@ -17,33 +14,44 @@ import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.UUID;
|
||||
import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.fs.FileUtils;
|
||||
import me.chanjar.weixin.common.util.http.RequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.RequestHttp;
|
||||
import me.chanjar.weixin.common.util.http.ResponseHandler;
|
||||
import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler;
|
||||
import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
|
||||
|
||||
/**
|
||||
* @author <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;
|
||||
|
||||
public QrCodeRequestExecutor(RequestHttp requestHttp) {
|
||||
public QrcodeRequestExecutor(RequestHttp requestHttp) {
|
||||
this.requestHttp = requestHttp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File execute(String uri, AbstractWxMaQrcodeWrapper ticket) throws WxErrorException, IOException {
|
||||
public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler<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);
|
||||
if (requestHttp.getRequestHttpProxy() != null) {
|
||||
httpPost.setConfig(
|
||||
RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build()
|
||||
);
|
||||
}
|
||||
httpPost.setEntity(new StringEntity(ticket.toJson()));
|
||||
|
||||
try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost);
|
||||
InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) {
|
||||
httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson()));
|
||||
|
||||
try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost);
|
||||
final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
|
||||
Header[] contentTypeHeader = response.getHeaders("Content-Type");
|
||||
if (contentTypeHeader != null && contentTypeHeader.length > 0
|
||||
&& ContentType.APPLICATION_JSON.getMimeType()
|
||||
@@ -7,6 +7,9 @@ import org.testng.annotations.*;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.test.ApiTestModule;
|
||||
import com.google.inject.Inject;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
@@ -18,21 +21,38 @@ public class WxMaQrcodeServiceImplTest {
|
||||
private WxMaService wxService;
|
||||
|
||||
@Test
|
||||
public void testCreateQrCode() throws Exception {
|
||||
public void testCreateQrcode() throws Exception {
|
||||
final File qrCode = this.wxService.getQrcodeService().createQrcode("111", 122);
|
||||
System.out.println(qrCode);
|
||||
assertThat(qrCode).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWxaCode() throws Exception {
|
||||
final File wxCode = this.wxService.getQrcodeService().createWxaCode("111", 122);
|
||||
System.out.println(wxCode);
|
||||
assertThat(wxCode).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWxaCodeUnlimit() throws Exception {
|
||||
final File wxCode = this.wxService.getQrcodeService().createWxaCodeUnlimit("111", null);
|
||||
System.out.println(wxCode);
|
||||
assertThat(wxCode).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateQrcodeBytes() throws WxErrorException {
|
||||
final byte[] qrCode = this.wxService.getQrcodeService().createQrcodeBytes("111", 122);
|
||||
assertThat(qrCode).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWxaCodeBytes() throws WxErrorException {
|
||||
final byte[] wxCode = this.wxService.getQrcodeService().createWxaCodeBytes("111", 122, true, null, false);
|
||||
assertThat(wxCode).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWxaCodeUnlimitBytes() throws WxErrorException {
|
||||
final byte[] wxCode = this.wxService.getQrcodeService().createWxaCodeUnlimitBytes("111", null, 122, true, null, false);
|
||||
assertThat(wxCode).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user