Browse Source

Merge pull request #138 from Wechat-Group/develop

merge Develop branch
master
Binary Wang 8 years ago
committed by GitHub
parent
commit
910ba3283e
100 changed files with 3838 additions and 1739 deletions
  1. +2
    -0
      .gitignore
  2. +18
    -4
      .travis.yml
  3. +1
    -1
      build.gradle
  4. +9
    -11
      pom.xml
  5. +1
    -1
      weixin-java-common/pom.xml
  6. +10
    -11
      weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java
  7. +3
    -1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java
  8. +5
    -1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java
  9. +1
    -2
      weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxError.java
  10. +70
    -42
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSession.java
  11. +20
    -12
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java
  12. +18
    -13
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java
  13. +67
    -61
      weixin-java-cp/pom.xml
  14. +19
    -9
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
  15. +7
    -7
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java
  16. +77
    -67
      weixin-java-mp/pom.xml
  17. +41
    -5
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java
  18. +80
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java
  19. +81
    -31
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java
  20. +22
    -9
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java
  21. +150
    -27
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java
  22. +14
    -14
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java
  23. +7
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
  24. +72
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java
  25. +39
    -11
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java
  26. +267
    -206
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java
  27. +31
    -14
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
  28. +69
    -75
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java
  29. +17
    -5
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java
  30. +42
    -12
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java
  31. +12
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/AbstractDeviceBean.java
  32. +60
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java
  33. +30
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/RespMsg.java
  34. +53
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/TransMsgResp.java
  35. +117
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDevice.java
  36. +57
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceAuthorize.java
  37. +24
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceAuthorizeResult.java
  38. +38
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBind.java
  39. +24
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBindResult.java
  40. +54
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceMsg.java
  41. +54
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceQrCodeResult.java
  42. +92
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java
  43. +14
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java
  44. +2
    -1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java
  45. +0
    -267
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxPayJsSDKCallback.java
  46. +64
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxPayOrderNotifyCoupon.java
  47. +60
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxPayOrderNotifyResponse.java
  48. +130
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxPayOrderNotifyResultConverter.java
  49. +0
    -1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxEntPayQueryRequest.java
  50. +9
    -46
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxEntPayRequest.java
  51. +35
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayBaseRequest.java
  52. +123
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayDownloadBillRequest.java
  53. +2
    -86
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayRefundRequest.java
  54. +273
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayReportRequest.java
  55. +6
    -49
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPaySendRedpackRequest.java
  56. +8
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayUnifiedOrderRequest.java
  57. +104
    -13
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayBaseResult.java
  58. +15
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayCommonResult.java
  59. +392
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayOrderNotifyResult.java
  60. +81
    -76
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayOrderQueryResult.java
  61. +5
    -5
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayRedpackQueryResult.java
  62. +60
    -16
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayRefundQueryResult.java
  63. +9
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayUnifiedOrderResult.java
  64. +5
    -8
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java
  65. +2
    -1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/BaseBuilder.java
  66. +4
    -2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/BaseBuilder.java
  67. +0
    -2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java
  68. +4
    -9
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCardGsonAdapter.java
  69. +5
    -10
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCardResultGsonAdapter.java
  70. +4
    -25
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java
  71. +13
    -13
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpIndustryGsonAdapter.java
  72. +1
    -1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java
  73. +3
    -2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassOpenIdsMessageGsonAdapter.java
  74. +1
    -3
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassSendResultAdapter.java
  75. +12
    -12
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassTagMessageGsonAdapter.java
  76. +1
    -3
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassUploadResultAdapter.java
  77. +0
    -2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassVideoAdapter.java
  78. +2
    -2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsArticleGsonAdapter.java
  79. +4
    -9
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpOAuth2AccessTokenAdapter.java
  80. +1
    -3
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpSemanticQueryResultAdapter.java
  81. +0
    -1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpTemplateMessageGsonAdapter.java
  82. +7
    -15
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserCumulateGsonAdapter.java
  83. +4
    -9
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java
  84. +7
    -13
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserSummaryGsonAdapter.java
  85. +1
    -3
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxQrCodeTicketAdapter.java
  86. +4
    -4
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java
  87. +11
    -14
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java
  88. +7
    -9
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java
  89. +41
    -45
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java
  90. +67
    -67
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java
  91. +3
    -5
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java
  92. +3
    -3
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpShortUrlAPITest.java
  93. +4
    -4
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java
  94. +43
    -52
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImplTest.java
  95. +38
    -0
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImplTest.java
  96. +38
    -40
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImplTest.java
  97. +34
    -40
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java
  98. +100
    -51
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java
  99. +82
    -35
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java
  100. +15
    -10
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImplTest.java

+ 2
- 0
.gitignore View File

@@ -48,3 +48,5 @@ Icon
Network Trash Folder Network Trash Folder
Temporary Items Temporary Items
.apdisk .apdisk
/.sonar/
sonar-project.properties

+ 18
- 4
.travis.yml View File

@@ -1,12 +1,26 @@
language: java language: java
jdk:
- oraclejdk7

script: "mvn clean package -Dmaven.test.skip=true"
sudo: false
install: true
addons:
sonarqube:
token:
secure: "834110c7191f97ecb226970c46dcaff8e681da5a"


jdk:
- oraclejdk8
#script: "mvn clean package -Dmaven.test.skip=true"
script:
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar
branches: branches:
only: only:
- develop - develop
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.sonar/cache'


notifications: notifications:
email: email:


+ 1
- 1
build.gradle View File

@@ -2,7 +2,7 @@ allprojects {
apply plugin: 'maven' apply plugin: 'maven'


group = 'com.github.binarywang' group = 'com.github.binarywang'
version = '2.4.0'
version = '2.5.0-SNAPSHOT'
} }


subprojects { subprojects {


+ 9
- 11
pom.xml View File

@@ -1,11 +1,11 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<project <project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.github.binarywang</groupId> <groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId> <artifactId>weixin-java-parent</artifactId>
<version>2.4.0</version>
<version>2.5.0</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>WeiXin Java Tools - Parent</name> <name>WeiXin Java Tools - Parent</name>
<description>微信公众号、企业号上级POM</description> <description>微信公众号、企业号上级POM</description>
@@ -69,6 +69,11 @@
<email>dongfuqiang1988@163.com</email> <email>dongfuqiang1988@163.com</email>
<url>https://github.com/johnnytung</url> <url>https://github.com/johnnytung</url>
</developer> </developer>
<developer>
<name>Jonk</name>
<email>aimilin@yeah.net</email>
<url>https://github.com/aimilin6688</url>
</developer>
</developers> </developers>


<scm> <scm>
@@ -94,7 +99,6 @@
<httpclient.version>4.5</httpclient.version> <httpclient.version>4.5</httpclient.version>
<slf4j.version>1.7.10</slf4j.version> <slf4j.version>1.7.10</slf4j.version>
<logback.version>1.1.2</logback.version> <logback.version>1.1.2</logback.version>
<jedis.version>2.9.0</jedis.version>
<gson.version>2.7</gson.version> <gson.version>2.7</gson.version>
<guava.version>19.0</guava.version> <guava.version>19.0</guava.version>
<commons-lang3.version>3.5</commons-lang3.version> <commons-lang3.version>3.5</commons-lang3.version>
@@ -145,12 +149,6 @@
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version> <version>${commons-lang3.version}</version>
</dependency> </dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
@@ -302,7 +300,7 @@
<configuration> <configuration>
<serverId>ossrh</serverId> <serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl> <nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>false</autoReleaseAfterClose>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>


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

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


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


+ 10
- 11
weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java View File

@@ -8,9 +8,9 @@ import java.io.Serializable;
public class WxJsapiSignature implements Serializable { public class WxJsapiSignature implements Serializable {
private static final long serialVersionUID = -1116808193154384804L; private static final long serialVersionUID = -1116808193154384804L;


private String appid;
private String appId;


private String noncestr;
private String nonceStr;


private long timestamp; private long timestamp;


@@ -26,12 +26,12 @@ public class WxJsapiSignature implements Serializable {
this.signature = signature; this.signature = signature;
} }


public String getNoncestr() {
return this.noncestr;
public String getNonceStr() {
return nonceStr;
} }


public void setNoncestr(String noncestr) {
this.noncestr = noncestr;
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
} }


public long getTimestamp() { public long getTimestamp() {
@@ -50,12 +50,11 @@ public class WxJsapiSignature implements Serializable {
this.url = url; this.url = url;
} }


public String getAppid() {
return this.appid;
public String getAppId() {
return appId;
} }


public void setAppid(String appid) {
this.appid = appid;
public void setAppId(String appId) {
this.appId = appId;
} }

} }

+ 3
- 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuButton.java View File

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


import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.ToStringUtils;


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


public class WxMenuButton {
public class WxMenuButton implements Serializable {
private static final long serialVersionUID = -1070939403109776555L;


private String type; private String type;
private String name; private String name;


+ 5
- 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/menu/WxMenuRule.java View File

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


import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.ToStringUtils;


public class WxMenuRule {
import java.io.Serializable;

public class WxMenuRule implements Serializable {
private static final long serialVersionUID = -4587181819499286670L;

private String tagId; private String tagId;
private String sex; private String sex;
private String country; private String country;


+ 1
- 2
weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxError.java View File

@@ -20,8 +20,7 @@ public class WxError implements Serializable {
private String json; private String json;


public static WxError fromJson(String json) { public static WxError fromJson(String json) {
WxError error = WxGsonBuilder.create().fromJson(json, WxError.class);
return error;
return WxGsonBuilder.create().fromJson(json, WxError.class);
} }


public static Builder newBuilder() { public static Builder newBuilder() {


+ 70
- 42
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSession.java View File

@@ -11,12 +11,12 @@ public class StandardSession implements WxSession, InternalSession {
/** /**
* The string manager for this package. * The string manager for this package.
*/ */
protected static final StringManager sm =
StringManager.getManager(Constants.Package);
protected static final StringManager sm = StringManager.getManager(Constants.Package);
/** /**
* Type array. * Type array.
*/ */
protected static final String EMPTY_ARRAY[] = new String[0];
private static final String[] EMPTY_ARRAY = new String[0];

// ------------------------------ WxSession // ------------------------------ WxSession
protected Map<String, Object> attributes = new ConcurrentHashMap<>(); protected Map<String, Object> attributes = new ConcurrentHashMap<>();
/** /**
@@ -71,20 +71,23 @@ public class StandardSession implements WxSession, InternalSession {
@Override @Override
public Object getAttribute(String name) { public Object getAttribute(String name) {


if (!isValidInternal())
if (!isValidInternal()) {
throw new IllegalStateException throw new IllegalStateException
(sm.getString("sessionImpl.getAttribute.ise"));
(sm.getString("sessionImpl.getAttribute.ise"));
}


if (name == null) return null;
if (name == null) {
return null;
}


return (this.attributes.get(name));
return this.attributes.get(name);
} }


@Override @Override
public Enumeration<String> getAttributeNames() { public Enumeration<String> getAttributeNames() {
if (!isValidInternal())
throw new IllegalStateException
(sm.getString("sessionImpl.getAttributeNames.ise"));
if (!isValidInternal()) {
throw new IllegalStateException(sm.getString("sessionImpl.getAttributeNames.ise"));
}


Set<String> names = new HashSet<>(); Set<String> names = new HashSet<>();
names.addAll(this.attributes.keySet()); names.addAll(this.attributes.keySet());
@@ -94,9 +97,9 @@ public class StandardSession implements WxSession, InternalSession {
@Override @Override
public void setAttribute(String name, Object value) { public void setAttribute(String name, Object value) {
// Name cannot be null // Name cannot be null
if (name == null)
throw new IllegalArgumentException
(sm.getString("sessionImpl.setAttribute.namenull"));
if (name == null) {
throw new IllegalArgumentException(sm.getString("sessionImpl.setAttribute.namenull"));
}


// Null value is the same as removeAttribute() // Null value is the same as removeAttribute()
if (value == null) { if (value == null) {
@@ -105,9 +108,9 @@ public class StandardSession implements WxSession, InternalSession {
} }


// Validate our current state // Validate our current state
if (!isValidInternal())
throw new IllegalStateException(sm.getString(
"sessionImpl.setAttribute.ise", getIdInternal()));
if (!isValidInternal()) {
throw new IllegalStateException(sm.getString("sessionImpl.setAttribute.ise", getIdInternal()));
}


this.attributes.put(name, value); this.attributes.put(name, value);


@@ -121,8 +124,7 @@ public class StandardSession implements WxSession, InternalSession {
@Override @Override
public void invalidate() { public void invalidate() {
if (!isValidInternal()) if (!isValidInternal())
throw new IllegalStateException
(sm.getString("sessionImpl.invalidate.ise"));
throw new IllegalStateException(sm.getString("sessionImpl.invalidate.ise"));


// Cause this session to expire // Cause this session to expire
expire(); expire();
@@ -131,12 +133,11 @@ public class StandardSession implements WxSession, InternalSession {


@Override @Override
public WxSession getSession() { public WxSession getSession() {

if (this.facade == null) { if (this.facade == null) {
this.facade = new StandardSessionFacade(this); this.facade = new StandardSessionFacade(this);
} }
return (this.facade);


return this.facade;
} }


/** /**
@@ -185,12 +186,14 @@ public class StandardSession implements WxSession, InternalSession {


@Override @Override
public String getIdInternal() { public String getIdInternal() {
return (this.id);
return this.id;
} }


protected void removeAttributeInternal(String name) { protected void removeAttributeInternal(String name) {
// Avoid NPE // Avoid NPE
if (name == null) return;
if (name == null) {
return;
}


// Remove this attribute from our collection // Remove this attribute from our collection
this.attributes.remove(name); this.attributes.remove(name);
@@ -202,19 +205,22 @@ public class StandardSession implements WxSession, InternalSession {
// Check to see if session has already been invalidated. // Check to see if session has already been invalidated.
// Do not check expiring at this point as expire should not return until // Do not check expiring at this point as expire should not return until
// isValid is false // isValid is false
if (!this.isValid)
if (!this.isValid) {
return; return;
}


synchronized (this) { synchronized (this) {
// Check again, now we are inside the sync so this code only runs once // Check again, now we are inside the sync so this code only runs once
// Double check locking - isValid needs to be volatile // Double check locking - isValid needs to be volatile
// The check of expiring is to ensure that an infinite loop is not // The check of expiring is to ensure that an infinite loop is not
// entered as per bug 56339 // entered as per bug 56339
if (this.expiring || !this.isValid)
if (this.expiring || !this.isValid) {
return; return;
}


if (this.manager == null)
if (this.manager == null) {
return; return;
}


// Mark this session as "being expired" // Mark this session as "being expired"
this.expiring = true; this.expiring = true;
@@ -230,9 +236,9 @@ public class StandardSession implements WxSession, InternalSession {
this.expiring = false; this.expiring = false;


// Unbind any objects associated with this session // Unbind any objects associated with this session
String keys[] = keys();
for (int i = 0; i < keys.length; i++) {
removeAttributeInternal(keys[i]);
String[] keys = keys();
for (String key : keys) {
removeAttributeInternal(key);
} }
} }


@@ -273,13 +279,15 @@ public class StandardSession implements WxSession, InternalSession {


@Override @Override
public void setId(String id) { public void setId(String id) {
if ((this.id != null) && (this.manager != null))
if ((this.id != null) && (this.manager != null)) {
this.manager.remove(this); this.manager.remove(this);
}


this.id = id; this.id = id;


if (this.manager != null)
if (this.manager != null) {
this.manager.add(this); this.manager.add(this);
}
} }


/** /**
@@ -295,21 +303,41 @@ public class StandardSession implements WxSession, InternalSession {


@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof StandardSession)) return false;
if (this == o) {
return true;
}
if (!(o instanceof StandardSession)) {
return false;
}


StandardSession session = (StandardSession) o; StandardSession session = (StandardSession) o;


if (this.creationTime != session.creationTime) return false;
if (this.expiring != session.expiring) return false;
if (this.isValid != session.isValid) return false;
if (this.maxInactiveInterval != session.maxInactiveInterval) return false;
if (this.thisAccessedTime != session.thisAccessedTime) return false;
if (!this.accessCount.equals(session.accessCount)) return false;
if (!this.attributes.equals(session.attributes)) return false;
if (!this.facade.equals(session.facade)) return false;
if (!this.id.equals(session.id)) return false;
return this.manager.equals(session.manager);
if (this.creationTime != session.creationTime) {
return false;
}
if (this.expiring != session.expiring) {
return false;
}
if (this.isValid != session.isValid) {
return false;
}
if (this.maxInactiveInterval != session.maxInactiveInterval) {
return false;
}
if (this.thisAccessedTime != session.thisAccessedTime) {
return false;
}
if (this.accessCount.get() != session.accessCount.get()) {
return false;
}
if (!this.attributes.equals(session.attributes)) {
return false;
}
if (!this.facade.equals(session.facade)) {
return false;
}

return this.id.equals(session.id) && this.manager.equals(session.manager);


} }




+ 20
- 12
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java View File

@@ -6,6 +6,9 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
@@ -21,24 +24,28 @@ import java.util.Map;
* </pre> * </pre>
*/ */
public class BeanUtils { public class BeanUtils {
private static Logger log = LoggerFactory.getLogger(BeanUtils.class);


/** /**
* 检查bean里标记为@Required的field是否为空,为空则抛异常 * 检查bean里标记为@Required的field是否为空,为空则抛异常
*
* @param bean 要检查的bean对象 * @param bean 要检查的bean对象
* @throws WxErrorException * @throws WxErrorException
*/ */
public static void checkRequiredFields(Object bean) throws WxErrorException { public static void checkRequiredFields(Object bean) throws WxErrorException {
List<String> nullFields = Lists.newArrayList();
List<String> requiredFields = Lists.newArrayList();


List<Field> fields = new ArrayList<>( Arrays.asList(bean.getClass().getDeclaredFields()));
List<Field> fields = new ArrayList<>(Arrays.asList(bean.getClass().getDeclaredFields()));
fields.addAll(Arrays.asList(bean.getClass().getSuperclass().getDeclaredFields())); fields.addAll(Arrays.asList(bean.getClass().getSuperclass().getDeclaredFields()));
for (Field field : fields) { for (Field field : fields) {
try { try {
boolean isAccessible = field.isAccessible(); boolean isAccessible = field.isAccessible();
field.setAccessible(true); field.setAccessible(true);
if (field.isAnnotationPresent(Required.class)
&& field.get(bean) == null) {
nullFields.add(field.getName());
if (field.isAnnotationPresent(Required.class)) {
if (field.get(bean) == null || (field.get(bean) instanceof String && StringUtils.isBlank(field.get(bean).toString()))) {
//两种情况,一种是值为null,另外一种情况是类型为字符串,但是字符串内容为空的,都认为是没有提供值
requiredFields.add(field.getName());
}
} }
field.setAccessible(isAccessible); field.setAccessible(isAccessible);
} catch (SecurityException | IllegalArgumentException } catch (SecurityException | IllegalArgumentException
@@ -47,19 +54,22 @@ public class BeanUtils {
} }
} }


if (!nullFields.isEmpty()) {
throw new WxErrorException(WxError.newBuilder().setErrorMsg("必填字段 " + nullFields + " 必须提供值").build());
if (!requiredFields.isEmpty()) {
String msg = "必填字段 " + requiredFields + " 必须提供值";
log.debug(msg);
throw new WxErrorException(WxError.newBuilder().setErrorMsg(msg).build());
} }
} }


/** /**
* 将bean按照@XStreamAlias标识的字符串内容生成以之为key的map对象 * 将bean按照@XStreamAlias标识的字符串内容生成以之为key的map对象
*
* @param bean 包含@XStreamAlias的xml bean对象 * @param bean 包含@XStreamAlias的xml bean对象
* @return map对象 * @return map对象
*/ */
public static Map<String, String> xmlBean2Map(Object bean) { public static Map<String, String> xmlBean2Map(Object bean) {
Map<String, String> result = Maps.newHashMap(); Map<String, String> result = Maps.newHashMap();
List<Field> fields = new ArrayList<>( Arrays.asList(bean.getClass().getDeclaredFields()));
List<Field> fields = new ArrayList<>(Arrays.asList(bean.getClass().getDeclaredFields()));
fields.addAll(Arrays.asList(bean.getClass().getSuperclass().getDeclaredFields())); fields.addAll(Arrays.asList(bean.getClass().getSuperclass().getDeclaredFields()));
for (Field field : fields) { for (Field field : fields) {
try { try {
@@ -71,13 +81,11 @@ public class BeanUtils {
} }


if (field.isAnnotationPresent(XStreamAlias.class)) { if (field.isAnnotationPresent(XStreamAlias.class)) {
result.put(field.getAnnotation(XStreamAlias.class).value(),
field.get(bean).toString());
result.put(field.getAnnotation(XStreamAlias.class).value(), field.get(bean).toString());
} }


field.setAccessible(isAccessible); field.setAccessible(isAccessible);
} catch (SecurityException | IllegalArgumentException
| IllegalAccessException e) {
} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace(); e.printStackTrace();
} }




+ 18
- 13
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java View File

@@ -8,21 +8,13 @@
*/ */
package me.chanjar.weixin.common.util.json; package me.chanjar.weixin.common.util.json;


import java.lang.reflect.Type;

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 com.google.gson.*;
import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.bean.menu.WxMenuButton; import me.chanjar.weixin.common.bean.menu.WxMenuButton;
import me.chanjar.weixin.common.bean.menu.WxMenuRule; import me.chanjar.weixin.common.bean.menu.WxMenuRule;


import java.lang.reflect.Type;



/** /**
* @author Daniel Qian * @author Daniel Qian
@@ -76,6 +68,20 @@ public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializ
return matchRule; return matchRule;
} }


private WxMenuRule convertToRule(JsonObject json) {
WxMenuRule menuRule = new WxMenuRule();
//变态的微信接口,这里居然反人类的使用和序列化时不一样的名字
//menuRule.setTagId(GsonHelper.getString(json,"tag_id"));
menuRule.setTagId(GsonHelper.getString(json, "group_id"));
menuRule.setSex(GsonHelper.getString(json, "sex"));
menuRule.setCountry(GsonHelper.getString(json, "country"));
menuRule.setProvince(GsonHelper.getString(json, "province"));
menuRule.setCity(GsonHelper.getString(json, "city"));
menuRule.setClientPlatformType(GsonHelper.getString(json, "client_platform_type"));
menuRule.setLanguage(GsonHelper.getString(json, "language"));
return menuRule;
}

@Override @Override
public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
/* /*
@@ -84,8 +90,7 @@ public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializ
* 查询菜单时是 { menu : { button : ... } } * 查询菜单时是 { menu : { button : ... } }
*/ */
WxMenu menu = new WxMenu(); WxMenu menu = new WxMenu();
JsonObject menuJson = json.getAsJsonObject().get("menu").getAsJsonObject();
JsonArray buttonsJson = menuJson.get("button").getAsJsonArray();
JsonArray buttonsJson = json.getAsJsonObject().get("menu").getAsJsonObject().get("button").getAsJsonArray();
for (int i = 0; i < buttonsJson.size(); i++) { for (int i = 0; i < buttonsJson.size(); i++) {
JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject(); JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject();
WxMenuButton button = convertFromJson(buttonJson); WxMenuButton button = convertFromJson(buttonJson);


+ 67
- 61
weixin-java-cp/pom.xml View File

@@ -1,68 +1,74 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<project <project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>2.4.0</version>
</parent>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>2.5.0</version>
</parent>


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


<dependencies>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<optional>true</optional>
</dependency>
</dependencies>


<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>


</project> </project>

+ 19
- 9
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java View File

@@ -166,12 +166,12 @@ public class WxCpServiceImpl implements WxCpService {
); );
WxJsapiSignature jsapiSignature = new WxJsapiSignature(); WxJsapiSignature jsapiSignature = new WxJsapiSignature();
jsapiSignature.setTimestamp(timestamp); jsapiSignature.setTimestamp(timestamp);
jsapiSignature.setNoncestr(noncestr);
jsapiSignature.setNonceStr(noncestr);
jsapiSignature.setUrl(url); jsapiSignature.setUrl(url);
jsapiSignature.setSignature(signature); jsapiSignature.setSignature(signature);


// Fixed bug // Fixed bug
jsapiSignature.setAppid(this.configStorage.getCorpId());
jsapiSignature.setAppId(this.configStorage.getCorpId());


return jsapiSignature; return jsapiSignature;
} }
@@ -491,7 +491,7 @@ public class WxCpServiceImpl implements WxCpService {
String responseText = get(url, null); String responseText = get(url, null);
JsonElement je = new JsonParser().parse(responseText); JsonElement je = new JsonParser().parse(responseText);
JsonObject jo = je.getAsJsonObject(); JsonObject jo = je.getAsJsonObject();
return new String[]{GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId")};
return new String[]{GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId"), GsonHelper.getString(jo, "OpenId")};
} }


@Override @Override
@@ -538,8 +538,16 @@ public class WxCpServiceImpl implements WxCpService {
int retryTimes = 0; int retryTimes = 0;
do { do {
try { try {
return executeInternal(executor, uri, data);
T result = this.executeInternal(executor, uri, data);
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",uri, data, result);
return result;
} catch (WxErrorException e) { } catch (WxErrorException e) {
if (retryTimes + 1 > this.maxRetryTimes) {
this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
//最后一次重试失败后,直接抛出异常,不再等待
throw new RuntimeException("微信服务端异常,超出重试次数");
}

WxError error = e.getError(); WxError error = e.getError();
/* /*
* -1 系统繁忙, 1000ms后重试 * -1 系统繁忙, 1000ms后重试
@@ -547,8 +555,7 @@ public class WxCpServiceImpl implements WxCpService {
if (error.getErrorCode() == -1) { if (error.getErrorCode() == -1) {
int sleepMillis = this.retrySleepMillis * (1 << retryTimes); int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
try { try {
this.log.debug("微信系统繁忙,{}ms 后重试(第{}次)", sleepMillis,
retryTimes + 1);
this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
Thread.sleep(sleepMillis); Thread.sleep(sleepMillis);
} catch (InterruptedException e1) { } catch (InterruptedException e1) {
throw new RuntimeException(e1); throw new RuntimeException(e1);
@@ -557,8 +564,9 @@ public class WxCpServiceImpl implements WxCpService {
throw e; throw e;
} }
} }
} while (++retryTimes < this.maxRetryTimes);
} while (retryTimes++ < this.maxRetryTimes);


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


@@ -572,8 +580,7 @@ public class WxCpServiceImpl implements WxCpService {
uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken;


try { try {
return executor.execute(getHttpclient(), this.httpProxy,
uriWithAccessToken, data);
return executor.execute(getHttpclient(), this.httpProxy, uriWithAccessToken, data);
} catch (WxErrorException e) { } catch (WxErrorException e) {
WxError error = e.getError(); WxError error = e.getError();
/* /*
@@ -586,11 +593,14 @@ public class WxCpServiceImpl implements WxCpService {
this.configStorage.expireAccessToken(); this.configStorage.expireAccessToken();
return execute(executor, uri, data); return execute(executor, uri, data);
} }

if (error.getErrorCode() != 0) { if (error.getErrorCode() != 0) {
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error);
throw new WxErrorException(error); throw new WxErrorException(error);
} }
return null; return null;
} catch (IOException e) { } catch (IOException e) {
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", uri, data, e.getMessage());
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }


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

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


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

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


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

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

@Test @Test
public class WxCpBusyRetryTest { public class WxCpBusyRetryTest {


@@ -23,6 +22,7 @@ public class WxCpBusyRetryTest {
protected synchronized <T, E> T executeInternal( protected synchronized <T, E> T executeInternal(
RequestExecutor<T, E> executor, String uri, E data) RequestExecutor<T, E> executor, String uri, E data)
throws WxErrorException { throws WxErrorException {
this.log.info("Executed");
WxError error = new WxError(); WxError error = new WxError();
error.setErrorCode(-1); error.setErrorCode(-1);
throw new WxErrorException(error); throw new WxErrorException(error);


+ 77
- 67
weixin-java-mp/pom.xml View File

@@ -1,73 +1,83 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<project <project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>2.4.0</version>
</parent>
<artifactId>weixin-java-mp</artifactId>
<name>WeiXin Java Tools - MP</name>
<description>微信公众号Java SDK</description>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>2.5.0</version>
</parent>
<artifactId>weixin-java-mp</artifactId>
<name>WeiXin Java Tools - MP</name>
<description>微信公众号Java SDK</description>


<dependencies>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>xml-path</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>qrcode-utils</artifactId>
<version>1.0</version>
</dependency>
</dependencies>


<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>


</project> </project>

+ 41
- 5
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java View File

@@ -9,8 +9,8 @@ import java.util.concurrent.locks.Lock;


/** /**
* 微信客户端配置存储 * 微信客户端配置存储
* @author chanjarster
* *
* @author chanjarster
*/ */
public interface WxMpConfigStorage { public interface WxMpConfigStorage {


@@ -27,13 +27,15 @@ public interface WxMpConfigStorage {


/** /**
* 应该是线程安全的 * 应该是线程安全的
*
* @param accessToken 要更新的WxAccessToken对象 * @param accessToken 要更新的WxAccessToken对象
*/ */
void updateAccessToken(WxAccessToken accessToken); void updateAccessToken(WxAccessToken accessToken);


/** /**
* 应该是线程安全的 * 应该是线程安全的
* @param accessToken 新的accessToken值
*
* @param accessToken 新的accessToken值
* @param expiresInSeconds 过期时间,以秒为单位 * @param expiresInSeconds 过期时间,以秒为单位
*/ */
void updateAccessToken(String accessToken, int expiresInSeconds); void updateAccessToken(String accessToken, int expiresInSeconds);
@@ -51,7 +53,8 @@ public interface WxMpConfigStorage {


/** /**
* 应该是线程安全的 * 应该是线程安全的
* @param jsapiTicket 新的jsapi ticket值
*
* @param jsapiTicket 新的jsapi ticket值
* @param expiresInSeconds 过期时间,以秒为单位 * @param expiresInSeconds 过期时间,以秒为单位
*/ */
void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
@@ -69,7 +72,8 @@ public interface WxMpConfigStorage {


/** /**
* 应该是线程安全的 * 应该是线程安全的
* @param cardApiTicket 新的cardApi ticket值
*
* @param cardApiTicket 新的cardApi ticket值
* @param expiresInSeconds 过期时间,以秒为单位 * @param expiresInSeconds 过期时间,以秒为单位
*/ */
void updateCardApiTicket(String cardApiTicket, int expiresInSeconds); void updateCardApiTicket(String cardApiTicket, int expiresInSeconds);
@@ -82,6 +86,23 @@ public interface WxMpConfigStorage {


String getPartnerKey(); String getPartnerKey();


/**
* 微信支付异步回掉地址,通知url必须为直接可访问的url,不能携带参数。
*
* @since 2.5.0
*/
String getNotifyURL();

/**
* 交易类型
* <pre>
* JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付
* </pre>
*
* @since 2.5.0
*/
String getTradeType();

String getToken(); String getToken();


String getAesKey(); String getAesKey();
@@ -100,10 +121,20 @@ public interface WxMpConfigStorage {


File getTmpDirFile(); File getTmpDirFile();


SSLContext getSSLContext();
SSLContext getSslContext();

void setSslContext(SSLContext sslContext);

/**
* 在此之前,必须将partnerId进行赋值
*
* @param filePath apiclient_cert.p12的文件的绝对路径
*/
void setSslContextFilePath(String filePath) throws Exception;


/** /**
* http client builder * http client builder
*
* @return ApacheHttpClientBuilder * @return ApacheHttpClientBuilder
*/ */
ApacheHttpClientBuilder getApacheHttpClientBuilder(); ApacheHttpClientBuilder getApacheHttpClientBuilder();
@@ -112,4 +143,9 @@ public interface WxMpConfigStorage {
* 是否自动刷新token * 是否自动刷新token
*/ */
boolean autoRefreshToken(); boolean autoRefreshToken();

/**
* 微信支付是否使用仿真测试环境
*/
boolean useSandboxForWxPay();
} }

+ 80
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java View File

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

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.device.*;

/**
* Created by keungtung on 10/12/2016.
*/
public interface WxMpDeviceService {
/**
* <pre>
* 主动发送消息给设备
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-3
* </pre>
*/
TransMsgResp transMsg(WxDeviceMsg msg) throws WxErrorException;

/**
* <pre>
* 获取一组新的deviceid和设备二维码
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-6
* </pre>
* @param productId 产品id
* @return 返回WxDeviceQrCodeResult
*/
WxDeviceQrCodeResult getQrCode(String productId) throws WxErrorException;

/**
* <pre>
* 将device id及其属性信息提交公众平台进行授权
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-6
* </pre>
* @param wxDeviceAuthorize 授权请求对象
* @return WxDeviceAuthorizeResult
*/
WxDeviceAuthorizeResult authorize(WxDeviceAuthorize wxDeviceAuthorize) throws WxErrorException;


/**
* <pre>
* 第三方后台绑定成功后,通知公众平台
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html/page=3-4-7
* </pre>
* @param wxDeviceBind 绑定请求对象
* @return WxDeviceBindResult
*/
WxDeviceBindResult bind(WxDeviceBind wxDeviceBind) throws WxErrorException;

/**
* <pre>
* 强制绑定用户和设备
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-7
* </pre>
* @param wxDeviceBind 强制绑定请求对象
* @return WxDeviceBindResult
*/
WxDeviceBindResult compelBind(WxDeviceBind wxDeviceBind) throws WxErrorException;

/**
* <pre>
* 第三方确认用户和设备的解绑操作
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html/page=3-4-7
* </pre>
* @param wxDeviceBind 绑定请求对象
* @return WxDeviceBidResult
*/
WxDeviceBindResult unbind(WxDeviceBind wxDeviceBind) throws WxErrorException;

/**
* <pre>
* 强制解绑用户和设备
* 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-7
* </pre>
* @param wxDeviceBind 强制解绑请求对象
* @return WxDeviceBindResult
*/
WxDeviceBindResult compelUnbind(WxDeviceBind wxDeviceBind) throws WxErrorException;


}

+ 81
- 31
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java View File

@@ -3,16 +3,19 @@ package me.chanjar.weixin.mp.api;
import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.ToStringUtils;
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
import org.apache.http.ssl.SSLContexts;


import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;


/** /**
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
* @author chanjarster
* *
* @author chanjarster
*/ */
public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {


@@ -20,6 +23,8 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
protected volatile String secret; protected volatile String secret;
protected volatile String partnerId; protected volatile String partnerId;
protected volatile String partnerKey; protected volatile String partnerKey;
protected volatile String notifyURL;
protected volatile String tradeType;
protected volatile String token; protected volatile String token;
protected volatile String accessToken; protected volatile String accessToken;
protected volatile String aesKey; protected volatile String aesKey;
@@ -56,6 +61,10 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
return this.accessToken; return this.accessToken;
} }


public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}

@Override @Override
public Lock getAccessTokenLock() { public Lock getAccessTokenLock() {
return this.accessTokenLock; return this.accessTokenLock;
@@ -87,15 +96,15 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
return this.jsapiTicket; return this.jsapiTicket;
} }


public void setJsapiTicket(String jsapiTicket) {
this.jsapiTicket = jsapiTicket;
}

@Override @Override
public Lock getJsapiTicketLock() { public Lock getJsapiTicketLock() {
return this.jsapiTicketLock; return this.jsapiTicketLock;
} }


public void setJsapiTicket(String jsapiTicket) {
this.jsapiTicket = jsapiTicket;
}

public long getJsapiTicketExpiresTime() { public long getJsapiTicketExpiresTime() {
return this.jsapiTicketExpiresTime; return this.jsapiTicketExpiresTime;
} }
@@ -156,31 +165,35 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
return this.appId; return this.appId;
} }


public void setAppId(String appId) {
this.appId = appId;
}

@Override @Override
public String getSecret() { public String getSecret() {
return this.secret; return this.secret;
} }


public void setSecret(String secret) {
this.secret = secret;
}

@Override @Override
public String getToken() { public String getToken() {
return this.token; return this.token;
} }


public void setToken(String token) {
this.token = token;
}

@Override @Override
public long getExpiresTime() { public long getExpiresTime() {
return this.expiresTime; return this.expiresTime;
} }


public void setAppId(String appId) {
this.appId = appId;
}

public void setSecret(String secret) {
this.secret = secret;
}

public void setToken(String token) {
this.token = token;
public void setExpiresTime(long expiresTime) {
this.expiresTime = expiresTime;
} }


@Override @Override
@@ -192,14 +205,6 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
this.aesKey = aesKey; this.aesKey = aesKey;
} }


public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}

public void setExpiresTime(long expiresTime) {
this.expiresTime = expiresTime;
}

@Override @Override
public String getOauth2redirectUri() { public String getOauth2redirectUri() {
return this.oauth2redirectUri; return this.oauth2redirectUri;
@@ -252,20 +257,37 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {


@Override @Override
public String getPartnerId() { public String getPartnerId() {
return this.partnerId;
return this.partnerId;
} }


public void setPartnerId(String partnerId) { public void setPartnerId(String partnerId) {
this.partnerId = partnerId;
this.partnerId = partnerId;
} }


@Override @Override
public String getPartnerKey() { public String getPartnerKey() {
return this.partnerKey;
return this.partnerKey;
} }


public void setPartnerKey(String partnerKey) { public void setPartnerKey(String partnerKey) {
this.partnerKey = partnerKey;
this.partnerKey = partnerKey;
}


public String getNotifyURL() {
return notifyURL;
}

public void setNotifyURL(String notifyURL) {
this.notifyURL = notifyURL;
}

public String getTradeType() {
return tradeType;
}

public void setTradeType(String tradeType) {
this.tradeType = tradeType;
} }


@Override @Override
@@ -278,25 +300,53 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
} }


@Override @Override
public SSLContext getSSLContext() {
public SSLContext getSslContext() {
return this.sslContext; return this.sslContext;
} }


public void setSSLContext(SSLContext context) {
@Override
public void setSslContext(SSLContext context) {
this.sslContext = context; this.sslContext = context;
} }


@Override
public void setSslContextFilePath(String filePath) {
if (null == partnerId) {
throw new IllegalArgumentException("请设置partnerId的值");
}

File file = new File(filePath);
if (!file.exists()) {
throw new RuntimeException("证书文件:【" + file.getPath() + "】不存在!");
}

try {
FileInputStream inputStream = new FileInputStream(file);
KeyStore keystore = KeyStore.getInstance("PKCS12");
char[] partnerId2charArray = partnerId.toCharArray();
keystore.load(inputStream, partnerId2charArray);
this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build();
} catch (Exception e) {
throw new RuntimeException("证书文件有问题,请核实!", e);
}
}

@Override @Override
public ApacheHttpClientBuilder getApacheHttpClientBuilder() { public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
return this.apacheHttpClientBuilder; return this.apacheHttpClientBuilder;
} }


public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) {
this.apacheHttpClientBuilder = apacheHttpClientBuilder;
}

@Override @Override
public boolean autoRefreshToken() { public boolean autoRefreshToken() {
return true; return true;
} }


public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) {
this.apacheHttpClientBuilder = apacheHttpClientBuilder;
@Override
public boolean useSandboxForWxPay() {
return false;
} }
} }

+ 22
- 9
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java View File

@@ -3,6 +3,7 @@ package me.chanjar.weixin.mp.api;
import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult; import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
import me.chanjar.weixin.mp.bean.menu.WxMpMenu;


/** /**
* 菜单相关操作接口 * 菜单相关操作接口
@@ -14,17 +15,29 @@ public interface WxMpMenuService {
/** /**
* <pre> * <pre>
* 自定义菜单创建接口 * 自定义菜单创建接口
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
* 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
* 如果要创建个性化菜单,请设置matchrule属性 * 如果要创建个性化菜单,请设置matchrule属性
* 详情请见:http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
* 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
* </pre> * </pre>
* @return 如果是个性化菜单,则返回menuid,否则返回null
*/ */
void menuCreate(WxMenu menu) throws WxErrorException;
String menuCreate(WxMenu menu) throws WxErrorException;

/**
* <pre>
* 自定义菜单创建接口
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
* 如果要创建个性化菜单,请设置matchrule属性
* 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
* </pre>
* @return 如果是个性化菜单,则返回menuid,否则返回null
*/
String menuCreate(String json) throws WxErrorException;


/** /**
* <pre> * <pre>
* 自定义菜单删除接口 * 自定义菜单删除接口
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN
* </pre> * </pre>
*/ */
void menuDelete() throws WxErrorException; void menuDelete() throws WxErrorException;
@@ -32,20 +45,20 @@ public interface WxMpMenuService {
/** /**
* <pre> * <pre>
* 删除个性化菜单接口 * 删除个性化菜单接口
* 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
* </pre> * </pre>
* *
* @param menuid
* @param menuId 个性化菜单的menuid
*/ */
void menuDelete(String menuid) throws WxErrorException;
void menuDelete(String menuId) throws WxErrorException;


/** /**
* <pre> * <pre>
* 自定义菜单查询接口 * 自定义菜单查询接口
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN
* </pre> * </pre>
*/ */
WxMenu menuGet() throws WxErrorException;
WxMpMenu menuGet() throws WxErrorException;


/** /**
* <pre> * <pre>


+ 150
- 27
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java View File

@@ -1,11 +1,7 @@
package me.chanjar.weixin.mp.api; package me.chanjar.weixin.mp.api;


import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback;
import me.chanjar.weixin.mp.bean.pay.request.WxEntPayRequest;
import me.chanjar.weixin.mp.bean.pay.request.WxPayRefundRequest;
import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest;
import me.chanjar.weixin.mp.bean.pay.request.WxPayUnifiedOrderRequest;
import me.chanjar.weixin.mp.bean.pay.request.*;
import me.chanjar.weixin.mp.bean.pay.result.*; import me.chanjar.weixin.mp.bean.pay.result.*;


import java.io.File; import java.io.File;
@@ -31,9 +27,8 @@ public interface WxMpPayService {
* 接口地址:https://api.mch.weixin.qq.com/pay/orderquery * 接口地址:https://api.mch.weixin.qq.com/pay/orderquery
* </pre> * </pre>
* *
* @param transactionId 微信支付分配的商户
* @param transactionId 微信订单
* @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。 * @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。
* @throws WxErrorException
*/ */
WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException; WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException;


@@ -50,7 +45,6 @@ public interface WxMpPayService {
* </pre> * </pre>
* *
* @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。 * @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。
* @throws WxErrorException
*/ */
WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorException; WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorException;


@@ -60,7 +54,6 @@ public interface WxMpPayService {
* 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder * 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder
* *
* @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置) * @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
* @throws WxErrorException
*/ */
WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxErrorException; WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxErrorException;


@@ -69,7 +62,6 @@ public interface WxMpPayService {
* 详见http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN * 详见http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
* *
* @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置) * @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
* @throws WxErrorException
*/ */
Map<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException; Map<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException;


@@ -81,10 +73,9 @@ public interface WxMpPayService {
* </pre> * </pre>
* *
* @param request 请求对象 * @param request 请求对象
* @param keyFile 证书文件对象
* @return 退款操作结果 * @return 退款操作结果
*/ */
WxPayRefundResult refund(WxPayRefundRequest request, File keyFile) throws WxErrorException;
WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException;


/** /**
* <pre> * <pre>
@@ -94,7 +85,8 @@ public interface WxMpPayService {
* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5 * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
* 接口链接:https://api.mch.weixin.qq.com/pay/refundquery * 接口链接:https://api.mch.weixin.qq.com/pay/refundquery
* </pre> * </pre>
* 以下四个参数四选一
* 以下四个参数四选一
*
* @param transactionId 微信订单号 * @param transactionId 微信订单号
* @param outTradeNo 商户订单号 * @param outTradeNo 商户订单号
* @param outRefundNo 商户退款单号 * @param outRefundNo 商户退款单号
@@ -107,15 +99,85 @@ public interface WxMpPayService {
* 读取支付结果通知 * 读取支付结果通知
* 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7 * 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
*/ */
WxPayJsSDKCallback getJSSDKCallbackData(String xmlData) throws WxErrorException;
WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException;


/** /**
* <pre>
* 计算Map键值对是否和签名相符,
* 按照字段名的 ASCII 码从小到大排序(字典序)后,使用 URL 键值对的 格式(即 key1=value1&key2=value2...)拼接成字符串
* </pre>
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
*
* @param xmlbean Bean需要标记有XML注解,默认使用配置中的PartnerKey进行签名
* @return 签名字符串
* @see #createSign(Map, String)
* @since 2.5.0
*/
String createSign(Object xmlbean);

/**
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
*
* @param xmlbean Bean需要标记有XML注解
* @param signKey 签名Key
* @return 签名字符串
* @see #createSign(Map, String)
*/
String createSign(Object xmlbean, String signKey);

/**
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
*
* @param prams 参数信息,默认使用配置中的PartnerKey进行签名
* @return 签名字符串
* @see #createSign(Map, String)
*/
String createSign(Map<String, String> prams);


/**
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
*
* @param prams 参数信息
* @param signKey 签名Key
* @return 签名字符串
*/
String createSign(Map<String, String> prams, String signKey);


/**
* 校验签名是否正确,默认使用配置中的PartnerKey进行签名
*
* @param xmlbean Bean需要标记有XML注解
* @return true - 签名校验成功,false - 签名校验失败
* @see #checkSign(Map, String)
*/ */
boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature);
boolean checkSign(Object xmlbean);

/**
* 校验签名是否正确
*
* @param xmlbean Bean需要标记有XML注解
* @param signKey 校验的签名Key
* @return true - 签名校验成功,false - 签名校验失败
* @see #checkSign(Map, String)
*/
boolean checkSign(Object xmlbean, String signKey);

/**
* 校验签名是否正确,默认使用配置中的PartnerKey进行签名
*
* @param prams 需要校验的参数Map
* @return true - 签名校验成功,false - 签名校验失败
* @see #checkSign(Map, String)
*/
boolean checkSign(Map<String, String> prams);

/**
* 校验签名是否正确
*
* @param params 需要校验的参数Map
* @param signKey 校验的签名Key
* @return true - 签名校验成功,false - 签名校验失败
* @see #checkSign(Map, String)
*/
boolean checkSign(Map<String, String> params, String signKey);


/** /**
* 发送微信红包给个人用户 * 发送微信红包给个人用户
@@ -128,9 +190,8 @@ public interface WxMpPayService {
* </pre> * </pre>
* *
* @param request 请求对象 * @param request 请求对象
* @param keyFile 证书文件对象
*/ */
WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile) throws WxErrorException;
WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxErrorException;


/** /**
* <pre> * <pre>
@@ -140,10 +201,10 @@ public interface WxMpPayService {
* 是否需要证书 是(证书及使用说明详见商户证书) * 是否需要证书 是(证书及使用说明详见商户证书)
* 请求方式 POST * 请求方式 POST
* </pre> * </pre>
*
* @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890 * @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890
* @param keyFile 证书文件对象
*/ */
WxPayRedpackQueryResult queryRedpack(String mchBillNo, File keyFile) throws WxErrorException;
WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException;


/** /**
* <pre> * <pre>
@@ -156,9 +217,8 @@ public interface WxMpPayService {
* </pre> * </pre>
* *
* @param request 请求对象 * @param request 请求对象
* @param keyFile 证书文件对象
*/ */
WxEntPayResult entPay(WxEntPayRequest request, File keyFile) throws WxErrorException;
WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException;


/** /**
* <pre> * <pre>
@@ -169,8 +229,71 @@ public interface WxMpPayService {
* </pre> * </pre>
* *
* @param partnerTradeNo 商户订单号 * @param partnerTradeNo 商户订单号
* @param keyFile 证书文件对象
*/ */
WxEntPayQueryResult queryEntPay(String partnerTradeNo, File keyFile) throws WxErrorException;
WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException;


/**
* <pre>
* 扫码支付模式一生成二维码的方法
* 二维码中的内容为链接,形式为:
* weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
* 其中XXXXX为商户需要填写的内容,商户将该链接生成二维码,如需要打印发布二维码,需要采用此格式。商户可调用第三方库生成二维码图片。
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
* </pre>
*
* @param productId 产品Id
* @param sideLength 要生成的二维码的边长,如果为空,则取默认值400
* @param logoFile 商户logo图片的文件对象,可以为空
* @return 生成的二维码的字节数组
*/
byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength);

/**
* <pre>
* 扫码支付模式二生成二维码的方法
* 对应链接格式:weixin://wxpay/bizpayurl?sr=XXXXX。请商户调用第三方库将code_url生成二维码图片。
* 该模式链接较短,生成的二维码打印到结账小票上的识别率较高。
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
* </pre>
*
* @param codeUrl 微信返回的交易会话的二维码链接
* @param logoFile 商户logo图片的文件对象,可以为空
* @param sideLength 要生成的二维码的边长,如果为空,则取默认值400
* @return 生成的二维码的字节数组
*/
byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength);

/**
* <pre>
* 交易保障
* 应用场景:
* 商户在调用微信支付提供的相关接口时,会得到微信支付返回的相关信息以及获得整个接口的响应时间。
* 为提高整体的服务水平,协助商户一起提高服务质量,微信支付提供了相关接口调用耗时和返回信息的主动上报接口,
* 微信支付可以根据商户侧上报的数据进一步优化网络部署,完善服务监控,和商户更好的协作为用户提供更好的业务体验。
* 接口地址: https://api.mch.weixin.qq.com/payitil/report
* 是否需要证书:不需要
* </pre>
*/
void report(WxPayReportRequest request) throws WxErrorException;

/**
* <pre>
* 下载对账单
* 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。
* 注意:
* 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中,跟原支付单订单号一致,bill_type为REVOKED;
* 2、微信在次日9点启动生成前一天的对账单,建议商户10点后再获取;
* 3、对账单中涉及金额的字段单位为“元”。
* 4、对账单接口只能下载三个月以内的账单。
* 接口链接:https://api.mch.weixin.qq.com/pay/downloadbill
* 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单</a>
* </pre>
*
* @param billDate 对账单日期 bill_date 下载对账单的日期,格式:20140603
* @param billType 账单类型 bill_type ALL,返回当日所有订单信息,默认值,SUCCESS,返回当日成功支付的订单,REFUND,返回当日退款订单
* @param tarType 压缩账单 tar_type 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
* @param deviceInfo 设备号 device_info 非必传参数,终端设备号
* @return 保存到本地的临时文件
*/
File downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException;
} }

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

@@ -7,7 +7,7 @@ import java.io.File;


/** /**
* 二维码相关操作接口 * 二维码相关操作接口
*
* 文档地址:https://mp.weixin.qq.com/wiki?action=doc&id=mp1443433542&t=0.9274944716856435
* @author Binary Wang * @author Binary Wang
*/ */
public interface WxMpQrcodeService { public interface WxMpQrcodeService {
@@ -15,38 +15,38 @@ public interface WxMpQrcodeService {
/** /**
* <pre> * <pre>
* 换取临时二维码ticket * 换取临时二维码ticket
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* 详情请见: <a href="https://mp.weixin.qq.com/wiki?action=doc&id=mp1443433542&t=0.9274944716856435">生成带参数的二维码</a>
* </pre> * </pre>
* *
* @param scene_id 参数。
* @param expire_seconds 过期秒数,默认60秒,最小60秒,最大1800秒
* @param sceneId 场景值ID,临时二维码时为32位非0整型
* @param expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
*/ */
WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException;
WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds) throws WxErrorException;


/** /**
* <pre> * <pre>
* 换取永久二维码ticket * 换取永久二维码ticket
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* 详情请见: <a href="https://mp.weixin.qq.com/wiki?action=doc&id=mp1443433542&t=0.9274944716856435">生成带参数的二维码</a>
* </pre> * </pre>
* *
* @param scene_id 参数。永久二维码时最大值为100000(目前参数只支持1--100000)
* @param sceneId 场景值ID,最大值为100000(目前参数只支持1--100000)
*/ */
WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException;
WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorException;


/** /**
* <pre> * <pre>
* 换取永久字符串二维码ticket * 换取永久字符串二维码ticket
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* 详情请见: <a href="https://mp.weixin.qq.com/wiki?action=doc&id=mp1443433542&t=0.9274944716856435">生成带参数的二维码</a>
* </pre> * </pre>
* *
* @param scene_str 参数。字符串类型长度现在为1到64
* @param sceneStr 参数。字符串类型长度现在为1到64
*/ */
WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException;
WxMpQrCodeTicket qrCodeCreateLastTicket(String sceneStr) throws WxErrorException;


/** /**
* <pre> * <pre>
* 换取二维码图片文件,jpg格式 * 换取二维码图片文件,jpg格式
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* 详情请见: <a href="https://mp.weixin.qq.com/wiki?action=doc&id=mp1443433542&t=0.9274944716856435">生成带参数的二维码</a>
* </pre> * </pre>
* *
* @param ticket 二维码ticket * @param ticket 二维码ticket
@@ -56,7 +56,7 @@ public interface WxMpQrcodeService {
/** /**
* <pre> * <pre>
* 换取二维码图片url地址(可以选择是否生成压缩的网址) * 换取二维码图片url地址(可以选择是否生成压缩的网址)
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* 详情请见: <a href="https://mp.weixin.qq.com/wiki?action=doc&id=mp1443433542&t=0.9274944716856435">生成带参数的二维码</a>
* </pre> * </pre>
* *
* @param ticket 二维码ticket * @param ticket 二维码ticket
@@ -67,7 +67,7 @@ public interface WxMpQrcodeService {
/** /**
* <pre> * <pre>
* 换取二维码图片url地址 * 换取二维码图片url地址
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* 详情请见: <a href="https://mp.weixin.qq.com/wiki?action=doc&id=mp1443433542&t=0.9274944716856435">生成带参数的二维码</a>
* </pre> * </pre>
* *
* @param ticket 二维码ticket * @param ticket 二维码ticket


+ 7
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java View File

@@ -345,4 +345,11 @@ public interface WxMpService {
* @return WxMpTemplateMsgService * @return WxMpTemplateMsgService
*/ */
WxMpTemplateMsgService getTemplateMsgService(); WxMpTemplateMsgService getTemplateMsgService();

/**
* 返回硬件平台相关接口方法的实现类对象,以方便调用其各个接口
*
* @return WxMpDeviceService
*/
WxMpDeviceService getDeviceService();
} }

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

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

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpDeviceService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.device.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Created by keungtung on 10/12/2016.
*/
public class WxMpDeviceServiceImpl implements WxMpDeviceService {
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/device";
private static Logger log = LoggerFactory.getLogger(WxMpMenuServiceImpl.class);

private WxMpService wxMpService;

WxMpDeviceServiceImpl(WxMpService wxMpService) {
this.wxMpService = wxMpService;
}

@Override
public TransMsgResp transMsg(WxDeviceMsg msg) throws WxErrorException {
String url = API_URL_PREFIX + "/transmsg";
String response = this.wxMpService.post(url,msg.toJson());
return TransMsgResp.fromJson(response);
}

@Override
public WxDeviceQrCodeResult getQrCode(String productId) throws WxErrorException {
String url = API_URL_PREFIX + "/getqrcode";
String response = this.wxMpService.get(url, "product_id=" + productId);
return WxDeviceQrCodeResult.fromJson(response);
}

@Override
public WxDeviceAuthorizeResult authorize(WxDeviceAuthorize wxDeviceAuthorize) throws WxErrorException {
String url = API_URL_PREFIX + "/authorize_device";
String response = this.wxMpService.post(url,wxDeviceAuthorize.toJson());
return WxDeviceAuthorizeResult.fromJson(response);
}

@Override
public WxDeviceBindResult bind(WxDeviceBind wxDeviceBind) throws WxErrorException {
String url = API_URL_PREFIX + "/bind";
String response = this.wxMpService.post(url,wxDeviceBind.toJson());
return WxDeviceBindResult.fromJson(response);
}

@Override
public WxDeviceBindResult compelBind(WxDeviceBind wxDeviceBind) throws WxErrorException {
String url = API_URL_PREFIX + "/compel_bind";
String response = this.wxMpService.post(url,wxDeviceBind.toJson());
return WxDeviceBindResult.fromJson(response);
}

@Override
public WxDeviceBindResult unbind(WxDeviceBind wxDeviceBind) throws WxErrorException {
String url = API_URL_PREFIX + "/unbind?";
String response = this.wxMpService.post(url, wxDeviceBind.toJson());
return WxDeviceBindResult.fromJson(response);
}

@Override
public WxDeviceBindResult compelUnbind(WxDeviceBind wxDeviceBind) throws WxErrorException {
String url = API_URL_PREFIX + "/compel_unbind?";
String response = this.wxMpService.post(url, wxDeviceBind.toJson());
return WxDeviceBindResult.fromJson(response);
}
}


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

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


import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpMenuService; import me.chanjar.weixin.mp.api.WxMpMenuService;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult; import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
import me.chanjar.weixin.mp.bean.menu.WxMpSelfMenuInfo;
import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


@@ -14,8 +16,7 @@ import org.slf4j.LoggerFactory;
*/ */
public class WxMpMenuServiceImpl implements WxMpMenuService { public class WxMpMenuServiceImpl implements WxMpMenuService {
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/menu"; private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/menu";
private static Logger log = LoggerFactory
.getLogger(WxMpMenuServiceImpl.class);
private static Logger log = LoggerFactory.getLogger(WxMpMenuServiceImpl.class);


private WxMpService wxMpService; private WxMpService wxMpService;


@@ -24,7 +25,7 @@ public class WxMpMenuServiceImpl implements WxMpMenuService {
} }


@Override @Override
public void menuCreate(WxMenu menu) throws WxErrorException {
public String menuCreate(WxMenu menu) throws WxErrorException {
String menuJson = menu.toJson(); String menuJson = menu.toJson();
String url = API_URL_PREFIX + "/create"; String url = API_URL_PREFIX + "/create";
if (menu.getMatchRule() != null) { if (menu.getMatchRule() != null) {
@@ -35,6 +36,29 @@ public class WxMpMenuServiceImpl implements WxMpMenuService {


String result = this.wxMpService.post(url, menuJson); String result = this.wxMpService.post(url, menuJson);
log.debug("创建菜单:{},结果:{}", menuJson, result); log.debug("创建菜单:{},结果:{}", menuJson, result);

if (menu.getMatchRule() != null) {
return new JsonParser().parse(result).getAsJsonObject().get("menuid").getAsString();
}

return null;
}

@Override
public String menuCreate(String json) throws WxErrorException {
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = jsonParser.parse(json).getAsJsonObject();
String url = API_URL_PREFIX + "/create";
if (jsonObject.get("matchrule") != null) {
url = API_URL_PREFIX + "/addconditional";
}

String result = this.wxMpService.post(url, json);
if (jsonObject.get("matchrule") != null) {
return jsonParser.parse(result).getAsJsonObject().get("menuid").getAsString();
}

return null;
} }


@Override @Override
@@ -45,18 +69,20 @@ public class WxMpMenuServiceImpl implements WxMpMenuService {
} }


@Override @Override
public void menuDelete(String menuid) throws WxErrorException {
public void menuDelete(String menuId) throws WxErrorException {
String url = API_URL_PREFIX + "/delconditional"; String url = API_URL_PREFIX + "/delconditional";
String result = this.wxMpService.get(url, "menuid=" + menuid);
log.debug("根据MeunId({})删除菜单结果:{}", menuid, result);
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("menuid", menuId);
String result = this.wxMpService.post(url, jsonObject.toString());
log.debug("根据MeunId({})删除个性化菜单结果:{}", menuId, result);
} }


@Override @Override
public WxMenu menuGet() throws WxErrorException {
public WxMpMenu menuGet() throws WxErrorException {
String url = API_URL_PREFIX + "/get"; String url = API_URL_PREFIX + "/get";
try { try {
String resultContent = this.wxMpService.get(url, null); String resultContent = this.wxMpService.get(url, null);
return WxMenu.fromJson(resultContent);
return WxMpMenu.fromJson(resultContent);
} catch (WxErrorException e) { } catch (WxErrorException e) {
// 46003 不存在的菜单数据 // 46003 不存在的菜单数据
if (e.getError().getErrorCode() == 46003) { if (e.getError().getErrorCode() == 46003) {
@@ -69,11 +95,13 @@ public class WxMpMenuServiceImpl implements WxMpMenuService {
@Override @Override
public WxMenu menuTryMatch(String userid) throws WxErrorException { public WxMenu menuTryMatch(String userid) throws WxErrorException {
String url = API_URL_PREFIX + "/trymatch"; String url = API_URL_PREFIX + "/trymatch";
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("user_id", userid);
try { try {
String resultContent = this.wxMpService.get(url, "user_id=" + userid);
String resultContent = this.wxMpService.post(url, jsonObject.toString());
return WxMenu.fromJson(resultContent); return WxMenu.fromJson(resultContent);
} catch (WxErrorException e) { } catch (WxErrorException e) {
// 46003 不存在的菜单数据 46002 不存在的菜单版本
// 46003 不存在的菜单数据46002 不存在的菜单版本
if (e.getError().getErrorCode() == 46003 if (e.getError().getErrorCode() == 46003
|| e.getError().getErrorCode() == 46002) { || e.getError().getErrorCode() == 46002) {
return null; return null;


+ 267
- 206
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java View File

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


import com.thoughtworks.xstream.XStream;
import com.github.binarywang.utils.qrcode.QrcodeUtils;
import com.google.common.collect.Maps;
import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.BeanUtils; import me.chanjar.weixin.common.util.BeanUtils;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import me.chanjar.weixin.mp.api.WxMpConfigStorage;
import me.chanjar.weixin.mp.api.WxMpPayService; import me.chanjar.weixin.mp.api.WxMpPayService;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback;
import me.chanjar.weixin.mp.bean.pay.request.*; import me.chanjar.weixin.mp.bean.pay.request.*;
import me.chanjar.weixin.mp.bean.pay.result.*; import me.chanjar.weixin.mp.bean.pay.result.*;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
@@ -22,16 +22,13 @@ import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.security.KeyStore;
import java.util.*; import java.util.*;


/** /**
@@ -43,35 +40,39 @@ public class WxMpPayServiceImpl implements WxMpPayService {


private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com"; private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com";
private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP"}; private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP"};
private static final String[] REFUND_ACCOUNT = new String[]{"REFUND_SOURCE_RECHARGE_FUNDS",
"REFUND_SOURCE_UNSETTLED_FUNDS"};
protected final Logger log = LoggerFactory.getLogger(this.getClass());
private static final String[] REFUND_ACCOUNT = new String[]{"REFUND_SOURCE_RECHARGE_FUNDS", "REFUND_SOURCE_UNSETTLED_FUNDS"};
private static final String[] BILL_TYPE = new String[]{"ALL","REFUND","SUCCESS"};;
private final Logger log = LoggerFactory.getLogger(this.getClass());
private WxMpService wxMpService; private WxMpService wxMpService;


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


private WxMpConfigStorage getConfig() {
return wxMpService.getWxMpConfigStorage();
}

private String getPayBaseUrl(){
if(this.getConfig().useSandboxForWxPay()){
return PAY_BASE_URL + "/sandboxnew";
}

return PAY_BASE_URL;
}

@Override @Override
public WxPayRefundResult refund(WxPayRefundRequest request, File keyFile)
throws WxErrorException {
checkParameters(request);

XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxPayRefundRequest.class);
xstream.processAnnotations(WxPayRefundResult.class);

request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
String partnerId = this.wxMpService.getWxMpConfigStorage().getPartnerId();
request.setMchId(partnerId);
request.setNonceStr(System.currentTimeMillis() + "");
request.setOpUserId(partnerId);
String sign = this.createSign(BeanUtils.xmlBean2Map(request), this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);

String url = PAY_BASE_URL + "/secapi/pay/refund";
String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), partnerId);
WxPayRefundResult result = (WxPayRefundResult) xstream.fromXML(responseContent);
public WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException {
this.initRequest(request);
if (StringUtils.isBlank(request.getOpUserId())) {
request.setOpUserId(this.getConfig().getPartnerId());
}
this.checkParameters(request);
request.setSign(this.createSign(request));

String url = this.getPayBaseUrl() + "/secapi/pay/refund";
String responseContent = this.executeWithKey(url, request.toXML());
WxPayRefundResult result = WxPayRefundResult.fromXML(responseContent, WxPayRefundResult.class);
this.checkResult(result); this.checkResult(result);
return result; return result;
} }
@@ -83,50 +84,63 @@ public class WxMpPayServiceImpl implements WxMpPayService {
throw new IllegalArgumentException("transaction_id , out_trade_no,out_refund_no, refund_id 必须四选一"); throw new IllegalArgumentException("transaction_id , out_trade_no,out_refund_no, refund_id 必须四选一");
} }


XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxPayRefundQueryRequest.class);
xstream.processAnnotations(WxPayRefundQueryResult.class);

WxPayRefundQueryRequest request = new WxPayRefundQueryRequest(); WxPayRefundQueryRequest request = new WxPayRefundQueryRequest();
this.initRequest(request);
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
request.setTransactionId(StringUtils.trimToNull(transactionId)); request.setTransactionId(StringUtils.trimToNull(transactionId));
request.setOutRefundNo(StringUtils.trimToNull(outRefundNo)); request.setOutRefundNo(StringUtils.trimToNull(outRefundNo));
request.setRefundId(StringUtils.trimToNull(refundId)); request.setRefundId(StringUtils.trimToNull(refundId));
request.setSign(this.createSign(request));


request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
request.setNonceStr(System.currentTimeMillis() + "");

String sign = this.createSign(BeanUtils.xmlBean2Map(request),
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);

String url = PAY_BASE_URL + "/pay/refundquery";

String responseContent = this.executeRequest(url, xstream.toXML(request));
WxPayRefundQueryResult result = (WxPayRefundQueryResult) xstream.fromXML(responseContent);
result.composeRefundRecords(responseContent);
String url = this.getPayBaseUrl() + "/pay/refundquery";
String responseContent = this.executeRequest(url, request.toXML());
WxPayRefundQueryResult result = WxPayRefundQueryResult.fromXML(responseContent, WxPayRefundQueryResult.class);
result.composeRefundRecords();
this.checkResult(result); this.checkResult(result);
return result; return result;
} }



private void checkResult(WxPayBaseResult result) throws WxErrorException { private void checkResult(WxPayBaseResult result) throws WxErrorException {
//校验返回结果签名
Map<String, String> map = result.toMap();
if (result.getSign() != null &&!this.checkSign(map)) {
log.debug("校验结果签名失败,参数:{}", map);
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("参数格式校验错误!").build());
}

//校验结果是否成功
if (!"SUCCESS".equalsIgnoreCase(result.getReturnCode()) if (!"SUCCESS".equalsIgnoreCase(result.getReturnCode())
|| !"SUCCESS".equalsIgnoreCase(result.getResultCode())) { || !"SUCCESS".equalsIgnoreCase(result.getResultCode())) {
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1)
WxError error = WxError.newBuilder().setErrorCode(-1)
.setErrorMsg("返回代码: " + result.getReturnCode() + ", 返回信息: " .setErrorMsg("返回代码: " + result.getReturnCode() + ", 返回信息: "
+ result.getReturnMsg() + ", 结果代码: " + result.getResultCode() + ", 错误代码: " + result.getReturnMsg() + ", 结果代码: " + result.getResultCode() + ", 错误代码: "
+ result.getErrCode() + ", 错误详情: " + result.getErrCodeDes()) + result.getErrCode() + ", 错误详情: " + result.getErrCodeDes())
.build());
.build();
log.error("结果业务代码异常,参数:{},详细:{}", map, error);
throw new WxErrorException(error);
} }
} }


private void checkParameters(WxPayDownloadBillRequest request) throws WxErrorException {
BeanUtils.checkRequiredFields(request);

if (StringUtils.isNotBlank(request.getTarType()) && !"GZIP".equals(request.getTarType())) {
throw new IllegalArgumentException("tar_type值如果存在,只能为GZIP");
}

if ( !ArrayUtils.contains(BILL_TYPE, request.getBillType())) {
throw new IllegalArgumentException("bill_tpye目前必须为" + Arrays.toString(BILL_TYPE) + "其中之一,实际值:" + request.getBillType());
}

}

private void checkParameters(WxPayRefundRequest request) throws WxErrorException { private void checkParameters(WxPayRefundRequest request) throws WxErrorException {
BeanUtils.checkRequiredFields(request); BeanUtils.checkRequiredFields(request);


if (StringUtils.isNotBlank(request.getRefundAccount())) { if (StringUtils.isNotBlank(request.getRefundAccount())) {
if (!ArrayUtils.contains(REFUND_ACCOUNT, request.getRefundAccount())) { if (!ArrayUtils.contains(REFUND_ACCOUNT, request.getRefundAccount())) {
throw new IllegalArgumentException("refund_account目前必须为" + Arrays.toString(REFUND_ACCOUNT) + "其中之一");
throw new IllegalArgumentException("refund_account目前必须为" + Arrays.toString(REFUND_ACCOUNT) + "其中之一,实际值:" + request.getRefundAccount());
} }
} }


@@ -136,103 +150,54 @@ public class WxMpPayServiceImpl implements WxMpPayService {
} }


@Override @Override
public WxPayJsSDKCallback getJSSDKCallbackData(String xmlData) throws WxErrorException {
public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException {
try { try {
XStream xstream = XStreamInitializer.getInstance();
xstream.alias("xml", WxPayJsSDKCallback.class);
return (WxPayJsSDKCallback) xstream.fromXML(xmlData);
log.trace("微信支付回调参数详细:{}", xmlData);
WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData);
log.debug("微信支付回调结果对象:{}", result);
this.checkResult(result);
return result;
} catch (WxErrorException e) {
log.error(e.getMessage(), e);
throw e;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(), e);
throw new WxErrorException(WxError.newBuilder().setErrorMsg("发生异常" + e.getMessage()).build()); throw new WxErrorException(WxError.newBuilder().setErrorMsg("发生异常" + e.getMessage()).build());
} }
} }


@Override @Override
public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm,
String signature) {
return signature.equals(this.createSign(kvm,
this.wxMpService.getWxMpConfigStorage().getPartnerKey()));
}

@Override
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile)
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request)
throws WxErrorException { throws WxErrorException {
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxPaySendRedpackRequest.class);
xstream.processAnnotations(WxPaySendRedpackResult.class);
this.initRequest(request);
request.setSign(this.createSign(request));


request.setWxAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
String mchId = this.wxMpService.getWxMpConfigStorage().getPartnerId();
request.setMchId(mchId);
request.setNonceStr(System.currentTimeMillis() + "");

String sign = this.createSign(BeanUtils.xmlBean2Map(request),
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);

String url = PAY_BASE_URL + "/mmpaymkttransfers/sendredpack";
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendredpack";
if (request.getAmtType() != null) { if (request.getAmtType() != null) {
//裂变红包 //裂变红包
url = PAY_BASE_URL + "/mmpaymkttransfers/sendgroupredpack";
url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendgroupredpack";
} }

String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), mchId);
WxPaySendRedpackResult result = (WxPaySendRedpackResult) xstream
.fromXML(responseContent);
String responseContent = this.executeWithKey(url, request.toXML());
WxPaySendRedpackResult result = WxPaySendRedpackResult.fromXML(responseContent, WxPaySendRedpackResult.class);
this.checkResult(result); this.checkResult(result);
return result; return result;
} }


@Override @Override
public WxPayRedpackQueryResult queryRedpack(String mchBillNo, File keyFile) throws WxErrorException {
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxPayRedpackQueryRequest.class);
xstream.processAnnotations(WxPayRedpackQueryResult.class);

public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException {
WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest(); WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest();
request.setMchBillNo(mchBillNo); request.setMchBillNo(mchBillNo);
request.setBillType("MCHT"); request.setBillType("MCHT");
initRequest(request);
request.setSign(this.createSign(request));


request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
String mchId = this.wxMpService.getWxMpConfigStorage().getPartnerId();
request.setMchId(mchId);
request.setNonceStr(System.currentTimeMillis() + "");

String sign = this.createSign(BeanUtils.xmlBean2Map(request),
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);

String url = PAY_BASE_URL + "/mmpaymkttransfers/gethbinfo";
String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), mchId);
WxPayRedpackQueryResult result = (WxPayRedpackQueryResult) xstream.fromXML(responseContent);
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gethbinfo";
String responseContent = this.executeWithKey(url, request.toXML());
WxPayRedpackQueryResult result = WxPayRedpackQueryResult.fromXML(responseContent, WxPayRedpackQueryResult.class);
this.checkResult(result); this.checkResult(result);
return result; return result;
} }


/**
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
*
* @param packageParams 原始参数
* @param signKey 加密Key(即 商户Key)
* @return 签名字符串
*/
private String createSign(Map<String, String> packageParams, String signKey) {
SortedMap<String, String> sortedMap = new TreeMap<>(packageParams);

StringBuilder toSign = new StringBuilder();
for (String key : sortedMap.keySet()) {
String value = packageParams.get(key);
if (null != value && !"".equals(value) && !"sign".equals(key)
&& !"key".equals(key)) {
toSign.append(key + "=" + value + "&");
}
}

toSign.append("key=" + signKey);

return DigestUtils.md5Hex(toSign.toString()).toUpperCase();
}

@Override @Override
public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException { public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException {
if ((StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo)) || if ((StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo)) ||
@@ -240,26 +205,16 @@ public class WxMpPayServiceImpl implements WxMpPayService {
throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时存在或同时为空,必须二选一"); throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时存在或同时为空,必须二选一");
} }


XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxPayOrderQueryRequest.class);
xstream.processAnnotations(WxPayOrderQueryResult.class);

WxPayOrderQueryRequest request = new WxPayOrderQueryRequest(); WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
request.setTransactionId(StringUtils.trimToNull(transactionId)); request.setTransactionId(StringUtils.trimToNull(transactionId));
request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
request.setNonceStr(System.currentTimeMillis() + "");

String sign = this.createSign(BeanUtils.xmlBean2Map(request),
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);
initRequest(request);
request.setSign(this.createSign(request));


String url = PAY_BASE_URL + "/pay/orderquery";

String responseContent = this.executeRequest(url, xstream.toXML(request));
WxPayOrderQueryResult result = (WxPayOrderQueryResult) xstream.fromXML(responseContent);
result.composeCoupons(responseContent);
String url = this.getPayBaseUrl() + "/pay/orderquery";
String responseContent = this.executeRequest(url, request.toXML());
WxPayOrderQueryResult result = WxPayOrderQueryResult.fromXML(responseContent, WxPayOrderQueryResult.class);
result.composeCoupons();
this.checkResult(result); this.checkResult(result);
return result; return result;
} }
@@ -270,24 +225,14 @@ public class WxMpPayServiceImpl implements WxMpPayService {
throw new IllegalArgumentException("out_trade_no 不能为空"); throw new IllegalArgumentException("out_trade_no 不能为空");
} }


XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxPayOrderCloseRequest.class);
xstream.processAnnotations(WxPayOrderCloseResult.class);

WxPayOrderCloseRequest request = new WxPayOrderCloseRequest(); WxPayOrderCloseRequest request = new WxPayOrderCloseRequest();
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
request.setNonceStr(System.currentTimeMillis() + "");
initRequest(request);
request.setSign(this.createSign(request));


String sign = this.createSign(BeanUtils.xmlBean2Map(request),
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);

String url = PAY_BASE_URL + "/pay/closeorder";

String responseContent = this.executeRequest(url, xstream.toXML(request));
WxPayOrderCloseResult result = (WxPayOrderCloseResult) xstream.fromXML(responseContent);
String url = this.getPayBaseUrl() + "/pay/closeorder";
String responseContent = this.executeRequest(url, request.toXML());
WxPayOrderCloseResult result = WxPayOrderCloseResult.fromXML(responseContent, WxPayOrderCloseResult.class);
this.checkResult(result); this.checkResult(result);


return result; return result;
@@ -296,34 +241,45 @@ public class WxMpPayServiceImpl implements WxMpPayService {
@Override @Override
public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request)
throws WxErrorException { throws WxErrorException {
checkParameters(request);

XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxPayUnifiedOrderRequest.class);
xstream.processAnnotations(WxPayUnifiedOrderResult.class);


request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
request.setNonceStr(System.currentTimeMillis() + "");

String sign = this.createSign(BeanUtils.xmlBean2Map(request),
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);
this.initRequest(request);
if (StringUtils.isBlank(request.getNotifyURL())) {
request.setNotifyURL(getConfig().getNotifyURL());
}
if (StringUtils.isBlank(request.getTradeType())) {
request.setTradeType(getConfig().getTradeType());
}
checkParameters(request);//校验参数
request.setSign(this.createSign(request));


String url = PAY_BASE_URL + "/pay/unifiedorder";
String url = this.getPayBaseUrl() + "/pay/unifiedorder";
String xmlParam = request.toXML();
log.debug("微信统一下单接口,URL:{},参数:{}", url, xmlParam);


String responseContent = this.executeRequest(url, xstream.toXML(request));
WxPayUnifiedOrderResult result = (WxPayUnifiedOrderResult) xstream
.fromXML(responseContent);
String responseContent = this.executeRequest(url, xmlParam);
log.debug("微信统一下单接口,URL:{},结果:{}", url, responseContent);
WxPayUnifiedOrderResult result = WxPayUnifiedOrderResult.fromXML(responseContent, WxPayUnifiedOrderResult.class);
this.checkResult(result); this.checkResult(result);
return result; return result;
} }


private void initRequest(WxPayBaseRequest request) {
if (StringUtils.isBlank(request.getAppid())) {
request.setAppid(getConfig().getAppId());
}
if (StringUtils.isBlank(request.getMchId())) {
request.setMchId(getConfig().getPartnerId());
}
if (StringUtils.isBlank(request.getNonceStr())) {
request.setNonceStr(String.valueOf(System.currentTimeMillis()));
}
}

private void checkParameters(WxPayUnifiedOrderRequest request) throws WxErrorException { private void checkParameters(WxPayUnifiedOrderRequest request) throws WxErrorException {
BeanUtils.checkRequiredFields(request); BeanUtils.checkRequiredFields(request);


if (!ArrayUtils.contains(TRADE_TYPES, request.getTradeType())) { if (!ArrayUtils.contains(TRADE_TYPES, request.getTradeType())) {
throw new IllegalArgumentException("trade_type目前必须为" + Arrays.toString(TRADE_TYPES) + "其中之一");
throw new IllegalArgumentException("trade_type目前必须为" + Arrays.toString(TRADE_TYPES) + "其中之一,实际值:" + request.getTradeType());
} }


if ("JSAPI".equals(request.getTradeType()) && request.getOpenid() == null) { if ("JSAPI".equals(request.getTradeType()) && request.getOpenid() == null) {
@@ -345,64 +301,110 @@ public class WxMpPayServiceImpl implements WxMpPayService {
} }


Map<String, String> payInfo = new HashMap<>(); Map<String, String> payInfo = new HashMap<>();
payInfo.put("appId", this.wxMpService.getWxMpConfigStorage().getAppId());
payInfo.put("appId", getConfig().getAppId());
// 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
payInfo.put("nonceStr", System.currentTimeMillis() + "");
payInfo.put("nonceStr", String.valueOf(System.currentTimeMillis()));
payInfo.put("package", "prepay_id=" + prepayId); payInfo.put("package", "prepay_id=" + prepayId);
payInfo.put("signType", "MD5"); payInfo.put("signType", "MD5");
if ("NATIVE".equals(request.getTradeType())) { if ("NATIVE".equals(request.getTradeType())) {
payInfo.put("codeUrl", unifiedOrderResult.getCodeURL()); payInfo.put("codeUrl", unifiedOrderResult.getCodeURL());
} }

String finalSign = this.createSign(payInfo, this.wxMpService.getWxMpConfigStorage().getPartnerKey());
payInfo.put("paySign", finalSign);
payInfo.put("paySign", this.createSign(payInfo));
return payInfo; return payInfo;
} }


@Override @Override
public WxEntPayResult entPay(WxEntPayRequest request, File keyFile) throws WxErrorException {
public WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException {
this.initRequest(request);
BeanUtils.checkRequiredFields(request); BeanUtils.checkRequiredFields(request);
request.setSign(this.createSign(request));


XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxEntPayRequest.class);
xstream.processAnnotations(WxEntPayResult.class);
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/promotion/transfers";


request.setMchAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
request.setNonceStr(System.currentTimeMillis() + "");

String sign = this.createSign(BeanUtils.xmlBean2Map(request), this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);
String responseContent = this.executeWithKey(url, request.toXML());
WxEntPayResult result = WxEntPayResult.fromXML(responseContent, WxEntPayResult.class);
this.checkResult(result);
return result;
}


String url = PAY_BASE_URL + "/mmpaymkttransfers/promotion/transfers";
@Override
public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException {
WxEntPayQueryRequest request = new WxEntPayQueryRequest();
this.initRequest(request);
request.setSign(this.createSign(request));


String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), request.getMchId());
WxEntPayResult result = (WxEntPayResult) xstream.fromXML(responseContent);
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gettransferinfo";
String responseContent = this.executeWithKey(url, request.toXML());
WxEntPayQueryResult result = WxEntPayQueryResult.fromXML(responseContent, WxEntPayQueryResult.class);
this.checkResult(result); this.checkResult(result);
return result; return result;
} }


@Override @Override
public WxEntPayQueryResult queryEntPay(String partnerTradeNo, File keyFile) throws WxErrorException {
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxEntPayQueryRequest.class);
xstream.processAnnotations(WxEntPayQueryResult.class);
public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) {
//weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
StringBuilder codeUrl = new StringBuilder("weixin://wxpay/bizpayurl?");
Map<String, String> params = Maps.newHashMap();
params.put("appid", this.getConfig().getAppId());
params.put("mch_id", this.getConfig().getPartnerId());
params.put("product_id", productId);
params.put("time_stamp", String.valueOf(System.currentTimeMillis()));
params.put("nonce_str", String.valueOf(System.currentTimeMillis()));

String sign = this.createSign(params);
params.put("sign", sign);

for (String key : params.keySet()) {
codeUrl.append(key + "=" + params.get(key) + "&");
}


WxEntPayQueryRequest request = new WxEntPayQueryRequest();
request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
request.setNonceStr(System.currentTimeMillis() + "");
String content = codeUrl.toString().substring(0, codeUrl.length() - 1);
if (sideLength == null || sideLength < 1) {
return QrcodeUtils.createQrcode(content, logoFile);
}

return QrcodeUtils.createQrcode(content, sideLength, logoFile);
}

@Override
public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) {
if (sideLength == null || sideLength < 1) {
return QrcodeUtils.createQrcode(codeUrl, logoFile);
}


String sign = this.createSign(BeanUtils.xmlBean2Map(request), this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);
return QrcodeUtils.createQrcode(codeUrl, sideLength, logoFile);
}


String url = PAY_BASE_URL + "/mmpaymkttransfers/gettransferinfo";
public void report(WxPayReportRequest request) throws WxErrorException {
BeanUtils.checkRequiredFields(request);
this.initRequest(request);
request.setSign(this.createSign(request));


String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), request.getMchId());
WxEntPayQueryResult result = (WxEntPayQueryResult) xstream.fromXML(responseContent);
String url = this.getPayBaseUrl() + "/payitil/report";
String responseContent = this.wxMpService.post(url, request.toXML());
WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class);
this.checkResult(result); this.checkResult(result);
return result;
}

@Override
public File downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException {
WxPayDownloadBillRequest request = new WxPayDownloadBillRequest();
this.initRequest(request);
request.setBillType(billType);
request.setBillDate(billDate);
request.setTarType(tarType);
request.setDeviceInfo(deviceInfo);
this.checkParameters(request);
request.setSign(this.createSign(request));

String url = this.getPayBaseUrl() + "/pay/downloadbill";
//TODO 返回的内容可能是文件流,也有可能是xml,需要区分对待
String responseContent = this.wxMpService.post(url, request.toXML());

WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class);
this.checkResult(result);
return null;
} }


private String executeRequest(String url, String requestStr) throws WxErrorException { private String executeRequest(String url, String requestStr) throws WxErrorException {
@@ -427,13 +429,14 @@ public class WxMpPayServiceImpl implements WxMpPayService {
} }
} }


private String executeRequestWithKeyFile(String url, File keyFile, String requestStr, String mchId) throws WxErrorException {
try (FileInputStream inputStream = new FileInputStream(keyFile)) {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(inputStream, mchId.toCharArray());
private String executeWithKey(String url, String requestStr) throws WxErrorException {
try {
SSLContext sslContext = getConfig().getSslContext();
if (null == sslContext) {
throw new IllegalArgumentException("请先初始化配置类(即WxMpConfigStorage的实现类)中的SSLContext!");
}


SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null,
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1"}, null,
new DefaultHostnameVerifier()); new DefaultHostnameVerifier());


HttpPost httpPost = new HttpPost(url); HttpPost httpPost = new HttpPost(url);
@@ -457,4 +460,62 @@ public class WxMpPayServiceImpl implements WxMpPayService {
} }
} }


@Override
public String createSign(Object xmlBean) {
return this.createSign(BeanUtils.xmlBean2Map(xmlBean), getConfig().getPartnerKey());
}

@Override
public String createSign(Object xmlBean, String signKey) {
return this.createSign(BeanUtils.xmlBean2Map(xmlBean), signKey);
}

@Override
public String createSign(Map<String, String> params) {
return this.createSign(params, this.getConfig().getPartnerKey());
}

@Override
public String createSign(Map<String, String> params, String signKey) {
if(this.getConfig().useSandboxForWxPay()){
//使用仿真测试环境
//TODO 目前测试发现,以下两行代码都会出问题,所以暂不建议使用这个仿真测试环境
signKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";
//return "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";
}

SortedMap<String, String> sortedMap = new TreeMap<>(params);

StringBuilder toSign = new StringBuilder();
for (String key : sortedMap.keySet()) {
String value = params.get(key);
if (StringUtils.isNotEmpty(value) && !"sign".equals(key) && !"key".equals(key)) {
toSign.append(key + "=" + value + "&");
}
}

toSign.append("key=" + signKey);
return DigestUtils.md5Hex(toSign.toString()).toUpperCase();
}

@Override
public boolean checkSign(Object xmlBean) {
return this.checkSign(BeanUtils.xmlBean2Map(xmlBean), getConfig().getPartnerKey());
}

@Override
public boolean checkSign(Object xmlBean, String signKey) {
return this.checkSign(BeanUtils.xmlBean2Map(xmlBean), signKey);
}

@Override
public boolean checkSign(Map<String, String> params) {
return this.checkSign(params, getConfig().getPartnerKey());
}

@Override
public boolean checkSign(Map<String, String> params, String signKey) {
String sign = this.createSign(params, signKey);
return sign.equals(params.get("sign"));
}
} }

+ 31
- 14
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java View File

@@ -3,7 +3,6 @@ package me.chanjar.weixin.mp.api.impl;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.mp.api.WxMpQrcodeService; import me.chanjar.weixin.mp.api.WxMpQrcodeService;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
@@ -26,47 +25,65 @@ public class WxMpQrcodeServiceImpl implements WxMpQrcodeService {
} }


@Override @Override
public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException {
public WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds) throws WxErrorException {
if (sceneId == 0) {
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("临时二维码场景值不能为0!").build());
}

//expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
if (expireSeconds != null && expireSeconds > 2592000) {
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1)
.setErrorMsg("临时二维码有效时间最大不能超过2592000(即30天)!").build());
}

if (expireSeconds == null) {
expireSeconds = 30;
}

String url = API_URL_PREFIX + "/create"; String url = API_URL_PREFIX + "/create";
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
json.addProperty("action_name", "QR_SCENE"); json.addProperty("action_name", "QR_SCENE");
if (expire_seconds != null) {
json.addProperty("expire_seconds", expire_seconds);
if (expireSeconds != null) {
json.addProperty("expire_seconds", expireSeconds);
} }
JsonObject actionInfo = new JsonObject(); JsonObject actionInfo = new JsonObject();
JsonObject scene = new JsonObject(); JsonObject scene = new JsonObject();
scene.addProperty("scene_id", scene_id);
scene.addProperty("scene_id", sceneId);
actionInfo.add("scene", scene); actionInfo.add("scene", scene);
json.add("action_info", actionInfo); json.add("action_info", actionInfo);
String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString());
String responseContent = this.wxMpService.post(url, json.toString());
return WxMpQrCodeTicket.fromJson(responseContent); return WxMpQrCodeTicket.fromJson(responseContent);
} }


@Override @Override
public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException {
public WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorException {
if (sceneId < 1 || sceneId > 100000) {
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("永久二维码的场景值目前只支持1--100000!").build());
}

String url = API_URL_PREFIX + "/create"; String url = API_URL_PREFIX + "/create";
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
json.addProperty("action_name", "QR_LIMIT_SCENE"); json.addProperty("action_name", "QR_LIMIT_SCENE");
JsonObject actionInfo = new JsonObject(); JsonObject actionInfo = new JsonObject();
JsonObject scene = new JsonObject(); JsonObject scene = new JsonObject();
scene.addProperty("scene_id", scene_id);
scene.addProperty("scene_id", sceneId);
actionInfo.add("scene", scene); actionInfo.add("scene", scene);
json.add("action_info", actionInfo); json.add("action_info", actionInfo);
String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString());
String responseContent = this.wxMpService.post(url, json.toString());
return WxMpQrCodeTicket.fromJson(responseContent); return WxMpQrCodeTicket.fromJson(responseContent);
} }


@Override @Override
public WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException {
public WxMpQrCodeTicket qrCodeCreateLastTicket(String sceneStr) throws WxErrorException {
String url = API_URL_PREFIX + "/create"; String url = API_URL_PREFIX + "/create";
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
json.addProperty("action_name", "QR_LIMIT_STR_SCENE"); json.addProperty("action_name", "QR_LIMIT_STR_SCENE");
JsonObject actionInfo = new JsonObject(); JsonObject actionInfo = new JsonObject();
JsonObject scene = new JsonObject(); JsonObject scene = new JsonObject();
scene.addProperty("scene_str", scene_str);
scene.addProperty("scene_str", sceneStr);
actionInfo.add("scene", scene); actionInfo.add("scene", scene);
json.add("action_info", actionInfo); json.add("action_info", actionInfo);
String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString());
String responseContent = this.wxMpService.post(url, json.toString());
return WxMpQrCodeTicket.fromJson(responseContent); return WxMpQrCodeTicket.fromJson(responseContent);
} }


@@ -81,7 +98,7 @@ public class WxMpQrcodeServiceImpl implements WxMpQrcodeService {
String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s"; String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s";
try { try {
String resultUrl = String.format(url, String resultUrl = String.format(url,
URLEncoder.encode(ticket, StandardCharsets.UTF_8.name()));
URLEncoder.encode(ticket, StandardCharsets.UTF_8.name()));
if (needShortUrl) { if (needShortUrl) {
return this.wxMpService.shortUrl(resultUrl); return this.wxMpService.shortUrl(resultUrl);
} }
@@ -89,7 +106,7 @@ public class WxMpQrcodeServiceImpl implements WxMpQrcodeService {
return resultUrl; return resultUrl;
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
WxError error = WxError.newBuilder().setErrorCode(-1) WxError error = WxError.newBuilder().setErrorCode(-1)
.setErrorMsg(e.getMessage()).build();
.setErrorMsg(e.getMessage()).build();
throw new WxErrorException(error); throw new WxErrorException(error);
} }
} }


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

@@ -20,8 +20,6 @@ import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -30,53 +28,39 @@ import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;


//import org.apache.http.conn.ssl.DefaultHostnameVerifier;
//import org.apache.http.conn.ssl.SSLConnectionSocketFactory;

public class WxMpServiceImpl implements WxMpService { public class WxMpServiceImpl implements WxMpService {


private static final JsonParser JSON_PARSER = new JsonParser(); private static final JsonParser JSON_PARSER = new JsonParser();


protected final Logger log = LoggerFactory.getLogger(this.getClass()); protected final Logger log = LoggerFactory.getLogger(this.getClass());

private WxMpConfigStorage configStorage;

protected WxSessionManager sessionManager = new StandardSessionManager();
private WxMpConfigStorage wxMpConfigStorage;
private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this);

private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this);

private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); private WxMpMenuService menuService = new WxMpMenuServiceImpl(this);

private WxMpUserService userService = new WxMpUserServiceImpl(this); private WxMpUserService userService = new WxMpUserServiceImpl(this);

private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this); private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this);

private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this);

private WxMpCardService cardService = new WxMpCardServiceImpl(this); private WxMpCardService cardService = new WxMpCardServiceImpl(this);

private WxMpPayService payService = new WxMpPayServiceImpl(this); private WxMpPayService payService = new WxMpPayServiceImpl(this);

private WxMpStoreService storeService = new WxMpStoreServiceImpl(this); private WxMpStoreService storeService = new WxMpStoreServiceImpl(this);

private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this); private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this);

private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this); private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this);

private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this);
private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this);
private CloseableHttpClient httpClient; private CloseableHttpClient httpClient;

private HttpHost httpProxy; private HttpHost httpProxy;

private int retrySleepMillis = 1000; private int retrySleepMillis = 1000;

private int maxRetryTimes = 5; private int maxRetryTimes = 5;


protected WxSessionManager sessionManager = new StandardSessionManager();

@Override @Override
public boolean checkSignature(String timestamp, String nonce, String signature) { public boolean checkSignature(String timestamp, String nonce, String signature) {
try { try {
return SHA1.gen(this.configStorage.getToken(), timestamp, nonce)
.equals(signature);
return SHA1.gen(this.wxMpConfigStorage.getToken(), timestamp, nonce)
.equals(signature);
} catch (Exception e) { } catch (Exception e) {
return false; return false;
} }
@@ -89,18 +73,18 @@ public class WxMpServiceImpl implements WxMpService {


@Override @Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException { public String getAccessToken(boolean forceRefresh) throws WxErrorException {
Lock lock = this.configStorage.getAccessTokenLock();
Lock lock = this.wxMpConfigStorage.getAccessTokenLock();
try { try {
lock.lock(); lock.lock();


if (forceRefresh) { if (forceRefresh) {
this.configStorage.expireAccessToken();
this.wxMpConfigStorage.expireAccessToken();
} }


if (this.configStorage.isAccessTokenExpired()) {
if (this.wxMpConfigStorage.isAccessTokenExpired()) {
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
"&appid=" + this.configStorage.getAppId() + "&secret="
+ this.configStorage.getSecret();
"&appid=" + this.wxMpConfigStorage.getAppId() + "&secret="
+ this.wxMpConfigStorage.getSecret();
try { try {
HttpGet httpGet = new HttpGet(url); HttpGet httpGet = new HttpGet(url);
if (this.httpProxy != null) { if (this.httpProxy != null) {
@@ -114,9 +98,9 @@ public class WxMpServiceImpl implements WxMpService {
throw new WxErrorException(error); throw new WxErrorException(error);
} }
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
this.configStorage.updateAccessToken(accessToken.getAccessToken(),
accessToken.getExpiresIn());
}finally {
this.wxMpConfigStorage.updateAccessToken(accessToken.getAccessToken(),
accessToken.getExpiresIn());
} finally {
httpGet.releaseConnection(); httpGet.releaseConnection();
} }
} catch (IOException e) { } catch (IOException e) {
@@ -126,7 +110,7 @@ public class WxMpServiceImpl implements WxMpService {
} finally { } finally {
lock.unlock(); lock.unlock();
} }
return this.configStorage.getAccessToken();
return this.wxMpConfigStorage.getAccessToken();
} }


@Override @Override
@@ -136,27 +120,27 @@ public class WxMpServiceImpl implements WxMpService {


@Override @Override
public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
Lock lock = this.configStorage.getJsapiTicketLock();
Lock lock = this.wxMpConfigStorage.getJsapiTicketLock();
try { try {
lock.lock(); lock.lock();


if (forceRefresh) { if (forceRefresh) {
this.configStorage.expireJsapiTicket();
this.wxMpConfigStorage.expireJsapiTicket();
} }


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


@Override @Override
@@ -165,11 +149,11 @@ public class WxMpServiceImpl implements WxMpService {
String noncestr = RandomUtils.getRandomStr(); String noncestr = RandomUtils.getRandomStr();
String jsapiTicket = getJsapiTicket(false); String jsapiTicket = getJsapiTicket(false);
String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket, String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket,
"noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url);
"noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url);
WxJsapiSignature jsapiSignature = new WxJsapiSignature(); WxJsapiSignature jsapiSignature = new WxJsapiSignature();
jsapiSignature.setAppid(this.configStorage.getAppId());
jsapiSignature.setAppId(this.wxMpConfigStorage.getAppId());
jsapiSignature.setTimestamp(timestamp); jsapiSignature.setTimestamp(timestamp);
jsapiSignature.setNoncestr(noncestr);
jsapiSignature.setNonceStr(noncestr);
jsapiSignature.setUrl(url); jsapiSignature.setUrl(url);
jsapiSignature.setSignature(signature); jsapiSignature.setSignature(signature);
return jsapiSignature; return jsapiSignature;
@@ -232,7 +216,7 @@ public class WxMpServiceImpl implements WxMpService {
public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) {
StringBuilder url = new StringBuilder(); StringBuilder url = new StringBuilder();
url.append("https://open.weixin.qq.com/connect/oauth2/authorize?"); url.append("https://open.weixin.qq.com/connect/oauth2/authorize?");
url.append("appid=").append(this.configStorage.getAppId());
url.append("appid=").append(this.wxMpConfigStorage.getAppId());
url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI));
url.append("&response_type=code"); url.append("&response_type=code");
url.append("&scope=").append(scope); url.append("&scope=").append(scope);
@@ -245,10 +229,10 @@ public class WxMpServiceImpl implements WxMpService {


@Override @Override
public String buildQrConnectUrl(String redirectURI, String scope, public String buildQrConnectUrl(String redirectURI, String scope,
String state) {
String state) {
StringBuilder url = new StringBuilder(); StringBuilder url = new StringBuilder();
url.append("https://open.weixin.qq.com/connect/qrconnect?"); url.append("https://open.weixin.qq.com/connect/qrconnect?");
url.append("appid=").append(this.configStorage.getAppId());
url.append("appid=").append(this.wxMpConfigStorage.getAppId());
url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI));
url.append("&response_type=code"); url.append("&response_type=code");
url.append("&scope=").append(scope); url.append("&scope=").append(scope);
@@ -274,8 +258,8 @@ public class WxMpServiceImpl implements WxMpService {
public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException {
StringBuilder url = new StringBuilder(); StringBuilder url = new StringBuilder();
url.append("https://api.weixin.qq.com/sns/oauth2/access_token?"); url.append("https://api.weixin.qq.com/sns/oauth2/access_token?");
url.append("appid=").append(this.configStorage.getAppId());
url.append("&secret=").append(this.configStorage.getSecret());
url.append("appid=").append(this.wxMpConfigStorage.getAppId());
url.append("&secret=").append(this.wxMpConfigStorage.getSecret());
url.append("&code=").append(code); url.append("&code=").append(code);
url.append("&grant_type=authorization_code"); url.append("&grant_type=authorization_code");


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


@@ -364,15 +348,21 @@ public class WxMpServiceImpl implements WxMpService {
do { do {
try { try {
T result = executeInternal(executor, uri, data); T result = executeInternal(executor, uri, data);
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",uri, data, result);
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, result);
return result; return result;
} catch (WxErrorException e) { } catch (WxErrorException e) {
if (retryTimes + 1 > this.maxRetryTimes) {
this.log.warn("重试达到最大次数【{}】", maxRetryTimes);
//最后一次重试失败后,直接抛出异常,不再等待
throw new RuntimeException("微信服务端异常,超出重试次数");
}

WxError error = e.getError(); WxError error = e.getError();
// -1 系统繁忙, 1000ms后重试 // -1 系统繁忙, 1000ms后重试
if (error.getErrorCode() == -1) { if (error.getErrorCode() == -1) {
int sleepMillis = this.retrySleepMillis * (1 << retryTimes); int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
try { try {
this.log.debug("微信系统繁忙,{}ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
Thread.sleep(sleepMillis); Thread.sleep(sleepMillis);
} catch (InterruptedException e1) { } catch (InterruptedException e1) {
throw new RuntimeException(e1); throw new RuntimeException(e1);
@@ -381,8 +371,9 @@ public class WxMpServiceImpl implements WxMpService {
throw e; throw e;
} }
} }
} while (++retryTimes < this.maxRetryTimes);
} while (retryTimes++ < this.maxRetryTimes);


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


@@ -406,15 +397,14 @@ public class WxMpServiceImpl implements WxMpService {
*/ */
if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) {
// 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token
this.configStorage.expireAccessToken();
if(this.configStorage.autoRefreshToken()){
this.wxMpConfigStorage.expireAccessToken();
if (this.wxMpConfigStorage.autoRefreshToken()) {
return this.execute(executor, uri, data); return this.execute(executor, uri, data);
} }
} }


if (error.getErrorCode() != 0) { if (error.getErrorCode() != 0) {
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data,
error);
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, error);
throw new WxErrorException(error); throw new WxErrorException(error);
} }
return null; return null;
@@ -433,33 +423,27 @@ public class WxMpServiceImpl implements WxMpService {
return this.httpClient; return this.httpClient;
} }


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

private void initHttpClient() { private void initHttpClient() {
ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage
.getApacheHttpClientBuilder();
ApacheHttpClientBuilder apacheHttpClientBuilder = this.wxMpConfigStorage
.getApacheHttpClientBuilder();
if (null == apacheHttpClientBuilder) { if (null == apacheHttpClientBuilder) {
apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get();
} }


apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost())
.httpProxyPort(this.configStorage.getHttpProxyPort())
.httpProxyUsername(this.configStorage.getHttpProxyUsername())
.httpProxyPassword(this.configStorage.getHttpProxyPassword());
apacheHttpClientBuilder.httpProxyHost(this.wxMpConfigStorage.getHttpProxyHost())
.httpProxyPort(this.wxMpConfigStorage.getHttpProxyPort())
.httpProxyUsername(this.wxMpConfigStorage.getHttpProxyUsername())
.httpProxyPassword(this.wxMpConfigStorage.getHttpProxyPassword());


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


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


this.httpClient = apacheHttpClientBuilder.build(); this.httpClient = apacheHttpClientBuilder.build();
@@ -467,7 +451,13 @@ public class WxMpServiceImpl implements WxMpService {


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

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


@Override @Override
@@ -540,4 +530,8 @@ public class WxMpServiceImpl implements WxMpService {
return this.templateMsgService; return this.templateMsgService;
} }


@Override
public WxMpDeviceService getDeviceService() {
return this.deviceService;
}
} }

+ 17
- 5
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java View File

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


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

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


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

/** /**
* openid列表群发的消息 * openid列表群发的消息
*
*
* @author chanjarster * @author chanjarster
*/ */
public class WxMpMassOpenIdsMessage implements Serializable { public class WxMpMassOpenIdsMessage implements Serializable {
private static final long serialVersionUID = -8022910911104788999L; private static final long serialVersionUID = -8022910911104788999L;
private List<String> toUsers = new ArrayList<>(); private List<String> toUsers = new ArrayList<>();
private String msgType; private String msgType;
private String content; private String content;
private String mediaId; private String mediaId;
private boolean sendIgnoreReprint = false;


public WxMpMassOpenIdsMessage() { public WxMpMassOpenIdsMessage() {
super(); super();
} }
public String getMsgType() { public String getMsgType() {
return this.msgType; return this.msgType;
} }
@@ -86,4 +87,15 @@ public class WxMpMassOpenIdsMessage implements Serializable {
this.toUsers = toUsers; this.toUsers = toUsers;
} }


public boolean isSendIgnoreReprint() {
return sendIgnoreReprint;
}

/**
*
* @param sendIgnoreReprint 文章被判定为转载时,是否继续进行群发操作。
*/
public void setSendIgnoreReprint(boolean sendIgnoreReprint) {
this.sendIgnoreReprint = sendIgnoreReprint;
}
} }

+ 42
- 12
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java View File

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


import java.io.Serializable;

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


import java.io.Serializable;

/** /**
* 按标签群发的消息 * 按标签群发的消息
*
*
* @author chanjarster * @author chanjarster
*/ */
public class WxMpMassTagMessage implements Serializable { public class WxMpMassTagMessage implements Serializable {
private static final long serialVersionUID = -6625914040986749286L; private static final long serialVersionUID = -6625914040986749286L;
private Long tagId; private Long tagId;
private String msgtype;
private String msgType;
private String content; private String content;
private String mediaId; private String mediaId;
private boolean isSendAll = false;
private boolean sendIgnoreReprint = false;


public WxMpMassTagMessage() { public WxMpMassTagMessage() {
super(); super();
} }
public String getMsgtype() {
return this.msgtype;
public String getMsgType() {
return this.msgType;
} }


/** /**
@@ -35,10 +37,11 @@ public class WxMpMassTagMessage implements Serializable {
* {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_VOICE} * {@link me.chanjar.weixin.common.api.WxConsts#MASS_MSG_VOICE}
* 如果msgtype和media_id不匹配的话,会返回系统繁忙的错误 * 如果msgtype和media_id不匹配的话,会返回系统繁忙的错误
* </pre> * </pre>
* @param msgtype
*
* @param msgType 消息类型
*/ */
public void setMsgtype(String msgtype) {
this.msgtype = msgtype;
public void setMsgType(String msgType) {
this.msgType = msgType;
} }


public String getContent() { public String getContent() {
@@ -67,10 +70,37 @@ public class WxMpMassTagMessage implements Serializable {


/** /**
* 如果不设置则就意味着发给所有用户 * 如果不设置则就意味着发给所有用户
* @param tagId
*
* @param tagId 标签id
*/ */
public void setTagId(Long tagId) { public void setTagId(Long tagId) {
this.tagId = tagId; this.tagId = tagId;
} }


public boolean isSendIgnoreReprint() {
return sendIgnoreReprint;
}

/**
*
* @param sendIgnoreReprint 文章被判定为转载时,是否继续进行群发操作。
*/
public void setSendIgnoreReprint(boolean sendIgnoreReprint) {
this.sendIgnoreReprint = sendIgnoreReprint;
}

/**
* 是否群发给所有用户
*/
public boolean isSendAll() {
return isSendAll;
}

public void setSendAll(boolean sendAll) {
if(sendAll){
this.tagId = null;
}

isSendAll = sendAll;
}
} }

+ 12
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/AbstractDeviceBean.java View File

@@ -0,0 +1,12 @@
package me.chanjar.weixin.mp.bean.device;

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

/**
* Created by keungtung on 14/12/2016.
*/
public abstract class AbstractDeviceBean {
public String toJson() {
return WxGsonBuilder.create().toJson(this);
}
}

+ 60
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java View File

@@ -0,0 +1,60 @@
package me.chanjar.weixin.mp.bean.device;

import com.google.gson.annotations.SerializedName;

/**
* Created by keungtung on 10/12/2016.
*/
public class BaseResp extends AbstractDeviceBean{
@SerializedName("base_info")
private BaseInfo baseInfo;
@SerializedName("errcode")
private Integer errCode;
@SerializedName("errmsg")
private String errMsg;

public Integer getErrCode() {
return errCode;
}

public void setErrCode(Integer errCode) {
this.errCode = errCode;
}

public BaseInfo getBaseInfo() {
return baseInfo;
}

public void setBaseInfo(BaseInfo baseInfo) {
this.baseInfo = baseInfo;
}

public String getErrMsg() {
return errMsg;
}

public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}

private class BaseInfo {
private String device_type;
private String device_id;

public String getDevice_type() {
return device_type;
}

public void setDevice_type(String device_type) {
this.device_type = device_type;
}

public String getDevice_id() {
return device_id;
}

public void setDevice_id(String device_id) {
this.device_id = device_id;
}
}
}

+ 30
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/RespMsg.java View File

@@ -0,0 +1,30 @@
package me.chanjar.weixin.mp.bean.device;

import com.google.gson.annotations.SerializedName;

/**
* Created by keungtung on 10/12/2016.
*/

public class RespMsg extends AbstractDeviceBean{
@SerializedName("ret_code")
private Integer retCode;
@SerializedName("error_info")
private String errorInfo;

public Integer getRetCode() {
return retCode;
}

public void setRetCode(Integer retCode) {
this.retCode = retCode;
}

public String getErrorInfo() {
return errorInfo;
}

public void setErrorInfo(String errorInfo) {
this.errorInfo = errorInfo;
}
}

+ 53
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/TransMsgResp.java View File

@@ -0,0 +1,53 @@
package me.chanjar.weixin.mp.bean.device;

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

/**
* Created by keungtung on 14/12/2016.
*/
public class TransMsgResp extends AbstractDeviceBean{
private Integer ret;
@SerializedName("ret_info")
private String retInfo;
@SerializedName("errcode")
private Integer errCode;
@SerializedName("errmsg")
private String errMsg;

public static TransMsgResp fromJson(String json) {
return WxGsonBuilder.create().fromJson(json, TransMsgResp.class);
}

public Integer getRet() {
return ret;
}

public void setRet(Integer ret) {
this.ret = ret;
}

public String getRetInfo() {
return retInfo;
}

public void setRetInfo(String retInfo) {
this.retInfo = retInfo;
}

public Integer getErrCode() {
return errCode;
}

public void setErrCode(Integer errCode) {
this.errCode = errCode;
}

public String getErrMsg() {
return errMsg;
}

public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
}

+ 117
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDevice.java View File

@@ -0,0 +1,117 @@
package me.chanjar.weixin.mp.bean.device;

import com.google.gson.annotations.SerializedName;

/**
* Created by keungtung on 10/12/2016.
*/
public class WxDevice {
private String id;
private String mac;
@SerializedName("connect_protocol")
private String connectProtocol;
@SerializedName("auth_key")
private String authKey;
@SerializedName("close_strategy")
private String closeStrategy;
@SerializedName("conn_strategy")
private String connStrategy;
@SerializedName("crypt_method")
private String cryptMethod;
@SerializedName("auth_ver")
private String authVer;
@SerializedName("manu_mac_pos")
private String manuMacPos;
@SerializedName("ser_mac_pos")
private String serMacPos;
@SerializedName("ble_simple_protocol")
private String bleSimpleProtocol;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getMac() {
return mac;
}

public void setMac(String mac) {
this.mac = mac;
}

public String getConnectProtocol() {
return connectProtocol;
}

public void setConnectProtocol(String connectProtocol) {
this.connectProtocol = connectProtocol;
}

public String getAuthKey() {
return authKey;
}

public void setAuthKey(String authKey) {
this.authKey = authKey;
}

public String getCloseStrategy() {
return closeStrategy;
}

public void setCloseStrategy(String closeStrategy) {
this.closeStrategy = closeStrategy;
}

public String getConnStrategy() {
return connStrategy;
}

public void setConnStrategy(String connStrategy) {
this.connStrategy = connStrategy;
}

public String getCryptMethod() {
return cryptMethod;
}

public void setCryptMethod(String cryptMethod) {
this.cryptMethod = cryptMethod;
}

public String getAuthVer() {
return authVer;
}

public void setAuthVer(String authVer) {
this.authVer = authVer;
}

public String getManuMacPos() {
return manuMacPos;
}

public void setManuMacPos(String manuMacPos) {
this.manuMacPos = manuMacPos;
}

public String getSerMacPos() {
return serMacPos;
}

public void setSerMacPos(String serMacPos) {
this.serMacPos = serMacPos;
}

public String getBleSimpleProtocol() {
return bleSimpleProtocol;
}

public void setBleSimpleProtocol(String bleSimpleProtocol) {
this.bleSimpleProtocol = bleSimpleProtocol;
}
}

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

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

import com.google.gson.annotations.SerializedName;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
* Created by keungtung on 10/12/2016.
*/
public class WxDeviceAuthorize extends AbstractDeviceBean {
@SerializedName("device_num")
private String deviceNum;
@SerializedName("op_type")
private String opType;
@SerializedName("product_id")
private String productId;
@SerializedName("device_list")
private List<WxDevice> deviceList = new LinkedList<>();

public String getDeviceNum() {
return deviceNum;
}

public void setDeviceNum(String deviceNum) {
this.deviceNum = deviceNum;
}

public String getOpType() {
return opType;
}

public void setOpType(String opType) {
this.opType = opType;
}

public String getProductId() {
return productId;
}

public void setProductId(String productId) {
this.productId = productId;
}

public List<WxDevice> getDeviceList() {
return deviceList;
}

public void setDeviceList(List<WxDevice> deviceList) {
this.deviceList = deviceList;
}

public void addDevice(WxDevice... devices) {
this.deviceList.addAll(Arrays.asList(devices));
}
}

+ 24
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceAuthorizeResult.java View File

@@ -0,0 +1,24 @@
package me.chanjar.weixin.mp.bean.device;

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

import java.util.List;

/**
* Created by keungtung on 10/12/2016.
*/
public class WxDeviceAuthorizeResult extends AbstractDeviceBean{
private List<BaseResp> resp;

public static WxDeviceAuthorizeResult fromJson(String response) {
return WxGsonBuilder.create().fromJson(response, WxDeviceAuthorizeResult.class);
}

public List<BaseResp> getResp() {
return resp;
}

public void setResp(List<BaseResp> resp) {
this.resp = resp;
}
}

+ 38
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBind.java View File

@@ -0,0 +1,38 @@
package me.chanjar.weixin.mp.bean.device;

import com.google.gson.annotations.SerializedName;

/**
* Created by keungtung on 10/12/2016.
*/
public class WxDeviceBind extends AbstractDeviceBean{
private String ticket;
@SerializedName("device_id")
private String deviceId;
@SerializedName("openid")
private String openId;

public String getTicket() {
return ticket;
}

public void setTicket(String ticket) {
this.ticket = ticket;
}

public String getDeviceId() {
return deviceId;
}

public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}

public String getOpenId() {
return openId;
}

public void setOpenId(String openId) {
this.openId = openId;
}
}

+ 24
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceBindResult.java View File

@@ -0,0 +1,24 @@
package me.chanjar.weixin.mp.bean.device;

import com.google.gson.annotations.SerializedName;
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
* Created by keungtung on 10/12/2016.
*/
public class WxDeviceBindResult extends AbstractDeviceBean{
@SerializedName("base_resp")
private BaseResp baseResp;

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

public BaseResp getBaseResp() {
return baseResp;
}

public void setBaseResp(BaseResp baseResp) {
this.baseResp = baseResp;
}
}

+ 54
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceMsg.java View File

@@ -0,0 +1,54 @@
package me.chanjar.weixin.mp.bean.device;

import com.google.gson.annotations.SerializedName;
import me.chanjar.weixin.common.util.ToStringUtils;

/**
* Created by keungtung on 10/12/2016.
*/
public class WxDeviceMsg extends AbstractDeviceBean{
@SerializedName("device_type")
private String deviceType;
@SerializedName("device_id")
private String deviceId;
@SerializedName("open_id")
private String openId;
private String content;

@Override
public String toString() {
return ToStringUtils.toSimpleString(this);
}

public String getDeviceType() {
return deviceType;
}

public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}

public String getDeviceId() {
return deviceId;
}

public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}

public String getOpenId() {
return openId;
}

public void setOpenId(String openId) {
this.openId = openId;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}
}

+ 54
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/WxDeviceQrCodeResult.java View File

@@ -0,0 +1,54 @@
package me.chanjar.weixin.mp.bean.device;

import com.google.gson.annotations.SerializedName;
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
* Created by keungtung on 10/12/2016.
*/
public class WxDeviceQrCodeResult extends AbstractDeviceBean{
@SerializedName("deviceid")
private String deviceId;
@SerializedName("qrticket")
private String qrTicket;
@SerializedName("devicelicence")
private String deviceLicence;
@SerializedName("resp_msg")
private RespMsg respMsg;

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

public String getDeviceLicence() {
return deviceLicence;
}

public void setDeviceLicence(String deviceLicence) {
this.deviceLicence = deviceLicence;
}

public RespMsg getRespMsg() {
return respMsg;
}

public void setRespMsg(RespMsg respMsg) {
this.respMsg = respMsg;
}

public String getDeviceId() {
return deviceId;
}

public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}

public String getQrTicket() {
return qrTicket;
}

public void setQrTicket(String qrTicket) {
this.qrTicket = qrTicket;
}
}

+ 92
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpMenu.java View File

@@ -0,0 +1,92 @@
package me.chanjar.weixin.mp.bean.menu;

import com.google.gson.annotations.SerializedName;
import me.chanjar.weixin.common.bean.menu.WxMenuButton;
import me.chanjar.weixin.common.bean.menu.WxMenuRule;
import me.chanjar.weixin.common.util.ToStringUtils;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;

import java.util.List;

/**
* <pre>
* 公众号专用的菜单类,可能包含个性化菜单
* Created by Binary Wang on 2017-1-17.
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
* </pre>
*/
public class WxMpMenu {
@SerializedName("menu")
private WxMpConditionalMenu menu;

@SerializedName("conditionalmenu")
private List<WxMpConditionalMenu> conditionalMenu;

public static WxMpMenu fromJson(String json) {
return WxGsonBuilder.create().fromJson(json, WxMpMenu.class);
}

public WxMpConditionalMenu getMenu() {
return menu;
}

public void setMenu(WxMpConditionalMenu menu) {
this.menu = menu;
}

public List<WxMpConditionalMenu> getConditionalMenu() {
return conditionalMenu;
}

public void setConditionalMenu(List<WxMpConditionalMenu> conditionalMenu) {
this.conditionalMenu = conditionalMenu;
}

@Override
public String toString() {
return ToStringUtils.toSimpleString(this);
}

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

public static class WxMpConditionalMenu {
@SerializedName("button")
private List<WxMenuButton> buttons;
@SerializedName("matchrule")
private WxMenuRule rule;
@SerializedName("menuid")
private String menuId;

@Override
public String toString() {
return ToStringUtils.toSimpleString(this);
}

public List<WxMenuButton> getButtons() {
return buttons;
}

public void setButtons(List<WxMenuButton> buttons) {
this.buttons = buttons;
}

public WxMenuRule getRule() {
return rule;
}

public void setRule(WxMenuRule rule) {
this.rule = rule;
}

public String getMenuId() {
return menuId;
}

public void setMenuId(String menuId) {
this.menuId = menuId;
}
}

}

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

@@ -281,6 +281,12 @@ public class WxMpXmlMessage implements Serializable {
@XStreamConverter(value = XStreamCDataConverter.class) @XStreamConverter(value = XStreamCDataConverter.class)
private String deviceId; private String deviceId;


/**
* 微信用户账号的OpenID
*/
@XStreamAlias("OpenID")
@XStreamConverter(value = XStreamCDataConverter.class)
private String openId;


@XStreamAlias("HardWare") @XStreamAlias("HardWare")
private HardWare hardWare = new HardWare(); private HardWare hardWare = new HardWare();
@@ -375,6 +381,14 @@ public class WxMpXmlMessage implements Serializable {
this.deviceId = deviceId; this.deviceId = deviceId;
} }


public String getOpenId() {
return openId;
}

public void setOpenId(String openId) {
this.openId = openId;
}

public Long getExpiredTime() { public Long getExpiredTime() {
return this.expiredTime; return this.expiredTime;
} }


+ 2
- 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java View File

@@ -62,7 +62,8 @@ public abstract class WxMpXmlOutMessage implements Serializable {
this.msgType = msgType; this.msgType = msgType;
} }


public String toXml() {
@SuppressWarnings("unchecked")
public String toXml() {
return XStreamTransformer.toXml((Class<WxMpXmlOutMessage>) this.getClass(), this); return XStreamTransformer.toXml((Class<WxMpXmlOutMessage>) this.getClass(), this);
} }




+ 0
- 267
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxPayJsSDKCallback.java View File

@@ -1,267 +0,0 @@
package me.chanjar.weixin.mp.bean.pay;

import me.chanjar.weixin.common.util.ToStringUtils;

import java.io.Serializable;

/**
* <pre>
* 订单支付状态回调
* 支付结果通知(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7)
* /pre>
*
* @author ukid
*/
public class WxPayJsSDKCallback implements Serializable {
private static final long serialVersionUID = -4143804055690843641L;
private String return_code;
private String return_msg;

private String appid;
private String mch_id;
private String device_info;
private String nonce_str;
private String sign;
private String result_code;
private String err_code;
private String err_code_des;
private String openid;
private String is_subscribe;
private String trade_type;
private String bank_type;
private String total_fee;
private String fee_type;
private String cash_fee;
private String cash_fee_type;
private String coupon_fee;
private String coupon_count;
private String coupon_batch_id_$n;
private String coupon_id_$n;
private String coupon_fee_$n;
private String transaction_id;
private String out_trade_no;
private String attach;
private String time_end;

public String getReturn_code() {
return this.return_code;
}

public void setReturn_code(String return_code) {
this.return_code = return_code;
}

public String getReturn_msg() {
return this.return_msg;
}

public void setReturn_msg(String return_msg) {
this.return_msg = return_msg;
}

public String getAppid() {
return this.appid;
}

public void setAppid(String appid) {
this.appid = appid;
}

public String getMch_id() {
return this.mch_id;
}

public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}

public String getDevice_info() {
return this.device_info;
}

public void setDevice_info(String device_info) {
this.device_info = device_info;
}

public String getNonce_str() {
return this.nonce_str;
}

public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}

public String getSign() {
return this.sign;
}

public void setSign(String sign) {
this.sign = sign;
}

public String getResult_code() {
return this.result_code;
}

public void setResult_code(String result_code) {
this.result_code = result_code;
}

public String getErr_code() {
return this.err_code;
}

public void setErr_code(String err_code) {
this.err_code = err_code;
}

public String getErr_code_des() {
return this.err_code_des;
}

public void setErr_code_des(String err_code_des) {
this.err_code_des = err_code_des;
}

public String getOpenid() {
return this.openid;
}

public void setOpenid(String openid) {
this.openid = openid;
}

public String getIs_subscribe() {
return this.is_subscribe;
}

public void setIs_subscribe(String is_subscribe) {
this.is_subscribe = is_subscribe;
}

public String getTrade_type() {
return this.trade_type;
}

public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}

public String getBank_type() {
return this.bank_type;
}

public void setBank_type(String bank_type) {
this.bank_type = bank_type;
}

public String getTotal_fee() {
return this.total_fee;
}

public void setTotal_fee(String total_fee) {
this.total_fee = total_fee;
}

public String getFee_type() {
return this.fee_type;
}

public void setFee_type(String fee_type) {
this.fee_type = fee_type;
}

public String getCash_fee() {
return this.cash_fee;
}

public void setCash_fee(String cash_fee) {
this.cash_fee = cash_fee;
}

public String getCash_fee_type() {
return this.cash_fee_type;
}

public void setCash_fee_type(String cash_fee_type) {
this.cash_fee_type = cash_fee_type;
}

public String getCoupon_fee() {
return this.coupon_fee;
}

public void setCoupon_fee(String coupon_fee) {
this.coupon_fee = coupon_fee;
}

public String getCoupon_count() {
return this.coupon_count;
}

public void setCoupon_count(String coupon_count) {
this.coupon_count = coupon_count;
}

public String getCoupon_batch_id_$n() {
return this.coupon_batch_id_$n;
}

public void setCoupon_batch_id_$n(String coupon_batch_id_$n) {
this.coupon_batch_id_$n = coupon_batch_id_$n;
}

public String getCoupon_id_$n() {
return this.coupon_id_$n;
}

public void setCoupon_id_$n(String coupon_id_$n) {
this.coupon_id_$n = coupon_id_$n;
}

public String getCoupon_fee_$n() {
return this.coupon_fee_$n;
}

public void setCoupon_fee_$n(String coupon_fee_$n) {
this.coupon_fee_$n = coupon_fee_$n;
}

public String getTransaction_id() {
return this.transaction_id;
}

public void setTransaction_id(String transaction_id) {
this.transaction_id = transaction_id;
}

public String getOut_trade_no() {
return this.out_trade_no;
}

public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}

public String getAttach() {
return this.attach;
}

public void setAttach(String attach) {
this.attach = attach;
}

public String getTime_end() {
return this.time_end;
}

public void setTime_end(String time_end) {
this.time_end = time_end;
}

@Override
public String toString() {
return ToStringUtils.toSimpleString(this);
}

}

+ 64
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxPayOrderNotifyCoupon.java View File

@@ -0,0 +1,64 @@
package me.chanjar.weixin.mp.bean.pay;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 支付异步通知代金券详细
*/
public class WxPayOrderNotifyCoupon implements Serializable {
/**
* @fields serialVersionUID
*/
private static final long serialVersionUID = -4165343733538156097L;
@XStreamAlias("coupon_id")
private String couponId;
@XStreamAlias("coupon_type")
private String couponType;
@XStreamAlias("coupon_fee")
private Integer couponFee;
public String getCouponId() {
return couponId;
}
public void setCouponId(String couponId) {
this.couponId = couponId;
}
public String getCouponType() {
return couponType;
}
public void setCouponType(String couponType) {
this.couponType = couponType;
}
public Integer getCouponFee() {
return couponFee;
}
public void setCouponFee(Integer couponFee) {
this.couponFee = couponFee;
}
public Map<String, String> toMap(int index) {
Map<String, String> map = new HashMap<>();
map.put("coupon_id_" + index, this.getCouponId());
map.put("coupon_type_" + index, this.getCouponType());
map.put("coupon_fee_" + index, this.getCouponFee() + "");
return map;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}

+ 60
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxPayOrderNotifyResponse.java View File

@@ -0,0 +1,60 @@
package me.chanjar.weixin.mp.bean.pay;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
@XStreamAlias("xml")
public class WxPayOrderNotifyResponse {
@XStreamOmitField
private transient static final String FAIL = "FAIL";
@XStreamOmitField
private transient static final String SUCCESS = "SUCCESS";
@XStreamAlias("return_code")
private String returnCode;
@XStreamAlias("return_msg")
private String returnMsg;
public String getReturnCode() {
return returnCode;
}
public void setReturnCode(String returnCode) {
this.returnCode = returnCode;
}
public String getReturnMsg() {
return returnMsg;
}
public void setReturnMsg(String returnMsg) {
this.returnMsg = returnMsg;
}
public WxPayOrderNotifyResponse() {
super();
}
public WxPayOrderNotifyResponse(String returnCode, String returnMsg) {
super();
this.returnCode = returnCode;
this.returnMsg = returnMsg;
}
public static String fail(String msg) {
WxPayOrderNotifyResponse response = new WxPayOrderNotifyResponse(FAIL, msg);
XStream xstream = XStreamInitializer.getInstance();
xstream.autodetectAnnotations(true);
return xstream.toXML(response);
}
public static String success(String msg) {
WxPayOrderNotifyResponse response = new WxPayOrderNotifyResponse(SUCCESS, msg);
XStream xstream = XStreamInitializer.getInstance();
xstream.autodetectAnnotations(true);
return xstream.toXML(response);
}
}

+ 130
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxPayOrderNotifyResultConverter.java View File

@@ -0,0 +1,130 @@
package me.chanjar.weixin.mp.bean.pay;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter;
import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.mapper.Mapper;
import me.chanjar.weixin.mp.bean.pay.result.WxPayOrderNotifyResult;
public class WxPayOrderNotifyResultConverter extends AbstractReflectionConverter {
public WxPayOrderNotifyResultConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
super(mapper, reflectionProvider);
}
@Override
@SuppressWarnings("rawtypes")
public boolean canConvert(Class type) {
return type.equals(WxPayOrderNotifyResult.class);
}
@Override
public void marshal(Object original, HierarchicalStreamWriter writer, MarshallingContext context) {
super.marshal(original, writer, context);
WxPayOrderNotifyResult obj = (WxPayOrderNotifyResult) original;
List<WxPayOrderNotifyCoupon> list = obj.getCouponList();
if (list == null || list.size() == 0) {
return;
}
for (int i = 0; i < list.size(); i++) {
WxPayOrderNotifyCoupon coupon = list.get(i);
writer.startNode("coupon_id_" + i);
writer.setValue(coupon.getCouponId());
writer.endNode();
writer.startNode("coupon_type_" + i);
writer.setValue(coupon.getCouponType());
writer.endNode();
writer.startNode("coupon_fee_" + i);
writer.setValue(coupon.getCouponFee() + "");
writer.endNode();
}
}
@Override
protected void marshallField(MarshallingContext context, Object newObj, Field field) {
if (field.getName().equals("couponList")) {
return;
} else {
super.marshallField(context, newObj, field);
}
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
WxPayOrderNotifyResult obj = new WxPayOrderNotifyResult();
List<Field> fields = new ArrayList<>(Arrays.asList(obj.getClass().getDeclaredFields()));
fields.addAll(Arrays.asList(obj.getClass().getSuperclass().getDeclaredFields()));
Map<String, Field> fieldMap = getFieldMap(fields);
List<WxPayOrderNotifyCoupon> coupons = new ArrayList<>(10);
while (reader.hasMoreChildren()) {
reader.moveDown();
if (fieldMap.containsKey(reader.getNodeName())) {
Field field = fieldMap.get(reader.getNodeName());
setFieldValue(context, obj, field);
} else if (StringUtils.startsWith(reader.getNodeName(), "coupon_id_")) {
String id = (String) context.convertAnother(obj, String.class);
getIndex(coupons, reader.getNodeName()).setCouponId(id);
} else if (StringUtils.startsWith(reader.getNodeName(), "coupon_type_")) {
String type = (String) context.convertAnother(obj, String.class);
getIndex(coupons, reader.getNodeName()).setCouponType(type);
} else if (StringUtils.startsWith(reader.getNodeName(), "coupon_fee_")) {
Integer fee = (Integer) context.convertAnother(obj, Integer.class);
getIndex(coupons, reader.getNodeName()).setCouponFee(fee);
}
reader.moveUp();
}
obj.setCouponList(coupons);
return obj;
}
private void setFieldValue(UnmarshallingContext context, WxPayOrderNotifyResult obj, Field field) {
Object val = context.convertAnother(obj, field.getType());
try {
if (val != null) {
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), obj.getClass());
pd.getWriteMethod().invoke(obj, val);
}
} catch (Exception e) {
}
}
private Map<String, Field> getFieldMap(List<Field> fields) {
Map<String, Field> fieldMap = Maps.uniqueIndex(fields, new Function<Field, String>() {
@Override
public String apply(Field field) {
if (field.isAnnotationPresent(XStreamAlias.class)) {
return field.getAnnotation(XStreamAlias.class).value();
}
return field.getName();
}
});
return fieldMap;
}
private WxPayOrderNotifyCoupon getIndex(List<WxPayOrderNotifyCoupon> coupons, String nodeName) {
Integer index = Integer.valueOf(StringUtils.substring(nodeName, nodeName.lastIndexOf("_") + 1));
if (index >= coupons.size() || coupons.get(index) == null) {
coupons.add(index, new WxPayOrderNotifyCoupon());
}
return coupons.get(index);
}
}

+ 0
- 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxEntPayQueryRequest.java View File

@@ -30,7 +30,6 @@ public class WxEntPayQueryRequest extends WxPayBaseRequest {
* 微信支付分配的商户号 * 微信支付分配的商户号
* </pre> * </pre>
*/ */
@SuppressWarnings("hiding")
@XStreamAlias("mchid") @XStreamAlias("mchid")
private String mchId; private String mchId;




+ 9
- 46
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxEntPayRequest.java View File

@@ -18,7 +18,7 @@ import me.chanjar.weixin.common.util.ToStringUtils;
* @author binarywang (https://github.com/binarywang) * @author binarywang (https://github.com/binarywang)
*/ */
@XStreamAlias("xml") @XStreamAlias("xml")
public class WxEntPayRequest {
public class WxEntPayRequest extends WxPayBaseRequest{
/** /**
* <pre> * <pre>
* 公众账号appid * 公众账号appid
@@ -58,32 +58,6 @@ public class WxEntPayRequest {
@XStreamAlias("device_info") @XStreamAlias("device_info")
private String deviceInfo; private String deviceInfo;


/**
* <pre>
* 随机字符串
* nonce_str
*是
*5K8264ILTKCH16CQ2502SI8ZNMTM67VS
*String(32)
*随机字符串,不长于32位
* </pre>
*/
@XStreamAlias("nonce_str")
private String nonceStr;

/**
* <pre>
* 签名
* sign
* 是
* C380BEC2BFD727A4B6845133519F3AD6
* String(32)
*签名,详见签名算法
* </pre>
*/
@XStreamAlias("sign")
private String sign;

/** /**
* <pre> * <pre>
* 商户订单号 * 商户订单号
@@ -178,18 +152,23 @@ public class WxEntPayRequest {
@XStreamAlias("spbill_create_ip") @XStreamAlias("spbill_create_ip")
private String spbillCreateIp; private String spbillCreateIp;


public String getMchAppid() {

@Override
public String getAppid() {
return this.mchAppid; return this.mchAppid;
} }


public void setMchAppid(String mchAppid) {
this.mchAppid = mchAppid;
@Override
public void setAppid(String appid) {
this.mchAppid = appid;
} }


@Override
public String getMchId() { public String getMchId() {
return this.mchId; return this.mchId;
} }


@Override
public void setMchId(String mchId) { public void setMchId(String mchId) {
this.mchId = mchId; this.mchId = mchId;
} }
@@ -202,22 +181,6 @@ public class WxEntPayRequest {
this.deviceInfo = deviceInfo; this.deviceInfo = deviceInfo;
} }


public String getNonceStr() {
return this.nonceStr;
}

public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}

public String getSign() {
return this.sign;
}

public void setSign(String sign) {
this.sign = sign;
}

public String getPartnerTradeNo() { public String getPartnerTradeNo() {
return this.partnerTradeNo; return this.partnerTradeNo;
} }


+ 35
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayBaseRequest.java View File

@@ -1,7 +1,11 @@
package me.chanjar.weixin.mp.bean.pay.request; package me.chanjar.weixin.mp.bean.pay.request;


import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.ToStringUtils;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;

import java.math.BigDecimal;


/** /**
* <pre> * <pre>
@@ -15,6 +19,7 @@ import me.chanjar.weixin.common.util.ToStringUtils;
* <li>示例值 * <li>示例值
* <li>描述 * <li>描述
* </pre> * </pre>
*
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> * @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
*/ */
public abstract class WxPayBaseRequest { public abstract class WxPayBaseRequest {
@@ -67,10 +72,24 @@ public abstract class WxPayBaseRequest {
@XStreamAlias("sign") @XStreamAlias("sign")
protected String sign; protected String sign;


/**
* 将单位为元转换为单位为分
*
* @param yuan 将要转换的元的数值字符串
*/
public static Integer yuanToFee(String yuan) {
return new BigDecimal(yuan).setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue();
}

public String getAppid() { public String getAppid() {
return this.appid; return this.appid;
} }


/**
* 如果配置中已经设置,可以不设置值
*
* @param appid 微信公众号appid
*/
public void setAppid(String appid) { public void setAppid(String appid) {
this.appid = appid; this.appid = appid;
} }
@@ -79,6 +98,11 @@ public abstract class WxPayBaseRequest {
return this.mchId; return this.mchId;
} }


/**
* 如果配置中已经设置,可以不设置值
*
* @param mchId 微信商户号
*/
public void setMchId(String mchId) { public void setMchId(String mchId) {
this.mchId = mchId; this.mchId = mchId;
} }
@@ -87,6 +111,11 @@ public abstract class WxPayBaseRequest {
return this.nonceStr; return this.nonceStr;
} }


/**
* 默认采用时间戳为随机字符串,可以不设置
*
* @param nonceStr 随机字符串
*/
public void setNonceStr(String nonceStr) { public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr; this.nonceStr = nonceStr;
} }
@@ -103,4 +132,10 @@ public abstract class WxPayBaseRequest {
public String toString() { public String toString() {
return ToStringUtils.toSimpleString(this); return ToStringUtils.toSimpleString(this);
} }

public String toXML() {
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(this.getClass());
return xstream.toXML(this);
}
} }

+ 123
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayDownloadBillRequest.java View File

@@ -0,0 +1,123 @@
package me.chanjar.weixin.mp.bean.pay.request;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.annotation.Required;

/**
* <pre>
* 微信支付下载对账单请求参数类
* Created by Binary Wang on 2017-01-11.
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
* </pre>
*/
@XStreamAlias("xml")
public class WxPayDownloadBillRequest extends WxPayBaseRequest {
/**
* <pre>
* 设备号
* device_info
* 否
* String(32)
* 13467007045764
* 终端设备号
* </pre>
*/
@XStreamAlias("device_info")
private String deviceInfo;

/**
* <pre>
* 签名类型
* sign_type
* 否
* String(32)
* HMAC-SHA256
* 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5
* </pre>
*/
@XStreamAlias("sign_type")
private String signType;

/**
* <pre>
* 账单类型
* bill_type
* 是
* ALL
* String(8)
* --ALL,返回当日所有订单信息,默认值
* --SUCCESS,返回当日成功支付的订单
* --REFUND,返回当日退款订单
* </pre>
*/
@Required
@XStreamAlias("bill_type")
private String billType;

/**
* <pre>
* 对账单日期
* bill_date
* 是
* String(8)
* 20140603
* 下载对账单的日期,格式:20140603
* </pre>
*/
@Required
@XStreamAlias("bill_date")
private String billDate;

/**
* <pre>
* 压缩账单
* tar_type
* 否
* String(8)
* GZIP
* 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
* </pre>
*/
@XStreamAlias("tar_type")
private String tarType;

public String getDeviceInfo() {
return deviceInfo;
}

public void setDeviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
}

public String getSignType() {
return signType;
}

public void setSignType(String signType) {
this.signType = signType;
}

public String getBillType() {
return billType;
}

public void setBillType(String billType) {
this.billType = billType;
}

public String getBillDate() {
return billDate;
}

public void setBillDate(String billDate) {
this.billDate = billDate;
}

public String getTarType() {
return tarType;
}

public void setTarType(String tarType) {
this.tarType = tarType;
}
}

+ 2
- 86
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayRefundRequest.java View File

@@ -1,7 +1,6 @@
package me.chanjar.weixin.mp.bean.pay.request; package me.chanjar.weixin.mp.bean.pay.request;


import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;

import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;


/** /**
@@ -20,33 +19,7 @@ import me.chanjar.weixin.common.annotation.Required;
* Created by Binary Wang on 2016-10-08. * Created by Binary Wang on 2016-10-08.
*/ */
@XStreamAlias("xml") @XStreamAlias("xml")
public class WxPayRefundRequest {
/**
* <pre>
* 公众账号ID
* appid
* 是
* String(32)
* wx8888888888888888
* 微信分配的公众账号ID(企业号corpid即为此appId)
* </pre>
*/
@XStreamAlias("appid")
private String appid;

/**
* <pre>
* 商户号
* mch_id
* 是
* String(32)
* 1900000109
* 微信支付分配的商户号
* </pre>
*/
@XStreamAlias("mch_id")
private String mchId;

public class WxPayRefundRequest extends WxPayBaseRequest {
/** /**
* <pre> * <pre>
* 设备号 * 设备号
@@ -60,32 +33,6 @@ public class WxPayRefundRequest {
@XStreamAlias("device_info") @XStreamAlias("device_info")
private String deviceInfo; private String deviceInfo;


/**
* <pre>
* 随机字符串
* nonce_str
* 是
* String(32)
* 5K8264ILTKCH16CQ2502SI8ZNMTM67VS
* 随机字符串,不长于32位。推荐随机数生成算法
* </pre>
*/
@XStreamAlias("nonce_str")
private String nonceStr;

/**
* <pre>
* 签名
* sign
* 是
* String(32)
* C380BEC2BFD727A4B6845133519F3AD6
* 签名,详见签名生成算法
* </pre>
*/
@XStreamAlias("sign")
private String sign;

/** /**
* <pre> * <pre>
* 微信订单号 * 微信订单号
@@ -196,22 +143,6 @@ public class WxPayRefundRequest {
@XStreamAlias("refund_account") @XStreamAlias("refund_account")
private String refundAccount; private String refundAccount;


public String getAppid() {
return this.appid;
}

public void setAppid(String appid) {
this.appid = appid;
}

public String getMchId() {
return this.mchId;
}

public void setMchId(String mchId) {
this.mchId = mchId;
}

public String getDeviceInfo() { public String getDeviceInfo() {
return this.deviceInfo; return this.deviceInfo;
} }
@@ -220,22 +151,6 @@ public class WxPayRefundRequest {
this.deviceInfo = deviceInfo; this.deviceInfo = deviceInfo;
} }


public String getNonceStr() {
return this.nonceStr;
}

public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}

public String getSign() {
return this.sign;
}

public void setSign(String sign) {
this.sign = sign;
}

public String getTransactionId() { public String getTransactionId() {
return this.transactionId; return this.transactionId;
} }
@@ -299,4 +214,5 @@ public class WxPayRefundRequest {
public void setRefundAccount(String refundAccount) { public void setRefundAccount(String refundAccount) {
this.refundAccount = refundAccount; this.refundAccount = refundAccount;
} }

} }

+ 273
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayReportRequest.java View File

@@ -0,0 +1,273 @@
package me.chanjar.weixin.mp.bean.pay.request;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.annotation.Required;

/**
* <pre>
* 微信支付-交易保障请求参数
* 注释中各行每个字段描述对应如下:
* <li>字段名
* <li>变量名
* <li>是否必填
* <li>类型
* <li>示例值
* <li>描述
* </pre>
*
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
*/
@XStreamAlias("xml")
public class WxPayReportRequest extends WxPayBaseRequest {
/**
* <pre>
* 设备号
* device_info
* 否
* String(32)
* 013467007045764
* 商户自定义的终端设备号,如门店编号、设备的ID等
* </pre>
*/
@XStreamAlias("device_info")
private String deviceInfo;

/**
* <pre>
* 签名类型
* sign_type
* 否
* String(32)
* HMAC-SHA256
* 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5
* </pre>
*/
@XStreamAlias("sign_type")
private String signType;

/**
* <pre>
* 接口URL
* interface_url
* 是
* String(127)
* https://api.mch.weixin.qq.com/pay/unifiedorder
* 报对应的接口的完整URL,类似:https://api.mch.weixin.qq.com/pay/unifiedorder,
* 对于刷卡支付,为更好的和商户共同分析一次业务行为的整体耗时情况,
* 对于两种接入模式,请都在门店侧对一次刷卡支付进行一次单独的整体上报,
* 上报URL指定为:https://api.mch.weixin.qq.com/pay/micropay/total,关于两种接入模式具体可参考本文档章节:
* 刷卡支付商户接入模式,其它接口调用仍然按照调用一次,上报一次来进行。
* </pre>
*/
@Required
@XStreamAlias("interface_url")
private String interfaceUrl;
/**
* <pre>
* 接口耗时
* execute_time
* 是
* Int
* 1000
* 接口耗时情况,单位为毫秒
* </pre>
*/
@Required
@XStreamAlias("execute_time_")//估计是官方接口搞错了
private Integer executeTime;
/**
* <pre>
* 返回状态码
* return_code
* 是
* String(16)
* SUCCESS
* SUCCESS/FAIL,此字段是通信标识,非交易标识,交易是否成功需要查看trade_state来判断
* </pre>
*/
@Required
@XStreamAlias("return_code")
private String returnCode;
/**
* <pre>
* 返回信息
* return_msg
* 否
* String(128)
* 签名失败
* 返回信息,如非空,为错误原因,签名失败,参数格式校验错误
* </pre>
*/
@XStreamAlias("return_msg")
private String returnMsg;
/**
* <pre>
* 业务结果
* result_code
* 是
* String(16)
* SUCCESS
* SUCCESS/FAIL
* </pre>
*/
@Required
@XStreamAlias("result_code")
private String resultCode;
/**
* <pre>
* 错误代码
* err_code
* 否
* String(32)
* SYSTEMERROR
* ORDERNOTEXIST—订单不存在,SYSTEMERROR—系统错误
* </pre>
*/
@XStreamAlias("err_code")
private String errCode;
/**
* <pre>
* 错误代码描述
* err_code_des
* 否
* String(128)
* 系统错误
* 结果信息描述
* </pre>
*/
@XStreamAlias("err_code_des")
private String errCodeDes;
/**
* <pre>
* 商户订单号
* out_trade_no
* 否
* String(32)
* 1217752501201407033233368018
* 商户系统内部的订单号,商户可以在上报时提供相关商户订单号方便微信支付更好的提高服务质量。
* </pre>
*/
@XStreamAlias("out_trade_no")
private String outTradeNo;
/**
* <pre>
* 访问接口IP
* user_ip
* 是
* String(16)
* 8.8.8.8
* 发起接口调用时的机器IP
* </pre>
*/
@Required
@XStreamAlias("user_ip")
private String userIp;
/**
* <pre>
* 商户上报时间
* time
* 否
* String(14)
* 20091227091010
* 系统时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则
* </pre>
*/
@XStreamAlias("time")
private String time;

public String getDeviceInfo() {
return deviceInfo;
}

public void setDeviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
}

public String getSignType() {
return signType;
}

public void setSignType(String signType) {
this.signType = signType;
}

public String getInterfaceUrl() {
return interfaceUrl;
}

public void setInterfaceUrl(String interfaceUrl) {
this.interfaceUrl = interfaceUrl;
}

public Integer getExecuteTime() {
return executeTime;
}

public void setExecuteTime(Integer executeTime) {
this.executeTime = executeTime;
}

public String getReturnCode() {
return returnCode;
}

public void setReturnCode(String returnCode) {
this.returnCode = returnCode;
}

public String getReturnMsg() {
return returnMsg;
}

public void setReturnMsg(String returnMsg) {
this.returnMsg = returnMsg;
}

public String getResultCode() {
return resultCode;
}

public void setResultCode(String resultCode) {
this.resultCode = resultCode;
}

public String getErrCode() {
return errCode;
}

public void setErrCode(String errCode) {
this.errCode = errCode;
}

public String getErrCodeDes() {
return errCodeDes;
}

public void setErrCodeDes(String errCodeDes) {
this.errCodeDes = errCodeDes;
}

public String getOutTradeNo() {
return outTradeNo;
}

public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}

public String getUserIp() {
return userIp;
}

public void setUserIp(String userIp) {
this.userIp = userIp;
}

public String getTime() {
return time;
}

public void setTime(String time) {
this.time = time;
}
}

+ 6
- 49
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPaySendRedpackRequest.java View File

@@ -8,7 +8,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
* @author binarywang (https://github.com/binarywang) * @author binarywang (https://github.com/binarywang)
*/ */
@XStreamAlias("xml") @XStreamAlias("xml")
public class WxPaySendRedpackRequest {
public class WxPaySendRedpackRequest extends WxPayBaseRequest{
/** /**
* mch_billno * mch_billno
* 商户订单号(每个订单号必须唯一) 组成:mch_id+yyyymmdd+10位一天内不能重复的数字。 接口根据商户订单号支持重入,如出现超时可再调用。 * 商户订单号(每个订单号必须唯一) 组成:mch_id+yyyymmdd+10位一天内不能重复的数字。 接口根据商户订单号支持重入,如出现超时可再调用。
@@ -90,27 +90,6 @@ public class WxPaySendRedpackRequest {
@XStreamAlias("wxappid") @XStreamAlias("wxappid")
private String wxAppid; private String wxAppid;


/**
* mch_id
* 微信支付分配的商户号
*/
@XStreamAlias("mch_id")
private String mchId;

/**
* nonce_str
* 随机字符串,不长于32位
*/
@XStreamAlias("nonce_str")
private String nonceStr;

/**
* sign
* 详见<a href="https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3">签名生成算法</a>
*/
@XStreamAlias("sign")
private String sign;

/** /**
* <pre> * <pre>
* scene_id * scene_id
@@ -237,36 +216,14 @@ public class WxPaySendRedpackRequest {
this.remark = remark; this.remark = remark;
} }


public String getWxAppid() {
@Override
public String getAppid() {
return this.wxAppid; return this.wxAppid;
} }


public void setWxAppid(String wxAppid) {
this.wxAppid = wxAppid;
}

public String getMchId() {
return this.mchId;
}

public void setMchId(String mchId) {
this.mchId = mchId;
}

public String getNonceStr() {
return this.nonceStr;
}

public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}

public String getSign() {
return this.sign;
}

public void setSign(String sign) {
this.sign = sign;
@Override
public void setAppid(String appid) {
this.wxAppid = appid;
} }


public String getSceneId() { public String getSceneId() {


+ 8
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayUnifiedOrderRequest.java View File

@@ -360,6 +360,10 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest {
return this.notifyURL; return this.notifyURL;
} }


/**
* 如果配置中已经设置,可以不设置值
* @param notifyURL
*/
public void setNotifyURL(String notifyURL) { public void setNotifyURL(String notifyURL) {
this.notifyURL = notifyURL; this.notifyURL = notifyURL;
} }
@@ -368,6 +372,10 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest {
return this.tradeType; return this.tradeType;
} }


/**
* 如果配置中已经设置,可以不设置值
* @param tradeType 交易类型
*/
public void setTradeType(String tradeType) { public void setTradeType(String tradeType) {
this.tradeType = tradeType; this.tradeType = tradeType;
} }


+ 104
- 13
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayBaseResult.java View File

@@ -1,7 +1,21 @@
package me.chanjar.weixin.mp.bean.pay.result; package me.chanjar.weixin.mp.bean.pay.result;


import com.google.common.collect.Maps;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import io.restassured.internal.path.xml.NodeChildrenImpl;
import io.restassured.internal.path.xml.NodeImpl;
import io.restassured.path.xml.XmlPath;
import io.restassured.path.xml.element.Node;
import io.restassured.path.xml.exception.XmlPathException;
import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.ToStringUtils;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.Iterator;
import java.util.Map;


/** /**
* <pre> * <pre>
@@ -11,65 +25,90 @@ import me.chanjar.weixin.common.util.ToStringUtils;
* </pre> * </pre>
*/ */
public abstract class WxPayBaseResult { public abstract class WxPayBaseResult {
@Override
public String toString() {
return ToStringUtils.toSimpleString(this);
}

/** /**
* 返回状态码 * 返回状态码
*/ */
@XStreamAlias("return_code") @XStreamAlias("return_code")
protected String returnCode; protected String returnCode;

/** /**
* 返回信息 * 返回信息
*/ */
@XStreamAlias("return_msg") @XStreamAlias("return_msg")
protected String returnMsg; protected String returnMsg;
private String xmlString;
/** /**
* 业务结果 * 业务结果
*/ */
@XStreamAlias("result_code") @XStreamAlias("result_code")
private String resultCode; private String resultCode;

/** /**
* 错误代码 * 错误代码
*/ */
@XStreamAlias("err_code") @XStreamAlias("err_code")
private String errCode; private String errCode;

/** /**
* 错误代码描述 * 错误代码描述
*/ */
@XStreamAlias("err_code_des") @XStreamAlias("err_code_des")
private String errCodeDes; private String errCodeDes;

/** /**
* 公众账号ID * 公众账号ID
*/ */
@XStreamAlias("appid") @XStreamAlias("appid")
private String appid; private String appid;

/** /**
* 商户号 * 商户号
*/ */
@XStreamAlias("mch_id") @XStreamAlias("mch_id")
private String mchId; private String mchId;

/** /**
* 随机字符串 * 随机字符串
*/ */
@XStreamAlias("nonce_str") @XStreamAlias("nonce_str")
private String nonceStr; private String nonceStr;

/** /**
* 签名 * 签名
*/ */
@XStreamAlias("sign") @XStreamAlias("sign")
private String sign; private String sign;


/**
* 将单位分转换成单位圆
*
* @param fee 将要被转换为元的分的数值
*/
public static String feeToYuan(Integer fee) {
return new BigDecimal(Double.valueOf(fee) / 100).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString();
}

/**
* 从xml字符串创建bean对象
*/
public static <T extends WxPayBaseResult> T fromXML(String xmlString, Class<T> clz) {
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(clz);
T result = (T) xstream.fromXML(xmlString);
result.setXmlString(xmlString);
return result;
}

public String getXmlString() {
return this.xmlString;
}

public void setXmlString(String xmlString) {
this.xmlString = xmlString;
}

protected Logger getLogger() {
return LoggerFactory.getLogger(this.getClass());
}

@Override
public String toString() {
return ToStringUtils.toSimpleString(this);
}

public String getReturnCode() { public String getReturnCode() {
return this.returnCode; return this.returnCode;
} }
@@ -141,4 +180,56 @@ public abstract class WxPayBaseResult {
public void setSign(String sign) { public void setSign(String sign) {
this.sign = sign; this.sign = sign;
} }

/**
* 将bean通过保存的xml字符串转换成map
*/
public Map<String, String> toMap() {
Map<String, String> result = Maps.newHashMap();
XmlPath xmlPath = new XmlPath(this.xmlString);
NodeImpl rootNode = null;
try {
rootNode = xmlPath.get("xml");
} catch (XmlPathException e) {
throw new RuntimeException("xml数据有问题,请核实!");
}

if (rootNode == null) {
throw new RuntimeException("xml数据有问题,请核实!");
}

Iterator<Node> iterator = rootNode.children().nodeIterator();
while (iterator.hasNext()) {
Node node = iterator.next();
result.put(node.name(), node.value());
}

return result;
}

private String getXmlValue(XmlPath xmlPath, String path) {
if (xmlPath.get(path) instanceof NodeChildrenImpl) {
if (((NodeChildrenImpl) xmlPath.get(path)).size() == 0) {
return null;
}
}

return xmlPath.getString(path);
}

protected <T> T getXmlValue(XmlPath xmlPath, String path, Class<T> clz) {
String value = this.getXmlValue(xmlPath, path);
if (value == null) {
return null;
}

switch (clz.getSimpleName()) {
case "String":
return (T) value;
case "Integer":
return (T) Integer.valueOf(value);
}

throw new UnsupportedOperationException("暂时不支持此种类型的数据");
}
} }

+ 15
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayCommonResult.java View File

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

import com.thoughtworks.xstream.annotations.XStreamAlias;

/**
* <pre>
* 微信支付结果仅包含有return 和result等相关信息的的属性类
* Created by Binary Wang on 2017-01-09.
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
* </pre>
*/

@XStreamAlias("xml")
public class WxPayCommonResult extends WxPayBaseResult {
}

+ 392
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayOrderNotifyResult.java View File

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

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.util.BeanUtils;
import me.chanjar.weixin.common.util.ToStringUtils;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import me.chanjar.weixin.mp.bean.pay.WxPayOrderNotifyCoupon;
import me.chanjar.weixin.mp.bean.pay.WxPayOrderNotifyResultConverter;

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

/**
* 支付结果通用通知 ,文档见:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
* @author aimilin6688
* @since 2.5.0
*/
@XStreamAlias("xml")
public class WxPayOrderNotifyResult extends WxPayBaseResult implements Serializable {

private static final long serialVersionUID = 5389718115223345496L;


/**
* <pre>
* 设备号
* device_info
* 否
* String(32)
* 013467007045764
* 微信支付分配的终端设备号,
* </pre>
*/
@XStreamAlias("device_info")
private String deviceInfo;

/**
* <pre>
* 用户标识
* openid
* 是
* String(128)
* wxd930ea5d5a258f4f
* 用户在商户appid下的唯一标识
* </pre>
*/
@XStreamAlias("openid")
private String openid;

/**
* <pre>
* 是否关注公众账号
* is_subscribe
* 否
* String(1)
* Y
* 用户是否关注公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效
* </pre>
*/
@XStreamAlias("is_subscribe")
private String isSubscribe;


/**
* <pre>
* 交易类型
* trade_type
* 是
* String(16)
* JSAPI JSAPI、NATIVE、APP
* </pre>
*/
@XStreamAlias("trade_type")
private String tradeType;


/**
* <pre>
* 付款银行
* bank_type
* 是
* String(16)
* CMC
* 银行类型,采用字符串类型的银行标识,银行类型见银行列表
* </pre>
*/
@XStreamAlias("bank_type")
private String bankType;


/**
* <pre>
* 订单金额
* total_fee
* 是
* Int
* 100
* 订单总金额,单位为分
* </pre>
*/
@XStreamAlias("total_fee")
private Integer totalFee;
/**
* <pre>
* 应结订单金额
* settlement_total_fee
* 否
* Int
* 100
* 应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。
* </pre>
*/
@XStreamAlias("settlement_total_fee")
private Integer settlementTotalFee;
/**
* <pre>
* 货币种类
* fee_type
* 否
* String(8)
* CNY
* 货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
* </pre>
*/
@XStreamAlias("fee_type")
private String feeType;
/**
* <pre>
* 现金支付金额
* cash_fee
* 是
* Int
* 100
* 现金支付金额订单现金支付金额,详见支付金额
* </pre>
*/
@XStreamAlias("cash_fee")
private Integer cashFee;
/**
* <pre>
* 现金支付货币类型
* cash_fee_type
* 否
* String(16)
* CNY
* 货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
* </pre>
*/
@XStreamAlias("cash_fee_type")
private String cashFeeType;
/**
* <pre>
* 总代金券金额
* coupon_fee
* 否
* Int
* 10
* 代金券金额<=订单金额,订单金额-代金券金额=现金支付金额,详见支付金额
* </pre>
*/
@XStreamAlias("coupon_fee")
private Integer couponFee;

/**
* <pre>
* 代金券使用数量
* coupon_count
* 否
* Int
* 1
* 代金券使用数量
* </pre>
*/
@XStreamAlias("coupon_count")
private Integer couponCount;

private List<WxPayOrderNotifyCoupon> couponList;

/**
* <pre>
* 微信支付订单号
* transaction_id
* 是
* String(32)
* 1217752501201407033233368018
* 微信支付订单号
* </pre>
*/
@XStreamAlias("transaction_id")
private String transactionId;

/**
* <pre>
* 商户订单号
* out_trade_no
* 是
* String(32)
* 1212321211201407033568112322
* 商户系统的订单号,与请求一致。
* </pre>
*/
@XStreamAlias("out_trade_no")
private String outTradeNo;
/**
* <pre>
* 商家数据包
* attach
* 否
* String(128)
* 123456
* 商家数据包,原样返回
* </pre>
*/
@XStreamAlias("attach")
private String attach;
/**
* <pre>
* 支付完成时间
* time_end
* 是
* String(14)
* 20141030133525
* 支付完成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
* </pre>
*/
@XStreamAlias("time_end")
private String timeEnd;

public Integer getCouponCount() {
return couponCount;
}

public void setCouponCount(Integer couponCount) {
this.couponCount = couponCount;
}

public List<WxPayOrderNotifyCoupon> getCouponList() {
return couponList;
}

public void setCouponList(List<WxPayOrderNotifyCoupon> couponList) {
this.couponList = couponList;
}

public String getDeviceInfo() {
return deviceInfo;
}

public void setDeviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
}

public String getOpenid() {
return openid;
}

public void setOpenid(String openid) {
this.openid = openid;
}

public String getIsSubscribe() {
return isSubscribe;
}

public void setIsSubscribe(String isSubscribe) {
this.isSubscribe = isSubscribe;
}

public String getTradeType() {
return tradeType;
}

public void setTradeType(String tradeType) {
this.tradeType = tradeType;
}

public String getBankType() {
return bankType;
}

public void setBankType(String bankType) {
this.bankType = bankType;
}

public Integer getTotalFee() {
return totalFee;
}

public void setTotalFee(Integer totalFee) {
this.totalFee = totalFee;
}

public Integer getSettlementTotalFee() {
return settlementTotalFee;
}

public void setSettlementTotalFee(Integer settlementTotalFee) {
this.settlementTotalFee = settlementTotalFee;
}

public String getFeeType() {
return feeType;
}

public void setFeeType(String feeType) {
this.feeType = feeType;
}

public Integer getCashFee() {
return cashFee;
}

public void setCashFee(Integer cashFee) {
this.cashFee = cashFee;
}

public String getCashFeeType() {
return cashFeeType;
}

public void setCashFeeType(String cashFeeType) {
this.cashFeeType = cashFeeType;
}

public Integer getCouponFee() {
return couponFee;
}

public void setCouponFee(Integer couponFee) {
this.couponFee = couponFee;
}

public String getTransactionId() {
return transactionId;
}

public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}

public String getOutTradeNo() {
return outTradeNo;
}

public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}

public String getAttach() {
return attach;
}

public void setAttach(String attach) {
this.attach = attach;
}

public String getTimeEnd() {
return timeEnd;
}

public void setTimeEnd(String timeEnd) {
this.timeEnd = timeEnd;
}

@Override
public Map<String,String> toMap(){
Map<String,String> resultMap = BeanUtils.xmlBean2Map(this);
if(this.getCouponCount() != null && this.getCouponCount() > 0){
for (int i = 0; i < this.getCouponCount(); i++) {
WxPayOrderNotifyCoupon coupon = couponList.get(i);
resultMap.putAll(coupon.toMap(i));
}
}
return resultMap;
}

@Override
public String toString() {
return ToStringUtils.toSimpleString(this);
}

public static WxPayOrderNotifyResult fromXML(String xmlString) {
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxPayOrderNotifyResult.class);
xstream.registerConverter(new WxPayOrderNotifyResultConverter(xstream.getMapper(), xstream.getReflectionProvider()));
WxPayOrderNotifyResult result = (WxPayOrderNotifyResult) xstream.fromXML(xmlString);
result.setXmlString(xmlString);
return result;
}
}

+ 81
- 76
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayOrderQueryResult.java View File

@@ -2,6 +2,7 @@ package me.chanjar.weixin.mp.bean.pay.result;


import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import io.restassured.path.xml.XmlPath;


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


@@ -17,6 +18,7 @@ import java.util.List;
* <li>示例值 * <li>示例值
* <li>描述 * <li>描述
* </pre> * </pre>
*
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> * @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
*/ */
@XStreamAlias("xml") @XStreamAlias("xml")
@@ -179,75 +181,6 @@ public class WxPayOrderQueryResult extends WxPayBaseResult {
private Integer couponCount; private Integer couponCount;


private List<Coupon> coupons; private List<Coupon> coupons;

public static class Coupon {
/**
* <pre>代金券类型
* coupon_type_$n
* 否
* String
* CASH
* <li>CASH--充值代金券
* <li>NO_CASH---非充值代金券
* 订单使用代金券时有返回(取值:CASH、NO_CASH)。$n为下标,从0开始编号,举例:coupon_type_$0
* </pre>
*/
private String couponType;

/**
* <pre>代金券ID
* coupon_id_$n
* 否
* String(20)
* 10000
* 代金券ID, $n为下标,从0开始编号
* </pre>
*/
private String couponId;

/**
* <pre>单个代金券支付金额
* coupon_fee_$n
* 否
* Int
* 100
* 单个代金券支付金额, $n为下标,从0开始编号
* </pre>
*/
private Integer couponFee;

public Coupon(String couponType, String couponId, Integer couponFee) {
this.couponType = couponType;
this.couponId = couponId;
this.couponFee = couponFee;
}

public String getCouponType() {
return this.couponType;
}

public void setCouponType(String couponType) {
this.couponType = couponType;
}

public String getCouponId() {
return this.couponId;
}

public void setCouponId(String couponId) {
this.couponId = couponId;
}

public Integer getCouponFee() {
return this.couponFee;
}

public void setCouponFee(Integer couponFee) {
this.couponFee = couponFee;
}

}

/** /**
* <pre>微信支付订单号 * <pre>微信支付订单号
* transaction_id * transaction_id
@@ -259,7 +192,6 @@ public class WxPayOrderQueryResult extends WxPayBaseResult {
*/ */
@XStreamAlias("transaction_id") @XStreamAlias("transaction_id")
private String transactionId; private String transactionId;

/** /**
* <pre>商户订单号 * <pre>商户订单号
* out_trade_no * out_trade_no
@@ -271,7 +203,6 @@ public class WxPayOrderQueryResult extends WxPayBaseResult {
*/ */
@XStreamAlias("out_trade_no") @XStreamAlias("out_trade_no")
private String outTradeNo; private String outTradeNo;

/** /**
* <pre>附加数据 * <pre>附加数据
* attach * attach
@@ -283,7 +214,6 @@ public class WxPayOrderQueryResult extends WxPayBaseResult {
*/ */
@XStreamAlias("attach") @XStreamAlias("attach")
private String attach; private String attach;

/** /**
* <pre>支付完成时间 * <pre>支付完成时间
* time_end * time_end
@@ -295,7 +225,6 @@ public class WxPayOrderQueryResult extends WxPayBaseResult {
*/ */
@XStreamAlias("time_end") @XStreamAlias("time_end")
private String timeEnd; private String timeEnd;

/** /**
* <pre>交易状态描述 * <pre>交易状态描述
* trade_state_desc * trade_state_desc
@@ -460,10 +389,86 @@ public class WxPayOrderQueryResult extends WxPayBaseResult {
this.tradeStateDesc = tradeStateDesc; this.tradeStateDesc = tradeStateDesc;
} }


public void composeCoupons(String xmlString){
if(this.couponCount != null && this.couponCount > 0 ){
/**
* 通过xml组装coupons属性内容
*/
public void composeCoupons() {
if (this.couponCount != null && this.couponCount > 0) {
this.coupons = Lists.newArrayList(); this.coupons = Lists.newArrayList();
//TODO 暂时待实现
XmlPath xmlPath = new XmlPath(this.getXmlString());
for (int i = 0; i < this.couponCount; i++){
this.coupons.add(new Coupon(this.getXmlValue(xmlPath, "xml.coupon_type_" + i, String.class),
this.getXmlValue(xmlPath, "xml.coupon_id_" + i, String.class),
this.getXmlValue(xmlPath, "xml.coupon_fee_" + i, Integer.class)));
}
}
}

public static class Coupon {
/**
* <pre>代金券类型
* coupon_type_$n
* 否
* String
* CASH
* <li>CASH--充值代金券
* <li>NO_CASH---非充值代金券
* 订单使用代金券时有返回(取值:CASH、NO_CASH)。$n为下标,从0开始编号,举例:coupon_type_$0
* </pre>
*/
private String couponType;

/**
* <pre>代金券ID
* coupon_id_$n
* 否
* String(20)
* 10000
* 代金券ID, $n为下标,从0开始编号
* </pre>
*/
private String couponId;

/**
* <pre>单个代金券支付金额
* coupon_fee_$n
* 否
* Int
* 100
* 单个代金券支付金额, $n为下标,从0开始编号
* </pre>
*/
private Integer couponFee;

public Coupon(String couponType, String couponId, Integer couponFee) {
this.couponType = couponType;
this.couponId = couponId;
this.couponFee = couponFee;
}

public String getCouponType() {
return this.couponType;
}

public void setCouponType(String couponType) {
this.couponType = couponType;
} }

public String getCouponId() {
return this.couponId;
}

public void setCouponId(String couponId) {
this.couponId = couponId;
}

public Integer getCouponFee() {
return this.couponFee;
}

public void setCouponFee(Integer couponFee) {
this.couponFee = couponFee;
}

} }
} }

+ 5
- 5
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayRedpackQueryResult.java View File

@@ -52,11 +52,11 @@ public class WxPayRedpackQueryResult extends WxPayBaseResult {
* RECEIVED * RECEIVED
* string(16) * string(16)
* SENDING:发放中, * SENDING:发放中,
* SENT:已发放待领取,
* FAILED:发放失败,
* RECEIVED:已领取,
* RFUND_ING:退款中,
* REFUND:已退款
* SENT:已发放待领取,
* FAILED:发放失败,
* RECEIVED:已领取,
* RFUND_ING:退款中,
* REFUND:已退款
* </pre> * </pre>
*/ */
@XStreamAlias("status") @XStreamAlias("status")


+ 60
- 16
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayRefundQueryResult.java View File

@@ -2,6 +2,7 @@ package me.chanjar.weixin.mp.bean.pay.result;


import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import io.restassured.path.xml.XmlPath;


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


@@ -183,10 +184,44 @@ public class WxPayRefundQueryResult extends WxPayBaseResult {
this.refundRecords = refundRecords; this.refundRecords = refundRecords;
} }


public void composeRefundRecords(String xmlString) {
/**
* 组装生成退款记录属性的内容
*/
public void composeRefundRecords() {
if (this.refundCount != null && this.refundCount > 0) { if (this.refundCount != null && this.refundCount > 0) {
this.refundRecords = Lists.newArrayList(); this.refundRecords = Lists.newArrayList();
//TODO 暂时待实现
XmlPath xmlPath = new XmlPath(this.getXmlString());

for (int i = 0; i < this.refundCount; i++) {
RefundRecord refundRecord = new RefundRecord();
this.refundRecords.add(refundRecord);

refundRecord.setOutRefundNo(this.getXmlValue(xmlPath, "xml.out_refund_no_" + i, String.class));
refundRecord.setRefundId(this.getXmlValue(xmlPath, "xml.refund_id_" + i, String.class));
refundRecord.setRefundChannel(this.getXmlValue(xmlPath, "xml.refund_channel_" + i, String.class));
refundRecord.setRefundFee(this.getXmlValue(xmlPath, "xml.refund_fee_" + i, Integer.class));
refundRecord.setSettlementRefundFee(this.getXmlValue(xmlPath, "xml.settlement_refund_fee_" + i, Integer.class));
refundRecord.setCouponType(this.getXmlValue(xmlPath, "xml.coupon_type_" + i, String.class));
refundRecord.setCouponRefundFee(this.getXmlValue(xmlPath, "xml.coupon_refund_fee_" + i, Integer.class));
refundRecord.setCouponRefundCount(this.getXmlValue(xmlPath, "xml.coupon_refund_count_" + i, Integer.class));
refundRecord.setRefundStatus(this.getXmlValue(xmlPath, "xml.refund_status_" + i, String.class));
refundRecord.setRefundRecvAccout(this.getXmlValue(xmlPath, "xml.refund_recv_accout_" + i, String.class));

if (refundRecord.getCouponRefundCount() == null || refundRecord.getCouponRefundCount() == 0) {
continue;
}

List<RefundRecord.RefundCoupon> coupons = Lists.newArrayList();
for (int j = 0; j < refundRecord.getCouponRefundCount(); j++) {
coupons.add(
new RefundRecord.RefundCoupon(
this.getXmlValue(xmlPath, "xml.coupon_refund_id_" + i + "_" + j, String.class),
this.getXmlValue(xmlPath, "xml.coupon_refund_fee_" + i + "_" + j, Integer.class)
)
);
}
}

} }
} }


@@ -241,7 +276,7 @@ public class WxPayRefundQueryResult extends WxPayBaseResult {
* </pre> * </pre>
*/ */
@XStreamAlias("refund_fee") @XStreamAlias("refund_fee")
private String refundFee;
private Integer refundFee;


/** /**
* <pre> * <pre>
@@ -254,7 +289,7 @@ public class WxPayRefundQueryResult extends WxPayBaseResult {
* </pre> * </pre>
*/ */
@XStreamAlias("settlement_refund_fee") @XStreamAlias("settlement_refund_fee")
private String settlementRefundFee;
private Integer settlementRefundFee;


/** /**
* <pre> * <pre>
@@ -293,7 +328,7 @@ public class WxPayRefundQueryResult extends WxPayBaseResult {
* </pre> * </pre>
*/ */
@XStreamAlias("coupon_refund_fee") @XStreamAlias("coupon_refund_fee")
private String couponRefundFee;
private Integer couponRefundFee;


/** /**
* <pre> * <pre>
@@ -306,7 +341,7 @@ public class WxPayRefundQueryResult extends WxPayBaseResult {
* </pre> * </pre>
*/ */
@XStreamAlias("coupon_refund_count") @XStreamAlias("coupon_refund_count")
private String couponRefundCount;
private Integer couponRefundCount;


private List<RefundCoupon> refundCoupons; private List<RefundCoupon> refundCoupons;


@@ -364,19 +399,19 @@ public class WxPayRefundQueryResult extends WxPayBaseResult {
this.refundChannel = refundChannel; this.refundChannel = refundChannel;
} }


public String getRefundFee() {
public Integer getRefundFee() {
return refundFee; return refundFee;
} }


public void setRefundFee(String refundFee) {
public void setRefundFee(Integer refundFee) {
this.refundFee = refundFee; this.refundFee = refundFee;
} }


public String getSettlementRefundFee() {
public Integer getSettlementRefundFee() {
return settlementRefundFee; return settlementRefundFee;
} }


public void setSettlementRefundFee(String settlementRefundFee) {
public void setSettlementRefundFee(Integer settlementRefundFee) {
this.settlementRefundFee = settlementRefundFee; this.settlementRefundFee = settlementRefundFee;
} }


@@ -396,19 +431,19 @@ public class WxPayRefundQueryResult extends WxPayBaseResult {
this.couponType = couponType; this.couponType = couponType;
} }


public String getCouponRefundFee() {
public Integer getCouponRefundFee() {
return couponRefundFee; return couponRefundFee;
} }


public void setCouponRefundFee(String couponRefundFee) {
public void setCouponRefundFee(Integer couponRefundFee) {
this.couponRefundFee = couponRefundFee; this.couponRefundFee = couponRefundFee;
} }


public String getCouponRefundCount() {
public Integer getCouponRefundCount() {
return couponRefundCount; return couponRefundCount;
} }


public void setCouponRefundCount(String couponRefundCount) {
public void setCouponRefundCount(Integer couponRefundCount) {
this.couponRefundCount = couponRefundCount; this.couponRefundCount = couponRefundCount;
} }


@@ -446,6 +481,8 @@ public class WxPayRefundQueryResult extends WxPayBaseResult {
* 100 * 100
* 退款代金券批次ID ,$n为下标,$m为下标,从0开始编号 * 退款代金券批次ID ,$n为下标,$m为下标,从0开始编号
* </pre> * </pre>
*
* @deprecated 貌似是被去掉了,但不知是何时!
*/ */
@XStreamAlias("coupon_refund_batch_id") @XStreamAlias("coupon_refund_batch_id")
private String couponRefundBatchId; private String couponRefundBatchId;
@@ -474,9 +511,15 @@ public class WxPayRefundQueryResult extends WxPayBaseResult {
* </pre> * </pre>
*/ */
@XStreamAlias("coupon_refund_fee") @XStreamAlias("coupon_refund_fee")
private String couponRefundFee;
private Integer couponRefundFee;

public RefundCoupon(String couponRefundId, Integer couponRefundFee) {
this.couponRefundId = couponRefundId;
this.couponRefundFee = couponRefundFee;
}


public RefundCoupon(String couponRefundBatchId, String couponRefundId, String couponRefundFee) {
@Deprecated
public RefundCoupon(String couponRefundBatchId, String couponRefundId, Integer couponRefundFee) {
this.couponRefundBatchId = couponRefundBatchId; this.couponRefundBatchId = couponRefundBatchId;
this.couponRefundId = couponRefundId; this.couponRefundId = couponRefundId;
this.couponRefundFee = couponRefundFee; this.couponRefundFee = couponRefundFee;
@@ -484,5 +527,6 @@ public class WxPayRefundQueryResult extends WxPayBaseResult {
} }


} }

} }



+ 9
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayUnifiedOrderResult.java View File

@@ -13,12 +13,21 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
@XStreamAlias("xml") @XStreamAlias("xml")
public class WxPayUnifiedOrderResult extends WxPayBaseResult { public class WxPayUnifiedOrderResult extends WxPayBaseResult {


/**
* 微信生成的预支付回话标识,用于后续接口调用中使用,该值有效期为2小时
*/
@XStreamAlias("prepay_id") @XStreamAlias("prepay_id")
private String prepayId; private String prepayId;


/**
* 交易类型,取值为:JSAPI,NATIVE,APP等
*/
@XStreamAlias("trade_type") @XStreamAlias("trade_type")
private String tradeType; private String tradeType;


/**
* trade_type为NATIVE时有返回,用于生成二维码,展示给用户进行扫码支付
*/
@XStreamAlias("code_url") @XStreamAlias("code_url")
private String codeURL; private String codeURL;




+ 5
- 8
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java View File

@@ -1,5 +1,6 @@
package me.chanjar.weixin.mp.bean.result; package me.chanjar.weixin.mp.bean.result;


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


import java.io.Serializable; import java.io.Serializable;
@@ -7,19 +8,15 @@ import java.io.Serializable;
/** /**
* <pre> * <pre>
* 群发消息一发送就返回的结果 * 群发消息一发送就返回的结果
*
*
* 真正的群发消息是否发送成功要看 * 真正的群发消息是否发送成功要看
* http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口#.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81.E7.BE.A4.E5.8F.91.E7.BB.93.E6.9E.9C * http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口#.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81.E7.BE.A4.E5.8F.91.E7.BB.93.E6.9E.9C
*
*
* </pre> * </pre>
* @author chanjarster * @author chanjarster
* *
*/ */
public class WxMpMassSendResult implements Serializable { public class WxMpMassSendResult implements Serializable {

/**
*
*/
private static final long serialVersionUID = -4816336807575562818L; private static final long serialVersionUID = -4816336807575562818L;
private String errorCode; private String errorCode;
private String errorMsg; private String errorMsg;
@@ -64,7 +61,7 @@ public class WxMpMassSendResult implements Serializable {


@Override @Override
public String toString() { public String toString() {
return "WxMassSendResult [errcode=" + this.errorCode + ", errmsg=" + this.errorMsg + ", msg_id=" + this.msgId + "]";
return ToStringUtils.toSimpleString(this);
} }
} }

+ 2
- 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/BaseBuilder.java View File

@@ -6,7 +6,8 @@ public class BaseBuilder<T> {
protected String msgType; protected String msgType;
protected String toUser; protected String toUser;


public T toUser(String toUser) {
@SuppressWarnings("unchecked")
public T toUser(String toUser) {
this.toUser = toUser; this.toUser = toUser;
return (T) this; return (T) this;
} }


+ 4
- 2
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/BaseBuilder.java View File

@@ -8,12 +8,14 @@ public abstract class BaseBuilder<BuilderType, ValueType> {


protected String fromUserName; protected String fromUserName;


public BuilderType toUser(String touser) {
@SuppressWarnings("unchecked")
public BuilderType toUser(String touser) {
this.toUserName = touser; this.toUserName = touser;
return (BuilderType) this; return (BuilderType) this;
} }


public BuilderType fromUser(String fromusername) {
@SuppressWarnings("unchecked")
public BuilderType fromUser(String fromusername) {
this.fromUserName = fromusername; this.fromUserName = fromusername;
return (BuilderType) this; return (BuilderType) this;
} }


+ 0
- 2
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialVoiceAndImageDownloadRequestExecutor.java View File

@@ -23,7 +23,6 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder;


public class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor<InputStream, String> { public class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor<InputStream, String> {


private File tmpDirFile;


public MaterialVoiceAndImageDownloadRequestExecutor() { public MaterialVoiceAndImageDownloadRequestExecutor() {
super(); super();
@@ -31,7 +30,6 @@ public class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExec


public MaterialVoiceAndImageDownloadRequestExecutor(File tmpDirFile) { public MaterialVoiceAndImageDownloadRequestExecutor(File tmpDirFile) {
super(); super();
this.tmpDirFile = tmpDirFile;
} }


@Override @Override


+ 4
- 9
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCardGsonAdapter.java View File

@@ -1,16 +1,11 @@
package me.chanjar.weixin.mp.util.json; package me.chanjar.weixin.mp.util.json;


import java.lang.reflect.Type;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import com.google.gson.*;
import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.WxMpCard; import me.chanjar.weixin.mp.bean.WxMpCard;


import java.lang.reflect.Type;

/** /**
* Created by YuJian on 15/11/11. * Created by YuJian on 15/11/11.
* *
@@ -21,7 +16,7 @@ public class WxMpCardGsonAdapter implements JsonDeserializer<WxMpCard> {


@Override @Override
public WxMpCard deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext public WxMpCard deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext
jsonDeserializationContext) throws JsonParseException {
jsonDeserializationContext) throws JsonParseException {
WxMpCard card = new WxMpCard(); WxMpCard card = new WxMpCard();
JsonObject jsonObject = jsonElement.getAsJsonObject(); JsonObject jsonObject = jsonElement.getAsJsonObject();




+ 5
- 10
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCardResultGsonAdapter.java View File

@@ -1,18 +1,13 @@
package me.chanjar.weixin.mp.util.json; package me.chanjar.weixin.mp.util.json;


import java.lang.reflect.Type;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;

import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.WxMpCard; import me.chanjar.weixin.mp.bean.WxMpCard;
import me.chanjar.weixin.mp.bean.result.WxMpCardResult; import me.chanjar.weixin.mp.bean.result.WxMpCardResult;


import java.lang.reflect.Type;

/** /**
* Created by YuJian on 15/11/11. * Created by YuJian on 15/11/11.
* *
@@ -32,8 +27,8 @@ public class WxMpCardResultGsonAdapter implements JsonDeserializer<WxMpCardResul
cardResult.setUserCardStatus(GsonHelper.getString(jsonObject, "user_card_status")); cardResult.setUserCardStatus(GsonHelper.getString(jsonObject, "user_card_status"));


WxMpCard card = WxMpGsonBuilder.INSTANCE.create().fromJson(jsonObject.get("card"), WxMpCard card = WxMpGsonBuilder.INSTANCE.create().fromJson(jsonObject.get("card"),
new TypeToken<WxMpCard>() {
}.getType());
new TypeToken<WxMpCard>() {
}.getType());


cardResult.setCard(card); cardResult.setCard(card);




+ 4
- 25
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java View File

@@ -2,33 +2,12 @@ package me.chanjar.weixin.mp.util.json;


import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;

import me.chanjar.weixin.mp.bean.WxMpCard;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import me.chanjar.weixin.mp.bean.WxMpMassNews;
import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage;
import me.chanjar.weixin.mp.bean.WxMpMassPreviewMessage;
import me.chanjar.weixin.mp.bean.WxMpMassTagMessage;
import me.chanjar.weixin.mp.bean.WxMpMassVideo;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialArticleUpdate;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews;
import me.chanjar.weixin.mp.bean.*;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate; import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;
import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult;
import me.chanjar.weixin.mp.bean.result.WxMpCardResult;
import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult;
import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialCountResult;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialFileBatchGetResult;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialNewsBatchGetResult;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.result.WxMpUserBlacklistGetResult;
import me.chanjar.weixin.mp.bean.result.WxMpUserList;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import me.chanjar.weixin.mp.bean.material.*;
import me.chanjar.weixin.mp.bean.result.*;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateIndustry; import me.chanjar.weixin.mp.bean.template.WxMpTemplateIndustry;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;




+ 13
- 13
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpIndustryGsonAdapter.java View File

@@ -10,10 +10,17 @@ import java.lang.reflect.Type;
* @author miller * @author miller
*/ */
public class WxMpIndustryGsonAdapter public class WxMpIndustryGsonAdapter
implements JsonSerializer<WxMpTemplateIndustry>, JsonDeserializer<WxMpTemplateIndustry> {
implements JsonSerializer<WxMpTemplateIndustry>, JsonDeserializer<WxMpTemplateIndustry> {
private static WxMpTemplateIndustry.Industry convertFromJson(JsonObject json) {
WxMpTemplateIndustry.Industry industry = new WxMpTemplateIndustry.Industry();
industry.setFirstClass(GsonHelper.getString(json, "first_class"));
industry.setSecondClass(GsonHelper.getString(json, "second_class"));
return industry;
}

@Override @Override
public JsonElement serialize(WxMpTemplateIndustry wxMpIndustry, Type type, public JsonElement serialize(WxMpTemplateIndustry wxMpIndustry, Type type,
JsonSerializationContext jsonSerializationContext) {
JsonSerializationContext jsonSerializationContext) {
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
json.addProperty("industry_id1", wxMpIndustry.getPrimaryIndustry().getId()); json.addProperty("industry_id1", wxMpIndustry.getPrimaryIndustry().getId());
json.addProperty("industry_id2", wxMpIndustry.getSecondIndustry().getId()); json.addProperty("industry_id2", wxMpIndustry.getSecondIndustry().getId());
@@ -22,22 +29,15 @@ public class WxMpIndustryGsonAdapter


@Override @Override
public WxMpTemplateIndustry deserialize(JsonElement jsonElement, Type type, public WxMpTemplateIndustry deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext)
throws JsonParseException {
JsonDeserializationContext jsonDeserializationContext)
throws JsonParseException {
WxMpTemplateIndustry wxMpIndustry = new WxMpTemplateIndustry(); WxMpTemplateIndustry wxMpIndustry = new WxMpTemplateIndustry();
JsonObject primaryIndustry = jsonElement.getAsJsonObject() JsonObject primaryIndustry = jsonElement.getAsJsonObject()
.get("primary_industry").getAsJsonObject();
.get("primary_industry").getAsJsonObject();
wxMpIndustry.setPrimaryIndustry(convertFromJson(primaryIndustry)); wxMpIndustry.setPrimaryIndustry(convertFromJson(primaryIndustry));
JsonObject secondaryIndustry = jsonElement.getAsJsonObject() JsonObject secondaryIndustry = jsonElement.getAsJsonObject()
.get("secondary_industry").getAsJsonObject();
.get("secondary_industry").getAsJsonObject();
wxMpIndustry.setSecondIndustry(convertFromJson(secondaryIndustry)); wxMpIndustry.setSecondIndustry(convertFromJson(secondaryIndustry));
return wxMpIndustry; return wxMpIndustry;
} }

private static WxMpTemplateIndustry.Industry convertFromJson(JsonObject json) {
WxMpTemplateIndustry.Industry industry = new WxMpTemplateIndustry.Industry();
industry.setFirstClass(GsonHelper.getString(json, "first_class"));
industry.setSecondClass(GsonHelper.getString(json, "second_class"));
return industry;
}
} }

+ 1
- 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java View File

@@ -87,7 +87,7 @@ public class WxMpKefuMessageGsonAdapter implements JsonSerializer<WxMpKefuMessag
messageJson.add("wxcard", wxcard); messageJson.add("wxcard", wxcard);
} }


if (StringUtils.isNotBlank(message.getKfAccount())){
if (StringUtils.isNotBlank(message.getKfAccount())) {
JsonObject newsJsonObject = new JsonObject(); JsonObject newsJsonObject = new JsonObject();
newsJsonObject.addProperty("kf_account", message.getKfAccount()); newsJsonObject.addProperty("kf_account", message.getKfAccount());
messageJson.add("customservice", newsJsonObject); messageJson.add("customservice", newsJsonObject);


+ 3
- 2
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassOpenIdsMessageGsonAdapter.java View File

@@ -19,13 +19,13 @@ public class WxMpMassOpenIdsMessageGsonAdapter implements JsonSerializer<WxMpMas
@Override @Override
public JsonElement serialize(WxMpMassOpenIdsMessage message, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(WxMpMassOpenIdsMessage message, Type typeOfSrc, JsonSerializationContext context) {
JsonObject messageJson = new JsonObject(); JsonObject messageJson = new JsonObject();
JsonArray toUsers = new JsonArray(); JsonArray toUsers = new JsonArray();
for (String openId : message.getToUsers()) { for (String openId : message.getToUsers()) {
toUsers.add(new JsonPrimitive(openId)); toUsers.add(new JsonPrimitive(openId));
} }
messageJson.add("touser", toUsers); messageJson.add("touser", toUsers);
if (WxConsts.MASS_MSG_NEWS.equals(message.getMsgType())) { if (WxConsts.MASS_MSG_NEWS.equals(message.getMsgType())) {
JsonObject sub = new JsonObject(); JsonObject sub = new JsonObject();
sub.addProperty("media_id", message.getMediaId()); sub.addProperty("media_id", message.getMediaId());
@@ -52,6 +52,7 @@ public class WxMpMassOpenIdsMessageGsonAdapter implements JsonSerializer<WxMpMas
messageJson.add(WxConsts.MASS_MSG_VIDEO, sub); messageJson.add(WxConsts.MASS_MSG_VIDEO, sub);
} }
messageJson.addProperty("msgtype", message.getMsgType()); messageJson.addProperty("msgtype", message.getMsgType());
messageJson.addProperty("send_ignore_reprint", message.isSendIgnoreReprint() ? 0 : 1);
return messageJson; return messageJson;
} }




+ 1
- 3
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassSendResultAdapter.java View File

@@ -15,9 +15,7 @@ import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult;
import java.lang.reflect.Type; import java.lang.reflect.Type;


/** /**
*
* @author Daniel Qian * @author Daniel Qian
*
*/ */
public class WxMpMassSendResultAdapter implements JsonDeserializer<WxMpMassSendResult> { public class WxMpMassSendResultAdapter implements JsonDeserializer<WxMpMassSendResult> {


@@ -40,5 +38,5 @@ public class WxMpMassSendResultAdapter implements JsonDeserializer<WxMpMassSendR
} }
return sendResult; return sendResult;
} }
} }

+ 12
- 12
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassTagMessageGsonAdapter.java View File

@@ -8,57 +8,57 @@
*/ */
package me.chanjar.weixin.mp.util.json; package me.chanjar.weixin.mp.util.json;


import java.lang.reflect.Type;

import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer; import com.google.gson.JsonSerializer;

import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.mp.bean.WxMpMassTagMessage; import me.chanjar.weixin.mp.bean.WxMpMassTagMessage;


import java.lang.reflect.Type;

public class WxMpMassTagMessageGsonAdapter implements JsonSerializer<WxMpMassTagMessage> { public class WxMpMassTagMessageGsonAdapter implements JsonSerializer<WxMpMassTagMessage> {


@Override @Override
public JsonElement serialize(WxMpMassTagMessage message, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(WxMpMassTagMessage message, Type typeOfSrc, JsonSerializationContext context) {
JsonObject messageJson = new JsonObject(); JsonObject messageJson = new JsonObject();
JsonObject filter = new JsonObject(); JsonObject filter = new JsonObject();
if(null == message.getTagId()) {
if (message.isSendAll() || null == message.getTagId()) {
filter.addProperty("is_to_all", true); filter.addProperty("is_to_all", true);
} else { } else {
filter.addProperty("is_to_all", false); filter.addProperty("is_to_all", false);
filter.addProperty("tag_id", message.getTagId()); filter.addProperty("tag_id", message.getTagId());
} }
messageJson.add("filter", filter); messageJson.add("filter", filter);
if (WxConsts.MASS_MSG_NEWS.equals(message.getMsgtype())) {
if (WxConsts.MASS_MSG_NEWS.equals(message.getMsgType())) {
JsonObject sub = new JsonObject(); JsonObject sub = new JsonObject();
sub.addProperty("media_id", message.getMediaId()); sub.addProperty("media_id", message.getMediaId());
messageJson.add(WxConsts.MASS_MSG_NEWS, sub); messageJson.add(WxConsts.MASS_MSG_NEWS, sub);
} }
if (WxConsts.MASS_MSG_TEXT.equals(message.getMsgtype())) {
if (WxConsts.MASS_MSG_TEXT.equals(message.getMsgType())) {
JsonObject sub = new JsonObject(); JsonObject sub = new JsonObject();
sub.addProperty("content", message.getContent()); sub.addProperty("content", message.getContent());
messageJson.add(WxConsts.MASS_MSG_TEXT, sub); messageJson.add(WxConsts.MASS_MSG_TEXT, sub);
} }
if (WxConsts.MASS_MSG_VOICE.equals(message.getMsgtype())) {
if (WxConsts.MASS_MSG_VOICE.equals(message.getMsgType())) {
JsonObject sub = new JsonObject(); JsonObject sub = new JsonObject();
sub.addProperty("media_id", message.getMediaId()); sub.addProperty("media_id", message.getMediaId());
messageJson.add(WxConsts.MASS_MSG_VOICE, sub); messageJson.add(WxConsts.MASS_MSG_VOICE, sub);
} }
if (WxConsts.MASS_MSG_IMAGE.equals(message.getMsgtype())) {
if (WxConsts.MASS_MSG_IMAGE.equals(message.getMsgType())) {
JsonObject sub = new JsonObject(); JsonObject sub = new JsonObject();
sub.addProperty("media_id", message.getMediaId()); sub.addProperty("media_id", message.getMediaId());
messageJson.add(WxConsts.MASS_MSG_IMAGE, sub); messageJson.add(WxConsts.MASS_MSG_IMAGE, sub);
} }
if (WxConsts.MASS_MSG_VIDEO.equals(message.getMsgtype())) {
if (WxConsts.MASS_MSG_VIDEO.equals(message.getMsgType())) {
JsonObject sub = new JsonObject(); JsonObject sub = new JsonObject();
sub.addProperty("media_id", message.getMediaId()); sub.addProperty("media_id", message.getMediaId());
messageJson.add(WxConsts.MASS_MSG_VIDEO, sub); messageJson.add(WxConsts.MASS_MSG_VIDEO, sub);
} }
messageJson.addProperty("msgtype", message.getMsgtype());
messageJson.addProperty("msgtype", message.getMsgType());
messageJson.addProperty("send_ignore_reprint", message.isSendIgnoreReprint() ? 0 : 1);
return messageJson; return messageJson;
} }




+ 1
- 3
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassUploadResultAdapter.java View File

@@ -15,9 +15,7 @@ import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult;
import java.lang.reflect.Type; import java.lang.reflect.Type;


/** /**
*
* @author Daniel Qian * @author Daniel Qian
*
*/ */
public class WxMpMassUploadResultAdapter implements JsonDeserializer<WxMpMassUploadResult> { public class WxMpMassUploadResultAdapter implements JsonDeserializer<WxMpMassUploadResult> {


@@ -37,5 +35,5 @@ public class WxMpMassUploadResultAdapter implements JsonDeserializer<WxMpMassUpl
} }
return uploadResult; return uploadResult;
} }
} }

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

@@ -17,9 +17,7 @@ import me.chanjar.weixin.mp.bean.WxMpMassVideo;
import java.lang.reflect.Type; import java.lang.reflect.Type;


/** /**
*
* @author Daniel Qian * @author Daniel Qian
*
*/ */
public class WxMpMassVideoAdapter implements JsonSerializer<WxMpMassVideo> { public class WxMpMassVideoAdapter implements JsonSerializer<WxMpMassVideo> {




+ 2
- 2
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMaterialNewsArticleGsonAdapter.java View File

@@ -21,7 +21,7 @@ public class WxMpMaterialNewsArticleGsonAdapter implements JsonSerializer<WxMpMa
JsonObject articleJson = new JsonObject(); JsonObject articleJson = new JsonObject();


articleJson.addProperty("thumb_media_id", article.getThumbMediaId()); articleJson.addProperty("thumb_media_id", article.getThumbMediaId());
articleJson.addProperty("thumb_url",article.getThumbUrl());
articleJson.addProperty("thumb_url", article.getThumbUrl());
articleJson.addProperty("title", article.getTitle()); articleJson.addProperty("title", article.getTitle());
articleJson.addProperty("content", article.getContent()); articleJson.addProperty("content", article.getContent());
if (null != article.getAuthor()) { if (null != article.getAuthor()) {
@@ -70,7 +70,7 @@ public class WxMpMaterialNewsArticleGsonAdapter implements JsonSerializer<WxMpMa
article.setThumbMediaId(GsonHelper.getAsString(thumbMediaId)); article.setThumbMediaId(GsonHelper.getAsString(thumbMediaId));
} }
JsonElement thumbUrl = articleInfo.get("thumb_url"); JsonElement thumbUrl = articleInfo.get("thumb_url");
if(thumbUrl != null && !thumbUrl.isJsonNull()) {
if (thumbUrl != null && !thumbUrl.isJsonNull()) {
article.setThumbUrl(GsonHelper.getAsString(thumbUrl)); article.setThumbUrl(GsonHelper.getAsString(thumbUrl));
} }
JsonElement showCoverPic = articleInfo.get("show_cover_pic"); JsonElement showCoverPic = articleInfo.get("show_cover_pic");


+ 4
- 9
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpOAuth2AccessTokenAdapter.java View File

@@ -1,21 +1,16 @@
package me.chanjar.weixin.mp.util.json; package me.chanjar.weixin.mp.util.json;


import java.lang.reflect.Type;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import com.google.gson.*;
import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;


import java.lang.reflect.Type;

public class WxMpOAuth2AccessTokenAdapter implements JsonDeserializer<WxMpOAuth2AccessToken> { public class WxMpOAuth2AccessTokenAdapter implements JsonDeserializer<WxMpOAuth2AccessToken> {


@Override @Override
public WxMpOAuth2AccessToken deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws public WxMpOAuth2AccessToken deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws
JsonParseException {
JsonParseException {
WxMpOAuth2AccessToken accessToken = new WxMpOAuth2AccessToken(); WxMpOAuth2AccessToken accessToken = new WxMpOAuth2AccessToken();
JsonObject accessTokenJsonObject = json.getAsJsonObject(); JsonObject accessTokenJsonObject = json.getAsJsonObject();




+ 1
- 3
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpSemanticQueryResultAdapter.java View File

@@ -15,9 +15,7 @@ import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
import java.lang.reflect.Type; import java.lang.reflect.Type;


/** /**
*
* @author Daniel Qian * @author Daniel Qian
*
*/ */
public class WxMpSemanticQueryResultAdapter implements JsonDeserializer<WxMpSemanticQueryResult> { public class WxMpSemanticQueryResultAdapter implements JsonDeserializer<WxMpSemanticQueryResult> {


@@ -46,5 +44,5 @@ public class WxMpSemanticQueryResultAdapter implements JsonDeserializer<WxMpSema
} }
return result; return result;
} }
} }

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

@@ -12,7 +12,6 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer; import com.google.gson.JsonSerializer;

import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;




+ 7
- 15
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserCumulateGsonAdapter.java View File

@@ -8,29 +8,21 @@
*/ */
package me.chanjar.weixin.mp.util.json; package me.chanjar.weixin.mp.util.json;


import java.lang.reflect.Type;
import java.text.ParseException;

import org.apache.commons.lang3.time.FastDateFormat;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import com.google.gson.*;
import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate; import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate;
import org.apache.commons.lang3.time.FastDateFormat;

import java.lang.reflect.Type;
import java.text.ParseException;


/** /**
*
* @author Daniel Qian * @author Daniel Qian
*
*/ */
public class WxMpUserCumulateGsonAdapter implements JsonDeserializer<WxDataCubeUserCumulate> { public class WxMpUserCumulateGsonAdapter implements JsonDeserializer<WxDataCubeUserCumulate> {


private static final FastDateFormat DATE_FORMAT = FastDateFormat private static final FastDateFormat DATE_FORMAT = FastDateFormat
.getInstance("yyyy-MM-dd");
.getInstance("yyyy-MM-dd");


@Override @Override
public WxDataCubeUserCumulate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { public WxDataCubeUserCumulate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
@@ -49,5 +41,5 @@ public class WxMpUserCumulateGsonAdapter implements JsonDeserializer<WxDataCubeU
return cumulate; return cumulate;


} }
} }

+ 4
- 9
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java View File

@@ -8,17 +8,12 @@
*/ */
package me.chanjar.weixin.mp.util.json; package me.chanjar.weixin.mp.util.json;


import java.lang.reflect.Type;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import com.google.gson.*;
import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.result.WxMpUser; import me.chanjar.weixin.mp.bean.result.WxMpUser;


import java.lang.reflect.Type;

public class WxMpUserGsonAdapter implements JsonDeserializer<WxMpUser> { public class WxMpUserGsonAdapter implements JsonDeserializer<WxMpUser> {


@Override @Override
@@ -43,7 +38,7 @@ public class WxMpUserGsonAdapter implements JsonDeserializer<WxMpUser> {
wxMpUser.setGroupId(GsonHelper.getInteger(o, "groupid")); wxMpUser.setGroupId(GsonHelper.getInteger(o, "groupid"));
wxMpUser.setTagIds(GsonHelper.getIntArray(o, "tagid_list")); wxMpUser.setTagIds(GsonHelper.getIntArray(o, "tagid_list"));
wxMpUser.setSexId(sexId); wxMpUser.setSexId(sexId);
if(new Integer(1).equals(sexId)) {
if (new Integer(1).equals(sexId)) {
wxMpUser.setSex("男"); wxMpUser.setSex("男");
} else if (new Integer(2).equals(sexId)) { } else if (new Integer(2).equals(sexId)) {
wxMpUser.setSex("女"); wxMpUser.setSex("女");


+ 7
- 13
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserSummaryGsonAdapter.java View File

@@ -8,19 +8,13 @@
*/ */
package me.chanjar.weixin.mp.util.json; package me.chanjar.weixin.mp.util.json;


import java.lang.reflect.Type;
import java.text.ParseException;

import org.apache.commons.lang3.time.FastDateFormat;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import com.google.gson.*;
import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;
import org.apache.commons.lang3.time.FastDateFormat;

import java.lang.reflect.Type;
import java.text.ParseException;


/** /**
* @author Daniel Qian * @author Daniel Qian
@@ -28,11 +22,11 @@ import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;
public class WxMpUserSummaryGsonAdapter implements JsonDeserializer<WxDataCubeUserSummary> { public class WxMpUserSummaryGsonAdapter implements JsonDeserializer<WxDataCubeUserSummary> {


private static final FastDateFormat DATE_FORMAT = FastDateFormat private static final FastDateFormat DATE_FORMAT = FastDateFormat
.getInstance("yyyy-MM-dd");
.getInstance("yyyy-MM-dd");


@Override @Override
public WxDataCubeUserSummary deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public WxDataCubeUserSummary deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
throws JsonParseException {
WxDataCubeUserSummary summary = new WxDataCubeUserSummary(); WxDataCubeUserSummary summary = new WxDataCubeUserSummary();
JsonObject summaryJsonObject = json.getAsJsonObject(); JsonObject summaryJsonObject = json.getAsJsonObject();




+ 1
- 3
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxQrCodeTicketAdapter.java View File

@@ -15,9 +15,7 @@ import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import java.lang.reflect.Type; import java.lang.reflect.Type;


/** /**
*
* @author Daniel Qian * @author Daniel Qian
*
*/ */
public class WxQrCodeTicketAdapter implements JsonDeserializer<WxMpQrCodeTicket> { public class WxQrCodeTicketAdapter implements JsonDeserializer<WxMpQrCodeTicket> {


@@ -37,5 +35,5 @@ public class WxQrCodeTicketAdapter implements JsonDeserializer<WxMpQrCodeTicket>
} }
return ticket; return ticket;
} }
} }

+ 4
- 4
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java View File

@@ -2,15 +2,15 @@ package me.chanjar.weixin.mp.api;


import com.google.inject.Inject; import com.google.inject.Inject;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import org.testng.*;
import org.testng.annotations.*;


/** /**
* 基础API测试 * 基础API测试
* @author chanjarster
* *
* @author chanjarster
*/ */
@Test(groups = "baseAPI") @Test(groups = "baseAPI")
@Guice(modules = ApiTestModule.class) @Guice(modules = ApiTestModule.class)


+ 11
- 14
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java View File

@@ -1,29 +1,28 @@
package me.chanjar.weixin.mp.api; package me.chanjar.weixin.mp.api;


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

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

import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import org.testng.annotations.*;

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


@Test @Test
public class WxMpBusyRetryTest { public class WxMpBusyRetryTest {


@DataProvider(name="getService")
@DataProvider(name = "getService")
public Object[][] getService() { public Object[][] getService() {
WxMpService service = new WxMpServiceImpl() { WxMpService service = new WxMpServiceImpl() {


@Override @Override
protected synchronized <T, E> T executeInternal( protected synchronized <T, E> T executeInternal(
RequestExecutor<T, E> executor, String uri, E data)
throws WxErrorException {
RequestExecutor<T, E> executor, String uri, E data)
throws WxErrorException {
this.log.info("Executed");
WxError error = new WxError(); WxError error = new WxError();
error.setErrorCode(-1); error.setErrorCode(-1);
throw new WxErrorException(error); throw new WxErrorException(error);
@@ -32,9 +31,7 @@ public class WxMpBusyRetryTest {


service.setMaxRetryTimes(3); service.setMaxRetryTimes(3);
service.setRetrySleepMillis(500); service.setRetrySleepMillis(500);
return new Object[][] {
new Object[] { service }
};
return new Object[][]{{service}};
} }


@Test(dataProvider = "getService", expectedExceptions = RuntimeException.class) @Test(dataProvider = "getService", expectedExceptions = RuntimeException.class)


+ 7
- 9
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java View File

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


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

import com.google.inject.Inject; import com.google.inject.Inject;

import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.common.util.crypto.SHA1;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import org.testng.*;
import org.testng.annotations.*;


/** /**
* 测试jsapi ticket接口 * 测试jsapi ticket接口
@@ -34,10 +32,10 @@ public class WxMpJsAPITest {
String noncestr = "82693e11-b9bc-448e-892f-f5289f46cd0f"; String noncestr = "82693e11-b9bc-448e-892f-f5289f46cd0f";
String jsapiTicket = "bxLdikRXVbTPdHSM05e5u4RbEYQn7pNQMPrfzl8lJNb1foLDa3HIwI3BRMkQmSO_5F64VFa75uURcq6Uz7QHgA"; String jsapiTicket = "bxLdikRXVbTPdHSM05e5u4RbEYQn7pNQMPrfzl8lJNb1foLDa3HIwI3BRMkQmSO_5F64VFa75uURcq6Uz7QHgA";
String result = SHA1.genWithAmple( String result = SHA1.genWithAmple(
"jsapi_ticket=" + jsapiTicket,
"noncestr=" + noncestr,
"timestamp=" + timestamp,
"url=" + url
"jsapi_ticket=" + jsapiTicket,
"noncestr=" + noncestr,
"timestamp=" + timestamp,
"url=" + url
); );


Assert.assertEquals(result, "c6f04b64d6351d197b71bd23fb7dd2d44c0db486"); Assert.assertEquals(result, "c6f04b64d6351d197b71bd23fb7dd2d44c0db486");


+ 41
- 45
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMassMessageAPITest.java View File

@@ -1,31 +1,29 @@
package me.chanjar.weixin.mp.api; package me.chanjar.weixin.mp.api;


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

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

import com.google.inject.Inject; import com.google.inject.Inject;

import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import me.chanjar.weixin.mp.api.test.TestConfigStorage;
import me.chanjar.weixin.mp.bean.WxMpMassNews; import me.chanjar.weixin.mp.bean.WxMpMassNews;
import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage; import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage;
import me.chanjar.weixin.mp.bean.WxMpMassTagMessage; import me.chanjar.weixin.mp.bean.WxMpMassTagMessage;
import me.chanjar.weixin.mp.bean.WxMpMassVideo; import me.chanjar.weixin.mp.bean.WxMpMassVideo;
import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult; import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult;
import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult;
import org.testng.*;
import org.testng.annotations.*;

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


/** /**
* 测试群发消息 * 测试群发消息
* @author chanjarster
* *
* @author chanjarster
*/ */
@Test(groups = "massAPI", dependsOnGroups = { "baseAPI", "mediaAPI", "groupAPI"})
@Test(groups = "massAPI", dependsOnGroups = {"baseAPI", "mediaAPI", "groupAPI"})
@Guice(modules = ApiTestModule.class) @Guice(modules = ApiTestModule.class)
public class WxMpMassMessageAPITest { public class WxMpMassMessageAPITest {


@@ -35,32 +33,31 @@ public class WxMpMassMessageAPITest {
@Test @Test
public void testTextMassOpenIdsMessageSend() throws WxErrorException { public void testTextMassOpenIdsMessageSend() throws WxErrorException {
// 发送群发消息 // 发送群发消息
WxXmlMpInMemoryConfigStorage configProvider = (WxXmlMpInMemoryConfigStorage) this.wxService
.getWxMpConfigStorage();
TestConfigStorage configProvider = (TestConfigStorage) this.wxService
.getWxMpConfigStorage();
WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage(); WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage();
massMessage.setMsgType(WxConsts.MASS_MSG_TEXT); massMessage.setMsgType(WxConsts.MASS_MSG_TEXT);
massMessage.setContent("测试群发消息\n欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>"); massMessage.setContent("测试群发消息\n欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");
massMessage.getToUsers().add(configProvider.getOpenid()); massMessage.getToUsers().add(configProvider.getOpenid());


WxMpMassSendResult massResult = this.wxService WxMpMassSendResult massResult = this.wxService
.massOpenIdsMessageSend(massMessage);
.massOpenIdsMessageSend(massMessage);
Assert.assertNotNull(massResult); Assert.assertNotNull(massResult);
Assert.assertNotNull(massResult.getMsgId()); Assert.assertNotNull(massResult.getMsgId());
} }


@Test(dataProvider="massMessages")
public void testMediaMassOpenIdsMessageSend(String massMsgType,
String mediaId) throws WxErrorException {
@Test(dataProvider = "massMessages")
public void testMediaMassOpenIdsMessageSend(String massMsgType, String mediaId) throws WxErrorException {
// 发送群发消息 // 发送群发消息
WxXmlMpInMemoryConfigStorage configProvider = (WxXmlMpInMemoryConfigStorage) this.wxService
.getWxMpConfigStorage();
TestConfigStorage configProvider = (TestConfigStorage) this.wxService
.getWxMpConfigStorage();
WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage(); WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage();
massMessage.setMsgType(massMsgType); massMessage.setMsgType(massMsgType);
massMessage.setMediaId(mediaId); massMessage.setMediaId(mediaId);
massMessage.getToUsers().add(configProvider.getOpenid()); massMessage.getToUsers().add(configProvider.getOpenid());


WxMpMassSendResult massResult = this.wxService WxMpMassSendResult massResult = this.wxService
.massOpenIdsMessageSend(massMessage);
.massOpenIdsMessageSend(massMessage);
Assert.assertNotNull(massResult); Assert.assertNotNull(massResult);
Assert.assertNotNull(massResult.getMsgId()); Assert.assertNotNull(massResult.getMsgId());
} }
@@ -68,28 +65,27 @@ public class WxMpMassMessageAPITest {
@Test @Test
public void testTextMassGroupMessageSend() throws WxErrorException { public void testTextMassGroupMessageSend() throws WxErrorException {
WxMpMassTagMessage massMessage = new WxMpMassTagMessage(); WxMpMassTagMessage massMessage = new WxMpMassTagMessage();
massMessage.setMsgtype(WxConsts.MASS_MSG_TEXT);
massMessage.setMsgType(WxConsts.MASS_MSG_TEXT);
massMessage.setContent("测试群发消息\n欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>"); massMessage.setContent("测试群发消息\n欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");
massMessage massMessage
.setTagId(this.wxService.getUserTagService().tagGet().get(0).getId());
.setTagId(this.wxService.getUserTagService().tagGet().get(0).getId());


WxMpMassSendResult massResult = this.wxService WxMpMassSendResult massResult = this.wxService
.massGroupMessageSend(massMessage);
.massGroupMessageSend(massMessage);
Assert.assertNotNull(massResult); Assert.assertNotNull(massResult);
Assert.assertNotNull(massResult.getMsgId()); Assert.assertNotNull(massResult.getMsgId());
} }


@Test(dataProvider="massMessages")
@Test(dataProvider = "massMessages")
public void testMediaMassGroupMessageSend(String massMsgType, String mediaId) public void testMediaMassGroupMessageSend(String massMsgType, String mediaId)
throws WxErrorException {
throws WxErrorException {
WxMpMassTagMessage massMessage = new WxMpMassTagMessage(); WxMpMassTagMessage massMessage = new WxMpMassTagMessage();
massMessage.setMsgtype(massMsgType);
massMessage.setMsgType(massMsgType);
massMessage.setMediaId(mediaId); massMessage.setMediaId(mediaId);
massMessage
.setTagId(this.wxService.getUserTagService().tagGet().get(0).getId());
massMessage.setTagId(this.wxService.getUserTagService().tagGet().get(0).getId());


WxMpMassSendResult massResult = this.wxService WxMpMassSendResult massResult = this.wxService
.massGroupMessageSend(massMessage);
.massGroupMessageSend(massMessage);
Assert.assertNotNull(massResult); Assert.assertNotNull(massResult);
Assert.assertNotNull(massResult.getMsgId()); Assert.assertNotNull(massResult.getMsgId());
} }
@@ -102,10 +98,10 @@ public class WxMpMassMessageAPITest {
* 视频素材 * 视频素材
*/ */
try (InputStream inputStream = ClassLoader try (InputStream inputStream = ClassLoader
.getSystemResourceAsStream("mm.mp4")) {
.getSystemResourceAsStream("mm.mp4")) {
// 上传视频到媒体库 // 上传视频到媒体库
WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService() WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService()
.mediaUpload(WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, inputStream);
.mediaUpload(WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, inputStream);
Assert.assertNotNull(uploadMediaRes); Assert.assertNotNull(uploadMediaRes);
Assert.assertNotNull(uploadMediaRes.getMediaId()); Assert.assertNotNull(uploadMediaRes.getMediaId());


@@ -117,41 +113,41 @@ public class WxMpMassMessageAPITest {
WxMpMassUploadResult uploadResult = this.wxService.massVideoUpload(video); WxMpMassUploadResult uploadResult = this.wxService.massVideoUpload(video);
Assert.assertNotNull(uploadResult); Assert.assertNotNull(uploadResult);
Assert.assertNotNull(uploadResult.getMediaId()); Assert.assertNotNull(uploadResult.getMediaId());
messages[0] = new Object[] { WxConsts.MASS_MSG_VIDEO, uploadResult.getMediaId() };
messages[0] = new Object[]{WxConsts.MASS_MSG_VIDEO, uploadResult.getMediaId()};
} }


/**
/*
* 图片素材 * 图片素材
*/ */
try (InputStream inputStream = ClassLoader try (InputStream inputStream = ClassLoader
.getSystemResourceAsStream("mm.jpeg")) {
.getSystemResourceAsStream("mm.jpeg")) {
WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService() WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService()
.mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, inputStream);
.mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, inputStream);
Assert.assertNotNull(uploadMediaRes); Assert.assertNotNull(uploadMediaRes);
Assert.assertNotNull(uploadMediaRes.getMediaId()); Assert.assertNotNull(uploadMediaRes.getMediaId());
messages[1] = new Object[] { WxConsts.MASS_MSG_IMAGE, uploadMediaRes.getMediaId() };
messages[1] = new Object[]{WxConsts.MASS_MSG_IMAGE, uploadMediaRes.getMediaId()};
} }


/**
/*
* 语音素材 * 语音素材
*/ */
try (InputStream inputStream = ClassLoader try (InputStream inputStream = ClassLoader
.getSystemResourceAsStream("mm.mp3")) {
.getSystemResourceAsStream("mm.mp3")) {
WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService() WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService()
.mediaUpload(WxConsts.MEDIA_VOICE, WxConsts.FILE_MP3, inputStream);
.mediaUpload(WxConsts.MEDIA_VOICE, WxConsts.FILE_MP3, inputStream);
Assert.assertNotNull(uploadMediaRes); Assert.assertNotNull(uploadMediaRes);
Assert.assertNotNull(uploadMediaRes.getMediaId()); Assert.assertNotNull(uploadMediaRes.getMediaId());
messages[2] = new Object[] { WxConsts.MASS_MSG_VOICE, uploadMediaRes.getMediaId() };
messages[2] = new Object[]{WxConsts.MASS_MSG_VOICE, uploadMediaRes.getMediaId()};
} }


/**
/*
* 图文素材 * 图文素材
*/ */
try (InputStream inputStream = ClassLoader try (InputStream inputStream = ClassLoader
.getSystemResourceAsStream("mm.jpeg")) {
.getSystemResourceAsStream("mm.jpeg")) {
// 上传照片到媒体库 // 上传照片到媒体库
WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService() WxMediaUploadResult uploadMediaRes = this.wxService.getMaterialService()
.mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, inputStream);
.mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, inputStream);
Assert.assertNotNull(uploadMediaRes); Assert.assertNotNull(uploadMediaRes);
Assert.assertNotNull(uploadMediaRes.getMediaId()); Assert.assertNotNull(uploadMediaRes.getMediaId());


@@ -174,10 +170,10 @@ public class WxMpMassMessageAPITest {
news.addArticle(article2); news.addArticle(article2);


WxMpMassUploadResult massUploadResult = this.wxService WxMpMassUploadResult massUploadResult = this.wxService
.massNewsUpload(news);
.massNewsUpload(news);
Assert.assertNotNull(massUploadResult); Assert.assertNotNull(massUploadResult);
Assert.assertNotNull(uploadMediaRes.getMediaId()); Assert.assertNotNull(uploadMediaRes.getMediaId());
messages[3] = new Object[] { WxConsts.MASS_MSG_NEWS, massUploadResult.getMediaId() };
messages[3] = new Object[]{WxConsts.MASS_MSG_NEWS, massUploadResult.getMediaId()};
} }


return messages; return messages;


+ 67
- 67
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java View File

@@ -5,16 +5,15 @@ import me.chanjar.weixin.common.session.StandardSessionManager;
import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.*;
import org.testng.annotations.*;


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


/** /**
* 测试消息路由器 * 测试消息路由器
* @author chanjarster
* *
* @author chanjarster
*/ */
@Test @Test
public class WxMpMessageRouterTest { public class WxMpMessageRouterTest {
@@ -23,19 +22,19 @@ public class WxMpMessageRouterTest {
public void prepare(boolean async, StringBuffer sb, WxMpMessageRouter router) { public void prepare(boolean async, StringBuffer sb, WxMpMessageRouter router) {
router router
.rule() .rule()
.async(async)
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1")
.handler(new WxEchoMpMessageHandler(sb, "COMBINE_4"))
.async(async)
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1")
.handler(new WxEchoMpMessageHandler(sb, "COMBINE_4"))
.end() .end()
.rule() .rule()
.async(async)
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1")
.handler(new WxEchoMpMessageHandler(sb, "COMBINE_3"))
.async(async)
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1")
.handler(new WxEchoMpMessageHandler(sb, "COMBINE_3"))
.end() .end()
.rule() .rule()
.async(async)
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK)
.handler(new WxEchoMpMessageHandler(sb, "COMBINE_2"))
.async(async)
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK)
.handler(new WxEchoMpMessageHandler(sb, "COMBINE_2"))
.end() .end()
.rule().async(async).msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoMpMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end() .rule().async(async).msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoMpMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end()
.rule().async(async).event(WxConsts.EVT_CLICK).handler(new WxEchoMpMessageHandler(sb, WxConsts.EVT_CLICK)).end() .rule().async(async).event(WxConsts.EVT_CLICK).handler(new WxEchoMpMessageHandler(sb, WxConsts.EVT_CLICK)).end()
@@ -43,15 +42,15 @@ public class WxMpMessageRouterTest {
.rule().async(async).content("CONTENT_1").handler(new WxEchoMpMessageHandler(sb, "CONTENT_1")).end() .rule().async(async).content("CONTENT_1").handler(new WxEchoMpMessageHandler(sb, "CONTENT_1")).end()
.rule().async(async).rContent(".*bc.*").handler(new WxEchoMpMessageHandler(sb, "abcd")).end() .rule().async(async).rContent(".*bc.*").handler(new WxEchoMpMessageHandler(sb, "abcd")).end()
.rule().async(async).matcher(new WxMpMessageMatcher() { .rule().async(async).matcher(new WxMpMessageMatcher() {
@Override
public boolean match(WxMpXmlMessage message) {
return "strangeformat".equals(message.getFormat());
}
}).handler(new WxEchoMpMessageHandler(sb, "matcher")).end()
@Override
public boolean match(WxMpXmlMessage message) {
return "strangeformat".equals(message.getFormat());
}
}).handler(new WxEchoMpMessageHandler(sb, "matcher")).end()
.rule().async(async).handler(new WxEchoMpMessageHandler(sb, "ALL")).end(); .rule().async(async).handler(new WxEchoMpMessageHandler(sb, "ALL")).end();
} }


@Test(dataProvider="messages-1")
@Test(dataProvider = "messages-1")
public void testSync(WxMpXmlMessage message, String expected) { public void testSync(WxMpXmlMessage message, String expected) {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
WxMpMessageRouter router = new WxMpMessageRouter(null); WxMpMessageRouter router = new WxMpMessageRouter(null);
@@ -60,11 +59,11 @@ public class WxMpMessageRouterTest {
Assert.assertEquals(sb.toString(), expected); Assert.assertEquals(sb.toString(), expected);
} }


@Test(dataProvider="messages-1")
@Test(dataProvider = "messages-1")
public void testAsync(WxMpXmlMessage message, String expected) throws InterruptedException { public void testAsync(WxMpXmlMessage message, String expected) throws InterruptedException {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
WxMpMessageRouter router = new WxMpMessageRouter(null); WxMpMessageRouter router = new WxMpMessageRouter(null);
prepare(true, sb, router);
prepare(true, sb, router);
router.route(message); router.route(message);
Thread.sleep(500l); Thread.sleep(500l);
Assert.assertEquals(sb.toString(), expected); Assert.assertEquals(sb.toString(), expected);
@@ -75,7 +74,7 @@ public class WxMpMessageRouterTest {
router.rule().handler(new WxMpMessageHandler() { router.rule().handler(new WxMpMessageHandler() {
@Override @Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService, public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
WxSessionManager sessionManager) {
return null; return null;
} }
}).end(); }).end();
@@ -97,7 +96,8 @@ public class WxMpMessageRouterTest {


Thread.sleep(1000l * 2); Thread.sleep(1000l * 2);
} }
@DataProvider(name="messages-1")

@DataProvider(name = "messages-1")
public Object[][] messages2() { public Object[][] messages2() {
WxMpXmlMessage message1 = new WxMpXmlMessage(); WxMpXmlMessage message1 = new WxMpXmlMessage();
message1.setMsgType(WxConsts.XML_MSG_TEXT); message1.setMsgType(WxConsts.XML_MSG_TEXT);
@@ -135,40 +135,21 @@ public class WxMpMessageRouterTest {
c4.setEventKey("KEY_1"); c4.setEventKey("KEY_1");
c4.setContent("CONTENT_1"); c4.setContent("CONTENT_1");


return new Object[][] {
new Object[] { message1, WxConsts.XML_MSG_TEXT + "," },
new Object[] { message2, WxConsts.EVT_CLICK + "," },
new Object[] { message3, "KEY_1," },
new Object[] { message4, "CONTENT_1," },
new Object[] { message5, "ALL," },
new Object[] { message6, "abcd," },
new Object[] { message7, "matcher," },
new Object[] { c2, "COMBINE_2," },
new Object[] { c3, "COMBINE_3," },
new Object[] { c4, "COMBINE_4," }
return new Object[][]{
new Object[]{message1, WxConsts.XML_MSG_TEXT + ","},
new Object[]{message2, WxConsts.EVT_CLICK + ","},
new Object[]{message3, "KEY_1,"},
new Object[]{message4, "CONTENT_1,"},
new Object[]{message5, "ALL,"},
new Object[]{message6, "abcd,"},
new Object[]{message7, "matcher,"},
new Object[]{c2, "COMBINE_2,"},
new Object[]{c3, "COMBINE_3,"},
new Object[]{c4, "COMBINE_4,"}
}; };


} }


public static class WxEchoMpMessageHandler implements WxMpMessageHandler {

private StringBuffer sb;
private String echoStr;

public WxEchoMpMessageHandler(StringBuffer sb, String echoStr) {
this.sb = sb;
this.echoStr = echoStr;
}

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
this.sb.append(this.echoStr).append(',');
return null;
}

}

@DataProvider @DataProvider
public Object[][] standardSessionManager() { public Object[][] standardSessionManager() {


@@ -178,8 +159,8 @@ public class WxMpMessageRouterTest {
ism.setProcessExpiresFrequency(1); ism.setProcessExpiresFrequency(1);
ism.setBackgroundProcessorDelay(1); ism.setBackgroundProcessorDelay(1);


return new Object[][] {
new Object[] { ism }
return new Object[][]{
new Object[]{ism}
}; };


} }
@@ -191,8 +172,8 @@ public class WxMpMessageRouterTest {
final WxMpMessageRouter router = new WxMpMessageRouter(null); final WxMpMessageRouter router = new WxMpMessageRouter(null);
router.setSessionManager(ism); router.setSessionManager(ism);
router router
.rule().async(false).handler(new WxSessionMessageHandler()).next()
.rule().async(false).handler(new WxSessionMessageHandler()).end();
.rule().async(false).handler(new WxSessionMessageHandler()).next()
.rule().async(false).handler(new WxSessionMessageHandler()).end();


WxMpXmlMessage msg = new WxMpXmlMessage(); WxMpXmlMessage msg = new WxMpXmlMessage();
msg.setFromUser("abc"); msg.setFromUser("abc");
@@ -211,8 +192,8 @@ public class WxMpMessageRouterTest {
final WxMpMessageRouter router = new WxMpMessageRouter(null); final WxMpMessageRouter router = new WxMpMessageRouter(null);
router.setSessionManager(ism); router.setSessionManager(ism);
router router
.rule().async(false).handler(new WxSessionMessageHandler()).next()
.rule().async(true).handler(new WxSessionMessageHandler()).end();
.rule().async(false).handler(new WxSessionMessageHandler()).next()
.rule().async(true).handler(new WxSessionMessageHandler()).end();


WxMpXmlMessage msg = new WxMpXmlMessage(); WxMpXmlMessage msg = new WxMpXmlMessage();
msg.setFromUser("abc"); msg.setFromUser("abc");
@@ -225,8 +206,8 @@ public class WxMpMessageRouterTest {
final WxMpMessageRouter router = new WxMpMessageRouter(null); final WxMpMessageRouter router = new WxMpMessageRouter(null);
router.setSessionManager(ism); router.setSessionManager(ism);
router router
.rule().async(true).handler(new WxSessionMessageHandler()).next()
.rule().async(false).handler(new WxSessionMessageHandler()).end();
.rule().async(true).handler(new WxSessionMessageHandler()).next()
.rule().async(false).handler(new WxSessionMessageHandler()).end();


WxMpXmlMessage msg = new WxMpXmlMessage(); WxMpXmlMessage msg = new WxMpXmlMessage();
msg.setFromUser("abc"); msg.setFromUser("abc");
@@ -245,8 +226,8 @@ public class WxMpMessageRouterTest {
final WxMpMessageRouter router = new WxMpMessageRouter(null); final WxMpMessageRouter router = new WxMpMessageRouter(null);
router.setSessionManager(ism); router.setSessionManager(ism);
router router
.rule().async(true).handler(new WxSessionMessageHandler()).next()
.rule().async(true).handler(new WxSessionMessageHandler()).end();
.rule().async(true).handler(new WxSessionMessageHandler()).next()
.rule().async(true).handler(new WxSessionMessageHandler()).end();


WxMpXmlMessage msg = new WxMpXmlMessage(); WxMpXmlMessage msg = new WxMpXmlMessage();
msg.setFromUser("abc"); msg.setFromUser("abc");
@@ -265,7 +246,7 @@ public class WxMpMessageRouterTest {
final WxMpMessageRouter router = new WxMpMessageRouter(null); final WxMpMessageRouter router = new WxMpMessageRouter(null);
router.setSessionManager(ism); router.setSessionManager(ism);
router router
.rule().async(false).handler(new WxSessionMessageHandler()).end();
.rule().async(false).handler(new WxSessionMessageHandler()).end();


WxMpXmlMessage msg = new WxMpXmlMessage(); WxMpXmlMessage msg = new WxMpXmlMessage();
msg.setFromUser("abc"); msg.setFromUser("abc");
@@ -279,7 +260,7 @@ public class WxMpMessageRouterTest {
final WxMpMessageRouter router = new WxMpMessageRouter(null); final WxMpMessageRouter router = new WxMpMessageRouter(null);
router.setSessionManager(ism); router.setSessionManager(ism);
router router
.rule().async(true).handler(new WxSessionMessageHandler()).end();
.rule().async(true).handler(new WxSessionMessageHandler()).end();


WxMpXmlMessage msg = new WxMpXmlMessage(); WxMpXmlMessage msg = new WxMpXmlMessage();
msg.setFromUser("abc"); msg.setFromUser("abc");
@@ -290,11 +271,30 @@ public class WxMpMessageRouterTest {
} }
} }


public static class WxSessionMessageHandler implements WxMpMessageHandler {
public static class WxEchoMpMessageHandler implements WxMpMessageHandler {

private StringBuffer sb;
private String echoStr;

public WxEchoMpMessageHandler(StringBuffer sb, String echoStr) {
this.sb = sb;
this.echoStr = echoStr;
}

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
this.sb.append(this.echoStr).append(',');
return null;
}

}

public static class WxSessionMessageHandler implements WxMpMessageHandler {


@Override @Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService, public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
WxSessionManager sessionManager) {
sessionManager.getSession(wxMessage.getFromUser()); sessionManager.getSession(wxMessage.getFromUser());
return null; return null;
} }


+ 3
- 5
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java View File

@@ -2,16 +2,14 @@ package me.chanjar.weixin.mp.api;


import com.google.inject.Inject; import com.google.inject.Inject;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import org.testng.*;
import org.testng.annotations.*;


import java.util.Arrays; import java.util.Arrays;


/** /**
*
* @author chanjarster * @author chanjarster
*
*/ */
@Test(groups = "miscAPI") @Test(groups = "miscAPI")
@Guice(modules = ApiTestModule.class) @Guice(modules = ApiTestModule.class)


+ 3
- 3
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpShortUrlAPITest.java View File

@@ -2,9 +2,9 @@ package me.chanjar.weixin.mp.api;


import com.google.inject.Inject; import com.google.inject.Inject;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import org.testng.*;
import org.testng.annotations.*;


/** /**
* 测试短连接 * 测试短连接


+ 4
- 4
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java View File

@@ -2,17 +2,17 @@ package me.chanjar.weixin.mp.api.impl;


import com.google.inject.Inject; import com.google.inject.Inject;
import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.bean.WxCardApiSignature;
import me.chanjar.weixin.mp.api.ApiTestModule;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import me.chanjar.weixin.mp.bean.result.WxMpCardResult; import me.chanjar.weixin.mp.bean.result.WxMpCardResult;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import org.testng.annotations.*;


import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.*;


/** /**
* 测试代码仅供参考,未做严格测试,因原接口作者并未提供单元测试代码 * 测试代码仅供参考,未做严格测试,因原接口作者并未提供单元测试代码
* Created by Binary Wang on 2016/7/27. * Created by Binary Wang on 2016/7/27.
*
* @author binarywang (https://github.com/binarywang) * @author binarywang (https://github.com/binarywang)
*/ */
@Test @Test


+ 43
- 52
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImplTest.java View File

@@ -1,83 +1,74 @@
package me.chanjar.weixin.mp.api.impl; package me.chanjar.weixin.mp.api.impl;


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

import com.google.inject.Inject;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import me.chanjar.weixin.mp.bean.datacube.*;
import org.apache.commons.lang3.time.FastDateFormat; import org.apache.commons.lang3.time.FastDateFormat;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;

import com.google.inject.Inject;
import org.testng.*;
import org.testng.annotations.*;


import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.ApiTestModule;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeArticleResult;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeArticleTotal;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeInterfaceResult;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeMsgResult;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate;
import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;
import java.text.ParseException;
import java.util.Date;
import java.util.List;


/** /**
* 测试统计分析相关的接口 * 测试统计分析相关的接口
* Created by Binary Wang on 2016/8/23.
* Created by Binary Wang on 2016/8/23.
*
* @author binarywang (https://github.com/binarywang) * @author binarywang (https://github.com/binarywang)
*/ */
@Guice(modules = ApiTestModule.class) @Guice(modules = ApiTestModule.class)
public class WxMpDataCubeServiceImplTest { public class WxMpDataCubeServiceImplTest {
private FastDateFormat simpleDateFormat = FastDateFormat
.getInstance("yyyy-MM-dd");

@Inject @Inject
protected WxMpService wxService; protected WxMpService wxService;
private FastDateFormat simpleDateFormat = FastDateFormat
.getInstance("yyyy-MM-dd");


@DataProvider @DataProvider
public Object[][] oneDay() throws ParseException { public Object[][] oneDay() throws ParseException {
return new Object[][] { { this.simpleDateFormat.parse("2016-08-22") } };
return new Object[][]{{this.simpleDateFormat.parse("2016-08-22")}};
} }


@DataProvider @DataProvider
public Object[][] threeDays() throws ParseException { public Object[][] threeDays() throws ParseException {
return new Object[][] { { this.simpleDateFormat.parse("2016-08-20"),
this.simpleDateFormat.parse("2016-08-22") } };
return new Object[][]{{this.simpleDateFormat.parse("2016-08-20"),
this.simpleDateFormat.parse("2016-08-22")}};
} }


@DataProvider @DataProvider
public Object[][] sevenDays() throws ParseException { public Object[][] sevenDays() throws ParseException {
return new Object[][] { { this.simpleDateFormat.parse("2016-08-16"),
this.simpleDateFormat.parse("2016-08-22") } };
return new Object[][]{{this.simpleDateFormat.parse("2016-08-16"),
this.simpleDateFormat.parse("2016-08-22")}};
} }


@DataProvider @DataProvider
public Object[][] fifteenDays() throws ParseException { public Object[][] fifteenDays() throws ParseException {
return new Object[][] { { this.simpleDateFormat.parse("2016-08-14"),
this.simpleDateFormat.parse("2016-08-27") } };
return new Object[][]{{this.simpleDateFormat.parse("2016-08-14"),
this.simpleDateFormat.parse("2016-08-27")}};
} }


@DataProvider @DataProvider
public Object[][] thirtyDays() throws ParseException { public Object[][] thirtyDays() throws ParseException {
return new Object[][] { { this.simpleDateFormat.parse("2016-07-30"),
this.simpleDateFormat.parse("2016-08-27") } };
return new Object[][]{{this.simpleDateFormat.parse("2016-07-30"),
this.simpleDateFormat.parse("2016-08-27")}};
} }


@Test(dataProvider = "sevenDays") @Test(dataProvider = "sevenDays")
public void testGetUserSummary(Date beginDate, Date endDate) public void testGetUserSummary(Date beginDate, Date endDate)
throws WxErrorException {
throws WxErrorException {
List<WxDataCubeUserSummary> summaries = this.wxService.getDataCubeService() List<WxDataCubeUserSummary> summaries = this.wxService.getDataCubeService()
.getUserSummary(beginDate, endDate);
.getUserSummary(beginDate, endDate);
Assert.assertNotNull(summaries); Assert.assertNotNull(summaries);
System.out.println(summaries); System.out.println(summaries);
} }


@Test(dataProvider = "sevenDays") @Test(dataProvider = "sevenDays")
public void testGetUserCumulate(Date beginDate, Date endDate) public void testGetUserCumulate(Date beginDate, Date endDate)
throws WxErrorException {
throws WxErrorException {
List<WxDataCubeUserCumulate> result = this.wxService.getDataCubeService() List<WxDataCubeUserCumulate> result = this.wxService.getDataCubeService()
.getUserCumulate(beginDate, endDate);
.getUserCumulate(beginDate, endDate);
Assert.assertNotNull(result); Assert.assertNotNull(result);
System.out.println(result); System.out.println(result);
} }
@@ -85,7 +76,7 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "oneDay") @Test(dataProvider = "oneDay")
public void testGetArticleSummary(Date date) throws WxErrorException { public void testGetArticleSummary(Date date) throws WxErrorException {
List<WxDataCubeArticleResult> results = this.wxService.getDataCubeService() List<WxDataCubeArticleResult> results = this.wxService.getDataCubeService()
.getArticleSummary(date, date);
.getArticleSummary(date, date);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -96,16 +87,16 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "oneDay") @Test(dataProvider = "oneDay")
public void testGetArticleTotal(Date date) throws WxErrorException { public void testGetArticleTotal(Date date) throws WxErrorException {
List<WxDataCubeArticleTotal> results = this.wxService.getDataCubeService() List<WxDataCubeArticleTotal> results = this.wxService.getDataCubeService()
.getArticleTotal(date, date);
.getArticleTotal(date, date);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }


@Test(dataProvider = "threeDays") @Test(dataProvider = "threeDays")
public void testGetUserRead(Date beginDate, Date endDate) public void testGetUserRead(Date beginDate, Date endDate)
throws WxErrorException {
throws WxErrorException {
List<WxDataCubeArticleResult> results = this.wxService.getDataCubeService() List<WxDataCubeArticleResult> results = this.wxService.getDataCubeService()
.getUserRead(beginDate, endDate);
.getUserRead(beginDate, endDate);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -113,16 +104,16 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "oneDay") @Test(dataProvider = "oneDay")
public void testGetUserReadHour(Date date) throws WxErrorException { public void testGetUserReadHour(Date date) throws WxErrorException {
List<WxDataCubeArticleResult> results = this.wxService.getDataCubeService() List<WxDataCubeArticleResult> results = this.wxService.getDataCubeService()
.getUserReadHour(date, date);
.getUserReadHour(date, date);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }


@Test(dataProvider = "sevenDays") @Test(dataProvider = "sevenDays")
public void testGetUserShare(Date beginDate, Date endDate) public void testGetUserShare(Date beginDate, Date endDate)
throws WxErrorException {
throws WxErrorException {
List<WxDataCubeArticleResult> results = this.wxService.getDataCubeService() List<WxDataCubeArticleResult> results = this.wxService.getDataCubeService()
.getUserShare(beginDate, endDate);
.getUserShare(beginDate, endDate);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -130,7 +121,7 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "oneDay") @Test(dataProvider = "oneDay")
public void testGetUserShareHour(Date date) throws WxErrorException { public void testGetUserShareHour(Date date) throws WxErrorException {
List<WxDataCubeArticleResult> results = this.wxService.getDataCubeService() List<WxDataCubeArticleResult> results = this.wxService.getDataCubeService()
.getUserShareHour(date, date);
.getUserShareHour(date, date);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -138,7 +129,7 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "sevenDays") @Test(dataProvider = "sevenDays")
public void testGetUpstreamMsg(Date beginDate, Date endDate) throws WxErrorException { public void testGetUpstreamMsg(Date beginDate, Date endDate) throws WxErrorException {
List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService() List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService()
.getUpstreamMsg(beginDate, endDate);
.getUpstreamMsg(beginDate, endDate);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -146,7 +137,7 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "oneDay") @Test(dataProvider = "oneDay")
public void testGetUpstreamMsgHour(Date date) throws WxErrorException { public void testGetUpstreamMsgHour(Date date) throws WxErrorException {
List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService() List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService()
.getUpstreamMsgHour(date, date);
.getUpstreamMsgHour(date, date);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -154,7 +145,7 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "thirtyDays") @Test(dataProvider = "thirtyDays")
public void testGetUpstreamMsgWeek(Date beginDate, Date endDate) throws WxErrorException { public void testGetUpstreamMsgWeek(Date beginDate, Date endDate) throws WxErrorException {
List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService() List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService()
.getUpstreamMsgWeek(beginDate, endDate);
.getUpstreamMsgWeek(beginDate, endDate);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -165,7 +156,7 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "thirtyDays") @Test(dataProvider = "thirtyDays")
public void testGetUpstreamMsgMonth(Date beginDate, Date endDate) throws WxErrorException { public void testGetUpstreamMsgMonth(Date beginDate, Date endDate) throws WxErrorException {
List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService() List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService()
.getUpstreamMsgMonth(beginDate, endDate);
.getUpstreamMsgMonth(beginDate, endDate);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -173,7 +164,7 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "fifteenDays") @Test(dataProvider = "fifteenDays")
public void testGetUpstreamMsgDist(Date beginDate, Date endDate) throws WxErrorException { public void testGetUpstreamMsgDist(Date beginDate, Date endDate) throws WxErrorException {
List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService() List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService()
.getUpstreamMsgDist(beginDate, endDate);
.getUpstreamMsgDist(beginDate, endDate);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -181,7 +172,7 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "thirtyDays") @Test(dataProvider = "thirtyDays")
public void testGetUpstreamMsgDistWeek(Date beginDate, Date endDate) throws WxErrorException { public void testGetUpstreamMsgDistWeek(Date beginDate, Date endDate) throws WxErrorException {
List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService() List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService()
.getUpstreamMsgDistWeek(beginDate, endDate);
.getUpstreamMsgDistWeek(beginDate, endDate);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -192,7 +183,7 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "thirtyDays") @Test(dataProvider = "thirtyDays")
public void testGetUpstreamMsgDistMonth(Date beginDate, Date endDate) throws WxErrorException { public void testGetUpstreamMsgDistMonth(Date beginDate, Date endDate) throws WxErrorException {
List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService() List<WxDataCubeMsgResult> results = this.wxService.getDataCubeService()
.getUpstreamMsgDistMonth(beginDate, endDate);
.getUpstreamMsgDistMonth(beginDate, endDate);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -200,7 +191,7 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "thirtyDays") @Test(dataProvider = "thirtyDays")
public void testGetInterfaceSummary(Date beginDate, Date endDate) throws WxErrorException { public void testGetInterfaceSummary(Date beginDate, Date endDate) throws WxErrorException {
List<WxDataCubeInterfaceResult> results = this.wxService.getDataCubeService() List<WxDataCubeInterfaceResult> results = this.wxService.getDataCubeService()
.getInterfaceSummary(beginDate, endDate);
.getInterfaceSummary(beginDate, endDate);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }
@@ -208,7 +199,7 @@ public class WxMpDataCubeServiceImplTest {
@Test(dataProvider = "oneDay") @Test(dataProvider = "oneDay")
public void testGetInterfaceSummaryHour(Date date) throws WxErrorException { public void testGetInterfaceSummaryHour(Date date) throws WxErrorException {
List<WxDataCubeInterfaceResult> results = this.wxService.getDataCubeService() List<WxDataCubeInterfaceResult> results = this.wxService.getDataCubeService()
.getInterfaceSummaryHour(date, date);
.getInterfaceSummaryHour(date, date);
Assert.assertNotNull(results); Assert.assertNotNull(results);
System.out.println(results); System.out.println(results);
} }


+ 38
- 0
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImplTest.java View File

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


import com.google.inject.Inject;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import me.chanjar.weixin.mp.bean.device.WxDeviceQrCodeResult;
import org.testng.annotations.*;

/**
* Created by keungtung on 14/12/2016.
*/
@Test(groups = "deviceApi")
@Guice(modules = ApiTestModule.class)
public class WxMpDeviceServiceImplTest {
@Inject
protected WxMpService wxService;

@Test(dataProvider = "productId")
public void testGetQrcode(String productId) {
try {
WxDeviceQrCodeResult result = wxService.getDeviceService().getQrCode(productId);
println(result.toJson());
} catch (WxErrorException e) {
println(e.getMessage());
}
}

private void println(String content) {
System.out.println(content);
}

@DataProvider(name = "productId")
public Object[][] getProductId() {
return new Object[][]{new Object[]{"25639"}};
}
}

+ 38
- 40
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImplTest.java View File

@@ -3,25 +3,23 @@ package me.chanjar.weixin.mp.api.impl;
import com.google.inject.Inject; import com.google.inject.Inject;
import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.ApiTestModule;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxXmlMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import me.chanjar.weixin.mp.api.test.TestConfigStorage;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest;
import me.chanjar.weixin.mp.bean.kefu.result.*; import me.chanjar.weixin.mp.bean.kefu.result.*;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import org.testng.*;
import org.testng.annotations.*;


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


/** /**
* 测试客服相关接口 * 测试客服相关接口
* @author Binary Wang
* *
* @author Binary Wang
*/ */
@Test @Test
@Guice(modules = ApiTestModule.class) @Guice(modules = ApiTestModule.class)
@@ -31,7 +29,7 @@ public class WxMpKefuServiceImplTest {
protected WxMpService wxService; protected WxMpService wxService;


public void testSendKefuMpNewsMessage() throws WxErrorException { public void testSendKefuMpNewsMessage() throws WxErrorException {
WxXmlMpInMemoryConfigStorage configStorage = (WxXmlMpInMemoryConfigStorage) this.wxService
TestConfigStorage configStorage = (TestConfigStorage) this.wxService
.getWxMpConfigStorage(); .getWxMpConfigStorage();
WxMpKefuMessage message = new WxMpKefuMessage(); WxMpKefuMessage message = new WxMpKefuMessage();
message.setMsgType(WxConsts.CUSTOM_MSG_MPNEWS); message.setMsgType(WxConsts.CUSTOM_MSG_MPNEWS);
@@ -42,26 +40,26 @@ public class WxMpKefuServiceImplTest {
} }


public void testSendKefuMessage() throws WxErrorException { public void testSendKefuMessage() throws WxErrorException {
WxXmlMpInMemoryConfigStorage configStorage = (WxXmlMpInMemoryConfigStorage) this.wxService
.getWxMpConfigStorage();
TestConfigStorage configStorage = (TestConfigStorage) this.wxService
.getWxMpConfigStorage();
WxMpKefuMessage message = new WxMpKefuMessage(); WxMpKefuMessage message = new WxMpKefuMessage();
message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); message.setMsgType(WxConsts.CUSTOM_MSG_TEXT);
message.setToUser(configStorage.getOpenid()); message.setToUser(configStorage.getOpenid());
message.setContent( message.setContent(
"欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");
"欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");


this.wxService.getKefuService().sendKefuMessage(message); this.wxService.getKefuService().sendKefuMessage(message);
} }


public void testSendKefuMessageWithKfAccount() throws WxErrorException { public void testSendKefuMessageWithKfAccount() throws WxErrorException {
WxXmlMpInMemoryConfigStorage configStorage = (WxXmlMpInMemoryConfigStorage) this.wxService
.getWxMpConfigStorage();
TestConfigStorage configStorage = (TestConfigStorage) this.wxService
.getWxMpConfigStorage();
WxMpKefuMessage message = new WxMpKefuMessage(); WxMpKefuMessage message = new WxMpKefuMessage();
message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); message.setMsgType(WxConsts.CUSTOM_MSG_TEXT);
message.setToUser(configStorage.getOpenid()); message.setToUser(configStorage.getOpenid());
message.setKfAccount(configStorage.getKfAccount()); message.setKfAccount(configStorage.getKfAccount());
message.setContent( message.setContent(
"欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");
"欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>");


this.wxService.getKefuService().sendKefuMessage(message); this.wxService.getKefuService().sendKefuMessage(message);
} }
@@ -76,7 +74,7 @@ public class WxMpKefuServiceImplTest {


public void testKfOnlineList() throws WxErrorException { public void testKfOnlineList() throws WxErrorException {
WxMpKfOnlineList kfOnlineList = this.wxService.getKefuService() WxMpKfOnlineList kfOnlineList = this.wxService.getKefuService()
.kfOnlineList();
.kfOnlineList();
Assert.assertNotNull(kfOnlineList); Assert.assertNotNull(kfOnlineList);
for (WxMpKfInfo k : kfOnlineList.getKfOnlineList()) { for (WxMpKfInfo k : kfOnlineList.getKfOnlineList()) {
System.err.println(k); System.err.println(k);
@@ -85,41 +83,41 @@ public class WxMpKefuServiceImplTest {


@DataProvider @DataProvider
public Object[][] getKfAccount() { public Object[][] getKfAccount() {
WxXmlMpInMemoryConfigStorage configStorage = (WxXmlMpInMemoryConfigStorage) this.wxService
.getWxMpConfigStorage();
return new Object[][] { { configStorage.getKfAccount() } };
TestConfigStorage configStorage = (TestConfigStorage) this.wxService
.getWxMpConfigStorage();
return new Object[][]{{configStorage.getKfAccount()}};
} }


@Test(dataProvider = "getKfAccount") @Test(dataProvider = "getKfAccount")
public void testKfAccountAdd(String kfAccount) throws WxErrorException { public void testKfAccountAdd(String kfAccount) throws WxErrorException {
WxMpKfAccountRequest request = WxMpKfAccountRequest.builder() WxMpKfAccountRequest request = WxMpKfAccountRequest.builder()
.kfAccount(kfAccount).nickName("我晕").build();
.kfAccount(kfAccount).nickName("我晕").build();
Assert.assertTrue(this.wxService.getKefuService().kfAccountAdd(request)); Assert.assertTrue(this.wxService.getKefuService().kfAccountAdd(request));
} }


@Test(dependsOnMethods = { @Test(dependsOnMethods = {
"testKfAccountAdd" }, dataProvider = "getKfAccount")
"testKfAccountAdd"}, dataProvider = "getKfAccount")
public void testKfAccountUpdate(String kfAccount) throws WxErrorException { public void testKfAccountUpdate(String kfAccount) throws WxErrorException {
WxMpKfAccountRequest request = WxMpKfAccountRequest.builder() WxMpKfAccountRequest request = WxMpKfAccountRequest.builder()
.kfAccount(kfAccount).nickName("我晕").build();
.kfAccount(kfAccount).nickName("我晕").build();
Assert.assertTrue(this.wxService.getKefuService().kfAccountUpdate(request)); Assert.assertTrue(this.wxService.getKefuService().kfAccountUpdate(request));
} }


@Test(dependsOnMethods = { @Test(dependsOnMethods = {
"testKfAccountAdd" }, dataProvider = "getKfAccount")
"testKfAccountAdd"}, dataProvider = "getKfAccount")
public void testKfAccountInviteWorker(String kfAccount) throws WxErrorException { public void testKfAccountInviteWorker(String kfAccount) throws WxErrorException {
WxMpKfAccountRequest request = WxMpKfAccountRequest.builder() WxMpKfAccountRequest request = WxMpKfAccountRequest.builder()
.kfAccount(kfAccount).inviteWx(" ").build();
.kfAccount(kfAccount).inviteWx(" ").build();
Assert.assertTrue(this.wxService.getKefuService().kfAccountInviteWorker(request)); Assert.assertTrue(this.wxService.getKefuService().kfAccountInviteWorker(request));
} }


@Test(dependsOnMethods = { @Test(dependsOnMethods = {
"testKfAccountUpdate" }, dataProvider = "getKfAccount")
"testKfAccountUpdate"}, dataProvider = "getKfAccount")
public void testKfAccountUploadHeadImg(String kfAccount) public void testKfAccountUploadHeadImg(String kfAccount)
throws WxErrorException {
throws WxErrorException {
File imgFile = new File("src\\test\\resources\\mm.jpeg"); File imgFile = new File("src\\test\\resources\\mm.jpeg");
boolean result = this.wxService.getKefuService() boolean result = this.wxService.getKefuService()
.kfAccountUploadHeadImg(kfAccount, imgFile);
.kfAccountUploadHeadImg(kfAccount, imgFile);
Assert.assertTrue(result); Assert.assertTrue(result);
} }


@@ -131,33 +129,33 @@ public class WxMpKefuServiceImplTest {


@DataProvider @DataProvider
public Object[][] getKfAccountAndOpenid() { public Object[][] getKfAccountAndOpenid() {
WxXmlMpInMemoryConfigStorage configStorage = (WxXmlMpInMemoryConfigStorage) this.wxService
.getWxMpConfigStorage();
return new Object[][] {
{ configStorage.getKfAccount(), configStorage.getOpenid() } };
TestConfigStorage configStorage = (TestConfigStorage) this.wxService
.getWxMpConfigStorage();
return new Object[][]{
{configStorage.getKfAccount(), configStorage.getOpenid()}};
} }


@Test(dataProvider = "getKfAccountAndOpenid") @Test(dataProvider = "getKfAccountAndOpenid")
public void testKfSessionCreate(String kfAccount, String openid) public void testKfSessionCreate(String kfAccount, String openid)
throws WxErrorException {
throws WxErrorException {
boolean result = this.wxService.getKefuService().kfSessionCreate(openid, boolean result = this.wxService.getKefuService().kfSessionCreate(openid,
kfAccount);
kfAccount);
Assert.assertTrue(result); Assert.assertTrue(result);
} }


@Test(dataProvider = "getKfAccountAndOpenid") @Test(dataProvider = "getKfAccountAndOpenid")
public void testKfSessionClose(String kfAccount, String openid) public void testKfSessionClose(String kfAccount, String openid)
throws WxErrorException {
throws WxErrorException {
boolean result = this.wxService.getKefuService().kfSessionClose(openid, boolean result = this.wxService.getKefuService().kfSessionClose(openid,
kfAccount);
kfAccount);
Assert.assertTrue(result); Assert.assertTrue(result);
} }


@Test(dataProvider = "getKfAccountAndOpenid") @Test(dataProvider = "getKfAccountAndOpenid")
public void testKfSessionGet(@SuppressWarnings("unused") String kfAccount, public void testKfSessionGet(@SuppressWarnings("unused") String kfAccount,
String openid) throws WxErrorException {
String openid) throws WxErrorException {
WxMpKfSessionGetResult result = this.wxService.getKefuService() WxMpKfSessionGetResult result = this.wxService.getKefuService()
.kfSessionGet(openid);
.kfSessionGet(openid);
Assert.assertNotNull(result); Assert.assertNotNull(result);
System.err.println(result); System.err.println(result);
} }
@@ -165,7 +163,7 @@ public class WxMpKefuServiceImplTest {
@Test(dataProvider = "getKfAccount") @Test(dataProvider = "getKfAccount")
public void testKfSessionList(String kfAccount) throws WxErrorException { public void testKfSessionList(String kfAccount) throws WxErrorException {
WxMpKfSessionList result = this.wxService.getKefuService() WxMpKfSessionList result = this.wxService.getKefuService()
.kfSessionList(kfAccount);
.kfSessionList(kfAccount);
Assert.assertNotNull(result); Assert.assertNotNull(result);
System.err.println(result); System.err.println(result);
} }
@@ -173,7 +171,7 @@ public class WxMpKefuServiceImplTest {
@Test @Test
public void testKfSessionGetWaitCase() throws WxErrorException { public void testKfSessionGetWaitCase() throws WxErrorException {
WxMpKfSessionWaitCaseList result = this.wxService.getKefuService() WxMpKfSessionWaitCaseList result = this.wxService.getKefuService()
.kfSessionGetWaitCase();
.kfSessionGetWaitCase();
Assert.assertNotNull(result); Assert.assertNotNull(result);
System.err.println(result); System.err.println(result);
} }
@@ -182,7 +180,7 @@ public class WxMpKefuServiceImplTest {
public void testKfMsgList() throws WxErrorException { public void testKfMsgList() throws WxErrorException {
Date startTime = DateTime.now().minusDays(1).toDate(); Date startTime = DateTime.now().minusDays(1).toDate();
Date endTime = DateTime.now().minusDays(0).toDate(); Date endTime = DateTime.now().minusDays(0).toDate();
WxMpKfMsgList result = this.wxService.getKefuService().kfMsgList(startTime,endTime, 1L, 50);
WxMpKfMsgList result = this.wxService.getKefuService().kfMsgList(startTime, endTime, 1L, 50);
Assert.assertNotNull(result); Assert.assertNotNull(result);
System.err.println(result); System.err.println(result);
} }
@@ -191,7 +189,7 @@ public class WxMpKefuServiceImplTest {
public void testKfMsgListAll() throws WxErrorException { public void testKfMsgListAll() throws WxErrorException {
Date startTime = DateTime.now().minusDays(1).toDate(); Date startTime = DateTime.now().minusDays(1).toDate();
Date endTime = DateTime.now().minusDays(0).toDate(); Date endTime = DateTime.now().minusDays(0).toDate();
WxMpKfMsgList result = this.wxService.getKefuService().kfMsgList(startTime,endTime);
WxMpKfMsgList result = this.wxService.getKefuService().kfMsgList(startTime, endTime);
Assert.assertNotNull(result); Assert.assertNotNull(result);
System.err.println(result); System.err.println(result);
} }


+ 34
- 40
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java View File

@@ -5,15 +5,10 @@ import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.fs.FileUtils; import me.chanjar.weixin.common.util.fs.FileUtils;
import me.chanjar.weixin.mp.api.ApiTestModule;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.material.WxMpMaterial;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialArticleUpdate;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import me.chanjar.weixin.mp.bean.material.*; import me.chanjar.weixin.mp.bean.material.*;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import org.testng.annotations.*;


import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -44,14 +39,16 @@ public class WxMpMaterialServiceImplTest {
private String multiNewsMediaId = ""; private String multiNewsMediaId = "";
// 先查询保存测试开始前永久素材数据 // 先查询保存测试开始前永久素材数据
private WxMpMaterialCountResult wxMaterialCountResultBeforeTest; private WxMpMaterialCountResult wxMaterialCountResultBeforeTest;
// 以下为media接口的测试
private List<String> mediaIdsToDownload = new ArrayList<>();


@DataProvider @DataProvider
public Object[][] mediaFiles() { public Object[][] mediaFiles() {
return new Object[][] {
new Object[] { WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, "mm.jpeg" },
new Object[] { WxConsts.MEDIA_VOICE, WxConsts.FILE_MP3, "mm.mp3" },
new Object[] { WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, "mm.mp4" },
new Object[] { WxConsts.MEDIA_THUMB, WxConsts.FILE_JPG, "mm.jpeg" }
return new Object[][]{
new Object[]{WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, "mm.jpeg"},
new Object[]{WxConsts.MEDIA_VOICE, WxConsts.FILE_MP3, "mm.mp3"},
new Object[]{WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, "mm.mp4"},
new Object[]{WxConsts.MEDIA_THUMB, WxConsts.FILE_JPG, "mm.jpeg"}
}; };
} }


@@ -59,13 +56,13 @@ public class WxMpMaterialServiceImplTest {
public void testUploadMaterial(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { public void testUploadMaterial(String mediaType, String fileType, String fileName) throws WxErrorException, IOException {
if (this.wxMaterialCountResultBeforeTest == null) { if (this.wxMaterialCountResultBeforeTest == null) {
this.wxMaterialCountResultBeforeTest = this.wxService.getMaterialService() this.wxMaterialCountResultBeforeTest = this.wxService.getMaterialService()
.materialCount();
.materialCount();
} }


try (InputStream inputStream = ClassLoader try (InputStream inputStream = ClassLoader
.getSystemResourceAsStream(fileName)) {
.getSystemResourceAsStream(fileName)) {
File tempFile = FileUtils.createTmpFile(inputStream, File tempFile = FileUtils.createTmpFile(inputStream,
UUID.randomUUID().toString(), fileType);
UUID.randomUUID().toString(), fileType);
WxMpMaterial wxMaterial = new WxMpMaterial(); WxMpMaterial wxMaterial = new WxMpMaterial();
wxMaterial.setFile(tempFile); wxMaterial.setFile(tempFile);
wxMaterial.setName(fileName); wxMaterial.setName(fileName);
@@ -75,11 +72,11 @@ public class WxMpMaterialServiceImplTest {
} }


WxMpMaterialUploadResult res = this.wxService.getMaterialService() WxMpMaterialUploadResult res = this.wxService.getMaterialService()
.materialFileUpload(mediaType, wxMaterial);
.materialFileUpload(mediaType, wxMaterial);
assertNotNull(res.getMediaId()); assertNotNull(res.getMediaId());


if (WxConsts.MEDIA_IMAGE.equals(mediaType) if (WxConsts.MEDIA_IMAGE.equals(mediaType)
|| WxConsts.MEDIA_THUMB.equals(mediaType)) {
|| WxConsts.MEDIA_THUMB.equals(mediaType)) {
assertNotNull(res.getUrl()); assertNotNull(res.getUrl());
} }


@@ -145,16 +142,16 @@ public class WxMpMaterialServiceImplTest {
WxMpMaterialCountResult wxMaterialCountResult = this.wxService.getMaterialService().materialCount(); WxMpMaterialCountResult wxMaterialCountResult = this.wxService.getMaterialService().materialCount();
// 测试上传过程中添加了一个音频,一个视频,两个图片,两个图文消息 // 测试上传过程中添加了一个音频,一个视频,两个图片,两个图文消息
assertEquals( assertEquals(
this.wxMaterialCountResultBeforeTest.getVoiceCount() + 1,
wxMaterialCountResult.getVoiceCount());
this.wxMaterialCountResultBeforeTest.getVoiceCount() + 1,
wxMaterialCountResult.getVoiceCount());
assertEquals( assertEquals(
this.wxMaterialCountResultBeforeTest.getVideoCount() + 1,
wxMaterialCountResult.getVideoCount());
this.wxMaterialCountResultBeforeTest.getVideoCount() + 1,
wxMaterialCountResult.getVideoCount());
assertEquals( assertEquals(
this.wxMaterialCountResultBeforeTest.getImageCount() + 2,
wxMaterialCountResult.getImageCount());
this.wxMaterialCountResultBeforeTest.getImageCount() + 2,
wxMaterialCountResult.getImageCount());
assertEquals(this.wxMaterialCountResultBeforeTest.getNewsCount() + 2, assertEquals(this.wxMaterialCountResultBeforeTest.getNewsCount() + 2,
wxMaterialCountResult.getNewsCount());
wxMaterialCountResult.getNewsCount());
} }


@Test(dependsOnMethods = {"testMaterialCount"}, dataProvider = "downloadMaterial") @Test(dependsOnMethods = {"testMaterialCount"}, dataProvider = "downloadMaterial")
@@ -164,7 +161,7 @@ public class WxMpMaterialServiceImplTest {
String filename = materialInfo.get("filename").toString(); String filename = materialInfo.get("filename").toString();
if (filename.endsWith(".mp3") || filename.endsWith(".jpeg")) { if (filename.endsWith(".mp3") || filename.endsWith(".jpeg")) {
try (InputStream inputStream = this.wxService.getMaterialService() try (InputStream inputStream = this.wxService.getMaterialService()
.materialImageOrVoiceDownload(mediaId)) {
.materialImageOrVoiceDownload(mediaId)) {
assertNotNull(inputStream); assertNotNull(inputStream);
} }
} }
@@ -178,9 +175,9 @@ public class WxMpMaterialServiceImplTest {
@Test(dependsOnMethods = {"testAddNews"}) @Test(dependsOnMethods = {"testAddNews"})
public void testGetNewsInfo() throws WxErrorException { public void testGetNewsInfo() throws WxErrorException {
WxMpMaterialNews wxMpMaterialNewsSingle = this.wxService WxMpMaterialNews wxMpMaterialNewsSingle = this.wxService
.getMaterialService().materialNewsInfo(this.singleNewsMediaId);
.getMaterialService().materialNewsInfo(this.singleNewsMediaId);
WxMpMaterialNews wxMpMaterialNewsMultiple = this.wxService WxMpMaterialNews wxMpMaterialNewsMultiple = this.wxService
.getMaterialService().materialNewsInfo(this.multiNewsMediaId);
.getMaterialService().materialNewsInfo(this.multiNewsMediaId);
assertNotNull(wxMpMaterialNewsSingle); assertNotNull(wxMpMaterialNewsSingle);
assertNotNull(wxMpMaterialNewsMultiple); assertNotNull(wxMpMaterialNewsMultiple);
} }
@@ -188,7 +185,7 @@ public class WxMpMaterialServiceImplTest {
@Test(dependsOnMethods = {"testGetNewsInfo"}) @Test(dependsOnMethods = {"testGetNewsInfo"})
public void testUpdateNewsInfo() throws WxErrorException { public void testUpdateNewsInfo() throws WxErrorException {
WxMpMaterialNews wxMpMaterialNewsSingle = this.wxService WxMpMaterialNews wxMpMaterialNewsSingle = this.wxService
.getMaterialService().materialNewsInfo(this.singleNewsMediaId);
.getMaterialService().materialNewsInfo(this.singleNewsMediaId);
assertNotNull(wxMpMaterialNewsSingle); assertNotNull(wxMpMaterialNewsSingle);
WxMpMaterialArticleUpdate wxMpMaterialArticleUpdateSingle = new WxMpMaterialArticleUpdate(); WxMpMaterialArticleUpdate wxMpMaterialArticleUpdateSingle = new WxMpMaterialArticleUpdate();
WxMpMaterialNews.WxMpMaterialNewsArticle articleSingle = wxMpMaterialNewsSingle.getArticles().get(0); WxMpMaterialNews.WxMpMaterialNewsArticle articleSingle = wxMpMaterialNewsSingle.getArticles().get(0);
@@ -199,13 +196,13 @@ public class WxMpMaterialServiceImplTest {
boolean resultSingle = this.wxService.getMaterialService().materialNewsUpdate(wxMpMaterialArticleUpdateSingle); boolean resultSingle = this.wxService.getMaterialService().materialNewsUpdate(wxMpMaterialArticleUpdateSingle);
assertTrue(resultSingle); assertTrue(resultSingle);
wxMpMaterialNewsSingle = this.wxService.getMaterialService() wxMpMaterialNewsSingle = this.wxService.getMaterialService()
.materialNewsInfo(this.singleNewsMediaId);
.materialNewsInfo(this.singleNewsMediaId);
assertNotNull(wxMpMaterialNewsSingle); assertNotNull(wxMpMaterialNewsSingle);
assertEquals("content single update", assertEquals("content single update",
wxMpMaterialNewsSingle.getArticles().get(0).getContent());
wxMpMaterialNewsSingle.getArticles().get(0).getContent());


WxMpMaterialNews wxMpMaterialNewsMultiple = this.wxService WxMpMaterialNews wxMpMaterialNewsMultiple = this.wxService
.getMaterialService().materialNewsInfo(this.multiNewsMediaId);
.getMaterialService().materialNewsInfo(this.multiNewsMediaId);
assertNotNull(wxMpMaterialNewsMultiple); assertNotNull(wxMpMaterialNewsMultiple);
WxMpMaterialArticleUpdate wxMpMaterialArticleUpdateMulti = new WxMpMaterialArticleUpdate(); WxMpMaterialArticleUpdate wxMpMaterialArticleUpdateMulti = new WxMpMaterialArticleUpdate();
WxMpMaterialNews.WxMpMaterialNewsArticle articleMulti = wxMpMaterialNewsMultiple.getArticles().get(1); WxMpMaterialNews.WxMpMaterialNewsArticle articleMulti = wxMpMaterialNewsMultiple.getArticles().get(1);
@@ -216,10 +213,10 @@ public class WxMpMaterialServiceImplTest {
boolean resultMulti = this.wxService.getMaterialService().materialNewsUpdate(wxMpMaterialArticleUpdateMulti); boolean resultMulti = this.wxService.getMaterialService().materialNewsUpdate(wxMpMaterialArticleUpdateMulti);
assertTrue(resultMulti); assertTrue(resultMulti);
wxMpMaterialNewsMultiple = this.wxService.getMaterialService() wxMpMaterialNewsMultiple = this.wxService.getMaterialService()
.materialNewsInfo(this.multiNewsMediaId);
.materialNewsInfo(this.multiNewsMediaId);
assertNotNull(wxMpMaterialNewsMultiple); assertNotNull(wxMpMaterialNewsMultiple);
assertEquals("content 2 update", assertEquals("content 2 update",
wxMpMaterialNewsMultiple.getArticles().get(1).getContent());
wxMpMaterialNewsMultiple.getArticles().get(1).getContent());
} }


@Test(dependsOnMethods = {"testUpdateNewsInfo"}) @Test(dependsOnMethods = {"testUpdateNewsInfo"})
@@ -266,12 +263,9 @@ public class WxMpMaterialServiceImplTest {
return params.iterator(); return params.iterator();
} }


// 以下为media接口的测试
private List<String> mediaIdsToDownload = new ArrayList<>();

@Test(dataProvider="mediaFiles")
@Test(dataProvider = "mediaFiles")
public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException {
try(InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)){
try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)) {
WxMediaUploadResult res = this.wxService.getMaterialService().mediaUpload(mediaType, fileType, inputStream); WxMediaUploadResult res = this.wxService.getMaterialService().mediaUpload(mediaType, fileType, inputStream);
assertNotNull(res.getType()); assertNotNull(res.getType());
assertNotNull(res.getCreatedAt()); assertNotNull(res.getCreatedAt());
@@ -294,12 +288,12 @@ public class WxMpMaterialServiceImplTest {
public Object[][] downloadMedia() { public Object[][] downloadMedia() {
Object[][] params = new Object[this.mediaIdsToDownload.size()][]; Object[][] params = new Object[this.mediaIdsToDownload.size()][];
for (int i = 0; i < this.mediaIdsToDownload.size(); i++) { for (int i = 0; i < this.mediaIdsToDownload.size(); i++) {
params[i] = new Object[] { this.mediaIdsToDownload.get(i) };
params[i] = new Object[]{this.mediaIdsToDownload.get(i)};
} }
return params; return params;
} }


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


+ 100
- 51
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImplTest.java View File

@@ -5,26 +5,26 @@ import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.bean.menu.WxMenuButton; import me.chanjar.weixin.common.bean.menu.WxMenuButton;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.ApiTestModule;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult; import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
import org.testng.*;
import org.testng.annotations.*;


/** /**
* 测试菜单 * 测试菜单
*
* @author chanjarster * @author chanjarster
* @author Binary Wang * @author Binary Wang
*
*/ */
@Test(groups="menuAPI")
@Test(groups = "menuAPI")
@Guice(modules = ApiTestModule.class) @Guice(modules = ApiTestModule.class)
public class WxMpMenuServiceImplTest { public class WxMpMenuServiceImplTest {


@Inject @Inject
protected WxMpService wxService; protected WxMpService wxService;
private String menuId = null;


@Test(dataProvider = "menu") @Test(dataProvider = "menu")
public void testMenuCreate(WxMenu wxMenu) throws WxErrorException { public void testMenuCreate(WxMenu wxMenu) throws WxErrorException {
@@ -34,7 +34,8 @@ public class WxMpMenuServiceImplTest {


@Test @Test
public void testMenuTryMatch() throws Exception { public void testMenuTryMatch() throws Exception {
//TODO
WxMenu menu = this.wxService.getMenuService().menuTryMatch("...");
System.out.println(menu);
} }


@Test @Test
@@ -43,63 +44,111 @@ public class WxMpMenuServiceImplTest {
System.out.println(selfMenuInfo); System.out.println(selfMenuInfo);
} }


@Test
public void testCreateConditionalMenu() throws WxErrorException {
String json = "{\n" +
" \"button\":[\n" +
" { \n" +
" \"type\":\"click\",\n" +
" \"name\":\"今日歌曲\",\n" +
" \"key\":\"V1001_TODAY_MUSIC\" \n" +
" },\n" +
" { \n" +
" \"name\":\"菜单\",\n" +
" \"sub_button\":[\n" +
" { \n" +
" \"type\":\"view\",\n" +
" \"name\":\"搜索\",\n" +
" \"url\":\"http://www.soso.com/\"\n" +
" },\n" +
" {\n" +
" \"type\":\"view\",\n" +
" \"name\":\"视频\",\n" +
" \"url\":\"http://v.qq.com/\"\n" +
" },\n" +
" {\n" +
" \"type\":\"click\",\n" +
" \"name\":\"赞一下我们\",\n" +
" \"key\":\"V1001_GOOD\"\n" +
" }]\n" +
" }],\n" +
"\"matchrule\":{\n" +
" \"tag_id\":\"2\",\n" +
" \"sex\":\"1\",\n" +
" \"country\":\"中国\",\n" +
" \"province\":\"广东\",\n" +
" \"city\":\"广州\",\n" +
" \"client_platform_type\":\"2\",\n" +
" \"language\":\"zh_CN\"\n" +
" }\n" +
"}";

this.menuId = this.wxService.getMenuService().menuCreate(json);
System.out.println(this.menuId);
}

@Test(dependsOnMethods = {"testCreateConditionalMenu"})
public void testDeleteConditionalMenu() throws WxErrorException {
this.wxService.getMenuService().menuDelete(menuId);
}

@Test @Test
public void testCreateMenu2() throws WxErrorException { public void testCreateMenu2() throws WxErrorException {
String a = "{\n" String a = "{\n"
+ " \"menu\": {\n"
+ " \"button\": [\n"
+ " {\n"
+ " \"type\": \"click\",\n"
+ " \"name\": \"今日歌曲\",\n"
+ " \"key\": \"V1001_TODAY_MUSIC\"\n"
+ " },\n"
+ " {\n"
+ " \"type\": \"click\",\n"
+ " \"name\": \"歌手简介\",\n"
+ " \"key\": \"V1001_TODAY_SINGER\"\n"
+ " },\n"
+ " {\n"
+ " \"name\": \"菜单\",\n"
+ " \"sub_button\": [\n"
+ " {\n"
+ " \"type\": \"view\",\n"
+ " \"name\": \"搜索\",\n"
+ " \"url\": \"http://www.soso.com/\"\n"
+ " },\n"
+ " {\n"
+ " \"type\": \"view\",\n"
+ " \"name\": \"视频\",\n"
+ " \"url\": \"http://v.qq.com/\"\n"
+ " },\n"
+ " {\n"
+ " \"type\": \"click\",\n"
+ " \"name\": \"赞一下我们\",\n"
+ " \"key\": \"V1001_GOOD\"\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ "}";
+ " \"menu\": {\n"
+ " \"button\": [\n"
+ " {\n"
+ " \"type\": \"click\",\n"
+ " \"name\": \"今日歌曲\",\n"
+ " \"key\": \"V1001_TODAY_MUSIC\"\n"
+ " },\n"
+ " {\n"
+ " \"type\": \"click\",\n"
+ " \"name\": \"歌手简介\",\n"
+ " \"key\": \"V1001_TODAY_SINGER\"\n"
+ " },\n"
+ " {\n"
+ " \"name\": \"菜单\",\n"
+ " \"sub_button\": [\n"
+ " {\n"
+ " \"type\": \"view\",\n"
+ " \"name\": \"搜索\",\n"
+ " \"url\": \"http://www.soso.com/\"\n"
+ " },\n"
+ " {\n"
+ " \"type\": \"view\",\n"
+ " \"name\": \"视频\",\n"
+ " \"url\": \"http://v.qq.com/\"\n"
+ " },\n"
+ " {\n"
+ " \"type\": \"click\",\n"
+ " \"name\": \"赞一下我们\",\n"
+ " \"key\": \"V1001_GOOD\"\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ "}";


WxMenu menu = WxMenu.fromJson(a); WxMenu menu = WxMenu.fromJson(a);
System.out.println(menu.toJson()); System.out.println(menu.toJson());
this.wxService.getMenuService().menuCreate(menu); this.wxService.getMenuService().menuCreate(menu);
} }


@Test(dependsOnMethods = { "testMenuCreate"})
@Test(dependsOnMethods = {"testMenuCreate"})
public void testMenuGet() throws WxErrorException { public void testMenuGet() throws WxErrorException {
WxMenu wxMenu = this.wxService.getMenuService().menuGet();
WxMpMenu wxMenu = this.wxService.getMenuService().menuGet();
Assert.assertNotNull(wxMenu); Assert.assertNotNull(wxMenu);
System.out.println(wxMenu.toJson()); System.out.println(wxMenu.toJson());
} }


@Test(dependsOnMethods = { "testMenuGet"})
@Test(dependsOnMethods = {"testMenuGet"})
public void testMenuDelete() throws WxErrorException { public void testMenuDelete() throws WxErrorException {
this.wxService.getMenuService().menuDelete(); this.wxService.getMenuService().menuDelete();
} }


@DataProvider(name="menu")
@DataProvider(name = "menu")
public Object[][] getMenu() { public Object[][] getMenu() {
WxMenu menu = new WxMenu(); WxMenu menu = new WxMenu();
WxMenuButton button1 = new WxMenuButton(); WxMenuButton button1 = new WxMenuButton();
@@ -138,10 +187,10 @@ public class WxMpMenuServiceImplTest {
button3.getSubButtons().add(button32); button3.getSubButtons().add(button32);
button3.getSubButtons().add(button33); button3.getSubButtons().add(button33);


return new Object[][] {
new Object[] {
menu
}
return new Object[][]{
new Object[]{
menu
}
}; };


} }


+ 82
- 35
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java View File

@@ -1,19 +1,20 @@
package me.chanjar.weixin.mp.api.impl; package me.chanjar.weixin.mp.api.impl;


import com.github.binarywang.utils.qrcode.QrcodeUtils;
import com.google.inject.Inject; import com.google.inject.Inject;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.ApiTestModule;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxXmlMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.bean.pay.request.WxEntPayRequest;
import me.chanjar.weixin.mp.bean.pay.request.WxPayRefundRequest;
import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest;
import me.chanjar.weixin.mp.bean.pay.request.WxPayUnifiedOrderRequest;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import me.chanjar.weixin.mp.api.test.TestConfigStorage;
import me.chanjar.weixin.mp.bean.pay.request.*;
import me.chanjar.weixin.mp.bean.pay.result.*; import me.chanjar.weixin.mp.bean.pay.result.*;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import org.testng.annotations.*;


import java.io.File; import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.testng.Assert.*;


/** /**
* 测试支付相关接口 * 测试支付相关接口
@@ -33,28 +34,58 @@ public class WxMpPayServiceImplTest {


} }


@Test
public void testDownloadBill() throws Exception {
File file = this.wxService.getPayService().downloadBill("20170101", "ALL", "GZIP", "1111111");
assertNotNull(file);
//必填字段为空时,抛出异常
this.wxService.getPayService().downloadBill("", "", "", null);
}

@Test
public void testReport() throws Exception {
WxPayReportRequest request = new WxPayReportRequest();
request.setInterfaceUrl("hahahah");
request.setSignType("HMAC-SHA256");//貌似接口未校验此字段
request.setExecuteTime(1000);
request.setReturnCode("aaa");
request.setResultCode("aaa");
request.setUserIp("8.8.8");
this.wxService.getPayService().report(request);
}

/** /**
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#refund(WxPayRefundRequest, File)} .
* 需要证书的接口需要先执行该方法
*/ */
@Test @Test
public void setSSLKey() {
TestConfigStorage config = (TestConfigStorage) this.wxService.getWxMpConfigStorage();
config.setSslContextFilePath(config.getKeyPath());
}

/**
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#refund(WxPayRefundRequest)} .
*/
@Test(dependsOnMethods = {"setSSLKey"})
public void testRefund() throws Exception { public void testRefund() throws Exception {
WxPayRefundRequest request = new WxPayRefundRequest(); WxPayRefundRequest request = new WxPayRefundRequest();
request.setOutRefundNo("aaa"); request.setOutRefundNo("aaa");
request.setOutTradeNo("1111"); request.setOutTradeNo("1111");
request.setTotalFee(1222); request.setTotalFee(1222);
request.setRefundFee(111); request.setRefundFee(111);
File keyFile = new File("E:\\dlt.p12");
WxPayRefundResult result = this.wxService.getPayService().refund(request, keyFile);
WxPayRefundResult result = this.wxService.getPayService().refund(request);
System.err.println(result); System.err.println(result);
} }



/** /**
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#refundQuery(String, String, String, String)} . * Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#refundQuery(String, String, String, String)} .
*/ */
@Test @Test
public void testRefundQuery() throws Exception { public void testRefundQuery() throws Exception {
WxPayRefundQueryResult result = this.wxService.getPayService().refundQuery("1", "", "", "");
WxPayRefundQueryResult result;

result = this.wxService.getPayService().refundQuery("1", "", "", "");
System.err.println(result);
result = this.wxService.getPayService().refundQuery("", "2", "", ""); result = this.wxService.getPayService().refundQuery("", "2", "", "");
System.err.println(result); System.err.println(result);
result = this.wxService.getPayService().refundQuery("", "", "3", ""); result = this.wxService.getPayService().refundQuery("", "", "3", "");
@@ -66,34 +97,27 @@ public class WxMpPayServiceImplTest {
System.err.println(result); System.err.println(result);
} }


@Test
public void testCheckJSSDKCallbackDataSignature() throws Exception {

}

/** /**
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#sendRedpack(WxPaySendRedpackRequest, File)} .
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#sendRedpack(WxPaySendRedpackRequest)} .
*/ */
@Test
@Test(dependsOnMethods = {"setSSLKey"})
public void testSendRedpack() throws Exception { public void testSendRedpack() throws Exception {
WxPaySendRedpackRequest request = new WxPaySendRedpackRequest(); WxPaySendRedpackRequest request = new WxPaySendRedpackRequest();
request.setActName("abc"); request.setActName("abc");
request.setClientIp("aaa"); request.setClientIp("aaa");
request.setMchBillNo("aaaa"); request.setMchBillNo("aaaa");
request request
.setReOpenid(((WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage()).getOpenid());
File keyFile = new File("E:\\dlt.p12");
WxPaySendRedpackResult redpackResult = this.wxService.getPayService().sendRedpack(request, keyFile);
.setReOpenid(((TestConfigStorage) this.wxService.getWxMpConfigStorage()).getOpenid());
WxPaySendRedpackResult redpackResult = this.wxService.getPayService().sendRedpack(request);
System.err.println(redpackResult); System.err.println(redpackResult);
} }


/** /**
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#queryRedpack(String, File)}.
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#queryRedpack(String)}.
*/ */
@Test
@Test(dependsOnMethods = {"setSSLKey"})
public void testQueryRedpack() throws Exception { public void testQueryRedpack() throws Exception {
File keyFile = new File("E:\\dlt.p12");
WxPayRedpackQueryResult redpackResult = this.wxService.getPayService().queryRedpack("aaaa", keyFile);
WxPayRedpackQueryResult redpackResult = this.wxService.getPayService().queryRedpack("aaaa");
System.err.println(redpackResult); System.err.println(redpackResult);
} }


@@ -128,21 +152,44 @@ public class WxMpPayServiceImplTest {
} }


/** /**
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#entPay(WxEntPayRequest, File)}.
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#entPay(WxEntPayRequest)}.
*/ */
@Test
@Test(dependsOnMethods = {"setSSLKey"})
public final void testEntPay() throws WxErrorException { public final void testEntPay() throws WxErrorException {
File keyFile = new File("E:\\dlt.p12");
WxEntPayRequest request = new WxEntPayRequest(); WxEntPayRequest request = new WxEntPayRequest();
System.err.println(this.wxService.getPayService().entPay(request, keyFile));
System.err.println(this.wxService.getPayService().entPay(request));
} }


/** /**
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#queryEntPay(String, File)}.
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#queryEntPay(String)}.
*/ */
@Test
@Test(dependsOnMethods = {"setSSLKey"})
public final void testQueryEntPay() throws WxErrorException { public final void testQueryEntPay() throws WxErrorException {
File keyFile = new File("E:\\dlt.p12");
System.err.println(this.wxService.getPayService().queryEntPay("11212121", keyFile));
System.err.println(this.wxService.getPayService().queryEntPay("11212121"));
} }

@Test
public void testCreateScanPayQrcodeMode1() throws Exception {
String productId = "abc";
byte[] bytes = this.wxService.getPayService().createScanPayQrcodeMode1(productId, null, null);
Path qrcodeFilePath = Files.createTempFile("qrcode_", ".jpg");
Files.write(qrcodeFilePath, bytes);
String qrcodeContent = QrcodeUtils.decodeQrcode(qrcodeFilePath.toFile());
System.out.println(qrcodeContent);

assertTrue(qrcodeContent.startsWith("weixin://wxpay/bizpayurl?"));
assertTrue(qrcodeContent.contains("product_id=" + productId));
}

@Test
public void testCreateScanPayQrcodeMode2() throws Exception {
String qrcodeContent = "abc";
byte[] bytes = this.wxService.getPayService().createScanPayQrcodeMode2(qrcodeContent, null, null);
Path qrcodeFilePath = Files.createTempFile("qrcode_", ".jpg");
Files.write(qrcodeFilePath, bytes);

assertEquals(QrcodeUtils.decodeQrcode(qrcodeFilePath.toFile()), qrcodeContent);
}


} }

weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpQrCodeServiceImplTest.java → weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImplTest.java View File

@@ -2,12 +2,11 @@ package me.chanjar.weixin.mp.api.impl;


import com.google.inject.Inject; import com.google.inject.Inject;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.ApiTestModule;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import org.testng.*;
import org.testng.annotations.*;


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


@@ -18,21 +17,27 @@ import java.io.File;
*/ */
@Test(groups = "qrCodeAPI") @Test(groups = "qrCodeAPI")
@Guice(modules = ApiTestModule.class) @Guice(modules = ApiTestModule.class)
public class WxMpQrCodeServiceImplTest {

public class WxMpQrcodeServiceImplTest {
@Inject @Inject
protected WxMpService wxService; protected WxMpService wxService;


public void testQrCodeCreateTmpTicket() throws WxErrorException {
WxMpQrCodeTicket ticket = this.wxService.getQrcodeService().qrCodeCreateTmpTicket(1, null);
@DataProvider
public Object[][] sceneIds() {
return new Object[][]{{-1}, {0}, {1}, {200000}};
}

@Test(dataProvider = "sceneIds")
public void testQrCodeCreateTmpTicket(int sceneId) throws WxErrorException {
WxMpQrCodeTicket ticket = this.wxService.getQrcodeService().qrCodeCreateTmpTicket(sceneId, null);
Assert.assertNotNull(ticket.getUrl()); Assert.assertNotNull(ticket.getUrl());
Assert.assertNotNull(ticket.getTicket()); Assert.assertNotNull(ticket.getTicket());
Assert.assertTrue(ticket.getExpire_seconds() != -1); Assert.assertTrue(ticket.getExpire_seconds() != -1);
System.out.println(ticket); System.out.println(ticket);
} }


public void testQrCodeCreateLastTicket() throws WxErrorException {
WxMpQrCodeTicket ticket = this.wxService.getQrcodeService().qrCodeCreateLastTicket(1);
@Test(dataProvider = "sceneIds")
public void testQrCodeCreateLastTicket(int sceneId) throws WxErrorException {
WxMpQrCodeTicket ticket = this.wxService.getQrcodeService().qrCodeCreateLastTicket(sceneId);
Assert.assertNotNull(ticket.getUrl()); Assert.assertNotNull(ticket.getUrl());
Assert.assertNotNull(ticket.getTicket()); Assert.assertNotNull(ticket.getTicket());
Assert.assertTrue(ticket.getExpire_seconds() == -1); Assert.assertTrue(ticket.getExpire_seconds() == -1);

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

Loading…
Cancel
Save