@@ -1,381 +1,387 @@ | |||||
<?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> | |||||
<groupId>com.github.binarywang</groupId> | |||||
<artifactId>weixin-java-parent</artifactId> | |||||
<version>2.8.6.BETA</version> | |||||
<packaging>pom</packaging> | |||||
<name>WeiXin Java Tools - Parent</name> | |||||
<description>微信公众号、企业号上级POM</description> | |||||
<url>https://github.com/wechat-group/weixin-java-tools</url> | |||||
<licenses> | |||||
<license> | |||||
<name>The Apache License, Version 2.0</name> | |||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> | |||||
</license> | |||||
</licenses> | |||||
<developers> | |||||
<developer> | |||||
<name>Daniel Qian</name> | |||||
<email>chanjarster@gmail.com</email> | |||||
<url>https://github.com/chanjarster</url> | |||||
</developer> | |||||
<developer> | |||||
<name>Binary Wang</name> | |||||
<email>binarywang@gmail.com</email> | |||||
<url>https://github.com/binarywang</url> | |||||
</developer> | |||||
<developer> | |||||
<name>gaigeshen</name> | |||||
<email>gaigeshen@qq.com</email> | |||||
<url>https://github.com/gaigeshen</url> | |||||
</developer> | |||||
<developer> | |||||
<name>Liu Mingbo</name> | |||||
<email>liumingbo2008@gmail.com</email> | |||||
<url>https://github.com/FirenzesEagle</url> | |||||
</developer> | |||||
<developer> | |||||
<name>kakotor</name> | |||||
<email>kakotor@gmail.com</email> | |||||
<url>https://github.com/kakotor</url> | |||||
</developer> | |||||
<developer> | |||||
<name>xiong</name> | |||||
<email>zhaoxiong.tan@gmail.com</email> | |||||
<url>https://github.com/ZhaoxiongTan</url> | |||||
</developer> | |||||
<developer> | |||||
<name>LiuJunGuang</name> | |||||
<email>aimilin@yeah.net</email> | |||||
<url>https://github.com/aimilin6688</url> | |||||
</developer> | |||||
<developer> | |||||
<name>Eric.Tsai</name> | |||||
<email>xiaodong.cai.ks@gmail.com</email> | |||||
<url>https://github.com/iwareserictsai</url> | |||||
</developer> | |||||
<developer> | |||||
<name>withinthefog</name> | |||||
<email>withinthefog@gmail.com</email> | |||||
<url>https://github.com/withinthefog</url> | |||||
</developer> | |||||
<developer> | |||||
<name>Keung</name> | |||||
<email>dongfuqiang1988@163.com</email> | |||||
<url>https://github.com/johnnytung</url> | |||||
</developer> | |||||
<developer> | |||||
<name>Jonk</name> | |||||
<email>aimilin@yeah.net</email> | |||||
<url>https://github.com/aimilin6688</url> | |||||
</developer> | |||||
<developer> | |||||
<name>ecoolper</name> | |||||
<email>crskyp@gmail.com</email> | |||||
<url>https://github.com/crskyp</url> | |||||
</developer> | |||||
</developers> | |||||
<scm> | |||||
<connection>scm:git:https://github.com/wechat-group/weixin-java-tools.git</connection> | |||||
<developerConnection>scm:git:git@github.com:wechat-group/weixin-java-tools.git</developerConnection> | |||||
<url>https://github.com/wechat-group/weixin-java-tools</url> | |||||
</scm> | |||||
<modules> | |||||
<module>weixin-java-common</module> | |||||
<module>weixin-java-cp</module> | |||||
<module>weixin-java-mp</module> | |||||
<module>weixin-java-pay</module> | |||||
<module>weixin-java-miniapp</module> | |||||
<!--module>weixin-java-osgi</module--> | |||||
</modules> | |||||
<properties> | |||||
<maven.compiler.source>1.7</maven.compiler.source> | |||||
<maven.compiler.target>1.7</maven.compiler.target> | |||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |||||
<downloadJavadocs>true</downloadJavadocs> | |||||
<downloadSources>true</downloadSources> | |||||
<httpclient.version>4.5</httpclient.version> | |||||
<jetty.version>9.3.0.RC0</jetty.version> | |||||
</properties> | |||||
<dependencyManagement> | |||||
<dependencies> | |||||
<dependency> | |||||
<groupId>com.github.binarywang</groupId> | |||||
<artifactId>qrcode-utils</artifactId> | |||||
<version>1.1</version> | |||||
</dependency> | |||||
<!-- 由于jodd-http较新的3.8版本需要jdk8,故而此处采用较低版本 --> | |||||
<dependency> | |||||
<groupId>org.jodd</groupId> | |||||
<artifactId>jodd-http</artifactId> | |||||
<version>3.7.1</version> | |||||
<scope>provided</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.squareup.okhttp3</groupId> | |||||
<artifactId>okhttp</artifactId> | |||||
<version>3.7.0</version> | |||||
<scope>provided</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.httpcomponents</groupId> | |||||
<artifactId>httpclient</artifactId> | |||||
<version>${httpclient.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.httpcomponents</groupId> | |||||
<artifactId>httpmime</artifactId> | |||||
<version>${httpclient.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>commons-codec</groupId> | |||||
<artifactId>commons-codec</artifactId> | |||||
<version>1.10</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>commons-io</groupId> | |||||
<artifactId>commons-io</artifactId> | |||||
<version>2.5</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.commons</groupId> | |||||
<artifactId>commons-lang3</artifactId> | |||||
<version>3.5</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.slf4j</groupId> | |||||
<artifactId>slf4j-api</artifactId> | |||||
<version>1.7.24</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.thoughtworks.xstream</groupId> | |||||
<artifactId>xstream</artifactId> | |||||
<version>1.4.9</version> | |||||
</dependency> | |||||
<!-- 由于guava较新的21.0版本需要jdk8,故而此处采用较低版本 --> | |||||
<dependency> | |||||
<groupId>com.google.guava</groupId> | |||||
<artifactId>guava</artifactId> | |||||
<version>20.0</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.google.code.gson</groupId> | |||||
<artifactId>gson</artifactId> | |||||
<version>2.8.0</version> | |||||
</dependency> | |||||
<!-- 测试所用依赖 --> | |||||
<dependency> | |||||
<groupId>joda-time</groupId> | |||||
<artifactId>joda-time</artifactId> | |||||
<version>2.9.7</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>ch.qos.logback</groupId> | |||||
<artifactId>logback-classic</artifactId> | |||||
<version>1.1.11</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.google.inject</groupId> | |||||
<artifactId>guice</artifactId> | |||||
<version>3.0</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.testng</groupId> | |||||
<artifactId>testng</artifactId> | |||||
<version>6.10</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.mockito</groupId> | |||||
<artifactId>mockito-all</artifactId> | |||||
<version>1.9.5</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.eclipse.jetty</groupId> | |||||
<artifactId>jetty-server</artifactId> | |||||
<version>${jetty.version}</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.eclipse.jetty</groupId> | |||||
<artifactId>jetty-servlet</artifactId> | |||||
<version>${jetty.version}</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>redis.clients</groupId> | |||||
<artifactId>jedis</artifactId> | |||||
<version>2.9.0</version> | |||||
<scope>provided</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.projectlombok</groupId> | |||||
<artifactId>lombok</artifactId> | |||||
<version>1.16.18</version> | |||||
<scope>compile</scope> | |||||
</dependency> | |||||
</dependencies> | |||||
</dependencyManagement> | |||||
<distributionManagement> | |||||
<snapshotRepository> | |||||
<id>ossrh</id> | |||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url> | |||||
</snapshotRepository> | |||||
<repository> | |||||
<id>ossrh</id> | |||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> | |||||
</repository> | |||||
</distributionManagement> | |||||
<profiles> | |||||
<profile> | |||||
<id>doclint-java8-disable</id> | |||||
<activation> | |||||
<jdk>[1.8,)</jdk> | |||||
</activation> | |||||
<properties> | |||||
<javadoc.opts>-Xdoclint:none</javadoc.opts> | |||||
</properties> | |||||
</profile> | |||||
<profile> | |||||
<id>release</id> | |||||
<build> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-source-plugin</artifactId> | |||||
<version>2.2.1</version> | |||||
<executions> | |||||
<execution> | |||||
<id>attach-sources</id> | |||||
<goals> | |||||
<goal>jar-no-fork</goal> | |||||
</goals> | |||||
</execution> | |||||
</executions> | |||||
</plugin> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-javadoc-plugin</artifactId> | |||||
<version>2.9.1</version> | |||||
<executions> | |||||
<execution> | |||||
<id>attach-javadocs</id> | |||||
<goals> | |||||
<goal>jar</goal> | |||||
</goals> | |||||
</execution> | |||||
</executions> | |||||
<configuration> | |||||
<additionalparam>${javadoc.opts}</additionalparam> | |||||
<charset>UTF-8</charset> | |||||
<locale>zh_CN</locale> | |||||
</configuration> | |||||
</plugin> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-gpg-plugin</artifactId> | |||||
<version>1.6</version> | |||||
<executions> | |||||
<execution> | |||||
<id>sign-artifacts</id> | |||||
<phase>verify</phase> | |||||
<goals> | |||||
<goal>sign</goal> | |||||
</goals> | |||||
</execution> | |||||
</executions> | |||||
</plugin> | |||||
</plugins> | |||||
</build> | |||||
</profile> | |||||
</profiles> | |||||
<build> | |||||
<pluginManagement> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-surefire-plugin</artifactId> | |||||
<version>2.17</version> | |||||
<configuration> | |||||
<skip>true</skip> | |||||
</configuration> | |||||
</plugin> | |||||
</plugins> | |||||
</pluginManagement> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>org.sonatype.plugins</groupId> | |||||
<artifactId>nexus-staging-maven-plugin</artifactId> | |||||
<version>1.6.3</version> | |||||
<extensions>true</extensions> | |||||
<configuration> | |||||
<serverId>ossrh</serverId> | |||||
<nexusUrl>https://oss.sonatype.org/</nexusUrl> | |||||
<autoReleaseAfterClose>true</autoReleaseAfterClose> | |||||
</configuration> | |||||
</plugin> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-release-plugin</artifactId> | |||||
<version>2.5.1</version> | |||||
<configuration> | |||||
<autoVersionSubmodules>true</autoVersionSubmodules> | |||||
<useReleaseProfile>false</useReleaseProfile> | |||||
<releaseProfiles>release</releaseProfiles> | |||||
<goals>deploy</goals> | |||||
</configuration> | |||||
</plugin> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-compiler-plugin</artifactId> | |||||
<version>3.6.0</version> | |||||
<configuration> | |||||
<encoding>UTF-8</encoding> | |||||
</configuration> | |||||
</plugin> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-checkstyle-plugin</artifactId> | |||||
<version>2.17</version> | |||||
<configuration> | |||||
<configLocation>quality-checks/google_checks.xml</configLocation> | |||||
<includeTestSourceDirectory>true</includeTestSourceDirectory> | |||||
<consoleOutput>true</consoleOutput> | |||||
<failsOnError>true</failsOnError> | |||||
</configuration> | |||||
<executions> | |||||
<execution> | |||||
<phase>verify</phase> | |||||
<goals> | |||||
<goal>check</goal> | |||||
</goals> | |||||
</execution> | |||||
</executions> | |||||
</plugin> | |||||
</plugins> | |||||
</build> | |||||
</project> | |||||
<?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> | |||||
<groupId>com.github.binarywang</groupId> | |||||
<artifactId>weixin-java-parent</artifactId> | |||||
<version>2.8.6.BETA</version> | |||||
<packaging>pom</packaging> | |||||
<name>WeiXin Java Tools - Parent</name> | |||||
<description>微信公众号、企业号上级POM</description> | |||||
<url>https://github.com/wechat-group/weixin-java-tools</url> | |||||
<licenses> | |||||
<license> | |||||
<name>The Apache License, Version 2.0</name> | |||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> | |||||
</license> | |||||
</licenses> | |||||
<developers> | |||||
<developer> | |||||
<name>Daniel Qian</name> | |||||
<email>chanjarster@gmail.com</email> | |||||
<url>https://github.com/chanjarster</url> | |||||
</developer> | |||||
<developer> | |||||
<name>Binary Wang</name> | |||||
<email>binarywang@gmail.com</email> | |||||
<url>https://github.com/binarywang</url> | |||||
</developer> | |||||
<developer> | |||||
<name>gaigeshen</name> | |||||
<email>gaigeshen@qq.com</email> | |||||
<url>https://github.com/gaigeshen</url> | |||||
</developer> | |||||
<developer> | |||||
<name>Liu Mingbo</name> | |||||
<email>liumingbo2008@gmail.com</email> | |||||
<url>https://github.com/FirenzesEagle</url> | |||||
</developer> | |||||
<developer> | |||||
<name>kakotor</name> | |||||
<email>kakotor@gmail.com</email> | |||||
<url>https://github.com/kakotor</url> | |||||
</developer> | |||||
<developer> | |||||
<name>xiong</name> | |||||
<email>zhaoxiong.tan@gmail.com</email> | |||||
<url>https://github.com/ZhaoxiongTan</url> | |||||
</developer> | |||||
<developer> | |||||
<name>LiuJunGuang</name> | |||||
<email>aimilin@yeah.net</email> | |||||
<url>https://github.com/aimilin6688</url> | |||||
</developer> | |||||
<developer> | |||||
<name>Eric.Tsai</name> | |||||
<email>xiaodong.cai.ks@gmail.com</email> | |||||
<url>https://github.com/iwareserictsai</url> | |||||
</developer> | |||||
<developer> | |||||
<name>withinthefog</name> | |||||
<email>withinthefog@gmail.com</email> | |||||
<url>https://github.com/withinthefog</url> | |||||
</developer> | |||||
<developer> | |||||
<name>Keung</name> | |||||
<email>dongfuqiang1988@163.com</email> | |||||
<url>https://github.com/johnnytung</url> | |||||
</developer> | |||||
<developer> | |||||
<name>Jonk</name> | |||||
<email>aimilin@yeah.net</email> | |||||
<url>https://github.com/aimilin6688</url> | |||||
</developer> | |||||
<developer> | |||||
<name>ecoolper</name> | |||||
<email>crskyp@gmail.com</email> | |||||
<url>https://github.com/crskyp</url> | |||||
</developer> | |||||
<developer> | |||||
<name>007</name> | |||||
<email>007gzs@gmail.com</email> | |||||
<url>https://github.com/007gzs</url> | |||||
</developer> | |||||
</developers> | |||||
<scm> | |||||
<connection>scm:git:https://github.com/wechat-group/weixin-java-tools.git</connection> | |||||
<developerConnection>scm:git:git@github.com:wechat-group/weixin-java-tools.git</developerConnection> | |||||
<url>https://github.com/wechat-group/weixin-java-tools</url> | |||||
</scm> | |||||
<modules> | |||||
<module>weixin-java-common</module> | |||||
<module>weixin-java-cp</module> | |||||
<module>weixin-java-mp</module> | |||||
<module>weixin-java-pay</module> | |||||
<module>weixin-java-miniapp</module> | |||||
<module>weixin-java-open</module> | |||||
<!--module>weixin-java-osgi</module--> | |||||
</modules> | |||||
<properties> | |||||
<maven.compiler.source>1.7</maven.compiler.source> | |||||
<maven.compiler.target>1.7</maven.compiler.target> | |||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |||||
<downloadJavadocs>true</downloadJavadocs> | |||||
<downloadSources>true</downloadSources> | |||||
<httpclient.version>4.5</httpclient.version> | |||||
<jetty.version>9.3.0.RC0</jetty.version> | |||||
</properties> | |||||
<dependencyManagement> | |||||
<dependencies> | |||||
<dependency> | |||||
<groupId>com.github.binarywang</groupId> | |||||
<artifactId>qrcode-utils</artifactId> | |||||
<version>1.1</version> | |||||
</dependency> | |||||
<!-- 由于jodd-http较新的3.8版本需要jdk8,故而此处采用较低版本 --> | |||||
<dependency> | |||||
<groupId>org.jodd</groupId> | |||||
<artifactId>jodd-http</artifactId> | |||||
<version>3.7.1</version> | |||||
<scope>provided</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.squareup.okhttp3</groupId> | |||||
<artifactId>okhttp</artifactId> | |||||
<version>3.7.0</version> | |||||
<scope>provided</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.httpcomponents</groupId> | |||||
<artifactId>httpclient</artifactId> | |||||
<version>${httpclient.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.httpcomponents</groupId> | |||||
<artifactId>httpmime</artifactId> | |||||
<version>${httpclient.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>commons-codec</groupId> | |||||
<artifactId>commons-codec</artifactId> | |||||
<version>1.10</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>commons-io</groupId> | |||||
<artifactId>commons-io</artifactId> | |||||
<version>2.5</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.commons</groupId> | |||||
<artifactId>commons-lang3</artifactId> | |||||
<version>3.5</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.slf4j</groupId> | |||||
<artifactId>slf4j-api</artifactId> | |||||
<version>1.7.24</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.thoughtworks.xstream</groupId> | |||||
<artifactId>xstream</artifactId> | |||||
<version>1.4.9</version> | |||||
</dependency> | |||||
<!-- 由于guava较新的21.0版本需要jdk8,故而此处采用较低版本 --> | |||||
<dependency> | |||||
<groupId>com.google.guava</groupId> | |||||
<artifactId>guava</artifactId> | |||||
<version>20.0</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.google.code.gson</groupId> | |||||
<artifactId>gson</artifactId> | |||||
<version>2.8.0</version> | |||||
</dependency> | |||||
<!-- 测试所用依赖 --> | |||||
<dependency> | |||||
<groupId>joda-time</groupId> | |||||
<artifactId>joda-time</artifactId> | |||||
<version>2.9.7</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>ch.qos.logback</groupId> | |||||
<artifactId>logback-classic</artifactId> | |||||
<version>1.1.11</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.google.inject</groupId> | |||||
<artifactId>guice</artifactId> | |||||
<version>3.0</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.testng</groupId> | |||||
<artifactId>testng</artifactId> | |||||
<version>6.10</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.mockito</groupId> | |||||
<artifactId>mockito-all</artifactId> | |||||
<version>1.9.5</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.eclipse.jetty</groupId> | |||||
<artifactId>jetty-server</artifactId> | |||||
<version>${jetty.version}</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.eclipse.jetty</groupId> | |||||
<artifactId>jetty-servlet</artifactId> | |||||
<version>${jetty.version}</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>redis.clients</groupId> | |||||
<artifactId>jedis</artifactId> | |||||
<version>2.9.0</version> | |||||
<scope>provided</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.projectlombok</groupId> | |||||
<artifactId>lombok</artifactId> | |||||
<version>1.16.18</version> | |||||
<scope>compile</scope> | |||||
</dependency> | |||||
</dependencies> | |||||
</dependencyManagement> | |||||
<distributionManagement> | |||||
<snapshotRepository> | |||||
<id>ossrh</id> | |||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url> | |||||
</snapshotRepository> | |||||
<repository> | |||||
<id>ossrh</id> | |||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> | |||||
</repository> | |||||
</distributionManagement> | |||||
<profiles> | |||||
<profile> | |||||
<id>doclint-java8-disable</id> | |||||
<activation> | |||||
<jdk>[1.8,)</jdk> | |||||
</activation> | |||||
<properties> | |||||
<javadoc.opts>-Xdoclint:none</javadoc.opts> | |||||
</properties> | |||||
</profile> | |||||
<profile> | |||||
<id>release</id> | |||||
<build> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-source-plugin</artifactId> | |||||
<version>2.2.1</version> | |||||
<executions> | |||||
<execution> | |||||
<id>attach-sources</id> | |||||
<goals> | |||||
<goal>jar-no-fork</goal> | |||||
</goals> | |||||
</execution> | |||||
</executions> | |||||
</plugin> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-javadoc-plugin</artifactId> | |||||
<version>2.9.1</version> | |||||
<executions> | |||||
<execution> | |||||
<id>attach-javadocs</id> | |||||
<goals> | |||||
<goal>jar</goal> | |||||
</goals> | |||||
</execution> | |||||
</executions> | |||||
<configuration> | |||||
<additionalparam>${javadoc.opts}</additionalparam> | |||||
<charset>UTF-8</charset> | |||||
<locale>zh_CN</locale> | |||||
</configuration> | |||||
</plugin> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-gpg-plugin</artifactId> | |||||
<version>1.6</version> | |||||
<executions> | |||||
<execution> | |||||
<id>sign-artifacts</id> | |||||
<phase>verify</phase> | |||||
<goals> | |||||
<goal>sign</goal> | |||||
</goals> | |||||
</execution> | |||||
</executions> | |||||
</plugin> | |||||
</plugins> | |||||
</build> | |||||
</profile> | |||||
</profiles> | |||||
<build> | |||||
<pluginManagement> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-surefire-plugin</artifactId> | |||||
<version>2.17</version> | |||||
<configuration> | |||||
<skip>true</skip> | |||||
</configuration> | |||||
</plugin> | |||||
</plugins> | |||||
</pluginManagement> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>org.sonatype.plugins</groupId> | |||||
<artifactId>nexus-staging-maven-plugin</artifactId> | |||||
<version>1.6.3</version> | |||||
<extensions>true</extensions> | |||||
<configuration> | |||||
<serverId>ossrh</serverId> | |||||
<nexusUrl>https://oss.sonatype.org/</nexusUrl> | |||||
<autoReleaseAfterClose>true</autoReleaseAfterClose> | |||||
</configuration> | |||||
</plugin> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-release-plugin</artifactId> | |||||
<version>2.5.1</version> | |||||
<configuration> | |||||
<autoVersionSubmodules>true</autoVersionSubmodules> | |||||
<useReleaseProfile>false</useReleaseProfile> | |||||
<releaseProfiles>release</releaseProfiles> | |||||
<goals>deploy</goals> | |||||
</configuration> | |||||
</plugin> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-compiler-plugin</artifactId> | |||||
<version>3.6.0</version> | |||||
<configuration> | |||||
<encoding>UTF-8</encoding> | |||||
</configuration> | |||||
</plugin> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-checkstyle-plugin</artifactId> | |||||
<version>2.17</version> | |||||
<configuration> | |||||
<configLocation>quality-checks/google_checks.xml</configLocation> | |||||
<includeTestSourceDirectory>true</includeTestSourceDirectory> | |||||
<consoleOutput>true</consoleOutput> | |||||
<failsOnError>true</failsOnError> | |||||
</configuration> | |||||
<executions> | |||||
<execution> | |||||
<phase>verify</phase> | |||||
<goals> | |||||
<goal>check</goal> | |||||
</goals> | |||||
</execution> | |||||
</executions> | |||||
</plugin> | |||||
</plugins> | |||||
</build> | |||||
</project> |
@@ -0,0 +1,62 @@ | |||||
消息机制未实现,下面为通知回调中设置的代码部分 | |||||
``` | |||||
@RestController | |||||
@RequestMapping("notify") | |||||
public class NotifyController extends WechatThridBaseController { | |||||
@Autowired | |||||
protected WxOpenServiceDemo wxOpenService; | |||||
@RequestMapping("receive_ticket") | |||||
public Object receiveTicket(@RequestBody(required = false) String requestBody, @RequestParam("timestamp") String timestamp, | |||||
@RequestParam("nonce") String nonce, @RequestParam("signature") String signature, | |||||
@RequestParam(name = "encrypt_type", required = false) String encType, | |||||
@RequestParam(name = "msg_signature", required = false) String msgSignature) { | |||||
this.logger.info( | |||||
"\n接收微信请求:[signature=[{}], encType=[{}], msgSignature=[{}]," | |||||
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", | |||||
signature, encType, msgSignature, timestamp, nonce, requestBody); | |||||
if (!StringUtils.equalsIgnoreCase("aes", encType) || !wxOpenService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) { | |||||
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); | |||||
} | |||||
// aes加密的消息 | |||||
WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(requestBody, wxOpenService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature); | |||||
this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString()); | |||||
String out = null; | |||||
try { | |||||
out = wxOpenService.getWxOpenComponentService().route(inMessage); | |||||
} catch (WxErrorException e) { | |||||
throw new ResponseException(ErrorCodeEnum.ERROR, e); | |||||
} | |||||
this.logger.debug("\n组装回复信息:{}", out); | |||||
return out; | |||||
} | |||||
@RequestMapping("{appId}/callback") | |||||
public Object callback(@RequestBody(required = false)String requestBody, | |||||
@PathVariable ("appId") String appId, | |||||
@RequestParam("signature") String signature, | |||||
@RequestParam("timestamp") String timestamp, | |||||
@RequestParam("nonce") String nonce, | |||||
@RequestParam("openid") String openid, | |||||
@RequestParam("encrypt_type") String encType, | |||||
@RequestParam("msg_signature") String msgSignature) { | |||||
this.logger.info( | |||||
"\n接收微信请求:[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}]," | |||||
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", | |||||
appId, openid, signature, encType, msgSignature, timestamp, nonce, requestBody); | |||||
logger.info("query:"+getHttpServletRequest().getQueryString()+"\nbody:"+requestBody); | |||||
if (!StringUtils.equalsIgnoreCase("aes", encType) || !wxOpenService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) { | |||||
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); | |||||
} | |||||
String out = ""; | |||||
// aes加密的消息 | |||||
WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(requestBody, wxOpenService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature); | |||||
this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString()); | |||||
//wxOpenService.getWxOpenComponentService().getWxMpServiceByAppid(appId); | |||||
return out; | |||||
} | |||||
} | |||||
``` |
@@ -0,0 +1,97 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<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> | |||||
<parent> | |||||
<groupId>com.github.binarywang</groupId> | |||||
<artifactId>weixin-java-parent</artifactId> | |||||
<version>2.8.6.BETA</version> | |||||
</parent> | |||||
<artifactId>weixin-java-open</artifactId> | |||||
<name>WeiXin Java Tools - Open</name> | |||||
<description>微信开放平台Java SDK</description> | |||||
<developers> | |||||
<developer> | |||||
<name>007</name> | |||||
<email>007gzs@gmail.com</email> | |||||
<url>https://github.com/007gzs</url> | |||||
</developer> | |||||
</developers> | |||||
<dependencies> | |||||
<dependency> | |||||
<groupId>com.github.binarywang</groupId> | |||||
<artifactId>weixin-java-common</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.github.binarywang</groupId> | |||||
<artifactId>weixin-java-mp</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.jodd</groupId> | |||||
<artifactId>jodd-http</artifactId> | |||||
<scope>provided</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.squareup.okhttp3</groupId> | |||||
<artifactId>okhttp</artifactId> | |||||
<scope>provided</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.testng</groupId> | |||||
<artifactId>testng</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> | |||||
</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> | |||||
</project> |
@@ -0,0 +1,82 @@ | |||||
package me.chanjar.weixin.open.api; | |||||
import me.chanjar.weixin.common.bean.result.WxError; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.mp.api.WxMpService; | |||||
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; | |||||
import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerOptionResult; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public interface WxOpenComponentService { | |||||
String API_COMPONENT_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/component/api_component_token"; | |||||
String API_CREATE_PREAUTHCODE_URL = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode"; | |||||
String API_QUERY_AUTH_URL = "https://api.weixin.qq.com/cgi-bin/component/api_query_auth"; | |||||
String API_AUTHORIZER_TOKEN_URL = "https://api.weixin.qq.com /cgi-bin/component/api_authorizer_token"; | |||||
String API_GET_AUTHORIZER_INFO_URL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info"; | |||||
String API_GET_AUTHORIZER_OPTION_URL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_option"; | |||||
String API_SET_AUTHORIZER_OPTION_URL = "https://api.weixin.qq.com/cgi-bin/component/ api_set_authorizer_option"; | |||||
String COMPONENT_LOGIN_PAGE_URL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=%s&pre_auth_code=%s&redirect_uri=%s"; | |||||
String CONNECT_OAUTH2_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&component_appid=%s#wechat_redirect"; | |||||
/** | |||||
* 用code换取oauth2的access token | |||||
*/ | |||||
String OAUTH2_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&code=%s&grant_type=authorization_code&component_appid=%s"; | |||||
/** | |||||
* 刷新oauth2的access token | |||||
*/ | |||||
String OAUTH2_REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s&component_appid==%s"; | |||||
WxMpService getWxMpServiceByAppid(String appid); | |||||
WxOpenConfigStorage getWxOpenConfigStorage(); | |||||
boolean checkSignature(String timestamp, String nonce, String signature); | |||||
String getComponentAccessToken(boolean forceRefresh) throws WxErrorException; | |||||
/** | |||||
* 获取用户授权页URL(来路URL和成功跳转URL 的域名都需要为三方平台设置的 登录授权的发起页域名) | |||||
*/ | |||||
String getPreAuthUrl(String redirectURI) throws WxErrorException; | |||||
String route(WxOpenXmlMessage wxMessage) throws WxErrorException; | |||||
/** | |||||
* 使用授权码换取公众号或小程序的接口调用凭据和授权信息 | |||||
*/ | |||||
WxOpenQueryAuthResult getQueryAuth(String authorizationCode) throws WxErrorException; | |||||
/** | |||||
* 获取授权方的帐号基本信息 | |||||
*/ | |||||
WxOpenAuthorizerInfoResult getAuthorizerInfo(String authorizerAppid) throws WxErrorException; | |||||
/** | |||||
* 获取授权方的选项设置信息 | |||||
*/ | |||||
WxOpenAuthorizerOptionResult getAuthorizerOption(String authorizerAppid, String optionName) throws WxErrorException; | |||||
/** | |||||
* 设置授权方的选项信息 | |||||
*/ | |||||
WxError setAuthorizerOption(String authorizerAppid, String optionName, String optionValue) throws WxErrorException; | |||||
String getAuthorizerAccessToken(String appid, boolean forceRefresh) throws WxErrorException; | |||||
WxMpOAuth2AccessToken oauth2getAccessToken(String appid, String code) throws WxErrorException; | |||||
boolean checkSignature(String appId, String timestamp, String nonce, String signature); | |||||
WxMpOAuth2AccessToken oauth2refreshAccessToken(String appid, String refreshToken) throws WxErrorException; | |||||
String oauth2buildAuthorizationUrl(String appid, String redirectURI, String scope, String state); | |||||
} |
@@ -0,0 +1,106 @@ | |||||
package me.chanjar.weixin.open.api; | |||||
import me.chanjar.weixin.mp.api.WxMpConfigStorage; | |||||
import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; | |||||
import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public interface WxOpenConfigStorage { | |||||
void setComponentAppId(String componentAppId); | |||||
void setComponentAppSecret(String componentAppSecret); | |||||
void setComponentToken(String componentToken); | |||||
void setComponentAesKey(String componentAesKey); | |||||
String getComponentAppId(); | |||||
String getComponentAppSecret(); | |||||
String getComponentToken(); | |||||
String getComponentAesKey(); | |||||
String getComponentVerifyTicket(); | |||||
void setComponentVerifyTicket(String componentVerifyTicket); | |||||
String getComponentAccessToken(); | |||||
boolean isComponentAccessTokenExpired(); | |||||
void updateComponentAccessTokent(WxOpenComponentAccessToken componentAccessToken); | |||||
WxMpConfigStorage getWxMpConfigStorage(String appId); | |||||
/** | |||||
* 应该是线程安全的 | |||||
* | |||||
* @param componentAccessToken 新的accessToken值 | |||||
* @param expiresInSeconds 过期时间,以秒为单位 | |||||
*/ | |||||
void updateComponentAccessTokent(String componentAccessToken, int expiresInSeconds); | |||||
/** | |||||
* 是否自动刷新token | |||||
*/ | |||||
boolean autoRefreshToken(); | |||||
String getAuthorizerRefreshToken(String appId); | |||||
void setAuthorizerRefreshToken(String appId, String authorizerRefreshToken); | |||||
String getAuthorizerAccessToken(String appId); | |||||
boolean isAuthorizerAccessTokenExpired(String appId); | |||||
/** | |||||
* 强制将access token过期掉 | |||||
*/ | |||||
void expireAuthorizerAccessToken(String appId); | |||||
/** | |||||
* 应该是线程安全的 | |||||
* | |||||
* @param authorizerAccessToken 要更新的WxAccessToken对象 | |||||
*/ | |||||
void updateAuthorizerAccessToken(String appId, WxOpenAuthorizerAccessToken authorizerAccessToken); | |||||
/** | |||||
* 应该是线程安全的 | |||||
* | |||||
* @param authorizerAccessToken 新的accessToken值 | |||||
* @param expiresInSeconds 过期时间,以秒为单位 | |||||
*/ | |||||
void updateAuthorizerAccessToken(String appId, String authorizerAccessToken, int expiresInSeconds); | |||||
String getJsapiTicket(String appId); | |||||
boolean isJsapiTicketExpired(String appId); | |||||
/** | |||||
* 强制将jsapi ticket过期掉 | |||||
*/ | |||||
void expireJsapiTicket(String appId); | |||||
/** | |||||
* 应该是线程安全的 | |||||
* | |||||
* @param jsapiTicket 新的jsapi ticket值 | |||||
* @param expiresInSeconds 过期时间,以秒为单位 | |||||
*/ | |||||
void updateJsapiTicket(String appId, String jsapiTicket, int expiresInSeconds); | |||||
String getCardApiTicket(String appId); | |||||
boolean isCardApiTicketExpired(String appId); | |||||
/** | |||||
* 强制将卡券api ticket过期掉 | |||||
*/ | |||||
void expireCardApiTicket(String appId); | |||||
/** | |||||
* 应该是线程安全的 | |||||
* | |||||
* @param cardApiTicket 新的cardApi ticket值 | |||||
* @param expiresInSeconds 过期时间,以秒为单位 | |||||
*/ | |||||
void updateCardApiTicket(String appId, String cardApiTicket, int expiresInSeconds); | |||||
} |
@@ -0,0 +1,22 @@ | |||||
package me.chanjar.weixin.open.api; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public interface WxOpenService { | |||||
WxOpenComponentService getWxOpenComponentService(); | |||||
WxOpenConfigStorage getWxOpenConfigStorage(); | |||||
void setWxOpenConfigStorage(WxOpenConfigStorage wxOpenConfigStorage); | |||||
/** | |||||
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 | |||||
*/ | |||||
String get(String url, String queryParam) throws WxErrorException; | |||||
/** | |||||
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 | |||||
*/ | |||||
String post(String url, String postData) throws WxErrorException; | |||||
} |
@@ -0,0 +1,218 @@ | |||||
package me.chanjar.weixin.open.api.impl; | |||||
import com.google.gson.JsonObject; | |||||
import me.chanjar.weixin.common.bean.result.WxError; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.util.crypto.SHA1; | |||||
import me.chanjar.weixin.common.util.http.URIUtil; | |||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
import me.chanjar.weixin.mp.api.WxMpService; | |||||
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; | |||||
import me.chanjar.weixin.open.api.WxOpenComponentService; | |||||
import me.chanjar.weixin.open.api.WxOpenConfigStorage; | |||||
import me.chanjar.weixin.open.api.WxOpenService; | |||||
import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; | |||||
import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; | |||||
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo; | |||||
import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerOptionResult; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult; | |||||
import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; | |||||
import org.apache.commons.lang3.StringUtils; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import java.util.Hashtable; | |||||
import java.util.Map; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenComponentServiceImpl implements WxOpenComponentService { | |||||
protected final Logger log = LoggerFactory.getLogger(this.getClass()); | |||||
private WxOpenService wxOpenService; | |||||
private static final Map<String, WxMpService> wxOpenMpServiceMap = new Hashtable<>(); | |||||
public WxOpenComponentServiceImpl(WxOpenService wxOpenService) { | |||||
this.wxOpenService = wxOpenService; | |||||
} | |||||
@Override | |||||
public WxMpService getWxMpServiceByAppid(String appId) { | |||||
WxMpService wxMpService = wxOpenMpServiceMap.get(appId); | |||||
if (wxMpService == null) { | |||||
synchronized (wxOpenMpServiceMap) { | |||||
wxMpService = wxOpenMpServiceMap.get(appId); | |||||
if (wxMpService == null) { | |||||
wxMpService = new WxOpenMpServiceImpl(this, appId, getWxOpenConfigStorage().getWxMpConfigStorage(appId)); | |||||
wxOpenMpServiceMap.put(appId, wxMpService); | |||||
} | |||||
} | |||||
} | |||||
return wxMpService; | |||||
} | |||||
public WxOpenService getWxOpenService() { | |||||
return wxOpenService; | |||||
} | |||||
@Override | |||||
public WxOpenConfigStorage getWxOpenConfigStorage() { | |||||
return wxOpenService.getWxOpenConfigStorage(); | |||||
} | |||||
@Override | |||||
public boolean checkSignature(String timestamp, String nonce, String signature) { | |||||
try { | |||||
return SHA1.gen(getWxOpenConfigStorage().getComponentToken(), timestamp, nonce) | |||||
.equals(signature); | |||||
} catch (Exception e) { | |||||
this.log.error("Checking signature failed, and the reason is :" + e.getMessage()); | |||||
return false; | |||||
} | |||||
} | |||||
@Override | |||||
public String getComponentAccessToken(boolean forceRefresh) throws WxErrorException { | |||||
if (this.getWxOpenConfigStorage().isComponentAccessTokenExpired() || forceRefresh) { | |||||
JsonObject jsonObject = new JsonObject(); | |||||
jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId()); | |||||
jsonObject.addProperty("component_appsecret", getWxOpenConfigStorage().getComponentAppSecret()); | |||||
jsonObject.addProperty("component_verify_ticket", getWxOpenConfigStorage().getComponentVerifyTicket()); | |||||
String responseContent = this.getWxOpenService().post(API_COMPONENT_TOKEN_URL, jsonObject.toString()); | |||||
WxOpenComponentAccessToken componentAccessToken = WxOpenComponentAccessToken.fromJson(responseContent); | |||||
getWxOpenConfigStorage().updateComponentAccessTokent(componentAccessToken); | |||||
} | |||||
return this.getWxOpenConfigStorage().getComponentAccessToken(); | |||||
} | |||||
private String post(String uri, String postData) throws WxErrorException { | |||||
String componentAccessToken = getComponentAccessToken(false); | |||||
String uriWithComponentAccessToken = uri + (uri.contains("?") ? "&" : "?") + "component_access_token=" + componentAccessToken; | |||||
return getWxOpenService().post(uriWithComponentAccessToken, postData); | |||||
} | |||||
private String get(String uri) throws WxErrorException { | |||||
String componentAccessToken = getComponentAccessToken(false); | |||||
String uriWithComponentAccessToken = uri + (uri.contains("?") ? "&" : "?") + "component_access_token=" + componentAccessToken; | |||||
return getWxOpenService().get(uriWithComponentAccessToken, null); | |||||
} | |||||
@Override | |||||
public String getPreAuthUrl(String redirectURI) throws WxErrorException { | |||||
JsonObject jsonObject = new JsonObject(); | |||||
jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId()); | |||||
String responseContent = post(API_CREATE_PREAUTHCODE_URL, jsonObject.toString()); | |||||
jsonObject = WxGsonBuilder.create().fromJson(responseContent, JsonObject.class); | |||||
return String.format(COMPONENT_LOGIN_PAGE_URL, getWxOpenConfigStorage().getComponentAppId(), jsonObject.get("pre_auth_code").getAsString(), URIUtil.encodeURIComponent(redirectURI)); | |||||
} | |||||
@Override | |||||
public String route(final WxOpenXmlMessage wxMessage) throws WxErrorException { | |||||
if (wxMessage == null) { | |||||
throw new NullPointerException("message is empty"); | |||||
} | |||||
if (StringUtils.equalsIgnoreCase(wxMessage.getInfoType(), "component_verify_ticket")) { | |||||
getWxOpenConfigStorage().setComponentVerifyTicket(wxMessage.getComponentVerifyTicket()); | |||||
return "success"; | |||||
} | |||||
//新增、跟新授权 | |||||
if (StringUtils.equalsAnyIgnoreCase(wxMessage.getInfoType(), "authorized", "updateauthorized")) { | |||||
WxOpenQueryAuthResult queryAuth = wxOpenService.getWxOpenComponentService().getQueryAuth(wxMessage.getAuthorizationCode()); | |||||
if (queryAuth == null || queryAuth.getAuthorizationInfo() == null || queryAuth.getAuthorizationInfo().getAuthorizerAppid() == null) { | |||||
throw new NullPointerException("getQueryAuth"); | |||||
} | |||||
WxOpenAuthorizationInfo authorizationInfo = queryAuth.getAuthorizationInfo(); | |||||
if (authorizationInfo.getAuthorizerAccessToken() != null) { | |||||
getWxOpenConfigStorage().updateAuthorizerAccessToken(authorizationInfo.getAuthorizerAppid(), | |||||
authorizationInfo.getAuthorizerAccessToken(), authorizationInfo.getExpiresIn()); | |||||
} | |||||
if (authorizationInfo.getAuthorizerRefreshToken() != null) { | |||||
getWxOpenConfigStorage().setAuthorizerRefreshToken(authorizationInfo.getAuthorizerAppid(), authorizationInfo.getAuthorizerRefreshToken()); | |||||
} | |||||
return "success"; | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public WxOpenQueryAuthResult getQueryAuth(String authorizationCode) throws WxErrorException { | |||||
JsonObject jsonObject = new JsonObject(); | |||||
jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId()); | |||||
jsonObject.addProperty("authorization_code", authorizationCode); | |||||
String responseContent = post(API_QUERY_AUTH_URL, jsonObject.toString()); | |||||
return WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenQueryAuthResult.class); | |||||
} | |||||
@Override | |||||
public WxOpenAuthorizerInfoResult getAuthorizerInfo(String authorizerAppid) throws WxErrorException { | |||||
JsonObject jsonObject = new JsonObject(); | |||||
jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId()); | |||||
jsonObject.addProperty("authorizer_appid", authorizerAppid); | |||||
String responseContent = post(API_GET_AUTHORIZER_INFO_URL, jsonObject.toString()); | |||||
return WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenAuthorizerInfoResult.class); | |||||
} | |||||
@Override | |||||
public WxOpenAuthorizerOptionResult getAuthorizerOption(String authorizerAppid, String optionName) throws WxErrorException { | |||||
JsonObject jsonObject = new JsonObject(); | |||||
jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId()); | |||||
jsonObject.addProperty("authorizer_appid", authorizerAppid); | |||||
jsonObject.addProperty("option_name", optionName); | |||||
String responseContent = post(API_GET_AUTHORIZER_OPTION_URL, jsonObject.toString()); | |||||
return WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenAuthorizerOptionResult.class); | |||||
} | |||||
@Override | |||||
public WxError setAuthorizerOption(String authorizerAppid, String optionName, String optionValue) throws WxErrorException { | |||||
JsonObject jsonObject = new JsonObject(); | |||||
jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId()); | |||||
jsonObject.addProperty("authorizer_appid", authorizerAppid); | |||||
jsonObject.addProperty("option_name", optionName); | |||||
jsonObject.addProperty("option_value", optionValue); | |||||
String responseContent = post(API_SET_AUTHORIZER_OPTION_URL, jsonObject.toString()); | |||||
return WxGsonBuilder.create().fromJson(responseContent, WxError.class); | |||||
} | |||||
@Override | |||||
public String getAuthorizerAccessToken(String appId, boolean forceRefresh) throws WxErrorException { | |||||
if (this.getWxOpenConfigStorage().isAuthorizerAccessTokenExpired(appId) || forceRefresh) { | |||||
JsonObject jsonObject = new JsonObject(); | |||||
jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId()); | |||||
jsonObject.addProperty("authorizer_appid", appId); | |||||
jsonObject.addProperty("authorizer_refresh_token", getWxOpenConfigStorage().getAuthorizerRefreshToken(appId)); | |||||
String responseContent = post(API_AUTHORIZER_TOKEN_URL, jsonObject.toString()); | |||||
WxOpenAuthorizerAccessToken wxOpenAuthorizerAccessToken = WxOpenAuthorizerAccessToken.fromJson(responseContent); | |||||
getWxOpenConfigStorage().updateAuthorizerAccessToken(appId, wxOpenAuthorizerAccessToken); | |||||
} | |||||
return this.getWxOpenConfigStorage().getAuthorizerAccessToken(appId); | |||||
} | |||||
@Override | |||||
public WxMpOAuth2AccessToken oauth2getAccessToken(String appId, String code) throws WxErrorException { | |||||
String url = String.format(OAUTH2_ACCESS_TOKEN_URL, appId, code, getWxOpenConfigStorage().getComponentAppId()); | |||||
String responseContent = get(url); | |||||
return WxMpOAuth2AccessToken.fromJson(responseContent); | |||||
} | |||||
@Override | |||||
public boolean checkSignature(String appid, String timestamp, String nonce, String signature) { | |||||
return false; | |||||
} | |||||
@Override | |||||
public WxMpOAuth2AccessToken oauth2refreshAccessToken(String appId, String refreshToken) throws WxErrorException { | |||||
String url = String.format(OAUTH2_REFRESH_TOKEN_URL, appId, refreshToken, getWxOpenConfigStorage().getComponentAppId()); | |||||
String responseContent = get(url); | |||||
return WxMpOAuth2AccessToken.fromJson(responseContent); | |||||
} | |||||
@Override | |||||
public String oauth2buildAuthorizationUrl(String appId, String redirectURI, String scope, String state) { | |||||
return String.format(CONNECT_OAUTH2_AUTHORIZE_URL, | |||||
appId, URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state), getWxOpenConfigStorage().getComponentAppId()); | |||||
} | |||||
} |
@@ -0,0 +1,386 @@ | |||||
package me.chanjar.weixin.open.api.impl; | |||||
import me.chanjar.weixin.common.bean.WxAccessToken; | |||||
import me.chanjar.weixin.common.util.ToStringUtils; | |||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | |||||
import me.chanjar.weixin.mp.api.WxMpConfigStorage; | |||||
import me.chanjar.weixin.open.api.WxOpenConfigStorage; | |||||
import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; | |||||
import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; | |||||
import java.io.File; | |||||
import java.util.Hashtable; | |||||
import java.util.Map; | |||||
import java.util.concurrent.locks.Lock; | |||||
import java.util.concurrent.locks.ReentrantLock; | |||||
/** | |||||
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 | |||||
* | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { | |||||
private String componentAppId; | |||||
private String componentAppSecret; | |||||
private String componentToken; | |||||
private String componentAesKey; | |||||
private String componentVerifyTicket; | |||||
private String componentAccessToken; | |||||
private long componentExpiresTime; | |||||
private Map<String, Token> authorizerRefreshTokens = new Hashtable<>(); | |||||
private Map<String, Token> authorizerAccessTokens = new Hashtable<>(); | |||||
private Map<String, Token> jsapiTickets = new Hashtable<>(); | |||||
private Map<String, Token> cardApiTickets = new Hashtable<>(); | |||||
@Override | |||||
public void setComponentAppId(String componentAppId) { | |||||
this.componentAppId = componentAppId; | |||||
} | |||||
@Override | |||||
public void setComponentAppSecret(String componentAppSecret) { | |||||
this.componentAppSecret = componentAppSecret; | |||||
} | |||||
@Override | |||||
public void setComponentToken(String componentToken) { | |||||
this.componentToken = componentToken; | |||||
} | |||||
@Override | |||||
public void setComponentAesKey(String componentAesKey) { | |||||
this.componentAesKey = componentAesKey; | |||||
} | |||||
@Override | |||||
public String getComponentAppId() { | |||||
return componentAppId; | |||||
} | |||||
@Override | |||||
public String getComponentAppSecret() { | |||||
return componentAppSecret; | |||||
} | |||||
@Override | |||||
public String getComponentToken() { | |||||
return componentToken; | |||||
} | |||||
@Override | |||||
public String getComponentAesKey() { | |||||
return componentAesKey; | |||||
} | |||||
@Override | |||||
public String getComponentVerifyTicket() { | |||||
return componentVerifyTicket; | |||||
} | |||||
@Override | |||||
public void setComponentVerifyTicket(String componentVerifyTicket) { | |||||
this.componentVerifyTicket = componentVerifyTicket; | |||||
} | |||||
@Override | |||||
public String getComponentAccessToken() { | |||||
return componentAccessToken; | |||||
} | |||||
@Override | |||||
public boolean isComponentAccessTokenExpired() { | |||||
return System.currentTimeMillis() > componentExpiresTime; | |||||
} | |||||
@Override | |||||
public void updateComponentAccessTokent(WxOpenComponentAccessToken componentAccessToken) { | |||||
updateComponentAccessTokent(componentAccessToken.getComponentAccessToken(), componentAccessToken.getExpiresIn()); | |||||
} | |||||
@Override | |||||
public WxMpConfigStorage getWxMpConfigStorage(String appId) { | |||||
return new WxOpenMpConfigStorage(this, appId); | |||||
} | |||||
@Override | |||||
public void updateComponentAccessTokent(String componentAccessToken, int expiresInSeconds) { | |||||
this.componentAccessToken = componentAccessToken; | |||||
this.componentExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; | |||||
} | |||||
@Override | |||||
public boolean autoRefreshToken() { | |||||
return true; | |||||
} | |||||
private String getTokenString(Map<String, Token> map, String key){ | |||||
Token token = map.get(key); | |||||
if(token == null || (token.expiresTime != null && System.currentTimeMillis() > token.expiresTime)){ | |||||
return null; | |||||
} | |||||
return token.token; | |||||
} | |||||
private void expireToken(Map<String, Token> map, String key){ | |||||
Token token = map.get(key); | |||||
if(token != null){ | |||||
token.expiresTime = 0L; | |||||
} | |||||
} | |||||
private void updateToken(Map<String, Token> map, String key, String tokenString, Integer expiresInSeconds){ | |||||
Token token = map.get(key); | |||||
if(token == null){ | |||||
token = new Token(); | |||||
map.put(key, token); | |||||
} | |||||
token.token = tokenString; | |||||
if(expiresInSeconds != null) { | |||||
token.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; | |||||
} | |||||
} | |||||
@Override | |||||
public String getAuthorizerRefreshToken(String appId) { | |||||
return getTokenString(authorizerRefreshTokens, appId); | |||||
} | |||||
@Override | |||||
public void setAuthorizerRefreshToken(String appId, String authorizerRefreshToken) { | |||||
updateToken(authorizerRefreshTokens, appId, authorizerRefreshToken, null); | |||||
} | |||||
@Override | |||||
public String getAuthorizerAccessToken(String appId) { | |||||
return getTokenString(authorizerAccessTokens, appId); | |||||
} | |||||
@Override | |||||
public boolean isAuthorizerAccessTokenExpired(String appId) { | |||||
return getTokenString(authorizerAccessTokens, appId) == null; | |||||
} | |||||
@Override | |||||
public void expireAuthorizerAccessToken(String appId) { | |||||
expireToken(authorizerAccessTokens, appId); | |||||
} | |||||
@Override | |||||
public void updateAuthorizerAccessToken(String appId, WxOpenAuthorizerAccessToken authorizerAccessToken) { | |||||
updateAuthorizerAccessToken(appId, authorizerAccessToken.getAuthorizerAccessToken(), authorizerAccessToken.getExpiresIn()); | |||||
} | |||||
@Override | |||||
public void updateAuthorizerAccessToken(String appId, String authorizerAccessToken, int expiresInSeconds) { | |||||
updateToken(authorizerAccessTokens, appId, authorizerAccessToken, expiresInSeconds); | |||||
} | |||||
@Override | |||||
public String getJsapiTicket(String appId) { | |||||
return getTokenString(jsapiTickets, appId); | |||||
} | |||||
@Override | |||||
public boolean isJsapiTicketExpired(String appId) { | |||||
return getTokenString(jsapiTickets, appId) == null; | |||||
} | |||||
@Override | |||||
public void expireJsapiTicket(String appId) { | |||||
expireToken(jsapiTickets, appId); | |||||
} | |||||
@Override | |||||
public void updateJsapiTicket(String appId, String jsapiTicket, int expiresInSeconds) { | |||||
updateToken(jsapiTickets, appId, jsapiTicket, expiresInSeconds); | |||||
} | |||||
@Override | |||||
public String getCardApiTicket(String appId) { | |||||
return getTokenString(cardApiTickets, appId); | |||||
} | |||||
@Override | |||||
public boolean isCardApiTicketExpired(String appId) { | |||||
return getTokenString(cardApiTickets, appId) == null; | |||||
} | |||||
@Override | |||||
public void expireCardApiTicket(String appId) { | |||||
expireToken(cardApiTickets, appId); | |||||
} | |||||
@Override | |||||
public void updateCardApiTicket(String appId, String cardApiTicket, int expiresInSeconds) { | |||||
updateToken(cardApiTickets, appId, cardApiTicket, expiresInSeconds); | |||||
} | |||||
private static class Token{ | |||||
private String token; | |||||
private Long expiresTime; | |||||
} | |||||
private static class WxOpenMpConfigStorage implements WxMpConfigStorage{ | |||||
private WxOpenConfigStorage wxOpenConfigStorage; | |||||
private String appId; | |||||
private WxOpenMpConfigStorage(WxOpenConfigStorage wxOpenConfigStorage, String appId){ | |||||
this.wxOpenConfigStorage = wxOpenConfigStorage; | |||||
this.appId = appId; | |||||
} | |||||
private Lock accessTokenLock = new ReentrantLock(); | |||||
private Lock jsapiTicketLock = new ReentrantLock(); | |||||
private Lock cardApiTicketLock = new ReentrantLock(); | |||||
@Override | |||||
public String getAccessToken() { | |||||
return wxOpenConfigStorage.getAuthorizerAccessToken(appId); | |||||
} | |||||
@Override | |||||
public Lock getAccessTokenLock() { | |||||
return this.accessTokenLock; | |||||
} | |||||
@Override | |||||
public boolean isAccessTokenExpired() { | |||||
return wxOpenConfigStorage.isAuthorizerAccessTokenExpired(appId); | |||||
} | |||||
@Override | |||||
public synchronized void updateAccessToken(WxAccessToken accessToken) { | |||||
updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); | |||||
} | |||||
@Override | |||||
public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { | |||||
wxOpenConfigStorage.updateAuthorizerAccessToken(appId, accessToken, expiresInSeconds); | |||||
} | |||||
@Override | |||||
public void expireAccessToken() { | |||||
wxOpenConfigStorage.expireAuthorizerAccessToken(appId); | |||||
} | |||||
@Override | |||||
public String getJsapiTicket() { | |||||
return wxOpenConfigStorage.getJsapiTicket(appId); | |||||
} | |||||
@Override | |||||
public Lock getJsapiTicketLock() { | |||||
return this.jsapiTicketLock; | |||||
} | |||||
@Override | |||||
public boolean isJsapiTicketExpired() { | |||||
return wxOpenConfigStorage.isJsapiTicketExpired(appId); | |||||
} | |||||
@Override | |||||
public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { | |||||
wxOpenConfigStorage.updateJsapiTicket(appId, jsapiTicket, expiresInSeconds); | |||||
} | |||||
@Override | |||||
public void expireJsapiTicket() { | |||||
wxOpenConfigStorage.expireJsapiTicket(appId); | |||||
} | |||||
/** | |||||
* 卡券api_ticket | |||||
*/ | |||||
@Override | |||||
public String getCardApiTicket() { | |||||
return wxOpenConfigStorage.getCardApiTicket(appId); | |||||
} | |||||
@Override | |||||
public Lock getCardApiTicketLock() { | |||||
return this.cardApiTicketLock; | |||||
} | |||||
@Override | |||||
public boolean isCardApiTicketExpired() { | |||||
return wxOpenConfigStorage.isCardApiTicketExpired(appId); | |||||
} | |||||
@Override | |||||
public synchronized void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { | |||||
wxOpenConfigStorage.updateCardApiTicket(appId, cardApiTicket, expiresInSeconds); | |||||
} | |||||
@Override | |||||
public void expireCardApiTicket() { | |||||
wxOpenConfigStorage.expireCardApiTicket(appId); | |||||
} | |||||
@Override | |||||
public String getAppId() { | |||||
return this.appId; | |||||
} | |||||
@Override | |||||
public String getSecret() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public String getToken() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public long getExpiresTime() { | |||||
return 0; | |||||
} | |||||
@Override | |||||
public String getAesKey() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public String getOauth2redirectUri() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public String getHttpProxyHost() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public int getHttpProxyPort() { | |||||
return 0; | |||||
} | |||||
@Override | |||||
public String getHttpProxyUsername() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public String getHttpProxyPassword() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return ToStringUtils.toSimpleString(this); | |||||
} | |||||
@Override | |||||
public File getTmpDirFile() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public ApacheHttpClientBuilder getApacheHttpClientBuilder() { | |||||
return null; | |||||
} | |||||
@Override | |||||
public boolean autoRefreshToken() { | |||||
return true; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,164 @@ | |||||
package me.chanjar.weixin.open.api.impl; | |||||
import redis.clients.jedis.Jedis; | |||||
import redis.clients.jedis.JedisPool; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenInRedisConfigStorage extends WxOpenInMemoryConfigStorage { | |||||
private final static String COMPONENT_VERIFY_TICKET_KEY = "wechat_component_verify_ticket:"; | |||||
private final static String COMPONENT_ACCESS_TOKEN_KEY = "wechat_component_access_token:"; | |||||
private final static String AUTHORIZER_REFRESH_TOKEN_KEY = "wechat_authorizer_refresh_token:"; | |||||
private final static String AUTHORIZER_ACCESS_TOKEN_KEY = "wechat_authorizer_access_token:"; | |||||
private final static String JSAPI_TICKET_KEY = "wechat_jsapi_ticket:"; | |||||
private final static String CARD_API_TICKET_KEY = "wechat_card_api_ticket:"; | |||||
protected final JedisPool jedisPool; | |||||
private String componentVerifyTicketKey; | |||||
private String componentAccessTokenKey; | |||||
private String authorizerRefreshTokenKey; | |||||
private String authorizerAccessTokenKey; | |||||
private String jsapiTicketKey; | |||||
private String cardApiTicket; | |||||
public WxOpenInRedisConfigStorage(JedisPool jedisPool) { | |||||
this.jedisPool = jedisPool; | |||||
} | |||||
@Override | |||||
public void setComponentAppId(String componentAppId) { | |||||
super.setComponentAppId(componentAppId); | |||||
componentVerifyTicketKey = COMPONENT_VERIFY_TICKET_KEY.concat(componentAppId); | |||||
componentAccessTokenKey = COMPONENT_ACCESS_TOKEN_KEY.concat(componentAppId); | |||||
authorizerRefreshTokenKey = AUTHORIZER_REFRESH_TOKEN_KEY.concat(componentAppId); | |||||
authorizerAccessTokenKey = AUTHORIZER_ACCESS_TOKEN_KEY.concat(componentAppId); | |||||
jsapiTicketKey = JSAPI_TICKET_KEY.concat(componentAppId); | |||||
cardApiTicket = CARD_API_TICKET_KEY.concat(componentAppId); | |||||
} | |||||
@Override | |||||
public String getComponentVerifyTicket(){ | |||||
try(Jedis jedis = jedisPool.getResource()){ | |||||
return jedis.get(componentVerifyTicketKey); | |||||
} | |||||
} | |||||
@Override | |||||
public void setComponentVerifyTicket(String componentVerifyTicket){ | |||||
try(Jedis jedis = jedisPool.getResource()){ | |||||
jedis.set(componentVerifyTicketKey, componentVerifyTicket); | |||||
} | |||||
} | |||||
@Override | |||||
public String getComponentAccessToken(){ | |||||
try(Jedis jedis = jedisPool.getResource()){ | |||||
return jedis.get(componentAccessTokenKey); | |||||
} | |||||
} | |||||
@Override | |||||
public boolean isComponentAccessTokenExpired(){ | |||||
try(Jedis jedis = jedisPool.getResource()){ | |||||
return jedis.ttl(componentAccessTokenKey) < 2; | |||||
} | |||||
} | |||||
@Override | |||||
public void updateComponentAccessTokent(String componentAccessToken, int expiresInSeconds){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
jedis.setex(componentAccessTokenKey, expiresInSeconds - 200, componentAccessToken); | |||||
} | |||||
} | |||||
private String getKey(String prefix, String appId){ | |||||
return prefix.endsWith(":") ? prefix.concat(appId) : prefix.concat(":").concat(appId); | |||||
} | |||||
@Override | |||||
public String getAuthorizerRefreshToken(String appId){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
return jedis.get(getKey(authorizerRefreshTokenKey, appId)); | |||||
} | |||||
} | |||||
@Override | |||||
public void setAuthorizerRefreshToken(String appId, String authorizerRefreshToken){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
jedis.set(getKey(authorizerRefreshTokenKey, appId), authorizerRefreshToken); | |||||
} | |||||
} | |||||
@Override | |||||
public String getAuthorizerAccessToken(String appId){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
return jedis.get(getKey(authorizerAccessTokenKey, appId)); | |||||
} | |||||
} | |||||
@Override | |||||
public boolean isAuthorizerAccessTokenExpired(String appId){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
return jedis.ttl(getKey(authorizerAccessTokenKey, appId)) < 2; | |||||
} | |||||
} | |||||
@Override | |||||
public void expireAuthorizerAccessToken(String appId){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
jedis.expire(getKey(authorizerAccessTokenKey, appId), 0); | |||||
} | |||||
} | |||||
@Override | |||||
public void updateAuthorizerAccessToken(String appId, String authorizerAccessToken, int expiresInSeconds){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
jedis.setex(getKey(authorizerAccessTokenKey, appId), expiresInSeconds - 200, authorizerAccessToken); | |||||
} | |||||
} | |||||
@Override | |||||
public String getJsapiTicket(String appId){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
return jedis.get(getKey(jsapiTicketKey, appId)); | |||||
} | |||||
} | |||||
@Override | |||||
public boolean isJsapiTicketExpired(String appId){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
return jedis.ttl(getKey(jsapiTicketKey, appId)) < 2; | |||||
} | |||||
} | |||||
@Override | |||||
public void expireJsapiTicket(String appId){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
jedis.expire(getKey(jsapiTicketKey, appId), 0); | |||||
} | |||||
} | |||||
@Override | |||||
public void updateJsapiTicket(String appId, String jsapiTicket, int expiresInSeconds){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
jedis.setex(getKey(jsapiTicketKey, appId), expiresInSeconds - 200, jsapiTicket); | |||||
} | |||||
} | |||||
@Override | |||||
public String getCardApiTicket(String appId){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
return jedis.get(getKey(jsapiTicketKey, appId)); | |||||
} | |||||
} | |||||
@Override | |||||
public boolean isCardApiTicketExpired(String appId){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
return jedis.ttl(getKey(cardApiTicket, appId)) < 2; | |||||
} | |||||
} | |||||
@Override | |||||
public void expireCardApiTicket(String appId){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
jedis.expire(getKey(cardApiTicket, appId), 0); | |||||
} | |||||
} | |||||
@Override | |||||
public void updateCardApiTicket(String appId, String cardApiTicket, int expiresInSeconds){ | |||||
try (Jedis jedis = this.jedisPool.getResource()) { | |||||
jedis.setex(getKey(cardApiTicket, appId), expiresInSeconds - 200, cardApiTicket); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,49 @@ | |||||
package me.chanjar.weixin.open.api.impl; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.mp.api.WxMpConfigStorage; | |||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; | |||||
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; | |||||
import me.chanjar.weixin.open.api.WxOpenComponentService; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenMpServiceImpl extends WxMpServiceImpl { | |||||
private WxOpenComponentService wxOpenComponentService; | |||||
private WxMpConfigStorage wxMpConfigStorage; | |||||
private String appId; | |||||
public WxOpenMpServiceImpl(WxOpenComponentService wxOpenComponentService, String appId, WxMpConfigStorage wxMpConfigStorage){ | |||||
this.wxOpenComponentService = wxOpenComponentService; | |||||
this.appId = appId; | |||||
this.wxMpConfigStorage = wxMpConfigStorage; | |||||
} | |||||
@Override | |||||
public WxMpConfigStorage getWxMpConfigStorage(){ | |||||
return wxMpConfigStorage; | |||||
} | |||||
@Override | |||||
public String getAccessToken(boolean forceRefresh) throws WxErrorException { | |||||
return wxOpenComponentService.getAuthorizerAccessToken(appId, forceRefresh); | |||||
} | |||||
@Override | |||||
public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { | |||||
return wxOpenComponentService.oauth2getAccessToken(appId, code); | |||||
} | |||||
// @Override | |||||
// public boolean checkSignature(String timestamp, String nonce, String signature) { | |||||
// return wxOpenComponentService.checkSignature(appId, timestamp, nonce, signature); | |||||
// } | |||||
@Override | |||||
public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { | |||||
return wxOpenComponentService.oauth2refreshAccessToken(appId, refreshToken); | |||||
} | |||||
@Override | |||||
public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { | |||||
return wxOpenComponentService.oauth2buildAuthorizationUrl(appId, redirectURI, scope, state); | |||||
} | |||||
} |
@@ -0,0 +1,63 @@ | |||||
package me.chanjar.weixin.open.api.impl; | |||||
import me.chanjar.weixin.common.bean.result.WxError; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.util.http.RequestExecutor; | |||||
import me.chanjar.weixin.common.util.http.RequestHttp; | |||||
import me.chanjar.weixin.open.api.WxOpenComponentService; | |||||
import me.chanjar.weixin.open.api.WxOpenConfigStorage; | |||||
import me.chanjar.weixin.open.api.WxOpenService; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import java.io.IOException; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public abstract class WxOpenServiceAbstractImpl<H, P> implements WxOpenService, RequestHttp<H, P> { | |||||
protected final Logger log = LoggerFactory.getLogger(this.getClass()); | |||||
private WxOpenConfigStorage wxOpenConfigStorage; | |||||
protected WxOpenComponentService wxOpenComponentService = new WxOpenComponentServiceImpl(this); | |||||
@Override | |||||
public WxOpenComponentService getWxOpenComponentService() { | |||||
return wxOpenComponentService; | |||||
} | |||||
@Override | |||||
public WxOpenConfigStorage getWxOpenConfigStorage(){ | |||||
return wxOpenConfigStorage; | |||||
} | |||||
public void setWxOpenConfigStorage(WxOpenConfigStorage wxOpenConfigStorage){ | |||||
this.wxOpenConfigStorage = wxOpenConfigStorage; | |||||
} | |||||
protected synchronized <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | |||||
try { | |||||
T result = executor.execute(uri, data); | |||||
this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uri, data, result); | |||||
return result; | |||||
} catch (WxErrorException e) { | |||||
WxError error = e.getError(); | |||||
// /* | |||||
// * 发生以下情况时尝试刷新access_token | |||||
// * 40001 获取access_token时AppSecret错误,或者access_token无效 | |||||
// * 42001 access_token超时 | |||||
// * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口 | |||||
// */ | |||||
// if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001 || error.getErrorCode() == 40014) { | |||||
// // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token | |||||
// this.configStorage.expireAccessToken(); | |||||
// return execute(executor, uri, data); | |||||
// } | |||||
if (error.getErrorCode() != 0) { | |||||
this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uri, data, error); | |||||
throw new WxErrorException(error, e); | |||||
} | |||||
return null; | |||||
} catch (IOException e) { | |||||
this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uri, data, e.getMessage()); | |||||
throw new RuntimeException(e); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,44 @@ | |||||
package me.chanjar.weixin.open.api.impl; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.util.http.HttpType; | |||||
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | |||||
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; | |||||
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; | |||||
import org.apache.http.HttpHost; | |||||
import org.apache.http.impl.client.CloseableHttpClient; | |||||
/** | |||||
* apache-http方式实现 | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenServiceApacheHttpClientImpl extends WxOpenServiceAbstractImpl<CloseableHttpClient, HttpHost> { | |||||
private CloseableHttpClient httpClient = DefaultApacheHttpClientBuilder.get().build(); | |||||
private HttpHost httpProxy = null; | |||||
@Override | |||||
public CloseableHttpClient getRequestHttpClient() { | |||||
return httpClient; | |||||
} | |||||
@Override | |||||
public HttpHost getRequestHttpProxy() { | |||||
return httpProxy; | |||||
} | |||||
@Override | |||||
public HttpType getRequestType() { | |||||
return HttpType.APACHE_HTTP; | |||||
} | |||||
@Override | |||||
public String get(String url, String queryParam) throws WxErrorException { | |||||
return execute(SimpleGetRequestExecutor.create(this), url, queryParam); | |||||
} | |||||
@Override | |||||
public String post(String url, String postData) throws WxErrorException { | |||||
return execute(SimplePostRequestExecutor.create(this), url, postData); | |||||
} | |||||
} |
@@ -0,0 +1,8 @@ | |||||
package me.chanjar.weixin.open.api.impl; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenServiceImpl extends WxOpenServiceApacheHttpClientImpl { | |||||
} |
@@ -0,0 +1,35 @@ | |||||
package me.chanjar.weixin.open.bean; | |||||
import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; | |||||
import java.io.Serializable; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenAuthorizerAccessToken implements Serializable{ | |||||
private String authorizerAccessToken; | |||||
private int expiresIn = -1; | |||||
public static WxOpenAuthorizerAccessToken fromJson(String json) { | |||||
return WxOpenGsonBuilder.create().fromJson(json, WxOpenAuthorizerAccessToken.class); | |||||
} | |||||
public String getAuthorizerAccessToken() { | |||||
return authorizerAccessToken; | |||||
} | |||||
public void setAuthorizerAccessToken(String authorizerAccessToken) { | |||||
this.authorizerAccessToken = authorizerAccessToken; | |||||
} | |||||
public int getExpiresIn() { | |||||
return expiresIn; | |||||
} | |||||
public void setExpiresIn(int expiresIn) { | |||||
this.expiresIn = expiresIn; | |||||
} | |||||
} |
@@ -0,0 +1,35 @@ | |||||
package me.chanjar.weixin.open.bean; | |||||
import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; | |||||
import java.io.Serializable; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenComponentAccessToken implements Serializable{ | |||||
private String componentAccessToken; | |||||
private int expiresIn = -1; | |||||
public static WxOpenComponentAccessToken fromJson(String json) { | |||||
return WxOpenGsonBuilder.create().fromJson(json, WxOpenComponentAccessToken.class); | |||||
} | |||||
public String getComponentAccessToken() { | |||||
return componentAccessToken; | |||||
} | |||||
public void setComponentAccessToken(String componentAccessToken) { | |||||
this.componentAccessToken = componentAccessToken; | |||||
} | |||||
public int getExpiresIn() { | |||||
return expiresIn; | |||||
} | |||||
public void setExpiresIn(int expiresIn) { | |||||
this.expiresIn = expiresIn; | |||||
} | |||||
} |
@@ -0,0 +1,18 @@ | |||||
package me.chanjar.weixin.open.bean.auth; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
@Data | |||||
public class WxOpenAuthorizationInfo implements Serializable{ | |||||
private String authorizerAppid; | |||||
private String authorizerAccessToken; | |||||
private int expiresIn; | |||||
private String authorizerRefreshToken; | |||||
private List<Integer> funcInfo; | |||||
} |
@@ -0,0 +1,22 @@ | |||||
package me.chanjar.weixin.open.bean.auth; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
import java.util.Map; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
@Data | |||||
public class WxOpenAuthorizerInfo implements Serializable{ | |||||
private String nickName; | |||||
private String headImg; | |||||
private Integer serviceTypeInfo; | |||||
private Integer verifyTypeInfo; | |||||
private String userName; | |||||
private String principalName; | |||||
private Map<String, Integer> businessInfo; | |||||
private String alias; | |||||
private String qrcodeUrl; | |||||
} |
@@ -0,0 +1,100 @@ | |||||
package me.chanjar.weixin.open.bean.message; | |||||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||||
import com.thoughtworks.xstream.annotations.XStreamConverter; | |||||
import lombok.Data; | |||||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; | |||||
import me.chanjar.weixin.open.api.WxOpenConfigStorage; | |||||
import me.chanjar.weixin.open.util.WxOpenCryptUtil; | |||||
import me.chanjar.weixin.open.util.xml.XStreamTransformer; | |||||
import org.apache.commons.io.IOUtils; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import java.io.Serializable; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
@XStreamAlias("xml") | |||||
@Data | |||||
public class WxOpenXmlMessage implements Serializable{ | |||||
@XStreamAlias("AppId") | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String appId; | |||||
@XStreamAlias("CreateTime") | |||||
private Long createTime; | |||||
@XStreamAlias("InfoType") | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String infoType; | |||||
@XStreamAlias("ComponentVerifyTicket") | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String componentVerifyTicket; | |||||
@XStreamAlias("AuthorizerAppid") | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String authorizerAppid; | |||||
@XStreamAlias("AuthorizationCode") | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String authorizationCode; | |||||
@XStreamAlias("AuthorizationCodeExpiredTime") | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private Long authorizationCodeExpiredTime; | |||||
@XStreamAlias("PreAuthCode") | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String preAuthCode; | |||||
public static WxOpenXmlMessage fromXml(String xml) { | |||||
//修改微信变态的消息内容格式,方便解析 | |||||
xml = xml.replace("</PicList><PicList>", ""); | |||||
return XStreamTransformer.fromXml(WxOpenXmlMessage.class, xml); | |||||
} | |||||
public static WxOpenXmlMessage fromXml(InputStream is) { | |||||
return XStreamTransformer.fromXml(WxOpenXmlMessage.class, is); | |||||
} | |||||
/** | |||||
* 从加密字符串转换 | |||||
* | |||||
* @param encryptedXml 密文 | |||||
* @param wxOpenConfigStorage 配置存储器对象 | |||||
* @param timestamp 时间戳 | |||||
* @param nonce 随机串 | |||||
* @param msgSignature 签名串 | |||||
*/ | |||||
public static WxOpenXmlMessage fromEncryptedXml(String encryptedXml, | |||||
WxOpenConfigStorage wxOpenConfigStorage, String timestamp, String nonce, | |||||
String msgSignature) { | |||||
WxOpenCryptUtil cryptUtil = new WxOpenCryptUtil(wxOpenConfigStorage); | |||||
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, | |||||
encryptedXml); | |||||
return fromXml(plainText); | |||||
} | |||||
public static WxMpXmlMessage fromEncryptedMpXml(String encryptedXml, | |||||
WxOpenConfigStorage wxOpenConfigStorage, String timestamp, String nonce, | |||||
String msgSignature) { | |||||
WxOpenCryptUtil cryptUtil = new WxOpenCryptUtil(wxOpenConfigStorage); | |||||
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, | |||||
encryptedXml); | |||||
return WxMpXmlMessage.fromXml(plainText); | |||||
} | |||||
public static WxOpenXmlMessage fromEncryptedXml(InputStream is, | |||||
WxOpenConfigStorage wxOpenConfigStorage, String timestamp, String nonce, | |||||
String msgSignature) { | |||||
try { | |||||
return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxOpenConfigStorage, | |||||
timestamp, nonce, msgSignature); | |||||
} catch (IOException e) { | |||||
throw new RuntimeException(e); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,16 @@ | |||||
package me.chanjar.weixin.open.bean.result; | |||||
import lombok.Data; | |||||
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo; | |||||
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizerInfo; | |||||
import java.io.Serializable; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
@Data | |||||
public class WxOpenAuthorizerInfoResult implements Serializable{ | |||||
private WxOpenAuthorizationInfo authorizationInfo; | |||||
private WxOpenAuthorizerInfo authorizerInfo; | |||||
} |
@@ -0,0 +1,15 @@ | |||||
package me.chanjar.weixin.open.bean.result; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
@Data | |||||
public class WxOpenAuthorizerOptionResult implements Serializable{ | |||||
String authorizerAppid; | |||||
String optionName; | |||||
String optionValue; | |||||
} |
@@ -0,0 +1,14 @@ | |||||
package me.chanjar.weixin.open.bean.result; | |||||
import lombok.Data; | |||||
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo; | |||||
import java.io.Serializable; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
@Data | |||||
public class WxOpenQueryAuthResult implements Serializable{ | |||||
private WxOpenAuthorizationInfo authorizationInfo; | |||||
} |
@@ -0,0 +1,28 @@ | |||||
package me.chanjar.weixin.open.util; | |||||
import me.chanjar.weixin.open.api.WxOpenConfigStorage; | |||||
import org.apache.commons.codec.binary.Base64; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenCryptUtil extends me.chanjar.weixin.common.util.crypto.WxCryptUtil { | |||||
/** | |||||
* 构造函数 | |||||
* | |||||
* @param wxOpenConfigStorage | |||||
*/ | |||||
public WxOpenCryptUtil(WxOpenConfigStorage wxOpenConfigStorage) { | |||||
/* | |||||
* @param token 公众平台上,开发者设置的token | |||||
* @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey | |||||
* @param appId 公众平台appid | |||||
*/ | |||||
String encodingAesKey = wxOpenConfigStorage.getComponentAesKey(); | |||||
String token = wxOpenConfigStorage.getComponentToken(); | |||||
String appId = wxOpenConfigStorage.getComponentAppId(); | |||||
this.token = token; | |||||
this.appidOrCorpid = appId; | |||||
this.aesKey = Base64.decodeBase64(encodingAesKey + "="); | |||||
} | |||||
} |
@@ -0,0 +1,45 @@ | |||||
package me.chanjar.weixin.open.util.json; | |||||
import com.google.gson.*; | |||||
import me.chanjar.weixin.common.util.json.GsonHelper; | |||||
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo; | |||||
import java.lang.reflect.Type; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenAuthorizationInfoGsonAdapter implements JsonDeserializer<WxOpenAuthorizationInfo> { | |||||
@Override | |||||
public WxOpenAuthorizationInfo deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { | |||||
WxOpenAuthorizationInfo authorizationInfo = new WxOpenAuthorizationInfo(); | |||||
JsonObject jsonObject = jsonElement.getAsJsonObject(); | |||||
authorizationInfo.setAuthorizerAppid(GsonHelper.getString(jsonObject, "authorizer_appid")); | |||||
authorizationInfo.setAuthorizerAccessToken(GsonHelper.getString(jsonObject, "authorizer_access_token")); | |||||
authorizationInfo.setExpiresIn(GsonHelper.getPrimitiveInteger(jsonObject, "expires_in")); | |||||
authorizationInfo.setAuthorizerRefreshToken(GsonHelper.getString(jsonObject, "authorizer_refresh_token")); | |||||
List<Integer> funcInfo = new ArrayList<>(); | |||||
JsonArray jsonArray = GsonHelper.getAsJsonArray(jsonObject.get("func_info")); | |||||
if(jsonArray != null && !jsonArray.isJsonNull()){ | |||||
for(int i = 0; i < jsonArray.size(); i++){ | |||||
jsonObject = jsonArray.get(i).getAsJsonObject(); | |||||
if(jsonObject == null || jsonObject.isJsonNull()){ | |||||
continue; | |||||
} | |||||
jsonObject = jsonObject.getAsJsonObject("funcscope_category"); | |||||
if(jsonObject == null || jsonObject.isJsonNull()){ | |||||
continue; | |||||
} | |||||
Integer id = GsonHelper.getInteger(jsonObject, "id"); | |||||
if(id == null) { | |||||
continue; | |||||
} | |||||
funcInfo.add(id); | |||||
} | |||||
} | |||||
authorizationInfo.setFuncInfo(funcInfo); | |||||
return authorizationInfo; | |||||
} | |||||
} |
@@ -0,0 +1,21 @@ | |||||
package me.chanjar.weixin.open.util.json; | |||||
import com.google.gson.*; | |||||
import me.chanjar.weixin.common.util.json.GsonHelper; | |||||
import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; | |||||
import java.lang.reflect.Type; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenAuthorizerAccessTokenGsonAdapter implements JsonDeserializer<WxOpenAuthorizerAccessToken> { | |||||
@Override | |||||
public WxOpenAuthorizerAccessToken deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { | |||||
WxOpenAuthorizerAccessToken authorizerAccessToken = new WxOpenAuthorizerAccessToken(); | |||||
JsonObject jsonObject = jsonElement.getAsJsonObject(); | |||||
authorizerAccessToken.setAuthorizerAccessToken(GsonHelper.getString(jsonObject, "authorizer_access_token")); | |||||
authorizerAccessToken.setExpiresIn(GsonHelper.getPrimitiveInteger(jsonObject, "expires_in")); | |||||
return authorizerAccessToken; | |||||
} | |||||
} |
@@ -0,0 +1,38 @@ | |||||
package me.chanjar.weixin.open.util.json; | |||||
import com.google.gson.*; | |||||
import com.google.gson.reflect.TypeToken; | |||||
import me.chanjar.weixin.common.util.json.GsonHelper; | |||||
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizerInfo; | |||||
import java.lang.reflect.Type; | |||||
import java.util.Map; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenAuthorizerInfoGsonAdapter implements JsonDeserializer<WxOpenAuthorizerInfo> { | |||||
@Override | |||||
public WxOpenAuthorizerInfo deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { | |||||
WxOpenAuthorizerInfo authorizationInfo = new WxOpenAuthorizerInfo(); | |||||
JsonObject jsonObject = jsonElement.getAsJsonObject(); | |||||
authorizationInfo.setNickName(GsonHelper.getString(jsonObject, "nick_name")); | |||||
authorizationInfo.setHeadImg(GsonHelper.getString(jsonObject, "head_img")); | |||||
authorizationInfo.setUserName(GsonHelper.getString(jsonObject, "user_name")); | |||||
authorizationInfo.setPrincipalName(GsonHelper.getString(jsonObject, "principal_name")); | |||||
authorizationInfo.setAlias(GsonHelper.getString(jsonObject, "alias")); | |||||
authorizationInfo.setQrcodeUrl(GsonHelper.getString(jsonObject, "qrcode_url")); | |||||
if(jsonObject.has("service_type_info")) { | |||||
authorizationInfo.setServiceTypeInfo(GsonHelper.getInteger(jsonObject.getAsJsonObject("service_type_info"), "id")); | |||||
} | |||||
if(jsonObject.has("verify_type_info")) { | |||||
authorizationInfo.setVerifyTypeInfo(GsonHelper.getInteger(jsonObject.getAsJsonObject("verify_type_info"), "id")); | |||||
} | |||||
Map<String, Integer> businessInfo = WxOpenGsonBuilder.create().fromJson(jsonObject.get("business_info"), | |||||
new TypeToken<Map<String, Integer>>() { | |||||
}.getType()); | |||||
authorizationInfo.setBusinessInfo(businessInfo); | |||||
return authorizationInfo; | |||||
} | |||||
} |
@@ -0,0 +1,32 @@ | |||||
package me.chanjar.weixin.open.util.json; | |||||
import com.google.gson.*; | |||||
import com.google.gson.reflect.TypeToken; | |||||
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo; | |||||
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizerInfo; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult; | |||||
import java.lang.reflect.Type; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenAuthorizerInfoResultGsonAdapter implements JsonDeserializer<WxOpenAuthorizerInfoResult> { | |||||
@Override | |||||
public WxOpenAuthorizerInfoResult deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { | |||||
WxOpenAuthorizerInfoResult authorizerInfoResult = new WxOpenAuthorizerInfoResult(); | |||||
JsonObject jsonObject = jsonElement.getAsJsonObject(); | |||||
WxOpenAuthorizationInfo authorizationInfo = WxOpenGsonBuilder.INSTANCE.create().fromJson(jsonObject.get("authorization_info"), | |||||
new TypeToken<WxOpenAuthorizationInfo>() { | |||||
}.getType()); | |||||
authorizerInfoResult.setAuthorizationInfo(authorizationInfo); | |||||
WxOpenAuthorizerInfo authorizerInfo = WxOpenGsonBuilder.INSTANCE.create().fromJson(jsonObject.get("authorizer_info"), | |||||
new TypeToken<WxOpenAuthorizerInfo>() { | |||||
}.getType()); | |||||
authorizerInfoResult.setAuthorizerInfo(authorizerInfo); | |||||
return authorizerInfoResult; | |||||
} | |||||
} |
@@ -0,0 +1,22 @@ | |||||
package me.chanjar.weixin.open.util.json; | |||||
import com.google.gson.*; | |||||
import me.chanjar.weixin.common.util.json.GsonHelper; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerOptionResult; | |||||
import java.lang.reflect.Type; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenAuthorizerOptionResultGsonAdapter implements JsonDeserializer<WxOpenAuthorizerOptionResult> { | |||||
@Override | |||||
public WxOpenAuthorizerOptionResult deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { | |||||
WxOpenAuthorizerOptionResult authorizerOptionResult = new WxOpenAuthorizerOptionResult(); | |||||
JsonObject jsonObject = jsonElement.getAsJsonObject(); | |||||
authorizerOptionResult.setAuthorizerAppid(GsonHelper.getString(jsonObject, "authorizer_appid")); | |||||
authorizerOptionResult.setOptionName(GsonHelper.getString(jsonObject, "option_name")); | |||||
authorizerOptionResult.setOptionValue(GsonHelper.getString(jsonObject, "option_value")); | |||||
return authorizerOptionResult; | |||||
} | |||||
} |
@@ -0,0 +1,21 @@ | |||||
package me.chanjar.weixin.open.util.json; | |||||
import com.google.gson.*; | |||||
import me.chanjar.weixin.common.util.json.GsonHelper; | |||||
import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; | |||||
import java.lang.reflect.Type; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenComponentAccessTokenGsonAdapter implements JsonDeserializer<WxOpenComponentAccessToken> { | |||||
@Override | |||||
public WxOpenComponentAccessToken deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { | |||||
WxOpenComponentAccessToken componentAccessToken = new WxOpenComponentAccessToken(); | |||||
JsonObject jsonObject = jsonElement.getAsJsonObject(); | |||||
componentAccessToken.setComponentAccessToken(GsonHelper.getString(jsonObject, "component_access_token")); | |||||
componentAccessToken.setExpiresIn(GsonHelper.getPrimitiveInteger(jsonObject, "expires_in")); | |||||
return componentAccessToken; | |||||
} | |||||
} |
@@ -0,0 +1,36 @@ | |||||
package me.chanjar.weixin.open.util.json; | |||||
import com.google.gson.Gson; | |||||
import com.google.gson.GsonBuilder; | |||||
import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; | |||||
import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; | |||||
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo; | |||||
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizerInfo; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerOptionResult; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenGsonBuilder { | |||||
public static final GsonBuilder INSTANCE = new GsonBuilder(); | |||||
static { | |||||
INSTANCE.disableHtmlEscaping(); | |||||
INSTANCE.registerTypeAdapter(WxOpenComponentAccessToken.class, new WxOpenComponentAccessTokenGsonAdapter()); | |||||
INSTANCE.registerTypeAdapter(WxOpenAuthorizerAccessToken.class, new WxOpenAuthorizerAccessTokenGsonAdapter()); | |||||
INSTANCE.registerTypeAdapter(WxOpenAuthorizationInfo.class, new WxOpenAuthorizationInfoGsonAdapter()); | |||||
INSTANCE.registerTypeAdapter(WxOpenAuthorizerInfo.class, new WxOpenAuthorizerInfoGsonAdapter()); | |||||
INSTANCE.registerTypeAdapter(WxOpenQueryAuthResult.class, new WxOpenQueryAuthResultGsonAdapter()); | |||||
INSTANCE.registerTypeAdapter(WxOpenAuthorizerInfoResult.class, new WxOpenAuthorizerInfoResultGsonAdapter()); | |||||
INSTANCE.registerTypeAdapter(WxOpenAuthorizerOptionResult.class, new WxOpenAuthorizerOptionResultGsonAdapter()); | |||||
} | |||||
public static Gson create() { | |||||
return INSTANCE.create(); | |||||
} | |||||
} |
@@ -0,0 +1,26 @@ | |||||
package me.chanjar.weixin.open.util.json; | |||||
import com.google.gson.*; | |||||
import com.google.gson.reflect.TypeToken; | |||||
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo; | |||||
import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult; | |||||
import java.lang.reflect.Type; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class WxOpenQueryAuthResultGsonAdapter implements JsonDeserializer<WxOpenQueryAuthResult> { | |||||
@Override | |||||
public WxOpenQueryAuthResult deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { | |||||
WxOpenQueryAuthResult queryAuthResult = new WxOpenQueryAuthResult(); | |||||
JsonObject jsonObject = jsonElement.getAsJsonObject(); | |||||
WxOpenAuthorizationInfo authorizationInfo = WxOpenGsonBuilder.INSTANCE.create().fromJson(jsonObject.get("authorization_info"), | |||||
new TypeToken<WxOpenAuthorizationInfo>() { | |||||
}.getType()); | |||||
queryAuthResult.setAuthorizationInfo(authorizationInfo); | |||||
return queryAuthResult; | |||||
} | |||||
} |
@@ -0,0 +1,90 @@ | |||||
package me.chanjar.weixin.open.util.xml; | |||||
import com.thoughtworks.xstream.XStream; | |||||
import me.chanjar.weixin.common.util.xml.XStreamInitializer; | |||||
import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage; | |||||
import java.io.InputStream; | |||||
import java.util.*; | |||||
/** | |||||
* @author <a href="https://github.com/007gzs">007</a> | |||||
*/ | |||||
public class XStreamTransformer { | |||||
private static final Map<Class<?>, XStream> CLASS_2_XSTREAM_INSTANCE = new HashMap<>(); | |||||
static { | |||||
registerClass(WxOpenXmlMessage.class); | |||||
} | |||||
/** | |||||
* xml -> pojo | |||||
*/ | |||||
@SuppressWarnings("unchecked") | |||||
public static <T> T fromXml(Class<T> clazz, String xml) { | |||||
T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(xml); | |||||
return object; | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
public static <T> T fromXml(Class<T> clazz, InputStream is) { | |||||
T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(is); | |||||
return object; | |||||
} | |||||
/** | |||||
* pojo -> xml | |||||
*/ | |||||
public static <T> String toXml(Class<T> clazz, T object) { | |||||
return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); | |||||
} | |||||
/** | |||||
* 注册扩展消息的解析器 | |||||
* | |||||
* @param clz 类型 | |||||
* @param xStream xml解析器 | |||||
*/ | |||||
private static void register(Class<?> clz, XStream xStream) { | |||||
CLASS_2_XSTREAM_INSTANCE.put(clz, xStream); | |||||
} | |||||
/** | |||||
* 会自动注册该类及其子类 | |||||
* | |||||
* @param clz 要注册的类 | |||||
*/ | |||||
private static void registerClass(Class<?> clz) { | |||||
XStream xstream = XStreamInitializer.getInstance(); | |||||
xstream.setClassLoader(Thread.currentThread().getContextClassLoader()); | |||||
xstream.processAnnotations(clz); | |||||
xstream.processAnnotations(getInnerClasses(clz)); | |||||
if (clz.equals(WxOpenXmlMessage.class)) { | |||||
// 操蛋的微信,模板消息推送成功的消息是MsgID,其他消息推送过来是MsgId | |||||
xstream.aliasField("MsgID", WxOpenXmlMessage.class, "msgId"); | |||||
} | |||||
register(clz, xstream); | |||||
} | |||||
private static Class<?>[] getInnerClasses(Class<?> clz) { | |||||
Class<?>[] innerClasses = clz.getClasses(); | |||||
if (innerClasses == null) { | |||||
return null; | |||||
} | |||||
List<Class<?>> result = new ArrayList<>(); | |||||
result.addAll(Arrays.asList(innerClasses)); | |||||
for (Class<?> inner : innerClasses) { | |||||
Class<?>[] innerClz = getInnerClasses(inner); | |||||
if (innerClz == null) { | |||||
continue; | |||||
} | |||||
result.addAll(Arrays.asList(innerClz)); | |||||
} | |||||
return result.toArray(new Class<?>[0]); | |||||
} | |||||
} |