Browse Source

Merge pull request #2 from wechat-group/develop

同步版本
master
Jonk 8 years ago
committed by GitHub
parent
commit
b18056cc04
100 changed files with 1707 additions and 1030 deletions
  1. +14
    -0
      .editorconfig
  2. +6
    -4
      README.md
  3. +2
    -7
      pom.xml
  4. BIN
      res/github_id.png
  5. +1
    -1
      weixin-java-common/pom.xml
  6. +6
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
  7. +4
    -5
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java
  8. +28
    -29
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java
  9. +12
    -24
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java
  10. +23
    -21
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/DefaultApacheHttpClientBuilder.java
  11. +4
    -5
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/JoddGetRequestExecutor.java
  12. +4
    -5
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/JoddPostRequestExecutor.java
  13. +13
    -12
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java
  14. +2
    -2
      weixin-java-common/src/test/java/me/chanjar/weixin/common/session/SessionTest.java
  15. +1
    -1
      weixin-java-cp/pom.xml
  16. +4
    -4
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java
  17. +50
    -43
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java
  18. +20
    -20
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java
  19. +15
    -14
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
  20. +5
    -5
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java
  21. +134
    -97
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
  22. +12
    -8
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java
  23. +23
    -19
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java
  24. +7
    -2
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java
  25. +20
    -16
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java
  26. +83
    -78
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java
  27. +1
    -1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessage.java
  28. +4
    -4
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java
  29. +11
    -11
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessage.java
  30. +1
    -1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessage.java
  31. +9
    -9
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessage.java
  32. +1
    -1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessage.java
  33. +1
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/FileBuilder.java
  34. +1
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/ImageBuilder.java
  35. +2
    -1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/NewsBuilder.java
  36. +1
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TextBuilder.java
  37. +4
    -3
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/VideoBuilder.java
  38. +1
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/VoiceBuilder.java
  39. +1
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/ImageBuilder.java
  40. +3
    -2
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java
  41. +1
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/TextBuilder.java
  42. +4
    -3
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/VideoBuilder.java
  43. +2
    -1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/VoiceBuilder.java
  44. +2
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java
  45. +1
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java
  46. +2
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java
  47. +1
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java
  48. +1
    -1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java
  49. +22
    -15
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java
  50. +7
    -5
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java
  51. +10
    -7
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java
  52. +19
    -16
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java
  53. +26
    -20
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java
  54. +8
    -6
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java
  55. +1
    -1
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java
  56. +12
    -12
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java
  57. +5
    -5
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java
  58. +3
    -3
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java
  59. +2
    -2
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java
  60. +56
    -57
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java
  61. +13
    -13
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java
  62. +8
    -7
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java
  63. +2
    -2
      weixin-java-mp/pom.xml
  64. +2
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGroupService.java
  65. +18
    -4
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java
  66. +15
    -14
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
  67. +42
    -14
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
  68. +35
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserBlacklistService.java
  69. +58
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java
  70. +6
    -11
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java
  71. +63
    -93
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java
  72. +3
    -3
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImpl.java
  73. +60
    -27
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java
  74. +111
    -59
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java
  75. +50
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java
  76. +95
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java
  77. +0
    -3
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java
  78. +15
    -1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleResult.java
  79. +14
    -2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleTotal.java
  80. +15
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeInterfaceResult.java
  81. +15
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeMsgResult.java
  82. +18
    -3
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserCumulate.java
  83. +18
    -3
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserSummary.java
  84. +2
    -4
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java
  85. +57
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserBlacklistGetResult.java
  86. +78
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxUserTag.java
  87. +0
    -23
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxLongTimeJsonSerializer.java
  88. +1
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java
  89. +32
    -25
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpIndustryGsonAdapter.java
  90. +14
    -7
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserCumulateGsonAdapter.java
  91. +14
    -7
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserSummaryGsonAdapter.java
  92. +28
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserBlacklistGetResultGsonAdapter.java
  93. +17
    -8
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XStreamTransformer.java
  94. +15
    -5
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/ApiTestModule.java
  95. +11
    -8
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java
  96. +0
    -44
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpCustomMessageAPITest.java
  97. +6
    -6
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java
  98. +10
    -10
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java
  99. +12
    -12
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImplTest.java
  100. +15
    -3
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImplTest.java

+ 14
- 0
.editorconfig View File

@@ -0,0 +1,14 @@
# EditorConfig: http://editorconfig.org/

root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

+ 6
- 4
README.md View File

@@ -1,19 +1,21 @@
# Weixin Java Tools 微信公众号/企业号开发Java SDK
## [![Join QQ Group](http://pub.idqqimg.com/wpa/images/group.png)](http://shang.qq.com/wpa/qunwpa?idkey=078f7a153d243853e24cf2b542e7a6ccbf2a592bc138080f84d11297f736ec46) [![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/ellerbrock/open-source-badge/) ![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/weixin-java-parent.svg) [![Build Status](https://travis-ci.org/binarywang/weixin-java-tools.svg?branch=develop)](https://travis-ci.org/binarywang/weixin-java-tools)
## [![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/ellerbrock/open-source-badge/) ![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/weixin-java-parent.svg) [![Build Status](https://travis-ci.org/binarywang/weixin-java-tools.svg?branch=develop)](https://travis-ci.org/binarywang/weixin-java-tools)


### 声明:本项目Fork自chanjarster/weixin-java-tools,但由于原项目已停止维护,故单独维护和发布,且发布到maven上的groupId也会不同,详细信息见下文。

### 最新更新:2.1.0版发布!!! on 2016-08-31
#### 自2.0.0版本以来,接口调整比较大,主要是公众号的调整,企业号无过多调整,主要是为了解决主接口类过于庞大不方便管理的问题,将接口实现代码按模块进行拆分。所以如果习惯于1.X.X版本的同学不想做过多更改的话,请慎重考虑升级到2.X.X版本。

#### ***自2.0.0版本以来,接口调整比较大,主要是公众号的调整,企业号无过多调整,主要是为了解决主接口类过于庞大不方便管理的问题,将接口实现代码按模块进行拆分。所以如果习惯于1.X.X版本的同学不想做过多更改的话,请慎重考虑升级到2.X.X版本.***
---

### 详细开发文档请看 [wiki](https://github.com/chanjarster/weixin-java-tools/wiki)。
===========
## 开发交流工具:
* QQ群:343954419 [![Join QQ Group](http://pub.idqqimg.com/wpa/images/group.png)](http://shang.qq.com/wpa/qunwpa?idkey=078f7a153d243853e24cf2b542e7a6ccbf2a592bc138080f84d11297f736ec46)
* 注意:为保证入群成员质量,请申请入群时认真输入Github帐号ID,即你的github主页地址https://github.com/XXXX 中最后的部分XXXX的内容,谢谢~
* 微信群: 因二维码有时间限制,如有想加入微信群的,请入QQ群后咨询获取最新入群二维码。
* QQ群:343954419 [![Join QQ Group](http://pub.idqqimg.com/wpa/images/group.png)](http://shang.qq.com/wpa/qunwpa?idkey=078f7a153d243853e24cf2b542e7a6ccbf2a592bc138080f84d11297f736ec46)
* ***注意:为保证入群成员质量,请申请入群前,先Star本项目,然后在申请入群时,输入您的Github帐号ID,以便管理员核对,ID即你的github主页地址https://github.com/XXXX 中最后的部分XXXX的内容,或者在github网页右上角点击头像查看,如下图Signed in as下方黄色标识内容即是:***
* ![github_id](https://raw.githubusercontent.com/wechat-group/weixin-java-tools/develop/res/github_id.png)
===========



+ 2
- 7
pom.xml View File

@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>2.1.0</version>
<version>2.1.2</version>
<packaging>pom</packaging>
<name>WeiXin Java Tools - Parent</name>
<description>微信公众号、企业号上级POM</description>
@@ -49,7 +49,6 @@
<slf4j.version>1.7.10</slf4j.version>
<logback.version>1.1.2</logback.version>
<jodd-http.version>3.6.7</jodd-http.version>
<jackson.version>2.8.0</jackson.version>
<jedis.version>2.9.0</jedis.version>
<gson.version>2.7</gson.version>
<commons-lang3.version>3.4</commons-lang3.version>
@@ -106,15 +105,11 @@
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>



BIN
res/github_id.png View File

Before After
Width: 218  |  Height: 119  |  Size: 3.9 KiB

+ 1
- 1
weixin-java-common/pom.xml View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>2.1.0</version>
<version>2.1.2</version>
</parent>

<artifactId>weixin-java-common</artifactId>


+ 6
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java View File

@@ -164,6 +164,12 @@ public class WxConsts {
* 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息
*/
public static final String OAUTH2_SCOPE_USER_INFO = "snsapi_userinfo";
/**
* 网页应用登录授权作用域 snsapi_login
*/
public static final String QRCONNECT_SCOPE_SNSAPI_LOGIN = "snsapi_login";

///////////////////////
// 永久素材类型
///////////////////////


+ 4
- 5
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java View File

@@ -1,10 +1,9 @@
package me.chanjar.weixin.common.util.crypto;

import org.apache.commons.codec.digest.DigestUtils;

import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import org.apache.commons.codec.digest.DigestUtils;

/**
* Created by Daniel Qian on 14/10/19.
*/
@@ -13,7 +12,7 @@ public class SHA1 {
/**
* 串接arr参数,生成sha1 digest
*/
public static String gen(String... arr) throws NoSuchAlgorithmException {
public static String gen(String... arr) {
Arrays.sort(arr);
StringBuilder sb = new StringBuilder();
for (String a : arr) {
@@ -25,7 +24,7 @@ public class SHA1 {
/**
* 用&串接arr参数,生成sha1 digest
*/
public static String genWithAmple(String... arr) throws NoSuchAlgorithmException {
public static String genWithAmple(String... arr) {
Arrays.sort(arr);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; i++) {


+ 28
- 29
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java View File

@@ -17,11 +17,16 @@
*/
package me.chanjar.weixin.common.util.crypto;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
@@ -29,10 +34,12 @@ import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
public class WxCryptUtil {
@@ -130,13 +137,9 @@ public class WxCryptUtil {
String timeStamp = Long.toString(System.currentTimeMillis() / 1000l);
String nonce = genRandomStr();
try {
String signature = SHA1.gen(this.token, timeStamp, nonce, encryptedXml);
String result = generateXml(encryptedXml, signature, timeStamp, nonce);
return result;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
String signature = SHA1.gen(this.token, timeStamp, nonce, encryptedXml);
String result = generateXml(encryptedXml, signature, timeStamp, nonce);
return result;
}
/**
@@ -205,14 +208,10 @@ public class WxCryptUtil {
// 提取密文
String cipherText = extractEncryptPart(encryptedXml);
try {
// 验证安全签名
String signature = SHA1.gen(this.token, timeStamp, nonce, cipherText);
if (!signature.equals(msgSignature)) {
throw new RuntimeException("加密消息签名校验失败");
}
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
// 验证安全签名
String signature = SHA1.gen(this.token, timeStamp, nonce, cipherText);
if (!signature.equals(msgSignature)) {
throw new RuntimeException("加密消息签名校验失败");
}
// 解密
@@ -277,7 +276,7 @@ public class WxCryptUtil {
*
* @param number
*/
private byte[] number2BytesInNetworkOrder(int number) {
private static byte[] number2BytesInNetworkOrder(int number) {
byte[] orderBytes = new byte[4];
orderBytes[3] = (byte) (number & 0xFF);
orderBytes[2] = (byte) (number >> 8 & 0xFF);
@@ -291,7 +290,7 @@ public class WxCryptUtil {
*
* @param bytesInNetworkOrder
*/
private int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) {
private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) {
int sourceNumber = 0;
for (int i = 0; i < 4; i++) {
sourceNumber <<= 8;
@@ -303,7 +302,7 @@ public class WxCryptUtil {
/**
* 随机生成16位字符串
*/
private String genRandomStr() {
private static String genRandomStr() {
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
@@ -323,8 +322,8 @@ public class WxCryptUtil {
* @param nonce 随机字符串
* @return 生成的xml字符串
*/
private String generateXml(String encrypt, String signature, String timestamp,
String nonce) {
private static String generateXml(String encrypt, String signature,
String timestamp, String nonce) {
String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n"
+ "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n"
+ "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n"


+ 12
- 24
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java View File

@@ -17,37 +17,25 @@ public class FileUtils {
* @param tmpDirFile 临时文件夹目录
*/
public static File createTmpFile(InputStream inputStream, String name, String ext, File tmpDirFile) throws IOException {
FileOutputStream fos = null;
try {
File tmpFile;
if (tmpDirFile == null) {
tmpFile = File.createTempFile(name, '.' + ext);
} else {
tmpFile = File.createTempFile(name, '.' + ext, tmpDirFile);
}
tmpFile.deleteOnExit();
fos = new FileOutputStream(tmpFile);
File tmpFile;
if (tmpDirFile == null) {
tmpFile = File.createTempFile(name, '.' + ext);
} else {
tmpFile = File.createTempFile(name, '.' + ext, tmpDirFile);
}
tmpFile.deleteOnExit();
try (FileOutputStream fos = new FileOutputStream(tmpFile)) {
int read = 0;
byte[] bytes = new byte[1024 * 100];
while ((read = inputStream.read(bytes)) != -1) {
fos.write(bytes, 0, read);
}

fos.flush();
return tmpFile;
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
}
}
}
}
}

/**


+ 23
- 21
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/DefaultApacheHttpClientBuilder.java View File

@@ -103,43 +103,45 @@ public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder {

private void prepare() {
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", this.plainConnectionSocketFactory)
.register("https", this.sslConnectionSocketFactory)
.build();
.register("http", this.plainConnectionSocketFactory)
.register("https", this.sslConnectionSocketFactory)
.build();

@SuppressWarnings("resource")
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
connectionManager.setMaxTotal(this.maxTotalConn);
connectionManager.setDefaultMaxPerRoute(this.maxConnPerHost);
connectionManager.setDefaultSocketConfig(
SocketConfig.copy(SocketConfig.DEFAULT)
.setSoTimeout(this.soTimeout)
.build()
SocketConfig.copy(SocketConfig.DEFAULT)
.setSoTimeout(this.soTimeout)
.build()
);

this.idleConnectionMonitorThread = new IdleConnectionMonitorThread(
connectionManager, this.idleConnTimeout, this.checkWaitTime);
connectionManager, this.idleConnTimeout, this.checkWaitTime);
this.idleConnectionMonitorThread.setDaemon(true);
this.idleConnectionMonitorThread.start();

this.httpClientBuilder = HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(
RequestConfig.custom()
.setSocketTimeout(this.soTimeout)
.setConnectTimeout(this.connectionTimeout)
.setConnectionRequestTimeout(this.connectionRequestTimeout)
.build()
)
.setRetryHandler(this.httpRequestRetryHandler);
.setConnectionManager(connectionManager)
.setConnectionManagerShared(true)
.setDefaultRequestConfig(
RequestConfig.custom()
.setSocketTimeout(this.soTimeout)
.setConnectTimeout(this.connectionTimeout)
.setConnectionRequestTimeout(this.connectionRequestTimeout)
.build()
)
.setRetryHandler(this.httpRequestRetryHandler);

if (StringUtils.isNotBlank(this.httpProxyHost)
&& StringUtils.isNotBlank(this.httpProxyUsername)) {
&& StringUtils.isNotBlank(this.httpProxyUsername)) {
// 使用代理服务器 需要用户认证的代理服务器
CredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(
new AuthScope(this.httpProxyHost, this.httpProxyPort),
new UsernamePasswordCredentials(this.httpProxyUsername,
this.httpProxyPassword));
new AuthScope(this.httpProxyHost, this.httpProxyPort),
new UsernamePasswordCredentials(this.httpProxyUsername,
this.httpProxyPassword));
this.httpClientBuilder.setDefaultCredentialsProvider(provider);
}

@@ -180,7 +182,7 @@ public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder {
wait(this.checkWaitTime);
this.connMgr.closeExpiredConnections();
this.connMgr.closeIdleConnections(this.idleConnTimeout,
TimeUnit.MILLISECONDS);
TimeUnit.MILLISECONDS);
}
}
} catch (InterruptedException ignore) {


+ 4
- 5
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/JoddGetRequestExecutor.java View File

@@ -1,15 +1,14 @@
package me.chanjar.weixin.common.util.http;

import org.apache.http.HttpHost;
import org.apache.http.impl.client.CloseableHttpClient;

import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import jodd.http.ProxyInfo;
import jodd.http.net.SocketHttpConnectionProvider;
import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException;
import org.apache.http.HttpHost;
import org.apache.http.impl.client.CloseableHttpClient;

import java.io.IOException;

/**
* 简单的GET请求执行器,请求的参数是String, 返回的结果也是String
@@ -20,7 +19,7 @@ public class JoddGetRequestExecutor implements RequestExecutor<String, String> {

@Override
public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri,
String queryParam) throws WxErrorException, IOException {
String queryParam) throws WxErrorException {
if (queryParam != null) {
if (uri.indexOf('?') == -1) {
uri += '?';


+ 4
- 5
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/JoddPostRequestExecutor.java View File

@@ -1,15 +1,14 @@
package me.chanjar.weixin.common.util.http;

import org.apache.http.HttpHost;
import org.apache.http.impl.client.CloseableHttpClient;

import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import jodd.http.ProxyInfo;
import jodd.http.net.SocketHttpConnectionProvider;
import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException;
import org.apache.http.HttpHost;
import org.apache.http.impl.client.CloseableHttpClient;

import java.io.IOException;

/**
* 简单的POST请求执行器,请求的参数是String, 返回的结果也是String
@@ -20,7 +19,7 @@ public class JoddPostRequestExecutor implements RequestExecutor<String, String>

@Override
public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri,
String postEntity) throws WxErrorException, IOException {
String postEntity) throws WxErrorException {
SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider();

if (httpProxy != null) {


+ 13
- 12
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java View File

@@ -1,9 +1,11 @@
package me.chanjar.weixin.common.util.http;

import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.StringUtils;
import me.chanjar.weixin.common.util.fs.FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
@@ -12,11 +14,10 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.StringUtils;
import me.chanjar.weixin.common.util.fs.FileUtils;

/**
* 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File
@@ -52,7 +53,9 @@ public class MediaDownloadRequestExecutor implements RequestExecutor<File, Strin
httpGet.setConfig(config);
}

try (CloseableHttpResponse response = httpclient.execute(httpGet)) {
try (CloseableHttpResponse response = httpclient.execute(httpGet);
InputStream inputStream = InputStreamResponseHandler.INSTANCE
.handleResponse(response)) {

Header[] contentTypeHeader = response.getHeaders("Content-Type");
if (contentTypeHeader != null && contentTypeHeader.length > 0) {
@@ -62,8 +65,6 @@ public class MediaDownloadRequestExecutor implements RequestExecutor<File, Strin
throw new WxErrorException(WxError.fromJson(responseContent));
}
}
InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);

// 视频文件不支持下载
String fileName = getFileName(response);
if (StringUtils.isBlank(fileName)) {


+ 2
- 2
weixin-java-common/src/test/java/me/chanjar/weixin/common/session/SessionTest.java View File

@@ -106,7 +106,7 @@ public class SessionTest {
}

@Test(dataProvider = "getSessionManager")
public void testMaxActive(WxSessionManager sessionManager) throws InterruptedException {
public void testMaxActive(WxSessionManager sessionManager) {

InternalSessionManager ism = (InternalSessionManager) sessionManager;
ism.setMaxActiveSessions(2);
@@ -118,7 +118,7 @@ public class SessionTest {
}

@Test(dataProvider = "getSessionManager", expectedExceptions = TooManyActiveSessionsException.class)
public void testMaxActive2(WxSessionManager sessionManager) throws InterruptedException {
public void testMaxActive2(WxSessionManager sessionManager) {

InternalSessionManager ism = (InternalSessionManager) sessionManager;
ism.setMaxActiveSessions(2);


+ 1
- 1
weixin-java-cp/pom.xml View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>2.1.0</version>
<version>2.1.2</version>
</parent>

<artifactId>weixin-java-cp</artifactId>


+ 4
- 4
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java View File

@@ -55,13 +55,13 @@ public interface WxCpConfigStorage {

String getOauth2redirectUri();

String getHttp_proxy_host();
String getHttpProxyHost();

int getHttp_proxy_port();
int getHttpProxyPort();

String getHttp_proxy_username();
String getHttpProxyUsername();

String getHttp_proxy_password();
String getHttpProxyPassword();

File getTmpDirFile();



+ 50
- 43
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java View File

@@ -1,10 +1,13 @@
package me.chanjar.weixin.cp.api;

import java.io.File;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;

import java.io.File;

/**
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
*
@@ -23,10 +26,10 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {

protected volatile String oauth2redirectUri;

protected volatile String http_proxy_host;
protected volatile int http_proxy_port;
protected volatile String http_proxy_username;
protected volatile String http_proxy_password;
protected volatile String httpProxyHost;
protected volatile int httpProxyPort;
protected volatile String httpProxyUsername;
protected volatile String httpProxyPassword;

protected volatile String jsapiTicket;
protected volatile long jsapiTicketExpiresTime;
@@ -35,6 +38,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {

private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;

@Override
public String getAccessToken() {
return this.accessToken;
}
@@ -43,18 +47,22 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
this.accessToken = accessToken;
}

@Override
public boolean isAccessTokenExpired() {
return System.currentTimeMillis() > this.expiresTime;
}

@Override
public void expireAccessToken() {
this.expiresTime = 0;
}

@Override
public synchronized void updateAccessToken(WxAccessToken accessToken) {
updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
}

@Override
public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {
this.accessToken = accessToken;
this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l;
@@ -62,7 +70,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {

@Override
public String getJsapiTicket() {
return jsapiTicket;
return this.jsapiTicket;
}

public void setJsapiTicket(String jsapiTicket) {
@@ -70,27 +78,31 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
}

public long getJsapiTicketExpiresTime() {
return jsapiTicketExpiresTime;
return this.jsapiTicketExpiresTime;
}

public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) {
this.jsapiTicketExpiresTime = jsapiTicketExpiresTime;
}

@Override
public boolean isJsapiTicketExpired() {
return System.currentTimeMillis() > this.jsapiTicketExpiresTime;
}

@Override
public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
this.jsapiTicket = jsapiTicket;
// 预留200秒的时间
this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l;
}

@Override
public void expireJsapiTicket() {
this.jsapiTicketExpiresTime = 0;
}

@Override
public String getCorpId() {
return this.corpId;
}
@@ -99,6 +111,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
this.corpId = corpId;
}

@Override
public String getCorpSecret() {
return this.corpSecret;
}
@@ -107,6 +120,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
this.corpSecret = corpSecret;
}

@Override
public String getToken() {
return this.token;
}
@@ -115,6 +129,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
this.token = token;
}

@Override
public long getExpiresTime() {
return this.expiresTime;
}
@@ -123,16 +138,18 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
this.expiresTime = expiresTime;
}

@Override
public String getAesKey() {
return aesKey;
return this.aesKey;
}

public void setAesKey(String aesKey) {
this.aesKey = aesKey;
}

@Override
public String getAgentId() {
return agentId;
return this.agentId;
}

public void setAgentId(String agentId) {
@@ -148,60 +165,50 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
this.oauth2redirectUri = oauth2redirectUri;
}

public String getHttp_proxy_host() {
return http_proxy_host;
@Override
public String getHttpProxyHost() {
return this.httpProxyHost;
}

public void setHttp_proxy_host(String http_proxy_host) {
this.http_proxy_host = http_proxy_host;
public void setHttpProxyHost(String httpProxyHost) {
this.httpProxyHost = httpProxyHost;
}

public int getHttp_proxy_port() {
return http_proxy_port;
@Override
public int getHttpProxyPort() {
return this.httpProxyPort;
}

public void setHttp_proxy_port(int http_proxy_port) {
this.http_proxy_port = http_proxy_port;
public void setHttpProxyPort(int httpProxyPort) {
this.httpProxyPort = httpProxyPort;
}

public String getHttp_proxy_username() {
return http_proxy_username;
@Override
public String getHttpProxyUsername() {
return this.httpProxyUsername;
}

public void setHttp_proxy_username(String http_proxy_username) {
this.http_proxy_username = http_proxy_username;
public void setHttpProxyUsername(String httpProxyUsername) {
this.httpProxyUsername = httpProxyUsername;
}

public String getHttp_proxy_password() {
return http_proxy_password;
@Override
public String getHttpProxyPassword() {
return this.httpProxyPassword;
}

public void setHttp_proxy_password(String http_proxy_password) {
this.http_proxy_password = http_proxy_password;
public void setHttpProxyPassword(String httpProxyPassword) {
this.httpProxyPassword = httpProxyPassword;
}

@Override
public String toString() {
return "WxCpInMemoryConfigStorage{" +
"corpId='" + corpId + '\'' +
", corpSecret='" + corpSecret + '\'' +
", token='" + token + '\'' +
", accessToken='" + accessToken + '\'' +
", aesKey='" + aesKey + '\'' +
", agentId='" + agentId + '\'' +
", expiresTime=" + expiresTime +
", http_proxy_host='" + http_proxy_host + '\'' +
", http_proxy_port=" + http_proxy_port +
", http_proxy_username='" + http_proxy_username + '\'' +
", http_proxy_password='" + http_proxy_password + '\'' +
", jsapiTicket='" + jsapiTicket + '\'' +
", jsapiTicketExpiresTime='" + jsapiTicketExpiresTime + '\'' +
", tmpDirFile='" + tmpDirFile + '\'' +
'}';
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

@Override
public File getTmpDirFile() {
return tmpDirFile;
return this.tmpDirFile;
}

public void setTmpDirFile(File tmpDirFile) {


+ 20
- 20
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpJedisConfigStorage.java View File

@@ -29,10 +29,10 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage {
private volatile String oauth2redirectUri;
private volatile String http_proxy_host;
private volatile int http_proxy_port;
private volatile String http_proxy_username;
private volatile String http_proxy_password;
private volatile String httpProxyHost;
private volatile int httpProxyPort;
private volatile String httpProxyUsername;
private volatile String httpProxyPassword;
private volatile File tmpDirFile;
@@ -185,23 +185,23 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage {
}
@Override
public String getHttp_proxy_host() {
return this.http_proxy_host;
public String getHttpProxyHost() {
return this.httpProxyHost;
}
@Override
public int getHttp_proxy_port() {
return this.http_proxy_port;
public int getHttpProxyPort() {
return this.httpProxyPort;
}
@Override
public String getHttp_proxy_username() {
return this.http_proxy_username;
public String getHttpProxyUsername() {
return this.httpProxyUsername;
}
@Override
public String getHttp_proxy_password() {
return this.http_proxy_password;
public String getHttpProxyPassword() {
return this.httpProxyPassword;
}
@Override
@@ -240,20 +240,20 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage {
this.oauth2redirectUri = oauth2redirectUri;
}
public void setHttp_proxy_host(String http_proxy_host) {
this.http_proxy_host = http_proxy_host;
public void setHttpProxyHost(String httpProxyHost) {
this.httpProxyHost = httpProxyHost;
}
public void setHttp_proxy_port(int http_proxy_port) {
this.http_proxy_port = http_proxy_port;
public void setHttpProxyPort(int httpProxyPort) {
this.httpProxyPort = httpProxyPort;
}
public void setHttp_proxy_username(String http_proxy_username) {
this.http_proxy_username = http_proxy_username;
public void setHttpProxyUsername(String httpProxyUsername) {
this.httpProxyUsername = httpProxyUsername;
}
public void setHttp_proxy_password(String http_proxy_password) {
this.http_proxy_password = http_proxy_password;
public void setHttpProxyPassword(String httpProxyPassword) {
this.httpProxyPassword = httpProxyPassword;
}
public void setTmpDirFile(File tmpDirFile) {


+ 15
- 14
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java View File

@@ -52,7 +52,7 @@ public class WxCpMessageRouter {

private static final int DEFAULT_THREAD_POOL_SIZE = 100;
protected final Logger log = LoggerFactory.getLogger(WxCpMessageRouter.class);
private final List<WxCpMessageRouterRule> rules = new ArrayList<WxCpMessageRouterRule>();
private final List<WxCpMessageRouterRule> rules = new ArrayList<>();

private final WxCpService wxCpService;

@@ -142,9 +142,9 @@ public class WxCpMessageRouter {
return null;
}

final List<WxCpMessageRouterRule> matchRules = new ArrayList<WxCpMessageRouterRule>();
final List<WxCpMessageRouterRule> matchRules = new ArrayList<>();
// 收集匹配的规则
for (final WxCpMessageRouterRule rule : rules) {
for (final WxCpMessageRouterRule rule : this.rules) {
if (rule.test(wxMessage)) {
matchRules.add(rule);
if (!rule.isReEnter()) {
@@ -158,39 +158,40 @@ public class WxCpMessageRouter {
}

WxCpXmlOutMessage res = null;
final List<Future> futures = new ArrayList<Future>();
final List<Future> futures = new ArrayList<>();
for (final WxCpMessageRouterRule rule : matchRules) {
// 返回最后一个非异步的rule的执行结果
if (rule.isAsync()) {
futures.add(
executorService.submit(new Runnable() {
this.executorService.submit(new Runnable() {
@Override
public void run() {
rule.service(wxMessage, wxCpService, sessionManager, exceptionHandler);
rule.service(wxMessage, WxCpMessageRouter.this.wxCpService, WxCpMessageRouter.this.sessionManager, WxCpMessageRouter.this.exceptionHandler);
}
})
);
} else {
res = rule.service(wxMessage, wxCpService, sessionManager, exceptionHandler);
res = rule.service(wxMessage, this.wxCpService, this.sessionManager, this.exceptionHandler);
// 在同步操作结束,session访问结束
log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUserName());
this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUserName());
sessionEndAccess(wxMessage);
}
}

if (futures.size() > 0) {
executorService.submit(new Runnable() {
this.executorService.submit(new Runnable() {
@Override
public void run() {
for (Future future : futures) {
try {
future.get();
log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUserName());
WxCpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUserName());
// 异步操作结束,session访问结束
sessionEndAccess(wxMessage);
} catch (InterruptedException e) {
log.error("Error happened when wait task finish", e);
WxCpMessageRouter.this.log.error("Error happened when wait task finish", e);
} catch (ExecutionException e) {
log.error("Error happened when wait task finish", e);
WxCpMessageRouter.this.log.error("Error happened when wait task finish", e);
}
}
}
@@ -213,7 +214,7 @@ public class WxCpMessageRouter {
messageId = String.valueOf(wxMessage.getMsgId());
}

return messageDuplicateChecker.isDuplicate(messageId);
return this.messageDuplicateChecker.isDuplicate(messageId);

}

@@ -224,7 +225,7 @@ public class WxCpMessageRouter {
*/
protected void sessionEndAccess(WxCpXmlMessage wxMessage) {

InternalSession session = ((InternalSessionManager) sessionManager).findSession(wxMessage.getFromUserName());
InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUserName());
if (session != null) {
session.endAccess();
}


+ 5
- 5
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java View File

@@ -36,9 +36,9 @@ public class WxCpMessageRouterRule {

private Integer agentId;

private List<WxCpMessageHandler> handlers = new ArrayList<WxCpMessageHandler>();
private List<WxCpMessageHandler> handlers = new ArrayList<>();

private List<WxCpMessageInterceptor> interceptors = new ArrayList<WxCpMessageInterceptor>();
private List<WxCpMessageInterceptor> interceptors = new ArrayList<>();

protected WxCpMessageRouterRule(WxCpMessageRouter routerBuilder) {
this.routerBuilder = routerBuilder;
@@ -235,7 +235,7 @@ public class WxCpMessageRouterRule {

try {

Map<String, Object> context = new HashMap<String, Object>();
Map<String, Object> context = new HashMap<>();
// 如果拦截器不通过
for (WxCpMessageInterceptor interceptor : this.interceptors) {
if (!interceptor.intercept(wxMessage, context, wxCpService, sessionManager)) {
@@ -300,7 +300,7 @@ public class WxCpMessageRouterRule {
}

public boolean isAsync() {
return async;
return this.async;
}

public void setAsync(boolean async) {
@@ -308,7 +308,7 @@ public class WxCpMessageRouterRule {
}

public boolean isReEnter() {
return reEnter;
return this.reEnter;
}

public void setReEnter(boolean reEnter) {


+ 134
- 97
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java View File

@@ -1,12 +1,28 @@
package me.chanjar.weixin.cp.api;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.internal.Streams;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.bean.menu.WxMenu;
@@ -20,30 +36,20 @@ import me.chanjar.weixin.common.util.RandomUtils;
import me.chanjar.weixin.common.util.StringUtils;
import me.chanjar.weixin.common.util.crypto.SHA1;
import me.chanjar.weixin.common.util.fs.FileUtils;
import me.chanjar.weixin.common.util.http.*;
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.DefaultApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor;
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.common.util.http.URIUtil;
import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.cp.bean.WxCpDepart;
import me.chanjar.weixin.cp.bean.WxCpMessage;
import me.chanjar.weixin.cp.bean.WxCpTag;
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.UUID;

public class WxCpServiceImpl implements WxCpService {

@@ -59,7 +65,7 @@ public class WxCpServiceImpl implements WxCpService {
*/
protected final Object globalJsapiTicketRefreshLock = new Object();

protected WxCpConfigStorage wxCpConfigStorage;
protected WxCpConfigStorage configStorage;

protected CloseableHttpClient httpClient;

@@ -72,42 +78,48 @@ public class WxCpServiceImpl implements WxCpService {
private int retrySleepMillis = 1000;
private int maxRetryTimes = 5;

@Override
public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) {
try {
return SHA1.gen(wxCpConfigStorage.getToken(), timestamp, nonce, data).equals(msgSignature);
return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data)
.equals(msgSignature);
} catch (Exception e) {
return false;
}
}

@Override
public void userAuthenticated(String userId) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId;
get(url, null);
}

@Override
public String getAccessToken() throws WxErrorException {
return getAccessToken(false);
}

@Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
if (forceRefresh) {
wxCpConfigStorage.expireAccessToken();
this.configStorage.expireAccessToken();
}
if (wxCpConfigStorage.isAccessTokenExpired()) {
synchronized (globalAccessTokenRefreshLock) {
if (wxCpConfigStorage.isAccessTokenExpired()) {
if (this.configStorage.isAccessTokenExpired()) {
synchronized (this.globalAccessTokenRefreshLock) {
if (this.configStorage.isAccessTokenExpired()) {
String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
+ "&corpid=" + wxCpConfigStorage.getCorpId()
+ "&corpsecret=" + wxCpConfigStorage.getCorpSecret();
+ "&corpid=" + this.configStorage.getCorpId()
+ "&corpsecret=" + this.configStorage.getCorpSecret();
try {
HttpGet httpGet = new HttpGet(url);
if (httpProxy != null) {
RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build();
if (this.httpProxy != null) {
RequestConfig config = RequestConfig.custom()
.setProxy(this.httpProxy).build();
httpGet.setConfig(config);
}
CloseableHttpClient httpclient = getHttpclient();
String resultContent = null;
try (CloseableHttpResponse response = httpclient.execute(httpGet)) {
try (CloseableHttpClient httpclient = getHttpclient();
CloseableHttpResponse response = httpclient.execute(httpGet)) {
resultContent = new BasicResponseHandler().handleResponse(response);
} finally {
httpGet.releaseConnection();
@@ -117,7 +129,8 @@ public class WxCpServiceImpl implements WxCpService {
throw new WxErrorException(error);
}
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
wxCpConfigStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
this.configStorage.updateAccessToken(
accessToken.getAccessToken(), accessToken.getExpiresIn());
} catch (ClientProtocolException e) {
throw new RuntimeException(e);
} catch (IOException e) {
@@ -126,59 +139,60 @@ public class WxCpServiceImpl implements WxCpService {
}
}
}
return wxCpConfigStorage.getAccessToken();
return this.configStorage.getAccessToken();
}

@Override
public String getJsapiTicket() throws WxErrorException {
return getJsapiTicket(false);
}

@Override
public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
if (forceRefresh) {
wxCpConfigStorage.expireJsapiTicket();
this.configStorage.expireJsapiTicket();
}
if (wxCpConfigStorage.isJsapiTicketExpired()) {
synchronized (globalJsapiTicketRefreshLock) {
if (wxCpConfigStorage.isJsapiTicketExpired()) {
if (this.configStorage.isJsapiTicketExpired()) {
synchronized (this.globalJsapiTicketRefreshLock) {
if (this.configStorage.isJsapiTicketExpired()) {
String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket";
String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
wxCpConfigStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds);
this.configStorage.updateJsapiTicket(jsapiTicket,
expiresInSeconds);
}
}
}
return wxCpConfigStorage.getJsapiTicket();
return this.configStorage.getJsapiTicket();
}

@Override
public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException {
long timestamp = System.currentTimeMillis() / 1000;
String noncestr = RandomUtils.getRandomStr();
String jsapiTicket = getJsapiTicket(false);
try {
String signature = SHA1.genWithAmple(
"jsapi_ticket=" + jsapiTicket,
"noncestr=" + noncestr,
"timestamp=" + timestamp,
"url=" + url
);
WxJsapiSignature jsapiSignature = new WxJsapiSignature();
jsapiSignature.setTimestamp(timestamp);
jsapiSignature.setNoncestr(noncestr);
jsapiSignature.setUrl(url);
jsapiSignature.setSignature(signature);
// Fixed bug
jsapiSignature.setAppid(this.wxCpConfigStorage.getCorpId());
return jsapiSignature;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
String signature = SHA1.genWithAmple(
"jsapi_ticket=" + jsapiTicket,
"noncestr=" + noncestr,
"timestamp=" + timestamp,
"url=" + url
);
WxJsapiSignature jsapiSignature = new WxJsapiSignature();
jsapiSignature.setTimestamp(timestamp);
jsapiSignature.setNoncestr(noncestr);
jsapiSignature.setUrl(url);
jsapiSignature.setSignature(signature);
// Fixed bug
jsapiSignature.setAppid(this.configStorage.getCorpId());
return jsapiSignature;
}

@Override
public void messageSend(WxCpMessage message) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send";
post(url, message.toJson());
@@ -186,18 +200,19 @@ public class WxCpServiceImpl implements WxCpService {

@Override
public void menuCreate(WxMenu menu) throws WxErrorException {
menuCreate(wxCpConfigStorage.getAgentId(), menu);
menuCreate(this.configStorage.getAgentId(), menu);
}

@Override
public void menuCreate(String agentId, WxMenu menu) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" + wxCpConfigStorage.getAgentId();
String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid="
+ this.configStorage.getAgentId();
post(url, menu.toJson());
}

@Override
public void menuDelete() throws WxErrorException {
menuDelete(wxCpConfigStorage.getAgentId());
menuDelete(this.configStorage.getAgentId());
}

@Override
@@ -208,7 +223,7 @@ public class WxCpServiceImpl implements WxCpService {

@Override
public WxMenu menuGet() throws WxErrorException {
return menuGet(wxCpConfigStorage.getAgentId());
return menuGet(this.configStorage.getAgentId());
}

@Override
@@ -226,42 +241,52 @@ public class WxCpServiceImpl implements WxCpService {
}
}

@Override
public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream)
throws WxErrorException, IOException {
return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType));
}

@Override
public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType;
return execute(new MediaUploadRequestExecutor(), url, file);
}

@Override
public File mediaDownload(String media_id) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get";
return execute(new MediaDownloadRequestExecutor(wxCpConfigStorage.getTmpDirFile()), url, "media_id=" + media_id);
return execute(
new MediaDownloadRequestExecutor(
this.configStorage.getTmpDirFile()),
url, "media_id=" + media_id);
}


@Override
public Integer departCreate(WxCpDepart depart) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create";
String responseContent = execute(
new SimplePostRequestExecutor(),
url,
depart.toJson());
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id"));
}

@Override
public void departUpdate(WxCpDepart group) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update";
post(url, group.toJson());
}

@Override
public void departDelete(Integer departId) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId;
get(url, null);
}

@Override
public List<WxCpDepart> departGet() throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list";
String responseContent = get(url, null);
@@ -269,7 +294,7 @@ public class WxCpServiceImpl implements WxCpService {
* 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} }
* 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] }
*/
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return WxCpGsonBuilder.INSTANCE.create()
.fromJson(
tmpJsonElement.getAsJsonObject().get("department"),
@@ -329,7 +354,7 @@ public class WxCpServiceImpl implements WxCpService {
}

String responseContent = get(url, params);
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return WxCpGsonBuilder.INSTANCE.create()
.fromJson(
tmpJsonElement.getAsJsonObject().get("userlist"),
@@ -352,7 +377,7 @@ public class WxCpServiceImpl implements WxCpService {
}

String responseContent = get(url, params);
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return WxCpGsonBuilder.INSTANCE.create()
.fromJson(
tmpJsonElement.getAsJsonObject().get("userlist"),
@@ -367,7 +392,7 @@ public class WxCpServiceImpl implements WxCpService {
JsonObject o = new JsonObject();
o.addProperty("tagname", tagName);
String responseContent = post(url, o.toString());
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return tmpJsonElement.getAsJsonObject().get("tagid").getAsString();
}

@@ -390,7 +415,7 @@ public class WxCpServiceImpl implements WxCpService {
public List<WxCpTag> tagGet() throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list";
String responseContent = get(url, null);
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return WxCpGsonBuilder.INSTANCE.create()
.fromJson(
tmpJsonElement.getAsJsonObject().get("taglist"),
@@ -403,7 +428,7 @@ public class WxCpServiceImpl implements WxCpService {
public List<WxCpUser> tagGetUsers(String tagId) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId;
String responseContent = get(url, null);
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return WxCpGsonBuilder.INSTANCE.create()
.fromJson(
tmpJsonElement.getAsJsonObject().get("userlist"),
@@ -450,7 +475,7 @@ public class WxCpServiceImpl implements WxCpService {
@Override
public String oauth2buildAuthorizationUrl(String state) {
return this.oauth2buildAuthorizationUrl(
this.wxCpConfigStorage.getOauth2redirectUri(),
this.configStorage.getOauth2redirectUri(),
state
);
}
@@ -458,7 +483,7 @@ public class WxCpServiceImpl implements WxCpService {
@Override
public String oauth2buildAuthorizationUrl(String redirectUri, String state) {
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?";
url += "appid=" + wxCpConfigStorage.getCorpId();
url += "appid=" + this.configStorage.getCorpId();
url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri);
url += "&response_type=code";
url += "&scope=snsapi_base";
@@ -471,7 +496,7 @@ public class WxCpServiceImpl implements WxCpService {

@Override
public String[] oauth2getUserInfo(String code) throws WxErrorException {
return oauth2getUserInfo(wxCpConfigStorage.getAgentId(), code);
return oauth2getUserInfo(this.configStorage.getAgentId(), code);
}

@Override
@@ -480,7 +505,7 @@ public class WxCpServiceImpl implements WxCpService {
+ "code=" + code
+ "&agendid=" + agentId;
String responseText = get(url, null);
JsonElement je = Streams.parse(new JsonReader(new StringReader(responseText)));
JsonElement je = new JsonParser().parse(responseText);
JsonObject jo = je.getAsJsonObject();
return new String[]{GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId")};
}
@@ -494,7 +519,7 @@ public class WxCpServiceImpl implements WxCpService {
jsonObject.addProperty("invite_tips", inviteTips);
}
String responseContent = post(url, jsonObject.toString());
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return tmpJsonElement.getAsJsonObject().get("type").getAsInt();
}

@@ -502,7 +527,7 @@ public class WxCpServiceImpl implements WxCpService {
public String[] getCallbackIp() throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip";
String responseContent = get(url, null);
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray();
String[] ips = new String[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
@@ -511,10 +536,12 @@ public class WxCpServiceImpl implements WxCpService {
return ips;
}

@Override
public String get(String url, String queryParam) throws WxErrorException {
return execute(new SimpleGetRequestExecutor(), url, queryParam);
}

@Override
public String post(String url, String postData) throws WxErrorException {
return execute(new SimplePostRequestExecutor(), url, postData);
}
@@ -522,6 +549,7 @@ public class WxCpServiceImpl implements WxCpService {
/**
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求
*/
@Override
public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
int retryTimes = 0;
do {
@@ -533,9 +561,10 @@ public class WxCpServiceImpl implements WxCpService {
* -1 系统繁忙, 1000ms后重试
*/
if (error.getErrorCode() == -1) {
int sleepMillis = retrySleepMillis * (1 << retryTimes);
int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
try {
log.debug("微信系统繁忙,{}ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
this.log.debug("微信系统繁忙,{}ms 后重试(第{}次)", sleepMillis,
retryTimes + 1);
Thread.sleep(sleepMillis);
} catch (InterruptedException e1) {
throw new RuntimeException(e1);
@@ -544,7 +573,7 @@ public class WxCpServiceImpl implements WxCpService {
throw e;
}
}
} while (++retryTimes < maxRetryTimes);
} while (++retryTimes < this.maxRetryTimes);

throw new RuntimeException("微信服务端异常,超出重试次数");
}
@@ -559,7 +588,8 @@ public class WxCpServiceImpl implements WxCpService {
uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken;

try {
return executor.execute(getHttpclient(), httpProxy, uriWithAccessToken, data);
return executor.execute(getHttpclient(), this.httpProxy,
uriWithAccessToken, data);
} catch (WxErrorException e) {
WxError error = e.getError();
/*
@@ -569,7 +599,7 @@ public class WxCpServiceImpl implements WxCpService {
*/
if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) {
// 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token
wxCpConfigStorage.expireAccessToken();
this.configStorage.expireAccessToken();
return execute(executor, uri, data);
}
if (error.getErrorCode() != 0) {
@@ -584,21 +614,28 @@ public class WxCpServiceImpl implements WxCpService {
}

protected CloseableHttpClient getHttpclient() {
return httpClient;
return this.httpClient;
}

@Override
public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) {
this.wxCpConfigStorage = wxConfigProvider;
ApacheHttpClientBuilder apacheHttpClientBuilder = wxCpConfigStorage.getApacheHttpClientBuilder();
this.configStorage = wxConfigProvider;
ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage
.getApacheHttpClientBuilder();
if (null == apacheHttpClientBuilder) {
apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get();
}
apacheHttpClientBuilder.httpProxyHost(wxCpConfigStorage.getHttp_proxy_host())
.httpProxyPort(wxCpConfigStorage.getHttp_proxy_port())
.httpProxyUsername(wxCpConfigStorage.getHttp_proxy_username())
.httpProxyPassword(wxCpConfigStorage.getHttp_proxy_password());

httpClient = apacheHttpClientBuilder.build();
apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost())
.httpProxyPort(this.configStorage.getHttpProxyPort())
.httpProxyUsername(this.configStorage.getHttpProxyUsername())
.httpProxyPassword(this.configStorage.getHttpProxyPassword());

if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort());
}

this.httpClient = apacheHttpClientBuilder.build();
}

@Override
@@ -614,18 +651,18 @@ public class WxCpServiceImpl implements WxCpService {

@Override
public WxSession getSession(String id) {
if (sessionManager == null) {
if (this.sessionManager == null) {
return null;
}
return sessionManager.getSession(id);
return this.sessionManager.getSession(id);
}

@Override
public WxSession getSession(String id, boolean create) {
if (sessionManager == null) {
if (this.sessionManager == null) {
return null;
}
return sessionManager.getSession(id, create);
return this.sessionManager.getSession(id, create);
}


@@ -657,7 +694,7 @@ public class WxCpServiceImpl implements WxCpService {
}

public File getTmpDirFile() {
return tmpDirFile;
return this.tmpDirFile;
}

public void setTmpDirFile(File tmpDirFile) {


+ 12
- 8
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java View File

@@ -11,6 +11,10 @@ import java.io.Serializable;
*/
public class WxCpDepart implements Serializable {

/**
*
*/
private static final long serialVersionUID = -5028321625140879571L;
private Integer id;
private String name;
private Integer parentId;
@@ -21,7 +25,7 @@ public class WxCpDepart implements Serializable {
}

public Integer getId() {
return id;
return this.id;
}

public void setId(Integer id) {
@@ -29,7 +33,7 @@ public class WxCpDepart implements Serializable {
}

public String getName() {
return name;
return this.name;
}

public void setName(String name) {
@@ -37,7 +41,7 @@ public class WxCpDepart implements Serializable {
}

public Integer getParentId() {
return parentId;
return this.parentId;
}

public void setParentId(Integer parentId) {
@@ -45,7 +49,7 @@ public class WxCpDepart implements Serializable {
}

public Integer getOrder() {
return order;
return this.order;
}

public void setOrder(Integer order) {
@@ -59,10 +63,10 @@ public class WxCpDepart implements Serializable {
@Override
public String toString() {
return "WxCpDepart{" +
"id=" + id +
", name='" + name + '\'' +
", parentId=" + parentId +
", order=" + order +
"id=" + this.id +
", name='" + this.name + '\'' +
", parentId=" + this.parentId +
", order=" + this.order +
'}';
}
}

+ 23
- 19
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java View File

@@ -14,6 +14,10 @@ import java.util.List;
*/
public class WxCpMessage implements Serializable {

/**
*
*/
private static final long serialVersionUID = -2082278303476631708L;
private String toUser;
private String toParty;
private String toTag;
@@ -27,7 +31,7 @@ public class WxCpMessage implements Serializable {
private String musicUrl;
private String hqMusicUrl;
private String safe;
private List<WxArticle> articles = new ArrayList<WxArticle>();
private List<WxArticle> articles = new ArrayList<>();

/**
* 获得文本消息builder
@@ -72,7 +76,7 @@ public class WxCpMessage implements Serializable {
}

public String getToUser() {
return toUser;
return this.toUser;
}

public void setToUser(String toUser) {
@@ -80,7 +84,7 @@ public class WxCpMessage implements Serializable {
}

public String getToParty() {
return toParty;
return this.toParty;
}

public void setToParty(String toParty) {
@@ -88,7 +92,7 @@ public class WxCpMessage implements Serializable {
}

public String getToTag() {
return toTag;
return this.toTag;
}

public void setToTag(String toTag) {
@@ -96,7 +100,7 @@ public class WxCpMessage implements Serializable {
}

public String getAgentId() {
return agentId;
return this.agentId;
}

public void setAgentId(String agentId) {
@@ -104,7 +108,7 @@ public class WxCpMessage implements Serializable {
}

public String getMsgType() {
return msgType;
return this.msgType;
}

/**
@@ -125,7 +129,7 @@ public class WxCpMessage implements Serializable {
}

public String getSafe() {
return safe;
return this.safe;
}

public void setSafe(String safe) {
@@ -133,7 +137,7 @@ public class WxCpMessage implements Serializable {
}

public String getContent() {
return content;
return this.content;
}

public void setContent(String content) {
@@ -141,7 +145,7 @@ public class WxCpMessage implements Serializable {
}

public String getMediaId() {
return mediaId;
return this.mediaId;
}

public void setMediaId(String mediaId) {
@@ -149,7 +153,7 @@ public class WxCpMessage implements Serializable {
}

public String getThumbMediaId() {
return thumbMediaId;
return this.thumbMediaId;
}

public void setThumbMediaId(String thumbMediaId) {
@@ -157,7 +161,7 @@ public class WxCpMessage implements Serializable {
}

public String getTitle() {
return title;
return this.title;
}

public void setTitle(String title) {
@@ -165,7 +169,7 @@ public class WxCpMessage implements Serializable {
}

public String getDescription() {
return description;
return this.description;
}

public void setDescription(String description) {
@@ -173,7 +177,7 @@ public class WxCpMessage implements Serializable {
}

public String getMusicUrl() {
return musicUrl;
return this.musicUrl;
}

public void setMusicUrl(String musicUrl) {
@@ -181,7 +185,7 @@ public class WxCpMessage implements Serializable {
}

public String getHqMusicUrl() {
return hqMusicUrl;
return this.hqMusicUrl;
}

public void setHqMusicUrl(String hqMusicUrl) {
@@ -189,7 +193,7 @@ public class WxCpMessage implements Serializable {
}

public List<WxArticle> getArticles() {
return articles;
return this.articles;
}

public void setArticles(List<WxArticle> articles) {
@@ -208,7 +212,7 @@ public class WxCpMessage implements Serializable {
private String picUrl;

public String getTitle() {
return title;
return this.title;
}

public void setTitle(String title) {
@@ -216,7 +220,7 @@ public class WxCpMessage implements Serializable {
}

public String getDescription() {
return description;
return this.description;
}

public void setDescription(String description) {
@@ -224,7 +228,7 @@ public class WxCpMessage implements Serializable {
}

public String getUrl() {
return url;
return this.url;
}

public void setUrl(String url) {
@@ -232,7 +236,7 @@ public class WxCpMessage implements Serializable {
}

public String getPicUrl() {
return picUrl;
return this.picUrl;
}

public void setPicUrl(String picUrl) {


+ 7
- 2
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java View File

@@ -9,6 +9,11 @@ import java.io.Serializable;
*/
public class WxCpTag implements Serializable {

/**
*
*/
private static final long serialVersionUID = -7243320279646928402L;

private String id;

private String name;
@@ -28,7 +33,7 @@ public class WxCpTag implements Serializable {
}

public String getName() {
return name;
return this.name;
}

public void setName(String name) {
@@ -36,7 +41,7 @@ public class WxCpTag implements Serializable {
}

public String getId() {
return id;
return this.id;
}

public void setId(String id) {


+ 20
- 16
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java View File

@@ -13,7 +13,11 @@ import java.util.List;
*/
public class WxCpUser implements Serializable {

private final List<Attr> extAttrs = new ArrayList<Attr>();
/**
*
*/
private static final long serialVersionUID = -5696099236344075582L;
private final List<Attr> extAttrs = new ArrayList<>();
private String userId;
private String name;
private Integer[] departIds;
@@ -32,7 +36,7 @@ public class WxCpUser implements Serializable {
}

public String getUserId() {
return userId;
return this.userId;
}

public void setUserId(String userId) {
@@ -40,7 +44,7 @@ public class WxCpUser implements Serializable {
}

public String getName() {
return name;
return this.name;
}

public void setName(String name) {
@@ -48,7 +52,7 @@ public class WxCpUser implements Serializable {
}

public Integer[] getDepartIds() {
return departIds;
return this.departIds;
}

public void setDepartIds(Integer[] departIds) {
@@ -56,7 +60,7 @@ public class WxCpUser implements Serializable {
}

public String getGender() {
return gender;
return this.gender;
}

public void setGender(String gender) {
@@ -64,7 +68,7 @@ public class WxCpUser implements Serializable {
}

public String getPosition() {
return position;
return this.position;
}

public void setPosition(String position) {
@@ -72,7 +76,7 @@ public class WxCpUser implements Serializable {
}

public String getMobile() {
return mobile;
return this.mobile;
}

public void setMobile(String mobile) {
@@ -80,7 +84,7 @@ public class WxCpUser implements Serializable {
}

public String getTel() {
return tel;
return this.tel;
}

public void setTel(String tel) {
@@ -88,7 +92,7 @@ public class WxCpUser implements Serializable {
}

public String getEmail() {
return email;
return this.email;
}

public void setEmail(String email) {
@@ -96,7 +100,7 @@ public class WxCpUser implements Serializable {
}

public String getWeiXinId() {
return weiXinId;
return this.weiXinId;
}

public void setWeiXinId(String weiXinId) {
@@ -104,7 +108,7 @@ public class WxCpUser implements Serializable {
}

public String getAvatar() {
return avatar;
return this.avatar;
}

public void setAvatar(String avatar) {
@@ -112,7 +116,7 @@ public class WxCpUser implements Serializable {
}

public Integer getStatus() {
return status;
return this.status;
}

public void setStatus(Integer status) {
@@ -120,7 +124,7 @@ public class WxCpUser implements Serializable {
}

public Integer getEnable() {
return enable;
return this.enable;
}

public void setEnable(Integer enable) {
@@ -132,7 +136,7 @@ public class WxCpUser implements Serializable {
}

public List<Attr> getExtAttrs() {
return extAttrs;
return this.extAttrs;
}

public String toJson() {
@@ -150,7 +154,7 @@ public class WxCpUser implements Serializable {
}

public String getName() {
return name;
return this.name;
}

public void setName(String name) {
@@ -158,7 +162,7 @@ public class WxCpUser implements Serializable {
}

public String getValue() {
return value;
return this.value;
}

public void setValue(String value) {


+ 83
- 78
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java View File

@@ -32,6 +32,11 @@ public class WxCpXmlMessage implements Serializable {
// 以下都是微信推送过来的消息的xml的element所对应的属性
///////////////////////

/**
*
*/
private static final long serialVersionUID = -1042994982179476410L;

@XStreamAlias("AgentID")
private Integer agentId;

@@ -200,7 +205,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Integer getAgentId() {
return agentId;
return this.agentId;
}

public void setAgentId(Integer agentId) {
@@ -208,7 +213,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getToUserName() {
return toUserName;
return this.toUserName;
}

public void setToUserName(String toUserName) {
@@ -216,7 +221,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Long getCreateTime() {
return createTime;
return this.createTime;
}

public void setCreateTime(Long createTime) {
@@ -236,7 +241,7 @@ public class WxCpXmlMessage implements Serializable {
* </pre>
*/
public String getMsgType() {
return msgType;
return this.msgType;
}

/**
@@ -256,7 +261,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getContent() {
return content;
return this.content;
}

public void setContent(String content) {
@@ -264,7 +269,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Long getMsgId() {
return msgId;
return this.msgId;
}

public void setMsgId(Long msgId) {
@@ -272,7 +277,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getPicUrl() {
return picUrl;
return this.picUrl;
}

public void setPicUrl(String picUrl) {
@@ -280,7 +285,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getMediaId() {
return mediaId;
return this.mediaId;
}

public void setMediaId(String mediaId) {
@@ -288,7 +293,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getFormat() {
return format;
return this.format;
}

public void setFormat(String format) {
@@ -296,7 +301,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getThumbMediaId() {
return thumbMediaId;
return this.thumbMediaId;
}

public void setThumbMediaId(String thumbMediaId) {
@@ -304,7 +309,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Double getLocationX() {
return locationX;
return this.locationX;
}

public void setLocationX(Double locationX) {
@@ -312,7 +317,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Double getLocationY() {
return locationY;
return this.locationY;
}

public void setLocationY(Double locationY) {
@@ -320,7 +325,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Double getScale() {
return scale;
return this.scale;
}

public void setScale(Double scale) {
@@ -328,7 +333,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getLabel() {
return label;
return this.label;
}

public void setLabel(String label) {
@@ -336,7 +341,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getTitle() {
return title;
return this.title;
}

public void setTitle(String title) {
@@ -344,7 +349,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getDescription() {
return description;
return this.description;
}

public void setDescription(String description) {
@@ -352,7 +357,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getUrl() {
return url;
return this.url;
}

public void setUrl(String url) {
@@ -360,7 +365,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getEvent() {
return event;
return this.event;
}

public void setEvent(String event) {
@@ -368,7 +373,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getEventKey() {
return eventKey;
return this.eventKey;
}

public void setEventKey(String eventKey) {
@@ -376,7 +381,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getTicket() {
return ticket;
return this.ticket;
}

public void setTicket(String ticket) {
@@ -384,7 +389,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Double getLatitude() {
return latitude;
return this.latitude;
}

public void setLatitude(Double latitude) {
@@ -392,7 +397,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Double getLongitude() {
return longitude;
return this.longitude;
}

public void setLongitude(Double longitude) {
@@ -400,7 +405,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Double getPrecision() {
return precision;
return this.precision;
}

public void setPrecision(Double precision) {
@@ -408,7 +413,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getRecognition() {
return recognition;
return this.recognition;
}

public void setRecognition(String recognition) {
@@ -416,7 +421,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getFromUserName() {
return fromUserName;
return this.fromUserName;
}

public void setFromUserName(String fromUserName) {
@@ -424,7 +429,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getStatus() {
return status;
return this.status;
}

public void setStatus(String status) {
@@ -432,7 +437,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Integer getTotalCount() {
return totalCount;
return this.totalCount;
}

public void setTotalCount(Integer totalCount) {
@@ -440,7 +445,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Integer getFilterCount() {
return filterCount;
return this.filterCount;
}

public void setFilterCount(Integer filterCount) {
@@ -448,7 +453,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Integer getSentCount() {
return sentCount;
return this.sentCount;
}

public void setSentCount(Integer sentCount) {
@@ -456,7 +461,7 @@ public class WxCpXmlMessage implements Serializable {
}

public Integer getErrorCount() {
return errorCount;
return this.errorCount;
}

public void setErrorCount(Integer errorCount) {
@@ -464,7 +469,7 @@ public class WxCpXmlMessage implements Serializable {
}

public WxCpXmlMessage.ScanCodeInfo getScanCodeInfo() {
return scanCodeInfo;
return this.scanCodeInfo;
}

public void setScanCodeInfo(WxCpXmlMessage.ScanCodeInfo scanCodeInfo) {
@@ -472,7 +477,7 @@ public class WxCpXmlMessage implements Serializable {
}

public WxCpXmlMessage.SendPicsInfo getSendPicsInfo() {
return sendPicsInfo;
return this.sendPicsInfo;
}

public void setSendPicsInfo(WxCpXmlMessage.SendPicsInfo sendPicsInfo) {
@@ -480,7 +485,7 @@ public class WxCpXmlMessage implements Serializable {
}

public WxCpXmlMessage.SendLocationInfo getSendLocationInfo() {
return sendLocationInfo;
return this.sendLocationInfo;
}

public void setSendLocationInfo(WxCpXmlMessage.SendLocationInfo sendLocationInfo) {
@@ -490,39 +495,39 @@ public class WxCpXmlMessage implements Serializable {
@Override
public String toString() {
return "WxCpXmlMessage{" +
"agentId=" + agentId +
", toUserName='" + toUserName + '\'' +
", fromUserName='" + fromUserName + '\'' +
", createTime=" + createTime +
", msgType='" + msgType + '\'' +
", content='" + content + '\'' +
", msgId=" + msgId +
", picUrl='" + picUrl + '\'' +
", mediaId='" + mediaId + '\'' +
", format='" + format + '\'' +
", thumbMediaId='" + thumbMediaId + '\'' +
", locationX=" + locationX +
", locationY=" + locationY +
", scale=" + scale +
", label='" + label + '\'' +
", title='" + title + '\'' +
", description='" + description + '\'' +
", url='" + url + '\'' +
", event='" + event + '\'' +
", eventKey='" + eventKey + '\'' +
", ticket='" + ticket + '\'' +
", latitude=" + latitude +
", longitude=" + longitude +
", precision=" + precision +
", recognition='" + recognition + '\'' +
", status='" + status + '\'' +
", totalCount=" + totalCount +
", filterCount=" + filterCount +
", sentCount=" + sentCount +
", errorCount=" + errorCount +
", scanCodeInfo=" + scanCodeInfo +
", sendPicsInfo=" + sendPicsInfo +
", sendLocationInfo=" + sendLocationInfo +
"agentId=" + this.agentId +
", toUserName='" + this.toUserName + '\'' +
", fromUserName='" + this.fromUserName + '\'' +
", createTime=" + this.createTime +
", msgType='" + this.msgType + '\'' +
", content='" + this.content + '\'' +
", msgId=" + this.msgId +
", picUrl='" + this.picUrl + '\'' +
", mediaId='" + this.mediaId + '\'' +
", format='" + this.format + '\'' +
", thumbMediaId='" + this.thumbMediaId + '\'' +
", locationX=" + this.locationX +
", locationY=" + this.locationY +
", scale=" + this.scale +
", label='" + this.label + '\'' +
", title='" + this.title + '\'' +
", description='" + this.description + '\'' +
", url='" + this.url + '\'' +
", event='" + this.event + '\'' +
", eventKey='" + this.eventKey + '\'' +
", ticket='" + this.ticket + '\'' +
", latitude=" + this.latitude +
", longitude=" + this.longitude +
", precision=" + this.precision +
", recognition='" + this.recognition + '\'' +
", status='" + this.status + '\'' +
", totalCount=" + this.totalCount +
", filterCount=" + this.filterCount +
", sentCount=" + this.sentCount +
", errorCount=" + this.errorCount +
", scanCodeInfo=" + this.scanCodeInfo +
", sendPicsInfo=" + this.sendPicsInfo +
", sendLocationInfo=" + this.sendLocationInfo +
'}';
}

@@ -542,7 +547,7 @@ public class WxCpXmlMessage implements Serializable {
*/
public String getScanType() {

return scanType;
return this.scanType;
}

public void setScanType(String scanType) {
@@ -553,7 +558,7 @@ public class WxCpXmlMessage implements Serializable {
* 扫描结果,即二维码对应的字符串信息
*/
public String getScanResult() {
return scanResult;
return this.scanResult;
}

public void setScanResult(String scanResult) {
@@ -566,12 +571,12 @@ public class WxCpXmlMessage implements Serializable {
public static class SendPicsInfo {

@XStreamAlias("PicList")
protected final List<Item> picList = new ArrayList<Item>();
protected final List<Item> picList = new ArrayList<>();
@XStreamAlias("Count")
private Long count;

public Long getCount() {
return count;
return this.count;
}

public void setCount(Long count) {
@@ -579,7 +584,7 @@ public class WxCpXmlMessage implements Serializable {
}

public List<Item> getPicList() {
return picList;
return this.picList;
}

@XStreamAlias("item")
@@ -590,11 +595,11 @@ public class WxCpXmlMessage implements Serializable {
private String PicMd5Sum;

public String getPicMd5Sum() {
return PicMd5Sum;
return this.PicMd5Sum;
}

public void setPicMd5Sum(String picMd5Sum) {
PicMd5Sum = picMd5Sum;
this.PicMd5Sum = picMd5Sum;
}
}
}
@@ -623,7 +628,7 @@ public class WxCpXmlMessage implements Serializable {
private String poiname;

public String getLocationX() {
return locationX;
return this.locationX;
}

public void setLocationX(String locationX) {
@@ -631,7 +636,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getLocationY() {
return locationY;
return this.locationY;
}

public void setLocationY(String locationY) {
@@ -639,7 +644,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getScale() {
return scale;
return this.scale;
}

public void setScale(String scale) {
@@ -647,7 +652,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getLabel() {
return label;
return this.label;
}

public void setLabel(String label) {
@@ -655,7 +660,7 @@ public class WxCpXmlMessage implements Serializable {
}

public String getPoiname() {
return poiname;
return this.poiname;
}

public void setPoiname(String poiname) {


+ 1
- 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessage.java View File

@@ -17,7 +17,7 @@ public class WxCpXmlOutImageMessage extends WxCpXmlOutMessage {
}

public String getMediaId() {
return mediaId;
return this.mediaId;
}

public void setMediaId(String mediaId) {


+ 4
- 4
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java View File

@@ -62,7 +62,7 @@ public abstract class WxCpXmlOutMessage {
}

public String getToUserName() {
return toUserName;
return this.toUserName;
}

public void setToUserName(String toUserName) {
@@ -70,7 +70,7 @@ public abstract class WxCpXmlOutMessage {
}

public String getFromUserName() {
return fromUserName;
return this.fromUserName;
}

public void setFromUserName(String fromUserName) {
@@ -78,7 +78,7 @@ public abstract class WxCpXmlOutMessage {
}

public Long getCreateTime() {
return createTime;
return this.createTime;
}

public void setCreateTime(Long createTime) {
@@ -86,7 +86,7 @@ public abstract class WxCpXmlOutMessage {
}

public String getMsgType() {
return msgType;
return this.msgType;
}

public void setMsgType(String msgType) {


+ 11
- 11
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessage.java View File

@@ -12,7 +12,7 @@ import java.util.List;
public class WxCpXmlOutNewsMessage extends WxCpXmlOutMessage {

@XStreamAlias("Articles")
protected final List<Item> articles = new ArrayList<Item>();
protected final List<Item> articles = new ArrayList<>();
@XStreamAlias("ArticleCount")
protected int articleCount;

@@ -21,7 +21,7 @@ public class WxCpXmlOutNewsMessage extends WxCpXmlOutMessage {
}

public int getArticleCount() {
return articleCount;
return this.articleCount;
}

public void addArticle(Item item) {
@@ -30,7 +30,7 @@ public class WxCpXmlOutNewsMessage extends WxCpXmlOutMessage {
}

public List<Item> getArticles() {
return articles;
return this.articles;
}


@@ -54,35 +54,35 @@ public class WxCpXmlOutNewsMessage extends WxCpXmlOutMessage {
private String Url;

public String getTitle() {
return Title;
return this.Title;
}

public void setTitle(String title) {
Title = title;
this.Title = title;
}

public String getDescription() {
return Description;
return this.Description;
}

public void setDescription(String description) {
Description = description;
this.Description = description;
}

public String getPicUrl() {
return PicUrl;
return this.PicUrl;
}

public void setPicUrl(String picUrl) {
PicUrl = picUrl;
this.PicUrl = picUrl;
}

public String getUrl() {
return Url;
return this.Url;
}

public void setUrl(String url) {
Url = url;
this.Url = url;
}

}


+ 1
- 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessage.java View File

@@ -17,7 +17,7 @@ public class WxCpXmlOutTextMessage extends WxCpXmlOutMessage {
}

public String getContent() {
return content;
return this.content;
}

public void setContent(String content) {


+ 9
- 9
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessage.java View File

@@ -16,27 +16,27 @@ public class WxCpXmlOutVideoMessage extends WxCpXmlOutMessage {
}

public String getMediaId() {
return video.getMediaId();
return this.video.getMediaId();
}

public void setMediaId(String mediaId) {
video.setMediaId(mediaId);
this.video.setMediaId(mediaId);
}

public String getTitle() {
return video.getTitle();
return this.video.getTitle();
}

public void setTitle(String title) {
video.setTitle(title);
this.video.setTitle(title);
}

public String getDescription() {
return video.getDescription();
return this.video.getDescription();
}

public void setDescription(String description) {
video.setDescription(description);
this.video.setDescription(description);
}


@@ -56,7 +56,7 @@ public class WxCpXmlOutVideoMessage extends WxCpXmlOutMessage {
private String description;

public String getMediaId() {
return mediaId;
return this.mediaId;
}

public void setMediaId(String mediaId) {
@@ -64,7 +64,7 @@ public class WxCpXmlOutVideoMessage extends WxCpXmlOutMessage {
}

public String getTitle() {
return title;
return this.title;
}

public void setTitle(String title) {
@@ -72,7 +72,7 @@ public class WxCpXmlOutVideoMessage extends WxCpXmlOutMessage {
}

public String getDescription() {
return description;
return this.description;
}

public void setDescription(String description) {


+ 1
- 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessage.java View File

@@ -17,7 +17,7 @@ public class WxCpXmlOutVoiceMessage extends WxCpXmlOutMessage {
}

public String getMediaId() {
return mediaId;
return this.mediaId;
}

public void setMediaId(String mediaId) {


+ 1
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/FileBuilder.java View File

@@ -23,6 +23,7 @@ public final class FileBuilder extends BaseBuilder<FileBuilder> {
return this;
}

@Override
public WxCpMessage build() {
WxCpMessage m = super.build();
m.setMediaId(this.mediaId);


+ 1
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/ImageBuilder.java View File

@@ -23,6 +23,7 @@ public final class ImageBuilder extends BaseBuilder<ImageBuilder> {
return this;
}

@Override
public WxCpMessage build() {
WxCpMessage m = super.build();
m.setMediaId(this.mediaId);


+ 2
- 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/NewsBuilder.java View File

@@ -17,7 +17,7 @@ import java.util.List;
*/
public final class NewsBuilder extends BaseBuilder<NewsBuilder> {

private List<WxCpMessage.WxArticle> articles = new ArrayList<WxCpMessage.WxArticle>();
private List<WxCpMessage.WxArticle> articles = new ArrayList<>();

public NewsBuilder() {
this.msgType = WxConsts.CUSTOM_MSG_NEWS;
@@ -28,6 +28,7 @@ public final class NewsBuilder extends BaseBuilder<NewsBuilder> {
return this;
}

@Override
public WxCpMessage build() {
WxCpMessage m = super.build();
m.setArticles(this.articles);


+ 1
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TextBuilder.java View File

@@ -23,6 +23,7 @@ public final class TextBuilder extends BaseBuilder<TextBuilder> {
return this;
}

@Override
public WxCpMessage build() {
WxCpMessage m = super.build();
m.setContent(this.content);


+ 4
- 3
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/VideoBuilder.java View File

@@ -47,12 +47,13 @@ public final class VideoBuilder extends BaseBuilder<VideoBuilder> {
return this;
}

@Override
public WxCpMessage build() {
WxCpMessage m = super.build();
m.setMediaId(this.mediaId);
m.setTitle(title);
m.setDescription(description);
m.setThumbMediaId(thumbMediaId);
m.setTitle(this.title);
m.setDescription(this.description);
m.setThumbMediaId(this.thumbMediaId);
return m;
}
}

+ 1
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/VoiceBuilder.java View File

@@ -23,6 +23,7 @@ public final class VoiceBuilder extends BaseBuilder<VoiceBuilder> {
return this;
}

@Override
public WxCpMessage build() {
WxCpMessage m = super.build();
m.setMediaId(this.mediaId);


+ 1
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/ImageBuilder.java View File

@@ -16,6 +16,7 @@ public final class ImageBuilder extends BaseBuilder<ImageBuilder, WxCpXmlOutImag
return this;
}

@Override
public WxCpXmlOutImageMessage build() {
WxCpXmlOutImageMessage m = new WxCpXmlOutImageMessage();
setCommon(m);


+ 3
- 2
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java View File

@@ -13,16 +13,17 @@ import java.util.List;
*/
public final class NewsBuilder extends BaseBuilder<NewsBuilder, WxCpXmlOutNewsMessage> {

protected final List<Item> articles = new ArrayList<Item>();
protected final List<Item> articles = new ArrayList<>();

public NewsBuilder addArticle(Item item) {
this.articles.add(item);
return this;
}

@Override
public WxCpXmlOutNewsMessage build() {
WxCpXmlOutNewsMessage m = new WxCpXmlOutNewsMessage();
for (Item item : articles) {
for (Item item : this.articles) {
m.addArticle(item);
}
setCommon(m);


+ 1
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/TextBuilder.java View File

@@ -15,6 +15,7 @@ public final class TextBuilder extends BaseBuilder<TextBuilder, WxCpXmlOutTextMe
return this;
}

@Override
public WxCpXmlOutTextMessage build() {
WxCpXmlOutTextMessage m = new WxCpXmlOutTextMessage();
setCommon(m);


+ 4
- 3
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/VideoBuilder.java View File

@@ -28,12 +28,13 @@ public final class VideoBuilder extends BaseBuilder<VideoBuilder, WxCpXmlOutVide
return this;
}

@Override
public WxCpXmlOutVideoMessage build() {
WxCpXmlOutVideoMessage m = new WxCpXmlOutVideoMessage();
setCommon(m);
m.setTitle(title);
m.setDescription(description);
m.setMediaId(mediaId);
m.setTitle(this.title);
m.setDescription(this.description);
m.setMediaId(this.mediaId);
return m;
}



+ 2
- 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/VoiceBuilder.java View File

@@ -16,10 +16,11 @@ public final class VoiceBuilder extends BaseBuilder<VoiceBuilder, WxCpXmlOutVoic
return this;
}

@Override
public WxCpXmlOutVoiceMessage build() {
WxCpXmlOutVoiceMessage m = new WxCpXmlOutVoiceMessage();
setCommon(m);
m.setMediaId(mediaId);
m.setMediaId(this.mediaId);
return m;
}



+ 2
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java View File

@@ -19,6 +19,7 @@ import java.lang.reflect.Type;
*/
public class WxCpDepartGsonAdapter implements JsonSerializer<WxCpDepart>, JsonDeserializer<WxCpDepart> {

@Override
public JsonElement serialize(WxCpDepart group, Type typeOfSrc, JsonSerializationContext context) {
JsonObject json = new JsonObject();
if (group.getId() != null) {
@@ -36,6 +37,7 @@ public class WxCpDepartGsonAdapter implements JsonSerializer<WxCpDepart>, JsonDe
return json;
}

@Override
public WxCpDepart deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
WxCpDepart depart = new WxCpDepart();


+ 1
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpMessageGsonAdapter.java View File

@@ -20,6 +20,7 @@ import java.lang.reflect.Type;
*/
public class WxCpMessageGsonAdapter implements JsonSerializer<WxCpMessage> {

@Override
public JsonElement serialize(WxCpMessage message, Type typeOfSrc, JsonSerializationContext context) {
JsonObject messageJson = new JsonObject();
messageJson.addProperty("agentid", message.getAgentId());


+ 2
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java View File

@@ -19,6 +19,7 @@ import java.lang.reflect.Type;
*/
public class WxCpTagGsonAdapter implements JsonSerializer<WxCpTag>, JsonDeserializer<WxCpTag> {

@Override
public JsonElement serialize(WxCpTag tag, Type typeOfSrc, JsonSerializationContext context) {
JsonObject o = new JsonObject();
o.addProperty("tagid", tag.getId());
@@ -26,6 +27,7 @@ public class WxCpTagGsonAdapter implements JsonSerializer<WxCpTag>, JsonDeserial
return o;
}

@Override
public WxCpTag deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();


+ 1
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java View File

@@ -19,6 +19,7 @@ import java.lang.reflect.Type;
*/
public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSerializer<WxCpUser> {

@Override
public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject o = json.getAsJsonObject();


+ 1
- 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java View File

@@ -45,7 +45,7 @@ public class XStreamTransformer {
}

private static Map<Class, XStream> configXStreamInstance() {
Map<Class, XStream> map = new HashMap<Class, XStream>();
Map<Class, XStream> map = new HashMap<>();
map.put(WxCpXmlMessage.class, config_WxCpXmlMessage());
map.put(WxCpXmlOutNewsMessage.class, config_WxCpXmlOutNewsMessage());
map.put(WxCpXmlOutTextMessage.class, config_WxCpXmlOutTextMessage());


+ 22
- 15
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java View File

@@ -1,12 +1,14 @@
package me.chanjar.weixin.cp.api;

import java.io.IOException;
import java.io.InputStream;

import com.google.inject.Binder;
import com.google.inject.Module;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;

import java.io.InputStream;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;

public class ApiTestModule implements Module {

@@ -19,13 +21,18 @@ public class ApiTestModule implements Module {

@Override
public void configure(Binder binder) {
InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml");
WxXmlCpInMemoryConfigStorage config = fromXml(WxXmlCpInMemoryConfigStorage.class, is1);
WxCpServiceImpl wxService = new WxCpServiceImpl();
wxService.setWxCpConfigStorage(config);

binder.bind(WxCpServiceImpl.class).toInstance(wxService);
binder.bind(WxCpConfigStorage.class).toInstance(config);
try (InputStream is1 = ClassLoader
.getSystemResourceAsStream("test-config.xml")) {
WxXmlCpInMemoryConfigStorage config = fromXml(
WxXmlCpInMemoryConfigStorage.class, is1);
WxCpServiceImpl wxService = new WxCpServiceImpl();
wxService.setWxCpConfigStorage(config);

binder.bind(WxCpServiceImpl.class).toInstance(wxService);
binder.bind(WxCpConfigStorage.class).toInstance(config);
} catch (IOException e) {
e.printStackTrace();
}
}

@XStreamAlias("xml")
@@ -38,7 +45,7 @@ public class ApiTestModule implements Module {
protected String tagId;

public String getUserId() {
return userId;
return this.userId;
}

public void setUserId(String userId) {
@@ -46,7 +53,7 @@ public class ApiTestModule implements Module {
}

public String getDepartmentId() {
return departmentId;
return this.departmentId;
}

public void setDepartmentId(String departmentId) {
@@ -54,7 +61,7 @@ public class ApiTestModule implements Module {
}

public String getTagId() {
return tagId;
return this.tagId;
}

public void setTagId(String tagId) {
@@ -64,9 +71,9 @@ public class ApiTestModule implements Module {
@Override
public String toString() {
return super.toString() + " > WxXmlCpConfigStorage{" +
"userId='" + userId + '\'' +
", departmentId='" + departmentId + '\'' +
", tagId='" + tagId + '\'' +
"userId='" + this.userId + '\'' +
", departmentId='" + this.departmentId + '\'' +
", tagId='" + this.tagId + '\'' +
'}';
}
}


+ 7
- 5
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java View File

@@ -1,12 +1,14 @@
package me.chanjar.weixin.cp.api;

import com.google.inject.Inject;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.StringUtils;
import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;

import com.google.inject.Inject;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.StringUtils;

/**
* 基础API测试
*
@@ -20,9 +22,9 @@ public class WxCpBaseAPITest {
protected WxCpServiceImpl wxService;

public void testRefreshAccessToken() throws WxErrorException {
WxCpConfigStorage configStorage = wxService.wxCpConfigStorage;
WxCpConfigStorage configStorage = this.wxService.configStorage;
String before = configStorage.getAccessToken();
wxService.getAccessToken(false);
this.wxService.getAccessToken(false);

String after = configStorage.getAccessToken();



+ 10
- 7
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java View File

@@ -1,16 +1,17 @@
package me.chanjar.weixin.cp.api;

import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestExecutor;

@Test
public class WxCpBusyRetryTest {

@@ -19,7 +20,9 @@ public class WxCpBusyRetryTest {
WxCpService service = new WxCpServiceImpl() {

@Override
protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
protected synchronized <T, E> T executeInternal(
RequestExecutor<T, E> executor, String uri, E data)
throws WxErrorException {
WxError error = new WxError();
error.setErrorCode(-1);
throw new WxErrorException(error);


+ 19
- 16
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpDepartAPITest.java View File

@@ -1,13 +1,15 @@
package me.chanjar.weixin.cp.api;

import com.google.inject.Inject;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.cp.bean.WxCpDepart;
import java.util.List;

import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;

import java.util.List;
import com.google.inject.Inject;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.cp.bean.WxCpDepart;

/**
* 测试部门接口
@@ -24,22 +26,23 @@ public class WxCpDepartAPITest {
protected WxCpDepart depart;

public void testDepartCreate() throws WxErrorException {
WxCpDepart depart = new WxCpDepart();
depart.setName("子部门" + System.currentTimeMillis());
depart.setParentId(1);
depart.setOrder(1);
Integer departId = wxCpService.departCreate(depart);
WxCpDepart cpDepart = new WxCpDepart();
cpDepart.setName("子部门" + System.currentTimeMillis());
cpDepart.setParentId(1);
cpDepart.setOrder(1);
Integer departId = this.wxCpService.departCreate(cpDepart);
System.out.println(departId);
}

@Test(dependsOnMethods = "testDepartCreate")
public void testDepartGet() throws WxErrorException {
System.out.println("=================获取部门");
List<WxCpDepart> departList = wxCpService.departGet();
List<WxCpDepart> departList = this.wxCpService.departGet();
Assert.assertNotNull(departList);
Assert.assertTrue(departList.size() > 0);
for (WxCpDepart g : departList) {
depart = g;
System.out.println(depart.getId() + ":" + depart.getName());
this.depart = g;
System.out.println(this.depart.getId() + ":" + this.depart.getName());
Assert.assertNotNull(g.getName());
}
}
@@ -47,15 +50,15 @@ public class WxCpDepartAPITest {
@Test(dependsOnMethods = {"testDepartGet", "testDepartCreate"})
public void testDepartUpdate() throws WxErrorException {
System.out.println("=================更新部门");
depart.setName("子部门改名" + System.currentTimeMillis());
wxCpService.departUpdate(depart);
this.depart.setName("子部门改名" + System.currentTimeMillis());
this.wxCpService.departUpdate(this.depart);
}

@Test(dependsOnMethods = "testDepartUpdate")
public void testDepartDelete() throws WxErrorException {
System.out.println("=================删除部门");
System.out.println(depart.getId() + ":" + depart.getName());
wxCpService.departDelete(depart.getId());
System.out.println(this.depart.getId() + ":" + this.depart.getName());
this.wxCpService.departDelete(this.depart.getId());
}

}

+ 26
- 20
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMediaAPITest.java View File

@@ -1,18 +1,20 @@
package me.chanjar.weixin.cp.api;

import com.google.inject.Inject;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.exception.WxErrorException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import com.google.inject.Inject;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.exception.WxErrorException;

/**
* 测试多媒体文件上传下载
@@ -27,21 +29,25 @@ public class WxCpMediaAPITest {
@Inject
protected WxCpServiceImpl wxService;

private List<String> media_ids = new ArrayList<String>();
private List<String> media_ids = new ArrayList<>();

@Test(dataProvider = "uploadMedia")
public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException {
InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName);
WxMediaUploadResult res = wxService.mediaUpload(mediaType, fileType, inputStream);
Assert.assertNotNull(res.getType());
Assert.assertNotNull(res.getCreatedAt());
Assert.assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null);
try (InputStream inputStream = ClassLoader
.getSystemResourceAsStream(fileName);) {
WxMediaUploadResult res = this.wxService.mediaUpload(mediaType, fileType,
inputStream);
Assert.assertNotNull(res.getType());
Assert.assertNotNull(res.getCreatedAt());
Assert.assertTrue(
res.getMediaId() != null || res.getThumbMediaId() != null);

if (res.getMediaId() != null) {
media_ids.add(res.getMediaId());
}
if (res.getThumbMediaId() != null) {
media_ids.add(res.getThumbMediaId());
if (res.getMediaId() != null) {
this.media_ids.add(res.getMediaId());
}
if (res.getThumbMediaId() != null) {
this.media_ids.add(res.getThumbMediaId());
}
}
}

@@ -57,7 +63,7 @@ public class WxCpMediaAPITest {

@Test(dependsOnMethods = {"testUploadMedia"}, dataProvider = "downloadMedia")
public void testDownloadMedia(String media_id) throws WxErrorException {
wxService.mediaDownload(media_id);
this.wxService.mediaDownload(media_id);
}

@DataProvider


+ 8
- 6
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java View File

@@ -1,11 +1,13 @@
package me.chanjar.weixin.cp.api;

import org.testng.annotations.Guice;
import org.testng.annotations.Test;

import com.google.inject.Inject;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.cp.bean.WxCpMessage;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;

/***
* 测试发送消息
@@ -20,21 +22,21 @@ public class WxCpMessageAPITest {
protected WxCpServiceImpl wxService;

public void testSendCustomMessage() throws WxErrorException {
ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlCpInMemoryConfigStorage) wxService.wxCpConfigStorage;
ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlCpInMemoryConfigStorage) this.wxService.configStorage;
WxCpMessage message1 = new WxCpMessage();
message1.setAgentId(configStorage.getAgentId());
message1.setMsgType(WxConsts.CUSTOM_MSG_TEXT);
message1.setToUser(configStorage.getUserId());
message1.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");
wxService.messageSend(message1);
this.wxService.messageSend(message1);

WxCpMessage message2 = WxCpMessage
.TEXT()
.agentId(configStorage.getAgentId())
.toUser(configStorage.getUserId())
.content("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>")
.content("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>")
.build();
wxService.messageSend(message2);
this.wxService.messageSend(message2);

}



+ 1
- 1
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java View File

@@ -286,7 +286,7 @@ public class WxCpMessageRouterTest {
@Override
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService wxCpService,
WxSessionManager sessionManager) {
sb.append(this.echoStr).append(',');
this.sb.append(this.echoStr).append(',');
return null;
}



+ 12
- 12
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTagAPITest.java View File

@@ -23,44 +23,44 @@ public class WxCpTagAPITest {
protected String tagId;

public void testTagCreate() throws Exception {
tagId = wxService.tagCreate("测试标签4");
System.out.println(tagId);
this.tagId = this.wxService.tagCreate("测试标签4");
System.out.println(this.tagId);
}

@Test(dependsOnMethods = "testTagCreate")
public void testTagUpdate() throws Exception {
wxService.tagUpdate(tagId, "测试标签-改名");
this.wxService.tagUpdate(this.tagId, "测试标签-改名");
}

@Test(dependsOnMethods = "testTagUpdate")
public void testTagGet() throws Exception {
List<WxCpTag> tags = wxService.tagGet();
List<WxCpTag> tags = this.wxService.tagGet();
Assert.assertNotEquals(tags.size(), 0);
}

@Test(dependsOnMethods = "testTagGet")
public void testTagAddUsers() throws Exception {
List<String> userIds = new ArrayList<String>();
userIds.add(((ApiTestModule.WxXmlCpInMemoryConfigStorage) configStorage).getUserId());
wxService.tagAddUsers(tagId, userIds, null);
List<String> userIds = new ArrayList<>();
userIds.add(((ApiTestModule.WxXmlCpInMemoryConfigStorage) this.configStorage).getUserId());
this.wxService.tagAddUsers(this.tagId, userIds, null);
}

@Test(dependsOnMethods = "testTagAddUsers")
public void testTagGetUsers() throws Exception {
List<WxCpUser> users = wxService.tagGetUsers(tagId);
List<WxCpUser> users = this.wxService.tagGetUsers(this.tagId);
Assert.assertNotEquals(users.size(), 0);
}

@Test(dependsOnMethods = "testTagGetUsers")
public void testTagRemoveUsers() throws Exception {
List<String> userIds = new ArrayList<String>();
userIds.add(((ApiTestModule.WxXmlCpInMemoryConfigStorage) configStorage).getUserId());
wxService.tagRemoveUsers(tagId, userIds);
List<String> userIds = new ArrayList<>();
userIds.add(((ApiTestModule.WxXmlCpInMemoryConfigStorage) this.configStorage).getUserId());
this.wxService.tagRemoveUsers(this.tagId, userIds);
}

@Test(dependsOnMethods = "testTagRemoveUsers")
public void testTagDelete() throws Exception {
wxService.tagDelete(tagId);
this.wxService.tagDelete(this.tagId);
}

}

+ 5
- 5
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpUserAPITest.java View File

@@ -35,7 +35,7 @@ public class WxCpUserAPITest {
user.setPosition("woman");
user.setTel("3300393");
user.addExtAttr("爱好", "table");
wxCpService.userCreate(user);
this.wxCpService.userCreate(user);
}

@Test(dependsOnMethods = "testUserCreate")
@@ -44,23 +44,23 @@ public class WxCpUserAPITest {
user.setUserId("some.woman");
user.setName("Some Woman");
user.addExtAttr("爱好", "table2");
wxCpService.userUpdate(user);
this.wxCpService.userUpdate(user);
}

@Test(dependsOnMethods = "testUserUpdate")
public void testUserGet() throws WxErrorException {
WxCpUser user = wxCpService.userGet("some.woman");
WxCpUser user = this.wxCpService.userGet("some.woman");
Assert.assertNotNull(user);
}

@Test(dependsOnMethods = "testUserGet")
public void testDepartGetUsers() throws WxErrorException {
List<WxCpUser> users = wxCpService.departGetUsers(1, true, 0);
List<WxCpUser> users = this.wxCpService.departGetUsers(1, true, 0);
Assert.assertNotEquals(users.size(), 0);
}

@Test(dependsOnMethods = "testDepartGetUsers")
public void testUserDelete() throws WxErrorException {
wxCpService.userDelete("some.woman");
this.wxCpService.userDelete("some.woman");
}
}

+ 3
- 3
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxMenuAPITest.java View File

@@ -24,17 +24,17 @@ public class WxMenuAPITest {

@Test(dataProvider = "menu")
public void testCreateMenu(WxMenu wxMenu) throws WxErrorException {
wxService.menuCreate(wxMenu);
this.wxService.menuCreate(wxMenu);
}

@Test(dependsOnMethods = {"testCreateMenu"})
public void testGetMenu() throws WxErrorException {
Assert.assertNotNull(wxService.menuGet());
Assert.assertNotNull(this.wxService.menuGet());
}

@Test(dependsOnMethods = {"testGetMenu"})
public void testDeleteMenu() throws WxErrorException {
wxService.menuDelete();
this.wxService.menuDelete();
}

@DataProvider(name = "menu")


+ 2
- 2
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java View File

@@ -21,8 +21,8 @@ class WxCpDemoInMemoryConfigStorage extends WxCpInMemoryConfigStorage {

@Override
public String toString() {
return "SimpleWxConfigProvider [appidOrCorpid=" + corpId + ", corpSecret=" + corpSecret + ", accessToken=" + accessToken
+ ", expiresTime=" + expiresTime + ", token=" + token + ", aesKey=" + aesKey + "]";
return "SimpleWxConfigProvider [appidOrCorpid=" + this.corpId + ", corpSecret=" + this.corpSecret + ", accessToken=" + this.accessToken
+ ", expiresTime=" + this.expiresTime + ", token=" + this.token + ", aesKey=" + this.aesKey + "]";
}

}

+ 56
- 57
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java View File

@@ -1,16 +1,22 @@
package me.chanjar.weixin.cp.demo;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.cp.api.*;
import me.chanjar.weixin.cp.bean.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage;
import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;

import java.io.InputStream;
import java.util.Map;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.cp.api.WxCpConfigStorage;
import me.chanjar.weixin.cp.api.WxCpMessageHandler;
import me.chanjar.weixin.cp.api.WxCpMessageRouter;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.WxCpServiceImpl;
import me.chanjar.weixin.cp.bean.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage;
import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage;

public class WxCpDemoServer {

@@ -36,55 +42,48 @@ public class WxCpDemoServer {
server.join();
}

private static void initWeixin() {
InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml");
WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage.fromXml(is1);

wxCpConfigStorage = config;
wxCpService = new WxCpServiceImpl();
wxCpService.setWxCpConfigStorage(config);

WxCpMessageHandler handler = new WxCpMessageHandler() {
@Override
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context,
WxCpService wxCpService, WxSessionManager sessionManager) {
WxCpXmlOutTextMessage m = WxCpXmlOutMessage
.TEXT()
.content("测试加密消息")
.fromUser(wxMessage.getToUserName())
.toUser(wxMessage.getFromUserName())
.build();
return m;
}
};

WxCpMessageHandler oauth2handler = new WxCpMessageHandler() {
@Override
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context,
WxCpService wxCpService, WxSessionManager sessionManager) {
String href = "<a href=\"" + wxCpService.oauth2buildAuthorizationUrl(wxCpConfigStorage.getOauth2redirectUri(), null)
+ "\">测试oauth2</a>";
return WxCpXmlOutMessage
.TEXT()
.content(href)
.fromUser(wxMessage.getToUserName())
.toUser(wxMessage.getFromUserName()).build();
}
};

wxCpMessageRouter = new WxCpMessageRouter(wxCpService);
wxCpMessageRouter
.rule()
.async(false)
.content("哈哈") // 拦截内容为“哈哈”的消息
.handler(handler)
.end()
.rule()
.async(false)
.content("oauth")
.handler(oauth2handler)
.end()
;

private static void initWeixin() throws IOException {
try (InputStream is1 = ClassLoader
.getSystemResourceAsStream("test-config.xml")) {
WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage
.fromXml(is1);

wxCpConfigStorage = config;
wxCpService = new WxCpServiceImpl();
wxCpService.setWxCpConfigStorage(config);

WxCpMessageHandler handler = new WxCpMessageHandler() {
@Override
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage,
Map<String, Object> context, WxCpService wxService,
WxSessionManager sessionManager) {
WxCpXmlOutTextMessage m = WxCpXmlOutMessage.TEXT().content("测试加密消息")
.fromUser(wxMessage.getToUserName())
.toUser(wxMessage.getFromUserName()).build();
return m;
}
};

WxCpMessageHandler oauth2handler = new WxCpMessageHandler() {
@Override
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage,
Map<String, Object> context, WxCpService wxService,
WxSessionManager sessionManager) {
String href = "<a href=\""
+ wxService.oauth2buildAuthorizationUrl(
wxCpConfigStorage.getOauth2redirectUri(), null)
+ "\">测试oauth2</a>";
return WxCpXmlOutMessage.TEXT().content(href)
.fromUser(wxMessage.getToUserName())
.toUser(wxMessage.getFromUserName()).build();
}
};

wxCpMessageRouter = new WxCpMessageRouter(wxCpService);
wxCpMessageRouter.rule().async(false).content("哈哈") // 拦截内容为“哈哈”的消息
.handler(handler).end().rule().async(false).content("oauth")
.handler(oauth2handler).end();

}
}
}

+ 13
- 13
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java View File

@@ -1,5 +1,11 @@
package me.chanjar.weixin.cp.demo;

import java.io.IOException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import me.chanjar.weixin.common.util.StringUtils;
import me.chanjar.weixin.cp.api.WxCpConfigStorage;
import me.chanjar.weixin.cp.api.WxCpMessageRouter;
@@ -8,17 +14,11 @@ import me.chanjar.weixin.cp.bean.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage;
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* @author Daniel Qian
*/
public class WxCpEndpointServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected WxCpConfigStorage wxCpConfigStorage;
protected WxCpService wxCpService;
protected WxCpMessageRouter wxCpMessageRouter;
@@ -32,7 +32,7 @@ public class WxCpEndpointServlet extends HttpServlet {

@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
throws IOException {

response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
@@ -43,12 +43,12 @@ public class WxCpEndpointServlet extends HttpServlet {
String echostr = request.getParameter("echostr");

if (StringUtils.isNotBlank(echostr)) {
if (!wxCpService.checkSignature(msgSignature, timestamp, nonce, echostr)) {
if (!this.wxCpService.checkSignature(msgSignature, timestamp, nonce, echostr)) {
// 消息签名不正确,说明不是公众平台发过来的消息
response.getWriter().println("非法请求");
return;
}
WxCpCryptUtil cryptUtil = new WxCpCryptUtil(wxCpConfigStorage);
WxCpCryptUtil cryptUtil = new WxCpCryptUtil(this.wxCpConfigStorage);
String plainText = cryptUtil.decrypt(echostr);
// 说明是一个仅仅用来验证的请求,回显echostr
response.getWriter().println(plainText);
@@ -56,10 +56,10 @@ public class WxCpEndpointServlet extends HttpServlet {
}

WxCpXmlMessage inMessage = WxCpXmlMessage
.fromEncryptedXml(request.getInputStream(), wxCpConfigStorage, timestamp, nonce, msgSignature);
WxCpXmlOutMessage outMessage = wxCpMessageRouter.route(inMessage);
.fromEncryptedXml(request.getInputStream(), this.wxCpConfigStorage, timestamp, nonce, msgSignature);
WxCpXmlOutMessage outMessage = this.wxCpMessageRouter.route(inMessage);
if (outMessage != null) {
response.getWriter().write(outMessage.toEncryptedXml(wxCpConfigStorage));
response.getWriter().write(outMessage.toEncryptedXml(this.wxCpConfigStorage));
}

return;


+ 8
- 7
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java View File

@@ -1,16 +1,17 @@
package me.chanjar.weixin.cp.demo;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpService;
import java.io.IOException;
import java.util.Arrays;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpService;

public class WxCpOAuth2Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;

protected WxCpService wxCpService;

@@ -20,7 +21,7 @@ public class WxCpOAuth2Servlet extends HttpServlet {

@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
throws IOException {

response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
@@ -30,7 +31,7 @@ public class WxCpOAuth2Servlet extends HttpServlet {
response.getWriter().println("<h1>code</h1>");
response.getWriter().println(code);

String[] res = wxCpService.oauth2getUserInfo(code);
String[] res = this.wxCpService.oauth2getUserInfo(code);
response.getWriter().println("<h1>result</h1>");
response.getWriter().println(Arrays.toString(res));
} catch (WxErrorException e) {


+ 2
- 2
weixin-java-mp/pom.xml View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>2.1.0</version>
<version>2.1.2</version>
</parent>
<artifactId>weixin-java-mp</artifactId>
<name>WeiXin Java Tools - MP</name>
@@ -47,7 +47,7 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency><!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>


+ 2
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGroupService.java View File

@@ -8,8 +8,10 @@ import java.util.List;
/**
* 用户分组相关操作接口
* @author Binary Wang
* 分组接口属于老接口,不知道啥时候被替换成用户标签接口
*
*/
@Deprecated
public interface WxMpGroupService {




+ 18
- 4
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java View File

@@ -1,12 +1,18 @@
package me.chanjar.weixin.mp.api;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest;
import me.chanjar.weixin.mp.bean.kefu.result.*;

import java.io.File;
import java.util.Date;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.WxMpCustomMessage;
import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfMsgList;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionGetResult;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionList;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList;

/**
* 客服接口 ,
* 命名采用kefu拼音的原因是:
@@ -17,6 +23,14 @@ import java.util.Date;
*/
public interface WxMpKefuService {

/**
* <pre>
* 发送客服消息
* 详情请见: <a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140547&token=&lang=zh_CN">发送客服消息</a>
* </pre>
*/
boolean customMessageSend(WxMpCustomMessage message) throws WxErrorException;

//*******************客服管理接口***********************//

/**


+ 15
- 14
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java View File

@@ -1,24 +1,25 @@
package me.chanjar.weixin.mp.api;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import me.chanjar.weixin.common.api.WxErrorExceptionHandler;
import me.chanjar.weixin.common.api.WxMessageDuplicateChecker;
import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker;
import me.chanjar.weixin.common.session.InternalSession;
import me.chanjar.weixin.common.session.InternalSessionManager;
import me.chanjar.weixin.common.session.StandardSessionManager;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.common.util.LogExceptionHandler;
import me.chanjar.weixin.common.api.WxErrorExceptionHandler;
import me.chanjar.weixin.common.api.WxMessageDuplicateChecker;
import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* <pre>
@@ -155,7 +156,7 @@ public class WxMpMessageRouter {
}
WxMpXmlOutMessage res = null;
final List<Future> futures = new ArrayList<>();
final List<Future<?>> futures = new ArrayList<>();
for (final WxMpMessageRouterRule rule : matchRules) {
// 返回最后一个非异步的rule的执行结果
if(rule.isAsync()) {
@@ -179,7 +180,7 @@ public class WxMpMessageRouter {
this.executorService.submit(new Runnable() {
@Override
public void run() {
for (Future future : futures) {
for (Future<?> future : futures) {
try {
future.get();
WxMpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUserName());


+ 42
- 14
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java View File

@@ -3,18 +3,25 @@ package me.chanjar.weixin.mp.api;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.mp.bean.*;
import me.chanjar.weixin.mp.bean.result.*;

import java.text.SimpleDateFormat;
import me.chanjar.weixin.mp.bean.WxMpIndustry;
import me.chanjar.weixin.mp.bean.WxMpMassGroupMessage;
import me.chanjar.weixin.mp.bean.WxMpMassNews;
import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage;
import me.chanjar.weixin.mp.bean.WxMpMassPreviewMessage;
import me.chanjar.weixin.mp.bean.WxMpMassVideo;
import me.chanjar.weixin.mp.bean.WxMpSemanticQuery;
import me.chanjar.weixin.mp.bean.WxMpTemplateMessage;
import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult;
import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
import me.chanjar.weixin.mp.bean.result.WxMpUser;

/**
* 微信API的Service
*/
public interface WxMpService {

SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

/**
* <pre>
* 验证推送过来的消息的正确性
@@ -74,14 +81,6 @@ public interface WxMpService {
*/
WxJsapiSignature createJsapiSignature(String url) throws WxErrorException;

/**
* <pre>
* 发送客服消息
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
* </pre>
*/
void customMessageSend(WxMpCustomMessage message) throws WxErrorException;

/**
* <pre>
* 上传群发用的图文消息,上传后才能群发图文消息
@@ -152,6 +151,20 @@ public interface WxMpService {
*/
WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException;

/**
* <pre>
* 构造第三方使用网站应用授权登录的url
* 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN">网站应用微信登录开发指南</a>
* URL格式为:https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
* </pre>
*
* @param redirectURI 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode
* @param scope 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可
* @param state 非必填,用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验
* @return url
*/
String buildQrConnectUrl(String redirectURI, String scope, String state);

/**
* <pre>
* 构造oauth2授权的url连接
@@ -314,8 +327,16 @@ public interface WxMpService {
*
* @return WxMpGroupService
*/

WxMpGroupService getGroupService();

/**
* 返回用户标签相关接口的方法实现类,以方便调用个其各种接口
*
* @return WxMpUserTagService
*/
WxMpUserTagService getUserTagService();

/**
* 返回二维码相关接口的方法实现类,以方便调用个其各种接口
*
@@ -343,4 +364,11 @@ public interface WxMpService {
* @return WxMpDataCubeService
*/
WxMpDataCubeService getDataCubeService();

/**
* 返回用户黑名单管理相关接口的方法实现类,以方便调用其各种借口
*
* @return WxMpUserBlackListService
*/
WxMpUserBlacklistService getBlackListService();
}

+ 35
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserBlacklistService.java View File

@@ -0,0 +1,35 @@
package me.chanjar.weixin.mp.api;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.result.WxMpUserBlacklistGetResult;

import java.util.List;

/**
* @author miller
*/
public interface WxMpUserBlacklistService {
/**
* <pre>
* 获取公众号的黑名单列表
* 详情请见http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1471422259_pJMWA&token=&lang=zh_CN
* </pre>
*/
WxMpUserBlacklistGetResult getBlacklist(String nextOpenid) throws WxErrorException;

/**
* <pre>
* 拉黑用户
* 详情请见http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1471422259_pJMWA&token=&lang=zh_CN
* </pre>
*/
void pushToBlacklist(List<String> openidList) throws WxErrorException;

/**
* <pre>
* 取消拉黑用户
* 详情请见http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1471422259_pJMWA&token=&lang=zh_CN
* </pre>
*/
void pullFromBlacklist(List<String> openidList) throws WxErrorException;
}

+ 58
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java View File

@@ -0,0 +1,58 @@
package me.chanjar.weixin.mp.api;

import java.util.List;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.tag.WxUserTag;

/**
* 用户标签管理相关接口
* Created by Binary Wang on 2016/9/2.
* @author binarywang(https://github.com/binarywang)
*
*/
public interface WxMpUserTagService {

/**
* <pre>
* 创建标签
* 一个公众号,最多可以创建100个标签。
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140837&token=&lang=zh_CN">用户标签管理</a>
* 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/create?access_token=ACCESS_TOKEN
* </pre>
*
* @param name 标签名字(30个字符以内)
*/
WxUserTag tagCreate(String name) throws WxErrorException;

/**
* <pre>
* 获取公众号已创建的标签
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140837&token=&lang=zh_CN">用户标签管理</a>
* 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/get?access_token=ACCESS_TOKEN
* </pre>
*
*/
List<WxUserTag> tagGet() throws WxErrorException;

/**
* <pre>
* 编辑标签
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140837&token=&lang=zh_CN">用户标签管理</a>
* 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/update?access_token=ACCESS_TOKEN
* </pre>
*
*/
Boolean tagUpdate(Integer id, String name) throws WxErrorException;

/**
* <pre>
* 删除标签
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140837&token=&lang=zh_CN">用户标签管理</a>
* 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/delete?access_token=ACCESS_TOKEN
* </pre>
*
*/
Boolean tagDelete(Integer id) throws WxErrorException;

}

+ 6
- 11
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java View File

@@ -1,6 +1,5 @@
package me.chanjar.weixin.mp.api.impl;

import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import org.slf4j.Logger;
@@ -111,16 +110,12 @@ public class WxMpCardServiceImpl implements WxMpCardService {
signParam[optionalSignParam.length] = String.valueOf(timestamp);
signParam[optionalSignParam.length + 1] = nonceStr;
signParam[optionalSignParam.length + 2] = cardApiTicket;
try {
String signature = SHA1.gen(signParam);
WxCardApiSignature cardApiSignature = new WxCardApiSignature();
cardApiSignature.setTimestamp(timestamp);
cardApiSignature.setNonceStr(nonceStr);
cardApiSignature.setSignature(signature);
return cardApiSignature;
} catch (NoSuchAlgorithmException e) {
throw new WxErrorException(WxError.newBuilder().setErrorMsg(e.getMessage()).build());
}
String signature = SHA1.gen(signParam);
WxCardApiSignature cardApiSignature = new WxCardApiSignature();
cardApiSignature.setTimestamp(timestamp);
cardApiSignature.setNonceStr(nonceStr);
cardApiSignature.setSignature(signature);
return cardApiSignature;
}

/**


+ 63
- 93
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java View File

@@ -1,8 +1,15 @@
package me.chanjar.weixin.mp.api.impl;

import java.text.Format;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.time.FastDateFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpDataCubeService;
import me.chanjar.weixin.mp.api.WxMpService;
@@ -12,12 +19,6 @@ import me.chanjar.weixin.mp.bean.datacube.WxDataCubeInterfaceResult;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeMsgResult;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.List;

/**
* Created by Binary Wang on 2016/8/23.
@@ -27,6 +28,9 @@ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
protected final Logger log = LoggerFactory.getLogger(WxMpDataCubeServiceImpl.class);

private static final String API_URL_PREFIX = "https://api.weixin.qq.com/datacube";

private final Format dateFormat = FastDateFormat.getInstance("yyyy-MM-dd");

private WxMpService wxMpService;

public WxMpDataCubeServiceImpl(WxMpService wxMpService) {
@@ -37,104 +41,88 @@ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
public List<WxDataCubeUserSummary> getUserSummary(Date beginDate, Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getusersummary";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeUserSummary>>() {
}.getType());
return WxDataCubeUserSummary.fromJson(responseContent);
}

@Override
public List<WxDataCubeUserCumulate> getUserCumulate(Date beginDate, Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getusercumulate";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeUserCumulate>>() {
}.getType());
return WxDataCubeUserCumulate.fromJson(responseContent);
}

@Override
public List<WxDataCubeArticleResult> getArticleSummary(Date beginDate, Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getarticlesummary";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeArticleResult>>() {
}.getType());
return WxDataCubeArticleResult.fromJson(responseContent);
}

@Override
public List<WxDataCubeArticleTotal> getArticleTotal(Date beginDate, Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getarticletotal";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeArticleTotal>>() {
}.getType());
return WxDataCubeArticleTotal.fromJson(responseContent);
}

@Override
public List<WxDataCubeArticleResult> getUserRead(Date beginDate, Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getuserread";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeArticleResult>>() {
}.getType());
return WxDataCubeArticleResult.fromJson(responseContent);
}

@Override
public List<WxDataCubeArticleResult> getUserReadHour(Date beginDate, Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getuserreadhour";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeArticleResult>>() {
}.getType());
return WxDataCubeArticleResult.fromJson(responseContent);
}

@Override
public List<WxDataCubeArticleResult> getUserShare(Date beginDate, Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getusershare";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeArticleResult>>() {
}.getType());
return WxDataCubeArticleResult.fromJson(responseContent);
}

@Override
public List<WxDataCubeArticleResult> getUserShareHour(Date beginDate, Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getusersharehour";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeArticleResult>>() {
}.getType());
return WxDataCubeArticleResult.fromJson(responseContent);
}

@Override
@@ -142,13 +130,11 @@ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
throws WxErrorException {
String url = API_URL_PREFIX + "/getupstreammsg";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeMsgResult>>() {
}.getType());
return WxDataCubeMsgResult.fromJson(responseContent);
}

@Override
@@ -156,13 +142,11 @@ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getupstreammsghour";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeMsgResult>>() {
}.getType());
return WxDataCubeMsgResult.fromJson(responseContent);
}

@Override
@@ -170,13 +154,11 @@ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getupstreammsgweek";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeMsgResult>>() {
}.getType());
return WxDataCubeMsgResult.fromJson(responseContent);
}

@Override
@@ -184,13 +166,11 @@ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getupstreammsgmonth";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeMsgResult>>() {
}.getType());
return WxDataCubeMsgResult.fromJson(responseContent);
}

@Override
@@ -198,13 +178,11 @@ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getupstreammsgdist";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeMsgResult>>() {
}.getType());
return WxDataCubeMsgResult.fromJson(responseContent);
}

@Override
@@ -212,13 +190,11 @@ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getupstreammsgdistweek";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeMsgResult>>() {
}.getType());
return WxDataCubeMsgResult.fromJson(responseContent);
}

@Override
@@ -226,13 +202,11 @@ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getupstreammsgdistmonth";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeMsgResult>>() {
}.getType());
return WxDataCubeMsgResult.fromJson(responseContent);
}

@Override
@@ -240,13 +214,11 @@ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getinterfacesummary";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeInterfaceResult>>() {
}.getType());
return WxDataCubeInterfaceResult.fromJson(responseContent);
}

@Override
@@ -254,12 +226,10 @@ public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
Date endDate) throws WxErrorException {
String url = API_URL_PREFIX + "/getinterfacesummaryhour";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
param.addProperty("begin_date", this.dateFormat.format(beginDate));
param.addProperty("end_date", this.dateFormat.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}",url, param, responseContent);
return WxMpGsonBuilder.INSTANCE.create().fromJson(new JsonParser().parse(responseContent).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeInterfaceResult>>() {
}.getType());
return WxDataCubeInterfaceResult.fromJson(responseContent);
}
}

+ 3
- 3
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImpl.java View File

@@ -1,12 +1,9 @@
package me.chanjar.weixin.mp.api.impl;

import java.util.List;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
@@ -16,9 +13,12 @@ import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpGroup;
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

import java.util.List;

/**
* Created by Binary Wang on 2016/7/21.
*/
@Deprecated
public class WxMpGroupServiceImpl implements WxMpGroupService {
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/groups";
private WxMpService wxMpService;


+ 60
- 27
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java View File

@@ -3,15 +3,18 @@ package me.chanjar.weixin.mp.api.impl;
import java.io.File;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.JsonObject;

import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.mp.api.WxMpKefuService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpCustomMessage;
import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest;
import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfSessionRequest;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList;
@@ -27,6 +30,8 @@ import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList;
*
*/
public class WxMpKefuServiceImpl implements WxMpKefuService {
protected final Logger log = LoggerFactory
.getLogger(WxMpKefuServiceImpl.class);
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/customservice";
private WxMpService wxMpService;

@@ -34,19 +39,31 @@ public class WxMpKefuServiceImpl implements WxMpKefuService {
this.wxMpService = wxMpService;
}

@Override
public boolean customMessageSend(WxMpCustomMessage message)
throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
String responseContent = this.wxMpService.post(url, message.toJson());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, message.toJson(),
responseContent);
return true;
}

@Override
public WxMpKfList kfList() throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/customservice/getkflist";
String responseContent = this.wxMpService
.execute(new SimpleGetRequestExecutor(), url, null);
String url = API_URL_PREFIX + "/getkflist";
String responseContent = this.wxMpService.get(url, null);
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, null,
responseContent);
return WxMpKfList.fromJson(responseContent);
}

@Override
public WxMpKfOnlineList kfOnlineList() throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist";
String responseContent = this.wxMpService
.execute(new SimpleGetRequestExecutor(), url, null);
String url = API_URL_PREFIX + "/getonlinekflist";
String responseContent = this.wxMpService.get(url, null);
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, null,
responseContent);
return WxMpKfOnlineList.fromJson(responseContent);
}

@@ -54,8 +71,9 @@ public class WxMpKefuServiceImpl implements WxMpKefuService {
public boolean kfAccountAdd(WxMpKfAccountRequest request)
throws WxErrorException {
String url = API_URL_PREFIX + "/kfaccount/add";
this.wxMpService.execute(new SimplePostRequestExecutor(), url,
request.toJson());
String responseContent = this.wxMpService.post(url, request.toJson());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, request.toJson(),
responseContent);
return true;
}

@@ -63,16 +81,18 @@ public class WxMpKefuServiceImpl implements WxMpKefuService {
public boolean kfAccountUpdate(WxMpKfAccountRequest request)
throws WxErrorException {
String url = API_URL_PREFIX + "/kfaccount/update";
this.wxMpService.execute(new SimplePostRequestExecutor(), url,
request.toJson());
String responseContent = this.wxMpService.post(url, request.toJson());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, request.toJson(),
responseContent);
return true;
}

@Override
public boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErrorException {
String url = API_URL_PREFIX + "/kfaccount/inviteworker";
this.wxMpService.execute(new SimplePostRequestExecutor(), url,
request.toJson());
String responseContent = this.wxMpService.post(url, request.toJson());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, request.toJson(),
responseContent);
return true;
}

@@ -80,14 +100,20 @@ public class WxMpKefuServiceImpl implements WxMpKefuService {
public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile)
throws WxErrorException {
String url = API_URL_PREFIX + "/kfaccount/uploadheadimg?kf_account=" + kfAccount;
this.wxMpService.execute(new MediaUploadRequestExecutor(), url, imgFile);
WxMediaUploadResult responseContent = this.wxMpService
.execute(new MediaUploadRequestExecutor(), url, imgFile);
this.log.debug("\nurl:{}\nparams:{}&file:{}\nresponse:{}", url, kfAccount,
imgFile.getAbsolutePath(),
responseContent);
return true;
}

@Override
public boolean kfAccountDel(String kfAccount) throws WxErrorException {
String url = API_URL_PREFIX + "/kfaccount/del?kf_account=" + kfAccount;
this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null);
String responseContent = this.wxMpService.get(url, null);
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, null,
responseContent);
return true;
}

@@ -96,8 +122,9 @@ public class WxMpKefuServiceImpl implements WxMpKefuService {
throws WxErrorException {
WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid);
String url = API_URL_PREFIX + "/kfsession/create";
this.wxMpService.execute(new SimplePostRequestExecutor(), url,
request.toJson());
String responseContent = this.wxMpService.post(url, request.toJson());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, request.toJson(),
responseContent);
return true;
}

@@ -106,8 +133,9 @@ public class WxMpKefuServiceImpl implements WxMpKefuService {
throws WxErrorException {
WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid);
String url = API_URL_PREFIX + "/kfsession/close";
this.wxMpService.execute(new SimplePostRequestExecutor(), url,
request.toJson());
String responseContent = this.wxMpService.post(url, request.toJson());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, request.toJson(),
responseContent);
return true;
}

@@ -115,8 +143,9 @@ public class WxMpKefuServiceImpl implements WxMpKefuService {
public WxMpKfSessionGetResult kfSessionGet(String openid)
throws WxErrorException {
String url = API_URL_PREFIX + "/kfsession/getsession?openid=" + openid;
String responseContent = this.wxMpService
.execute(new SimpleGetRequestExecutor(), url, null);
String responseContent = this.wxMpService.get(url, null);
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, null,
responseContent);
return WxMpKfSessionGetResult.fromJson(responseContent);
}

@@ -124,8 +153,9 @@ public class WxMpKefuServiceImpl implements WxMpKefuService {
public WxMpKfSessionList kfSessionList(String kfAccount)
throws WxErrorException {
String url = API_URL_PREFIX + "/kfsession/getsessionlist?kf_account=" + kfAccount;
String responseContent = this.wxMpService
.execute(new SimpleGetRequestExecutor(), url, null);
String responseContent = this.wxMpService.get(url, null);
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, null,
responseContent);
return WxMpKfSessionList.fromJson(responseContent);
}

@@ -133,8 +163,9 @@ public class WxMpKefuServiceImpl implements WxMpKefuService {
public WxMpKfSessionWaitCaseList kfSessionGetWaitCase()
throws WxErrorException {
String url = API_URL_PREFIX + "/kfsession/getwaitcase";
String responseContent = this.wxMpService
.execute(new SimpleGetRequestExecutor(), url, null);
String responseContent = this.wxMpService.get(url, null);
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, null,
responseContent);
return WxMpKfSessionWaitCaseList.fromJson(responseContent);
}

@@ -156,7 +187,9 @@ public class WxMpKefuServiceImpl implements WxMpKefuService {
param.addProperty("msgid", msgId); //msgid 消息id顺序从小到大,从1开始
param.addProperty("number", number); //number 每次获取条数,最多10000条

String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, param.toString());
String responseContent = this.wxMpService.post(url, param.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, param.toString(),
responseContent);
return WxMpKfMsgList.fromJson(responseContent);
}



+ 111
- 59
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java View File

@@ -12,10 +12,38 @@ import me.chanjar.weixin.common.session.StandardSessionManager;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.common.util.RandomUtils;
import me.chanjar.weixin.common.util.crypto.SHA1;
import me.chanjar.weixin.common.util.http.*;
import me.chanjar.weixin.mp.api.*;
import me.chanjar.weixin.mp.bean.*;
import me.chanjar.weixin.mp.bean.result.*;
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.DefaultApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.common.util.http.URIUtil;
import me.chanjar.weixin.mp.api.WxMpCardService;
import me.chanjar.weixin.mp.api.WxMpConfigStorage;
import me.chanjar.weixin.mp.api.WxMpDataCubeService;
import me.chanjar.weixin.mp.api.WxMpGroupService;
import me.chanjar.weixin.mp.api.WxMpKefuService;
import me.chanjar.weixin.mp.api.WxMpMaterialService;
import me.chanjar.weixin.mp.api.WxMpMenuService;
import me.chanjar.weixin.mp.api.WxMpPayService;
import me.chanjar.weixin.mp.api.WxMpQrcodeService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxMpUserBlacklistService;
import me.chanjar.weixin.mp.api.WxMpUserService;
import me.chanjar.weixin.mp.api.WxMpUserTagService;
import me.chanjar.weixin.mp.bean.WxMpIndustry;
import me.chanjar.weixin.mp.bean.WxMpMassGroupMessage;
import me.chanjar.weixin.mp.bean.WxMpMassNews;
import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage;
import me.chanjar.weixin.mp.bean.WxMpMassPreviewMessage;
import me.chanjar.weixin.mp.bean.WxMpMassVideo;
import me.chanjar.weixin.mp.bean.WxMpSemanticQuery;
import me.chanjar.weixin.mp.bean.WxMpTemplateMessage;
import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult;
import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
@@ -28,7 +56,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;

public class WxMpServiceImpl implements WxMpService {

@@ -46,8 +73,8 @@ public class WxMpServiceImpl implements WxMpService {
*/
private final Object globalJsapiTicketRefreshLock = new Object();

private WxMpConfigStorage wxMpConfigStorage;
private WxMpConfigStorage configStorage;
private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this);

private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this);
@@ -58,6 +85,8 @@ public class WxMpServiceImpl implements WxMpService {

private WxMpGroupService groupService = new WxMpGroupServiceImpl(this);

private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this);

private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this);

private WxMpCardService cardService = new WxMpCardServiceImpl(this);
@@ -66,6 +95,8 @@ public class WxMpServiceImpl implements WxMpService {

private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this);

private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this);

private CloseableHttpClient httpClient;

private HttpHost httpProxy;
@@ -79,7 +110,8 @@ public class WxMpServiceImpl implements WxMpService {
@Override
public boolean checkSignature(String timestamp, String nonce, String signature) {
try {
return SHA1.gen(this.wxMpConfigStorage.getToken(), timestamp, nonce).equals(signature);
return SHA1.gen(this.configStorage.getToken(), timestamp, nonce)
.equals(signature);
} catch (Exception e) {
return false;
}
@@ -93,14 +125,14 @@ public class WxMpServiceImpl implements WxMpService {
@Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
if (forceRefresh) {
this.wxMpConfigStorage.expireAccessToken();
this.configStorage.expireAccessToken();
}
if (this.wxMpConfigStorage.isAccessTokenExpired()) {
if (this.configStorage.isAccessTokenExpired()) {
synchronized (this.globalAccessTokenRefreshLock) {
if (this.wxMpConfigStorage.isAccessTokenExpired()) {
if (this.configStorage.isAccessTokenExpired()) {
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
"&appid=" + this.wxMpConfigStorage.getAppId() +
"&secret=" + this.wxMpConfigStorage.getSecret();
"&appid=" + this.configStorage.getAppId() + "&secret="
+ this.configStorage.getSecret();
try {
HttpGet httpGet = new HttpGet(url);
if (this.httpProxy != null) {
@@ -114,7 +146,8 @@ public class WxMpServiceImpl implements WxMpService {
throw new WxErrorException(error);
}
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
this.wxMpConfigStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
this.configStorage.updateAccessToken(accessToken.getAccessToken(),
accessToken.getExpiresIn());
}finally {
httpGet.releaseConnection();
}
@@ -124,7 +157,7 @@ public class WxMpServiceImpl implements WxMpService {
}
}
}
return this.wxMpConfigStorage.getAccessToken();
return this.configStorage.getAccessToken();
}

@Override
@@ -135,23 +168,23 @@ public class WxMpServiceImpl implements WxMpService {
@Override
public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
if (forceRefresh) {
this.wxMpConfigStorage.expireJsapiTicket();
this.configStorage.expireJsapiTicket();
}

if (this.wxMpConfigStorage.isJsapiTicketExpired()) {
if (this.configStorage.isJsapiTicketExpired()) {
synchronized (this.globalJsapiTicketRefreshLock) {
if (this.wxMpConfigStorage.isJsapiTicketExpired()) {
if (this.configStorage.isJsapiTicketExpired()) {
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
this.wxMpConfigStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds);
this.configStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds);
}
}
}
return this.wxMpConfigStorage.getJsapiTicket();
return this.configStorage.getJsapiTicket();
}

@Override
@@ -159,29 +192,15 @@ public class WxMpServiceImpl implements WxMpService {
long timestamp = System.currentTimeMillis() / 1000;
String noncestr = RandomUtils.getRandomStr();
String jsapiTicket = getJsapiTicket(false);
try {
String signature = SHA1.genWithAmple(
"jsapi_ticket=" + jsapiTicket,
"noncestr=" + noncestr,
"timestamp=" + timestamp,
"url=" + url
);
WxJsapiSignature jsapiSignature = new WxJsapiSignature();
jsapiSignature.setAppid(this.wxMpConfigStorage.getAppId());
jsapiSignature.setTimestamp(timestamp);
jsapiSignature.setNoncestr(noncestr);
jsapiSignature.setUrl(url);
jsapiSignature.setSignature(signature);
return jsapiSignature;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}

@Override
public void customMessageSend(WxMpCustomMessage message) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
execute(new SimplePostRequestExecutor(), url, message.toJson());
String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket,
"noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url);
WxJsapiSignature jsapiSignature = new WxJsapiSignature();
jsapiSignature.setAppid(this.configStorage.getAppId());
jsapiSignature.setTimestamp(timestamp);
jsapiSignature.setNoncestr(noncestr);
jsapiSignature.setUrl(url);
jsapiSignature.setSignature(signature);
return jsapiSignature;
}

@Override
@@ -271,13 +290,30 @@ public class WxMpServiceImpl implements WxMpService {
public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) {
StringBuilder url = new StringBuilder();
url.append("https://open.weixin.qq.com/connect/oauth2/authorize?");
url.append("appid=").append(this.wxMpConfigStorage.getAppId());
url.append("appid=").append(this.configStorage.getAppId());
url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI));
url.append("&response_type=code");
url.append("&scope=").append(scope);
if (state != null) {
url.append("&state=").append(state);
}
url.append("#wechat_redirect");
return url.toString();
}

@Override
public String buildQrConnectUrl(String redirectURI, String scope,
String state) {
StringBuilder url = new StringBuilder();
url.append("https://open.weixin.qq.com/connect/qrconnect?");
url.append("appid=").append(this.configStorage.getAppId());
url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI));
url.append("&response_type=code");
url.append("&scope=").append(scope);
if (state != null) {
url.append("&state=").append(state);
}

url.append("#wechat_redirect");
return url.toString();
}
@@ -296,8 +332,8 @@ public class WxMpServiceImpl implements WxMpService {
public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException {
StringBuilder url = new StringBuilder();
url.append("https://api.weixin.qq.com/sns/oauth2/access_token?");
url.append("appid=").append(this.wxMpConfigStorage.getAppId());
url.append("&secret=").append(this.wxMpConfigStorage.getSecret());
url.append("appid=").append(this.configStorage.getAppId());
url.append("&secret=").append(this.configStorage.getSecret());
url.append("&code=").append(code);
url.append("&grant_type=authorization_code");

@@ -308,7 +344,7 @@ public class WxMpServiceImpl implements WxMpService {
public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException {
StringBuilder url = new StringBuilder();
url.append("https://api.weixin.qq.com/sns/oauth2/refresh_token?");
url.append("appid=").append(this.wxMpConfigStorage.getAppId());
url.append("appid=").append(this.configStorage.getAppId());
url.append("&grant_type=refresh_token");
url.append("&refresh_token=").append(refreshToken);

@@ -428,7 +464,7 @@ public class WxMpServiceImpl implements WxMpService {
*/
if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) {
// 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token
this.wxMpConfigStorage.expireAccessToken();
this.configStorage.expireAccessToken();
return execute(executor, uri, data);
}
if (error.getErrorCode() != 0) {
@@ -439,7 +475,7 @@ public class WxMpServiceImpl implements WxMpService {
throw new RuntimeException(e);
}
}
public HttpHost getHttpProxy() {
return this.httpProxy;
}
@@ -450,33 +486,39 @@ public class WxMpServiceImpl implements WxMpService {

@Override
public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) {
this.wxMpConfigStorage = wxConfigProvider;
this.configStorage = wxConfigProvider;
this.initHttpClient();
}

private void initHttpClient() {
ApacheHttpClientBuilder apacheHttpClientBuilder = this.wxMpConfigStorage.getApacheHttpClientBuilder();
ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage
.getApacheHttpClientBuilder();
if (null == apacheHttpClientBuilder) {
apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get();
}
apacheHttpClientBuilder.httpProxyHost(this.wxMpConfigStorage.getHttpProxyHost())
.httpProxyPort(this.wxMpConfigStorage.getHttpProxyPort())
.httpProxyUsername(this.wxMpConfigStorage.getHttpProxyUsername())
.httpProxyPassword(this.wxMpConfigStorage.getHttpProxyPassword());

if (this.wxMpConfigStorage.getSSLContext() != null){
apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost())
.httpProxyPort(this.configStorage.getHttpProxyPort())
.httpProxyUsername(this.configStorage.getHttpProxyUsername())
.httpProxyPassword(this.configStorage.getHttpProxyPassword());

if (this.configStorage.getSSLContext() != null) {
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
this.wxMpConfigStorage.getSSLContext(), new String[] { "TLSv1" }, null, new DefaultHostnameVerifier());
this.configStorage.getSSLContext(), new String[] { "TLSv1" }, null,
new DefaultHostnameVerifier());
apacheHttpClientBuilder.sslConnectionSocketFactory(sslsf);
}

if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort());
}

this.httpClient = apacheHttpClientBuilder.build();
}

@Override
public WxMpConfigStorage getWxMpConfigStorage() {
return this.wxMpConfigStorage;
return this.configStorage;
}

@Override
@@ -514,6 +556,11 @@ public class WxMpServiceImpl implements WxMpService {
return this.groupService;
}

@Override
public WxMpUserTagService getUserTagService() {
return this.tagService;
}

@Override
public WxMpQrcodeService getQrcodeService() {
return this.qrCodeService;
@@ -534,4 +581,9 @@ public class WxMpServiceImpl implements WxMpService {
return this.dataCubeService;
}

@Override
public WxMpUserBlacklistService getBlackListService() {
return this.blackListService;
}

}

+ 50
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java View File

@@ -0,0 +1,50 @@
package me.chanjar.weixin.mp.api.impl;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxMpUserBlacklistService;
import me.chanjar.weixin.mp.bean.result.WxMpUserBlacklistGetResult;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @author miller
*/
public class WxMpUserBlacklistServiceImpl implements WxMpUserBlacklistService {
private static final String API_BLACKLIST_PREFIX = "https://api.weixin.qq.com/cgi-bin/tags/members";
private WxMpService wxMpService;

public WxMpUserBlacklistServiceImpl(WxMpService wxMpService) {
this.wxMpService = wxMpService;
}

@Override
public WxMpUserBlacklistGetResult getBlacklist(String nextOpenid) throws WxErrorException {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("begin_openid", nextOpenid);
String url = API_BLACKLIST_PREFIX + "/getblacklist";
String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, jsonObject.toString());
return WxMpUserBlacklistGetResult.fromJson(responseContent);
}

@Override
public void pushToBlacklist(List<String> openidList) throws WxErrorException {
Map<String, Object> map = new HashMap<>();
map.put("openid_list", openidList);
String url = API_BLACKLIST_PREFIX + "/batchblacklist";
this.wxMpService.execute(new SimplePostRequestExecutor(), url, new Gson().toJson(map));
}

@Override
public void pullFromBlacklist(List<String> openidList) throws WxErrorException {
Map<String, Object> map = new HashMap<>();
map.put("openid_list", openidList);
String url = API_BLACKLIST_PREFIX + "/batchunblacklist";
this.wxMpService.execute(new SimplePostRequestExecutor(), url, new Gson().toJson(map));
}
}

+ 95
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java View File

@@ -0,0 +1,95 @@
package me.chanjar.weixin.mp.api.impl;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.JsonObject;

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.api.WxMpUserTagService;
import me.chanjar.weixin.mp.bean.tag.WxUserTag;

/**
*
* @author binarywang(https://github.com/binarywang)
* Created by Binary Wang on 2016/9/2.
*/
public class WxMpUserTagServiceImpl implements WxMpUserTagService {
protected final Logger log = LoggerFactory
.getLogger(WxMpDataCubeServiceImpl.class);
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/tags";

private WxMpService wxMpService;

public WxMpUserTagServiceImpl(WxMpService wxMpService) {
this.wxMpService = wxMpService;
}

@Override
public WxUserTag tagCreate(String name) throws WxErrorException {
String url = API_URL_PREFIX + "/create";
JsonObject json = new JsonObject();
JsonObject tagJson = new JsonObject();
tagJson.addProperty("name", name);
json.add("tag", tagJson);

String responseContent = this.wxMpService.post(url, json.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, json.toString(),
responseContent);
return WxUserTag.fromJson(responseContent);
}

@Override
public List<WxUserTag> tagGet() throws WxErrorException {
String url = API_URL_PREFIX + "/get";

String responseContent = this.wxMpService.get(url, null);
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, "[empty]",
responseContent);
return WxUserTag.listFromJson(responseContent);
}

@Override
public Boolean tagUpdate(Integer id, String name) throws WxErrorException {
String url = API_URL_PREFIX + "/update";

JsonObject json = new JsonObject();
JsonObject tagJson = new JsonObject();
tagJson.addProperty("id", id);
tagJson.addProperty("name", name);
json.add("tag", tagJson);

String responseContent = this.wxMpService.post(url, json.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, json.toString(), responseContent);
WxError wxError = WxError.fromJson(responseContent);
if (wxError.getErrorCode() == 0) {
return true;
}

throw new WxErrorException(wxError);
}

@Override
public Boolean tagDelete(Integer id) throws WxErrorException {
String url = API_URL_PREFIX + "/delete";

JsonObject json = new JsonObject();
JsonObject tagJson = new JsonObject();
tagJson.addProperty("id", id);
json.add("tag", tagJson);

String responseContent = this.wxMpService.post(url, json.toString());
this.log.debug("\nurl:{}\nparams:{}\nresponse:{}", url, json.toString(),
responseContent);
WxError wxError = WxError.fromJson(responseContent);
if (wxError.getErrorCode() == 0) {
return true;
}

throw new WxErrorException(wxError);
}
}

+ 0
- 3
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java View File

@@ -6,8 +6,6 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import me.chanjar.weixin.mp.util.json.WxLongTimeJsonSerializer;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@@ -49,7 +47,6 @@ public class WxMpXmlMessage implements Serializable {
private String fromUserName;

@XStreamAlias("CreateTime")
@JsonSerialize(using = WxLongTimeJsonSerializer.class)
private Long createTime;

@XStreamAlias("MsgType")


+ 15
- 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleResult.java View File

@@ -1,6 +1,12 @@
package me.chanjar.weixin.mp.bean.datacube;

import java.util.List;

import com.google.gson.JsonParser;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
* 图文分析数据接口返回结果对象
@@ -9,6 +15,8 @@ import com.google.gson.annotations.SerializedName;
*/
public class WxDataCubeArticleResult extends WxDataCubeBaseResult {

private static final JsonParser JSON_PARSER = new JsonParser();

/**
* ref_hour
* 数据的小时,包括从000到2300,分别代表的是[000,100)到[2300,2400),即每日的第1小时和最后1小时
@@ -203,5 +211,11 @@ public class WxDataCubeArticleResult extends WxDataCubeBaseResult {
public void setUserSource(Integer userSource) {
this.userSource = userSource;
}

public static List<WxDataCubeArticleResult> fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(
JSON_PARSER.parse(json).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeArticleResult>>() {
}.getType());
}
}

+ 14
- 2
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeArticleTotal.java View File

@@ -1,8 +1,12 @@
package me.chanjar.weixin.mp.bean.datacube;

import java.util.List;

import com.google.gson.JsonParser;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;

import java.util.List;
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
* 图文分析数据接口返回结果对象
@@ -11,6 +15,8 @@ import java.util.List;
*/
public class WxDataCubeArticleTotal extends WxDataCubeBaseResult {

private static final JsonParser JSON_PARSER = new JsonParser();

/**
* msgid
* 请注意:这里的msgid实际上是由msgid(图文消息id,这也就是群发接口调用后返回的msg_data_id)和index(消息次序索引)组成, 例如12003_3, 其中12003是msgid,即一次群发的消息的id; 3为index,假设该次群发的图文消息共5个文章(因为可能为多图文),3表示5个中的第3个
@@ -55,5 +61,11 @@ public class WxDataCubeArticleTotal extends WxDataCubeBaseResult {
public void setDetails(List<WxDataCubeArticleTotalDetail> details) {
this.details = details;
}

public static List<WxDataCubeArticleTotal> fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(
JSON_PARSER.parse(json).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeArticleTotal>>() {
}.getType());
}
}

+ 15
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeInterfaceResult.java View File

@@ -1,6 +1,12 @@
package me.chanjar.weixin.mp.bean.datacube;

import java.util.List;

import com.google.gson.JsonParser;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
* 接口分析数据接口返回结果对象
@@ -9,6 +15,8 @@ import com.google.gson.annotations.SerializedName;
*/
public class WxDataCubeInterfaceResult extends WxDataCubeBaseResult {

private static final JsonParser JSON_PARSER = new JsonParser();

/**
* ref_hour
* 数据的小时,包括从000到2300,分别代表的是[000,100)到[2300,2400),即每日的第1小时和最后1小时
@@ -83,5 +91,12 @@ public class WxDataCubeInterfaceResult extends WxDataCubeBaseResult {
public void setMaxTimeCost(Integer maxTimeCost) {
this.maxTimeCost = maxTimeCost;
}

public static List<WxDataCubeInterfaceResult> fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(
JSON_PARSER.parse(json).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeInterfaceResult>>() {
}.getType());
}
}

+ 15
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeMsgResult.java View File

@@ -1,6 +1,12 @@
package me.chanjar.weixin.mp.bean.datacube;

import java.util.List;

import com.google.gson.JsonParser;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
* 消息分析数据接口返回结果对象
@@ -9,6 +15,8 @@ import com.google.gson.annotations.SerializedName;
*/
public class WxDataCubeMsgResult extends WxDataCubeBaseResult {

private static final JsonParser JSON_PARSER = new JsonParser();

/**
* ref_hour
* 数据的小时,包括从000到2300,分别代表的是[000,100)到[2300,2400),即每日的第1小时和最后1小时
@@ -114,4 +122,11 @@ public class WxDataCubeMsgResult extends WxDataCubeBaseResult {
this.oriPageReadUser = oriPageReadUser;
}

public static List<WxDataCubeMsgResult> fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(
JSON_PARSER.parse(json).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeMsgResult>>() {
}.getType());
}

}

+ 18
- 3
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserCumulate.java View File

@@ -1,19 +1,27 @@
package me.chanjar.weixin.mp.bean.datacube;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import java.io.Serializable;
import java.util.Date;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
* <pre>
* 累计用户数据接口的返回JSON数据包
* http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
* 详情查看文档:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141082&token=&lang=zh_CN">用户分析数据接口</a>
* </pre>
*/
public class WxDataCubeUserCumulate implements Serializable {

private static final JsonParser JSON_PARSER = new JsonParser();

private static final long serialVersionUID = -3570981300225093657L;

private Date refDate;
@@ -40,4 +48,11 @@ public class WxDataCubeUserCumulate implements Serializable {
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

public static List<WxDataCubeUserCumulate> fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(
JSON_PARSER.parse(json).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeUserCumulate>>() {
}.getType());
}
}

+ 18
- 3
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/datacube/WxDataCubeUserSummary.java View File

@@ -1,20 +1,28 @@
package me.chanjar.weixin.mp.bean.datacube;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import java.io.Serializable;
import java.util.Date;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
* <pre>
* 用户增减数据接口的返回JSON数据包
* http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
* 详情查看文档:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141082&token=&lang=zh_CN">用户分析数据接口</a>
* </pre>
*/
public class WxDataCubeUserSummary implements Serializable {
private static final long serialVersionUID = -2336654489906694173L;

private static final JsonParser JSON_PARSER = new JsonParser();

private Date refDate;

private Integer userSource;
@@ -59,4 +67,11 @@ public class WxDataCubeUserSummary implements Serializable {
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

public static List<WxDataCubeUserSummary> fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(
JSON_PARSER.parse(json).getAsJsonObject().get("list"),
new TypeToken<List<WxDataCubeUserSummary>>() {
}.getType());
}
}

+ 2
- 4
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java View File

@@ -1,11 +1,10 @@
package me.chanjar.weixin.mp.bean.kefu.result;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.gson.annotations.SerializedName;
import me.chanjar.weixin.mp.util.json.WxLongTimeJsonSerializer;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.gson.annotations.SerializedName;

/**
* Created by Binary Wang on 2016/7/18.
*/
@@ -38,7 +37,6 @@ public class WxMpKfMsgRecord {
* time 操作时间,unix时间戳
*/
@SerializedName("time")
@JsonSerialize(using = WxLongTimeJsonSerializer.class)
private Long time;

@Override


+ 57
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserBlacklistGetResult.java View File

@@ -0,0 +1,57 @@
package me.chanjar.weixin.mp.bean.result;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

import java.util.ArrayList;
import java.util.List;

/**
* @author miller
*/
public class WxMpUserBlacklistGetResult {
protected int total = -1;
protected int count = -1;
protected List<String> openidList = new ArrayList<>();
protected String nextOpenid;

public static WxMpUserBlacklistGetResult fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUserBlacklistGetResult.class);
}

public int getTotal() {
return this.total;
}

public void setTotal(int total) {
this.total = total;
}

public int getCount() {
return this.count;
}

public void setCount(int count) {
this.count = count;
}

public List<String> getOpenidList() {
return this.openidList;
}

public void setOpenidList(List<String> openidList) {
this.openidList = openidList;
}

public String getNextOpenid() {
return this.nextOpenid;
}

public void setNextOpenid(String nextOpenid) {
this.nextOpenid = nextOpenid;
}

@Override
public String toString() {
return WxMpGsonBuilder.INSTANCE.create().toJson(this);
}
}

+ 78
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/tag/WxUserTag.java View File

@@ -0,0 +1,78 @@
package me.chanjar.weixin.mp.bean.tag;

import java.util.List;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
* 用户标签对象
* @author binarywang(https://github.com/binarywang)
* Created by Binary Wang on 2016/9/2.
*/
public class WxUserTag {
/**
* id 标签id,由微信分配
*/
private Integer id;

/**
* name 标签名,UTF8编码
*/
private String name;

/**
* count 此标签下粉丝数
*/
private Integer count;

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}

public Integer getCount() {
return this.count;
}

public void setCount(Integer count) {
this.count = count;
}

public Integer getId() {
return this.id;
}

public void setId(Integer id) {
this.id = id;
}

public static WxUserTag fromJson(String json) {
return WxMpGsonBuilder.create().fromJson(
new JsonParser().parse(json).getAsJsonObject().get("tag"),
WxUserTag.class);
}

public static List<WxUserTag> listFromJson(String json) {
return WxMpGsonBuilder.create().fromJson(
new JsonParser().parse(json).getAsJsonObject().get("tags"),
new TypeToken<List<WxUserTag>>(){}.getType());
}

public String toJson() {
return WxMpGsonBuilder.create().toJson(this);
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
}

+ 0
- 23
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxLongTimeJsonSerializer.java View File

@@ -1,23 +0,0 @@
package me.chanjar.weixin.mp.util.json;

import java.io.IOException;
import java.text.SimpleDateFormat;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

/**
* Created by Binary Wang on 2016/7/13.
*/
public class WxLongTimeJsonSerializer extends JsonSerializer<Long> {
private static SimpleDateFormat DF = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");

@Override
public void serialize(Long value, JsonGenerator gen,
SerializerProvider serializers)
throws IOException {
gen.writeString(DF.format(value * 1000));
}
}

+ 1
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java View File

@@ -45,6 +45,7 @@ public class WxMpGsonBuilder {
INSTANCE.registerTypeAdapter(WxMpMassPreviewMessage.class, new WxMpMassPreviewMessageGsonAdapter());
INSTANCE.registerTypeAdapter(WxMediaImgUploadResult.class, new WxMediaImgUploadResultGsonAdapter());
INSTANCE.registerTypeAdapter(WxMpIndustry.class, new WxMpIndustryGsonAdapter());
INSTANCE.registerTypeAdapter(WxMpUserBlacklistGetResult.class, new WxUserBlacklistGetResultGsonAdapter());
}

public static Gson create() {


+ 32
- 25
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpIndustryGsonAdapter.java View File

@@ -1,5 +1,7 @@
package me.chanjar.weixin.mp.util.json;

import java.lang.reflect.Type;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
@@ -7,38 +9,43 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.Industry;
import me.chanjar.weixin.mp.bean.WxMpIndustry;

import java.lang.reflect.Type;

/**
* @author miller
*/
public class WxMpIndustryGsonAdapter implements JsonSerializer<WxMpIndustry>, JsonDeserializer<WxMpIndustry> {
@Override
public JsonElement serialize(WxMpIndustry wxMpIndustry, Type type, JsonSerializationContext jsonSerializationContext) {
JsonObject json = new JsonObject();
json.addProperty("industry_id1", wxMpIndustry.getPrimaryIndustry().getId());
json.addProperty("industry_id2", wxMpIndustry.getSecondIndustry().getId());
return json;
}
public class WxMpIndustryGsonAdapter
implements JsonSerializer<WxMpIndustry>, JsonDeserializer<WxMpIndustry> {
@Override
public JsonElement serialize(WxMpIndustry wxMpIndustry, Type type,
JsonSerializationContext jsonSerializationContext) {
JsonObject json = new JsonObject();
json.addProperty("industry_id1", wxMpIndustry.getPrimaryIndustry().getId());
json.addProperty("industry_id2", wxMpIndustry.getSecondIndustry().getId());
return json;
}

@Override
public WxMpIndustry deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
WxMpIndustry wxMpIndustry = new WxMpIndustry();
JsonObject primaryIndustry = jsonElement.getAsJsonObject().get("primary_industry").getAsJsonObject();
wxMpIndustry.setPrimaryIndustry(convertFromJson(primaryIndustry));
JsonObject secondaryIndustry = jsonElement.getAsJsonObject().get("secondary_industry").getAsJsonObject();
wxMpIndustry.setSecondIndustry(convertFromJson(secondaryIndustry));
return wxMpIndustry;
}
@Override
public WxMpIndustry deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext)
throws JsonParseException {
WxMpIndustry wxMpIndustry = new WxMpIndustry();
JsonObject primaryIndustry = jsonElement.getAsJsonObject()
.get("primary_industry").getAsJsonObject();
wxMpIndustry.setPrimaryIndustry(convertFromJson(primaryIndustry));
JsonObject secondaryIndustry = jsonElement.getAsJsonObject()
.get("secondary_industry").getAsJsonObject();
wxMpIndustry.setSecondIndustry(convertFromJson(secondaryIndustry));
return wxMpIndustry;
}

private Industry convertFromJson(JsonObject json) {
Industry industry = new Industry();
industry.setFirstClass(GsonHelper.getString(json, "first_class"));
industry.setSecondClass(GsonHelper.getString(json, "second_class"));
return industry;
}
private static Industry convertFromJson(JsonObject json) {
Industry industry = new Industry();
industry.setFirstClass(GsonHelper.getString(json, "first_class"));
industry.setSecondClass(GsonHelper.getString(json, "second_class"));
return industry;
}
}

+ 14
- 7
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserCumulateGsonAdapter.java View File

@@ -8,13 +8,19 @@
*/
package me.chanjar.weixin.mp.util.json;

import com.google.gson.*;
import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate;

import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import org.apache.commons.lang3.time.FastDateFormat;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate;

/**
*
@@ -23,7 +29,8 @@ import java.text.SimpleDateFormat;
*/
public class WxMpUserCumulateGsonAdapter implements JsonDeserializer<WxDataCubeUserCumulate> {

private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
private static final FastDateFormat DATE_FORMAT = FastDateFormat
.getInstance("yyyy-MM-dd");

@Override
public WxDataCubeUserCumulate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
@@ -33,7 +40,7 @@ public class WxMpUserCumulateGsonAdapter implements JsonDeserializer<WxDataCubeU
try {
String refDate = GsonHelper.getString(summaryJsonObject, "ref_date");
if (refDate != null) {
cumulate.setRefDate(SIMPLE_DATE_FORMAT.parse(refDate));
cumulate.setRefDate(DATE_FORMAT.parse(refDate));
}
cumulate.setCumulateUser(GsonHelper.getInteger(summaryJsonObject, "cumulate_user"));
} catch (ParseException e) {


+ 14
- 7
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserSummaryGsonAdapter.java View File

@@ -8,20 +8,27 @@
*/
package me.chanjar.weixin.mp.util.json;

import com.google.gson.*;
import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;

import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import org.apache.commons.lang3.time.FastDateFormat;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;

/**
* @author Daniel Qian
*/
public class WxMpUserSummaryGsonAdapter implements JsonDeserializer<WxDataCubeUserSummary> {

private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
private static final FastDateFormat DATE_FORMAT = FastDateFormat
.getInstance("yyyy-MM-dd");

@Override
public WxDataCubeUserSummary deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
@@ -32,7 +39,7 @@ public class WxMpUserSummaryGsonAdapter implements JsonDeserializer<WxDataCubeUs
try {
String refDate = GsonHelper.getString(summaryJsonObject, "ref_date");
if (refDate != null) {
summary.setRefDate(SIMPLE_DATE_FORMAT.parse(refDate));
summary.setRefDate(DATE_FORMAT.parse(refDate));
}
summary.setUserSource(GsonHelper.getInteger(summaryJsonObject, "user_source"));
summary.setNewUser(GsonHelper.getInteger(summaryJsonObject, "new_user"));


+ 28
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserBlacklistGetResultGsonAdapter.java View File

@@ -0,0 +1,28 @@
package me.chanjar.weixin.mp.util.json;

import com.google.gson.*;
import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.result.WxMpUserBlacklistGetResult;

import java.lang.reflect.Type;

/**
* @author miller
*/
public class WxUserBlacklistGetResultGsonAdapter implements JsonDeserializer<WxMpUserBlacklistGetResult> {
@Override
public WxMpUserBlacklistGetResult deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject o = json.getAsJsonObject();
WxMpUserBlacklistGetResult wxMpUserBlacklistGetResult = new WxMpUserBlacklistGetResult();
wxMpUserBlacklistGetResult.setTotal(GsonHelper.getInteger(o, "total"));
wxMpUserBlacklistGetResult.setCount(GsonHelper.getInteger(o, "count"));
wxMpUserBlacklistGetResult.setNextOpenid(GsonHelper.getString(o, "next_openid"));
if (o.get("data") != null && !o.get("data").isJsonNull() && !o.get("data").getAsJsonObject().get("openid").isJsonNull()) {
JsonArray data = o.get("data").getAsJsonObject().get("openid").getAsJsonArray();
for (int i = 0; i < data.size(); i++) {
wxMpUserBlacklistGetResult.getOpenidList().add(GsonHelper.getAsString(data.get(i)));
}
}
return wxMpUserBlacklistGetResult;
}
}

+ 17
- 8
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XStreamTransformer.java View File

@@ -1,16 +1,25 @@
package me.chanjar.weixin.mp.util.xml;

import com.thoughtworks.xstream.XStream;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import me.chanjar.weixin.mp.bean.*;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import com.thoughtworks.xstream.XStream;

import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutImageMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMusicMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutNewsMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutTextMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutTransferCustomerServiceMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutVideoMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutVoiceMessage;

public class XStreamTransformer {

protected static final Map<Class, XStream> CLASS_2_XSTREAM_INSTANCE = configXStreamInstance();
protected static final Map<Class<?>, XStream> CLASS_2_XSTREAM_INSTANCE = configXStreamInstance();

/**
* xml -> pojo
@@ -32,7 +41,7 @@ public class XStreamTransformer {
* @param clz 类型
* @param xStream xml解析器
*/
public static void register(Class clz,XStream xStream){
public static void register(Class<?> clz, XStream xStream) {
CLASS_2_XSTREAM_INSTANCE.put(clz,xStream);
}

@@ -44,8 +53,8 @@ public class XStreamTransformer {
return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object);
}

private static Map<Class, XStream> configXStreamInstance() {
Map<Class, XStream> map = new HashMap<>();
private static Map<Class<?>, XStream> configXStreamInstance() {
Map<Class<?>, XStream> map = new HashMap<>();
map.put(WxMpXmlMessage.class, config_WxMpXmlMessage());
map.put(WxMpXmlOutMusicMessage.class, config_WxMpXmlOutMusicMessage());
map.put(WxMpXmlOutNewsMessage.class, config_WxMpXmlOutNewsMessage());


+ 15
- 5
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/ApiTestModule.java View File

@@ -31,6 +31,7 @@ public class ApiTestModule implements Module {
}
}

@SuppressWarnings("unchecked")
public static <T> T fromXml(Class<T> clazz, InputStream is) {
XStream xstream = XStreamInitializer.getInstance();
xstream.alias("xml", clazz);
@@ -42,15 +43,16 @@ public class ApiTestModule implements Module {
public static class WxXmlMpInMemoryConfigStorage
extends WxMpInMemoryConfigStorage {

private String openId;
private String openid;
private String kfAccount;
private String qrconnectRedirectUrl;

public String getOpenId() {
return this.openId;
public String getOpenid() {
return this.openid;
}

public void setOpenId(String openId) {
this.openId = openId;
public void setOpenid(String openid) {
this.openid = openid;
}

@Override
@@ -66,6 +68,14 @@ public class ApiTestModule implements Module {
this.kfAccount = kfAccount;
}

public String getQrconnectRedirectUrl() {
return this.qrconnectRedirectUrl;
}

public void setQrconnectRedirectUrl(String qrconnectRedirectUrl) {
this.qrconnectRedirectUrl = qrconnectRedirectUrl;
}

}

}

+ 11
- 8
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java View File

@@ -1,17 +1,18 @@
package me.chanjar.weixin.mp.api;

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.mp.api.impl.WxMpServiceImpl;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

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.mp.api.impl.WxMpServiceImpl;

@Test
public class WxMpBusyRetryTest {

@@ -20,7 +21,9 @@ public class WxMpBusyRetryTest {
WxMpService service = new WxMpServiceImpl() {

@Override
protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
protected synchronized <T, E> T executeInternal(
RequestExecutor<T, E> executor, String uri, E data)
throws WxErrorException {
WxError error = new WxError();
error.setErrorCode(-1);
throw new WxErrorException(error);


+ 0
- 44
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpCustomMessageAPITest.java View File

@@ -1,44 +0,0 @@
package me.chanjar.weixin.mp.api;

import com.google.inject.Inject;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.WxMpCustomMessage;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;

/***
* 测试发送客服消息
* @author chanjarster
*
*/
@Test(groups="customMessageAPI")
@Guice(modules = ApiTestModule.class)
public class WxMpCustomMessageAPITest {

@Inject
protected WxMpServiceImpl wxService;

public void testSendCustomMessage() throws WxErrorException {
ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage();
WxMpCustomMessage message = new WxMpCustomMessage();
message.setMsgType(WxConsts.CUSTOM_MSG_TEXT);
message.setToUser(configStorage.getOpenId());
message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");

this.wxService.customMessageSend(message);
}

public void testSendCustomMessageWithKfAccount() throws WxErrorException {
ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage();
WxMpCustomMessage message = new WxMpCustomMessage();
message.setMsgType(WxConsts.CUSTOM_MSG_TEXT);
message.setToUser(configStorage.getOpenId());
message.setKfAccount(configStorage.getKfAccount());
message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");

this.wxService.customMessageSend(message);
}

}

+ 6
- 6
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java View File

@@ -1,14 +1,14 @@
package me.chanjar.weixin.mp.api;

import com.google.inject.Inject;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.crypto.SHA1;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;

import java.security.NoSuchAlgorithmException;
import com.google.inject.Inject;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.crypto.SHA1;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;

/**
* 测试jsapi ticket接口
@@ -29,7 +29,7 @@ public class WxMpJsAPITest {
Assert.assertNotNull(jsapiTicket);
}

public void test() throws NoSuchAlgorithmException {
public void test() {
long timestamp = 1419835025l;
String url = "http://omstest.vmall.com:23568/thirdparty/wechat/vcode/gotoshare?quantity=1&batchName=MATE7";
String noncestr = "82693e11-b9bc-448e-892f-f5289f46cd0f";


+ 10
- 10
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java View File

@@ -41,7 +41,7 @@ public class WxMpMassMessageAPITest {
WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage();
massMessage.setMsgType(WxConsts.MASS_MSG_TEXT);
massMessage.setContent("测试群发消息\n欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");
massMessage.getToUsers().add(configProvider.getOpenId());
massMessage.getToUsers().add(configProvider.getOpenid());

WxMpMassSendResult massResult = this.wxService
.massOpenIdsMessageSend(massMessage);
@@ -58,7 +58,7 @@ public class WxMpMassMessageAPITest {
WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage();
massMessage.setMsgType(massMsgType);
massMessage.setMediaId(mediaId);
massMessage.getToUsers().add(configProvider.getOpenId());
massMessage.getToUsers().add(configProvider.getOpenid());

WxMpMassSendResult massResult = this.wxService
.massOpenIdsMessageSend(massMessage);
@@ -73,13 +73,13 @@ public class WxMpMassMessageAPITest {
massMessage.setContent("测试群发消息\n欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");
massMessage
.setGroupId(this.wxService.getGroupService().groupGet().get(0).getId());
WxMpMassSendResult massResult = this.wxService
.massGroupMessageSend(massMessage);
Assert.assertNotNull(massResult);
Assert.assertNotNull(massResult.getMsgId());
}
@Test(dataProvider="massMessages")
public void testMediaMassGroupMessageSend(String massMsgType, String mediaId)
throws WxErrorException {
@@ -94,7 +94,7 @@ public class WxMpMassMessageAPITest {
Assert.assertNotNull(massResult);
Assert.assertNotNull(massResult.getMsgId());
}
@DataProvider
public Object[][] massMessages() throws WxErrorException, IOException {
Object[][] messages = new Object[4][];
@@ -109,7 +109,7 @@ public class WxMpMassMessageAPITest {
.mediaUpload(WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, inputStream);
Assert.assertNotNull(uploadMediaRes);
Assert.assertNotNull(uploadMediaRes.getMediaId());
// 把视频变成可被群发的媒体
WxMpMassVideo video = new WxMpMassVideo();
video.setTitle("测试标题");
@@ -155,7 +155,7 @@ public class WxMpMassMessageAPITest {
.mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, inputStream);
Assert.assertNotNull(uploadMediaRes);
Assert.assertNotNull(uploadMediaRes.getMediaId());
// 上传图文消息
WxMpMassNews news = new WxMpMassNews();
WxMpMassNews.WxMpMassNewsArticle article1 = new WxMpMassNews.WxMpMassNewsArticle();
@@ -163,7 +163,7 @@ public class WxMpMassMessageAPITest {
article1.setContent("内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1内容1");
article1.setThumbMediaId(uploadMediaRes.getMediaId());
news.addArticle(article1);
WxMpMassNews.WxMpMassNewsArticle article2 = new WxMpMassNews.WxMpMassNewsArticle();
article2.setTitle("标题2");
article2.setContent("内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2内容2");
@@ -173,7 +173,7 @@ public class WxMpMassMessageAPITest {
article2.setContentSourceUrl("www.baidu.com");
article2.setDigest("摘要2");
news.addArticle(article2);
WxMpMassUploadResult massUploadResult = this.wxService
.massNewsUpload(news);
Assert.assertNotNull(massUploadResult);
@@ -183,5 +183,5 @@ public class WxMpMassMessageAPITest {

return messages;
}
}

+ 12
- 12
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImplTest.java View File

@@ -1,10 +1,10 @@
package me.chanjar.weixin.mp.api.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.time.FastDateFormat;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Guice;
@@ -28,39 +28,39 @@ import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;
*/
@Guice(modules = ApiTestModule.class)
public class WxMpDataCubeServiceImplTest {
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
"yyyy-MM-dd");
private FastDateFormat simpleDateFormat = FastDateFormat
.getInstance("yyyy-MM-dd");

@Inject
protected WxMpServiceImpl wxService;

@DataProvider
public Object[][] oneDay() throws ParseException {
return new Object[][] { { simpleDateFormat.parse("2016-08-22") } };
return new Object[][] { { this.simpleDateFormat.parse("2016-08-22") } };
}

@DataProvider
public Object[][] threeDays() throws ParseException {
return new Object[][] { { simpleDateFormat.parse("2016-08-20"),
simpleDateFormat.parse("2016-08-22") } };
return new Object[][] { { this.simpleDateFormat.parse("2016-08-20"),
this.simpleDateFormat.parse("2016-08-22") } };
}

@DataProvider
public Object[][] sevenDays() throws ParseException {
return new Object[][] { { simpleDateFormat.parse("2016-08-16"),
simpleDateFormat.parse("2016-08-22") } };
return new Object[][] { { this.simpleDateFormat.parse("2016-08-16"),
this.simpleDateFormat.parse("2016-08-22") } };
}

@DataProvider
public Object[][] fifteenDays() throws ParseException {
return new Object[][] { { simpleDateFormat.parse("2016-08-14"),
simpleDateFormat.parse("2016-08-27") } };
return new Object[][] { { this.simpleDateFormat.parse("2016-08-14"),
this.simpleDateFormat.parse("2016-08-27") } };
}

@DataProvider
public Object[][] thirtyDays() throws ParseException {
return new Object[][] { { simpleDateFormat.parse("2016-07-30"),
simpleDateFormat.parse("2016-08-27") } };
return new Object[][] { { this.simpleDateFormat.parse("2016-07-30"),
this.simpleDateFormat.parse("2016-08-27") } };
}

@Test(dataProvider = "sevenDays")


+ 15
- 3
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImplTest.java View File

@@ -12,9 +12,10 @@ import java.util.List;

/**
* 测试分组接口
*
*
* @author chanjarster
*/
@Deprecated
@Test(groups = "groupAPI")
@Guice(modules = ApiTestModule.class)
public class WxMpGroupServiceImplTest {
@@ -23,7 +24,7 @@ public class WxMpGroupServiceImplTest {
protected WxMpServiceImpl wxService;

protected WxMpGroup group;
public void testGroupCreate() throws WxErrorException {
WxMpGroup res = this.wxService.getGroupService().groupCreate("测试分组1");
Assert.assertEquals(res.getName(), "测试分组1");
@@ -39,11 +40,22 @@ public class WxMpGroupServiceImplTest {
Assert.assertNotNull(g.getName());
}
}
@Test(dependsOnMethods={"testGroupGet", "testGroupCreate"})
public void getGroupUpdate() throws WxErrorException {
this.group.setName("分组改名");
this.wxService.getGroupService().groupUpdate(this.group);
}

public void testGroupQueryUserGroup() throws WxErrorException {
ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage();
long groupid = this.wxService.getGroupService().userGetGroup(configStorage.getOpenid());
Assert.assertTrue(groupid != -1l);
}

public void testGroupMoveUser() throws WxErrorException {
ApiTestModule.WxXmlMpInMemoryConfigStorage configStorage = (ApiTestModule.WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage();
this.wxService.getGroupService().userUpdateGroup(configStorage.getOpenid(), this.wxService.getGroupService().groupGet().get(3).getId());
}

}

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

Loading…
Cancel
Save