Kaynağa Gözat

Merge branch 'develop'

master
Binary Wang 6 yıl önce
ebeveyn
işleme
cc8359b22c
100 değiştirilmiş dosya ile 2050 ekleme ve 435 silme
  1. +3
    -0
      .gitignore
  2. +3
    -3
      contribution.md
  3. +10
    -5
      pom.xml
  4. +0
    -8
      quality-checks/google_checks.xml
  5. +4
    -4
      readme.md
  6. +8
    -3
      weixin-java-common/pom.xml
  7. +9
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
  8. +1
    -1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java
  9. +2
    -4
      weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java
  10. +1
    -4
      weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenu.java
  11. +2
    -4
      weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java
  12. +2
    -4
      weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java
  13. +1
    -4
      weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java
  14. +1
    -2
      weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxCpErrorMsgEnum.java
  15. +5
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java
  16. +253
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java
  17. +1
    -2
      weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMpErrorMsgEnum.java
  18. +1
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java
  19. +9
    -7
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java
  20. +96
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java
  21. +12
    -15
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/PKCS7Encoder.java
  22. +19
    -16
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java
  23. +11
    -3
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java
  24. +3
    -3
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java
  25. +11
    -3
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
  26. +20
    -3
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java
  27. +11
    -2
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java
  28. +19
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ResponseHandler.java
  29. +10
    -1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java
  30. +8
    -0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java
  31. +13
    -18
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/URIUtil.java
  32. +6
    -5
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientSimpleGetRequestExecutor.java
  33. +5
    -4
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java
  34. +0
    -1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java
  35. +10
    -5
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java
  36. +5
    -1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java
  37. +34
    -34
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java
  38. +2
    -3
      weixin-java-common/src/test/java/me/chanjar/weixin/common/util/DataUtilsTest.java
  39. +78
    -0
      weixin-java-common/src/test/java/me/chanjar/weixin/common/util/XmlUtilsTest.java
  40. +8
    -6
      weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/WxCryptUtilTest.java
  41. +4
    -4
      weixin-java-cp/pom.xml
  42. +48
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java
  43. +13
    -8
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java
  44. +17
    -1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java
  45. +10
    -2
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
  46. +2
    -2
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java
  47. +3
    -3
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java
  48. +83
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
  49. +5
    -5
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java
  50. +8
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java
  51. +2
    -2
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java
  52. +26
    -9
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java
  53. +9
    -5
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java
  54. +4
    -4
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java
  55. +5
    -3
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgent.java
  56. +20
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpChat.java
  57. +4
    -4
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java
  58. +2
    -4
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpInviteResult.java
  59. +13
    -6
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java
  60. +2
    -4
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java
  61. +3
    -2
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java
  62. +2
    -4
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java
  63. +2
    -2
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java
  64. +4
    -4
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java
  65. +2
    -4
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java
  66. +16
    -15
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java
  67. +77
    -0
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java
  68. +27
    -15
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java
  69. +3
    -1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java
  70. +46
    -0
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java
  71. +6
    -6
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java
  72. +15
    -6
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java
  73. +2
    -2
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java
  74. +3
    -3
      weixin-java-miniapp/pom.xml
  75. +20
    -1
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaJsapiService.java
  76. +114
    -10
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java
  77. +24
    -0
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaRunService.java
  78. +43
    -0
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSecCheckService.java
  79. +22
    -17
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java
  80. +21
    -0
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaShareService.java
  81. +27
    -1
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImpl.java
  82. +56
    -20
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java
  83. +29
    -0
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaRunServiceImpl.java
  84. +48
    -0
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImpl.java
  85. +30
    -21
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java
  86. +23
    -0
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaShareServiceImpl.java
  87. +15
    -15
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaTemplateServiceImpl.java
  88. +1
    -3
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java
  89. +38
    -0
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaRunStepInfo.java
  90. +20
    -0
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaShareInfo.java
  91. +17
    -5
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxaCode.java
  92. +24
    -2
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java
  93. +36
    -4
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java
  94. +66
    -0
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeBytesRequestExecutor.java
  95. +27
    -19
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeRequestExecutor.java
  96. +24
    -4
      weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java
  97. +51
    -0
      weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImplTest.java
  98. +0
    -5
      weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java
  99. +46
    -0
      weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaShareServiceImplTest.java
  100. +43
    -0
      weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaRunStepInfoTest.java

+ 3
- 0
.gitignore Dosyayı Görüntüle

@@ -53,3 +53,6 @@ sonar-project.properties

!/.mvn/wrapper/maven-wrapper.jar
*.versionsBackup

# STS
.factorypath

+ 3
- 3
contribution.md Dosyayı Görüntüle

@@ -8,10 +8,10 @@
- (***暂停此种方式,请使用第一种***)另外一种贡献代码的方式就是加入SDK Developers开发组,前提是对自己的代码足够自信就可以申请加入,加入之后可以随时直接提交代码,但要注意对所做的修改或新增的代码进行单元测试,保证提交代码没有明显问题。

### PR方式贡献代码步骤
* 在 GitHub 上 `fork` 到自己的仓库,如 `my_user/weixin-java-tools`,然后 `clone` 到本地,并设置用户信息。
* 在 GitHub 上 `fork` 到自己的仓库,如 `my_user/WxJava`,然后 `clone` 到本地,并设置用户信息。

```bash
$ git clone git@github.com:my_user/weixin-java-tools.git
$ git clone git@github.com:my_user/WxJava.git
$ cd weixin-java-tools
$ git config user.name "yourname"
$ git config user.email "your email"
@@ -27,7 +27,7 @@ $ git push
* 定期使用项目仓库内容更新自己仓库内容。

```bash
$ git remote add upstream https://github.com/wechat-group/weixin-java-tools
$ git remote add upstream https://github.com/Wechat-Group/WxJava
$ git fetch upstream
$ git checkout develop
$ git rebase upstream/develop


+ 10
- 5
pom.xml Dosyayı Görüntüle

@@ -5,12 +5,12 @@
xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>3.2.0</version>
<artifactId>wx-java</artifactId>
<version>3.3.0</version>
<packaging>pom</packaging>
<name>Weixin Java Tools - Parent</name>
<name>WxJava - Weixin/Wechat Java SDK</name>
<description>微信开发Java SDK</description>
<url>https://github.com/wechat-group/weixin-java-tools</url>
<url>https://github.com/Wechat-Group/WxJava</url>

<licenses>
<license>
@@ -85,6 +85,11 @@
<email>007gzs@gmail.com</email>
<url>https://github.com/007gzs</url>
</developer>
<developer>
<name>Howard Liu</name>
<email>liuxinghao1988@gmail.com</email>
<url>https://github.com/howardliu-cn</url>
</developer>
</developers>

<scm>
@@ -166,7 +171,7 @@
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.9</version>
<version>1.4.10</version>
</dependency>
<!-- 由于guava较新的21.0版本需要jdk8,故而此处采用较低版本 -->
<dependency>


+ 0
- 8
quality-checks/google_checks.xml Dosyayı Görüntüle

@@ -140,14 +140,6 @@
</module>
<module name="OverloadMethodsDeclarationOrder"/>
<module name="VariableDeclarationUsageDistance"/>
<module name="CustomImportOrder">
<property name="customImportOrderRules"
value="SPECIAL_IMPORTS###STANDARD_JAVA_PACKAGE###THIRD_PARTY_PACKAGE###STATIC"/>
<property name="specialImportsRegExp" value="^javax\."/>
<property name="standardPackageRegExp" value="^java\."/>
<property name="sortImportsInGroupAlphabetically" value="true"/>
<property name="separateLineBetweenGroups" value="false"/>
</module>
<module name="MethodParamPad"/>
<module name="ParenPad"/>
<module name="OperatorWrap">


+ 4
- 4
readme.md Dosyayı Görüntüle

@@ -3,9 +3,9 @@
[![码云Gitee](https://gitee.com/binary/weixin-java-tools/badge/star.svg?theme=blue)](https://gitee.com/binary/weixin-java-tools)
[![Github](http://github-svg-buttons.herokuapp.com/star.svg?user=Wechat-Group&repo=WxJava&style=flat&background=1081C1)](https://github.com/Wechat-Group/WxJava)
[![GitHub release](https://img.shields.io/github/release/Wechat-Group/WxJava.svg)](https://github.com/Wechat-Group/WxJava/releases)
[![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/weixin-java-parent.svg)](http://mvnrepository.com/artifact/com.github.binarywang/weixin-java-parent)
[![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](http://mvnrepository.com/artifact/com.github.binarywang/wx-java)
[![Build Status](https://travis-ci.org/Wechat-Group/WxJava.svg?branch=develop)](https://travis-ci.org/Wechat-Group/WxJava)
[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=weixin-java-tools)
[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=WxJava-weixin-java-tools)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

---------------------------------
@@ -13,8 +13,7 @@
---------------------------------

### 重要信息

1. **2018-09-24 发布 [【3.2.0正式版】](https://github.com/Wechat-Group/WxJava/releases)**!
1. **2018-12-23 项目更名为WxJava,并发布 [【3.3.0正式版】](https://github.com/Wechat-Group/WxJava/releases)**!
1. 新手重要提示:本项目仅是一个SDK开发工具包,未提供Web实现,建议使用maven或gradle引用本项目即可使用本SDK提供的各种功能,详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码;另外微信开发新手请务必阅读[【开发文档 Wiki 首页】](https://github.com/Wechat-Group/WxJava/wiki)的常见问题部分,可以少走很多弯路,节省不少时间。

---------------------------------
@@ -152,3 +151,4 @@
1. [qsjia (QSJia)](http://github.com/qsjia)
1. [webcreazy (webcreazy)](http://github.com/webcreazy)
1. [cwivan (鱼丸Cwivan)](http://github.com/cwivan)
1. [howardliu-cn (看山)](https://github.com/howardliu-cn)

+ 8
- 3
weixin-java-common/pom.xml Dosyayı Görüntüle

@@ -6,12 +6,12 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>3.2.0</version>
<artifactId>wx-java</artifactId>
<version>3.3.0</version>
</parent>

<artifactId>weixin-java-common</artifactId>
<name>Weixin Java Tools - Common</name>
<name>WxJava - Common</name>
<description>微信开发Java SDK公共模块</description>

<dependencies>
@@ -114,6 +114,11 @@
<artifactId>assertj-guava</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>

<build>


+ 9
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java Dosyayı Görüntüle

@@ -250,6 +250,15 @@ public class WxConsts {
*/
public static final String CARD_PAY_ORDER = "card_pay_order";

/**
* 小程序审核事件:审核通过
*/
public static final String WEAPP_AUDIT_SUCCESS = "weapp_audit_success";

/**
* 小程序审核事件:审核不通过
*/
public static final String WEAPP_AUDIT_FAIL = "weapp_audit_fail";

}



+ 1
- 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java Dosyayı Görüntüle

@@ -76,7 +76,7 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec
}
}
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
});


+ 2
- 4
weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxCardApiSignature.java Dosyayı Görüntüle

@@ -2,10 +2,8 @@ package me.chanjar.weixin.common.bean;

import java.io.Serializable;

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

import lombok.Data;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;

/**
* 卡券Api签名.
@@ -37,6 +35,6 @@ public class WxCardApiSignature implements Serializable {

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return WxGsonBuilder.create().toJson(this);
}
}

+ 1
- 4
weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenu.java Dosyayı Görüntüle

@@ -7,9 +7,6 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

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

import lombok.Data;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;

@@ -49,7 +46,7 @@ public class WxMenu implements Serializable {

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return this.toJson();
}

}

+ 2
- 4
weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java Dosyayı Görüntüle

@@ -4,11 +4,9 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

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

import com.google.gson.annotations.SerializedName;
import lombok.Data;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;

/**
* menu button.
@@ -83,7 +81,7 @@ public class WxMenuButton implements Serializable {

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return WxGsonBuilder.create().toJson(this);
}

}

+ 2
- 4
weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java Dosyayı Görüntüle

@@ -2,11 +2,9 @@ package me.chanjar.weixin.common.bean.menu;

import java.io.Serializable;

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

import com.google.gson.annotations.SerializedName;
import lombok.Data;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;

/**
* menu rule.
@@ -31,6 +29,6 @@ public class WxMenuRule implements Serializable {

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return WxGsonBuilder.create().toJson(this);
}
}

+ 1
- 4
weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java Dosyayı Görüntüle

@@ -2,9 +2,6 @@ package me.chanjar.weixin.common.bean.result;

import java.io.Serializable;

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

import lombok.Data;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;

@@ -28,7 +25,7 @@ public class WxMediaUploadResult implements Serializable {

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return WxGsonBuilder.create().toJson(this);
}

}

+ 1
- 2
weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxCpErrorMsgEnum.java Dosyayı Görüntüle

@@ -794,8 +794,7 @@ public enum WxCpErrorMsgEnum {
* 通过错误代码查找其中文含义.
*/
public static String findMsgByCode(int code) {
WxCpErrorMsgEnum[] values = WxCpErrorMsgEnum.values();
for (WxCpErrorMsgEnum value : values) {
for (WxCpErrorMsgEnum value : WxCpErrorMsgEnum.values()) {
if (value.code == code) {
return value.msg;
}


+ 5
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java Dosyayı Görüntüle

@@ -64,6 +64,11 @@ public class WxError implements Serializable {
if (msg != null) {
wxError.setErrorMsg(msg);
}
} else if (type == WxType.MiniApp) {
final String msg = WxMaErrorMsgEnum.findMsgByCode(wxError.getErrorCode());
if (msg != null) {
wxError.setErrorMsg(msg);
}
}

return wxError;


+ 253
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java Dosyayı Görüntüle

@@ -0,0 +1,253 @@
package me.chanjar.weixin.common.error;

import lombok.Getter;

/**
* 微信小程序错误码
*
* @author <a href="https://github.com/biggates">biggates</a>
*/
@Getter
public enum WxMaErrorMsgEnum {
/**
* <pre>
* 获取 access_token 时 AppSecret 错误,
* 或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的小程序调用接口
* 对应操作:<code>sendCustomerMessage</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
* </pre>
*/
CODE_40001(40001, "access_token 无效或 AppSecret 错误"),
/**
* <pre>
* 不合法的凭证类型
* 对应操作:<code>sendCustomerMessage</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
* </pre>
*/
CODE_40002(40002, "不合法的凭证类型"),
/**
* <pre>
* touser不是正确的openid.
* 对应操作:<code>sendCustomerMessage</code>, <code>sendUniformMessage</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
* https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
* </pre>
*/
CODE_40003(40003, "openid 不正确"),
/**
* <pre>
* 无效媒体文件类型
* 对应操作:<code>uploadTempMedia</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/uploadTempMedia.html
* </pre>
*/
CODE_40004(40004, "无效媒体文件类型"),
/**
* <pre>
* 无效媒体文件 ID.
* 对应操作:<code>getTempMedia</code>
* 对应地址:
* GET https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/getTempMedia.html
* </pre>
*/
CODE_40007(40007, "无效媒体文件 ID"),
/**
* <pre>
* appid不正确,或者不符合绑定关系要求.
* 对应操作:<code>sendUniformMessage</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
* </pre>
*/
CODE_40013(40013, "appid不正确,或者不符合绑定关系要求"),
/**
* <pre>
* template_id 不正确.
* 对应操作:<code>sendUniformMessage</code>, <code>sendTemplateMessage</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
* https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html
* </pre>
*/
CODE_40037(40037, "template_id 不正确"),
/**
* <pre>
* form_id不正确,或者过期.
* 对应操作:<code>sendUniformMessage</code>, <code>sendTemplateMessage</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
* https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html
* </pre>
*/
CODE_41028(41028, "form_id 不正确,或者过期"),
/**
* <pre>
* code 或 template_id 不正确.
* 对应操作:<code>code2Session</code>, <code>sendUniformMessage</code>, <code>sendTemplateMessage</code>
* 对应地址:
* GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/code2Session.html
* https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
* https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html
* </pre>
*/
CODE_41029(41029, "请求的参数不正确"),
/**
* <pre>
* form_id 已被使用,或者所传page页面不存在,或者小程序没有发布
* 对应操作:<code>sendUniformMessage</coce>, <code>getWXACodeUnlimit</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
* POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
* https://developers.weixin.qq.com/miniprogram/dev/api/open-api/qr-code/getWXACodeUnlimit.html
* </pre>
*/
CODE_41030(41030, "请求的参数不正确"),
/**
* <pre>
* 调用分钟频率受限.
* 对应操作:<code>getWXACodeUnlimit</code>, <code>sendUniformMessage</code>, <code>sendTemplateMessage</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
* POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
* https://developers.weixin.qq.com/miniprogram/dev/api/open-api/qr-code/getWXACodeUnlimit.html
* </pre>
*/
CODE_45009(45009, "调用分钟频率受限"),
/**
* <pre>
* 频率限制,每个用户每分钟100次.
* 对应操作:<code>code2Session</code>
* 对应地址:
* GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/code2Session.html
* </pre>
*/
CODE_45011(45011, "频率限制,每个用户每分钟100次"),
/**
* <pre>
* 回复时间超过限制.
* 对应操作:<code>sendCustomerMessage</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
* </pre>
*/
CODE_45015(45015, "回复时间超过限制"),
/**
* <pre>
* 接口调用超过限额, 或生成码个数总和到达最大个数限制.
* 对应操作:<code>createWXAQRCode</code>, <code>sendTemplateMessage</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=ACCESS_TOKEN
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/qr-code/getWXACode.html
* https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html
* </pre>
*/
CODE_45029(45029, "接口调用超过限额"),
/**
* <pre>
* 客服接口下行条数超过上限.
* 对应操作:<code>sendCustomerMessage</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
* </pre>
*/
CODE_45047(45047, "客服接口下行条数超过上限"),
/**
* <pre>
* command字段取值不对
* 对应操作:<code>customerTyping</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/customerTyping.html
* </pre>
*/
CODE_45072(45072, "command字段取值不对"),
/**
* <pre>
* 下发输入状态,需要之前30秒内跟用户有过消息交互.
* 对应操作:<code>customerTyping</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/customerTyping.html
*/
CODE_45080(45080, "下发输入状态,需要之前30秒内跟用户有过消息交互"),
/**
* <pre>
* 已经在输入状态,不可重复下发.
* 对应操作:<code>customerTyping</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/customerTyping.html
* </pre>
*/
CODE_45081(45081, "已经在输入状态,不可重复下发"),
/**
* <pre>
* API 功能未授权,请确认小程序已获得该接口.
* 对应操作:<code>sendCustomerMessage</code>
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/sendCustomerMessage.html
* </pre>
*/
CODE_48001(48001, "API 功能未授权"),
/**
* <pre>
* 内容含有违法违规内容.
* 对应操作:<code>imgSecCheck</code>, <code>msgSecCheck</code>
* 对应地址:
* POST https://api.weixin.qq.com/wxa/img_sec_check?access_token=ACCESS_TOKEN
* POST https://api.weixin.qq.com/wxa/msg_sec_check?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/imgSecCheck.html
* https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/msgSecCheck.html
* </pre>
*/
CODE_87014(87014, "内容含有违法违规内容");

private int code;
private String msg;

WxMaErrorMsgEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}

/**
* <pre>
* 通过错误代码查找其中文含义.
*/
public static String findMsgByCode(int code) {
for (WxMaErrorMsgEnum value : WxMaErrorMsgEnum.values()) {
if (value.code == code) {
return value.msg;
}
}

return null;
}
}

+ 1
- 2
weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMpErrorMsgEnum.java Dosyayı Görüntüle

@@ -642,8 +642,7 @@ public enum WxMpErrorMsgEnum {
* 通过错误代码查找其中文含义.
*/
public static String findMsgByCode(int code) {
WxMpErrorMsgEnum[] values = WxMpErrorMsgEnum.values();
for (WxMpErrorMsgEnum value : values) {
for (WxMpErrorMsgEnum value : WxMpErrorMsgEnum.values()) {
if (value.code == code) {
return value.msg;
}


+ 1
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java Dosyayı Görüntüle

@@ -196,6 +196,7 @@ public class StandardSessionManager implements WxSessionManager, InternalSession
Thread.sleep(StandardSessionManager.this.backgroundProcessorDelay * 1000L);
backgroundProcess();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
StandardSessionManager.this.log.error("SessionManagerImpl.backgroundProcess error", e);
}
}


+ 9
- 7
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java Dosyayı Görüntüle

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

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Hex;

import lombok.extern.slf4j.Slf4j;

/**
* <pre>
@@ -27,9 +29,9 @@ public class SignUtils {
public static String createHmacSha256Sign(String message, String key) {
try {
Mac sha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256.init(secretKeySpec);
byte[] bytes = sha256.doFinal(message.getBytes());
byte[] bytes = sha256.doFinal(message.getBytes(StandardCharsets.UTF_8));
return Hex.encodeHexString(bytes).toUpperCase();
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
SignUtils.log.error(e.getMessage(), e);


+ 96
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java Dosyayı Görüntüle

@@ -0,0 +1,96 @@
package me.chanjar.weixin.common.util;

import java.io.StringReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.dom4j.tree.DefaultText;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
* <pre>
* XML转换工具类.
* Created by Binary Wang on 2018/11/4.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class XmlUtils {

public static Map<String, Object> xml2Map(String xmlString) {
Map<String, Object> map = new HashMap<>(16);
try {
SAXReader saxReader = new SAXReader();
Document doc = saxReader.read(new StringReader(xmlString));
Element root = doc.getRootElement();
List<Element> elements = root.elements();
for (Element element : elements) {
map.put(element.getName(), element2MapOrString(element));
}
} catch (DocumentException e) {
throw new RuntimeException(e);
}

return map;
}

private static Object element2MapOrString(Element element) {
Map<String, Object> result = Maps.newHashMap();

final List<Node> content = element.content();
if (content.size() <= 1) {
return element.getText();
}

final Set<String> names = names(content);
if (names.size() == 1) {
// 说明是个列表,各个子对象是相同的name
List<Object> list = Lists.newArrayList();
for (Node node : content) {
if (node instanceof DefaultText) {
continue;
}

if (node instanceof Element) {
list.add(element2MapOrString((Element) node));
}
}

result.put(names.iterator().next(), list);
} else {
for (Node node : content) {
if (node instanceof DefaultText) {
continue;
}

if (node instanceof Element) {
result.put(node.getName(), element2MapOrString((Element) node));
}
}
}

return result;
}

private static Set<String> names(List<Node> nodes) {
Set<String> names = Sets.newHashSet();
for (Node node : nodes) {
if (node instanceof DefaultText) {
continue;
}
names.add(node.getName());
}

return names;
}
}

+ 12
- 15
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/PKCS7Encoder.java Dosyayı Görüntüle

@@ -1,22 +1,22 @@
/**
/*
* 对公众平台发送给公众账号的消息加解密示例代码.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/

// ------------------------------------------------------------------------

package me.chanjar.weixin.common.util.crypto;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

/**
* 提供基于PKCS7算法的加解
* 提供基于PKCS7算法的加解.
*
* @author tencent
*/
public class PKCS7Encoder {

private static final Charset CHARSET = Charset.forName("utf-8");
private static final Charset CHARSET = StandardCharsets.UTF_8;
private static final int BLOCK_SIZE = 32;

/**
@@ -28,20 +28,17 @@ public class PKCS7Encoder {
public static byte[] encode(int count) {
// 计算需要填充的位数
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
if (amountToPad == 0) {
amountToPad = BLOCK_SIZE;
}
// 获得补位所用的字符
char padChr = chr(amountToPad);
String tmp = new String();
StringBuilder tmp = new StringBuilder();
for (int index = 0; index < amountToPad; index++) {
tmp += padChr;
tmp.append(padChr);
}
return tmp.getBytes(CHARSET);
return tmp.toString().getBytes(CHARSET);
}

/**
* 删除解密后明文的补位字符
* 删除解密后明文的补位字符.
*
* @param decrypted 解密后的明文
* @return 删除补位字符后的明文
@@ -55,12 +52,12 @@ public class PKCS7Encoder {
}

/**
* 将数字转化成ASCII码对应的字符,用于对明文进行补码
* 将数字转化成ASCII码对应的字符,用于对明文进行补码.
*
* @param a 需要转化的数字
* @return 转化得到的字符
*/
public static char chr(int a) {
private static char chr(int a) {
byte target = (byte) (a & 0xFF);
return (char) target;
}


+ 19
- 16
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java Dosyayı Görüntüle

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

import org.apache.commons.codec.binary.Base64;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Random;
import org.apache.commons.codec.binary.Base64;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;

/**
* <pre>
@@ -25,6 +25,8 @@ import java.util.Random;
* 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
* 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
* </pre>
*
* @author Tencent
*/
public class WxCryptUtil {

@@ -35,7 +37,9 @@ public class WxCryptUtil {
@Override
protected DocumentBuilder initialValue() {
try {
return DocumentBuilderFactory.newInstance().newDocumentBuilder();
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setExpandEntityReferences(false);
return factory.newDocumentBuilder();
} catch (ParserConfigurationException exc) {
throw new IllegalArgumentException(exc);
}
@@ -164,8 +168,7 @@ public class WxCryptUtil {
ByteGroup byteCollector = new ByteGroup();
byte[] randomStringBytes = randomStr.getBytes(CHARSET);
byte[] plainTextBytes = plainText.getBytes(CHARSET);
byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(
plainTextBytes.length);
byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length);
byte[] appIdBytes = this.appidOrCorpid.getBytes(CHARSET);

// randomStr + networkBytesOrder + text + appid
@@ -252,7 +255,7 @@ public class WxCryptUtil {
throw new RuntimeException(e);
}

String xmlContent, from_appid;
String xmlContent, fromAppid;
try {
// 去除补位字符
byte[] bytes = PKCS7Encoder.decode(original);
@@ -264,14 +267,14 @@ public class WxCryptUtil {

xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength),
CHARSET);
from_appid = new String(
fromAppid = new String(
Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET);
} catch (Exception e) {
throw new RuntimeException(e);
}

// appid不相同的情况
if (!from_appid.equals(this.appidOrCorpid)) {
if (!fromAppid.equals(this.appidOrCorpid)) {
throw new RuntimeException("AppID不正确");
}



+ 11
- 3
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java Dosyayı Görüntüle

@@ -1,13 +1,16 @@
package me.chanjar.weixin.common.util.http;

import java.io.File;
import java.io.IOException;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.apache.ApacheMediaDownloadRequestExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaDownloadRequestExecutor;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaDownloadRequestExecutor;

import java.io.File;

/**
* 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File
* 下载媒体文件请求执行器.
* 请求的参数是String, 返回的结果是File
* 视频文件不支持下载
*
* @author Daniel Qian
@@ -21,6 +24,11 @@ public abstract class BaseMediaDownloadRequestExecutor<H, P> implements RequestE
this.tmpDirFile = tmpDirFile;
}

@Override
public void execute(String uri, String data, ResponseHandler<File> handler) throws WxErrorException, IOException {
handler.handle(this.execute(uri, data));
}

public static RequestExecutor<File, String> create(RequestHttp requestHttp, File tmpDirFile) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:


+ 3
- 3
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java Dosyayı Görüntüle

@@ -58,7 +58,7 @@ public class HttpResponseProxy {
private String getFileName(CloseableHttpResponse response) throws WxErrorException {
Header[] contentDispositionHeader = response.getHeaders("Content-disposition");
if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build());
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build());
}

return this.extractFileNameFromContentString(contentDispositionHeader[0].getValue());
@@ -76,7 +76,7 @@ public class HttpResponseProxy {

private String extractFileNameFromContentString(String content) throws WxErrorException {
if (content == null || content.length() == 0) {
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build());
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build());
}

Matcher m = PATTERN.matcher(content);
@@ -84,7 +84,7 @@ public class HttpResponseProxy {
return m.group(1);
}

throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build());
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build());
}

}

+ 11
- 3
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java Dosyayı Görüntüle

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

import java.io.File;
import java.io.IOException;

import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.apache.ApacheMediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaUploadRequestExecutor;

import java.io.File;

/**
* 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String
* 上传媒体文件请求执行器.
* 请求的参数是File, 返回的结果是String
*
* @author Daniel Qian
*/
@@ -19,6 +22,11 @@ public abstract class MediaUploadRequestExecutor<H, P> implements RequestExecuto
this.requestHttp = requestHttp;
}

@Override
public void execute(String uri, File data, ResponseHandler<WxMediaUploadResult> handler) throws WxErrorException, IOException {
handler.handle(this.execute(uri, data));
}

public static RequestExecutor<WxMediaUploadResult, File> create(RequestHttp requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:


+ 20
- 3
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java Dosyayı Görüntüle

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

import me.chanjar.weixin.common.error.WxErrorException;

import java.io.IOException;

import me.chanjar.weixin.common.error.WxErrorException;

/**
* http请求执行器
* http请求执行器.
*
* @param <T> 返回值类型
* @param <E> 请求参数类型
@@ -14,8 +14,25 @@ import java.io.IOException;
public interface RequestExecutor<T, E> {

/**
* 执行http请求.
*
* @param uri uri
* @param data 数据
* @return 响应结果
* @throws WxErrorException 自定义异常
* @throws IOException io异常
*/
T execute(String uri, E data) throws WxErrorException, IOException;


/**
* 执行http请求.
*
* @param uri uri
* @param data 数据
* @param handler http响应处理器
* @throws WxErrorException 自定义异常
* @throws IOException io异常
*/
void execute(String uri, E data, ResponseHandler<T> handler) throws WxErrorException, IOException;
}

+ 11
- 2
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java Dosyayı Görüntüle

@@ -2,21 +2,30 @@ package me.chanjar.weixin.common.util.http;

/**
* Created by ecoolper on 2017/4/22.
*
* @author ecoolper
*/
public interface RequestHttp<H, P> {

/**
* 返回httpClient
* 返回httpClient.
*
* @return 返回httpClient
*/
H getRequestHttpClient();

/**
* 返回httpProxy
* 返回httpProxy.
*
* @return 返回httpProxy
*/
P getRequestHttpProxy();

/**
* 返回HttpType.
*
* @return HttpType
*/
HttpType getRequestType();

}

+ 19
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ResponseHandler.java Dosyayı Görüntüle

@@ -0,0 +1,19 @@
package me.chanjar.weixin.common.util.http;

/**
* <pre>
* http请求响应回调处理接口.
* Created by Binary Wang on 2018/12/8.
* </pre>
*
* @param <T> 返回值类型
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public interface ResponseHandler<T> {
/**
* 响应结果处理.
*
* @param t 要处理的对象
*/
void handle(T t);
}

+ 10
- 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java Dosyayı Görüntüle

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

import java.io.IOException;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientSimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimpleGetRequestExecutor;

/**
* 简单的GET请求执行器,请求的参数是String, 返回的结果也是String
* 简单的GET请求执行器.
* 请求的参数是String, 返回的结果也是String
*
* @author Daniel Qian
*/
@@ -16,6 +20,11 @@ public abstract class SimpleGetRequestExecutor<H, P> implements RequestExecutor<
this.requestHttp = requestHttp;
}

@Override
public void execute(String uri, String data, ResponseHandler<String> handler) throws WxErrorException, IOException {
handler.handle(this.execute(uri, data));
}

public static RequestExecutor<String, String> create(RequestHttp requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:


+ 8
- 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java Dosyayı Görüntüle

@@ -1,5 +1,8 @@
package me.chanjar.weixin.common.util.http;

import java.io.IOException;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.apache.ApacheSimplePostRequestExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimplePostRequestExecutor;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimplePostRequestExecutor;
@@ -17,6 +20,11 @@ public abstract class SimplePostRequestExecutor<H, P> implements RequestExecutor
this.requestHttp = requestHttp;
}

@Override
public void execute(String uri, String data, ResponseHandler<String> handler) throws WxErrorException, IOException {
handler.handle(this.execute(uri, data));
}

public static RequestExecutor<String, String> create(RequestHttp requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:


+ 13
- 18
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/URIUtil.java Dosyayı Görüntüle

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


import org.apache.commons.lang3.StringUtils;
import java.nio.charset.StandardCharsets;

import java.io.UnsupportedEncodingException;
import org.apache.commons.lang3.StringUtils;

public class URIUtil {

@@ -16,27 +16,22 @@ public class URIUtil {

int l = input.length();
StringBuilder o = new StringBuilder(l * 3);
try {
for (int i = 0; i < l; i++) {
String e = input.substring(i, i + 1);
if (ALLOWED_CHARS.indexOf(e) == -1) {
byte[] b = e.getBytes("utf-8");
o.append(getHex(b));
continue;
}
o.append(e);
for (int i = 0; i < l; i++) {
String e = input.substring(i, i + 1);
if (!ALLOWED_CHARS.contains(e)) {
byte[] b = e.getBytes(StandardCharsets.UTF_8);
o.append(getHex(b));
continue;
}
return o.toString();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
o.append(e);
}
return input;
return o.toString();
}

private static String getHex(byte buf[]) {
private static String getHex(byte[] buf) {
StringBuilder o = new StringBuilder(buf.length * 3);
for (int i = 0; i < buf.length; i++) {
int n = buf[i] & 0xff;
for (byte aBuf : buf) {
int n = aBuf & 0xff;
o.append("%");
if (n < 0x10) {
o.append("0");


+ 6
- 5
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientSimpleGetRequestExecutor.java Dosyayı Görüntüle

@@ -1,16 +1,17 @@
package me.chanjar.weixin.common.util.http.apache;

import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import java.io.IOException;

import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;

import java.io.IOException;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;

/**
* Created by ecoolper on 2017/5/4.


+ 5
- 4
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java Dosyayı Görüntüle

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

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.annotation.NotThreadSafe;
@@ -25,10 +29,6 @@ import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
* httpclient 连接管理器 自带DNS解析.
* <p>大部分代码拷贝自:DefaultApacheHttpClientBuilder</p>
@@ -292,6 +292,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder {
}
}
} catch (InterruptedException ignore) {
Thread.currentThread().interrupt();
}
}



+ 0
- 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java Dosyayı Görüntüle

@@ -25,7 +25,6 @@ import me.chanjar.weixin.common.util.http.RequestHttp;
* Created by ecoolper on 2017/5/5.
*/
public class ApacheMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor<CloseableHttpClient, HttpHost> {

public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
super(requestHttp, tmpDirFile);
}


+ 10
- 5
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java Dosyayı Görüntüle

@@ -1,5 +1,8 @@
package me.chanjar.weixin.common.util.http.apache;

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

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
@@ -7,18 +10,20 @@ import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.util.EntityUtils;

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

/**
* 输入流响应处理器.
*
* @author Daniel Qian
*/
public class InputStreamResponseHandler implements ResponseHandler<InputStream> {

public static final ResponseHandler<InputStream> INSTANCE = new InputStreamResponseHandler();
private static final int STATUS_CODE_300 = 300;

@Override
public InputStream handleResponse(final HttpResponse response) throws IOException {
final StatusLine statusLine = response.getStatusLine();
final HttpEntity entity = response.getEntity();
if (statusLine.getStatusCode() >= 300) {
if (statusLine.getStatusCode() >= STATUS_CODE_300) {
EntityUtils.consume(entity);
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
}


+ 5
- 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java Dosyayı Görüntüle

@@ -7,9 +7,13 @@ import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;

/**
* .
* @author chanjarster
*/
public class WxGsonBuilder {

public static final GsonBuilder INSTANCE = new GsonBuilder();
private static final GsonBuilder INSTANCE = new GsonBuilder();

static {
INSTANCE.disableHtmlEscaping();


+ 34
- 34
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java Dosyayı Görüntüle

@@ -8,47 +8,47 @@ import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.thoughtworks.xstream.security.NullPermission;
import com.thoughtworks.xstream.security.PrimitiveTypePermission;

public class XStreamInitializer {

public static XStream getInstance() {
XStream xstream = new XStream(new PureJavaReflectionProvider(), new XppDriver() {

@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out, getNameCoder()) {
protected String PREFIX_CDATA = "<![CDATA[";
protected String SUFFIX_CDATA = "]]>";
protected String PREFIX_MEDIA_ID = "<MediaId>";
protected String SUFFIX_MEDIA_ID = "</MediaId>";

@Override
protected void writeText(QuickWriter writer, String text) {
if (text.startsWith(this.PREFIX_CDATA) && text.endsWith(this.SUFFIX_CDATA)) {
writer.write(text);
} else if (text.startsWith(this.PREFIX_MEDIA_ID) && text.endsWith(this.SUFFIX_MEDIA_ID)) {
writer.write(text);
} else {
super.writeText(writer, text);
}

private static final XppDriver XPP_DRIVER = new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out, getNameCoder()) {
private static final String PREFIX_CDATA = "<![CDATA[";
private static final String SUFFIX_CDATA = "]]>";
private static final String PREFIX_MEDIA_ID = "<MediaId>";
private static final String SUFFIX_MEDIA_ID = "</MediaId>";

@Override
protected void writeText(QuickWriter writer, String text) {
if (text.startsWith(PREFIX_CDATA) && text.endsWith(SUFFIX_CDATA)) {
writer.write(text);
} else if (text.startsWith(PREFIX_MEDIA_ID) && text.endsWith(SUFFIX_MEDIA_ID)) {
writer.write(text);
} else {
super.writeText(writer, text);
}

@Override
public String encodeNode(String name) {
//防止将_转换成__
return name;
}
};
}
});
}

@Override
public String encodeNode(String name) {
//防止将_转换成__
return name;
}
};
}
};

public static XStream getInstance() {
XStream xstream = new XStream(new PureJavaReflectionProvider(), XPP_DRIVER);
xstream.ignoreUnknownElements();
xstream.setMode(XStream.NO_REFERENCES);
xstream.addPermission(NullPermission.NULL);
xstream.addPermission(PrimitiveTypePermission.PRIMITIVES);
XStream.setupDefaultSecurity(xstream);
xstream.allowTypesByWildcard(new String[]{
"me.chanjar.weixin.**", "cn.binarywang.wx.**", "com.github.binarywang.**"
});

xstream.setClassLoader(Thread.currentThread().getContextClassLoader());
return xstream;
}


+ 2
- 3
weixin-java-common/src/test/java/me/chanjar/weixin/common/util/DataUtilsTest.java Dosyayı Görüntüle

@@ -1,8 +1,7 @@
package me.chanjar.weixin.common.util;

import org.testng.annotations.Test;
import org.testng.annotations.*;

import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.*;

/**
@@ -18,6 +17,6 @@ public class DataUtilsTest {
public void testHandleDataWithSecret() {
String data = "js_code=001tZveq0SMoiq1AEXeq0ECJeq0tZveZ&secret=5681022fa1643845392367ea88888888&grant_type=authorization_code&appid=wxe156d4848d999999";
final String s = DataUtils.handleDataWithSecret(data);
assertThat(s).contains("&secret=******&");
assertTrue(s.contains("&secret=******&"));
}
}

+ 78
- 0
weixin-java-common/src/test/java/me/chanjar/weixin/common/util/XmlUtilsTest.java Dosyayı Görüntüle

@@ -0,0 +1,78 @@
package me.chanjar.weixin.common.util;

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

import org.testng.annotations.*;

import static org.assertj.core.api.Assertions.assertThat;

/**
* <pre>
*
* Created by Binary Wang on 2018/11/4.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class XmlUtilsTest {

@Test
public void testXml2Map() {
String xml = "<xml>\n" +
"<CopyrightCheckResult>\n" +
"<Count>2</Count>\n" +
"<ResultList>\n" +
"<item>\n" +
"<ArticleIdx>1</ArticleIdx>\n" +
"<UserDeclareState>0</UserDeclareState>\n" +
"<AuditState>2</AuditState>\n" +
"<OriginalArticleUrl><![CDATA[Url_1]]></OriginalArticleUrl>\n" +
"<OriginalArticleType>1</OriginalArticleType>\n" +
"<CanReprint>1</CanReprint>\n" +
"<NeedReplaceContent>1</NeedReplaceContent>\n" +
"<NeedShowReprintSource>1</NeedShowReprintSource>\n" +
"</item>\n" +
"<item>\n" +
"<ArticleIdx>2</ArticleIdx>\n" +
"<UserDeclareState>0</UserDeclareState>\n" +
"<AuditState>2</AuditState>\n" +
"<OriginalArticleUrl><![CDATA[Url_2]]></OriginalArticleUrl>\n" +
"<OriginalArticleType>1</OriginalArticleType>\n" +
"<CanReprint>1</CanReprint>\n" +
"<NeedReplaceContent>1</NeedReplaceContent>\n" +
"<NeedShowReprintSource>1</NeedShowReprintSource>\n" +
"</item>\n" +
"</ResultList>\n" +
"<CheckState>2</CheckState>\n" +
"</CopyrightCheckResult>\n" +
"</xml>";

final Map<String, Object> map = XmlUtils.xml2Map(xml);
assertThat(map).isNotNull();
final Map<String, Object> copyrightCheckResult = (Map<String, Object>) map.get("CopyrightCheckResult");
List<Map<String, Object>> resultList = (List<Map<String, Object>>) ((Map<String, Object>) copyrightCheckResult.get("ResultList")).get("item");
assertThat(copyrightCheckResult).isNotNull();

assertThat(copyrightCheckResult.get("Count")).isEqualTo("2");
assertThat(copyrightCheckResult.get("CheckState")).isEqualTo("2");

assertThat(resultList.get(0).get("ArticleIdx")).isEqualTo("1");
assertThat(resultList.get(0).get("UserDeclareState")).isEqualTo("0");
assertThat(resultList.get(0).get("AuditState")).isEqualTo("2");
assertThat(resultList.get(0).get("OriginalArticleUrl")).isEqualTo("Url_1");
assertThat(resultList.get(0).get("OriginalArticleType")).isEqualTo("1");
assertThat(resultList.get(0).get("CanReprint")).isEqualTo("1");
assertThat(resultList.get(0).get("NeedReplaceContent")).isEqualTo("1");
assertThat(resultList.get(0).get("NeedShowReprintSource")).isEqualTo("1");

assertThat(resultList.get(1).get("ArticleIdx")).isEqualTo("2");
assertThat(resultList.get(1).get("UserDeclareState")).isEqualTo("0");
assertThat(resultList.get(1).get("AuditState")).isEqualTo("2");
assertThat(resultList.get(1).get("OriginalArticleUrl")).isEqualTo("Url_2");
assertThat(resultList.get(1).get("OriginalArticleType")).isEqualTo("1");
assertThat(resultList.get(1).get("CanReprint")).isEqualTo("1");
assertThat(resultList.get(1).get("NeedReplaceContent")).isEqualTo("1");
assertThat(resultList.get(1).get("NeedShowReprintSource")).isEqualTo("1");
}
}

+ 8
- 6
weixin-java-common/src/test/java/me/chanjar/weixin/common/util/crypto/WxCryptUtilTest.java Dosyayı Görüntüle

@@ -1,5 +1,11 @@
package me.chanjar.weixin.common.util.crypto;

import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.testng.annotations.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -7,12 +13,6 @@ import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;

import static org.testng.Assert.*;

@Test
@@ -39,6 +39,7 @@ public class WxCryptUtilTest {
System.out.println(encryptedXml);

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setExpandEntityReferences(false);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(new InputSource(new StringReader(encryptedXml)));

@@ -81,6 +82,7 @@ public class WxCryptUtilTest {
WxCryptUtil pc = new WxCryptUtil(this.token, this.encodingAesKey, this.appId);
String afterEncrpt = pc.encrypt(this.replyMsg);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(afterEncrpt);
InputSource is = new InputSource(sr);


+ 4
- 4
weixin-java-cp/pom.xml Dosyayı Görüntüle

@@ -6,13 +6,13 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>3.2.0</version>
<artifactId>wx-java</artifactId>
<version>3.3.0</version>
</parent>

<artifactId>weixin-java-cp</artifactId>
<name>Weixin Java Tools - CP</name>
<description>微信企业号Java SDK</description>
<name>WxJava - CP</name>
<description>微信企业号/企业微信 Java SDK</description>

<dependencies>
<dependency>


+ 48
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java Dosyayı Görüntüle

@@ -0,0 +1,48 @@
package me.chanjar.weixin.cp.api;

import java.util.List;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.bean.WxCpChat;

/**
* 群聊服务
*
* @author gaigeshen
*/
public interface WxCpChatService {

/**
* 创建群聊会话,注意:刚创建的群,如果没有下发消息,在企业微信不会出现该群。
*
* @param name 群聊名,最多50个utf8字符,超过将截断
* @param owner 指定群主的id。如果不指定,系统会随机从userlist中选一人作为群主
* @param users 群成员id列表。至少2人,至多500人
* @param chatId 群聊的唯一标志,不能与已有的群重复;字符串类型,最长32个字符。只允许字符0-9及字母a-zA-Z。如果不填,系统会随机生成群id
* @return 创建群聊会话的结果,群聊的唯一标志
* @throws WxErrorException 发生异常
*/
String chatCreate(String name, String owner, List<String> users, String chatId) throws WxErrorException;
/**
* 修改群聊会话
*
* @param chatId 群聊id
* @param name 新的群聊名。若不需更新,请忽略此参数(null or empty)。最多50个utf8字符,超过将截断
* @param owner 新群主的id。若不需更新,请忽略此参数(null or empty)
* @param usersToAdd 添加成员的id列表,若不需要更新,则传递空对象或者空集合
* @param usersToDelete 踢出成员的id列表,若不需要更新,则传递空对象或者空集合
* @throws WxErrorException 发生异常
*/
void chatUpdate(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete) throws WxErrorException;

/**
* 获取群聊会话
*
* @param chatId 群聊编号
* @return 群聊会话
* @throws WxErrorException 发生异常
*/
WxCpChat chatGet(String chatId) throws WxErrorException;
}

+ 13
- 8
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java Dosyayı Görüntüle

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

import java.util.List;

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

import java.util.List;

/**
* <pre>
* 部门管理接口
@@ -17,42 +17,47 @@ public interface WxCpDepartmentService {

/**
* <pre>
* 部门管理接口 - 创建部门
* 部门管理接口 - 创建部门.
* 最多支持创建500个部门
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
* </pre>
*
* @param depart 部门
* @return 部门id
* @throws WxErrorException 异常
*/
Integer create(WxCpDepart depart) throws WxErrorException;

/**
* <pre>
* 部门管理接口 - 查询部门
* 部门管理接口 - 查询部门.
* 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E5.88.97.E8.A1.A8
* </pre>
*
* @param id 部门id。获取指定部门及其下的子部门。非必需,可为null
* @throws WxErrorException 异常
*/
List<WxCpDepart> list(Integer id) throws WxErrorException;
List<WxCpDepart> list(Long id) throws WxErrorException;

/**
* <pre>
* 部门管理接口 - 修改部门名
* 部门管理接口 - 修改部门名.
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
* 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
* </pre>
*
* @param group 要更新的group,group的id,name必须设置
* @throws WxErrorException 异常
*/
void update(WxCpDepart group) throws WxErrorException;

/**
* <pre>
* 部门管理接口 - 删除部门
* 部门管理接口 - 删除部门.
* </pre>
*
* @param departId 部门id
* @throws WxErrorException 异常
*/
void delete(Integer departId) throws WxErrorException;
void delete(Long departId) throws WxErrorException;
}

+ 17
- 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java Dosyayı Görüntüle

@@ -19,6 +19,7 @@ public interface WxCpMediaService {
String MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get";
String MEDIA_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=";
String IMG_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg";
String JSSDK_MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk";

/**
* <pre>
@@ -59,6 +60,21 @@ public interface WxCpMediaService {
*/
File download(String mediaId) throws WxErrorException;

/**
* <pre>
* 获取高清语音素材.
* 可以使用本接口获取从JSSDK的uploadVoice接口上传的临时语音素材,格式为speex,16K采样率。该音频比上文的临时素材获取接口(格式为amr,8K采样率)更加清晰,适合用作语音识别等对音质要求较高的业务。
* 请求方式:GET(HTTPS)
* 请求地址:https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
* 仅企业微信2.4及以上版本支持。
* 文档地址:https://work.weixin.qq.com/api/doc#90000/90135/90255
* </pre>
*
* @param mediaId 媒体id
* @return 保存到本地的临时文件
*/
File getJssdkFile(String mediaId) throws WxErrorException;

/**
* <pre>
* 上传图片.
@@ -69,7 +85,7 @@ public interface WxCpMediaService {
* </pre>
*
* @param file 上传的文件对象
* @return 返回图片url
* @return 返回图片url
*/
String uploadImg(File file) throws WxErrorException;
}

+ 10
- 2
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java Dosyayı Görüntüle

@@ -7,7 +7,8 @@ import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.cp.bean.*;
import me.chanjar.weixin.cp.bean.WxCpMessage;
import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;

/**
@@ -241,13 +242,20 @@ public interface WxCpService {
* 获取用户相关接口的服务类对象
*/
WxCpUserService getUserService();
/**
* 获取群聊服务
*
* @return 群聊服务
*/
WxCpChatService getChatService();

WxCpAgentService getAgentService();

/**
* http请求对象
*/
RequestHttp getRequestHttp();
RequestHttp<?, ?> getRequestHttp();

void setUserService(WxCpUserService userService);



+ 2
- 2
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java Dosyayı Görüntüle

@@ -38,7 +38,7 @@ public interface WxCpUserService {
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员
* @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加
*/
List<WxCpUser> listByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException;
List<WxCpUser> listByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException;

/**
* <pre>
@@ -51,7 +51,7 @@ public interface WxCpUserService {
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员
* @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加
*/
List<WxCpUser> listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException;
List<WxCpUser> listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException;

/**
* 新建用户.


+ 3
- 3
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java Dosyayı Görüntüle

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

import com.google.gson.Gson;
import java.util.List;

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

import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpAgentService;
@@ -11,8 +13,6 @@ import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpAgent;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

import java.util.List;


/**
* <pre>


+ 83
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java Dosyayı Görüntüle

@@ -0,0 +1,83 @@
package me.chanjar.weixin.cp.api.impl;

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

import org.apache.commons.lang3.StringUtils;

import com.google.gson.JsonParser;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.cp.api.WxCpChatService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpChat;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

/**
* 群聊服务实现
*
* @author gaigeshen
*/
public class WxCpChatServiceImpl implements WxCpChatService {

private final WxCpService internalService;
/**
* 创建群聊服务实现的实例
*
* @param internalService 企业微信的服务
*/
public WxCpChatServiceImpl(WxCpService internalService) {
this.internalService = internalService;
}

@Override
public String chatCreate(String name, String owner, List<String> users, String chatId) throws WxErrorException {
Map<String, Object> data = new HashMap<>(4);
if (StringUtils.isNotBlank(name)) {
data.put("name", name);
}
if (StringUtils.isNotBlank(owner)) {
data.put("owner", owner);
}
if (users != null) {
data.put("userlist", users);
}
if (StringUtils.isNotBlank(chatId)) {
data.put("chatid", chatId);
}
String result = internalService.post("https://qyapi.weixin.qq.com/cgi-bin/appchat/create", WxGsonBuilder.create().toJson(data));
return new JsonParser().parse(result).getAsJsonObject().get("chatid").getAsString();
}

@Override
public void chatUpdate(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete) throws WxErrorException {
Map<String, Object> data = new HashMap<>(5);
if (StringUtils.isNotBlank(chatId)) {
data.put("chatid", chatId);
}
if (StringUtils.isNotBlank(name)) {
data.put("name", name);
}
if (StringUtils.isNotBlank(owner)) {
data.put("owner", owner);
}
if (usersToAdd != null && !usersToAdd.isEmpty()) {
data.put("add_user_list", usersToAdd);
}
if (usersToDelete != null && !usersToDelete.isEmpty()) {
data.put("del_user_list", usersToDelete);
}
internalService.post("https://qyapi.weixin.qq.com/cgi-bin/appchat/update", WxGsonBuilder.create().toJson(data));
}

@Override
public WxCpChat chatGet(String chatId) throws WxErrorException {
String result = internalService.get("https://qyapi.weixin.qq.com/cgi-bin/appchat/get?chatid=" + chatId, null);
return WxCpGsonBuilder.create().fromJson(
new JsonParser().parse(result).getAsJsonObject().getAsJsonObject("chat_info").toString(), WxCpChat.class);
}

}

+ 5
- 5
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java Dosyayı Görüntüle

@@ -1,5 +1,7 @@
package me.chanjar.weixin.cp.api.impl;

import java.util.List;

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
@@ -10,8 +12,6 @@ import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpDepart;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

import java.util.List;

/**
* <pre>
* 部门管理接口
@@ -42,13 +42,13 @@ public class WxCpDepartmentServiceImpl implements WxCpDepartmentService {
}

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

@Override
public List<WxCpDepart> list(Integer id) throws WxErrorException {
public List<WxCpDepart> list(Long id) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list";
if (id != null) {
url += "?id=" + id;
@@ -56,7 +56,7 @@ public class WxCpDepartmentServiceImpl implements WxCpDepartmentService {

String responseContent = this.mainService.get(url, null);
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return WxCpGsonBuilder.INSTANCE.create()
return WxCpGsonBuilder.create()
.fromJson(tmpJsonElement.getAsJsonObject().get("department"),
new TypeToken<List<WxCpDepart>>() {
}.getType()


+ 8
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java Dosyayı Görüntüle

@@ -48,6 +48,14 @@ public class WxCpMediaServiceImpl implements WxCpMediaService {
MEDIA_GET_URL, "media_id=" + mediaId);
}

@Override
public File getJssdkFile(String mediaId) throws WxErrorException {
return this.mainService.execute(
BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(),
this.mainService.getWxCpConfigStorage().getTmpDirFile()),
JSSDK_MEDIA_GET_URL, "media_id=" + mediaId);
}

@Override
public String uploadImg(File file) throws WxErrorException {
final WxMediaUploadResult result = this.mainService


+ 2
- 2
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java Dosyayı Görüntüle

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

import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
@@ -11,6 +10,7 @@ import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpUserDetail;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

/**
* <pre>
@@ -87,6 +87,6 @@ public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service {
JsonObject param = new JsonObject();
param.addProperty("user_ticket", userTicket);
String responseText = this.mainService.post(url, param.toString());
return new GsonBuilder().create().fromJson(responseText, WxCpUserDetail.class);
return WxCpGsonBuilder.create().fromJson(responseText, WxCpUserDetail.class);
}
}

+ 26
- 9
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java Dosyayı Görüntüle

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

import java.io.File;
import java.io.IOException;

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

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
@@ -17,19 +24,24 @@ import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.cp.api.*;
import me.chanjar.weixin.cp.bean.*;
import me.chanjar.weixin.cp.api.WxCpAgentService;
import me.chanjar.weixin.cp.api.WxCpChatService;
import me.chanjar.weixin.cp.api.WxCpDepartmentService;
import me.chanjar.weixin.cp.api.WxCpMediaService;
import me.chanjar.weixin.cp.api.WxCpMenuService;
import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.WxCpTagService;
import me.chanjar.weixin.cp.api.WxCpUserService;
import me.chanjar.weixin.cp.bean.WxCpMessage;
import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;

public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, RequestHttp<H, P> {
protected final Logger log = LoggerFactory.getLogger(this.getClass());

private WxCpUserService userService = new WxCpUserServiceImpl(this);
private WxCpChatService chatService = new WxCpChatServiceImpl(this);
private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this);
private WxCpMediaService mediaService = new WxCpMediaServiceImpl(this);
private WxCpMenuService menuService = new WxCpMenuServiceImpl(this);
@@ -184,7 +196,7 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
Thread.sleep(sleepMillis);
} catch (InterruptedException e1) {
throw new RuntimeException(e1);
Thread.currentThread().interrupt();
}
} else {
throw e;
@@ -334,7 +346,12 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
}

@Override
public RequestHttp getRequestHttp() {
public WxCpChatService getChatService() {
return chatService;
}

@Override
public RequestHttp<?, ?> getRequestHttp() {
return this;
}



+ 9
- 5
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java Dosyayı Görüntüle

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

import com.google.gson.*;
import java.util.List;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.reflect.TypeToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpService;
@@ -11,8 +17,6 @@ import me.chanjar.weixin.cp.bean.WxCpTagGetResult;
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

import java.util.List;

/**
* <pre>
* 标签管理接口
@@ -57,7 +61,7 @@ public class WxCpTagServiceImpl implements WxCpTagService {
String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list";
String responseContent = this.mainService.get(url, null);
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return WxCpGsonBuilder.INSTANCE.create()
return WxCpGsonBuilder.create()
.fromJson(
tmpJsonElement.getAsJsonObject().get("taglist"),
new TypeToken<List<WxCpTag>>() {
@@ -70,7 +74,7 @@ public class WxCpTagServiceImpl implements WxCpTagService {
String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId;
String responseContent = this.mainService.get(url, null);
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return WxCpGsonBuilder.INSTANCE.create()
return WxCpGsonBuilder.create()
.fromJson(
tmpJsonElement.getAsJsonObject().get("userlist"),
new TypeToken<List<WxCpUser>>() {


+ 4
- 4
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java Dosyayı Görüntüle

@@ -76,7 +76,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {
}

@Override
public List<WxCpUser> listByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException {
public List<WxCpUser> listByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId;
String params = "";
if (fetchChild != null) {
@@ -90,7 +90,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {

String responseContent = this.mainService.get(url, params);
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return WxCpGsonBuilder.INSTANCE.create()
return WxCpGsonBuilder.create()
.fromJson(tmpJsonElement.getAsJsonObject().get("userlist"),
new TypeToken<List<WxCpUser>>() {
}.getType()
@@ -98,7 +98,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {
}

@Override
public List<WxCpUser> listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException {
public List<WxCpUser> listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException {
String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId;
String params = "";
if (fetchChild != null) {
@@ -112,7 +112,7 @@ public class WxCpUserServiceImpl implements WxCpUserService {

String responseContent = this.mainService.get(url, params);
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
return WxCpGsonBuilder.INSTANCE.create()
return WxCpGsonBuilder.create()
.fromJson(
tmpJsonElement.getAsJsonObject().get("userlist"),
new TypeToken<List<WxCpUser>>() {


+ 5
- 3
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgent.java Dosyayı Görüntüle

@@ -1,5 +1,8 @@
package me.chanjar.weixin.cp.bean;

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

import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -7,9 +10,6 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

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

/**
* <pre>
* 企业号应用信息.
@@ -80,12 +80,14 @@ public class WxCpAgent implements Serializable {

@Data
public static class Users implements Serializable {
private static final long serialVersionUID = 8801100463558788565L;
@SerializedName("user")
private List<User> users;
}

@Data
public class User implements Serializable {
private static final long serialVersionUID = 7287632514385508024L;
@SerializedName("userid")
private String userId;
}


+ 20
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpChat.java Dosyayı Görüntüle

@@ -0,0 +1,20 @@
package me.chanjar.weixin.cp.bean;
import java.util.List;
import lombok.Data;
/**
* 群聊
*
* @author gaigeshen
*/
@Data
public class WxCpChat {
private String id;
private String name;
private String owner;
private List<String> users;
}

+ 4
- 4
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java Dosyayı Görüntüle

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

import java.io.Serializable;

import lombok.Data;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

import java.io.Serializable;

/**
* 微信部门.
*
@@ -14,9 +14,9 @@ import java.io.Serializable;
public class WxCpDepart implements Serializable {

private static final long serialVersionUID = -5028321625140879571L;
private Integer id;
private Long id;
private String name;
private Integer parentId;
private Long parentId;
private Long order;

public static WxCpDepart fromJson(String json) {


+ 2
- 4
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpInviteResult.java Dosyayı Görüntüle

@@ -5,8 +5,6 @@ import java.util.Collections;
import java.util.List;

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

import com.google.common.base.Splitter;
import com.google.gson.annotations.SerializedName;
@@ -25,11 +23,11 @@ public class WxCpInviteResult implements Serializable {

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return WxCpGsonBuilder.create().toJson(this);
}

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

@SerializedName("errcode")


+ 13
- 6
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java Dosyayı Görüntüle

@@ -1,16 +1,23 @@
package me.chanjar.weixin.cp.bean;

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

import lombok.Data;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
import me.chanjar.weixin.cp.bean.article.NewArticle;
import me.chanjar.weixin.cp.bean.messagebuilder.*;
import me.chanjar.weixin.cp.bean.messagebuilder.FileBuilder;
import me.chanjar.weixin.cp.bean.messagebuilder.ImageBuilder;
import me.chanjar.weixin.cp.bean.messagebuilder.MpnewsBuilder;
import me.chanjar.weixin.cp.bean.messagebuilder.NewsBuilder;
import me.chanjar.weixin.cp.bean.messagebuilder.TextBuilder;
import me.chanjar.weixin.cp.bean.messagebuilder.TextCardBuilder;
import me.chanjar.weixin.cp.bean.messagebuilder.VideoBuilder;
import me.chanjar.weixin.cp.bean.messagebuilder.VoiceBuilder;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

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

/**
* 消息.
*
@@ -114,7 +121,7 @@ public class WxCpMessage implements Serializable {
}

public String toJson() {
return WxCpGsonBuilder.INSTANCE.create().toJson(this);
return WxCpGsonBuilder.create().toJson(this);
}

}

+ 2
- 4
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessageSendResult.java Dosyayı Görüntüle

@@ -5,8 +5,6 @@ import java.util.Collections;
import java.util.List;

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

import com.google.common.base.Splitter;
import com.google.gson.annotations.SerializedName;
@@ -25,11 +23,11 @@ public class WxCpMessageSendResult implements Serializable {

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return WxCpGsonBuilder.create().toJson(this);
}

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

@SerializedName("errcode")


+ 3
- 2
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java Dosyayı Görüntüle

@@ -1,14 +1,15 @@
package me.chanjar.weixin.cp.bean;

import java.io.Serializable;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

import java.io.Serializable;

/**
* Created by Daniel Qian.
* @author Daniel Qian
*/
@Data
@AllArgsConstructor


+ 2
- 4
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagAddOrRemoveUsersResult.java Dosyayı Görüntüle

@@ -5,8 +5,6 @@ import java.util.Collections;
import java.util.List;

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

import com.google.common.base.Splitter;
import com.google.gson.annotations.SerializedName;
@@ -25,11 +23,11 @@ public class WxCpTagAddOrRemoveUsersResult implements Serializable {

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return WxCpGsonBuilder.create().toJson(this);
}

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

@SerializedName("errcode")


+ 2
- 2
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java Dosyayı Görüntüle

@@ -50,11 +50,11 @@ public class WxCpUser implements Serializable {
}

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

public String toJson() {
return WxCpGsonBuilder.INSTANCE.create().toJson(this);
return WxCpGsonBuilder.create().toJson(this);
}

@Data


+ 4
- 4
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java Dosyayı Görüntüle

@@ -3,12 +3,11 @@ package me.chanjar.weixin.cp.bean;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

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

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamConverter;
@@ -18,6 +17,7 @@ import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import me.chanjar.weixin.cp.util.xml.XStreamTransformer;

/**
@@ -370,7 +370,7 @@ public class WxCpXmlMessage implements Serializable {
public static WxCpXmlMessage fromEncryptedXml(InputStream is, WxCpConfigStorage wxCpConfigStorage,
String timestamp, String nonce, String msgSignature) {
try {
return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxCpConfigStorage, timestamp, nonce, msgSignature);
return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), wxCpConfigStorage, timestamp, nonce, msgSignature);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -378,7 +378,7 @@ public class WxCpXmlMessage implements Serializable {

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return WxCpGsonBuilder.create().toJson(this);
}

@Data


+ 2
- 4
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java Dosyayı Görüntüle

@@ -2,11 +2,9 @@ package me.chanjar.weixin.cp.config;

import java.io.File;

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

import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

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

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return WxCpGsonBuilder.create().toJson(this);
}

@Override


+ 16
- 15
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java Dosyayı Görüntüle

@@ -1,5 +1,18 @@
package me.chanjar.weixin.cp.message;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import me.chanjar.weixin.common.api.WxErrorExceptionHandler;
import me.chanjar.weixin.common.api.WxMessageDuplicateChecker;
import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker;
@@ -11,18 +24,6 @@ import me.chanjar.weixin.common.util.LogExceptionHandler;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
* <pre>
@@ -195,6 +196,7 @@ public class WxCpMessageRouter {
sessionEndAccess(wxMessage);
} catch (InterruptedException e) {
WxCpMessageRouter.this.log.error("Error happened when wait task finish", e);
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
WxCpMessageRouter.this.log.error("Error happened when wait task finish", e);
}
@@ -207,12 +209,11 @@ public class WxCpMessageRouter {


/**
* 处理微信消息
* 处理微信消息.
*
* @param wxMessage
*/
public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) {
return this.route(wxMessage, new HashMap<String, Object>());
return this.route(wxMessage, new HashMap<String, Object>(2));
}

protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) {


+ 77
- 0
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java Dosyayı Görüntüle

@@ -0,0 +1,77 @@
/*
* KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved.
*
* This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended
* only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction
* arose from modification of the original source, or other redistribution of this source
* is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD.
*/
package me.chanjar.weixin.cp.util.json;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.cp.bean.WxCpChat;

/**
* 群聊适配器
*
* @author gaigeshen
*/
public class WxCpChatGsonAdapter implements JsonSerializer<WxCpChat>, JsonDeserializer<WxCpChat> {

@Override
public JsonElement serialize(WxCpChat chat, Type typeOfSrc, JsonSerializationContext context) {
JsonObject json = new JsonObject();
if (chat.getId() != null) {
json.addProperty("chatid", chat.getId());
}
if (chat.getName() != null) {
json.addProperty("name", chat.getName());
}
if (chat.getOwner() != null) {
json.addProperty("owner", chat.getOwner());
}
if (chat.getUsers() != null) {
JsonArray users = new JsonArray();
for (String user : chat.getUsers()) {
users.add(user);
}
json.add("userlist", users);
}
return json;
}

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

WxCpChat chat = new WxCpChat();
chat.setId(GsonHelper.getAsString(chatJson.get("chatid")));
chat.setName(GsonHelper.getAsString(chatJson.get("name")));
chat.setOwner(GsonHelper.getAsString(chatJson.get("owner")));
JsonArray usersJson = chatJson.getAsJsonArray("userlist");
if (usersJson != null) {
List<String> users = new ArrayList<>(usersJson.size());
chat.setUsers(users);
for (JsonElement userJson : usersJson) {
users.add(userJson.getAsString());
}
}
return chat;
}

}

+ 27
- 15
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java Dosyayı Görüntüle

@@ -8,31 +8,43 @@
*/
package me.chanjar.weixin.cp.util.json;

import com.google.gson.*;
import java.lang.reflect.Type;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.cp.bean.WxCpDepart;

import java.lang.reflect.Type;

/**
* WxCpDepart的gson适配器.
*
* @author Daniel Qian
*/
public class WxCpDepartGsonAdapter implements JsonSerializer<WxCpDepart>, JsonDeserializer<WxCpDepart> {
private static final String ID = "id";
private static final String NAME = "name";
private static final String PARENT_ID = "parentid";
private static final String ORDER = "order";

@Override
public JsonElement serialize(WxCpDepart group, Type typeOfSrc, JsonSerializationContext context) {
JsonObject json = new JsonObject();
if (group.getId() != null) {
json.addProperty("id", group.getId());
json.addProperty(ID, group.getId());
}
if (group.getName() != null) {
json.addProperty("name", group.getName());
json.addProperty(NAME, group.getName());
}
if (group.getParentId() != null) {
json.addProperty("parentid", group.getParentId());
json.addProperty(PARENT_ID, group.getParentId());
}
if (group.getOrder() != null) {
json.addProperty("order", String.valueOf(group.getOrder()));
json.addProperty(ORDER, String.valueOf(group.getOrder()));
}
return json;
}
@@ -42,17 +54,17 @@ public class WxCpDepartGsonAdapter implements JsonSerializer<WxCpDepart>, JsonDe
throws JsonParseException {
WxCpDepart depart = new WxCpDepart();
JsonObject departJson = json.getAsJsonObject();
if (departJson.get("id") != null && !departJson.get("id").isJsonNull()) {
depart.setId(GsonHelper.getAsInteger(departJson.get("id")));
if (departJson.get(ID) != null && !departJson.get(ID).isJsonNull()) {
depart.setId(GsonHelper.getAsLong(departJson.get(ID)));
}
if (departJson.get("name") != null && !departJson.get("name").isJsonNull()) {
depart.setName(GsonHelper.getAsString(departJson.get("name")));
if (departJson.get(NAME) != null && !departJson.get(NAME).isJsonNull()) {
depart.setName(GsonHelper.getAsString(departJson.get(NAME)));
}
if (departJson.get("order") != null && !departJson.get("order").isJsonNull()) {
depart.setOrder(GsonHelper.getAsLong(departJson.get("order")));
if (departJson.get(ORDER) != null && !departJson.get(ORDER).isJsonNull()) {
depart.setOrder(GsonHelper.getAsLong(departJson.get(ORDER)));
}
if (departJson.get("parentid") != null && !departJson.get("parentid").isJsonNull()) {
depart.setParentId(GsonHelper.getAsInteger(departJson.get("parentid")));
if (departJson.get(PARENT_ID) != null && !departJson.get(PARENT_ID).isJsonNull()) {
depart.setParentId(GsonHelper.getAsLong(departJson.get(PARENT_ID)));
}
return depart;
}


+ 3
- 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java Dosyayı Görüntüle

@@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder;
import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.util.json.WxErrorAdapter;
import me.chanjar.weixin.cp.bean.WxCpChat;
import me.chanjar.weixin.cp.bean.WxCpDepart;
import me.chanjar.weixin.cp.bean.WxCpMessage;
import me.chanjar.weixin.cp.bean.WxCpTag;
@@ -15,11 +16,12 @@ import me.chanjar.weixin.cp.bean.WxCpUser;
*/
public class WxCpGsonBuilder {

public static final GsonBuilder INSTANCE = new GsonBuilder();
private static final GsonBuilder INSTANCE = new GsonBuilder();

static {
INSTANCE.disableHtmlEscaping();
INSTANCE.registerTypeAdapter(WxCpMessage.class, new WxCpMessageGsonAdapter());
INSTANCE.registerTypeAdapter(WxCpChat.class, new WxCpChatGsonAdapter());
INSTANCE.registerTypeAdapter(WxCpDepart.class, new WxCpDepartGsonAdapter());
INSTANCE.registerTypeAdapter(WxCpUser.class, new WxCpUserGsonAdapter());
INSTANCE.registerTypeAdapter(WxError.class, new WxErrorAdapter());


+ 46
- 0
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java Dosyayı Görüntüle

@@ -0,0 +1,46 @@
package me.chanjar.weixin.cp.api.impl;

import java.util.Arrays;

import me.chanjar.weixin.cp.bean.WxCpChat;
import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;

import com.google.inject.Inject;

import me.chanjar.weixin.cp.api.ApiTestModule;
import me.chanjar.weixin.cp.api.WxCpService;

/**
* 测试群聊服务
*
* @author gaigeshen
*/
@Guice(modules = ApiTestModule.class)
public class WxCpChatServiceImplTest {

@Inject
private WxCpService wxCpService;
@Test
public void create() throws Exception {
wxCpService.getChatService().chatCreate("测试群聊", "gaige_shen", Arrays.asList("gaige_shen", "ZhangXiaoMing"), "mychatid");
}

@Test
public void get() throws Exception {
WxCpChat chat = wxCpService.getChatService().chatGet("mychatid");
System.out.println(chat);
Assert.assertEquals(chat.getName(), "测试群聊");
}

@Test
public void update() throws Exception {
wxCpService.getChatService().chatUpdate("mychatid", "", "", Arrays.asList("ZhengWuYao"), null);
WxCpChat chat = wxCpService.getChatService().chatGet("mychatid");
System.out.println(chat);
Assert.assertEquals(chat.getUsers().size(), 3);
}

}

+ 6
- 6
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java Dosyayı Görüntüle

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

import java.util.List;

import org.testng.annotations.*;

import com.google.inject.Inject;
import me.chanjar.weixin.cp.api.ApiTestModule;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpDepart;
import org.testng.annotations.*;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.*;

/**
* <pre>
@@ -29,7 +29,7 @@ public class WxCpDepartmentServiceImplTest {
public void testCreate() throws Exception {
WxCpDepart cpDepart = new WxCpDepart();
cpDepart.setName("子部门" + System.currentTimeMillis());
cpDepart.setParentId(1);
cpDepart.setParentId(1L);
cpDepart.setOrder(1L);
Integer departId = this.wxCpService.getDepartmentService().create(cpDepart);
System.out.println(departId);
@@ -45,7 +45,7 @@ public class WxCpDepartmentServiceImplTest {
}

@Test(dataProvider = "departIds")
public void testList(Integer id) throws Exception {
public void testList(Long id) throws Exception {
System.out.println("=================获取部门");
List<WxCpDepart> departList = this.wxCpService.getDepartmentService().list(id);
assertThat(departList).isNotEmpty();


+ 15
- 6
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java Dosyayı Görüntüle

@@ -36,7 +36,8 @@ public class WxCpMediaServiceImplTest {
public Object[][] mediaData() {
return new Object[][]{
new Object[]{WxConsts.MediaFileType.IMAGE, TestConstants.FILE_JPG, "mm.jpeg"},
new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_MP3, "mm.mp3"},//{"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"}
//new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_MP3, "mm.mp3"},
// {"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"}
new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_AMR, "mm.amr"},
new Object[]{WxConsts.MediaFileType.VIDEO, TestConstants.FILE_MP4, "mm.mp4"},
new Object[]{WxConsts.MediaFileType.FILE, TestConstants.FILE_JPG, "mm.jpeg"}
@@ -47,8 +48,9 @@ public class WxCpMediaServiceImplTest {
public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException {
try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)) {
WxMediaUploadResult res = this.wxService.getMediaService().upload(mediaType, fileType, inputStream);
assertNotNull(res.getType());
assertNotNull(res.getCreatedAt());
assertThat(res).isNotNull();
assertThat(res.getType()).isNotEmpty();
assertThat(res.getCreatedAt()).isGreaterThan(0);
assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null);

if (res.getMediaId() != null) {
@@ -70,9 +72,9 @@ public class WxCpMediaServiceImplTest {
}

@Test(dependsOnMethods = {"testUploadMedia"}, dataProvider = "downloadMedia")
public void testDownloadMedia(String media_id) throws WxErrorException {
File file = this.wxService.getMediaService().download(media_id);
assertNotNull(file);
public void testDownload(String mediaId) throws WxErrorException {
File file = this.wxService.getMediaService().download(mediaId);
assertThat(file).isNotNull();
System.out.println(file);
}

@@ -82,4 +84,11 @@ public class WxCpMediaServiceImplTest {
String res = this.wxService.getMediaService().uploadImg(new File(url.getFile()));
assertThat(res).isNotEmpty();
}

@Test
public void testGetJssdkFile() throws WxErrorException {
File file = this.wxService.getMediaService().getJssdkFile("....");
assertThat(file).isNotNull();
System.out.println(file);
}
}

+ 2
- 2
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java Dosyayı Görüntüle

@@ -74,7 +74,7 @@ public class WxCpUserServiceImplTest {

@Test
public void testListByDepartment() throws Exception {
List<WxCpUser> users = this.wxCpService.getUserService().listByDepartment(1, true, 0);
List<WxCpUser> users = this.wxCpService.getUserService().listByDepartment(1L, true, 0);
assertNotEquals(users.size(), 0);
for (WxCpUser user : users) {
System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE));
@@ -83,7 +83,7 @@ public class WxCpUserServiceImplTest {

@Test
public void testListSimpleByDepartment() throws Exception {
List<WxCpUser> users = this.wxCpService.getUserService().listSimpleByDepartment(1, true, 0);
List<WxCpUser> users = this.wxCpService.getUserService().listSimpleByDepartment(1L, true, 0);
assertNotEquals(users.size(), 0);
for (WxCpUser user : users) {
System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE));


+ 3
- 3
weixin-java-miniapp/pom.xml Dosyayı Görüntüle

@@ -6,11 +6,11 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>3.2.0</version>
<artifactId>wx-java</artifactId>
<version>3.3.0</version>
</parent>
<artifactId>weixin-java-miniapp</artifactId>
<name>Weixin Java Tools - MiniApp</name>
<name>WxJava - MiniApp</name>
<description>微信小程序Java SDK</description>

<dependencies>


+ 20
- 1
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaJsapiService.java Dosyayı Görüntüle

@@ -15,7 +15,26 @@ public interface WxMaJsapiService {
/**
* 获得jsapi_ticket的url
*/
String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";

/**
* 获得卡券api_ticket,不强制刷新api_ticket
*
* @see #getJsapiTicket(boolean)
*/
String getCardApiTicket() throws WxErrorException;

/**
* <pre>
* 获得卡券api_ticket
* 获得时会检查apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
*
* 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
* </pre>
*
* @param forceRefresh 强制刷新
*/
String getCardApiTicket(boolean forceRefresh) throws WxErrorException;

/**
* 获得jsapi_ticket,不强制刷新jsapi_ticket


+ 114
- 10
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java Dosyayı Görüntüle

@@ -1,10 +1,10 @@
package cn.binarywang.wx.miniapp.api;

import java.io.File;

import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor;
import me.chanjar.weixin.common.error.WxErrorException;

import java.io.File;

/**
* <pre>
* 二维码相关操作接口.
@@ -32,24 +32,87 @@ public interface WxMaQrcodeService {
*
* @param path 不能为空,最大长度 128 字节
* @param width 默认430 二维码的宽度
* @return 文件内容字节数组
* @throws WxErrorException 异常
*/
byte[] createQrcodeBytes(String path, int width) throws WxErrorException;

/**
* 接口C: 获取小程序页面二维码.
* <pre>
* 适用于需要的码数量较少的业务场景
* 通过该接口,仅能生成已发布的小程序的二维码。
* 可以在开发者工具预览时生成开发版的带参二维码。
* 带参二维码只有 100000 个,请谨慎调用。
* </pre>
*
* @param path 不能为空,最大长度 128 字节
* @param width 默认430 二维码的宽度
* @return 文件对象
* @throws WxErrorException 异常
*/
File createQrcode(String path, int width) throws WxErrorException;

/**
* 接口C: 获取小程序页面二维码.
* <pre>
* 适用于需要的码数量较少的业务场景
* 通过该接口,仅能生成已发布的小程序的二维码。
* 可以在开发者工具预览时生成开发版的带参二维码。
* 带参二维码只有 100000 个,请谨慎调用。
* </pre>
*
* @param path 不能为空,最大长度 128 字节
* @return 文件对象
* @throws WxErrorException 异常
*/
File createQrcode(String path) throws WxErrorException;

/**
* 接口A: 获取小程序码.
*
* @param path 不能为空,最大长度 128 字节
* @param width 默认430 二维码的宽度
* @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
* @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}
* @param is_hyaline 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码
* @param path 不能为空,最大长度 128 字节
* @param width 默认430 二维码的宽度
* @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
* @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}
* @param isHyaline 是否需要透明底色, isHyaline 为true时,生成透明底色的小程序码
* @return 文件内容字节数组
* @throws WxErrorException 异常
*/
byte[] createWxaCodeBytes(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline)
throws WxErrorException;

/**
* 接口A: 获取小程序码.
*
* @param path 不能为空,最大长度 128 字节
* @param width 默认430 二维码的宽度
* @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
* @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}
* @param isHyaline 是否需要透明底色, isHyaline 为true时,生成透明底色的小程序码
* @return 文件对象
* @throws WxErrorException 异常
*/
File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean is_hyaline) throws WxErrorException;
File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline)
throws WxErrorException;

/**
* 接口A: 获取小程序码.
*
* @param path 不能为空,最大长度 128 字节
* @param width 默认430 二维码的宽度
* @return 文件对象
* @throws WxErrorException 异常
*/
File createWxaCode(String path, int width) throws WxErrorException;

/**
* 接口A: 获取小程序码.
*
* @param path 不能为空,最大长度 128 字节
* @return 文件对象
* @throws WxErrorException 异常
*/
File createWxaCode(String path) throws WxErrorException;

/**
@@ -61,15 +124,56 @@ public interface WxMaQrcodeService {
* 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode
* </pre>
*
* @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式)
* @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,
* 其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式)
* @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面
* @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
* @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
* @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}
* @param isHyaline 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码
* @return 文件内容字节数组
* @throws WxErrorException 异常
*/
byte[] createWxaCodeUnlimitBytes(String scene, String page, int width, boolean autoColor,
WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException;

/**
* 接口B: 获取小程序码(永久有效、数量暂无限制).
* <pre>
* 通过该接口生成的小程序码,永久有效,数量暂无限制。
* 用户扫描该码进入小程序后,将统一打开首页,开发者需在对应页面根据获取的码中 scene 字段的值,再做处理逻辑。
* 使用如下代码可以获取到二维码中的 scene 字段的值。
* 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode
* </pre>
*
* @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,
* 其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式)
* @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面
* @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
* @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
* @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}
* @param isHyaline 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码
* @return 文件对象
* @throws WxErrorException 异常
*/
File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException;
File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor,
WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException;

/**
* 接口B: 获取小程序码(永久有效、数量暂无限制).
* <pre>
* 通过该接口生成的小程序码,永久有效,数量暂无限制。
* 用户扫描该码进入小程序后,将统一打开首页,开发者需在对应页面根据获取的码中 scene 字段的值,再做处理逻辑。
* 使用如下代码可以获取到二维码中的 scene 字段的值。
* 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode
* </pre>
*
* @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,
* 其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式)
* @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面
* @return 文件对象
* @throws WxErrorException 异常
*/
File createWxaCodeUnlimit(String scene, String page) throws WxErrorException;

}

+ 24
- 0
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaRunService.java Dosyayı Görüntüle

@@ -0,0 +1,24 @@
package cn.binarywang.wx.miniapp.api;

import java.util.List;

import cn.binarywang.wx.miniapp.bean.WxMaRunStepInfo;

/**
* 微信运动相关操作接口.
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public interface WxMaRunService {

/**
* 解密分享敏感数据.
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/werun/wx.getWeRunData.html
*
* @param sessionKey 会话密钥
* @param encryptedData 消息密文
* @param ivStr 加密算法的初始向量
*/
List<WxMaRunStepInfo> getRunStepInfo(String sessionKey, String encryptedData, String ivStr);

}

+ 43
- 0
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSecCheckService.java Dosyayı Görüntüle

@@ -0,0 +1,43 @@
package cn.binarywang.wx.miniapp.api;

import java.io.File;

import me.chanjar.weixin.common.error.WxErrorException;

/**
* <pre>
* 内容安全相关接口.
* Created by Binary Wang on 2018/11/24.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public interface WxMaSecCheckService {

String IMG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/img_sec_check";

String MSG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/msg_sec_check";

/**
* <pre>
* 校验一张图片是否含有违法违规内容.
* 应用场景举例:
* 1)图片智能鉴黄:涉及拍照的工具类应用(如美拍,识图类应用)用户拍照上传检测;电商类商品上架图片检测;媒体类用户文章里的图片检测等;
* 2)敏感人脸识别:用户头像;媒体类用户文章里的图片检测;社交类用户上传的图片检测等。频率限制:单个 appId 调用上限为 1000 次/分钟,100,000 次/天
* 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/imgSecCheck.html
* </pre>
*/
boolean checkImage(File file) throws WxErrorException;

/**
* <pre>
* 检查一段文本是否含有违法违规内容。
* 应用场景举例:
* 用户个人资料违规文字检测;
* 媒体新闻类用户发表文章,评论内容检测;
* 游戏类用户编辑上传的素材(如答题类小游戏用户上传的问题及答案)检测等。 频率限制:单个 appId 调用上限为 4000 次/分钟,2,000,000 次/天*
* 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/msgSecCheck.html
* </pre>
*/
boolean checkMessage(String msgString);
}

+ 22
- 17
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java Dosyayı Görüntüle

@@ -1,7 +1,5 @@
package cn.binarywang.wx.miniapp.api;

import java.io.File;

import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import me.chanjar.weixin.common.error.WxErrorException;
@@ -20,17 +18,6 @@ public interface WxMaService {

String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session";

String IMG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/img_sec_check";

/**
* <pre>
* 校验一张图片是否含有违法违规内容.
* 应用场景举例:1)图片智能鉴黄:涉及拍照的工具类应用(如美拍,识图类应用)用户拍照上传检测;电商类商品上架图片检测;媒体类用户文章里的图片检测等;2)敏感人脸识别:用户头像;媒体类用户文章里的图片检测;社交类用户上传的图片检测等。频率限制:单个 appId 调用上限为 1000 次/分钟,100,000 次/天
* 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/imgSecCheck.html
* </pre>
*/
boolean imgSecCheck(File file) throws WxErrorException;

/**
* 获取登录后的session信息.
*
@@ -152,33 +139,51 @@ public interface WxMaService {
WxMaTemplateService getTemplateService();

/**
* 数据分析相关查询服务
* 数据分析相关查询服务.
*
* @return WxMaAnalysisService
*/
WxMaAnalysisService getAnalysisService();

/**
* 返回代码操作相关的 API
* 返回代码操作相关的 API.
*
* @return WxMaCodeService
*/
WxMaCodeService getCodeService();

/**
* 返回jsapi操作相关的 API服务类对象
* 返回jsapi操作相关的 API服务类对象.
*
* @return WxMaJsapiService
*/
WxMaJsapiService getJsapiService();

/**
* 小程序修改服务器地址、成员管理 API
* 小程序修改服务器地址、成员管理 API.
*
* @return WxMaSettingService
*/
WxMaSettingService getSettingService();

/**
* 返回分享相关查询服务.
* @return WxMaShareService
*/
WxMaShareService getShareService();

/**
* 返回微信运动相关接口服务对象.
* @return WxMaShareService
*/
WxMaRunService getRunService();

/**
* 返回内容安全相关接口服务对象.
* @return WxMaShareService
*/
WxMaSecCheckService getSecCheckService();

/**
* 初始化http请求对象.
*/


+ 21
- 0
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaShareService.java Dosyayı Görüntüle

@@ -0,0 +1,21 @@
package cn.binarywang.wx.miniapp.api;

import cn.binarywang.wx.miniapp.bean.WxMaShareInfo;

/**
* 分享信息相关操作接口.
*
* @author zhfish
*/
public interface WxMaShareService {

/**
* 解密分享敏感数据.
*
* @param sessionKey 会话密钥
* @param encryptedData 消息密文
* @param ivStr 加密算法的初始向量
*/
WxMaShareInfo getShareInfo(String sessionKey, String encryptedData, String ivStr);

}

+ 27
- 1
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImpl.java Dosyayı Görüntüle

@@ -28,6 +28,32 @@ public class WxMaJsapiServiceImpl implements WxMaJsapiService {
this.wxMaService = wxMaService;
}

public String getCardApiTicket() throws WxErrorException {
return getCardApiTicket(false);
}

public String getCardApiTicket(boolean forceRefresh) throws WxErrorException {
Lock lock = this.wxMaService.getWxMaConfig().getCardApiTicketLock();
try {
lock.lock();
if (forceRefresh) {
this.wxMaService.getWxMaConfig().expireCardApiTicket();
}

if (this.wxMaService.getWxMaConfig().isCardApiTicketExpired()) {
String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL + "?type=wx_card", null);
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
this.wxMaService.getWxMaConfig().updateCardApiTicket(jsapiTicket, expiresInSeconds);
}
} finally {
lock.unlock();
}
return this.wxMaService.getWxMaConfig().getJsapiTicket();
}

@Override
public String getJsapiTicket() throws WxErrorException {
return getJsapiTicket(false);
@@ -43,7 +69,7 @@ public class WxMaJsapiServiceImpl implements WxMaJsapiService {
}

if (this.wxMaService.getWxMaConfig().isJsapiTicketExpired()) {
String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL, null);
String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL + "?type=jsapi", null);
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();


+ 56
- 20
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java Dosyayı Görüntüle

@@ -1,16 +1,17 @@
package cn.binarywang.wx.miniapp.api.impl;

import java.io.File;

import cn.binarywang.wx.miniapp.api.WxMaQrcodeService;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor;
import cn.binarywang.wx.miniapp.bean.WxMaQrcode;
import cn.binarywang.wx.miniapp.bean.WxMaWxcode;
import cn.binarywang.wx.miniapp.bean.WxaCode;
import cn.binarywang.wx.miniapp.bean.WxaCodeUnlimit;
import cn.binarywang.wx.miniapp.util.http.QrCodeRequestExecutor;
import cn.binarywang.wx.miniapp.util.QrcodeBytesRequestExecutor;
import cn.binarywang.wx.miniapp.util.QrcodeRequestExecutor;
import me.chanjar.weixin.common.error.WxErrorException;

import java.io.File;

/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@@ -21,10 +22,16 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService {
this.wxMaService = wxMaService;
}

@Override
public byte[] createQrcodeBytes(String path, int width) throws WxErrorException {
final QrcodeBytesRequestExecutor executor = new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp());
return this.wxMaService.execute(executor, CREATE_QRCODE_URL, new WxMaQrcode(path, width));
}

@Override
public File createQrcode(String path, int width) throws WxErrorException {
return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()),
CREATE_QRCODE_URL, new WxMaQrcode(path, width));
final QrcodeRequestExecutor executor = new QrcodeRequestExecutor(this.wxMaService.getRequestHttp());
return this.wxMaService.execute(executor, CREATE_QRCODE_URL, new WxMaQrcode(path, width));
}

@Override
@@ -33,15 +40,29 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService {
}

@Override
public File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException {
WxMaWxcode wxMaWxcode = new WxMaWxcode();
wxMaWxcode.setPath(path);
wxMaWxcode.setWidth(width);
wxMaWxcode.setAutoColor(autoColor);
wxMaWxcode.setLineColor(lineColor);
wxMaWxcode.setHyaline(isHyaline);
return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()),
GET_WXACODE_URL, wxMaWxcode);
public byte[] createWxaCodeBytes(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline)
throws WxErrorException {
final QrcodeBytesRequestExecutor executor = new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp());
return this.wxMaService.execute(executor, GET_WXACODE_URL, WxaCode.builder()
.path(path)
.width(width)
.autoColor(autoColor)
.lineColor(lineColor)
.isHyaline(isHyaline)
.build());
}

@Override
public File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline)
throws WxErrorException {
final QrcodeRequestExecutor executor = new QrcodeRequestExecutor(this.wxMaService.getRequestHttp());
return this.wxMaService.execute(executor, GET_WXACODE_URL, WxaCode.builder()
.path(path)
.width(width)
.autoColor(autoColor)
.lineColor(lineColor)
.isHyaline(isHyaline)
.build());
}

@Override
@@ -51,12 +72,27 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService {

@Override
public File createWxaCode(String path) throws WxErrorException {
return this.createWxaCode(path, 430, true, null, false);
return this.createWxaCode(path, 430);
}

@Override
public File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline)
throws WxErrorException {
public byte[] createWxaCodeUnlimitBytes(String scene, String page, int width, boolean autoColor,
WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException {
return this.wxMaService.execute(new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp()),
GET_WXACODE_UNLIMIT_URL,
this.buildWxaCodeUnlimit(scene, page, width, autoColor, lineColor, isHyaline));
}

@Override
public File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor,
WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException {
return this.wxMaService.execute(new QrcodeRequestExecutor(this.wxMaService.getRequestHttp()),
GET_WXACODE_UNLIMIT_URL,
this.buildWxaCodeUnlimit(scene, page, width, autoColor, lineColor, isHyaline));
}

private WxaCodeUnlimit buildWxaCodeUnlimit(String scene, String page, int width, boolean autoColor,
WxMaCodeLineColor lineColor, boolean isHyaline) {
WxaCodeUnlimit wxaCodeUnlimit = new WxaCodeUnlimit();
wxaCodeUnlimit.setScene(scene);
wxaCodeUnlimit.setPage(page);
@@ -64,8 +100,8 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService {
wxaCodeUnlimit.setAutoColor(autoColor);
wxaCodeUnlimit.setLineColor(lineColor);
wxaCodeUnlimit.setHyaline(isHyaline);
return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()),
GET_WXACODE_UNLIMIT_URL, wxaCodeUnlimit);
return wxaCodeUnlimit;
}

@Override


+ 29
- 0
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaRunServiceImpl.java Dosyayı Görüntüle

@@ -0,0 +1,29 @@
package cn.binarywang.wx.miniapp.api.impl;

import java.util.List;

import cn.binarywang.wx.miniapp.api.WxMaRunService;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaRunStepInfo;
import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils;

/**
* <pre>
*
* Created by Binary Wang on 2018/11/4.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class WxMaRunServiceImpl implements WxMaRunService {
private WxMaService service;

public WxMaRunServiceImpl(WxMaService service) {
this.service = service;
}

@Override
public List<WxMaRunStepInfo> getRunStepInfo(String sessionKey, String encryptedData, String ivStr) {
return WxMaRunStepInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr));
}
}

+ 48
- 0
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImpl.java Dosyayı Görüntüle

@@ -0,0 +1,48 @@
package cn.binarywang.wx.miniapp.api.impl;

import java.io.File;

import cn.binarywang.wx.miniapp.api.WxMaSecCheckService;
import cn.binarywang.wx.miniapp.api.WxMaService;
import com.google.gson.JsonObject;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;

/**
* <pre>
*
* Created by Binary Wang on 2018/11/24.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class WxMaSecCheckServiceImpl implements WxMaSecCheckService {
private WxMaService service;

public WxMaSecCheckServiceImpl(WxMaService service) {
this.service = service;
}

@Override
public boolean checkImage(File file) throws WxErrorException {
//这里只是借用MediaUploadRequestExecutor,并不使用其返回值WxMediaUploadResult
WxMediaUploadResult result = this.service.execute(MediaUploadRequestExecutor
.create(this.service.getRequestHttp()), IMG_SEC_CHECK_URL, file);
return result != null;
}

@Override
public boolean checkMessage(String msgString) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("content", msgString);
try {
this.service.post(MSG_SEC_CHECK_URL, jsonObject.toString());
} catch (WxErrorException e) {
return false;
}

return true;
}

}

+ 30
- 21
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java Dosyayı Görüntüle

@@ -1,6 +1,5 @@
package cn.binarywang.wx.miniapp.api.impl;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@@ -12,8 +11,6 @@ import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.binarywang.wx.miniapp.api.WxMaAnalysisService;
import cn.binarywang.wx.miniapp.api.WxMaCodeService;
@@ -21,22 +18,24 @@ import cn.binarywang.wx.miniapp.api.WxMaJsapiService;
import cn.binarywang.wx.miniapp.api.WxMaMediaService;
import cn.binarywang.wx.miniapp.api.WxMaMsgService;
import cn.binarywang.wx.miniapp.api.WxMaQrcodeService;
import cn.binarywang.wx.miniapp.api.WxMaRunService;
import cn.binarywang.wx.miniapp.api.WxMaSecCheckService;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.WxMaSettingService;
import cn.binarywang.wx.miniapp.api.WxMaShareService;
import cn.binarywang.wx.miniapp.api.WxMaTemplateService;
import cn.binarywang.wx.miniapp.api.WxMaUserService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import com.google.common.base.Joiner;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.DataUtils;
import me.chanjar.weixin.common.util.crypto.SHA1;
import me.chanjar.weixin.common.util.http.HttpType;
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
@@ -49,9 +48,8 @@ import static cn.binarywang.wx.miniapp.constant.WxMaConstants.ErrorCode.*;
/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Slf4j
public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpClient, HttpHost> {
private final Logger log = LoggerFactory.getLogger(this.getClass());

private CloseableHttpClient httpClient;
private HttpHost httpProxy;
private WxMaConfig wxMaConfig;
@@ -65,6 +63,9 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
private WxMaCodeService codeService = new WxMaCodeServiceImpl(this);
private WxMaSettingService settingService = new WxMaSettingServiceImpl(this);
private WxMaJsapiService jsapiService = new WxMaJsapiServiceImpl(this);
private WxMaShareService shareService = new WxMaShareServiceImpl(this);
private WxMaRunService runService = new WxMaRunServiceImpl(this);
private WxMaSecCheckService secCheckService = new WxMaSecCheckServiceImpl(this);

private int retrySleepMillis = 1000;
private int maxRetryTimes = 5;
@@ -149,13 +150,6 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
return this.getWxMaConfig().getAccessToken();
}

@Override
public boolean imgSecCheck(File file) throws WxErrorException {
//这里只是借用MediaUploadRequestExecutor,并不使用其返回值WxMediaUploadResult
WxMediaUploadResult result = this.execute(MediaUploadRequestExecutor.create(this.getRequestHttp()), IMG_SEC_CHECK_URL, file);
return result != null;
}

@Override
public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException {
final WxMaConfig config = getWxMaConfig();
@@ -205,7 +199,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
return this.executeInternal(executor, uri, data);
} catch (WxErrorException e) {
if (retryTimes + 1 > this.maxRetryTimes) {
this.log.warn("重试达到最大次数【{}】", maxRetryTimes);
log.warn("重试达到最大次数【{}】", maxRetryTimes);
//最后一次重试失败后,直接抛出异常,不再等待
throw new RuntimeException("微信服务端异常,超出重试次数");
}
@@ -215,10 +209,10 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
if (error.getErrorCode() == -1) {
int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
try {
this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
Thread.sleep(sleepMillis);
} catch (InterruptedException e1) {
throw new RuntimeException(e1);
Thread.currentThread().interrupt();
}
} else {
throw e;
@@ -226,7 +220,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
}
} while (retryTimes++ < this.maxRetryTimes);

this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
throw new RuntimeException("微信服务端异常,超出重试次数");
}

@@ -242,7 +236,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl

try {
T result = executor.execute(uriWithAccessToken, data);
this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
return result;
} catch (WxErrorException e) {
WxError error = e.getError();
@@ -260,12 +254,12 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
}

if (error.getErrorCode() != 0) {
this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
throw new WxErrorException(error, e);
}
return null;
} catch (IOException e) {
this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
throw new RuntimeException(e);
}
}
@@ -335,4 +329,19 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl
public WxMaSettingService getSettingService() {
return this.settingService;
}

@Override
public WxMaShareService getShareService() {
return this.shareService;
}

@Override
public WxMaRunService getRunService() {
return this.runService;
}

@Override
public WxMaSecCheckService getSecCheckService() {
return this.secCheckService;
}
}

+ 23
- 0
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaShareServiceImpl.java Dosyayı Görüntüle

@@ -0,0 +1,23 @@
package cn.binarywang.wx.miniapp.api.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.WxMaShareService;
import cn.binarywang.wx.miniapp.bean.WxMaShareInfo;
import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils;

/**
* @author zhfish
*/
public class WxMaShareServiceImpl implements WxMaShareService {
private WxMaService service;

public WxMaShareServiceImpl(WxMaService service) {
this.service = service;
}

@Override
public WxMaShareInfo getShareInfo(String sessionKey, String encryptedData, String ivStr) {
return WxMaShareInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr));

}
}

+ 15
- 15
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaTemplateServiceImpl.java Dosyayı Görüntüle

@@ -1,5 +1,9 @@
package cn.binarywang.wx.miniapp.api.impl;

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

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.WxMaTemplateService;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateAddResult;
@@ -10,15 +14,11 @@ import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;

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

public class WxMaTemplateServiceImpl implements WxMaTemplateService {

private WxMaService wxMaService;

public WxMaTemplateServiceImpl(WxMaService wxMaService){
public WxMaTemplateServiceImpl(WxMaService wxMaService) {
this.wxMaService = wxMaService;
}

@@ -31,9 +31,9 @@ public class WxMaTemplateServiceImpl implements WxMaTemplateService {

String responseText = this.wxMaService.post(TEMPLATE_LIBRARY_LIST_URL, WxGsonBuilder.create().toJson(params));
WxError wxError = WxError.fromJson(responseText);
if(wxError.getErrorCode() == 0){
if (wxError.getErrorCode() == 0) {
return WxMaTemplateLibraryListResult.fromJson(responseText);
}else {
} else {
throw new WxErrorException(wxError);
}
}
@@ -46,9 +46,9 @@ public class WxMaTemplateServiceImpl implements WxMaTemplateService {

String responseText = this.wxMaService.post(TEMPLATE_LIBRARY_KEYWORD_URL, WxGsonBuilder.create().toJson(params));
WxError wxError = WxError.fromJson(responseText);
if(wxError.getErrorCode() == 0){
if (wxError.getErrorCode() == 0) {
return WxMaTemplateLibraryGetResult.fromJson(responseText);
}else {
} else {
throw new WxErrorException(wxError);
}
}
@@ -62,9 +62,9 @@ public class WxMaTemplateServiceImpl implements WxMaTemplateService {

String responseText = this.wxMaService.post(TEMPLATE_ADD_URL, WxGsonBuilder.create().toJson(params));
WxError wxError = WxError.fromJson(responseText);
if(wxError.getErrorCode() == 0){
if (wxError.getErrorCode() == 0) {
return WxMaTemplateAddResult.fromJson(responseText);
}else {
} else {
throw new WxErrorException(wxError);
}
}
@@ -78,9 +78,9 @@ public class WxMaTemplateServiceImpl implements WxMaTemplateService {

String responseText = this.wxMaService.post(TEMPLATE_LIST_URL, WxGsonBuilder.create().toJson(params));
WxError wxError = WxError.fromJson(responseText);
if(wxError.getErrorCode() == 0){
if (wxError.getErrorCode() == 0) {
return WxMaTemplateListResult.fromJson(responseText);
}else {
} else {
throw new WxErrorException(wxError);
}
}
@@ -92,9 +92,9 @@ public class WxMaTemplateServiceImpl implements WxMaTemplateService {

String responseText = this.wxMaService.post(TEMPLATE_DEL_URL, WxGsonBuilder.create().toJson(params));
WxError wxError = WxError.fromJson(responseText);
if(wxError.getErrorCode() == 0){
if (wxError.getErrorCode() == 0) {
return true;
}else {
} else {
throw new WxErrorException(wxError);
}
}


+ 1
- 3
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java Dosyayı Görüntüle

@@ -6,8 +6,6 @@ import java.io.Serializable;
import java.nio.charset.StandardCharsets;

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

import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils;
@@ -168,7 +166,7 @@ public class WxMaMessage implements Serializable {

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return this.toJson();
}

public String toJson() {


+ 38
- 0
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaRunStepInfo.java Dosyayı Görüntüle

@@ -0,0 +1,38 @@
package cn.binarywang.wx.miniapp.bean;

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

import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
import lombok.Data;

/**
* 微信运动步数信息.
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Data
public class WxMaRunStepInfo implements Serializable {
private static final JsonParser JSON_PARSER = new JsonParser();
private static final long serialVersionUID = -7496372171398607044L;

/**
* 时间戳,表示数据对应的时间.
*/
private Long timestamp;

/**
* 微信运动步数.
*/
private Integer step;

public static List<WxMaRunStepInfo> fromJson(String json) {
JsonObject jsonObject = JSON_PARSER.parse(json).getAsJsonObject();
return WxMaGsonBuilder.create().fromJson(jsonObject.get("stepInfoList").toString(),
new TypeToken<List<WxMaRunStepInfo>>() {
}.getType());
}
}

+ 20
- 0
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaShareInfo.java Dosyayı Görüntüle

@@ -0,0 +1,20 @@
package cn.binarywang.wx.miniapp.bean;

import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
import lombok.Data;

import java.io.Serializable;

/**
* @author zhfish
*/
@Data
public class WxMaShareInfo implements Serializable {
private static final long serialVersionUID = -8053613683499632226L;

private String openGId;

public static WxMaShareInfo fromJson(String json) {
return WxMaGsonBuilder.create().fromJson(json, WxMaShareInfo.class);
}
}

weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcode.java → weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxaCode.java Dosyayı Görüntüle

@@ -1,36 +1,48 @@
package cn.binarywang.wx.miniapp.bean;

import java.io.Serializable;

import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;
import lombok.NoArgsConstructor;

/**
* 小程序码.
*
* @author Element
* @date 2017/7/27
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class WxMaWxcode extends AbstractWxMaQrcodeWrapper implements Serializable {
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WxaCode extends AbstractWxMaQrcodeWrapper implements Serializable {
private static final long serialVersionUID = 1287399621649210322L;

private String path;

@Builder.Default
private int width = 430;

@SerializedName("auto_color")
@Builder.Default
private boolean autoColor = true;

@SerializedName("is_hyaline")
@Builder.Default
private boolean isHyaline = false;

@SerializedName("line_color")
@Builder.Default
private WxMaCodeLineColor lineColor = new WxMaCodeLineColor("0", "0", "0");

public static WxMaWxcode fromJson(String json) {
return WxMaGsonBuilder.create().fromJson(json, WxMaWxcode.class);
public static WxaCode fromJson(String json) {
return WxMaGsonBuilder.create().fromJson(json, WxaCode.class);
}

}

+ 24
- 2
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java Dosyayı Görüntüle

@@ -1,10 +1,10 @@
package cn.binarywang.wx.miniapp.config;

import java.util.concurrent.locks.Lock;

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

import java.util.concurrent.locks.Lock;

/**
* 小程序配置
*
@@ -57,6 +57,28 @@ public interface WxMaConfig {
*/
void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);

/**
* 卡券api_ticket.
*/
String getCardApiTicket();

Lock getCardApiTicketLock();

boolean isCardApiTicketExpired();

/**
* 强制将卡券api ticket过期掉.
*/
void expireCardApiTicket();

/**
* 应该是线程安全的.
*
* @param apiTicket 新的卡券api ticket值
* @param expiresInSeconds 过期时间,以秒为单位
*/
void updateCardApiTicket(String apiTicket, int expiresInSeconds);

String getAppid();

String getSecret();


+ 36
- 4
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java Dosyayı Görüntüle

@@ -4,9 +4,7 @@ import java.io.File;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

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

import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;

@@ -32,8 +30,14 @@ public class WxMaInMemoryConfig implements WxMaConfig {
protected volatile String jsapiTicket;
protected volatile long jsapiTicketExpiresTime;

//微信卡券的ticket单独缓存
protected volatile String cardApiTicket;
protected volatile long cardApiTicketExpiresTime;


protected Lock accessTokenLock = new ReentrantLock();
protected Lock jsapiTicketLock = new ReentrantLock();
protected Lock cardApiTicketLock = new ReentrantLock();

/**
* 临时文件目录
@@ -103,6 +107,34 @@ public class WxMaInMemoryConfig implements WxMaConfig {
this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
}


@Override
public String getCardApiTicket() {
return this.cardApiTicket;
}

@Override
public Lock getCardApiTicketLock() {
return this.cardApiTicketLock;
}

@Override
public boolean isCardApiTicketExpired() {
return System.currentTimeMillis() > this.cardApiTicketExpiresTime;
}

@Override
public void expireCardApiTicket() {
this.cardApiTicketExpiresTime = 0;
}

@Override
public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) {
this.cardApiTicket = cardApiTicket;
// 预留200秒的时间
this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
}

@Override
public void expireAccessToken() {
this.expiresTime = 0;
@@ -191,7 +223,7 @@ public class WxMaInMemoryConfig implements WxMaConfig {

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
return WxMaGsonBuilder.create().toJson(this);
}

@Override


+ 66
- 0
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeBytesRequestExecutor.java Dosyayı Görüntüle

@@ -0,0 +1,66 @@
package cn.binarywang.wx.miniapp.util;

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

import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;

import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.ResponseHandler;
import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler;
import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;

/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class QrcodeBytesRequestExecutor implements RequestExecutor<byte[], AbstractWxMaQrcodeWrapper> {
protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp;

public QrcodeBytesRequestExecutor(RequestHttp requestHttp) {
this.requestHttp = requestHttp;
}

@Override
public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler<byte[]> handler) throws WxErrorException, IOException {
handler.handle(this.execute(uri, data));
}

@Override
public byte[] execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper) throws WxErrorException, IOException {
HttpPost httpPost = new HttpPost(uri);
if (requestHttp.getRequestHttpProxy() != null) {
httpPost.setConfig(
RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build()
);
}

httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson()));

try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost);
final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
Header[] contentTypeHeader = response.getHeaders("Content-Type");
if (contentTypeHeader != null && contentTypeHeader.length > 0
&& ContentType.APPLICATION_JSON.getMimeType()
.equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) {
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
throw new WxErrorException(WxError.fromJson(responseContent));
}

return IOUtils.toByteArray(inputStream);
} finally {
httpPost.releaseConnection();
}
}
}

weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java → weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeRequestExecutor.java Dosyayı Görüntüle

@@ -1,13 +1,10 @@
package cn.binarywang.wx.miniapp.util.http;
package cn.binarywang.wx.miniapp.util;

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

import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.fs.FileUtils;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler;
import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
@@ -17,33 +14,44 @@ import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.fs.FileUtils;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.ResponseHandler;
import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler;
import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;

/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class QrCodeRequestExecutor implements RequestExecutor<File, AbstractWxMaQrcodeWrapper> {
public class QrcodeRequestExecutor implements RequestExecutor<File, AbstractWxMaQrcodeWrapper> {
protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp;

public QrCodeRequestExecutor(RequestHttp requestHttp) {
public QrcodeRequestExecutor(RequestHttp requestHttp) {
this.requestHttp = requestHttp;
}

@Override
public File execute(String uri, AbstractWxMaQrcodeWrapper ticket) throws WxErrorException, IOException {
public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler<File> handler) throws WxErrorException, IOException {
handler.handle(this.execute(uri, data));
}

@Override
public File execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper) throws WxErrorException, IOException {
HttpPost httpPost = new HttpPost(uri);
if (requestHttp.getRequestHttpProxy() != null) {
httpPost.setConfig(
RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build()
);
}
httpPost.setEntity(new StringEntity(ticket.toJson()));

try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost);
InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) {
httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson()));

try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost);
final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
Header[] contentTypeHeader = response.getHeaders("Content-Type");
if (contentTypeHeader != null && contentTypeHeader.length > 0
&& ContentType.APPLICATION_JSON.getMimeType()

+ 24
- 4
weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java Dosyayı Görüntüle

@@ -7,6 +7,9 @@ import org.testng.annotations.*;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.test.ApiTestModule;
import com.google.inject.Inject;
import me.chanjar.weixin.common.error.WxErrorException;

import static org.assertj.core.api.Assertions.assertThat;

/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
@@ -18,21 +21,38 @@ public class WxMaQrcodeServiceImplTest {
private WxMaService wxService;

@Test
public void testCreateQrCode() throws Exception {
public void testCreateQrcode() throws Exception {
final File qrCode = this.wxService.getQrcodeService().createQrcode("111", 122);
System.out.println(qrCode);
assertThat(qrCode).isNotNull();
}

@Test
public void testCreateWxaCode() throws Exception {
final File wxCode = this.wxService.getQrcodeService().createWxaCode("111", 122);
System.out.println(wxCode);
assertThat(wxCode).isNotNull();
}

@Test
public void testCreateWxaCodeUnlimit() throws Exception {
final File wxCode = this.wxService.getQrcodeService().createWxaCodeUnlimit("111", null);
System.out.println(wxCode);
assertThat(wxCode).isNotNull();
}

@Test
public void testCreateQrcodeBytes() throws WxErrorException {
final byte[] qrCode = this.wxService.getQrcodeService().createQrcodeBytes("111", 122);
assertThat(qrCode).isNotNull();
}

@Test
public void testCreateWxaCodeBytes() throws WxErrorException {
final byte[] wxCode = this.wxService.getQrcodeService().createWxaCodeBytes("111", 122, true, null, false);
assertThat(wxCode).isNotNull();
}

@Test
public void testCreateWxaCodeUnlimitBytes() throws WxErrorException {
final byte[] wxCode = this.wxService.getQrcodeService().createWxaCodeUnlimitBytes("111", null, 122, true, null, false);
assertThat(wxCode).isNotNull();
}
}

+ 51
- 0
weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImplTest.java Dosyayı Görüntüle

@@ -0,0 +1,51 @@
package cn.binarywang.wx.miniapp.api.impl;

import java.io.File;

import org.testng.annotations.*;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.test.ApiTestModule;
import com.google.inject.Inject;
import me.chanjar.weixin.common.error.WxErrorException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.*;

/**
* <pre>
*
* Created by Binary Wang on 2018/11/24.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Test
@Guice(modules = ApiTestModule.class)
public class WxMaSecCheckServiceImplTest {
@Inject
private WxMaService wxService;

@Test
public void testCheckImage() throws WxErrorException {
boolean result = this.wxService.getSecCheckService()
.checkImage(new File(ClassLoader.getSystemResource("tmp.png").getFile()));
assertTrue(result);
}

@DataProvider
public Object[][] secData() {
return new Object[][]{
{"特3456书yuuo莞6543李zxcz蒜7782法fgnv级", false},
{"完2347全dfji试3726测asad感3847知qwez到", false},
{"hello world!", true}
};
}

@Test(dataProvider = "secData")
public void testCheckMessage(String msg, boolean result) {
assertThat(this.wxService.getSecCheckService()
.checkMessage(msg))
.isEqualTo(result);
}
}

+ 0
- 5
weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java Dosyayı Görüntüle

@@ -33,9 +33,4 @@ public class WxMaServiceImplTest {
assertTrue(StringUtils.isNotBlank(after));
}

@Test
public void testImgSecCheck() throws WxErrorException {
boolean result = this.wxService.imgSecCheck(new File(ClassLoader.getSystemResource("tmp.png").getFile()));
assertTrue(result);
}
}

+ 46
- 0
weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaShareServiceImplTest.java Dosyayı Görüntüle

@@ -0,0 +1,46 @@
package cn.binarywang.wx.miniapp.api.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaShareInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.binarywang.wx.miniapp.test.ApiTestModule;
import cn.binarywang.wx.miniapp.test.TestConfig;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
import me.chanjar.weixin.common.error.WxErrorException;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;

import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;

/**
* 测试分享相关的接口
*
* @author zhfish
*/
@Test
@Guice(modules = ApiTestModule.class)
public class WxMaShareServiceImplTest {

@Inject
private WxMaService wxService;

@Test
public void testGetSessionKey() throws Exception {
assertNotNull(this.wxService.getUserService().getSessionInfo("aaa"));
}

/**
* TODO 测试数据有问题,需要替换为正确的数据
*/
@Test
public void testGetShareInfo() {
WxMaShareInfo shareInfo = this.wxService.getShareService().getShareInfo("tiihtNczf5v6AKRyjwEUhQ==",
"CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew==",
"r7BXXKkLb8qrSNn05n0qiA==");
assertNotNull(shareInfo);
System.out.println(shareInfo.toString());
}
}

+ 43
- 0
weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/bean/WxMaRunStepInfoTest.java Dosyayı Görüntüle

@@ -0,0 +1,43 @@
package cn.binarywang.wx.miniapp.bean;

import java.util.List;

import org.testng.annotations.*;

import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.*;

/**
* <pre>
*
* Created by Binary Wang on 2018/11/4.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class WxMaRunStepInfoTest {

@Test
public void testFromJson() {
// 数据来源:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/werun/wx.getWeRunData.html
String json = "{\n" +
" \"stepInfoList\": [\n" +
" {\n" +
" \"timestamp\": 1445866601,\n" +
" \"step\": 100\n" +
" },\n" +
" {\n" +
" \"timestamp\": 1445876601,\n" +
" \"step\": 120\n" +
" }\n" +
" ]\n" +
"}";

final List<WxMaRunStepInfo> stepInfoList = WxMaRunStepInfo.fromJson(json);
assertThat(stepInfoList).isNotEmpty();
assertThat(stepInfoList.get(0).getStep()).isEqualTo(100);
assertThat(stepInfoList.get(0).getTimestamp()).isEqualTo(1445866601);
assertThat(stepInfoList.get(1).getStep()).isEqualTo(120);
assertThat(stepInfoList.get(1).getTimestamp()).isEqualTo(1445876601);
}
}

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor

Yükleniyor…
İptal
Kaydet