@@ -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]); | |||
} | |||
} |