Compare commits

...

51 Commits
rxjava ... main

Author SHA1 Message Date
b4c3fef78c 暂时对不对 GPG 签名 2025-04-03 14:14:27 -04:00
019379f729 OSS-258 remove the commit with key and code 2023-06-14 16:29:53 -04:00
1a52833467 OSS-258 创建一个 Builder 对象,用来在测试中进行 Builder https://www.ossez.com/t/api/14400/2 2023-06-14 16:11:10 -04:00
77bea77f4e OSS-258 创建一个 Builder 对象,用来在测试中进行 Builder https://www.ossez.com/t/api/14400/2 2023-04-25 14:13:50 -04:00
4f5f90298d OSS-258 添加菜单处理服务 2023-04-25 13:23:36 -04:00
003cdd18f4 OSS-258 测试菜单 API 2023-04-25 13:23:03 -04:00
f863a25498 OSS-257 定义微信图文信息状态的数据返回接口
官方网站文档链接地址为:https://developers.weixin.qq.com/doc/offiaccount/Analytics/Graphic_Analysis_Data_Interface.html
2023-04-24 16:35:20 -04:00
66ccf11560 OSS-256 创建获取累计用户数据的方法。
需要注意的是,这里有一个时间跨度的问题,最多只能获取 7 天的数据。
2023-04-24 16:12:38 -04:00
5603ae28db OSS-256 创建 2 个新的对象和一个服务,这个服务用来处理数据相关的 API
用户分析返回的类型和结果为:https://www.ossez.com/t/topic/14398
2023-04-24 12:17:59 -04:00
d0dd1b82d7 OSS-255 格式化代码,删除不需要的引用 2023-04-24 09:22:49 -04:00
9446b1a636 OSS-255 更新 DI 的使用 2023-04-23 15:22:26 -04:00
e92e97ca11 OSS-255 格式化代码并且使用 Junit 5 的测试类 https://bug.ossez.com/browse/OSS-255 2023-04-23 15:13:04 -04:00
bce4e5a324 OSS-255 格式化代码并且使用 Junit 5 的测试类 https://bug.ossez.com/browse/OSS-255 2023-04-23 15:12:57 -04:00
03c5092164 OSS-255 更新测试使用 JUnit 5 2023-04-23 15:11:48 -04:00
9124457533 OSS-254 测试微信的消息发送 2023-04-19 22:06:03 -04:00
d217b67cf6 constant Change the name to MsgType 2023-04-19 09:27:45 -04:00
3e617b3a4c constant to update the WeChatConstant 2023-04-19 09:22:52 -04:00
bb3b148de4 Update Object to remove data from lombook 2023-04-19 08:52:39 -04:00
927361987f 更新客服信息 2023-04-19 08:48:29 -04:00
68bc4e84b4 格式化 Pom 文件 2023-04-19 08:43:29 -04:00
44208b4fab USVT-138 Change token for GPT 2023-03-22 13:17:01 -04:00
57079fecfd USVT-138 返回对象使用微信状态对象 2023-03-07 13:33:38 -05:00
f16561c82a USVT-138 针对微信返回的状态,我们提供一个状态对象 2023-03-07 13:20:19 -05:00
fba63df660 USVT-136 使用微信异步消息的策略来发布消息 2023-02-13 00:38:08 -05:00
5c1aef79c8 USVT-136 添加一个消息处理类,在这个消息处理类中为微信进行异步消息处理 2023-02-12 09:36:21 -05:00
aa235ae02f WeChat Official Account Platform related Service to process Platform related service 2023-02-09 12:44:47 -05:00
53bed19f45 USVT-135 设置超时时间为 15 秒,并且对代码进行格式化 2023-02-09 12:32:18 -05:00
75003069f9 接口的代码格式化 2023-02-09 11:22:27 -05:00
670766282a 配置使用不同的 Open ID 代码 2023-02-08 11:34:16 -05:00
706a42f7b2 配置 WeChat 的包的内容,尝试从 WeChat 包中调用需要的数据 2023-02-06 09:17:12 -05:00
3bdd0a99fa 针对公众号的登录程序,我们调整 Open 中的内容 2023-02-06 09:14:27 -05:00
34d1d5db58 create a wechat response object 2023-02-02 08:57:32 -05:00
c881e857ae Update logic by use retrofit2 package send request 2023-02-01 07:07:28 -05:00
f676c1239d 调用腾讯网络检测 API 2023-01-31 06:07:20 -05:00
4fa242751e 使用平台服务文件提供平台需要的相关服务 2023-01-31 06:02:07 -05:00
45010d1575 添加微信使用的第二个 API,获取微信服务器地址 2023-01-30 06:01:42 -05:00
21a71adba8 清理使用 httpClient 的实现,我们只会使用 okHttp 来实现所有的 HTTP 请求 2023-01-29 17:29:34 -05:00
1822d39c12 微信主机配置对象移动到 Common 模块中 2023-01-29 16:52:32 -05:00
e69e7edd02 移动微信常量到 Common 包中 2023-01-29 16:52:00 -05:00
faeb62abd8 修改拦截器中数据读取的方式,解决被拦截器拦截后的读取错误:https://www.ossez.com/t/okhttp-interceptor-close/14307 2023-01-29 08:41:02 -05:00
84acfa03f7 更新微信卡券的枚举类型 2023-01-27 05:43:34 -05:00
5dd10f3adc 微信公众号事件的常量类型移动到 Common 中 2023-01-26 14:16:32 -05:00
51185a972c 微信 API 可以支持的语言类型 2023-01-26 14:13:49 -05:00
9ba61c9f9b 修改代码,清理 lombok 在类中错误 2023-01-26 14:07:10 -05:00
29cccd94b2 不清楚为什么可以用 Apache 的随机字符串生成类还要自己写一个,直接使用 Apache 的字符串生成类 2023-01-26 14:01:54 -05:00
b8d15f0124 重命名腾讯企点的项目结构 2023-01-26 13:51:36 -05:00
d629d61250 针对腾讯企业账号的自述文件 2023-01-26 13:47:17 -05:00
704a41b1e2 把腾讯企点的 API 信息全部合并过来。 2023-01-26 13:46:58 -05:00
0a21e62667 处理加密解密包的问题,尽量避免直接调用 JDK 中保护的类。 2023-01-26 12:56:10 -05:00
e4f18688e1 添加 wecom 项目到整个库中 2023-01-26 12:42:49 -05:00
fd98fad567 微信支付的所有模块进行 Package 的重命名,删除不需要的模块 2023-01-26 07:35:47 -05:00
1226 changed files with 10783 additions and 9671 deletions

10
.idea/.gitignore generated vendored
View File

@ -1,10 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Zeppelin ignored files
/ZeppelinRemoteNotebooks/

16
.idea/checkstyle-idea.xml generated Normal file
View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CheckStyle-IDEA" serialisationVersion="2">
<checkstyleVersion>10.22.0</checkstyleVersion>
<scanScope>JavaOnly</scanScope>
<copyLibs>true</copyLibs>
<option name="thirdPartyClasspath" />
<option name="activeLocationIds" />
<option name="locations">
<list>
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
</list>
</option>
</component>
</project>

22
.idea/compiler.xml generated
View File

@ -2,37 +2,17 @@
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile default="true" name="Default" enabled="true" />
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="wechat-j-open" />
<module name="wechat-j-pay" />
<module name="wechat-j-work" />
<module name="wechat-j-common" />
<module name="wechat-j-mp" />
<module name="wechat-j-oa" />
</profile>
</annotationProcessing>
<bytecodeTargetLevel>
<module name="wechat-j-oa (1)" target="11" />
<module name="wechat-j-oa (2)" target="1.8" />
<module name="weixin-graal" target="1.8" />
<module name="weixin-java-common" target="1.8" />
<module name="weixin-java-cp" target="1.8" />
<module name="weixin-java-miniapp" target="1.8" />
<module name="weixin-java-mp" target="1.8" />
<module name="weixin-java-open" target="1.8" />
<module name="weixin-java-pay" target="1.8" />
<module name="weixin-java-qidian" target="1.8" />
<module name="wx-java" target="1.8" />
<module name="wx-java-cp-spring-boot-starter" target="1.8" />
<module name="wx-java-miniapp-spring-boot-starter" target="1.8" />
<module name="wx-java-mp-spring-boot-starter" target="1.8" />
<module name="wx-java-open-spring-boot-starter" target="1.8" />
<module name="wx-java-pay-spring-boot-starter" target="1.8" />
<module name="wx-java-qidian-spring-boot-starter" target="1.8" />
<module name="wx-java-spring-boot-starters" target="1.8" />
</bytecodeTargetLevel>
</component>
</project>

26
.idea/encodings.xml generated
View File

@ -11,31 +11,9 @@
<file url="file://$PROJECT_DIR$/open/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/pay/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/pay/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-cp-spring-boot-starter/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-cp-spring-boot-starter/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-open-spring-boot-starter/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-open-spring-boot-starter/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-qidian-spring-boot-starter/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/spring-boot-starters/wx-java-qidian-spring-boot-starter/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/weixin-graal/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/weixin-graal/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/weixin-java-cp/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/weixin-java-cp/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/weixin-java-miniapp/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/weixin-java-miniapp/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/weixin-java-mp/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/weixin-java-mp/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/weixin-java-qidian/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/weixin-java-qidian/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/work/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/work/src/main/resources" charset="UTF-8" />
</component>
</project>

View File

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="ossez-repo-snapshots" />
<option name="name" value="OSSEZ Private Snapshots" />
<option name="url" value="https://repo.ossez.com/repository/maven-snapshots/" />
</remote-repository>
<remote-repository>
<option name="id" value="ossez-repo-releases" />
<option name="name" value="OSSEZ Private Releases" />
<option name="url" value="https://repo.ossez.com/repository/maven-releases/" />
<option name="name" value="iSharkFly Private Releases" />
<option name="url" value="https://repo.isharkfly.com/repository/isharkfly-maven-releases/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.ossez.com/repository/maven-public/" />
<option name="url" value="https://repo.isharkfly.com/repository/maven/" />
</remote-repository>
<remote-repository>
<option name="id" value="ossez-repo-snapshots" />
<option name="name" value="iSharkFly Private Snapshots" />
<option name="url" value="https://repo.isharkfly.com/repository/isharkfly-maven-snapshots/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />

6
.idea/jpa-buddy.xml generated
View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JpaBuddyIdeaProjectConfig">
<option name="renamerInitialized" value="true" />
</component>
</project>

12
.idea/php.xml generated
View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

View File

@ -14,28 +14,34 @@ WeChat-J 开发使用的库。
我们旨在提供一个初始化的开发框架,能够让应用在使用 Spring Boot 框架的基础上让你的微信公众号快速接入微信平台。
# 项目说明
我们在网上找了一些微信相关的 SDK要不就是缺少维护要不就是集成了非常多的功能因我们的公众号希望能够尽量的自动化处理所以我们在已有的基础上进行了一些修改和整合。
## 必要的准备
因微信开发 Java SDK 的开发其实并不非常复杂,主要是通过 HTTP 发送请求并且将获得的返回数据进行一些处理返回对象就可以了。
我们需要调用微信的 HTTP 接口,所以我们需要在 Java 中使用一个 Http 客户端,在当前我们的环境中,我们只使用 OkHttp 来进行实现。
在老的项目中,可能不少人会使用 Apache 的 HttpClient 来进行实现,但因为 OkHttp 广泛的被使用在安卓的手机上,所以使用 OkHttp 会更加简便。
在老的项目中,可能不少人会使用 Apache 的 HttpClient 来进行实现,但因为 OkHttp 广泛的被使用在安卓的手机上,所以使用 OkHttp
会更加简便。
* [Retrofit 是什么](https://www.ossez.com/t/retrofit/14302)
* [RxJava 是什么](https://www.ossez.com/t/rxjava/14305)
* [微信测试平台获得测试账号](https://www.ossez.com/t/topic/14281)
### Maven 和依赖
### Maven 和依赖
当前我们还没有把正式版发布到仓库中,我们还在使用 0.0.1-SNAPSHOT 版本进行内部测试。
最好的版本就是下载我们的源代码后 Fork 到你本地,然后直接使用 Maven 来进行编译。
#### 微信公众号WeChat Java Official Account
模块名wechat-j-oa
```xml
<dependency>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j-oa</artifactId>
@ -44,9 +50,11 @@ WeChat-J 开发使用的库。
```
#### 微信小程序WeChat Java Mini Programs
模块名wechat-j-mp
```xml
<dependency>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j-mp</artifactId>
@ -55,16 +63,37 @@ WeChat-J 开发使用的库。
```
#### 微信支付WeChat Java Pay
模块名wechat-j-pay (模块还在开发,无实际内容,请不要使用。)
模块名wechat-j-pay
```xml
<dependency>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j-pay</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
```
#### 企业微信WeChat Java WeCom
模块名wechat-j-work (模块还在开发,无实际内容,请不要使用。)
模块名wechat-j-work
```xml
<dependency>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j-work</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
```
#### 微信开放平台WeChat Java Open
模块名wechat-j-open
```xml
<dependency>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j-open</artifactId>
@ -73,17 +102,18 @@ WeChat-J 开发使用的库。
```
### 其他内容
* 任何有关讨论,请访问 [社区](https://www.ossez.com/tag/wechat)您可以在这里提出功能需求Bug 修复,问题解答。
* 可以考虑使用 http://paste.ubuntu.com 来对你在提交问题的时候出现的为代码进行简化。
### 框架和案例
如果你想登记你的项目,请[访问这里](https://www.ossez.com/t/wechat-j-demo/14303)。
同时,我们也提供了一些开发框架,能够让你直接检出项目就可以直接对微信 SDK 进行接入和测试。
* [公众号 Spring Boot 测试程序](https://github.com/honeymoose/WeChat-Official-Account-Spring)
# 联系方式
请使用下面的联系方式和我们联系。

View File

@ -2,195 +2,185 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j-common</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>wechat-j-common</artifactId>
<packaging>jar</packaging>
<name>WeChat Java Common</name>
<description>The module is common for all other package</description>
<parent>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.jodd</groupId>
<artifactId>jodd-http</artifactId>
<scope>provided</scope>
</dependency>
<name>WeChat Java Common</name>
<description>The module is common for all other package</description>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.36</version>
</dependency>
<dependencies>
<dependency>
<groupId>org.jodd</groupId>
<artifactId>jodd-http</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-guava</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
<exclusions>
<exclusion>
<groupId>pull-parser</groupId>
<artifactId>pull-parser</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>com.github.jedis-lock</groupId>
<artifactId>jedis-lock</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-guava</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
<exclusions>
<exclusion>
<groupId>pull-parser</groupId>
<artifactId>pull-parser</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>com.github.jedis-lock</groupId>
<artifactId>jedis-lock</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>native-image</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<annotationProcessors>
com.github.binarywang.wx.graal.GraalProcessor,lombok.launch.AnnotationProcessorHider$AnnotationProcessor,lombok.launch.AnnotationProcessorHider$ClaimingProcessor
</annotationProcessors>
<annotationProcessorPaths>
<path>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-graal</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</build>
</profile>
</profiles>
<profiles>
<profile>
<id>native-image</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<annotationProcessors>
com.github.binarywang.wx.graal.GraalProcessor,lombok.launch.AnnotationProcessorHider$AnnotationProcessor,lombok.launch.AnnotationProcessorHider$ClaimingProcessor
</annotationProcessors>
<annotationProcessorPaths>
<path>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-graal</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,32 @@
package com.ossez.wechat.common.api;
import com.ossez.wechat.common.model.WeChatAccessToken;
import com.ossez.wechat.common.model.WeChatApiDomainIp;
import com.ossez.wechat.common.model.req.NetworkCheck;
import com.ossez.wechat.common.model.req.QueryQuota;
import com.ossez.wechat.common.model.res.NetworkCheckResponse;
import com.ossez.wechat.common.model.res.QueryQuotaResponse;
import io.reactivex.Single;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
public interface WeChatOfficialAccountApi {
@GET("/cgi-bin/token")
Single<WeChatAccessToken> getAccessToken(@Query("grant_type") String grantType, @Query("appid") String appId, @Query("secret") String secret);
@GET("/cgi-bin/get_api_domain_ip")
Single<WeChatApiDomainIp> getDomainIPs();
@POST("/cgi-bin/callback/check")
Single<NetworkCheckResponse> checkNetwork(@Body NetworkCheck request);
@POST("/cgi-bin/clear_quota")
Single<NetworkCheckResponse> clearQuota(@Body NetworkCheck request);
@POST("/cgi-bin/openapi/quota/get")
Single<QueryQuotaResponse> queryQuota(@Body QueryQuota request);
}

View File

@ -0,0 +1,26 @@
package com.ossez.wechat.common.api;
import com.ossez.wechat.common.model.WeChatAccessToken;
import com.ossez.wechat.common.model.WeChatApiDomainIp;
import com.ossez.wechat.common.model.WeChatOAuth2AccessToken;
import com.ossez.wechat.common.model.entity.WeChatOAuth2UserInfo;
import com.ossez.wechat.common.model.req.NetworkCheck;
import com.ossez.wechat.common.model.req.QueryQuota;
import com.ossez.wechat.common.model.res.NetworkCheckResponse;
import com.ossez.wechat.common.model.res.QueryQuotaResponse;
import io.reactivex.Single;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
public interface WeChatOpenApi {
@GET("/sns/oauth2/access_token")
Single<WeChatOAuth2AccessToken> getAccessToken(@Query("grant_type") String grantType, @Query("appid") String appId, @Query("secret") String secret, @Query("code") String code);
@GET("/sns/userinfo")
Single<WeChatOAuth2UserInfo> getWeChatUserInfo(@Query("access_token") String accessToken, @Query("openid") String openId);
}

View File

@ -1,70 +0,0 @@
package com.ossez.wechat.common.bean;
import com.google.gson.annotations.SerializedName;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import lombok.Data;
import java.io.Serializable;
/**
* oauth2用户个人信息.
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
* created on 2020-10-11
*/
@Data
public class WxOAuth2UserInfo implements Serializable {
private static final long serialVersionUID = 3181943506448954725L;
/**
* openid 普通用户的标识对当前开发者帐号唯一
*/
private String openid;
/**
* nickname 普通用户昵称
*/
private String nickname;
/**
* sex 普通用户性别1为男性2为女性
*/
private Integer sex;
/**
* city 普通用户个人资料填写的城市
*/
private String city;
/**
* province 普通用户个人资料填写的省份
*/
private String province;
/**
* country 国家如中国为CN
*/
private String country;
/**
* headimgurl 用户头像最后一个数值代表正方形头像大小有0466496132数值可选0代表640*640正方形头像
* 用户没有头像时该项为空
*/
@SerializedName("headimgurl")
private String headImgUrl;
/**
* unionid 用户统一标识针对一个微信开放平台帐号下的应用同一用户的unionid是唯一的
*/
@SerializedName("unionid")
private String unionId;
/**
* privilege 用户特权信息json数组如微信沃卡用户为chinaunicom
*/
@SerializedName("privilege")
private String[] privileges;
/**
* is_snapshotuser 是否为快照页模式虚拟账号值为0时是普通用户1时是虚拟帐号
*/
@SerializedName("is_snapshotuser")
private Integer snapshotUser;
public static WxOAuth2UserInfo fromJson(String json) {
return WxGsonBuilder.create().fromJson(json, WxOAuth2UserInfo.class);
}
}

View File

@ -1,96 +0,0 @@
package com.ossez.wechat.common.bean.menu;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.annotations.SerializedName;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import lombok.Data;
/**
* menu button.
*
* @author Daniel Qian
*/
@Data
public class WxMenuButton implements Serializable {
private static final long serialVersionUID = -1070939403109776555L;
/**
* <pre>
* 菜单的响应动作类型.
* view表示网页类型
* click表示点击类型
* miniprogram表示小程序类型
* </pre>
*/
private String type;
/**
* 菜单标题不超过16个字节子菜单不超过60个字节.
*/
private String name;
/**
* <pre>
* 菜单KEY值用于消息接口推送不超过128字节.
* click等点击类型必须
* </pre>
*/
private String key;
/**
* <pre>
* 网页链接.
* 用户点击菜单可打开链接不超过1024字节type为miniprogram时不支持小程序的老版本客户端将打开本url
* viewminiprogram类型必须
* </pre>
*/
private String url;
/**
* <pre>
* 调用新增永久素材接口返回的合法media_id.
* media_id类型和view_limited类型必须
* </pre>
*/
@SerializedName("media_id")
private String mediaId;
/**
* <pre>
* 调用发布图文接口获得的article_id.
* article_id类型和article_view_limited类型必须
* </pre>
*/
@SerializedName("article_id")
private String articleId;
/**
* <pre>
* 小程序的appid.
* miniprogram类型必须
* </pre>
*/
@SerializedName("appid")
private String appId;
/**
* <pre>
* 小程序的页面路径.
* miniprogram类型必须
* </pre>
*/
@SerializedName("pagepath")
private String pagePath;
@SerializedName("sub_button")
private List<WxMenuButton> subButtons = new ArrayList<>();
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
}

View File

@ -1,51 +0,0 @@
package com.ossez.wechat.common.bean.oauth2;
import com.google.gson.annotations.SerializedName;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import lombok.Data;
import java.io.Serializable;
/**
* https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
*
* @author Daniel Qian
*/
@Data
public class WxOAuth2AccessToken implements Serializable {
private static final long serialVersionUID = -1345910558078620805L;
@SerializedName("access_token")
private String accessToken;
@SerializedName("expires_in")
private int expiresIn = -1;
@SerializedName("refresh_token")
private String refreshToken;
@SerializedName("openid")
private String openId;
@SerializedName("scope")
private String scope;
@SerializedName("is_snapshotuser")
private Integer snapshotUser;
/**
* https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=11513156443eZYea&version=&lang=zh_CN.
* 本接口在scope参数为snsapi_base时不再提供unionID字段
*/
@SerializedName("unionid")
private String unionId;
public static WxOAuth2AccessToken fromJson(String json) {
return WxGsonBuilder.create().fromJson(json, WxOAuth2AccessToken.class);
}
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
}

View File

@ -1,9 +1,8 @@
package com.ossez.wechat.oa.config;
package com.ossez.wechat.common.config;
import com.ossez.wechat.common.model.WeChatAccessToken;
import com.ossez.wechat.common.enums.TicketType;
import com.ossez.wechat.common.util.http.apache.ApacheHttpClientBuilder;
import com.ossez.wechat.oa.api.impl.BaseWeChatOfficialAccountServiceImpl;
import java.io.File;
import java.util.concurrent.locks.Lock;
@ -96,6 +95,8 @@ public interface ConfigStorage {
*/
void updateTicket(TicketType type, String ticket, int expiresInSeconds);
String getOpenAppId();
String getOpenSecret();
/**
* Gets app id.
*

View File

@ -1,10 +1,9 @@
package com.ossez.wechat.oa.config;
package com.ossez.wechat.common.config;
import lombok.Data;
import com.ossez.wechat.common.model.WeChatAccessToken;
import com.ossez.wechat.common.enums.TicketType;
import com.ossez.wechat.common.util.http.apache.ApacheHttpClientBuilder;
import com.ossez.wechat.oa.util.json.WxMpGsonBuilder;
import java.io.File;
import java.io.Serializable;
@ -20,6 +19,8 @@ import java.util.concurrent.locks.ReentrantLock;
public class DefaultConfigStorage implements ConfigStorage, Serializable {
private static final long serialVersionUID = -6646519023303395185L;
protected volatile String openAppId;
protected volatile String openSecret;
protected volatile String appId;
protected volatile String secret;
protected volatile String token;
@ -174,10 +175,6 @@ public class DefaultConfigStorage implements ConfigStorage, Serializable {
}
}
@Override
public String toString() {
return WxMpGsonBuilder.create().toJson(this);
}
@Override
public boolean autoRefreshToken() {

View File

@ -1,6 +1,6 @@
package com.ossez.wechat.oa.config.impl;
package com.ossez.wechat.common.config;
import com.ossez.wechat.oa.config.DefaultConfigStorage;
import com.ossez.wechat.common.config.DefaultConfigStorage;
import lombok.Data;
import com.ossez.wechat.common.model.WeChatAccessToken;
@ -11,7 +11,6 @@ import java.util.concurrent.ConcurrentHashMap;
* created on 2021/1/16
* 提供accesstoken保存在concurrenthashmap中的实现支持高并发仅限于单机部署
*/
@Data
public class MapConfigStorage extends DefaultConfigStorage {
private static final long serialVersionUID = 5311395137835650104L;

View File

@ -1,6 +1,6 @@
package com.ossez.wechat.oa.config.impl;
package com.ossez.wechat.common.config;
import com.ossez.wechat.oa.config.DefaultConfigStorage;
import com.ossez.wechat.common.config.DefaultConfigStorage;
import lombok.Data;
import lombok.EqualsAndHashCode;
import com.ossez.wechat.common.enums.TicketType;
@ -18,8 +18,6 @@ import java.util.concurrent.TimeUnit;
*
* @author nickwong
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class RedisConfigStorage extends DefaultConfigStorage {
private static final long serialVersionUID = -988502871997239733L;

View File

@ -0,0 +1,68 @@
package com.ossez.wechat.common.config;
import com.ossez.wechat.common.constant.WeChatConstant;
/**
* 微信接口地址域名部分的自定义设置信息.
*/
public class WxMpHostConfig {
/**
* 对应于https://api.weixin.qq.com
*/
private String apiHost;
/**
* 对应于https://open.weixin.qq.com
*/
private String openHost;
/**
* 对应于https://mp.weixin.qq.com
*/
private String mpHost;
public static String buildUrl(WxMpHostConfig hostConfig, String prefix, String path) {
if (hostConfig == null) {
return prefix + path;
}
if (hostConfig.getApiHost() != null && prefix.equals(WeChatConstant.ENDPOINT_WECHAT)) {
return hostConfig.getApiHost() + path;
}
if (hostConfig.getMpHost() != null && prefix.equals(WeChatConstant.ENDPOINT_MP)) {
return hostConfig.getMpHost() + path;
}
if (hostConfig.getOpenHost() != null && prefix.equals(WeChatConstant.ENDPOINT_OPEN)) {
return hostConfig.getOpenHost() + path;
}
return prefix + path;
}
public String getApiHost() {
return apiHost;
}
public void setApiHost(String apiHost) {
this.apiHost = apiHost;
}
public String getOpenHost() {
return openHost;
}
public void setOpenHost(String openHost) {
this.openHost = openHost;
}
public String getMpHost() {
return mpHost;
}
public void setMpHost(String mpHost) {
this.mpHost = mpHost;
}
}

View File

@ -1,4 +1,4 @@
package com.ossez.wechat.oa.constant;
package com.ossez.wechat.common.constant;
/**
* <pre>
@ -8,7 +8,7 @@ package com.ossez.wechat.oa.constant;
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class WxMpEventConstants {
public class OfficialAccountEventConstants {
/**
* 门店审核事件.
*/

View File

@ -1,6 +1,7 @@
package com.ossez.wechat.common.constant;
import com.ossez.wechat.common.enums.WeChatErrorCode;
import java.util.*;
/**
@ -10,7 +11,10 @@ import java.util.*;
*/
public class WeChatConstant {
public static final String ENDPOINT_OFFICIAL_ACCOUNT = "https://api.weixin.qq.com/cgi-bin/";
public static final String ENDPOINT_WECHAT = "https://api.weixin.qq.com";
public static final String ENDPOINT_MP = "https://mp.weixin.qq.com";
public static final String ENDPOINT_OPEN = "https://open.weixin.qq.com";
/**
* access_token 相关错误代码
@ -54,51 +58,33 @@ public class WeChatConstant {
/**
* 主动发送消息(即客服消息)的消息类型.
*/
public static class KefuMsgType {
public static class MsgType {
/**
* 文本消息.
* 消息类型:
* text(文本)
* image(图片)
* voice(语音)
* video(视频)
* music(音乐)
* news(图文消息 - 点击跳转到外链)
* mpnews(图文消息 - 点击跳转到图文消息页面)
* wxcard(卡券)
* miniprogrampage(小程序)
* markdown(目前仅支持markdown语法的子集微工作台原企业号不支持展示markdown消息)
* file(发送文件 - CP专用)
* textcard(文本卡片消息 - CP专用)
* wxcard(卡券消息)
*/
public static final String TEXT = "text";
/**
* 图片消息.
*/
public static final String IMAGE = "image";
/**
* 语音消息.
*/
public static final String VOICE = "voice";
/**
* 视频消息.
*/
public static final String VIDEO = "video";
/**
* 音乐消息.
*/
public static final String MUSIC = "music";
/**
* 图文消息点击跳转到外链.
*/
public static final String NEWS = "news";
/**
* 图文消息点击跳转到图文消息页面.
*/
public static final String MPNEWS = "mpnews";
/**
* markdown消息.
* 目前仅支持markdown语法的子集微工作台原企业号不支持展示markdown消息
*/
public static final String MARKDOWN = "markdown";
/**
* 发送文件CP专用.
*/
public static final String FILE = "file";
/**
* 文本卡片消息CP专用.
*/
public static final String TEXTCARD = "textcard";
/**
* 卡券消息.
*/
public static final String WXCARD = "wxcard";
/**
* 转发到客服的消息.

View File

@ -0,0 +1,20 @@
package com.ossez.wechat.common.enums;
/**
* The language for WeChat API can support
*
* @author YuCheng Hu
*/
public enum Language {
ZH_CN("zh_CN"), EN_US("en_US");
private String code;
Language(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}

View File

@ -0,0 +1,12 @@
package com.ossez.wechat.common.enums;
/**
* WeChat's Storage Category
*
* We provide implement for MEM(RAM) and REDIS
*
* @author YuCheng Hu
*/
public enum WeChatStorageCategory {
MEM, REDIS
}

View File

@ -0,0 +1,25 @@
package com.ossez.wechat.common.enums;
/**
* 微信卡券
*
* @author YuCheng
*/
public enum WxCardType {
MEMBER_CARD("MEMBER_CARD"),
GROUPON("GROUPON"),
CASH("CASH"),
DISCOUNT("DISCOUNT"),
GIFT("GIFT"),
GENERAL_COUPON("GENERAL_COUPON");
private String code;
WxCardType(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
package com.ossez.wechat.common.exception;
/**
* @author Daniel Qian
*/
public class DataStructureException extends WxErrorException {
private static final long serialVersionUID = -6357149550353160810L;
private final WxError error;
private static final int DEFAULT_ERROR_CODE = -99;
public DataStructureException(String message) {
this(WxError.builder().errorCode(DEFAULT_ERROR_CODE).errorMsg(message).build());
}
public DataStructureException(WxError error) {
super(error.toString());
this.error = error;
}
public WxError getError() {
return this.error;
}
}

View File

@ -40,4 +40,5 @@ public class WeChatAccessToken {
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
}

View File

@ -0,0 +1,27 @@
package com.ossez.wechat.common.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import java.util.List;
/**
* WeChatAccessToken Response Object
*
* @author YuCheng Hu
*/
public class WeChatApiDomainIp {
@JsonProperty("ip_list")
private List<String> ipList;
public List<String> getIpList() {
return ipList;
}
public void setIpList(List<String> ipList) {
this.ipList = ipList;
}
}

View File

@ -0,0 +1,16 @@
package com.ossez.wechat.common.model;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
public class WeChatHost implements Serializable {
private static final long serialVersionUID = -7648920647310280817L;
private String apiHost;
private String openHost;
private String mpHost;
}

View File

@ -0,0 +1,107 @@
package com.ossez.wechat.common.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.annotations.SerializedName;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import lombok.Data;
import java.io.Serializable;
/**
* https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
*
* @author Daniel Qian
*/
public class WeChatOAuth2AccessToken implements Serializable {
private static final long serialVersionUID = 5755678830089329526L;
@JsonProperty("access_token")
private String accessToken;
@JsonProperty("expires_in")
private int expiresIn = -1;
@JsonProperty("refresh_token")
private String refreshToken;
@JsonProperty("openid")
private String openId;
@JsonProperty("scope")
private String scope;
@JsonProperty("is_snapshotuser")
private Integer snapshotUser;
/**
* https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=11513156443eZYea&version=&lang=zh_CN.
* 本接口在scope参数为snsapi_base时不再提供unionID字段
*/
@SerializedName("unionid")
private String unionId;
public static WeChatOAuth2AccessToken fromJson(String json) {
return WxGsonBuilder.create().fromJson(json, WeChatOAuth2AccessToken.class);
}
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public Integer getSnapshotUser() {
return snapshotUser;
}
public void setSnapshotUser(Integer snapshotUser) {
this.snapshotUser = snapshotUser;
}
public String getUnionId() {
return unionId;
}
public void setUnionId(String unionId) {
this.unionId = unionId;
}
}

View File

@ -0,0 +1,34 @@
package com.ossez.wechat.common.model;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* WeChatStatus Response Object
*
* @author YuCheng Hu
*/
public class WeChatStatus {
@JsonProperty("errcode")
private int errCode = 0;
@JsonProperty("errmsg")
private String errMsg;
public int getErrCode() {
return errCode;
}
public void setErrCode(int errCode) {
this.errCode = errCode;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
}

View File

@ -0,0 +1,129 @@
package com.ossez.wechat.common.model.entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.annotations.SerializedName;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import lombok.Data;
import java.io.Serializable;
/**
* oauth2用户个人信息.
* <pre>
* {
* "openid":"OPENID",
* "nickname":"NICKNAME",
* "sex":1,
* "province":"PROVINCE",
* "city":"CITY",
* "country":"COUNTRY",
* "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
* "privilege":[
* "PRIVILEGE1",
* "PRIVILEGE2"
* ],
* "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
*
* }
* </pre>
*
* @author YuCheng
*/
@Data
public class WeChatOAuth2UserInfo implements Serializable {
private static final long serialVersionUID = 3181943506448954725L;
@JsonProperty("openid")
private String openid;
@JsonProperty("nickname")
private String nickname;
@JsonProperty("sex")
private Integer sex;
@JsonProperty("city")
private String city;
@JsonProperty("province")
private String province;
@JsonProperty("country")
private String country;
@JsonProperty("headimgurl")
private String headImgUrl;
@JsonProperty("unionid")
private String unionId;
@JsonProperty("privilege")
private String[] privileges;
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getHeadImgUrl() {
return headImgUrl;
}
public void setHeadImgUrl(String headImgUrl) {
this.headImgUrl = headImgUrl;
}
public String getUnionId() {
return unionId;
}
public void setUnionId(String unionId) {
this.unionId = unionId;
}
public String[] getPrivileges() {
return privileges;
}
public void setPrivileges(String[] privileges) {
this.privileges = privileges;
}
}

View File

@ -0,0 +1,31 @@
package com.ossez.wechat.common.model.entity;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* WeChatAccessToken Response Object
*
* @author YuCheng Hu
*/
public class WeChatResponseStatus {
@JsonProperty("errcode")
private Integer errorCode;
@JsonProperty("errmsg")
private String errorMsg;
public Integer getErrorCode() {
return errorCode;
}
public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}

View File

@ -0,0 +1,104 @@
package com.ossez.wechat.common.model.entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.experimental.Accessors;
@Accessors(chain = true)
public class WeChatUser {
@JsonProperty(value = "openid", required = true)
private String openId;
@JsonProperty(required = true)
private String nickname;
private Integer sex;
private String language;
private String city;
private String province;
private String country;
@JsonProperty(value = "headimgurl")
private String headImgURL;
@JsonProperty(value = "unionid", required = true)
private String unionId;
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getHeadImgURL() {
return headImgURL;
}
public void setHeadImgURL(String headImgURL) {
this.headImgURL = headImgURL;
}
public String getUnionId() {
return unionId;
}
public void setUnionId(String unionId) {
this.unionId = unionId;
}
}

View File

@ -0,0 +1,43 @@
package com.ossez.wechat.common.model.entity.builder;
import com.ossez.wechat.common.model.entity.menu.MenuButton;
import com.ossez.wechat.common.model.req.MenuRequest;
import java.util.List;
public class MenuButtonBuilder {
private List<MenuButton> subButtonList;
private String type;
private String name;
private String key;
private String url;
public MenuButtonBuilder setSubButtonList(List<MenuButton> subButtonList) {
this.subButtonList = subButtonList;
return this;
}
public MenuButtonBuilder setType(String type) {
this.type = type;
return this;
}
public MenuButtonBuilder setName(String name) {
this.name = name;
return this;
}
public MenuButtonBuilder setKey(String key) {
this.key = key;
return this;
}
public MenuButtonBuilder setUrl(String url) {
this.url = url;
return this;
}
public MenuButton createMenuButton() {
return new MenuButton(subButtonList, type, name, key, url);
}
}

View File

@ -0,0 +1,40 @@
package com.ossez.wechat.common.model.entity.menu;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.annotations.SerializedName;
import com.ossez.wechat.common.model.req.MenuRequest;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import lombok.Data;
/**
* menu button.
*
* @author Daniel Qian
*/
@Data
public class MenuButton implements Serializable {
private static final long serialVersionUID = -1070939403109776555L;
public MenuButton(List<MenuButton> subButtonList, String type, String name, String key, String url) {
this.subButtonList = subButtonList;
this.type = type;
this.name = name;
this.key = key;
this.url = url;
}
@JsonProperty(value = "sub_button")
private List<MenuButton> subButtonList;
@JsonProperty("type")
private String type;
@JsonProperty("name")
private String name;
@JsonProperty("key")
private String key;
@JsonProperty("url")
private String url;
}

View File

@ -1,4 +1,4 @@
package com.ossez.wechat.common.bean.menu;
package com.ossez.wechat.common.model.entity.menu;
import java.io.InputStream;
import java.io.InputStreamReader;
@ -19,7 +19,7 @@ import lombok.Data;
public class WxMenu implements Serializable {
private static final long serialVersionUID = -7083914585539687746L;
private List<WxMenuButton> buttons = new ArrayList<>();
private List<MenuButton> buttons = new ArrayList<>();
private WxMenuRule matchRule;

View File

@ -1,4 +1,4 @@
package com.ossez.wechat.common.bean.menu;
package com.ossez.wechat.common.model.entity.menu;
import java.io.Serializable;

View File

@ -0,0 +1,128 @@
package com.ossez.wechat.common.model.req;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
/**
* CustomMessage
*
* @author YuCheng
*/
public class CustomMessage implements Serializable {
private static final long serialVersionUID = -9196732086954365246L;
@JsonProperty("touser")
private String toUser;
@JsonProperty("msgtype")
private String msgType;
@JsonProperty("text")
private KfText text;
@JsonProperty("image")
private KfImage image;
@JsonProperty("link")
private KfLink link;
@JsonProperty("miniprogrampage")
private KfMaPage maPage;
@Data
@AllArgsConstructor
public static class KfText implements Serializable {
private static final long serialVersionUID = 151122958720941270L;
private String content;
}
@Data
@AllArgsConstructor
public static class KfImage implements Serializable {
private static final long serialVersionUID = -5409342945117300782L;
@SerializedName("media_id")
private String mediaId;
}
@Data
@Builder
public static class KfLink implements Serializable {
private static final long serialVersionUID = -6728776817556127413L;
private String title;
private String description;
private String url;
@SerializedName("thumb_url")
private String thumbUrl;
}
@Data
@Builder
public static class KfMaPage implements Serializable {
private static final long serialVersionUID = -5633492281871634466L;
private String title;
@SerializedName("pagepath")
private String pagePath;
@SerializedName("thumb_media_id")
private String thumbMediaId;
}
public String getToUser() {
return toUser;
}
public void setToUser(String toUser) {
this.toUser = toUser;
}
public String getMsgType() {
return msgType;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public KfText getText() {
return text;
}
public void setText(KfText text) {
this.text = text;
}
public KfImage getImage() {
return image;
}
public void setImage(KfImage image) {
this.image = image;
}
public KfLink getLink() {
return link;
}
public void setLink(KfLink link) {
this.link = link;
}
public KfMaPage getMaPage() {
return maPage;
}
public void setMaPage(KfMaPage maPage) {
this.maPage = maPage;
}
}

View File

@ -0,0 +1,40 @@
package com.ossez.wechat.common.model.req;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
/**
* CustomMessage
*
* @author YuCheng
*/
public class DataCubeRequest implements Serializable {
private static final long serialVersionUID = -9196732086954365246L;
@JsonProperty(value = "begin_date", required = true)
private String beginDate;
@JsonProperty(value = "end_date", required = true)
private String endDate;
public String getBeginDate() {
return beginDate;
}
public void setBeginDate(String beginDate) {
this.beginDate = beginDate;
}
public String getEndDate() {
return endDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
}

View File

@ -0,0 +1,28 @@
package com.ossez.wechat.common.model.req;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ossez.wechat.common.model.entity.menu.MenuButton;
import com.ossez.wechat.common.model.res.DataCubeArticle;
import java.io.Serializable;
import java.util.List;
/**
* CustomMessage
*
* @author YuCheng
*/
public class MenuRequest implements Serializable {
private static final long serialVersionUID = -9196732086954365246L;
@JsonProperty(value = "button", required = true)
private List<MenuButton> buttonList;
public List<MenuButton> getButtonList() {
return buttonList;
}
public void setButtonList(List<MenuButton> buttonList) {
this.buttonList = buttonList;
}
}

View File

@ -0,0 +1,33 @@
package com.ossez.wechat.common.model.req;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import org.apache.commons.lang3.StringUtils;
/**
* WeChatAccessToken Response Object
*
* @author YuCheng Hu
*/
public class NetworkCheck {
@JsonProperty("action")
private String action = "all";
@JsonProperty("check_operator")
private String checkOperator = StringUtils.upperCase("DEFAULT");
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getCheckOperator() {
return checkOperator;
}
public void setCheckOperator(String checkOperator) {
this.checkOperator = checkOperator;
}
}

View File

@ -0,0 +1,22 @@
package com.ossez.wechat.common.model.req;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.commons.lang3.StringUtils;
/**
* WeChatAccessToken Response Object
*
* @author YuCheng Hu
*/
public class QueryQuota {
@JsonProperty("cgi_path")
private String cgiPath = "/cgi-bin/message/custom/send";
public String getCgiPath() {
return cgiPath;
}
public void setCgiPath(String cgiPath) {
this.cgiPath = cgiPath;
}
}

View File

@ -0,0 +1,130 @@
package com.ossez.wechat.common.model.res;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
/**
* UserSummaryResponse Object
*
* @author YuCheng Hu
*/
public class DataCubeArticle {
@JsonProperty("list")
private List<ArticleData> articleDataList;
public static class ArticleData {
@JsonProperty("ref_date")
private String refDate;
@JsonProperty("msgid")
private String msgId;
@JsonProperty("title")
private String title;
@JsonProperty("int_page_read_user")
private Long intPageReadUser;
@JsonProperty("ori_page_read_user")
private Long oriPageReadUser;
@JsonProperty("ori_page_read_count")
private Long oriPageReadCount;
@JsonProperty("share_user")
private Long shareUser;
@JsonProperty("shareCount")
private Long shareCount;
@JsonProperty("add_to_fav_user")
private Long addToFavUser;
@JsonProperty("add_to_fav_count")
private Long addToFavCount;
public String getRefDate() {
return refDate;
}
public void setRefDate(String refDate) {
this.refDate = refDate;
}
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Long getIntPageReadUser() {
return intPageReadUser;
}
public void setIntPageReadUser(Long intPageReadUser) {
this.intPageReadUser = intPageReadUser;
}
public Long getOriPageReadUser() {
return oriPageReadUser;
}
public void setOriPageReadUser(Long oriPageReadUser) {
this.oriPageReadUser = oriPageReadUser;
}
public Long getOriPageReadCount() {
return oriPageReadCount;
}
public void setOriPageReadCount(Long oriPageReadCount) {
this.oriPageReadCount = oriPageReadCount;
}
public Long getShareUser() {
return shareUser;
}
public void setShareUser(Long shareUser) {
this.shareUser = shareUser;
}
public Long getShareCount() {
return shareCount;
}
public void setShareCount(Long shareCount) {
this.shareCount = shareCount;
}
public Long getAddToFavUser() {
return addToFavUser;
}
public void setAddToFavUser(Long addToFavUser) {
this.addToFavUser = addToFavUser;
}
public Long getAddToFavCount() {
return addToFavCount;
}
public void setAddToFavCount(Long addToFavCount) {
this.addToFavCount = addToFavCount;
}
}
public List<ArticleData> getArticleDataList() {
return articleDataList;
}
public void setArticleDataList(List<ArticleData> articleDataList) {
this.articleDataList = articleDataList;
}
}

View File

@ -0,0 +1,78 @@
package com.ossez.wechat.common.model.res;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
/**
* UserSummaryResponse Object
*
* @author YuCheng Hu
*/
public class DataCubeUser {
@JsonProperty("list")
private List<UserData> userDataList;
public static class UserData {
@JsonProperty("ref_date")
private String refDate;
@JsonProperty("user_source")
private Long userSource;
@JsonProperty("new_user")
private Long newUser;
@JsonProperty("cancel_user")
private Long cancelUser;
@JsonProperty("cumulate_user")
private Long cumulateUser;
public String getRefDate() {
return refDate;
}
public void setRefDate(String refDate) {
this.refDate = refDate;
}
public Long getUserSource() {
return userSource;
}
public void setUserSource(Long userSource) {
this.userSource = userSource;
}
public Long getNewUser() {
return newUser;
}
public void setNewUser(Long newUser) {
this.newUser = newUser;
}
public Long getCancelUser() {
return cancelUser;
}
public void setCancelUser(Long cancelUser) {
this.cancelUser = cancelUser;
}
public Long getCumulateUser() {
return cumulateUser;
}
public void setCumulateUser(Long cumulateUser) {
this.cumulateUser = cumulateUser;
}
}
public List<UserData> getUserDataList() {
return userDataList;
}
public void setUserDataList(List<UserData> userDataList) {
this.userDataList = userDataList;
}
}

View File

@ -0,0 +1,35 @@
package com.ossez.wechat.common.model.res;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ossez.wechat.common.api.WxMessageInMemoryDuplicateCheckerSingleton;
import org.apache.commons.lang3.StringUtils;
/**
* WeChatAccessToken Response Object
*
* @author YuCheng Hu
*/
public class NetworkCheckResponse {
@JsonProperty("dns")
private String dns;
@JsonProperty("ping")
private Ping ping;
private static class dns {
@JsonProperty("ip")
private String ip;
@JsonProperty("real_operator")
private String realOperator;
}
private static class Ping {
@JsonProperty("ip")
private String ip;
@JsonProperty("from_operator")
private String fromOperator;
@JsonProperty("package_loss")
private String packageLoss;
@JsonProperty("time")
private String time;
}
}

View File

@ -0,0 +1,66 @@
package com.ossez.wechat.common.model.res;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* WeChatAccessToken Response Object
*
* @author YuCheng Hu
*/
public class QueryQuotaResponse {
@JsonProperty("errcode")
private Integer errorCode;
@JsonProperty("errmsg")
private String errorMsg;
@JsonProperty("quota")
private Quota quota;
private static class Quota {
@JsonProperty("daily_limit")
private String dailyLimit;
@JsonProperty("used")
private String used;
@JsonProperty("remain")
private String remain;
public String getDailyLimit() {
return dailyLimit;
}
public void setDailyLimit(String dailyLimit) {
this.dailyLimit = dailyLimit;
}
public String getUsed() {
return used;
}
public void setUsed(String used) {
this.used = used;
}
public String getRemain() {
return remain;
}
public void setRemain(String remain) {
this.remain = remain;
}
}
public Integer getErrorCode() {
return errorCode;
}
public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}

View File

@ -1,7 +1,7 @@
package com.ossez.wechat.common.service;
import com.ossez.wechat.common.bean.WxOAuth2UserInfo;
import com.ossez.wechat.common.bean.oauth2.WxOAuth2AccessToken;
import com.ossez.wechat.common.model.entity.WeChatOAuth2UserInfo;
import com.ossez.wechat.common.model.WeChatOAuth2AccessToken;
import com.ossez.wechat.common.exception.WxErrorException;
/**
@ -34,7 +34,7 @@ public interface WxOAuth2Service {
* @return token对象
* @throws WxErrorException .
*/
WxOAuth2AccessToken getAccessToken(String code) throws WxErrorException;
WeChatOAuth2AccessToken getAccessToken(String code) throws WxErrorException;
/**
* 用code换取oauth2的access token.
@ -45,7 +45,7 @@ public interface WxOAuth2Service {
* @return token对象
* @throws WxErrorException .
*/
WxOAuth2AccessToken getAccessToken(String appId, String appSecret, String code) throws WxErrorException;
WeChatOAuth2AccessToken getAccessToken(String appId, String appSecret, String code) throws WxErrorException;
/**
* <pre>
@ -56,7 +56,7 @@ public interface WxOAuth2Service {
* @return 新的token对象
* @throws WxErrorException .
*/
WxOAuth2AccessToken refreshAccessToken(String refreshToken) throws WxErrorException;
WeChatOAuth2AccessToken refreshAccessToken(String refreshToken) throws WxErrorException;
/**
* <pre>
@ -68,7 +68,7 @@ public interface WxOAuth2Service {
* @return 用户对象
* @throws WxErrorException .
*/
WxOAuth2UserInfo getUserInfo(WxOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException;
WeChatOAuth2UserInfo getUserInfo(WeChatOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException;
/**
* <pre>
@ -78,6 +78,6 @@ public interface WxOAuth2Service {
* @param oAuth2AccessToken token对象
* @return 是否有效
*/
boolean validateAccessToken(WxOAuth2AccessToken oAuth2AccessToken);
boolean validateAccessToken(WeChatOAuth2AccessToken oAuth2AccessToken);
}

View File

@ -1,17 +1,16 @@
package com.ossez.wechat.common.util;
import com.ossez.wechat.common.exception.WxErrorException;
import lombok.extern.slf4j.Slf4j;
import com.ossez.wechat.common.api.WxErrorExceptionHandler;
import com.ossez.wechat.common.exception.WxErrorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Daniel Qian
*/
@Slf4j
public class LogExceptionHandler implements WxErrorExceptionHandler {
@Override
public void handle(WxErrorException e) {
log.error("Error happens", e);
}
private final Logger log = LoggerFactory.getLogger(LogExceptionHandler.class);
@Override
public void handle(WxErrorException e) {
log.error("App Error", e);
}
}

View File

@ -1,17 +0,0 @@
package com.ossez.wechat.common.util;
public class RandomUtils {
private static final String RANDOM_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private static final java.util.Random RANDOM = new java.util.Random();
public static String getRandomStr() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 16; i++) {
sb.append(RANDOM_STR.charAt(RANDOM.nextInt(RANDOM_STR.length())));
}
return sb.toString();
}
}

View File

@ -5,7 +5,7 @@ import com.google.gson.GsonBuilder;
import com.ossez.wechat.common.exception.WxError;
import com.ossez.wechat.common.model.WeChatAccessToken;
import com.ossez.wechat.common.bean.WxNetCheckResult;
import com.ossez.wechat.common.bean.menu.WxMenu;
import com.ossez.wechat.common.model.entity.menu.WxMenu;
import com.ossez.wechat.common.bean.result.WxMediaUploadResult;
import java.util.Objects;

View File

@ -9,9 +9,10 @@
package com.ossez.wechat.common.util.json;
import com.google.gson.*;
import com.ossez.wechat.common.bean.menu.WxMenu;
import com.ossez.wechat.common.bean.menu.WxMenuButton;
import com.ossez.wechat.common.bean.menu.WxMenuRule;
import com.ossez.wechat.common.model.entity.builder.MenuButtonBuilder;
import com.ossez.wechat.common.model.entity.menu.WxMenu;
import com.ossez.wechat.common.model.entity.menu.MenuButton;
import com.ossez.wechat.common.model.entity.menu.WxMenuRule;
import java.lang.reflect.Type;
@ -19,16 +20,16 @@ import java.lang.reflect.Type;
/**
* @author Daniel Qian
*/
public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializer<WxMenu> {
public class WxMenuGsonAdapter {
@Override
// @Override
public JsonElement serialize(WxMenu menu, Type typeOfSrc, JsonSerializationContext context) {
JsonObject json = new JsonObject();
JsonArray buttonArray = new JsonArray();
for (WxMenuButton button : menu.getButtons()) {
JsonObject buttonJson = convertToJson(button);
buttonArray.add(buttonJson);
for (MenuButton button : menu.getButtons()) {
// JsonObject buttonJson = convertToJson(button);
// buttonArray.add(buttonJson);
}
json.add("button", buttonArray);
@ -39,25 +40,25 @@ public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializ
return json;
}
protected JsonObject convertToJson(WxMenuButton button) {
JsonObject buttonJson = new JsonObject();
buttonJson.addProperty("type", button.getType());
buttonJson.addProperty("name", button.getName());
buttonJson.addProperty("key", button.getKey());
buttonJson.addProperty("url", button.getUrl());
buttonJson.addProperty("media_id", button.getMediaId());
buttonJson.addProperty("article_id", button.getArticleId());
buttonJson.addProperty("appid", button.getAppId());
buttonJson.addProperty("pagepath", button.getPagePath());
if (button.getSubButtons() != null && button.getSubButtons().size() > 0) {
JsonArray buttonArray = new JsonArray();
for (WxMenuButton sub_button : button.getSubButtons()) {
buttonArray.add(convertToJson(sub_button));
}
buttonJson.add("sub_button", buttonArray);
}
return buttonJson;
}
// protected JsonObject convertToJson(MenuButton button) {
// JsonObject buttonJson = new JsonObject();
// buttonJson.addProperty("type", button.getType());
// buttonJson.addProperty("name", button.getName());
// buttonJson.addProperty("key", button.getKey());
// buttonJson.addProperty("url", button.getUrl());
// buttonJson.addProperty("media_id", button.getMediaId());
// buttonJson.addProperty("article_id", button.getArticleId());
// buttonJson.addProperty("appid", button.getAppId());
// buttonJson.addProperty("pagepath", button.getPagePath());
// if (button.getSubButtons() != null && button.getSubButtons().size() > 0) {
// JsonArray buttonArray = new JsonArray();
// for (MenuButton sub_button : button.getSubButtons()) {
// buttonArray.add(convertToJson(sub_button));
// }
// buttonJson.add("sub_button", buttonArray);
// }
// return buttonJson;
// }
protected JsonObject convertToJson(WxMenuRule menuRule) {
JsonObject matchRule = new JsonObject();
@ -86,47 +87,47 @@ public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializ
return menuRule;
}
@Override
public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
/*
* 操蛋的微信
* 创建菜单时是 { button : ... }
* 查询菜单时是 { menu : { button : ... } }
* 现在企业号升级为企业微信后没有此问题因此需要单独处理
*/
JsonArray buttonsJson = json.getAsJsonObject().get("menu").getAsJsonObject().get("button").getAsJsonArray();
return this.buildMenuFromJson(buttonsJson);
}
// @Override
// public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// /*
// * 操蛋的微信
// * 创建菜单时是 { button : ... }
// * 查询菜单时是 { menu : { button : ... } }
// * 现在企业号升级为企业微信后没有此问题因此需要单独处理
// */
// JsonArray buttonsJson = json.getAsJsonObject().get("menu").getAsJsonObject().get("button").getAsJsonArray();
// return this.buildMenuFromJson(buttonsJson);
// }
protected WxMenu buildMenuFromJson(JsonArray buttonsJson) {
WxMenu menu = new WxMenu();
for (int i = 0; i < buttonsJson.size(); i++) {
JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject();
WxMenuButton button = convertFromJson(buttonJson);
menu.getButtons().add(button);
if (buttonJson.get("sub_button") == null || buttonJson.get("sub_button").isJsonNull()) {
continue;
}
JsonArray sub_buttonsJson = buttonJson.get("sub_button").getAsJsonArray();
for (int j = 0; j < sub_buttonsJson.size(); j++) {
JsonObject sub_buttonJson = sub_buttonsJson.get(j).getAsJsonObject();
button.getSubButtons().add(convertFromJson(sub_buttonJson));
}
}
return menu;
}
// protected WxMenu buildMenuFromJson(JsonArray buttonsJson) {
// WxMenu menu = new WxMenu();
// for (int i = 0; i < buttonsJson.size(); i++) {
// JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject();
// MenuButton button = convertFromJson(buttonJson);
// menu.getButtons().add(button);
// if (buttonJson.get("sub_button") == null || buttonJson.get("sub_button").isJsonNull()) {
// continue;
// }
// JsonArray sub_buttonsJson = buttonJson.get("sub_button").getAsJsonArray();
// for (int j = 0; j < sub_buttonsJson.size(); j++) {
// JsonObject sub_buttonJson = sub_buttonsJson.get(j).getAsJsonObject();
// button.getSubButtons().add(convertFromJson(sub_buttonJson));
// }
// }
// return menu;
// }
protected WxMenuButton convertFromJson(JsonObject json) {
WxMenuButton button = new WxMenuButton();
button.setName(GsonHelper.getString(json, "name"));
button.setKey(GsonHelper.getString(json, "key"));
button.setUrl(GsonHelper.getString(json, "url"));
button.setType(GsonHelper.getString(json, "type"));
button.setMediaId(GsonHelper.getString(json, "media_id"));
button.setArticleId(GsonHelper.getString(json, "article_id"));
button.setAppId(GsonHelper.getString(json, "appid"));
button.setPagePath(GsonHelper.getString(json, "pagepath"));
return button;
}
// protected MenuButton convertFromJson(JsonObject json) {
// MenuButton button = new MenuButtonBuilder().createMenuButton();
// button.setName(GsonHelper.getString(json, "name"));
// button.setKey(GsonHelper.getString(json, "key"));
// button.setUrl(GsonHelper.getString(json, "url"));
// button.setType(GsonHelper.getString(json, "type"));
// button.setMediaId(GsonHelper.getString(json, "media_id"));
// button.setArticleId(GsonHelper.getString(json, "article_id"));
// button.setAppId(GsonHelper.getString(json, "appid"));
// button.setPagePath(GsonHelper.getString(json, "pagepath"));
// return button;
// }
}

View File

@ -1,11 +1,14 @@
package com.ossez.wechat.common.api;
import org.testng.annotations.Test;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.TestInstance;
import java.util.concurrent.TimeUnit;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
/**
* @author jiangby
@ -13,7 +16,8 @@ import static org.testng.Assert.assertTrue;
* @description: 作用
* created on 2022/5/26 1:46
*/
@Test
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Slf4j
public class WxMessageInMemoryDuplicateCheckerSingletonTest {
private static WxMessageInMemoryDuplicateCheckerSingleton checkerSingleton = WxMessageInMemoryDuplicateCheckerSingleton.getInstance();
@ -24,14 +28,14 @@ public class WxMessageInMemoryDuplicateCheckerSingletonTest {
// 第一次检查
for (Long msgId : msgIds) {
boolean result = checkerSingleton.isDuplicate(String.valueOf(msgId));
assertFalse(result);
assertThat(result).isFalse();
}
// 初始化后1S进行检查 每五秒检查一次过期时间为15秒过15秒再检查
TimeUnit.SECONDS.sleep(15);
for (Long msgId : msgIds) {
boolean result = checkerSingleton.isDuplicate(String.valueOf(msgId));
assertTrue(result);
assertThat(result).isTrue();
}
// 过6秒再检查

View File

@ -1,39 +1,41 @@
package com.ossez.wechat.common.api;
import org.testng.annotations.Test;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import java.util.concurrent.TimeUnit;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.assertj.core.api.Assertions.assertThat;
@Test
@TestInstance(Lifecycle.PER_CLASS)
@Slf4j
public class WxMessageInMemoryDuplicateCheckerTest {
private WxMessageInMemoryDuplicateChecker checker = new WxMessageInMemoryDuplicateChecker(2000L, 1000L);
private WxMessageInMemoryDuplicateChecker checker = new WxMessageInMemoryDuplicateChecker(2000L, 1000L);
public void test() throws InterruptedException {
Long[] msgIds = new Long[]{1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L};
@Test
public void test() throws InterruptedException {
Long[] msgIds = new Long[]{1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L};
// 第一次检查
for (Long msgId : msgIds) {
boolean result = checker.isDuplicate(String.valueOf(msgId));
assertFalse(result);
// 第一次检查
for (Long msgId : msgIds) {
boolean result = checker.isDuplicate(String.valueOf(msgId));
assertThat(result).isFalse();
}
// 过1秒再检查
TimeUnit.SECONDS.sleep(1);
for (Long msgId : msgIds) {
boolean result = checker.isDuplicate(String.valueOf(msgId));
assertThat(result).isTrue();
}
// 过1.5秒再检查
TimeUnit.MILLISECONDS.sleep(1500L);
for (Long msgId : msgIds) {
boolean result = checker.isDuplicate(String.valueOf(msgId));
assertThat(result).isFalse();
}
}
// 过1秒再检查
TimeUnit.SECONDS.sleep(1);
for (Long msgId : msgIds) {
boolean result = checker.isDuplicate(String.valueOf(msgId));
assertTrue(result);
}
// 过1.5秒再检查
TimeUnit.MILLISECONDS.sleep(1500L);
for (Long msgId : msgIds) {
boolean result = checker.isDuplicate(String.valueOf(msgId));
assertFalse(result);
}
}
}

View File

@ -1,35 +1,40 @@
package com.ossez.wechat.common.exception;
import com.ossez.wechat.common.enums.WxType;
import org.testng.annotations.Test;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import static org.assertj.core.api.Assertions.assertThat;
@Test
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Slf4j
public class WxErrorTest {
@Test
public void testFromJson() {
String json = "{ \"errcode\": 40003, \"errmsg\": \"invalid openid\" }";
WxError wxError = WxError.fromJson(json, WxType.MP);
assertEquals(40003, wxError.getErrorCode());
assertEquals(wxError.getErrorMsgEn(), "invalid openid");
assertThat(40003).isEqualTo(wxError.getErrorCode());
// assertEquals(wxError.getErrorMsgEn(), "invalid openid");
}
public void testFromBadJson1() {
String json = "{ \"errcode\": 40003, \"errmsg\": \"invalid openid\", \"media_id\": \"12323423dsfafsf232f\" }";
WxError wxError = WxError.fromJson(json, WxType.MP);
assertEquals(40003, wxError.getErrorCode());
assertEquals(wxError.getErrorMsgEn(), "invalid openid");
}
public void testFromBadJson2() {
String json = "{\"access_token\":\"ACCESS_TOKEN\",\"expires_in\":7200}";
WxError wxError = WxError.fromJson(json, WxType.MP);
assertEquals(0, wxError.getErrorCode());
assertNull(wxError.getErrorMsg());
}
// @Test
// public void testFromBadJson1() {
// String json = "{ \"errcode\": 40003, \"errmsg\": \"invalid openid\", \"media_id\": \"12323423dsfafsf232f\" }";
// WxError wxError = WxError.fromJson(json, WxType.MP);
// assertEquals(40003, wxError.getErrorCode());
// assertEquals(wxError.getErrorMsgEn(), "invalid openid");
//
// }
//
// @Test
// public void testFromBadJson2() {
// String json = "{\"access_token\":\"ACCESS_TOKEN\",\"expires_in\":7200}";
// WxError wxError = WxError.fromJson(json, WxType.MP);
// assertEquals(0, wxError.getErrorCode());
// assertNull(wxError.getErrorMsg());
//
// }
}

View File

@ -1,8 +1,9 @@
package com.ossez.wechat.common.model;
import com.ossez.wechat.common.bean.menu.WxMenu;
import com.ossez.wechat.common.bean.menu.WxMenuButton;
import com.ossez.wechat.common.bean.menu.WxMenuRule;
import com.ossez.wechat.common.model.entity.builder.MenuButtonBuilder;
import com.ossez.wechat.common.model.entity.menu.WxMenu;
import com.ossez.wechat.common.model.entity.menu.MenuButton;
import com.ossez.wechat.common.model.entity.menu.WxMenuRule;
import org.testng.*;
import org.testng.annotations.*;
@ -18,41 +19,41 @@ public class WxMenuTest {
@Test(dataProvider = "wxPushMenu")
public void testToJson(String json) {
WxMenu menu = new WxMenu();
WxMenuButton button1 = new WxMenuButton();
MenuButton button1 = new MenuButtonBuilder().createMenuButton();
button1.setType("click");
button1.setName("今日歌曲");
button1.setKey("V1001_TODAY_MUSIC");
WxMenuButton button2 = new WxMenuButton();
MenuButton button2 = new MenuButtonBuilder().createMenuButton();
button2.setType("click");
button2.setName("歌手简介");
button2.setKey("V1001_TODAY_SINGER");
WxMenuButton button3 = new WxMenuButton();
MenuButton button3 = new MenuButtonBuilder().createMenuButton();
button3.setName("菜单");
menu.getButtons().add(button1);
menu.getButtons().add(button2);
menu.getButtons().add(button3);
WxMenuButton button31 = new WxMenuButton();
MenuButton button31 = new MenuButtonBuilder().createMenuButton();
button31.setType("view");
button31.setName("搜索");
button31.setUrl("http://www.soso.com/");
WxMenuButton button32 = new WxMenuButton();
MenuButton button32 = new MenuButtonBuilder().createMenuButton();
button32.setType("view");
button32.setName("视频");
button32.setUrl("http://v.qq.com/");
WxMenuButton button33 = new WxMenuButton();
MenuButton button33 = new MenuButtonBuilder().createMenuButton();
button33.setType("click");
button33.setName("赞一下我们");
button33.setKey("V1001_GOOD");
button3.getSubButtons().add(button31);
button3.getSubButtons().add(button32);
button3.getSubButtons().add(button33);
// button3.getSubButtons().add(button31);
// button3.getSubButtons().add(button32);
// button3.getSubButtons().add(button33);
Assert.assertEquals(menu.toJson(), json);
}
@ -60,7 +61,7 @@ public class WxMenuTest {
@Test(dataProvider = "wxAddConditionalMenu")
public void testAddConditionalToJson(String json) {
WxMenu menu = new WxMenu();
WxMenuButton button1 = new WxMenuButton();
MenuButton button1 = new MenuButtonBuilder().createMenuButton();
button1.setType("click");
button1.setName("今日歌曲");
button1.setKey("V1001_TODAY_MUSIC");

View File

@ -1,151 +1,141 @@
<?xml version="1.0"?>
<project
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j-mp</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>wechat-j-mp</artifactId>
<packaging>jar</packaging>
<name>WeChat Java Mini Program</name>
<description>The module is WeChat Mini Program</description>
<parent>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<name>WeChat Java Mini Program</name>
<description>The module is WeChat Mini Program</description>
<dependencies>
<dependency>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependencies>
<dependency>
<groupId>com.ossez.wechat</groupId>
<artifactId>wechat-j-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jodd</groupId>
<artifactId>jodd-http</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jodd</groupId>
<artifactId>jodd-http</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-guava</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-guava</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native-image</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<annotationProcessors>
com.github.binarywang.wx.graal.GraalProcessor,lombok.launch.AnnotationProcessorHider$AnnotationProcessor,lombok.launch.AnnotationProcessorHider$ClaimingProcessor
</annotationProcessors>
<annotationProcessorPaths>
<path>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-graal</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</build>
<profiles>
<profile>
<id>native-image</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<annotationProcessors>
com.github.binarywang.wx.graal.GraalProcessor,lombok.launch.AnnotationProcessorHider$AnnotationProcessor,lombok.launch.AnnotationProcessorHider$ClaimingProcessor
</annotationProcessors>
<annotationProcessorPaths>
<path>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-graal</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -6,9 +6,9 @@ import com.google.gson.JsonObject;
import lombok.RequiredArgsConstructor;
import com.ossez.wechat.common.bean.WxJsapiSignature;
import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.common.util.RandomUtils;
import com.ossez.wechat.common.util.crypto.SHA1;
import com.ossez.wechat.common.util.json.GsonParser;
import org.apache.commons.lang3.RandomStringUtils;
import java.util.concurrent.locks.Lock;
@ -84,7 +84,7 @@ public class WxMaJsapiServiceImpl implements WxMaJsapiService {
@Override
public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException {
long timestamp = System.currentTimeMillis() / 1000;
String randomStr = RandomUtils.getRandomStr();
String randomStr = RandomStringUtils.randomAlphanumeric(16);
String jsapiTicket = getJsapiTicket(false);
String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket,
"noncestr=" + randomStr, "timestamp=" + timestamp, "url=" + url);

View File

@ -31,21 +31,6 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
@ -99,10 +84,6 @@
<version>4.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
</dependency>
</dependencies>

View File

@ -16,8 +16,8 @@ import com.ossez.wechat.oa.bean.WxMpSemanticQuery;
import com.ossez.wechat.oa.bean.result.WxMpCurrentAutoReplyInfo;
import com.ossez.wechat.oa.bean.result.WxMpShortKeyResult;
import com.ossez.wechat.oa.bean.result.WxMpSemanticQueryResult;
import com.ossez.wechat.oa.config.ConfigStorage;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.config.ConfigStorage;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import java.util.Map;

View File

@ -3,7 +3,7 @@ package com.ossez.wechat.oa.api;
import java.io.File;
import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.oa.enums.AiLangType;
import com.ossez.wechat.common.enums.Language;
/**
* <pre>
@ -27,7 +27,7 @@ public interface WxMpAiOpenService {
* @param voiceFile 语音文件
* @param voiceId 语音唯一标识
*/
void uploadVoice(String voiceId, AiLangType lang, File voiceFile) throws WxErrorException;
void uploadVoice(String voiceId, Language lang, File voiceFile) throws WxErrorException;
/**
* <pre>
@ -42,7 +42,7 @@ public interface WxMpAiOpenService {
* @param lang 语言zh_CN en_US默认中文
* @param voiceId 语音唯一标识
*/
String queryRecognitionResult(String voiceId, AiLangType lang) throws WxErrorException;
String queryRecognitionResult(String voiceId, Language lang) throws WxErrorException;
/**
* 识别指定语音文件内容.
@ -52,7 +52,7 @@ public interface WxMpAiOpenService {
* @param voiceFile 语音文件
* @param voiceId 语音唯一标识
*/
String recogniseVoice(String voiceId, AiLangType lang, File voiceFile) throws WxErrorException;
String recogniseVoice(String voiceId, Language lang, File voiceFile) throws WxErrorException;
/**
* <pre>
@ -68,5 +68,5 @@ public interface WxMpAiOpenService {
* @param langTo 目标语言zh_CN en_US
* @param content 要翻译的文本内容
*/
String translate(AiLangType langFrom, AiLangType langTo, String content) throws WxErrorException;
String translate(Language langFrom, Language langTo, String content) throws WxErrorException;
}

View File

@ -1,6 +1,6 @@
package com.ossez.wechat.oa.api;
import com.ossez.wechat.common.bean.menu.WxMenu;
import com.ossez.wechat.common.model.entity.menu.WxMenu;
import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.oa.bean.menu.WxMpGetSelfMenuInfoResult;
import com.ossez.wechat.oa.bean.menu.WxMpMenu;

View File

@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.ossez.wechat.common.config.ConfigStorage;
import com.ossez.wechat.common.constant.WeChatConstant;
import com.ossez.wechat.common.bean.ToJson;
import com.ossez.wechat.common.model.WeChatAccessToken;
@ -20,29 +21,30 @@ import com.ossez.wechat.common.service.WxOcrService;
import com.ossez.wechat.common.session.StandardSessionManager;
import com.ossez.wechat.common.session.WxSessionManager;
import com.ossez.wechat.common.util.DataUtils;
import com.ossez.wechat.common.util.RandomUtils;
import com.ossez.wechat.common.util.crypto.SHA1;
import com.ossez.wechat.common.util.http.*;
import com.ossez.wechat.common.util.json.GsonParser;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import com.ossez.wechat.oa.api.*;
import com.ossez.wechat.oa.api.impl.okhttp.WeChatMsgService;
import com.ossez.wechat.oa.bean.WxMpSemanticQuery;
import com.ossez.wechat.oa.bean.result.WxMpCurrentAutoReplyInfo;
import com.ossez.wechat.oa.bean.result.WxMpSemanticQueryResult;
import com.ossez.wechat.oa.bean.result.WxMpShortKeyResult;
import com.ossez.wechat.oa.config.ConfigStorage;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import com.ossez.wechat.oa.util.WxMpConfigStorageHolder;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Other.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Other.*;
/**
* 基础实现类.
@ -54,6 +56,8 @@ public abstract class BaseWeChatOfficialAccountServiceImpl<H, P> implements WeCh
protected WxSessionManager sessionManager = new StandardSessionManager();
@Getter
@Setter
private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this);
@ -156,7 +160,7 @@ public abstract class BaseWeChatOfficialAccountServiceImpl<H, P> implements WeCh
@Setter
private WxMpFreePublishService freePublishService = new WxMpFreePublishServiceImpl(this);
private Map<String, ConfigStorage> configStorageMap;
private Map<String, ConfigStorage> configStorageMap = new HashMap<>();
private int retrySleepMillis = 1000;
private int maxRetryTimes = 5;
@ -235,7 +239,7 @@ public abstract class BaseWeChatOfficialAccountServiceImpl<H, P> implements WeCh
@Override
public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException {
long timestamp = System.currentTimeMillis() / 1000;
String randomStr = RandomUtils.getRandomStr();
String randomStr = RandomStringUtils.randomAlphanumeric(16);
String jsapiTicket = getJsapiTicket(false);
String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket,
"noncestr=" + randomStr, "timestamp=" + timestamp, "url=" + url);

View File

@ -1,107 +0,0 @@
package com.ossez.wechat.oa.api.impl;
import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.common.exception.WxRuntimeException;
import com.ossez.wechat.common.util.http.HttpType;
import com.ossez.wechat.common.util.http.apache.ApacheHttpClientBuilder;
import com.ossez.wechat.common.util.http.apache.DefaultApacheHttpClientBuilder;
import com.ossez.wechat.oa.config.ConfigStorage;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL;
/**
* apache http client方式实现.
*
* @author someone
*/
public class WeChatOfficialAccountServiceHttpClientImpl extends BaseWeChatOfficialAccountServiceImpl<CloseableHttpClient, HttpHost> {
private CloseableHttpClient httpClient;
private HttpHost httpProxy;
@Override
public CloseableHttpClient getRequestHttpClient() {
return httpClient;
}
@Override
public HttpHost getRequestHttpProxy() {
return httpProxy;
}
@Override
public HttpType getRequestType() {
return HttpType.APACHE_HTTP;
}
@Override
public void initHttp() {
ConfigStorage configStorage = this.getWxMpConfigStorage();
ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder();
if (null == apacheHttpClientBuilder) {
apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get();
}
apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost())
.httpProxyPort(configStorage.getHttpProxyPort())
.httpProxyUsername(configStorage.getHttpProxyUsername())
.httpProxyPassword(configStorage.getHttpProxyPassword());
if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort());
}
this.httpClient = apacheHttpClientBuilder.build();
}
@Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
final ConfigStorage config = this.getWxMpConfigStorage();
if (!config.isAccessTokenExpired() && !forceRefresh) {
return config.getAccessToken();
}
Lock lock = config.getAccessTokenLock();
boolean locked = false;
try {
do {
locked = lock.tryLock(100, TimeUnit.MILLISECONDS);
if (!forceRefresh && !config.isAccessTokenExpired()) {
return config.getAccessToken();
}
} while (!locked);
String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(config), config.getAppId(), config.getSecret());
try {
HttpGet httpGet = new HttpGet(url);
if (this.getRequestHttpProxy() != null) {
RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
httpGet.setConfig(requestConfig);
}
try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) {
return this.extractAccessToken(new BasicResponseHandler().handleResponse(response));
} finally {
httpGet.releaseConnection();
}
} catch (IOException e) {
throw new WxRuntimeException(e);
}
} catch (InterruptedException e) {
throw new WxRuntimeException(e);
} finally {
if (locked) {
lock.unlock();
}
}
}
}

View File

@ -1,12 +0,0 @@
package com.ossez.wechat.oa.api.impl;
/**
* <pre>
* 默认接口实现类使用apache httpclient实现
* Created by Binary Wang on 2017-5-27.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class WeChatOfficialAccountServiceImpl extends WeChatOfficialAccountServiceHttpClientImpl {
}

View File

@ -7,12 +7,12 @@ import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.common.util.json.GsonParser;
import com.ossez.wechat.oa.api.WxMpAiOpenService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.enums.AiLangType;
import com.ossez.wechat.common.enums.Language;
import com.ossez.wechat.oa.util.requestexecuter.voice.VoiceUploadRequestExecutor;
import java.io.File;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.AiOpen.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.AiOpen.*;
/**
* <pre>
@ -26,9 +26,9 @@ public class WxMpAiOpenServiceImpl implements WxMpAiOpenService {
private final WeChatOfficialAccountService weChatOfficialAccountService;
@Override
public void uploadVoice(String voiceId, AiLangType lang, File voiceFile) throws WxErrorException {
public void uploadVoice(String voiceId, Language lang, File voiceFile) throws WxErrorException {
if (lang == null) {
lang = AiLangType.zh_CN;
lang = Language.ZH_CN;
}
this.weChatOfficialAccountService.execute(VoiceUploadRequestExecutor.create(this.weChatOfficialAccountService.getRequestHttp()),
@ -37,13 +37,13 @@ public class WxMpAiOpenServiceImpl implements WxMpAiOpenService {
}
@Override
public String recogniseVoice(String voiceId, AiLangType lang, File voiceFile) throws WxErrorException {
public String recogniseVoice(String voiceId, Language lang, File voiceFile) throws WxErrorException {
this.uploadVoice(voiceId, lang, voiceFile);
return this.queryRecognitionResult(voiceId, lang);
}
@Override
public String translate(AiLangType langFrom, AiLangType langTo, String content) throws WxErrorException {
public String translate(Language langFrom, Language langTo, String content) throws WxErrorException {
String response = this.weChatOfficialAccountService.post(String.format(TRANSLATE_URL.getUrl(this.weChatOfficialAccountService.getWxMpConfigStorage()),
langFrom.getCode(), langTo.getCode()), content);
@ -56,9 +56,9 @@ public class WxMpAiOpenServiceImpl implements WxMpAiOpenService {
}
@Override
public String queryRecognitionResult(String voiceId, AiLangType lang) throws WxErrorException {
public String queryRecognitionResult(String voiceId, Language lang) throws WxErrorException {
if (lang == null) {
lang = AiLangType.zh_CN;
lang = Language.ZH_CN;
}
final String response = this.weChatOfficialAccountService.get(VOICE_QUERY_RESULT_URL,

View File

@ -8,16 +8,16 @@ import lombok.extern.slf4j.Slf4j;
import com.ossez.wechat.common.bean.WxCardApiSignature;
import com.ossez.wechat.common.exception.WxError;
import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.common.util.RandomUtils;
import com.ossez.wechat.common.util.http.SimpleGetRequestExecutor;
import com.ossez.wechat.common.util.json.GsonParser;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import com.ossez.wechat.oa.api.WxMpCardService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.common.enums.TicketType;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import com.ossez.wechat.oa.util.json.WxMpGsonBuilder;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
@ -74,7 +74,7 @@ public class WxMpCardServiceImpl implements WxMpCardService {
@Override
public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws WxErrorException {
long timestamp = System.currentTimeMillis() / 1000;
String nonceStr = RandomUtils.getRandomStr();
String nonceStr = RandomStringUtils.randomAlphanumeric(16);
String cardApiTicket = getCardApiTicket(false);
String[] signParams = Arrays.copyOf(optionalSignParam, optionalSignParam.length + 3);

View File

@ -7,7 +7,7 @@ import com.ossez.wechat.oa.api.WxMpCommentService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.bean.comment.WxMpCommentListVo;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Comment.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Comment.*;
/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>

View File

@ -6,14 +6,14 @@ import lombok.RequiredArgsConstructor;
import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.oa.api.WxMpDataCubeService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import org.apache.commons.lang3.time.FastDateFormat;
import java.text.Format;
import java.util.Date;
import java.util.List;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.DataCube.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.DataCube.*;
/**
* Created by Binary Wang on 2016/8/23.

View File

@ -7,7 +7,7 @@ import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.oa.api.WxMpDeviceService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Device.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Device.*;
/**
* Created by keungtung on 10/12/2016.

View File

@ -11,7 +11,7 @@ import com.ossez.wechat.oa.bean.draft.WxMpDraftArticles;
import com.ossez.wechat.oa.bean.draft.WxMpDraftInfo;
import com.ossez.wechat.oa.bean.draft.WxMpDraftList;
import com.ossez.wechat.oa.bean.draft.WxMpUpdateDraft;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import java.util.ArrayList;
import java.util.List;

View File

@ -9,7 +9,7 @@ import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.bean.freepublish.WxMpFreePublishInfo;
import com.ossez.wechat.oa.bean.freepublish.WxMpFreePublishList;
import com.ossez.wechat.oa.bean.freepublish.WxMpFreePublishStatus;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
/**
* 发布能力-service实现类.

View File

@ -9,7 +9,7 @@ import com.ossez.wechat.common.util.json.GsonParser;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import com.ossez.wechat.oa.api.WxMpGuideBuyerService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import java.util.LinkedHashMap;
import java.util.List;

View File

@ -11,7 +11,7 @@ import com.ossez.wechat.common.util.json.GsonParser;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import com.ossez.wechat.oa.api.WxMpGuideMassedJobService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import java.util.LinkedHashMap;
import java.util.List;

View File

@ -11,7 +11,7 @@ import com.ossez.wechat.common.util.json.GsonParser;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import com.ossez.wechat.oa.api.WxMpGuideMaterialService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import java.util.LinkedHashMap;
import java.util.List;

View File

@ -11,7 +11,7 @@ import com.ossez.wechat.common.util.json.GsonParser;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import com.ossez.wechat.oa.api.WxMpGuideService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import java.util.LinkedHashMap;
import java.util.List;

View File

@ -11,7 +11,7 @@ import com.ossez.wechat.common.util.json.GsonParser;
import com.ossez.wechat.common.util.json.WxGsonBuilder;
import com.ossez.wechat.oa.api.WxMpGuideTagService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import java.util.LinkedHashMap;
import java.util.List;

View File

@ -15,12 +15,12 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.ImgProc.AI_CROP;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.ImgProc.FILE_AI_CROP;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.ImgProc.FILE_QRCODE;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.ImgProc.FILE_SUPER_RESOLUTION;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.ImgProc.QRCODE;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.ImgProc.SUPER_RESOLUTION;
import static com.ossez.wechat.common.enums.WxMpApiUrl.ImgProc.AI_CROP;
import static com.ossez.wechat.common.enums.WxMpApiUrl.ImgProc.FILE_AI_CROP;
import static com.ossez.wechat.common.enums.WxMpApiUrl.ImgProc.FILE_QRCODE;
import static com.ossez.wechat.common.enums.WxMpApiUrl.ImgProc.FILE_SUPER_RESOLUTION;
import static com.ossez.wechat.common.enums.WxMpApiUrl.ImgProc.QRCODE;
import static com.ossez.wechat.common.enums.WxMpApiUrl.ImgProc.SUPER_RESOLUTION;
/**
* 图像处理接口实现.

View File

@ -16,7 +16,7 @@ import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import java.io.File;
import java.util.Date;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Kefu.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Kefu.*;
/**
* @author Binary Wang

View File

@ -20,7 +20,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Marketing.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Marketing.*;
/**
* @author <a href="https://github.com/007gzs">007</a>

View File

@ -12,7 +12,7 @@ import com.ossez.wechat.oa.bean.result.WxMpMassUploadResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.MassMessage;
import static com.ossez.wechat.common.enums.WxMpApiUrl.MassMessage;
/**
* <pre>

View File

@ -24,7 +24,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Material.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Material.*;
/**

View File

@ -10,7 +10,7 @@ import com.ossez.wechat.oa.bean.card.enums.CardColor;
import com.ossez.wechat.oa.bean.card.enums.DateInfoType;
import com.ossez.wechat.oa.bean.card.membercard.*;
import lombok.RequiredArgsConstructor;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import org.apache.commons.lang3.StringUtils;
import com.google.gson.Gson;

View File

@ -5,14 +5,14 @@ import com.ossez.wechat.oa.bean.menu.WxMpGetSelfMenuInfoResult;
import com.ossez.wechat.oa.bean.menu.WxMpMenu;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.ossez.wechat.common.bean.menu.WxMenu;
import com.ossez.wechat.common.model.entity.menu.WxMenu;
import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.common.util.json.GsonParser;
import com.ossez.wechat.oa.api.WxMpMenuService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Menu.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Menu.*;
/**
* Created by Binary Wang on 2016/7/21.

View File

@ -11,11 +11,11 @@ import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.oa.api.WxMpCardService;
import com.ossez.wechat.oa.api.WxMpMerchantInvoiceService;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import java.util.Map;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Invoice.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Invoice.*;
/**

View File

@ -1,8 +1,8 @@
package com.ossez.wechat.oa.api.impl;
import com.ossez.wechat.common.model.WeChatOAuth2AccessToken;
import com.ossez.wechat.common.model.entity.WeChatOAuth2UserInfo;
import lombok.RequiredArgsConstructor;
import com.ossez.wechat.common.bean.WxOAuth2UserInfo;
import com.ossez.wechat.common.bean.oauth2.WxOAuth2AccessToken;
import com.ossez.wechat.common.enums.WxType;
import com.ossez.wechat.common.exception.WxError;
import com.ossez.wechat.common.exception.WxErrorException;
@ -12,12 +12,12 @@ import com.ossez.wechat.common.util.http.SimpleGetRequestExecutor;
import com.ossez.wechat.common.util.http.URIUtil;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.common.service.WxOAuth2Service;
import com.ossez.wechat.oa.config.ConfigStorage;
import com.ossez.wechat.common.config.ConfigStorage;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.OAuth2.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.OAuth2.*;
/**
* oauth2 相关接口实现类.
@ -35,28 +35,28 @@ public class WxMpOAuth2ServiceImpl implements WxOAuth2Service {
getMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectUri), scope, StringUtils.trimToEmpty(state));
}
private WxOAuth2AccessToken getOAuth2AccessToken(String url) throws WxErrorException {
private WeChatOAuth2AccessToken getOAuth2AccessToken(String url) throws WxErrorException {
try {
RequestExecutor<String, String> executor = SimpleGetRequestExecutor.create(this.weChatOfficialAccountService.getRequestHttp());
String responseText = executor.execute(url, null, WxType.MP);
return WxOAuth2AccessToken.fromJson(responseText);
return WeChatOAuth2AccessToken.fromJson(responseText);
} catch (IOException e) {
throw new WxErrorException(WxError.builder().errorCode(99999).errorMsg(e.getMessage()).build(), e);
}
}
@Override
public WxOAuth2AccessToken getAccessToken(String code) throws WxErrorException {
public WeChatOAuth2AccessToken getAccessToken(String code) throws WxErrorException {
return this.getAccessToken(getMpConfigStorage().getAppId(), getMpConfigStorage().getSecret(), code);
}
@Override
public WxOAuth2AccessToken getAccessToken(String appId, String appSecret, String code) throws WxErrorException {
public WeChatOAuth2AccessToken getAccessToken(String appId, String appSecret, String code) throws WxErrorException {
return this.getOAuth2AccessToken(String.format(OAUTH2_ACCESS_TOKEN_URL.getUrl(getMpConfigStorage()), appId, appSecret, code));
}
@Override
public WxOAuth2AccessToken refreshAccessToken(String refreshToken) throws WxErrorException {
public WeChatOAuth2AccessToken refreshAccessToken(String refreshToken) throws WxErrorException {
String url = String.format(OAUTH2_REFRESH_TOKEN_URL.getUrl(getMpConfigStorage()), getMpConfigStorage().getAppId(), refreshToken);
return this.getOAuth2AccessToken(url);
}
@ -66,7 +66,7 @@ public class WxMpOAuth2ServiceImpl implements WxOAuth2Service {
}
@Override
public WxOAuth2UserInfo getUserInfo(WxOAuth2AccessToken token, String lang) throws WxErrorException {
public WeChatOAuth2UserInfo getUserInfo(WeChatOAuth2AccessToken token, String lang) throws WxErrorException {
if (lang == null) {
lang = "zh_CN";
}
@ -76,14 +76,14 @@ public class WxMpOAuth2ServiceImpl implements WxOAuth2Service {
try {
RequestExecutor<String, String> executor = SimpleGetRequestExecutor.create(this.weChatOfficialAccountService.getRequestHttp());
String responseText = executor.execute(url, null, WxType.MP);
return WxOAuth2UserInfo.fromJson(responseText);
return null;
} catch (IOException e) {
throw new WxRuntimeException(e);
}
}
@Override
public boolean validateAccessToken(WxOAuth2AccessToken token) {
public boolean validateAccessToken(WeChatOAuth2AccessToken token) {
String url = String.format(OAUTH2_VALIDATE_TOKEN_URL.getUrl(getMpConfigStorage()), token.getAccessToken(), token.getOpenId());
try {

View File

@ -12,7 +12,7 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Ocr.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Ocr.*;
/**
* ocr 接口实现.

View File

@ -14,7 +14,7 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Qrcode.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Qrcode.*;
/**
* Created by Binary Wang on 2016/7/21.

View File

@ -8,7 +8,7 @@ import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import java.util.List;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Invoice.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Invoice.*;
/**
* 电子发票报销方相关接口实现

View File

@ -10,7 +10,7 @@ import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.api.WxMpShakeService;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.ShakeAround.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.ShakeAround.*;
/**
* Created by rememberber on 2017/6/5.

View File

@ -13,7 +13,7 @@ import com.ossez.wechat.common.util.BeanUtils;
import com.ossez.wechat.common.util.json.GsonParser;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.api.WxMpStoreService;
import com.ossez.wechat.oa.enums.WxMpApiUrl;
import com.ossez.wechat.common.enums.WxMpApiUrl;
import com.ossez.wechat.oa.util.json.WxMpGsonBuilder;
import java.util.List;

View File

@ -14,7 +14,7 @@ import com.ossez.wechat.common.exception.WxError;
import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.common.util.http.URIUtil;
import com.ossez.wechat.common.util.json.GsonParser;
import com.ossez.wechat.oa.config.ConfigStorage;
import com.ossez.wechat.common.config.ConfigStorage;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.api.WxMpSubscribeMsgService;
import com.ossez.wechat.oa.bean.subscribe.WxMpSubscribeMessage;
@ -24,7 +24,7 @@ import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
import java.util.List;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.SubscribeMsg.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.SubscribeMsg.*;
/**
* 订阅消息接口.

View File

@ -14,7 +14,7 @@ import com.ossez.wechat.oa.bean.template.WxMpTemplateMessage;
import java.util.List;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.TemplateMsg.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.TemplateMsg.*;
/**
* <pre>

View File

@ -13,7 +13,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.UserBlacklist.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.UserBlacklist.*;
/**
* @author miller

View File

@ -16,7 +16,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.User.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.User.*;
/**
* Created by Binary Wang on 2016/7/21.

View File

@ -17,7 +17,7 @@ import org.apache.commons.lang3.StringUtils;
import java.util.List;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.UserTag.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.UserTag.*;
/**
* Created by Binary Wang on 2016/9/2.

View File

@ -8,7 +8,7 @@ import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.api.WxMpWifiService;
import static com.ossez.wechat.oa.enums.WxMpApiUrl.Wifi.*;
import static com.ossez.wechat.common.enums.WxMpApiUrl.Wifi.*;
/**
* <pre>

View File

@ -0,0 +1,149 @@
package com.ossez.wechat.oa.api.impl.okhttp;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.ossez.wechat.common.constant.WeChatConstant;
import com.ossez.wechat.common.exception.DataStructureException;
import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.common.model.req.DataCubeRequest;
import com.ossez.wechat.common.model.res.DataCubeArticle;
import com.ossez.wechat.common.model.res.DataCubeUser;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.api.impl.okhttp.interceptor.AuthenticationInterceptor;
import com.ossez.wechat.oa.api.impl.okhttp.interceptor.WeChatErrorInterceptor;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import retrofit2.HttpException;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
/**
* WeChat Official Account Platform DataCube
*
* @author YuCheng
*/
public class WeChatDataCubeService {
private final Logger log = LoggerFactory.getLogger(WeChatDataCubeService.class);
private WeChatOfficialAccountApi weChatOfficialAccountApi;
public WeChatDataCubeService(WeChatOfficialAccountService weChatOfficialAccountService) {
String accessToken = null;
try {
accessToken = weChatOfficialAccountService.getAccessToken();
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setSerializationInclusion(Include.NON_NULL);
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new AuthenticationInterceptor(accessToken)).addInterceptor(new WeChatErrorInterceptor()).connectionPool(new ConnectionPool(5, 1, TimeUnit.SECONDS)).readTimeout(1000, TimeUnit.SECONDS).build();
Retrofit retrofit = new Retrofit.Builder().baseUrl(WeChatConstant.ENDPOINT_WECHAT).client(client).addConverterFactory(JacksonConverterFactory.create(mapper)).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();
this.weChatOfficialAccountApi = retrofit.create(WeChatOfficialAccountApi.class);
}
/**
* Get user summary
*
* @param beginDate
* @param endDate
* @return
* @throws WxErrorException
*/
public DataCubeUser getUserSummary(LocalDateTime beginDate, LocalDateTime endDate) throws WxErrorException {
if (!(ObjectUtils.isNotEmpty(beginDate) && ObjectUtils.isNotEmpty(endDate) && endDate.isAfter(beginDate))) {
log.warn("The begin date [{}] Or end date [{}] was null or ender date greater than begin date.", beginDate, endDate);
throw new DataStructureException("Query data range error ");
}
try {
DataCubeRequest dataCubeRequest = new DataCubeRequest();
dataCubeRequest.setBeginDate(beginDate.format(DateTimeFormatter.ISO_LOCAL_DATE));
dataCubeRequest.setEndDate(endDate.format(DateTimeFormatter.ISO_LOCAL_DATE));
return weChatOfficialAccountApi.getUserSummary(dataCubeRequest).blockingGet();
} catch (HttpException ex) {
log.warn("Call WeChat API with error: " + ex);
if (ex.code() == 400) {
throw new WxErrorException(ex);
}
}
return null;
}
public DataCubeUser getUserCumulate(LocalDateTime beginDate, LocalDateTime endDate) throws WxErrorException {
if (!(ObjectUtils.isNotEmpty(beginDate) && ObjectUtils.isNotEmpty(endDate) && endDate.isAfter(beginDate))) {
log.warn("The begin date [{}] Or end date [{}] was null or ender date greater than begin date.", beginDate, endDate);
throw new DataStructureException("Query data range error ");
}
try {
DataCubeRequest dataCubeRequest = new DataCubeRequest();
dataCubeRequest.setBeginDate(beginDate.format(DateTimeFormatter.ISO_LOCAL_DATE));
dataCubeRequest.setEndDate(endDate.format(DateTimeFormatter.ISO_LOCAL_DATE));
return weChatOfficialAccountApi.getUserCumulate(dataCubeRequest).blockingGet();
} catch (HttpException ex) {
log.warn("Call WeChat API with error: " + ex);
if (ex.code() == 400) {
throw new WxErrorException(ex);
}
}
return null;
}
/**
*
* @param beginDate
* @param endDate
* @return
* @throws WxErrorException
*/
public DataCubeArticle getArticleSummary(LocalDateTime beginDate, LocalDateTime endDate) throws WxErrorException {
try {
return weChatOfficialAccountApi.getarticlesummary(getDataCubeRequest(beginDate, endDate)).blockingGet();
} catch (HttpException ex) {
log.warn("Call WeChat API with error: " + ex);
if (ex.code() == 400) {
throw new WxErrorException(ex);
}
}
return null;
}
private DataCubeRequest getDataCubeRequest(LocalDateTime beginDate, LocalDateTime endDate) throws DataStructureException {
if (!(ObjectUtils.isNotEmpty(beginDate) && ObjectUtils.isNotEmpty(endDate) && endDate.isAfter(beginDate))) {
log.warn("The begin date [{}] Or end date [{}] was null or ender date greater than begin date.", beginDate, endDate);
throw new DataStructureException("Query data range error ");
}
DataCubeRequest dataCubeRequest = new DataCubeRequest();
dataCubeRequest.setBeginDate(beginDate.format(DateTimeFormatter.ISO_LOCAL_DATE));
dataCubeRequest.setEndDate(endDate.format(DateTimeFormatter.ISO_LOCAL_DATE));
return dataCubeRequest;
}
}

View File

@ -1,43 +0,0 @@
package com.ossez.wechat.oa.api.impl.okhttp;
import com.ossez.wechat.common.constant.HttpClientMediaType;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.MediaType;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
/**
* The reason we have Interceptor here was because will return code 200 with error message.
* <p>
* For example, if we have error secret and try to get access token.
* WeChat will return code 200 success with json error message like:
*
* <pre>
* {"errcode":40125,"errmsg":"invalid appsecret rid: 63cf14c3-1af7da21-37efbc86"}
* </pre>
* <p>
* We need to check the response content, if the response content has errcode.
* We Interceptor response with error code 400 and add error json format to response body.
*
* @author YuCheng Hu
*/
public class WeChatErrorInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
String responseStr = response.body().string();
if (StringUtils.contains(responseStr, "errcode")) {
ResponseBody responseBody = ResponseBody.create(MediaType.get(HttpClientMediaType.APPLICATION_JSON), responseStr);
return response.newBuilder().code(400).body(responseBody).build();
}
return response;
}
}

View File

@ -0,0 +1,90 @@
package com.ossez.wechat.oa.api.impl.okhttp;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.ossez.wechat.common.constant.WeChatConstant;
import com.ossez.wechat.common.exception.DataStructureException;
import com.ossez.wechat.common.exception.WxErrorException;
import com.ossez.wechat.common.model.WeChatStatus;
import com.ossez.wechat.common.model.req.DataCubeRequest;
import com.ossez.wechat.common.model.req.MenuRequest;
import com.ossez.wechat.common.model.res.DataCubeArticle;
import com.ossez.wechat.common.model.res.DataCubeUser;
import com.ossez.wechat.oa.api.WeChatOfficialAccountService;
import com.ossez.wechat.oa.api.impl.okhttp.interceptor.AuthenticationInterceptor;
import com.ossez.wechat.oa.api.impl.okhttp.interceptor.WeChatErrorInterceptor;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import retrofit2.HttpException;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
/**
* WeChat Official Account Platform DataCube
*
* @author YuCheng
*/
public class WeChatMenuService {
private final Logger log = LoggerFactory.getLogger(WeChatMenuService.class);
private WeChatOfficialAccountApi weChatOfficialAccountApi;
public WeChatMenuService(WeChatOfficialAccountService weChatOfficialAccountService) {
String accessToken = null;
try {
accessToken = weChatOfficialAccountService.getAccessToken();
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setSerializationInclusion(Include.NON_NULL);
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new AuthenticationInterceptor(accessToken))
.addInterceptor(new WeChatErrorInterceptor())
.connectionPool(new ConnectionPool(5, 1, TimeUnit.SECONDS)).readTimeout(1000, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder().baseUrl(WeChatConstant.ENDPOINT_WECHAT).client(client)
.addConverterFactory(JacksonConverterFactory.create(mapper))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
this.weChatOfficialAccountApi = retrofit.create(WeChatOfficialAccountApi.class);
}
/**
* @param menuRequest
* @return
* @throws WxErrorException
*/
public WeChatStatus create(MenuRequest menuRequest) throws WxErrorException {
try {
return weChatOfficialAccountApi.createMenu(menuRequest).blockingGet();
} catch (HttpException ex) {
log.warn("Call WeChat API with error: " + ex);
if (ex.code() == 400) {
throw new WxErrorException(ex);
}
}
return null;
}
}

Some files were not shown because too many files have changed in this diff Show More