mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-03-10 00:13:40 +08:00
1
.gitignore
vendored
1
.gitignore
vendored
@@ -26,6 +26,7 @@ test-config.xml
|
||||
/gradle/
|
||||
*.bat
|
||||
/gradlew
|
||||
**/build/
|
||||
|
||||
# OSX
|
||||
# Icon must end with two \r
|
||||
|
||||
@@ -2,7 +2,7 @@ allprojects {
|
||||
apply plugin: 'maven'
|
||||
|
||||
group = 'com.github.binarywang'
|
||||
version = '2.3.0'
|
||||
version = '2.4.0-SNAPSHOT'
|
||||
}
|
||||
|
||||
subprojects {
|
||||
@@ -21,6 +21,7 @@ subprojects {
|
||||
dependencies {
|
||||
compile group: 'org.slf4j', name: 'slf4j-api', version:'1.7.10'
|
||||
compile group: 'org.apache.httpcomponents', name: 'httpmime', version:'4.5'
|
||||
compile group: 'org.apache.httpcomponents', name: 'httpclient', version:'4.5'
|
||||
compile group: 'com.google.code.gson', name: 'gson', version:'2.7'
|
||||
compile group: 'com.google.guava', name: 'guava', version:'19.0'
|
||||
compile group: 'commons-codec', name: 'commons-codec', version:'1.10'
|
||||
|
||||
29
pom.xml
29
pom.xml
@@ -5,7 +5,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-parent</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<version>2.4.0</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>WeiXin Java Tools - Parent</name>
|
||||
<description>微信公众号、企业号上级POM</description>
|
||||
@@ -54,6 +54,21 @@
|
||||
<email>aimilin@yeah.net</email>
|
||||
<url>https://github.com/aimilin6688</url>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Eric.Tsai</name>
|
||||
<email>xiaodong.cai.ks@gmail.com</email>
|
||||
<url>https://github.com/iwareserictsai</url>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>withinthefog</name>
|
||||
<email>withinthefog@gmail.com</email>
|
||||
<url>https://github.com/withinthefog</url>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Keung</name>
|
||||
<email>dongfuqiang1988@163.com</email>
|
||||
<url>https://github.com/johnnytung</url>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
@@ -70,6 +85,9 @@
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.7</maven.compiler.source>
|
||||
<maven.compiler.target>1.7</maven.compiler.target>
|
||||
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<downloadJavadocs>true</downloadJavadocs>
|
||||
<downloadSources>true</downloadSources>
|
||||
@@ -97,6 +115,11 @@
|
||||
<version>${logback.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>${httpclient.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpmime</artifactId>
|
||||
@@ -296,10 +319,8 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<version>3.6.0</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
@@ -6,7 +6,7 @@ dependencies {
|
||||
testCompile group: 'org.testng', name: 'testng', version:'6.8.7'
|
||||
testCompile group: 'org.mockito', name: 'mockito-all', version:'1.9.5'
|
||||
testCompile group: 'com.google.inject', name: 'guice', version:'3.0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.M0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.M0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.RC0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.RC0'
|
||||
}
|
||||
test.useTestNG()
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-parent</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<version>2.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>weixin-java-common</artifactId>
|
||||
|
||||
@@ -18,8 +18,13 @@ public class WxConsts {
|
||||
public static final String XML_MSG_LOCATION = "location";
|
||||
public static final String XML_MSG_LINK = "link";
|
||||
public static final String XML_MSG_EVENT = "event";
|
||||
public static final String XML_MSG_DEVICE_TEXT = "device_text";
|
||||
public static final String XML_MSG_DEVICE_EVENT = "device_event";
|
||||
public static final String XML_MSG_DEVICE_STATUS = "device_status";
|
||||
public static final String XML_MSG_HARDWARE = "hardware";
|
||||
public static final String XML_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service";
|
||||
|
||||
|
||||
///////////////////////
|
||||
// 主动发送消息(即客服消息)的消息类型
|
||||
///////////////////////
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package me.chanjar.weixin.common.bean.menu;
|
||||
|
||||
import me.chanjar.weixin.common.util.ToStringUtils;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Serializable;
|
||||
@@ -7,11 +10,8 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.chanjar.weixin.common.bean.menu.WxMenuButton;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
|
||||
/**
|
||||
* 企业号菜单
|
||||
* 菜单(公众号和企业号共用的)
|
||||
*
|
||||
* @author Daniel Qian
|
||||
*/
|
||||
@@ -61,9 +61,7 @@ public class WxMenu implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WxMenu{" +
|
||||
"buttons=" + this.buttons +
|
||||
'}';
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ dependencies {
|
||||
testCompile group: 'org.testng', name: 'testng', version:'6.8.7'
|
||||
testCompile group: 'org.mockito', name: 'mockito-all', version:'1.9.5'
|
||||
testCompile group: 'com.google.inject', name: 'guice', version:'3.0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.M0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.M0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.RC0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.RC0'
|
||||
}
|
||||
test.useTestNG()
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-parent</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<version>2.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>weixin-java-cp</artifactId>
|
||||
|
||||
@@ -45,7 +45,7 @@ public interface WxCpConfigStorage {
|
||||
|
||||
String getCorpSecret();
|
||||
|
||||
String getAgentId();
|
||||
Integer getAgentId();
|
||||
|
||||
String getToken();
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
|
||||
protected volatile String token;
|
||||
protected volatile String accessToken;
|
||||
protected volatile String aesKey;
|
||||
protected volatile String agentId;
|
||||
protected volatile Integer agentId;
|
||||
protected volatile long expiresTime;
|
||||
|
||||
protected volatile String oauth2redirectUri;
|
||||
@@ -146,11 +146,11 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAgentId() {
|
||||
public Integer getAgentId() {
|
||||
return this.agentId;
|
||||
}
|
||||
|
||||
public void setAgentId(String agentId) {
|
||||
public void setAgentId(Integer agentId) {
|
||||
this.agentId = agentId;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,267 +1,259 @@
|
||||
package me.chanjar.weixin.cp.api;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
/**
|
||||
* Jedis client implementor for wechat config storage
|
||||
*
|
||||
* @author gaigeshen
|
||||
*/
|
||||
public class WxCpJedisConfigStorage implements WxCpConfigStorage {
|
||||
|
||||
/* Redis keys here */
|
||||
private static final String ACCESS_TOKEN_KEY = "WX_CP_ACCESS_TOKEN";
|
||||
private static final String ACCESS_TOKEN_EXPIRES_TIME_KEY = "WX_CP_ACCESS_TOKEN_EXPIRES_TIME";
|
||||
private static final String JS_API_TICKET_KEY = "WX_CP_JS_API_TICKET";
|
||||
private static final String JS_API_TICKET_EXPIRES_TIME_KEY = "WX_CP_JS_API_TICKET_EXPIRES_TIME";
|
||||
|
||||
private volatile String corpId;
|
||||
private volatile String corpSecret;
|
||||
|
||||
private volatile String token;
|
||||
private volatile String aesKey;
|
||||
private volatile String agentId;
|
||||
|
||||
private volatile String oauth2redirectUri;
|
||||
|
||||
private volatile String httpProxyHost;
|
||||
private volatile int httpProxyPort;
|
||||
private volatile String httpProxyUsername;
|
||||
private volatile String httpProxyPassword;
|
||||
|
||||
private volatile File tmpDirFile;
|
||||
|
||||
private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
|
||||
|
||||
/* Redis clients pool */
|
||||
private final JedisPool jedisPool;
|
||||
|
||||
public WxCpJedisConfigStorage(String host, int port) {
|
||||
this.jedisPool = new JedisPool(host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* This method will be destroy jedis pool
|
||||
*/
|
||||
public void destroy() {
|
||||
this.jedisPool.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessToken() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
return jedis.get(ACCESS_TOKEN_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccessTokenExpired() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY);
|
||||
|
||||
if (expiresTimeStr != null) {
|
||||
Long expiresTime = Long.parseLong(expiresTimeStr);
|
||||
return System.currentTimeMillis() > expiresTime;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expireAccessToken() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY, "0");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateAccessToken(WxAccessToken accessToken) {
|
||||
this.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.set(ACCESS_TOKEN_KEY, accessToken);
|
||||
|
||||
jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY,
|
||||
(System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L) + "");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJsapiTicket() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
return jedis.get(JS_API_TICKET_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJsapiTicketExpired() {
|
||||
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
String expiresTimeStr = jedis.get(JS_API_TICKET_EXPIRES_TIME_KEY);
|
||||
|
||||
if (expiresTimeStr != null) {
|
||||
Long expiresTime = Long.parseLong(expiresTimeStr);
|
||||
return System.currentTimeMillis() > expiresTime;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expireJsapiTicket() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY, "0");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
|
||||
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.set(JS_API_TICKET_KEY, jsapiTicket);
|
||||
|
||||
jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY,
|
||||
(System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L + ""));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCorpId() {
|
||||
return this.corpId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCorpSecret() {
|
||||
return this.corpSecret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAgentId() {
|
||||
return this.agentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToken() {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAesKey() {
|
||||
return this.aesKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExpiresTime() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY);
|
||||
|
||||
if (expiresTimeStr != null) {
|
||||
Long expiresTime = Long.parseLong(expiresTimeStr);
|
||||
return expiresTime;
|
||||
}
|
||||
|
||||
return 0L;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOauth2redirectUri() {
|
||||
return this.oauth2redirectUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHttpProxyHost() {
|
||||
return this.httpProxyHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHttpProxyPort() {
|
||||
return this.httpProxyPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHttpProxyUsername() {
|
||||
return this.httpProxyUsername;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHttpProxyPassword() {
|
||||
return this.httpProxyPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getTmpDirFile() {
|
||||
return this.tmpDirFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
|
||||
return this.apacheHttpClientBuilder;
|
||||
}
|
||||
|
||||
public void setCorpId(String corpId) {
|
||||
this.corpId = corpId;
|
||||
}
|
||||
|
||||
public void setCorpSecret(String corpSecret) {
|
||||
this.corpSecret = corpSecret;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public void setAesKey(String aesKey) {
|
||||
this.aesKey = aesKey;
|
||||
}
|
||||
|
||||
public void setAgentId(String agentId) {
|
||||
this.agentId = agentId;
|
||||
}
|
||||
|
||||
// ============================ Setters below
|
||||
|
||||
public void setOauth2redirectUri(String oauth2redirectUri) {
|
||||
this.oauth2redirectUri = oauth2redirectUri;
|
||||
}
|
||||
|
||||
public void setHttpProxyHost(String httpProxyHost) {
|
||||
this.httpProxyHost = httpProxyHost;
|
||||
}
|
||||
|
||||
public void setHttpProxyPort(int httpProxyPort) {
|
||||
this.httpProxyPort = httpProxyPort;
|
||||
}
|
||||
|
||||
public void setHttpProxyUsername(String httpProxyUsername) {
|
||||
this.httpProxyUsername = httpProxyUsername;
|
||||
}
|
||||
|
||||
public void setHttpProxyPassword(String httpProxyPassword) {
|
||||
this.httpProxyPassword = httpProxyPassword;
|
||||
}
|
||||
|
||||
public void setTmpDirFile(File tmpDirFile) {
|
||||
this.tmpDirFile = tmpDirFile;
|
||||
}
|
||||
|
||||
public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) {
|
||||
this.apacheHttpClientBuilder = apacheHttpClientBuilder;
|
||||
}
|
||||
|
||||
}
|
||||
package me.chanjar.weixin.cp.api;
|
||||
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Jedis client implementor for wechat config storage
|
||||
*
|
||||
* @author gaigeshen
|
||||
*/
|
||||
public class WxCpJedisConfigStorage implements WxCpConfigStorage {
|
||||
|
||||
/* Redis keys here */
|
||||
private static final String ACCESS_TOKEN_KEY = "WX_CP_ACCESS_TOKEN";
|
||||
private static final String ACCESS_TOKEN_EXPIRES_TIME_KEY = "WX_CP_ACCESS_TOKEN_EXPIRES_TIME";
|
||||
private static final String JS_API_TICKET_KEY = "WX_CP_JS_API_TICKET";
|
||||
private static final String JS_API_TICKET_EXPIRES_TIME_KEY = "WX_CP_JS_API_TICKET_EXPIRES_TIME";
|
||||
/* Redis clients pool */
|
||||
private final JedisPool jedisPool;
|
||||
private volatile String corpId;
|
||||
private volatile String corpSecret;
|
||||
private volatile String token;
|
||||
private volatile String aesKey;
|
||||
private volatile Integer agentId;
|
||||
private volatile String oauth2redirectUri;
|
||||
private volatile String httpProxyHost;
|
||||
private volatile int httpProxyPort;
|
||||
private volatile String httpProxyUsername;
|
||||
private volatile String httpProxyPassword;
|
||||
private volatile File tmpDirFile;
|
||||
private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
|
||||
|
||||
public WxCpJedisConfigStorage(String host, int port) {
|
||||
this.jedisPool = new JedisPool(host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be destroy jedis pool
|
||||
*/
|
||||
public void destroy() {
|
||||
this.jedisPool.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessToken() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
return jedis.get(ACCESS_TOKEN_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccessTokenExpired() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY);
|
||||
|
||||
if (expiresTimeStr != null) {
|
||||
Long expiresTime = Long.parseLong(expiresTimeStr);
|
||||
return System.currentTimeMillis() > expiresTime;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expireAccessToken() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY, "0");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateAccessToken(WxAccessToken accessToken) {
|
||||
this.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.set(ACCESS_TOKEN_KEY, accessToken);
|
||||
|
||||
jedis.set(ACCESS_TOKEN_EXPIRES_TIME_KEY,
|
||||
(System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L) + "");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJsapiTicket() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
return jedis.get(JS_API_TICKET_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJsapiTicketExpired() {
|
||||
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
String expiresTimeStr = jedis.get(JS_API_TICKET_EXPIRES_TIME_KEY);
|
||||
|
||||
if (expiresTimeStr != null) {
|
||||
Long expiresTime = Long.parseLong(expiresTimeStr);
|
||||
return System.currentTimeMillis() > expiresTime;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expireJsapiTicket() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY, "0");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
|
||||
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.set(JS_API_TICKET_KEY, jsapiTicket);
|
||||
|
||||
jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY,
|
||||
(System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L + ""));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCorpId() {
|
||||
return this.corpId;
|
||||
}
|
||||
|
||||
public void setCorpId(String corpId) {
|
||||
this.corpId = corpId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCorpSecret() {
|
||||
return this.corpSecret;
|
||||
}
|
||||
|
||||
public void setCorpSecret(String corpSecret) {
|
||||
this.corpSecret = corpSecret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getAgentId() {
|
||||
return this.agentId;
|
||||
}
|
||||
|
||||
public void setAgentId(Integer agentId) {
|
||||
this.agentId = agentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToken() {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAesKey() {
|
||||
return this.aesKey;
|
||||
}
|
||||
|
||||
public void setAesKey(String aesKey) {
|
||||
this.aesKey = aesKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExpiresTime() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY);
|
||||
|
||||
if (expiresTimeStr != null) {
|
||||
Long expiresTime = Long.parseLong(expiresTimeStr);
|
||||
return expiresTime;
|
||||
}
|
||||
|
||||
return 0L;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOauth2redirectUri() {
|
||||
return this.oauth2redirectUri;
|
||||
}
|
||||
|
||||
public void setOauth2redirectUri(String oauth2redirectUri) {
|
||||
this.oauth2redirectUri = oauth2redirectUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHttpProxyHost() {
|
||||
return this.httpProxyHost;
|
||||
}
|
||||
|
||||
public void setHttpProxyHost(String httpProxyHost) {
|
||||
this.httpProxyHost = httpProxyHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHttpProxyPort() {
|
||||
return this.httpProxyPort;
|
||||
}
|
||||
|
||||
public void setHttpProxyPort(int httpProxyPort) {
|
||||
this.httpProxyPort = httpProxyPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHttpProxyUsername() {
|
||||
return this.httpProxyUsername;
|
||||
}
|
||||
|
||||
// ============================ Setters below
|
||||
|
||||
public void setHttpProxyUsername(String httpProxyUsername) {
|
||||
this.httpProxyUsername = httpProxyUsername;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHttpProxyPassword() {
|
||||
return this.httpProxyPassword;
|
||||
}
|
||||
|
||||
public void setHttpProxyPassword(String httpProxyPassword) {
|
||||
this.httpProxyPassword = httpProxyPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getTmpDirFile() {
|
||||
return this.tmpDirFile;
|
||||
}
|
||||
|
||||
public void setTmpDirFile(File tmpDirFile) {
|
||||
this.tmpDirFile = tmpDirFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
|
||||
return this.apacheHttpClientBuilder;
|
||||
}
|
||||
|
||||
public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) {
|
||||
this.apacheHttpClientBuilder = apacheHttpClientBuilder;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -163,12 +163,12 @@ public class WxCpMessageRouter {
|
||||
// 返回最后一个非异步的rule的执行结果
|
||||
if (rule.isAsync()) {
|
||||
futures.add(
|
||||
this.executorService.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
rule.service(wxMessage, WxCpMessageRouter.this.wxCpService, WxCpMessageRouter.this.sessionManager, WxCpMessageRouter.this.exceptionHandler);
|
||||
}
|
||||
})
|
||||
this.executorService.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
rule.service(wxMessage, WxCpMessageRouter.this.wxCpService, WxCpMessageRouter.this.sessionManager, WxCpMessageRouter.this.exceptionHandler);
|
||||
}
|
||||
})
|
||||
);
|
||||
} else {
|
||||
res = rule.service(wxMessage, this.wxCpService, this.sessionManager, this.exceptionHandler);
|
||||
@@ -205,10 +205,10 @@ public class WxCpMessageRouter {
|
||||
String messageId = "";
|
||||
if (wxMessage.getMsgId() == null) {
|
||||
messageId = String.valueOf(wxMessage.getCreateTime())
|
||||
+ "-" + String.valueOf(wxMessage.getAgentId() == null ? "" : wxMessage.getAgentId())
|
||||
+ "-" + wxMessage.getFromUserName()
|
||||
+ "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey())
|
||||
+ "-" + String.valueOf(wxMessage.getEvent() == null ? "" : wxMessage.getEvent())
|
||||
+ "-" + String.valueOf(wxMessage.getAgentId() == null ? "" : wxMessage.getAgentId())
|
||||
+ "-" + wxMessage.getFromUserName()
|
||||
+ "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey())
|
||||
+ "-" + String.valueOf(wxMessage.getEvent() == null ? "" : wxMessage.getEvent())
|
||||
;
|
||||
} else {
|
||||
messageId = String.valueOf(wxMessage.getMsgId());
|
||||
|
||||
@@ -202,24 +202,24 @@ public class WxCpMessageRouterRule {
|
||||
|
||||
protected boolean test(WxCpXmlMessage wxMessage) {
|
||||
return
|
||||
(this.fromUser == null || this.fromUser.equals(wxMessage.getFromUserName()))
|
||||
&&
|
||||
(this.agentId == null || this.agentId.equals(wxMessage.getAgentId()))
|
||||
&&
|
||||
(this.msgType == null || this.msgType.equals(wxMessage.getMsgType()))
|
||||
&&
|
||||
(this.event == null || this.event.equals(wxMessage.getEvent()))
|
||||
&&
|
||||
(this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey()))
|
||||
&&
|
||||
(this.content == null || this.content
|
||||
.equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim()))
|
||||
&&
|
||||
(this.rContent == null || Pattern
|
||||
.matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim()))
|
||||
&&
|
||||
(this.matcher == null || this.matcher.match(wxMessage))
|
||||
;
|
||||
(this.fromUser == null || this.fromUser.equals(wxMessage.getFromUserName()))
|
||||
&&
|
||||
(this.agentId == null || this.agentId.equals(wxMessage.getAgentId()))
|
||||
&&
|
||||
(this.msgType == null || this.msgType.equals(wxMessage.getMsgType()))
|
||||
&&
|
||||
(this.event == null || this.event.equals(wxMessage.getEvent()))
|
||||
&&
|
||||
(this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey()))
|
||||
&&
|
||||
(this.content == null || this.content
|
||||
.equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim()))
|
||||
&&
|
||||
(this.rContent == null || Pattern
|
||||
.matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim()))
|
||||
&&
|
||||
(this.matcher == null || this.matcher.match(wxMessage))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -160,7 +160,7 @@ public interface WxCpService {
|
||||
*
|
||||
* @param menu
|
||||
* @throws WxErrorException
|
||||
* @see #menuCreate(String, me.chanjar.weixin.common.bean.menu.WxMenu)
|
||||
* @see #menuCreate(Integer, WxMenu)
|
||||
*/
|
||||
void menuCreate(WxMenu menu) throws WxErrorException;
|
||||
|
||||
@@ -177,7 +177,7 @@ public interface WxCpService {
|
||||
* @throws WxErrorException
|
||||
* @see #menuCreate(me.chanjar.weixin.common.bean.menu.WxMenu)
|
||||
*/
|
||||
void menuCreate(String agentId, WxMenu menu) throws WxErrorException;
|
||||
void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -188,7 +188,7 @@ public interface WxCpService {
|
||||
* </pre>
|
||||
*
|
||||
* @throws WxErrorException
|
||||
* @see #menuDelete(String)
|
||||
* @see #menuDelete(Integer)
|
||||
*/
|
||||
void menuDelete() throws WxErrorException;
|
||||
|
||||
@@ -204,7 +204,7 @@ public interface WxCpService {
|
||||
* @throws WxErrorException
|
||||
* @see #menuDelete()
|
||||
*/
|
||||
void menuDelete(String agentId) throws WxErrorException;
|
||||
void menuDelete(Integer agentId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -215,7 +215,7 @@ public interface WxCpService {
|
||||
* </pre>
|
||||
*
|
||||
* @throws WxErrorException
|
||||
* @see #menuGet(String)
|
||||
* @see #menuGet(Integer)
|
||||
*/
|
||||
WxMenu menuGet() throws WxErrorException;
|
||||
|
||||
@@ -231,7 +231,7 @@ public interface WxCpService {
|
||||
* @throws WxErrorException
|
||||
* @see #menuGet()
|
||||
*/
|
||||
WxMenu menuGet(String agentId) throws WxErrorException;
|
||||
WxMenu menuGet(Integer agentId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -396,12 +396,12 @@ public interface WxCpService {
|
||||
* <pre>
|
||||
* 构造oauth2授权的url连接
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @param state
|
||||
* @return url
|
||||
*/
|
||||
String oauth2buildAuthorizationUrl(String state);
|
||||
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 构造oauth2授权的url连接
|
||||
@@ -425,7 +425,7 @@ public interface WxCpService {
|
||||
*
|
||||
* @param code
|
||||
* @return [userid, deviceid]
|
||||
* @see #oauth2getUserInfo(String, String)
|
||||
* @see #oauth2getUserInfo(Integer, String)
|
||||
*/
|
||||
String[] oauth2getUserInfo(String code) throws WxErrorException;
|
||||
|
||||
@@ -443,7 +443,7 @@ public interface WxCpService {
|
||||
* @return [userid, deviceid]
|
||||
* @see #oauth2getUserInfo(String)
|
||||
*/
|
||||
String[] oauth2getUserInfo(String agentId, String code) throws WxErrorException;
|
||||
String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,7 +23,6 @@ import me.chanjar.weixin.cp.bean.WxCpUser;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
@@ -69,7 +68,7 @@ public class WxCpServiceImpl implements WxCpService {
|
||||
public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) {
|
||||
try {
|
||||
return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data)
|
||||
.equals(msgSignature);
|
||||
.equals(msgSignature);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
@@ -95,18 +94,18 @@ public class WxCpServiceImpl implements WxCpService {
|
||||
synchronized (this.globalAccessTokenRefreshLock) {
|
||||
if (this.configStorage.isAccessTokenExpired()) {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
|
||||
+ "&corpid=" + this.configStorage.getCorpId()
|
||||
+ "&corpsecret=" + this.configStorage.getCorpSecret();
|
||||
+ "&corpid=" + this.configStorage.getCorpId()
|
||||
+ "&corpsecret=" + this.configStorage.getCorpSecret();
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
if (this.httpProxy != null) {
|
||||
RequestConfig config = RequestConfig.custom()
|
||||
.setProxy(this.httpProxy).build();
|
||||
.setProxy(this.httpProxy).build();
|
||||
httpGet.setConfig(config);
|
||||
}
|
||||
String resultContent = null;
|
||||
try (CloseableHttpClient httpclient = getHttpclient();
|
||||
CloseableHttpResponse response = httpclient.execute(httpGet)) {
|
||||
CloseableHttpResponse response = httpclient.execute(httpGet)) {
|
||||
resultContent = new BasicResponseHandler().handleResponse(response);
|
||||
} finally {
|
||||
httpGet.releaseConnection();
|
||||
@@ -117,9 +116,7 @@ public class WxCpServiceImpl implements WxCpService {
|
||||
}
|
||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||
this.configStorage.updateAccessToken(
|
||||
accessToken.getAccessToken(), accessToken.getExpiresIn());
|
||||
} catch (ClientProtocolException e) {
|
||||
throw new RuntimeException(e);
|
||||
accessToken.getAccessToken(), accessToken.getExpiresIn());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -149,7 +146,7 @@ public class WxCpServiceImpl implements WxCpService {
|
||||
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
|
||||
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
|
||||
this.configStorage.updateJsapiTicket(jsapiTicket,
|
||||
expiresInSeconds);
|
||||
expiresInSeconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,10 +159,10 @@ public class WxCpServiceImpl implements WxCpService {
|
||||
String noncestr = RandomUtils.getRandomStr();
|
||||
String jsapiTicket = getJsapiTicket(false);
|
||||
String signature = SHA1.genWithAmple(
|
||||
"jsapi_ticket=" + jsapiTicket,
|
||||
"noncestr=" + noncestr,
|
||||
"timestamp=" + timestamp,
|
||||
"url=" + url
|
||||
"jsapi_ticket=" + jsapiTicket,
|
||||
"noncestr=" + noncestr,
|
||||
"timestamp=" + timestamp,
|
||||
"url=" + url
|
||||
);
|
||||
WxJsapiSignature jsapiSignature = new WxJsapiSignature();
|
||||
jsapiSignature.setTimestamp(timestamp);
|
||||
@@ -191,9 +188,9 @@ public class WxCpServiceImpl implements WxCpService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void menuCreate(String agentId, WxMenu menu) throws WxErrorException {
|
||||
public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid="
|
||||
+ this.configStorage.getAgentId();
|
||||
+ this.configStorage.getAgentId();
|
||||
post(url, menu.toJson());
|
||||
}
|
||||
|
||||
@@ -203,7 +200,7 @@ public class WxCpServiceImpl implements WxCpService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void menuDelete(String agentId) throws WxErrorException {
|
||||
public void menuDelete(Integer agentId) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId;
|
||||
get(url, null);
|
||||
}
|
||||
@@ -214,7 +211,7 @@ public class WxCpServiceImpl implements WxCpService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMenu menuGet(String agentId) throws WxErrorException {
|
||||
public WxMenu menuGet(Integer agentId) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId;
|
||||
try {
|
||||
String resultContent = get(url, null);
|
||||
@@ -230,7 +227,7 @@ public class WxCpServiceImpl implements WxCpService {
|
||||
|
||||
@Override
|
||||
public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream)
|
||||
throws WxErrorException, IOException {
|
||||
throws WxErrorException, IOException {
|
||||
return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType));
|
||||
}
|
||||
|
||||
@@ -244,9 +241,9 @@ public class WxCpServiceImpl implements WxCpService {
|
||||
public File mediaDownload(String media_id) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get";
|
||||
return execute(
|
||||
new MediaDownloadRequestExecutor(
|
||||
this.configStorage.getTmpDirFile()),
|
||||
url, "media_id=" + media_id);
|
||||
new MediaDownloadRequestExecutor(
|
||||
this.configStorage.getTmpDirFile()),
|
||||
url, "media_id=" + media_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -254,9 +251,9 @@ this.configStorage.getTmpDirFile()),
|
||||
public Integer departCreate(WxCpDepart depart) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create";
|
||||
String responseContent = execute(
|
||||
new SimplePostRequestExecutor(),
|
||||
url,
|
||||
depart.toJson());
|
||||
new SimplePostRequestExecutor(),
|
||||
url,
|
||||
depart.toJson());
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id"));
|
||||
}
|
||||
@@ -283,11 +280,11 @@ this.configStorage.getTmpDirFile()),
|
||||
*/
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return WxCpGsonBuilder.INSTANCE.create()
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("department"),
|
||||
new TypeToken<List<WxCpDepart>>() {
|
||||
}.getType()
|
||||
);
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("department"),
|
||||
new TypeToken<List<WxCpDepart>>() {
|
||||
}.getType()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -313,8 +310,8 @@ this.configStorage.getTmpDirFile()),
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete";
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
for (int i = 0; i < userids.length; i++) {
|
||||
jsonArray.add(new JsonPrimitive(userids[i]));
|
||||
for (String userid : userids) {
|
||||
jsonArray.add(new JsonPrimitive(userid));
|
||||
}
|
||||
jsonObject.add("useridlist", jsonArray);
|
||||
post(url, jsonObject.toString());
|
||||
@@ -343,11 +340,11 @@ this.configStorage.getTmpDirFile()),
|
||||
String responseContent = get(url, params);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return WxCpGsonBuilder.INSTANCE.create()
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("userlist"),
|
||||
new TypeToken<List<WxCpUser>>() {
|
||||
}.getType()
|
||||
);
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("userlist"),
|
||||
new TypeToken<List<WxCpUser>>() {
|
||||
}.getType()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -366,11 +363,11 @@ this.configStorage.getTmpDirFile()),
|
||||
String responseContent = get(url, params);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return WxCpGsonBuilder.INSTANCE.create()
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("userlist"),
|
||||
new TypeToken<List<WxCpUser>>() {
|
||||
}.getType()
|
||||
);
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("userlist"),
|
||||
new TypeToken<List<WxCpUser>>() {
|
||||
}.getType()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -404,11 +401,11 @@ this.configStorage.getTmpDirFile()),
|
||||
String responseContent = get(url, null);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return WxCpGsonBuilder.INSTANCE.create()
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("taglist"),
|
||||
new TypeToken<List<WxCpTag>>() {
|
||||
}.getType()
|
||||
);
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("taglist"),
|
||||
new TypeToken<List<WxCpTag>>() {
|
||||
}.getType()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -417,11 +414,11 @@ this.configStorage.getTmpDirFile()),
|
||||
String responseContent = get(url, null);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return WxCpGsonBuilder.INSTANCE.create()
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("userlist"),
|
||||
new TypeToken<List<WxCpUser>>() {
|
||||
}.getType()
|
||||
);
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("userlist"),
|
||||
new TypeToken<List<WxCpUser>>() {
|
||||
}.getType()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -460,14 +457,14 @@ this.configStorage.getTmpDirFile()),
|
||||
}
|
||||
|
||||
@Override
|
||||
public String oauth2buildAuthorizationUrl(String state) {
|
||||
return this.oauth2buildAuthorizationUrl(
|
||||
this.configStorage.getOauth2redirectUri(),
|
||||
state
|
||||
);
|
||||
}
|
||||
public String oauth2buildAuthorizationUrl(String state) {
|
||||
return this.oauth2buildAuthorizationUrl(
|
||||
this.configStorage.getOauth2redirectUri(),
|
||||
state
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public String oauth2buildAuthorizationUrl(String redirectUri, String state) {
|
||||
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?";
|
||||
url += "appid=" + this.configStorage.getCorpId();
|
||||
@@ -487,10 +484,10 @@ this.configStorage.getOauth2redirectUri(),
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] oauth2getUserInfo(String agentId, String code) throws WxErrorException {
|
||||
public String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?"
|
||||
+ "code=" + code
|
||||
+ "&agentid=" + agentId;
|
||||
+ "code=" + code
|
||||
+ "&agentid=" + agentId;
|
||||
String responseText = get(url, null);
|
||||
JsonElement je = new JsonParser().parse(responseText);
|
||||
JsonObject jo = je.getAsJsonObject();
|
||||
@@ -544,14 +541,14 @@ this.configStorage.getOauth2redirectUri(),
|
||||
return executeInternal(executor, uri, data);
|
||||
} catch (WxErrorException e) {
|
||||
WxError error = e.getError();
|
||||
/**
|
||||
/*
|
||||
* -1 系统繁忙, 1000ms后重试
|
||||
*/
|
||||
if (error.getErrorCode() == -1) {
|
||||
int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
|
||||
try {
|
||||
this.log.debug("微信系统繁忙,{}ms 后重试(第{}次)", sleepMillis,
|
||||
retryTimes + 1);
|
||||
retryTimes + 1);
|
||||
Thread.sleep(sleepMillis);
|
||||
} catch (InterruptedException e1) {
|
||||
throw new RuntimeException(e1);
|
||||
@@ -566,7 +563,7 @@ this.configStorage.getOauth2redirectUri(),
|
||||
}
|
||||
|
||||
protected synchronized <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
|
||||
if (uri.indexOf("access_token=") != -1) {
|
||||
if (uri.contains("access_token=")) {
|
||||
throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri);
|
||||
}
|
||||
String accessToken = getAccessToken(false);
|
||||
@@ -576,7 +573,7 @@ this.configStorage.getOauth2redirectUri(),
|
||||
|
||||
try {
|
||||
return executor.execute(getHttpclient(), this.httpProxy,
|
||||
uriWithAccessToken, data);
|
||||
uriWithAccessToken, data);
|
||||
} catch (WxErrorException e) {
|
||||
WxError error = e.getError();
|
||||
/*
|
||||
@@ -593,8 +590,6 @@ this.configStorage.getOauth2redirectUri(),
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
return null;
|
||||
} catch (ClientProtocolException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -608,15 +603,15 @@ this.configStorage.getOauth2redirectUri(),
|
||||
public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) {
|
||||
this.configStorage = wxConfigProvider;
|
||||
ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage
|
||||
.getApacheHttpClientBuilder();
|
||||
.getApacheHttpClientBuilder();
|
||||
if (null == apacheHttpClientBuilder) {
|
||||
apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get();
|
||||
}
|
||||
|
||||
apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost())
|
||||
.httpProxyPort(this.configStorage.getHttpProxyPort())
|
||||
.httpProxyUsername(this.configStorage.getHttpProxyUsername())
|
||||
.httpProxyPassword(this.configStorage.getHttpProxyPassword());
|
||||
.httpProxyPort(this.configStorage.getHttpProxyPort())
|
||||
.httpProxyUsername(this.configStorage.getHttpProxyUsername())
|
||||
.httpProxyPassword(this.configStorage.getHttpProxyPassword());
|
||||
|
||||
if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
|
||||
this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort());
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.*;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.FileBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.ImageBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.NewsBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.TextBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.VideoBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.VoiceBuilder;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
/**
|
||||
* 消息
|
||||
*
|
||||
@@ -23,7 +18,7 @@ public class WxCpMessage implements Serializable {
|
||||
private String toUser;
|
||||
private String toParty;
|
||||
private String toTag;
|
||||
private String agentId;
|
||||
private Integer agentId;
|
||||
private String msgType;
|
||||
private String content;
|
||||
private String mediaId;
|
||||
@@ -101,11 +96,11 @@ public class WxCpMessage implements Serializable {
|
||||
this.toTag = toTag;
|
||||
}
|
||||
|
||||
public String getAgentId() {
|
||||
public Integer getAgentId() {
|
||||
return this.agentId;
|
||||
}
|
||||
|
||||
public void setAgentId(String agentId) {
|
||||
public void setAgentId(Integer agentId) {
|
||||
this.agentId = agentId;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@ import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
|
||||
public class BaseBuilder<T> {
|
||||
protected String msgType;
|
||||
protected String agentId;
|
||||
protected Integer agentId;
|
||||
protected String toUser;
|
||||
protected String toParty;
|
||||
protected String toTag;
|
||||
protected String safe;
|
||||
|
||||
public T agentId(String agentId) {
|
||||
public T agentId(Integer agentId) {
|
||||
this.agentId = agentId;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ dependencies {
|
||||
testCompile group: 'org.testng', name: 'testng', version:'6.8.7'
|
||||
testCompile group: 'org.mockito', name: 'mockito-all', version:'1.9.5'
|
||||
testCompile group: 'com.google.inject', name: 'guice', version:'3.0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.M0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.M0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.RC0'
|
||||
testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.RC0'
|
||||
testCompile group: 'joda-time', name: 'joda-time', version:'2.9.4'
|
||||
}
|
||||
test.useTestNG()
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-parent</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<version>2.4.0</version>
|
||||
</parent>
|
||||
<artifactId>weixin-java-mp</artifactId>
|
||||
<name>WeiXin Java Tools - MP</name>
|
||||
|
||||
@@ -5,6 +5,7 @@ import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
/**
|
||||
* 微信客户端配置存储
|
||||
@@ -15,6 +16,8 @@ public interface WxMpConfigStorage {
|
||||
|
||||
String getAccessToken();
|
||||
|
||||
Lock getAccessTokenLock();
|
||||
|
||||
boolean isAccessTokenExpired();
|
||||
|
||||
/**
|
||||
@@ -24,19 +27,21 @@ public interface WxMpConfigStorage {
|
||||
|
||||
/**
|
||||
* 应该是线程安全的
|
||||
* @param accessToken
|
||||
* @param accessToken 要更新的WxAccessToken对象
|
||||
*/
|
||||
void updateAccessToken(WxAccessToken accessToken);
|
||||
|
||||
/**
|
||||
* 应该是线程安全的
|
||||
* @param accessToken
|
||||
* @param expiresIn
|
||||
* @param accessToken 新的accessToken值
|
||||
* @param expiresInSeconds 过期时间,以秒为单位
|
||||
*/
|
||||
void updateAccessToken(String accessToken, int expiresIn);
|
||||
void updateAccessToken(String accessToken, int expiresInSeconds);
|
||||
|
||||
String getJsapiTicket();
|
||||
|
||||
Lock getJsapiTicketLock();
|
||||
|
||||
boolean isJsapiTicketExpired();
|
||||
|
||||
/**
|
||||
@@ -46,12 +51,15 @@ public interface WxMpConfigStorage {
|
||||
|
||||
/**
|
||||
* 应该是线程安全的
|
||||
* @param jsapiTicket
|
||||
* @param jsapiTicket 新的jsapi ticket值
|
||||
* @param expiresInSeconds 过期时间,以秒为单位
|
||||
*/
|
||||
void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
|
||||
|
||||
String getCardApiTicket();
|
||||
|
||||
Lock getCardApiTicketLock();
|
||||
|
||||
boolean isCardApiTicketExpired();
|
||||
|
||||
/**
|
||||
@@ -61,7 +69,8 @@ public interface WxMpConfigStorage {
|
||||
|
||||
/**
|
||||
* 应该是线程安全的
|
||||
* @param cardApiTicket
|
||||
* @param cardApiTicket 新的cardApi ticket值
|
||||
* @param expiresInSeconds 过期时间,以秒为单位
|
||||
*/
|
||||
void updateCardApiTicket(String cardApiTicket, int expiresInSeconds);
|
||||
|
||||
@@ -70,7 +79,7 @@ public interface WxMpConfigStorage {
|
||||
String getSecret();
|
||||
|
||||
String getPartnerId();
|
||||
|
||||
|
||||
String getPartnerKey();
|
||||
|
||||
String getToken();
|
||||
@@ -88,7 +97,7 @@ public interface WxMpConfigStorage {
|
||||
String getHttpProxyUsername();
|
||||
|
||||
String getHttpProxyPassword();
|
||||
|
||||
|
||||
File getTmpDirFile();
|
||||
|
||||
SSLContext getSSLContext();
|
||||
@@ -98,4 +107,9 @@ public interface WxMpConfigStorage {
|
||||
* @return ApacheHttpClientBuilder
|
||||
*/
|
||||
ApacheHttpClientBuilder getApacheHttpClientBuilder();
|
||||
|
||||
/**
|
||||
* 是否自动刷新token
|
||||
*/
|
||||
boolean autoRefreshToken();
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
|
||||
@@ -36,6 +38,10 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
protected volatile String cardApiTicket;
|
||||
protected volatile long cardApiTicketExpiresTime;
|
||||
|
||||
protected Lock accessTokenLock = new ReentrantLock();
|
||||
protected Lock jsapiTicketLock = new ReentrantLock();
|
||||
protected Lock cardApiTicketLock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* 临时文件目录
|
||||
*/
|
||||
@@ -50,6 +56,11 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
return this.accessToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock getAccessTokenLock() {
|
||||
return this.accessTokenLock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccessTokenExpired() {
|
||||
return System.currentTimeMillis() > this.expiresTime;
|
||||
@@ -63,7 +74,7 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
@Override
|
||||
public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {
|
||||
this.accessToken = accessToken;
|
||||
this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l;
|
||||
this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,6 +87,11 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
return this.jsapiTicket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock getJsapiTicketLock() {
|
||||
return this.jsapiTicketLock;
|
||||
}
|
||||
|
||||
public void setJsapiTicket(String jsapiTicket) {
|
||||
this.jsapiTicket = jsapiTicket;
|
||||
}
|
||||
@@ -97,7 +113,7 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
|
||||
this.jsapiTicket = jsapiTicket;
|
||||
// 预留200秒的时间
|
||||
this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l;
|
||||
this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,6 +129,11 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
return this.cardApiTicket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock getCardApiTicketLock() {
|
||||
return this.cardApiTicketLock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCardApiTicketExpired() {
|
||||
return System.currentTimeMillis() > this.cardApiTicketExpiresTime;
|
||||
@@ -122,7 +143,7 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
public synchronized void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) {
|
||||
this.cardApiTicket = cardApiTicket;
|
||||
// 预留200秒的时间
|
||||
this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l;
|
||||
this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -270,6 +291,11 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
return this.apacheHttpClientBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean autoRefreshToken() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) {
|
||||
this.apacheHttpClientBuilder = apacheHttpClientBuilder;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.chanjar.weixin.mp.api;
|
||||
|
||||
import me.chanjar.weixin.common.bean.menu.WxMenu;
|
||||
import me.chanjar.weixin.common.exception.WxErrorException;
|
||||
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
|
||||
|
||||
/**
|
||||
* 菜单相关操作接口
|
||||
@@ -56,4 +57,20 @@ public interface WxMpMenuService {
|
||||
*/
|
||||
WxMenu menuTryMatch(String userid) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 获取自定义菜单配置接口
|
||||
* 本接口将会提供公众号当前使用的自定义菜单的配置,如果公众号是通过API调用设置的菜单,则返回菜单的开发配置,而如果公众号是在公众平台官网通过网站功能发布菜单,则本接口返回运营者设置的菜单配置。
|
||||
请注意:
|
||||
1、第三方平台开发者可以通过本接口,在旗下公众号将业务授权给你后,立即通过本接口检测公众号的自定义菜单配置,并通过接口再次给公众号设置好自动回复规则,以提升公众号运营者的业务体验。
|
||||
2、本接口与自定义菜单查询接口的不同之处在于,本接口无论公众号的接口是如何设置的,都能查询到接口,而自定义菜单查询接口则仅能查询到使用API设置的菜单配置。
|
||||
3、认证/未认证的服务号/订阅号,以及接口测试号,均拥有该接口权限。
|
||||
4、从第三方平台的公众号登录授权机制上来说,该接口从属于消息与菜单权限集。
|
||||
5、本接口中返回的图片/语音/视频为临时素材(临时素材每次获取都不同,3天内有效,通过素材管理-获取临时素材接口来获取这些素材),本接口返回的图文消息为永久素材素材(通过素材管理-获取永久素材接口来获取这些素材)。
|
||||
* 接口调用请求说明:
|
||||
http请求方式: GET(请使用https协议)
|
||||
https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
|
||||
*</pre>
|
||||
*/
|
||||
WxMpGetSelfMenuInfoResult getSelfMenuInfo() throws WxErrorException;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package me.chanjar.weixin.mp.api;
|
||||
|
||||
import me.chanjar.weixin.common.exception.WxErrorException;
|
||||
import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback;
|
||||
import me.chanjar.weixin.mp.bean.pay.result.WxPayOrderCloseResult;
|
||||
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;
|
||||
@@ -13,8 +12,9 @@ import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 微信支付相关接口
|
||||
* Created by Binary Wang on 2016/7/28.
|
||||
* 微信支付相关接口
|
||||
* Created by Binary Wang on 2016/7/28.
|
||||
*
|
||||
* @author binarywang (https://github.com/binarywang)
|
||||
*/
|
||||
public interface WxMpPayService {
|
||||
@@ -24,14 +24,15 @@ public interface WxMpPayService {
|
||||
* 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2)
|
||||
* 该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。
|
||||
* 需要调用查询接口的情况:
|
||||
◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;
|
||||
◆ 调用支付接口后,返回系统错误或未知交易状态情况;
|
||||
◆ 调用被扫支付API,返回USERPAYING的状态;
|
||||
◆ 调用关单或撤销接口API之前,需确认支付状态;
|
||||
* ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;
|
||||
* ◆ 调用支付接口后,返回系统错误或未知交易状态情况;
|
||||
* ◆ 调用被扫支付API,返回USERPAYING的状态;
|
||||
* ◆ 调用关单或撤销接口API之前,需确认支付状态;
|
||||
* 接口地址:https://api.mch.weixin.qq.com/pay/orderquery
|
||||
* </pre>
|
||||
*
|
||||
* @param transactionId 微信支付分配的商户号
|
||||
* @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。
|
||||
* @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException;
|
||||
@@ -47,6 +48,7 @@ public interface WxMpPayService {
|
||||
* 接口地址:https://api.mch.weixin.qq.com/pay/closeorder
|
||||
* 是否需要证书: 不需要。
|
||||
* </pre>
|
||||
*
|
||||
* @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
@@ -56,16 +58,18 @@ public interface WxMpPayService {
|
||||
* 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
|
||||
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
|
||||
* 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder
|
||||
* @throws WxErrorException
|
||||
* @param request 请求对象
|
||||
*
|
||||
* @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数
|
||||
* 详见http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
|
||||
* @param request 请求对象
|
||||
*
|
||||
* @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
Map<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException;
|
||||
|
||||
@@ -75,16 +79,33 @@ public interface WxMpPayService {
|
||||
* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
|
||||
* 接口链接:https://api.mch.weixin.qq.com/secapi/pay/refund
|
||||
* </pre>
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @param keyFile 证书文件对象
|
||||
* @param keyFile 证书文件对象
|
||||
* @return 退款操作结果
|
||||
*/
|
||||
WxPayRefundResult refund(WxPayRefundRequest request, File keyFile) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 微信支付-查询退款
|
||||
* 应用场景:
|
||||
* 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
|
||||
* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
|
||||
* 接口链接:https://api.mch.weixin.qq.com/pay/refundquery
|
||||
* </pre>
|
||||
* 以下四个参数四选一
|
||||
* @param transactionId 微信订单号
|
||||
* @param outTradeNo 商户订单号
|
||||
* @param outRefundNo 商户退款单号
|
||||
* @param refundId 微信退款单号
|
||||
* @return 退款信息
|
||||
*/
|
||||
WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 读取支付结果通知
|
||||
* 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
|
||||
*
|
||||
*/
|
||||
WxPayJsSDKCallback getJSSDKCallbackData(String xmlData) throws WxErrorException;
|
||||
|
||||
@@ -93,7 +114,6 @@ public interface WxMpPayService {
|
||||
* 计算Map键值对是否和签名相符,
|
||||
* 按照字段名的 ASCII 码从小到大排序(字典序)后,使用 URL 键值对的 格式(即 key1=value1&key2=value2...)拼接成字符串
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature);
|
||||
|
||||
@@ -102,13 +122,29 @@ public interface WxMpPayService {
|
||||
* <pre>
|
||||
* 文档详见:
|
||||
* 发送普通红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
|
||||
* 接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack
|
||||
* 发送裂变红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5&index=4
|
||||
* 接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack
|
||||
* </pre>
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @param keyFile 证书文件对象
|
||||
* @param keyFile 证书文件对象
|
||||
*/
|
||||
WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 查询红包记录
|
||||
* 用于商户对已发放的红包进行查询红包的具体信息,可支持普通红包和裂变包。
|
||||
* 请求Url https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo
|
||||
* 是否需要证书 是(证书及使用说明详见商户证书)
|
||||
* 请求方式 POST
|
||||
* </pre>
|
||||
* @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890
|
||||
* @param keyFile 证书文件对象
|
||||
*/
|
||||
WxPayRedpackQueryResult queryRedpack(String mchBillNo, File keyFile) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。
|
||||
@@ -118,8 +154,9 @@ public interface WxMpPayService {
|
||||
* 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
|
||||
* 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
|
||||
* </pre>
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @param keyFile 证书文件对象
|
||||
* @param keyFile 证书文件对象
|
||||
*/
|
||||
WxEntPayResult entPay(WxEntPayRequest request, File keyFile) throws WxErrorException;
|
||||
|
||||
@@ -130,8 +167,9 @@ public interface WxMpPayService {
|
||||
* 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3
|
||||
* 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo
|
||||
* </pre>
|
||||
*
|
||||
* @param partnerTradeNo 商户订单号
|
||||
* @param keyFile 证书文件对象
|
||||
* @param keyFile 证书文件对象
|
||||
*/
|
||||
WxEntPayQueryResult queryEntPay(String partnerTradeNo, File keyFile) throws WxErrorException;
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ public interface WxMpService {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 验证推送过来的消息的正确性
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=验证消息真实性
|
||||
* 验证消息的确来自微信服务器
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
|
||||
* </pre>
|
||||
*/
|
||||
boolean checkSignature(String timestamp, String nonce, String signature);
|
||||
@@ -36,7 +36,7 @@ public interface WxMpService {
|
||||
*
|
||||
* 程序员在非必要情况下尽量不要主动调用此方法
|
||||
*
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN
|
||||
* </pre>
|
||||
*
|
||||
* @param forceRefresh 强制刷新
|
||||
@@ -55,7 +55,7 @@ public interface WxMpService {
|
||||
* 获得jsapi_ticket
|
||||
* 获得时会检查jsapiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
|
||||
*
|
||||
* 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95
|
||||
* 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
|
||||
* </pre>
|
||||
*
|
||||
* @param forceRefresh 强制刷新
|
||||
@@ -66,7 +66,7 @@ public interface WxMpService {
|
||||
* <pre>
|
||||
* 创建调用jsapi时所需要的签名
|
||||
*
|
||||
* 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95
|
||||
* 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
|
||||
* </pre>
|
||||
*/
|
||||
WxJsapiSignature createJsapiSignature(String url) throws WxErrorException;
|
||||
@@ -75,7 +75,7 @@ public interface WxMpService {
|
||||
* <pre>
|
||||
* 上传群发用的图文消息,上传后才能群发图文消息
|
||||
*
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
|
||||
* </pre>
|
||||
*
|
||||
* @see #massGroupMessageSend(me.chanjar.weixin.mp.bean.WxMpMassTagMessage)
|
||||
@@ -86,7 +86,7 @@ public interface WxMpService {
|
||||
/**
|
||||
* <pre>
|
||||
* 上传群发用的视频,上传后才能群发视频消息
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
|
||||
* </pre>
|
||||
*
|
||||
* @see #massGroupMessageSend(me.chanjar.weixin.mp.bean.WxMpMassTagMessage)
|
||||
@@ -99,7 +99,7 @@ public interface WxMpService {
|
||||
* 分组群发消息
|
||||
* 如果发送图文消息,必须先使用 {@link #massNewsUpload(me.chanjar.weixin.mp.bean.WxMpMassNews)} 获得media_id,然后再发送
|
||||
* 如果发送视频消息,必须先使用 {@link #massVideoUpload(me.chanjar.weixin.mp.bean.WxMpMassVideo)} 获得media_id,然后再发送
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
|
||||
* </pre>
|
||||
*/
|
||||
WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException;
|
||||
@@ -109,7 +109,7 @@ public interface WxMpService {
|
||||
* 按openId列表群发消息
|
||||
* 如果发送图文消息,必须先使用 {@link #massNewsUpload(me.chanjar.weixin.mp.bean.WxMpMassNews)} 获得media_id,然后再发送
|
||||
* 如果发送视频消息,必须先使用 {@link #massVideoUpload(me.chanjar.weixin.mp.bean.WxMpMassVideo)} 获得media_id,然后再发送
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口
|
||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
|
||||
* </pre>
|
||||
*/
|
||||
WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException;
|
||||
@@ -263,84 +263,84 @@ public interface WxMpService {
|
||||
WxMpConfigStorage getWxMpConfigStorage();
|
||||
|
||||
/**
|
||||
* 返回客服接口方法实现类,以方便调用个其各种接口
|
||||
* 返回客服接口方法实现类,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpKefuService
|
||||
*/
|
||||
WxMpKefuService getKefuService();
|
||||
|
||||
/**
|
||||
* 返回素材相关接口方法的实现类对象,以方便调用个其各种接口
|
||||
* 返回素材相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpMaterialService
|
||||
*/
|
||||
WxMpMaterialService getMaterialService();
|
||||
|
||||
/**
|
||||
* 返回菜单相关接口方法的实现类对象,以方便调用个其各种接口
|
||||
* 返回菜单相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpMenuService
|
||||
*/
|
||||
WxMpMenuService getMenuService();
|
||||
|
||||
/**
|
||||
* 返回用户相关接口方法的实现类对象,以方便调用个其各种接口
|
||||
* 返回用户相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpUserService
|
||||
*/
|
||||
WxMpUserService getUserService();
|
||||
|
||||
/**
|
||||
* 返回用户标签相关接口方法的实现类对象,以方便调用个其各种接口
|
||||
* 返回用户标签相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpUserTagService
|
||||
*/
|
||||
WxMpUserTagService getUserTagService();
|
||||
|
||||
/**
|
||||
* 返回二维码相关接口方法的实现类对象,以方便调用个其各种接口
|
||||
* 返回二维码相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpQrcodeService
|
||||
*/
|
||||
WxMpQrcodeService getQrcodeService();
|
||||
|
||||
/**
|
||||
* 返回卡券相关接口方法的实现类对象,以方便调用个其各种接口
|
||||
* 返回卡券相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpCardService
|
||||
*/
|
||||
WxMpCardService getCardService();
|
||||
|
||||
/**
|
||||
* 返回微信支付相关接口方法的实现类对象,以方便调用个其各种接口
|
||||
* 返回微信支付相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpPayService
|
||||
*/
|
||||
WxMpPayService getPayService();
|
||||
|
||||
/**
|
||||
* 返回数据分析统计相关接口方法的实现类对象,以方便调用个其各种接口
|
||||
* 返回数据分析统计相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpDataCubeService
|
||||
*/
|
||||
WxMpDataCubeService getDataCubeService();
|
||||
|
||||
/**
|
||||
* 返回用户黑名单管理相关接口方法的实现类对象,以方便调用其各种接口
|
||||
* 返回用户黑名单管理相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpUserBlacklistService
|
||||
*/
|
||||
WxMpUserBlacklistService getBlackListService();
|
||||
|
||||
/**
|
||||
* 返回门店管理相关接口方法的实现类对象,以方便调用其各种接口
|
||||
* 返回门店管理相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpStoreService
|
||||
*/
|
||||
WxMpStoreService getStoreService();
|
||||
|
||||
/**
|
||||
* 返回模板消息相关接口方法的实现类对象,以方便调用其各种接口
|
||||
* 返回模板消息相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpTemplateMsgService
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.chanjar.weixin.mp.api.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -29,11 +30,6 @@ public class WxMpCardServiceImpl implements WxMpCardService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class);
|
||||
|
||||
/**
|
||||
* 全局的是否正在刷新卡券api_ticket的锁
|
||||
*/
|
||||
private final Object globalCardApiTicketRefreshLock = new Object();
|
||||
|
||||
private WxMpService wxMpService;
|
||||
|
||||
public WxMpCardServiceImpl(WxMpService wxMpService) {
|
||||
@@ -66,21 +62,25 @@ public class WxMpCardServiceImpl implements WxMpCardService {
|
||||
*/
|
||||
@Override
|
||||
public String getCardApiTicket(boolean forceRefresh) throws WxErrorException {
|
||||
if (forceRefresh) {
|
||||
this.wxMpService.getWxMpConfigStorage().expireCardApiTicket();
|
||||
}
|
||||
if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) {
|
||||
synchronized (this.globalCardApiTicketRefreshLock) {
|
||||
if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) {
|
||||
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card";
|
||||
String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
|
||||
String cardApiTicket = tmpJsonObject.get("ticket").getAsString();
|
||||
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
|
||||
this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds);
|
||||
}
|
||||
Lock lock = wxMpService.getWxMpConfigStorage().getCardApiTicketLock();
|
||||
try {
|
||||
lock.lock();
|
||||
|
||||
if (forceRefresh) {
|
||||
this.wxMpService.getWxMpConfigStorage().expireCardApiTicket();
|
||||
}
|
||||
|
||||
if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) {
|
||||
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card";
|
||||
String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
|
||||
String cardApiTicket = tmpJsonObject.get("ticket").getAsString();
|
||||
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
|
||||
this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return this.wxMpService.getWxMpConfigStorage().getCardApiTicket();
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package me.chanjar.weixin.mp.api.impl;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import me.chanjar.weixin.common.bean.menu.WxMenu;
|
||||
import me.chanjar.weixin.common.exception.WxErrorException;
|
||||
import me.chanjar.weixin.mp.api.WxMpMenuService;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
|
||||
import me.chanjar.weixin.mp.bean.menu.WxMpSelfMenuInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Created by Binary Wang on 2016/7/21.
|
||||
@@ -14,7 +15,7 @@ import me.chanjar.weixin.mp.api.WxMpService;
|
||||
public class WxMpMenuServiceImpl implements WxMpMenuService {
|
||||
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/menu";
|
||||
private static Logger log = LoggerFactory
|
||||
.getLogger(WxMpMenuServiceImpl.class);
|
||||
.getLogger(WxMpMenuServiceImpl.class);
|
||||
|
||||
private WxMpService wxMpService;
|
||||
|
||||
@@ -74,10 +75,17 @@ public class WxMpMenuServiceImpl implements WxMpMenuService {
|
||||
} catch (WxErrorException e) {
|
||||
// 46003 不存在的菜单数据 46002 不存在的菜单版本
|
||||
if (e.getError().getErrorCode() == 46003
|
||||
|| e.getError().getErrorCode() == 46002) {
|
||||
|| e.getError().getErrorCode() == 46002) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMpGetSelfMenuInfoResult getSelfMenuInfo() throws WxErrorException {
|
||||
String url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info";
|
||||
String resultContent = this.wxMpService.get(url, null);
|
||||
return WxMpGetSelfMenuInfoResult.fromJson(resultContent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import me.chanjar.weixin.common.util.xml.XStreamInitializer;
|
||||
import me.chanjar.weixin.mp.api.WxMpPayService;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback;
|
||||
import me.chanjar.weixin.mp.bean.pay.result.WxPayOrderCloseResult;
|
||||
import me.chanjar.weixin.mp.bean.pay.request.*;
|
||||
import me.chanjar.weixin.mp.bean.pay.result.*;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
@@ -42,13 +41,11 @@ import java.util.*;
|
||||
*/
|
||||
public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
|
||||
protected final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
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[] REFUND_ACCOUNT = new String[]{"REFUND_SOURCE_RECHARGE_FUNDS",
|
||||
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 WxMpService wxMpService;
|
||||
|
||||
public WxMpPayServiceImpl(WxMpService wxMpService) {
|
||||
@@ -57,7 +54,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
|
||||
@Override
|
||||
public WxPayRefundResult refund(WxPayRefundRequest request, File keyFile)
|
||||
throws WxErrorException {
|
||||
throws WxErrorException {
|
||||
checkParameters(request);
|
||||
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
@@ -67,7 +64,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
|
||||
String partnerId = this.wxMpService.getWxMpConfigStorage().getPartnerId();
|
||||
request.setMchId(partnerId);
|
||||
request.setNonceStr( System.currentTimeMillis() + "");
|
||||
request.setNonceStr(System.currentTimeMillis() + "");
|
||||
request.setOpUserId(partnerId);
|
||||
String sign = this.createSign(BeanUtils.xmlBean2Map(request), this.wxMpService.getWxMpConfigStorage().getPartnerKey());
|
||||
request.setSign(sign);
|
||||
@@ -79,11 +76,45 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) throws WxErrorException {
|
||||
if ((StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo) && StringUtils.isBlank(outRefundNo) && StringUtils.isBlank(refundId)) ||
|
||||
(StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(outTradeNo) && StringUtils.isNotBlank(outRefundNo) && StringUtils.isNotBlank(refundId))) {
|
||||
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();
|
||||
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
|
||||
request.setTransactionId(StringUtils.trimToNull(transactionId));
|
||||
request.setOutRefundNo(StringUtils.trimToNull(outRefundNo));
|
||||
request.setRefundId(StringUtils.trimToNull(refundId));
|
||||
|
||||
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);
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void checkResult(WxPayBaseResult result) throws WxErrorException {
|
||||
if (!"SUCCESS".equalsIgnoreCase(result.getReturnCode())
|
||||
|| !"SUCCESS".equalsIgnoreCase(result.getResultCode())) {
|
||||
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1)
|
||||
.setErrorMsg("返回代码:" + result.getReturnCode() + ", 返回信息: "
|
||||
.setErrorMsg("返回代码: " + result.getReturnCode() + ", 返回信息: "
|
||||
+ result.getReturnMsg() + ", 结果代码: " + result.getResultCode() + ", 错误代码: "
|
||||
+ result.getErrCode() + ", 错误详情: " + result.getErrCodeDes())
|
||||
.build());
|
||||
@@ -94,7 +125,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
BeanUtils.checkRequiredFields(request);
|
||||
|
||||
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) + "其中之一");
|
||||
}
|
||||
}
|
||||
@@ -118,14 +149,14 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
|
||||
@Override
|
||||
public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm,
|
||||
String signature) {
|
||||
String signature) {
|
||||
return signature.equals(this.createSign(kvm,
|
||||
this.wxMpService.getWxMpConfigStorage().getPartnerKey()));
|
||||
this.wxMpService.getWxMpConfigStorage().getPartnerKey()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile)
|
||||
throws WxErrorException {
|
||||
throws WxErrorException {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxPaySendRedpackRequest.class);
|
||||
xstream.processAnnotations(WxPaySendRedpackResult.class);
|
||||
@@ -136,7 +167,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
request.setNonceStr(System.currentTimeMillis() + "");
|
||||
|
||||
String sign = this.createSign(BeanUtils.xmlBean2Map(request),
|
||||
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
|
||||
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
|
||||
request.setSign(sign);
|
||||
|
||||
String url = PAY_BASE_URL + "/mmpaymkttransfers/sendredpack";
|
||||
@@ -147,25 +178,52 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
|
||||
String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), mchId);
|
||||
WxPaySendRedpackResult result = (WxPaySendRedpackResult) xstream
|
||||
.fromXML(responseContent);
|
||||
.fromXML(responseContent);
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayRedpackQueryResult queryRedpack(String mchBillNo, File keyFile) throws WxErrorException {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxPayRedpackQueryRequest.class);
|
||||
xstream.processAnnotations(WxPayRedpackQueryResult.class);
|
||||
|
||||
WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest();
|
||||
request.setMchBillNo(mchBillNo);
|
||||
request.setBillType("MCHT");
|
||||
|
||||
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);
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
|
||||
*
|
||||
* @param packageParams 原始参数
|
||||
* @param signKey 加密Key(即 商户Key)
|
||||
* @param signKey 加密Key(即 商户Key)
|
||||
* @return 签名字符串
|
||||
*/
|
||||
private String createSign(Map<String, String> packageParams, String signKey) {
|
||||
SortedMap<String, String> sortedMap = new TreeMap<>(packageParams);
|
||||
|
||||
StringBuffer toSign = new StringBuffer();
|
||||
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)) {
|
||||
&& !"key".equals(key)) {
|
||||
toSign.append(key + "=" + value + "&");
|
||||
}
|
||||
}
|
||||
@@ -237,7 +295,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
|
||||
@Override
|
||||
public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request)
|
||||
throws WxErrorException {
|
||||
throws WxErrorException {
|
||||
checkParameters(request);
|
||||
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
@@ -249,14 +307,14 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
request.setNonceStr(System.currentTimeMillis() + "");
|
||||
|
||||
String sign = this.createSign(BeanUtils.xmlBean2Map(request),
|
||||
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
|
||||
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
|
||||
request.setSign(sign);
|
||||
|
||||
String url = PAY_BASE_URL + "/pay/unifiedorder";
|
||||
|
||||
String responseContent = this.executeRequest(url, xstream.toXML(request));
|
||||
WxPayUnifiedOrderResult result = (WxPayUnifiedOrderResult) xstream
|
||||
.fromXML(responseContent);
|
||||
.fromXML(responseContent);
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
@@ -264,7 +322,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
private void checkParameters(WxPayUnifiedOrderRequest request) throws WxErrorException {
|
||||
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) + "其中之一");
|
||||
}
|
||||
|
||||
@@ -283,7 +341,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
String prepayId = unifiedOrderResult.getPrepayId();
|
||||
if (StringUtils.isBlank(prepayId)) {
|
||||
throw new RuntimeException(String.format("Failed to get prepay id due to error code '%s'(%s).",
|
||||
unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes()));
|
||||
unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes()));
|
||||
}
|
||||
|
||||
Map<String, String> payInfo = new HashMap<>();
|
||||
@@ -347,7 +405,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
return result;
|
||||
}
|
||||
|
||||
private String executeRequest( String url, String requestStr) throws WxErrorException {
|
||||
private String executeRequest(String url, String requestStr) throws WxErrorException {
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
if (this.wxMpService.getHttpProxy() != null) {
|
||||
httpPost.setConfig(RequestConfig.custom().setProxy(this.wxMpService.getHttpProxy()).build());
|
||||
@@ -358,25 +416,25 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
|
||||
try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
|
||||
String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
|
||||
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",url, requestStr, result);
|
||||
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result);
|
||||
return result;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", url, requestStr, e.getMessage());
|
||||
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg(e.getMessage()).build(), e);
|
||||
}finally {
|
||||
} finally {
|
||||
httpPost.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
private String executeRequestWithKeyFile( String url, File keyFile, String requestStr, String mchId) throws WxErrorException {
|
||||
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());
|
||||
|
||||
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
|
||||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
|
||||
new DefaultHostnameVerifier());
|
||||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null,
|
||||
new DefaultHostnameVerifier());
|
||||
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
if (this.wxMpService.getHttpProxy() != null) {
|
||||
@@ -387,10 +445,10 @@ public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
httpPost.setEntity(new StringEntity(new String(requestStr.getBytes("UTF-8"), "ISO-8859-1")));
|
||||
try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
|
||||
String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
|
||||
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",url, requestStr, result);
|
||||
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result);
|
||||
return result;
|
||||
}
|
||||
}finally {
|
||||
} finally {
|
||||
httpPost.releaseConnection();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
public class WxMpServiceImpl implements WxMpService {
|
||||
|
||||
@@ -35,16 +36,6 @@ public class WxMpServiceImpl implements WxMpService {
|
||||
|
||||
protected final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* 全局的是否正在刷新access token的锁
|
||||
*/
|
||||
private final Object globalAccessTokenRefreshLock = new Object();
|
||||
|
||||
/**
|
||||
* 全局的是否正在刷新jsapi_ticket的锁
|
||||
*/
|
||||
private final Object globalJsapiTicketRefreshLock = new Object();
|
||||
|
||||
private WxMpConfigStorage configStorage;
|
||||
|
||||
private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this);
|
||||
@@ -98,38 +89,42 @@ public class WxMpServiceImpl implements WxMpService {
|
||||
|
||||
@Override
|
||||
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
|
||||
if (forceRefresh) {
|
||||
this.configStorage.expireAccessToken();
|
||||
}
|
||||
if (this.configStorage.isAccessTokenExpired()) {
|
||||
synchronized (this.globalAccessTokenRefreshLock) {
|
||||
if (this.configStorage.isAccessTokenExpired()) {
|
||||
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
|
||||
"&appid=" + this.configStorage.getAppId() + "&secret="
|
||||
+ this.configStorage.getSecret();
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
if (this.httpProxy != null) {
|
||||
RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build();
|
||||
httpGet.setConfig(config);
|
||||
}
|
||||
try (CloseableHttpResponse response = getHttpclient().execute(httpGet)) {
|
||||
String resultContent = new BasicResponseHandler().handleResponse(response);
|
||||
WxError error = WxError.fromJson(resultContent);
|
||||
if (error.getErrorCode() != 0) {
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||
this.configStorage.updateAccessToken(accessToken.getAccessToken(),
|
||||
accessToken.getExpiresIn());
|
||||
}finally {
|
||||
httpGet.releaseConnection();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
Lock lock = this.configStorage.getAccessTokenLock();
|
||||
try {
|
||||
lock.lock();
|
||||
|
||||
if (forceRefresh) {
|
||||
this.configStorage.expireAccessToken();
|
||||
}
|
||||
|
||||
if (this.configStorage.isAccessTokenExpired()) {
|
||||
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
|
||||
"&appid=" + this.configStorage.getAppId() + "&secret="
|
||||
+ this.configStorage.getSecret();
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
if (this.httpProxy != null) {
|
||||
RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build();
|
||||
httpGet.setConfig(config);
|
||||
}
|
||||
try (CloseableHttpResponse response = getHttpclient().execute(httpGet)) {
|
||||
String resultContent = new BasicResponseHandler().handleResponse(response);
|
||||
WxError error = WxError.fromJson(resultContent);
|
||||
if (error.getErrorCode() != 0) {
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||
this.configStorage.updateAccessToken(accessToken.getAccessToken(),
|
||||
accessToken.getExpiresIn());
|
||||
}finally {
|
||||
httpGet.releaseConnection();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return this.configStorage.getAccessToken();
|
||||
}
|
||||
@@ -141,22 +136,25 @@ public class WxMpServiceImpl implements WxMpService {
|
||||
|
||||
@Override
|
||||
public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
|
||||
if (forceRefresh) {
|
||||
this.configStorage.expireJsapiTicket();
|
||||
}
|
||||
Lock lock = this.configStorage.getJsapiTicketLock();
|
||||
try {
|
||||
lock.lock();
|
||||
|
||||
if (this.configStorage.isJsapiTicketExpired()) {
|
||||
synchronized (this.globalJsapiTicketRefreshLock) {
|
||||
if (this.configStorage.isJsapiTicketExpired()) {
|
||||
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
|
||||
String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
|
||||
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
|
||||
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
|
||||
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
|
||||
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
|
||||
this.configStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds);
|
||||
}
|
||||
if (forceRefresh) {
|
||||
this.configStorage.expireJsapiTicket();
|
||||
}
|
||||
|
||||
if (this.configStorage.isJsapiTicketExpired()) {
|
||||
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
|
||||
String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
|
||||
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
|
||||
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
|
||||
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
|
||||
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
|
||||
this.configStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return this.configStorage.getJsapiTicket();
|
||||
}
|
||||
@@ -370,9 +368,7 @@ public class WxMpServiceImpl implements WxMpService {
|
||||
return result;
|
||||
} catch (WxErrorException e) {
|
||||
WxError error = e.getError();
|
||||
/**
|
||||
* -1 系统繁忙, 1000ms后重试
|
||||
*/
|
||||
// -1 系统繁忙, 1000ms后重试
|
||||
if (error.getErrorCode() == -1) {
|
||||
int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
|
||||
try {
|
||||
@@ -411,8 +407,11 @@ public class WxMpServiceImpl implements WxMpService {
|
||||
if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) {
|
||||
// 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token
|
||||
this.configStorage.expireAccessToken();
|
||||
return this.execute(executor, uri, data);
|
||||
if(this.configStorage.autoRefreshToken()){
|
||||
return this.execute(executor, uri, data);
|
||||
}
|
||||
}
|
||||
|
||||
if (error.getErrorCode() != 0) {
|
||||
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data,
|
||||
error);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package me.chanjar.weixin.mp.bean;
|
||||
|
||||
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
|
||||
|
||||
/**
|
||||
* OpenId列表群发的消息
|
||||
* openid列表群发的消息
|
||||
*
|
||||
* @author chanjarster
|
||||
*/
|
||||
@@ -64,17 +64,26 @@ public class WxMpMassOpenIdsMessage implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenId列表,最多支持10,000个
|
||||
* openid列表,最多支持10,000个
|
||||
*/
|
||||
public List<String> getToUsers() {
|
||||
return this.toUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加OpenId,最多支持10,000个
|
||||
* @param openId
|
||||
* 添加openid,最多支持10,000个
|
||||
* @param openid
|
||||
*/
|
||||
public void addUser(String openId) {
|
||||
this.toUsers.add(openId);
|
||||
public void addUser(String openid) {
|
||||
this.toUsers.add(openid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供set方法,方便客户端直接设置所有群发对象的openid列表
|
||||
* @param toUsers
|
||||
*/
|
||||
public void setToUsers(List<String> toUsers) {
|
||||
this.toUsers = toUsers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ public class WxDataCubeArticleTotalDetail {
|
||||
* 统计的日期,在getarticletotal接口中,ref_date指的是文章群发出日期, 而stat_date是数据统计日期
|
||||
*/
|
||||
@SerializedName("stat_date")
|
||||
private Integer statDate;
|
||||
private String statDate;
|
||||
|
||||
/**
|
||||
* target_user
|
||||
@@ -191,11 +191,11 @@ public class WxDataCubeArticleTotalDetail {
|
||||
@SerializedName("feed_share_from_other_cnt")
|
||||
private Integer feedShareFromOtherCnt;
|
||||
|
||||
public Integer getStatDate() {
|
||||
public String getStatDate() {
|
||||
return this.statDate;
|
||||
}
|
||||
|
||||
public void setStatDate(Integer statDate) {
|
||||
public void setStatDate(String statDate) {
|
||||
this.statDate = statDate;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ public class WxMpMaterialNews implements Serializable {
|
||||
/**
|
||||
* <pre>
|
||||
* 群发图文消息article
|
||||
* 1. thumbMediaId (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得
|
||||
* 1. thumbMediaId (必填) 图文消息的封面图片素材id(必须是永久mediaID)
|
||||
* 2. author 图文消息的作者
|
||||
* 3. title (必填) 图文消息的标题
|
||||
* 4. contentSourceUrl 在图文消息页面点击“阅读原文”后的页面链接
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package me.chanjar.weixin.mp.bean.menu;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import me.chanjar.weixin.common.util.ToStringUtils;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Created by Binary Wang on 2016-11-25.
|
||||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
|
||||
* </pre>
|
||||
*/
|
||||
public class WxMpGetSelfMenuInfoResult {
|
||||
@SerializedName("selfmenu_info")
|
||||
private WxMpSelfMenuInfo selfMenuInfo;
|
||||
|
||||
@SerializedName("is_menu_open")
|
||||
private Integer isMenuOpen;
|
||||
|
||||
public static WxMpGetSelfMenuInfoResult fromJson(String json) {
|
||||
return WxGsonBuilder.create().fromJson(json, WxMpGetSelfMenuInfoResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
public WxMpSelfMenuInfo getSelfMenuInfo() {
|
||||
return selfMenuInfo;
|
||||
}
|
||||
|
||||
public void setSelfMenuInfo(WxMpSelfMenuInfo selfMenuInfo) {
|
||||
this.selfMenuInfo = selfMenuInfo;
|
||||
}
|
||||
|
||||
public Integer getIsMenuOpen() {
|
||||
return isMenuOpen;
|
||||
}
|
||||
|
||||
public void setIsMenuOpen(Integer isMenuOpen) {
|
||||
this.isMenuOpen = isMenuOpen;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
package me.chanjar.weixin.mp.bean.menu;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import me.chanjar.weixin.common.util.ToStringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Created by Binary Wang on 2016-11-25.
|
||||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
|
||||
* </pre>
|
||||
*/
|
||||
public class WxMpSelfMenuInfo {
|
||||
/**
|
||||
* 菜单按钮
|
||||
*/
|
||||
@SerializedName("button")
|
||||
private List<WxMpSelfMenuButton> buttons;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
public static class WxMpSelfMenuButton {
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 菜单的类型,公众平台官网上能够设置的菜单类型有view(跳转网页)、text(返回文本,下同)、img、photo、video、voice。
|
||||
* 使用API设置的则有8种,详见<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN">《自定义菜单创建接口》</a>
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("type")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 菜单名称
|
||||
*/
|
||||
@SerializedName("name")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 对于不同的菜单类型,value的值意义不同。
|
||||
* 官网上设置的自定义菜单:
|
||||
* <li>Text:保存文字到value;
|
||||
* <li>Img、voice:保存mediaID到value;
|
||||
* <li>Video:保存视频下载链接到value;
|
||||
* <li>News:保存图文消息到news_info,同时保存mediaID到value;
|
||||
* <li>View:保存链接到url。</li>
|
||||
*
|
||||
* 使用API设置的自定义菜单:
|
||||
* <li>click、scancode_push、scancode_waitmsg、pic_sysphoto、pic_photo_or_album、 pic_weixin、location_select:保存值到key;
|
||||
* <li>view:保存链接到url
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("key")
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* @see #key
|
||||
*/
|
||||
@SerializedName("url")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* @see #key
|
||||
*/
|
||||
@SerializedName("value")
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* 子菜单信息
|
||||
*/
|
||||
@SerializedName("sub_button")
|
||||
private SubButtons subButtons;
|
||||
|
||||
public SubButtons getSubButtons() {
|
||||
return subButtons;
|
||||
}
|
||||
|
||||
public void setSubButtons(SubButtons subButtons) {
|
||||
this.subButtons = subButtons;
|
||||
}
|
||||
|
||||
public static class SubButtons {
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
@SerializedName("list")
|
||||
private List<WxMpSelfMenuButton> subButtons = new ArrayList<>();
|
||||
|
||||
public List<WxMpSelfMenuButton> getSubButtons() {
|
||||
return subButtons;
|
||||
}
|
||||
|
||||
public void setSubButtons(List<WxMpSelfMenuButton> subButtons) {
|
||||
this.subButtons = subButtons;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 图文消息的信息
|
||||
*/
|
||||
@SerializedName("news_info")
|
||||
private NewsInfo newsInfo;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public NewsInfo getNewsInfo() {
|
||||
return newsInfo;
|
||||
}
|
||||
|
||||
public void setNewsInfo(NewsInfo newsInfo) {
|
||||
this.newsInfo = newsInfo;
|
||||
}
|
||||
|
||||
public static class NewsInfo {
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
@SerializedName("list")
|
||||
private List<NewsInButton> news = new ArrayList<>();
|
||||
|
||||
public List<NewsInButton> getNews() {
|
||||
return news;
|
||||
}
|
||||
|
||||
public void setNews(List<NewsInButton> news) {
|
||||
this.news = news;
|
||||
}
|
||||
|
||||
public static class NewsInButton {
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 图文消息的标题
|
||||
*/
|
||||
@SerializedName("title")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 摘要
|
||||
*/
|
||||
@SerializedName("digest")
|
||||
private String digest;
|
||||
|
||||
/**
|
||||
* 作者
|
||||
*/
|
||||
@SerializedName("author")
|
||||
private String author;
|
||||
|
||||
/**
|
||||
* show_cover
|
||||
* 是否显示封面,0为不显示,1为显示
|
||||
*/
|
||||
@SerializedName("show_cover")
|
||||
private Integer showCover;
|
||||
|
||||
/**
|
||||
* 封面图片的URL
|
||||
*/
|
||||
@SerializedName("cover_url")
|
||||
private String coverUrl;
|
||||
|
||||
/**
|
||||
* 正文的URL
|
||||
*/
|
||||
@SerializedName("content_url")
|
||||
private String contentUrl;
|
||||
|
||||
/**
|
||||
* 原文的URL,若置空则无查看原文入口
|
||||
*/
|
||||
@SerializedName("source_url")
|
||||
private String sourceUrl;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getDigest() {
|
||||
return digest;
|
||||
}
|
||||
|
||||
public void setDigest(String digest) {
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Integer getShowCover() {
|
||||
return showCover;
|
||||
}
|
||||
|
||||
public void setShowCover(Integer showCover) {
|
||||
this.showCover = showCover;
|
||||
}
|
||||
|
||||
public String getCoverUrl() {
|
||||
return coverUrl;
|
||||
}
|
||||
|
||||
public void setCoverUrl(String coverUrl) {
|
||||
this.coverUrl = coverUrl;
|
||||
}
|
||||
|
||||
public String getContentUrl() {
|
||||
return contentUrl;
|
||||
}
|
||||
|
||||
public void setContentUrl(String contentUrl) {
|
||||
this.contentUrl = contentUrl;
|
||||
}
|
||||
|
||||
public String getSourceUrl() {
|
||||
return sourceUrl;
|
||||
}
|
||||
|
||||
public void setSourceUrl(String sourceUrl) {
|
||||
this.sourceUrl = sourceUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -263,6 +263,118 @@ public class WxMpXmlMessage implements Serializable {
|
||||
@XStreamAlias("FailReason")
|
||||
private String failReason;
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// 微信硬件平台相关事件推送
|
||||
///////////////////////////////////////
|
||||
/**
|
||||
* 设备类型,目前为"公众账号原始ID"
|
||||
*/
|
||||
@XStreamAlias("DeviceType")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 设备ID,第三方提供
|
||||
*/
|
||||
@XStreamAlias("DeviceID")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String deviceId;
|
||||
|
||||
|
||||
@XStreamAlias("HardWare")
|
||||
private HardWare hardWare = new HardWare();
|
||||
|
||||
/**
|
||||
* 请求类型:0:退订设备状态;1:心跳;(心跳的处理方式跟订阅一样)2:订阅设备状态
|
||||
*/
|
||||
@XStreamAlias("OpType")
|
||||
private Integer opType;
|
||||
|
||||
/**
|
||||
* 设备状态:0:未连接;1:已连接
|
||||
*/
|
||||
@XStreamAlias("DeviceStatus")
|
||||
private Integer deviceStatus;
|
||||
|
||||
public static WxMpXmlMessage fromXml(String xml) {
|
||||
return XStreamTransformer.fromXml(WxMpXmlMessage.class, xml);
|
||||
}
|
||||
|
||||
public static WxMpXmlMessage fromXml(InputStream is) {
|
||||
return XStreamTransformer.fromXml(WxMpXmlMessage.class, is);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从加密字符串转换
|
||||
*
|
||||
* @param encryptedXml
|
||||
* @param wxMpConfigStorage
|
||||
* @param timestamp
|
||||
* @param nonce
|
||||
* @param msgSignature
|
||||
*/
|
||||
public static WxMpXmlMessage fromEncryptedXml(String encryptedXml,
|
||||
WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce,
|
||||
String msgSignature) {
|
||||
WxMpCryptUtil cryptUtil = new WxMpCryptUtil(wxMpConfigStorage);
|
||||
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce,
|
||||
encryptedXml);
|
||||
return fromXml(plainText);
|
||||
}
|
||||
|
||||
public static WxMpXmlMessage fromEncryptedXml(InputStream is,
|
||||
WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce,
|
||||
String msgSignature) {
|
||||
try {
|
||||
return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage,
|
||||
timestamp, nonce, msgSignature);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Integer getOpType() {
|
||||
return opType;
|
||||
}
|
||||
|
||||
public void setOpType(Integer opType) {
|
||||
this.opType = opType;
|
||||
}
|
||||
|
||||
public Integer getDeviceStatus() {
|
||||
|
||||
return deviceStatus;
|
||||
}
|
||||
|
||||
public void setDeviceStatus(Integer deviceStatus) {
|
||||
this.deviceStatus = deviceStatus;
|
||||
}
|
||||
|
||||
public HardWare getHardWare() {
|
||||
return hardWare;
|
||||
}
|
||||
|
||||
public void setHardWare(HardWare hardWare) {
|
||||
this.hardWare = hardWare;
|
||||
}
|
||||
|
||||
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 Long getExpiredTime() {
|
||||
return this.expiredTime;
|
||||
}
|
||||
@@ -346,7 +458,6 @@ public class WxMpXmlMessage implements Serializable {
|
||||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_LINK}
|
||||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT}
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public String getMsgType() {
|
||||
return this.msgType;
|
||||
@@ -537,43 +648,6 @@ public class WxMpXmlMessage implements Serializable {
|
||||
this.fromUser = fromUser;
|
||||
}
|
||||
|
||||
public static WxMpXmlMessage fromXml(String xml) {
|
||||
return XStreamTransformer.fromXml(WxMpXmlMessage.class, xml);
|
||||
}
|
||||
|
||||
public static WxMpXmlMessage fromXml(InputStream is) {
|
||||
return XStreamTransformer.fromXml(WxMpXmlMessage.class, is);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从加密字符串转换
|
||||
*
|
||||
* @param encryptedXml
|
||||
* @param wxMpConfigStorage
|
||||
* @param timestamp
|
||||
* @param nonce
|
||||
* @param msgSignature
|
||||
*/
|
||||
public static WxMpXmlMessage fromEncryptedXml(String encryptedXml,
|
||||
WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce,
|
||||
String msgSignature) {
|
||||
WxMpCryptUtil cryptUtil = new WxMpCryptUtil(wxMpConfigStorage);
|
||||
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce,
|
||||
encryptedXml);
|
||||
return fromXml(plainText);
|
||||
}
|
||||
|
||||
public static WxMpXmlMessage fromEncryptedXml(InputStream is,
|
||||
WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce,
|
||||
String msgSignature) {
|
||||
try {
|
||||
return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage,
|
||||
timestamp, nonce, msgSignature);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
@@ -683,7 +757,7 @@ public class WxMpXmlMessage implements Serializable {
|
||||
}
|
||||
|
||||
public void setSendLocationInfo(
|
||||
WxMpXmlMessage.SendLocationInfo sendLocationInfo) {
|
||||
WxMpXmlMessage.SendLocationInfo sendLocationInfo) {
|
||||
this.sendLocationInfo = sendLocationInfo;
|
||||
}
|
||||
|
||||
@@ -719,21 +793,62 @@ public class WxMpXmlMessage implements Serializable {
|
||||
this.fromKfAccount = fromKfAccount;
|
||||
}
|
||||
|
||||
@XStreamAlias("ScanCodeInfo")
|
||||
public static class ScanCodeInfo {
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
@XStreamAlias("HardWare")
|
||||
public static class HardWare {
|
||||
/**
|
||||
* 消息展示,目前支持myrank(排行榜)
|
||||
*/
|
||||
@XStreamAlias("MessageView")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String messageView;
|
||||
/**
|
||||
* 消息点击动作,目前支持ranklist(点击跳转排行榜)
|
||||
*/
|
||||
@XStreamAlias("MessageAction")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String messageAction;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
public String getMessageView() {
|
||||
return messageView;
|
||||
}
|
||||
|
||||
public void setMessageView(String messageView) {
|
||||
this.messageView = messageView;
|
||||
}
|
||||
|
||||
public String getMessageAction() {
|
||||
return messageAction;
|
||||
}
|
||||
|
||||
public void setMessageAction(String messageAction) {
|
||||
this.messageAction = messageAction;
|
||||
}
|
||||
}
|
||||
|
||||
@XStreamAlias("ScanCodeInfo")
|
||||
public static class ScanCodeInfo {
|
||||
@XStreamAlias("ScanType")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String scanType;
|
||||
|
||||
@XStreamAlias("ScanResult")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String scanResult;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描类型,一般是qrcode
|
||||
*/
|
||||
@@ -761,17 +876,16 @@ public class WxMpXmlMessage implements Serializable {
|
||||
|
||||
@XStreamAlias("SendPicsInfo")
|
||||
public static class SendPicsInfo {
|
||||
@XStreamAlias("PicList")
|
||||
protected final List<Item> picList = new ArrayList<>();
|
||||
@XStreamAlias("Count")
|
||||
private Long count;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
@XStreamAlias("Count")
|
||||
private Long count;
|
||||
|
||||
@XStreamAlias("PicList")
|
||||
protected final List<Item> picList = new ArrayList<>();
|
||||
|
||||
public Long getCount() {
|
||||
return this.count;
|
||||
}
|
||||
@@ -786,15 +900,15 @@ public class WxMpXmlMessage implements Serializable {
|
||||
|
||||
@XStreamAlias("item")
|
||||
public static class Item {
|
||||
@XStreamAlias("PicMd5Sum")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String picMd5Sum;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
@XStreamAlias("PicMd5Sum")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String picMd5Sum;
|
||||
|
||||
public String getPicMd5Sum() {
|
||||
return this.picMd5Sum;
|
||||
}
|
||||
@@ -873,9 +987,4 @@ public class WxMpXmlMessage implements Serializable {
|
||||
this.poiname = poiname;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package me.chanjar.weixin.mp.bean.pay.request;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 注释中各行对应含义:
|
||||
* 字段名
|
||||
* 字段
|
||||
* 必填
|
||||
* 示例值
|
||||
* 类型
|
||||
* 说明
|
||||
* Created by Binary Wang on 2016-11-28.
|
||||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("xml")
|
||||
public class WxPayRedpackQueryRequest extends WxPayBaseRequest {
|
||||
/**
|
||||
* 商户订单号
|
||||
* mch_billno
|
||||
* 是
|
||||
* 10000098201411111234567890
|
||||
* String(28)
|
||||
* 商户发放红包的商户订单号
|
||||
*/
|
||||
@XStreamAlias("mch_billno")
|
||||
private String mchBillNo;
|
||||
|
||||
/**
|
||||
* 订单类型
|
||||
* bill_type
|
||||
* 是
|
||||
* MCHT
|
||||
* String(32)
|
||||
* MCHT:通过商户订单号获取红包信息。
|
||||
*/
|
||||
@XStreamAlias("bill_type")
|
||||
private String billType;
|
||||
|
||||
public String getBillType() {
|
||||
return billType;
|
||||
}
|
||||
|
||||
public void setBillType(String billType) {
|
||||
this.billType = billType;
|
||||
}
|
||||
|
||||
public String getMchBillNo() {
|
||||
return mchBillNo;
|
||||
}
|
||||
|
||||
public void setMchBillNo(String mchBillNo) {
|
||||
this.mchBillNo = mchBillNo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package me.chanjar.weixin.mp.bean.pay.request;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Created by Binary Wang on 2016-11-24.
|
||||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("xml")
|
||||
public class WxPayRefundQueryRequest 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>
|
||||
* 微信订单号
|
||||
* transaction_id
|
||||
* String(32)
|
||||
* 1217752501201407033233368018
|
||||
* 微信订单号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("transaction_id")
|
||||
private String transactionId;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 商户订单号
|
||||
* out_trade_no
|
||||
* String(32)
|
||||
* 1217752501201407033233368018
|
||||
* 商户系统内部的订单号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("out_trade_no")
|
||||
private String outTradeNo;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 商户退款单号
|
||||
* out_refund_no
|
||||
* String(32)
|
||||
* 1217752501201407033233368018
|
||||
* 商户侧传给微信的退款单号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("out_refund_no")
|
||||
private String outRefundNo;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 微信退款单号
|
||||
* refund_id
|
||||
* String(28)
|
||||
* 1217752501201407033233368018
|
||||
* 微信生成的退款单号,在申请退款接口有返回
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("refund_id")
|
||||
private String refundId;
|
||||
|
||||
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 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 getOutRefundNo() {
|
||||
return outRefundNo;
|
||||
}
|
||||
|
||||
public void setOutRefundNo(String outRefundNo) {
|
||||
this.outRefundNo = outRefundNo;
|
||||
}
|
||||
|
||||
public String getRefundId() {
|
||||
return refundId;
|
||||
}
|
||||
|
||||
public void setRefundId(String refundId) {
|
||||
this.refundId = refundId;
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ public class WxPaySendRedpackRequest {
|
||||
* 商户订单号(每个订单号必须唯一) 组成:mch_id+yyyymmdd+10位一天内不能重复的数字。 接口根据商户订单号支持重入,如出现超时可再调用。
|
||||
*/
|
||||
@XStreamAlias("mch_billno")
|
||||
private String mchBillno;
|
||||
private String mchBillNo;
|
||||
|
||||
/**
|
||||
* send_name
|
||||
@@ -157,12 +157,12 @@ public class WxPaySendRedpackRequest {
|
||||
@XStreamAlias("consume_mch_id")
|
||||
private String consumeMchId;
|
||||
|
||||
public String getMchBillno() {
|
||||
return this.mchBillno;
|
||||
public String getMchBillNo() {
|
||||
return mchBillNo;
|
||||
}
|
||||
|
||||
public void setMchBillno(String mchBillno) {
|
||||
this.mchBillno = mchBillno;
|
||||
public void setMchBillNo(String mchBillNo) {
|
||||
this.mchBillNo = mchBillNo;
|
||||
}
|
||||
|
||||
public String getSendName() {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package me.chanjar.weixin.mp.bean.pay.result;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 查询订单 返回结果对象
|
||||
|
||||
@@ -0,0 +1,405 @@
|
||||
package me.chanjar.weixin.mp.bean.pay.result;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 注释中各行对应含义:
|
||||
* 字段名
|
||||
* 字段
|
||||
* 必填
|
||||
* 示例值
|
||||
* 类型
|
||||
* 说明
|
||||
* Created by Binary Wang on 2016-11-28.
|
||||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
|
||||
* </pre>
|
||||
*/
|
||||
public class WxPayRedpackQueryResult extends WxPayBaseResult {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 商户订单号
|
||||
* mch_billno
|
||||
* 是
|
||||
* 10000098201411111234567890
|
||||
* String(28)
|
||||
* 商户使用查询API填写的商户单号的原路返回
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("mch_billno")
|
||||
private String mchBillNo;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 红包单号
|
||||
* detail_id
|
||||
* 是
|
||||
* 1000000000201503283103439304
|
||||
* String(32)
|
||||
* 使用API发放现金红包时返回的红包单号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("detail_id")
|
||||
private String detailId;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 红包状态
|
||||
* status
|
||||
* 是
|
||||
* RECEIVED
|
||||
* string(16)
|
||||
* SENDING:发放中,
|
||||
* SENT:已发放待领取,
|
||||
* FAILED:发放失败,
|
||||
* RECEIVED:已领取,
|
||||
* RFUND_ING:退款中,
|
||||
* REFUND:已退款
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 发放类型
|
||||
* send_type
|
||||
* 是
|
||||
* API
|
||||
* String(32)
|
||||
* API:通过API接口发放,
|
||||
* UPLOAD:通过上传文件方式发放,
|
||||
* ACTIVITY:通过活动方式发放
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("send_type")
|
||||
private String sendType;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 红包类型
|
||||
* hb_type
|
||||
* 是
|
||||
* GROUP
|
||||
* String(32)
|
||||
* GROUP:裂变红包,
|
||||
* NORMAL:普通红包
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("hb_type")
|
||||
private String hbType;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 红包个数
|
||||
* total_num
|
||||
* 是
|
||||
* 1
|
||||
* int
|
||||
* 红包个数
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("total_num")
|
||||
private Integer totalNum;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 红包金额
|
||||
* total_amount
|
||||
* 是
|
||||
* 5000
|
||||
* int
|
||||
* 红包总金额(单位分)
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("total_amount")
|
||||
private Integer totalAmount;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 失败原因
|
||||
* reason
|
||||
* 否
|
||||
* 余额不足
|
||||
* String(32)
|
||||
* 发送失败原因
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("reason")
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 红包发送时间
|
||||
* send_time
|
||||
* 是
|
||||
* 2015-04-21 20:00:00
|
||||
* String(32)
|
||||
* 红包的发送时间
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("send_time")
|
||||
private String sendTime;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 红包退款时间
|
||||
* refund_time
|
||||
* 否
|
||||
* 2015-04-21 23:03:00
|
||||
* String(32)
|
||||
* 红包的退款时间(如果其未领取的退款)
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("refund_time")
|
||||
private String refundTime;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 红包退款金额
|
||||
* refund_amount
|
||||
* 否
|
||||
* 8000
|
||||
* Int
|
||||
* 红包退款金额
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("refund_amount")
|
||||
private Integer refundAmount;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 祝福语
|
||||
* wishing
|
||||
* 否
|
||||
* 新年快乐
|
||||
* String(128)
|
||||
* 祝福语
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("wishing")
|
||||
private String wishing;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 活动描述
|
||||
* remark
|
||||
* 否
|
||||
* 新年红包
|
||||
* String(256)
|
||||
* 活动描述,低版本微信可见
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("remark")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 活动名称
|
||||
* act_name
|
||||
* 否
|
||||
* 新年红包
|
||||
* String(32)
|
||||
* 发红包的活动名称
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("act_name")
|
||||
private String actName;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 裂变红包领取列表
|
||||
* hblist
|
||||
* 否
|
||||
*
|
||||
*
|
||||
* 裂变红包的领取列表
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("hblist")
|
||||
private String hblist;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 领取红包的Openid
|
||||
* openid
|
||||
* 是
|
||||
* ohO4GtzOAAYMp2yapORH3dQB3W18
|
||||
* String(32)
|
||||
* 领取红包的openid
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("openid")
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 金额
|
||||
* amount
|
||||
* 是
|
||||
* 100
|
||||
* int
|
||||
* 领取金额
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("amount")
|
||||
private Integer amount;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 接收时间
|
||||
* rcv_time
|
||||
* 是
|
||||
* 2015-04-21 20:00:00
|
||||
* String(32)
|
||||
* 领取红包的时间
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("rcv_time")
|
||||
private String receiveTime;
|
||||
|
||||
public String getMchBillNo() {
|
||||
return mchBillNo;
|
||||
}
|
||||
|
||||
public void setMchBillNo(String mchBillNo) {
|
||||
this.mchBillNo = mchBillNo;
|
||||
}
|
||||
|
||||
public String getDetailId() {
|
||||
return detailId;
|
||||
}
|
||||
|
||||
public void setDetailId(String detailId) {
|
||||
this.detailId = detailId;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getSendType() {
|
||||
return sendType;
|
||||
}
|
||||
|
||||
public void setSendType(String sendType) {
|
||||
this.sendType = sendType;
|
||||
}
|
||||
|
||||
public String getHbType() {
|
||||
return hbType;
|
||||
}
|
||||
|
||||
public void setHbType(String hbType) {
|
||||
this.hbType = hbType;
|
||||
}
|
||||
|
||||
public Integer getTotalNum() {
|
||||
return totalNum;
|
||||
}
|
||||
|
||||
public void setTotalNum(Integer totalNum) {
|
||||
this.totalNum = totalNum;
|
||||
}
|
||||
|
||||
public Integer getTotalAmount() {
|
||||
return totalAmount;
|
||||
}
|
||||
|
||||
public void setTotalAmount(Integer totalAmount) {
|
||||
this.totalAmount = totalAmount;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public void setReason(String reason) {
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
public String getSendTime() {
|
||||
return sendTime;
|
||||
}
|
||||
|
||||
public void setSendTime(String sendTime) {
|
||||
this.sendTime = sendTime;
|
||||
}
|
||||
|
||||
public String getRefundTime() {
|
||||
return refundTime;
|
||||
}
|
||||
|
||||
public void setRefundTime(String refundTime) {
|
||||
this.refundTime = refundTime;
|
||||
}
|
||||
|
||||
public Integer getRefundAmount() {
|
||||
return refundAmount;
|
||||
}
|
||||
|
||||
public void setRefundAmount(Integer refundAmount) {
|
||||
this.refundAmount = refundAmount;
|
||||
}
|
||||
|
||||
public String getWishing() {
|
||||
return wishing;
|
||||
}
|
||||
|
||||
public void setWishing(String wishing) {
|
||||
this.wishing = wishing;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
public String getActName() {
|
||||
return actName;
|
||||
}
|
||||
|
||||
public void setActName(String actName) {
|
||||
this.actName = actName;
|
||||
}
|
||||
|
||||
public String getHblist() {
|
||||
return hblist;
|
||||
}
|
||||
|
||||
public void setHblist(String hblist) {
|
||||
this.hblist = hblist;
|
||||
}
|
||||
|
||||
public String getOpenid() {
|
||||
return openid;
|
||||
}
|
||||
|
||||
public void setOpenid(String openid) {
|
||||
this.openid = openid;
|
||||
}
|
||||
|
||||
public Integer getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(Integer amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getReceiveTime() {
|
||||
return receiveTime;
|
||||
}
|
||||
|
||||
public void setReceiveTime(String receiveTime) {
|
||||
this.receiveTime = receiveTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
package me.chanjar.weixin.mp.bean.pay.result;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Created by Binary Wang on 2016-11-24.
|
||||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("xml")
|
||||
public class WxPayRefundQueryResult extends WxPayBaseResult {
|
||||
/**
|
||||
* <pre>
|
||||
* 设备号
|
||||
* device_info
|
||||
* 否
|
||||
* String(32)
|
||||
* 013467007045764
|
||||
* 终端设备号
|
||||
*/
|
||||
@XStreamAlias("device_info")
|
||||
private String deviceInfo;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 微信订单号
|
||||
* transaction_id
|
||||
* 是
|
||||
* String(32)
|
||||
* 1217752501201407033233368018
|
||||
* 微信订单号
|
||||
*/
|
||||
@XStreamAlias("transaction_id")
|
||||
private String transactionId;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 商户订单号
|
||||
* out_trade_no
|
||||
* 是
|
||||
* String(32)
|
||||
* 1217752501201407033233368018
|
||||
* 商户系统内部的订单号
|
||||
*/
|
||||
@XStreamAlias("out_trade_no")
|
||||
private String outTradeNo;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 订单金额
|
||||
* total_fee
|
||||
* 是
|
||||
* Int
|
||||
* 100
|
||||
* 订单总金额,单位为分,只能为整数,详见支付金额
|
||||
*/
|
||||
@XStreamAlias("total_fee")
|
||||
private Integer totalFee;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 应结订单金额
|
||||
* settlement_total_fee
|
||||
* 否
|
||||
* Int
|
||||
* 100
|
||||
* 应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。
|
||||
*/
|
||||
@XStreamAlias("settlement_total_fee")
|
||||
private Integer settlementTotalFee;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 货币种类
|
||||
* fee_type
|
||||
* 否
|
||||
* String(8)
|
||||
* CNY
|
||||
* 订单金额货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
|
||||
*/
|
||||
@XStreamAlias("fee_type")
|
||||
private String feeType;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 现金支付金额
|
||||
* cash_fee
|
||||
* 是
|
||||
* Int
|
||||
* 100
|
||||
* 现金支付金额,单位为分,只能为整数,详见支付金额
|
||||
*/
|
||||
@XStreamAlias("cash_fee")
|
||||
private Integer cashFee;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 退款笔数
|
||||
* refund_count
|
||||
* 是
|
||||
* Int
|
||||
* 1
|
||||
* 退款记录数
|
||||
*/
|
||||
@XStreamAlias("refund_count")
|
||||
private Integer refundCount;
|
||||
|
||||
private List<RefundRecord> refundRecords;
|
||||
|
||||
public String getDeviceInfo() {
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
public void setDeviceInfo(String deviceInfo) {
|
||||
this.deviceInfo = deviceInfo;
|
||||
}
|
||||
|
||||
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 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 Integer getRefundCount() {
|
||||
return refundCount;
|
||||
}
|
||||
|
||||
public void setRefundCount(Integer refundCount) {
|
||||
this.refundCount = refundCount;
|
||||
}
|
||||
|
||||
public List<RefundRecord> getRefundRecords() {
|
||||
return refundRecords;
|
||||
}
|
||||
|
||||
public void setRefundRecords(List<RefundRecord> refundRecords) {
|
||||
this.refundRecords = refundRecords;
|
||||
}
|
||||
|
||||
public void composeRefundRecords(String xmlString) {
|
||||
if (this.refundCount != null && this.refundCount > 0) {
|
||||
this.refundRecords = Lists.newArrayList();
|
||||
//TODO 暂时待实现
|
||||
}
|
||||
}
|
||||
|
||||
public static class RefundRecord {
|
||||
/**
|
||||
* <pre>
|
||||
* 商户退款单号
|
||||
* out_refund_no_$n
|
||||
* 是
|
||||
* String(32)
|
||||
* 1217752501201407033233368018
|
||||
* 商户退款单号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("out_refund_no")
|
||||
private String outRefundNo;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 微信退款单号
|
||||
* refund_id_$n
|
||||
* 是
|
||||
* String(28)
|
||||
* 1217752501201407033233368018
|
||||
* 微信退款单号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("refund_id")
|
||||
private String refundId;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 退款渠道
|
||||
* refund_channel_$n
|
||||
* 否
|
||||
* String(16)
|
||||
* ORIGINAL
|
||||
* ORIGINAL—原路退款 BALANCE—退回到余额
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("refund_channel")
|
||||
private String refundChannel;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 申请退款金额
|
||||
* refund_fee_$n
|
||||
* 是
|
||||
* Int
|
||||
* 100
|
||||
* 退款总金额,单位为分,可以做部分退款
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("refund_fee")
|
||||
private String refundFee;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 退款金额
|
||||
* settlement_refund_fee_$n
|
||||
* 否
|
||||
* Int
|
||||
* 100
|
||||
* 退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("settlement_refund_fee")
|
||||
private String settlementRefundFee;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 退款资金来源
|
||||
* refund_account
|
||||
* 否
|
||||
* String(30)
|
||||
* REFUND_SOURCE_RECHARGE_FUNDS
|
||||
* REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款/基本账户, REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("refund_account")
|
||||
private String refundAccount;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 代金券类型
|
||||
* coupon_type_$n
|
||||
* 否
|
||||
* Int
|
||||
* CASH
|
||||
* CASH--充值代金券 , NO_CASH---非充值代金券。订单使用代金券时有返回(取值:CASH、NO_CASH)。$n为下标,从0开始编号,举例:coupon_type_$0
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_type")
|
||||
private String couponType;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 代金券退款金额
|
||||
* coupon_refund_fee_$n
|
||||
* 否
|
||||
* Int
|
||||
* 100
|
||||
* 代金券退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见代金券或立减优惠
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_refund_fee")
|
||||
private String couponRefundFee;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 退款代金券使用数量
|
||||
* coupon_refund_count_$n
|
||||
* 否
|
||||
* Int
|
||||
* 1
|
||||
* 退款代金券使用数量 ,$n为下标,从0开始编号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_refund_count")
|
||||
private String couponRefundCount;
|
||||
|
||||
private List<RefundCoupon> refundCoupons;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 退款状态
|
||||
* refund_status_$n
|
||||
* 是
|
||||
* String(16)
|
||||
* SUCCESS
|
||||
* 退款状态:
|
||||
* SUCCESS—退款成功,
|
||||
* FAIL—退款失败,
|
||||
* PROCESSING—退款处理中,
|
||||
* CHANGE—转入代发,
|
||||
* 退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,资金回流到商户的现金帐号,需要商户人工干预,通过线下或者财付通转账的方式进行退款。
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("refund_status")
|
||||
private String refundStatus;
|
||||
/**
|
||||
* <pre>
|
||||
* 退款入账账户
|
||||
* refund_recv_accout_$n
|
||||
* 是
|
||||
* String(64)
|
||||
* 招商银行信用卡0403
|
||||
* 取当前退款单的退款入账方,1)退回银行卡:{银行名称}{卡类型}{卡尾号},2)退回支付用户零钱:支付用户零钱
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("refund_recv_accout")
|
||||
private String refundRecvAccout;
|
||||
|
||||
public String getOutRefundNo() {
|
||||
return outRefundNo;
|
||||
}
|
||||
|
||||
public void setOutRefundNo(String outRefundNo) {
|
||||
this.outRefundNo = outRefundNo;
|
||||
}
|
||||
|
||||
public String getRefundId() {
|
||||
return refundId;
|
||||
}
|
||||
|
||||
public void setRefundId(String refundId) {
|
||||
this.refundId = refundId;
|
||||
}
|
||||
|
||||
public String getRefundChannel() {
|
||||
return refundChannel;
|
||||
}
|
||||
|
||||
public void setRefundChannel(String refundChannel) {
|
||||
this.refundChannel = refundChannel;
|
||||
}
|
||||
|
||||
public String getRefundFee() {
|
||||
return refundFee;
|
||||
}
|
||||
|
||||
public void setRefundFee(String refundFee) {
|
||||
this.refundFee = refundFee;
|
||||
}
|
||||
|
||||
public String getSettlementRefundFee() {
|
||||
return settlementRefundFee;
|
||||
}
|
||||
|
||||
public void setSettlementRefundFee(String settlementRefundFee) {
|
||||
this.settlementRefundFee = settlementRefundFee;
|
||||
}
|
||||
|
||||
public String getRefundAccount() {
|
||||
return refundAccount;
|
||||
}
|
||||
|
||||
public void setRefundAccount(String refundAccount) {
|
||||
this.refundAccount = refundAccount;
|
||||
}
|
||||
|
||||
public String getCouponType() {
|
||||
return couponType;
|
||||
}
|
||||
|
||||
public void setCouponType(String couponType) {
|
||||
this.couponType = couponType;
|
||||
}
|
||||
|
||||
public String getCouponRefundFee() {
|
||||
return couponRefundFee;
|
||||
}
|
||||
|
||||
public void setCouponRefundFee(String couponRefundFee) {
|
||||
this.couponRefundFee = couponRefundFee;
|
||||
}
|
||||
|
||||
public String getCouponRefundCount() {
|
||||
return couponRefundCount;
|
||||
}
|
||||
|
||||
public void setCouponRefundCount(String couponRefundCount) {
|
||||
this.couponRefundCount = couponRefundCount;
|
||||
}
|
||||
|
||||
public List<RefundCoupon> getRefundCoupons() {
|
||||
return refundCoupons;
|
||||
}
|
||||
|
||||
public void setRefundCoupons(List<RefundCoupon> refundCoupons) {
|
||||
this.refundCoupons = refundCoupons;
|
||||
}
|
||||
|
||||
public String getRefundStatus() {
|
||||
return refundStatus;
|
||||
}
|
||||
|
||||
public void setRefundStatus(String refundStatus) {
|
||||
this.refundStatus = refundStatus;
|
||||
}
|
||||
|
||||
public String getRefundRecvAccout() {
|
||||
return refundRecvAccout;
|
||||
}
|
||||
|
||||
public void setRefundRecvAccout(String refundRecvAccout) {
|
||||
this.refundRecvAccout = refundRecvAccout;
|
||||
}
|
||||
|
||||
public static class RefundCoupon {
|
||||
/**
|
||||
* <pre>
|
||||
* 退款代金券批次ID
|
||||
* coupon_refund_batch_id_$n_$m
|
||||
* 否
|
||||
* String(20)
|
||||
* 100
|
||||
* 退款代金券批次ID ,$n为下标,$m为下标,从0开始编号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_refund_batch_id")
|
||||
private String couponRefundBatchId;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 退款代金券ID
|
||||
* coupon_refund_id_$n_$m
|
||||
* 否
|
||||
* String(20)
|
||||
* 10000
|
||||
* 退款代金券ID, $n为下标,$m为下标,从0开始编号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_refund_id")
|
||||
private String couponRefundId;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 单个退款代金券支付金额
|
||||
* coupon_refund_fee_$n_$m
|
||||
* 否
|
||||
* Int
|
||||
* 100
|
||||
* 单个退款代金券支付金额, $n为下标,$m为下标,从0开始编号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_refund_fee")
|
||||
private String couponRefundFee;
|
||||
|
||||
public RefundCoupon(String couponRefundBatchId, String couponRefundId, String couponRefundFee) {
|
||||
this.couponRefundBatchId = couponRefundBatchId;
|
||||
this.couponRefundId = couponRefundId;
|
||||
this.couponRefundFee = couponRefundFee;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
package me.chanjar.weixin.mp.bean.template;
|
||||
|
||||
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
|
||||
|
||||
/**
|
||||
* 参考 http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN 发送模板消息接口部分
|
||||
*/
|
||||
public class WxMpTemplateMessage implements Serializable {
|
||||
private static final long serialVersionUID = 5063374783759519418L;
|
||||
|
||||
private String toUser;
|
||||
private String templateId;
|
||||
private String url;
|
||||
private String topColor;
|
||||
private List<WxMpTemplateData> data = new ArrayList<>();
|
||||
|
||||
public String getToUser() {
|
||||
@@ -39,14 +41,6 @@ public class WxMpTemplateMessage implements Serializable {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getTopColor() {
|
||||
return this.topColor;
|
||||
}
|
||||
|
||||
public void setTopColor(String topColor) {
|
||||
this.topColor = topColor;
|
||||
}
|
||||
|
||||
public List<WxMpTemplateData> getData() {
|
||||
return this.data;
|
||||
}
|
||||
@@ -71,7 +65,6 @@ public class WxMpTemplateMessage implements Serializable {
|
||||
private String toUser;
|
||||
private String templateId;
|
||||
private String url;
|
||||
private String topColor;
|
||||
private List<WxMpTemplateData> data = new ArrayList<>();
|
||||
|
||||
public WxMpTemplateMessageBuilder toUser(String toUser) {
|
||||
@@ -89,11 +82,6 @@ public class WxMpTemplateMessage implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public WxMpTemplateMessageBuilder topColor(String topColor) {
|
||||
this.topColor = topColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WxMpTemplateMessageBuilder data(List<WxMpTemplateData> data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
@@ -103,7 +91,6 @@ public class WxMpTemplateMessage implements Serializable {
|
||||
this.toUser(origin.toUser);
|
||||
this.templateId(origin.templateId);
|
||||
this.url(origin.url);
|
||||
this.topColor(origin.topColor);
|
||||
this.data(origin.data);
|
||||
return this;
|
||||
}
|
||||
@@ -113,7 +100,6 @@ public class WxMpTemplateMessage implements Serializable {
|
||||
m.toUser = this.toUser;
|
||||
m.templateId = this.templateId;
|
||||
m.url = this.url;
|
||||
m.topColor = this.topColor;
|
||||
m.data = this.data;
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -28,9 +28,6 @@ public class WxMpTemplateMessageGsonAdapter implements JsonSerializer<WxMpTempla
|
||||
if (message.getUrl() != null) {
|
||||
messageJson.addProperty("url", message.getUrl());
|
||||
}
|
||||
if (message.getTopColor() != null) {
|
||||
messageJson.addProperty("topcolor", message.getTopColor());
|
||||
}
|
||||
|
||||
JsonObject data = new JsonObject();
|
||||
messageJson.add("data", data);
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
package me.chanjar.weixin.mp.util.xml;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
|
||||
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutImageMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMusicMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutNewsMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTextMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTransferKefuMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutVideoMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutVoiceMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
public class XStreamTransformer {
|
||||
private static final Map<Class<?>, XStream> CLASS_2_XSTREAM_INSTANCE = new HashMap<>();
|
||||
|
||||
protected static final Map<Class<?>, XStream> CLASS_2_XSTREAM_INSTANCE = configXStreamInstance();
|
||||
static {
|
||||
registerClass(WxMpXmlMessage.class);
|
||||
registerClass(WxMpXmlOutMusicMessage.class);
|
||||
registerClass(WxMpXmlOutNewsMessage.class);
|
||||
registerClass(WxMpXmlOutTextMessage.class);
|
||||
registerClass(WxMpXmlOutImageMessage.class);
|
||||
registerClass(WxMpXmlOutVideoMessage.class);
|
||||
registerClass(WxMpXmlOutVoiceMessage.class);
|
||||
registerClass(WxMpXmlOutTransferKefuMessage.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* xml -> pojo
|
||||
@@ -36,16 +36,6 @@ public class XStreamTransformer {
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册扩展消息的解析器
|
||||
* @param clz 类型
|
||||
* @param xStream xml解析器
|
||||
*/
|
||||
public static void register(Class<?> clz, XStream xStream) {
|
||||
CLASS_2_XSTREAM_INSTANCE.put(clz,xStream);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pojo -> xml
|
||||
*/
|
||||
@@ -53,83 +43,44 @@ public class XStreamTransformer {
|
||||
return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object);
|
||||
}
|
||||
|
||||
private static Map<Class<?>, XStream> configXStreamInstance() {
|
||||
Map<Class<?>, XStream> map = new HashMap<>();
|
||||
map.put(WxMpXmlMessage.class, config_WxMpXmlMessage());
|
||||
map.put(WxMpXmlOutMusicMessage.class, config_WxMpXmlOutMusicMessage());
|
||||
map.put(WxMpXmlOutNewsMessage.class, config_WxMpXmlOutNewsMessage());
|
||||
map.put(WxMpXmlOutTextMessage.class, config_WxMpXmlOutTextMessage());
|
||||
map.put(WxMpXmlOutImageMessage.class, config_WxMpXmlOutImageMessage());
|
||||
map.put(WxMpXmlOutVideoMessage.class, config_WxMpXmlOutVideoMessage());
|
||||
map.put(WxMpXmlOutVoiceMessage.class, config_WxMpXmlOutVoiceMessage());
|
||||
map.put(WxMpXmlOutTransferKefuMessage.class, config_WxMpXmlOutTransferCustomerServiceMessage());
|
||||
|
||||
return map;
|
||||
/**
|
||||
* 注册扩展消息的解析器
|
||||
*
|
||||
* @param clz 类型
|
||||
* @param xStream xml解析器
|
||||
*/
|
||||
public static void register(Class<?> clz, XStream xStream) {
|
||||
CLASS_2_XSTREAM_INSTANCE.put(clz, xStream);
|
||||
}
|
||||
|
||||
private static XStream config_WxMpXmlMessage() {
|
||||
/**
|
||||
* 会自动注册该类及其子类
|
||||
* @param clz 要注册的类
|
||||
*/
|
||||
public static void registerClass(Class<?> clz) {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxMpXmlMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlMessage.ScanCodeInfo.class);
|
||||
xstream.processAnnotations(WxMpXmlMessage.SendPicsInfo.class);
|
||||
xstream.processAnnotations(WxMpXmlMessage.SendPicsInfo.Item.class);
|
||||
xstream.processAnnotations(WxMpXmlMessage.SendLocationInfo.class);
|
||||
|
||||
xstream.aliasField("MsgID", WxMpXmlMessage.class, "msgId");
|
||||
return xstream;
|
||||
xstream.processAnnotations(clz);
|
||||
xstream.processAnnotations(getInnerClasses(clz));
|
||||
register(clz, xstream);
|
||||
}
|
||||
|
||||
private static XStream config_WxMpXmlOutImageMessage() {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxMpXmlOutMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlOutImageMessage.class);
|
||||
return xstream;
|
||||
}
|
||||
private static Class<?>[] getInnerClasses(Class<?> clz) {
|
||||
Class<?>[] innerClasses = clz.getClasses();
|
||||
if (innerClasses == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static XStream config_WxMpXmlOutNewsMessage() {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxMpXmlOutMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlOutNewsMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlOutNewsMessage.Item.class);
|
||||
return xstream;
|
||||
}
|
||||
List<Class<?>> result = new ArrayList<>();
|
||||
result.addAll(Arrays.asList(innerClasses));
|
||||
for (Class<?> inner : innerClasses) {
|
||||
Class<?>[] innerClz = getInnerClasses(inner);
|
||||
if (innerClz == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
private static XStream config_WxMpXmlOutMusicMessage() {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxMpXmlOutMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlOutMusicMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlOutMusicMessage.Music.class);
|
||||
return xstream;
|
||||
}
|
||||
result.addAll(Arrays.asList(innerClz));
|
||||
}
|
||||
|
||||
private static XStream config_WxMpXmlOutTextMessage() {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxMpXmlOutMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlOutTextMessage.class);
|
||||
return xstream;
|
||||
return result.toArray(new Class<?>[0]);
|
||||
}
|
||||
|
||||
private static XStream config_WxMpXmlOutVideoMessage() {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxMpXmlOutMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlOutVideoMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlOutVideoMessage.Video.class);
|
||||
return xstream;
|
||||
}
|
||||
|
||||
private static XStream config_WxMpXmlOutVoiceMessage() {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxMpXmlOutMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlOutVoiceMessage.class);
|
||||
return xstream;
|
||||
}
|
||||
|
||||
private static XStream config_WxMpXmlOutTransferCustomerServiceMessage() {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxMpXmlOutMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlOutTransferKefuMessage.class);
|
||||
xstream.processAnnotations(WxMpXmlOutTransferKefuMessage.TransInfo.class);
|
||||
return xstream;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package me.chanjar.weixin.mp.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.Module;
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
|
||||
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
|
||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class ApiTestModule implements Module {
|
||||
|
||||
@Override
|
||||
@@ -18,6 +18,7 @@ public class ApiTestModule implements Module {
|
||||
.getSystemResourceAsStream("test-config.xml")) {
|
||||
WxXmlMpInMemoryConfigStorage config = this
|
||||
.fromXml(WxXmlMpInMemoryConfigStorage.class, is1);
|
||||
config.setAccessTokenLock(new ReentrantLock());
|
||||
WxMpService wxService = new WxMpServiceImpl();
|
||||
wxService.setWxMpConfigStorage(config);
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package me.chanjar.weixin.mp.api;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
@XStreamAlias("xml")
|
||||
public class WxXmlMpInMemoryConfigStorage
|
||||
@@ -50,4 +51,7 @@ public class WxXmlMpInMemoryConfigStorage
|
||||
this.templateId = templateId;
|
||||
}
|
||||
|
||||
}
|
||||
public void setAccessTokenLock(Lock lock){
|
||||
super.accessTokenLock = lock;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
package me.chanjar.weixin.mp.api.impl;
|
||||
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
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 me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.bean.menu.WxMenu;
|
||||
import me.chanjar.weixin.common.bean.menu.WxMenuButton;
|
||||
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.bean.menu.WxMpGetSelfMenuInfoResult;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* 测试菜单
|
||||
@@ -28,11 +27,22 @@ public class WxMpMenuServiceImplTest {
|
||||
protected WxMpService wxService;
|
||||
|
||||
@Test(dataProvider = "menu")
|
||||
public void testCreateMenu(WxMenu wxMenu) throws WxErrorException {
|
||||
public void testMenuCreate(WxMenu wxMenu) throws WxErrorException {
|
||||
System.out.println(wxMenu.toJson());
|
||||
this.wxService.getMenuService().menuCreate(wxMenu);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMenuTryMatch() throws Exception {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSelfMenuInfo() throws Exception {
|
||||
WxMpGetSelfMenuInfoResult selfMenuInfo = this.wxService.getMenuService().getSelfMenuInfo();
|
||||
System.out.println(selfMenuInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateMenu2() throws WxErrorException {
|
||||
String a = "{\n"
|
||||
@@ -77,15 +87,15 @@ public class WxMpMenuServiceImplTest {
|
||||
this.wxService.getMenuService().menuCreate(menu);
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = { "testCreateMenu"})
|
||||
public void testGetMenu() throws WxErrorException {
|
||||
@Test(dependsOnMethods = { "testMenuCreate"})
|
||||
public void testMenuGet() throws WxErrorException {
|
||||
WxMenu wxMenu = this.wxService.getMenuService().menuGet();
|
||||
Assert.assertNotNull(wxMenu);
|
||||
System.out.println(wxMenu.toJson());
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = { "testGetMenu"})
|
||||
public void testDeleteMenu() throws WxErrorException {
|
||||
@Test(dependsOnMethods = { "testMenuGet"})
|
||||
public void testMenuDelete() throws WxErrorException {
|
||||
this.wxService.getMenuService().menuDelete();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,7 @@ 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.result.WxPayRefundResult;
|
||||
import me.chanjar.weixin.mp.bean.pay.result.WxPaySendRedpackResult;
|
||||
import me.chanjar.weixin.mp.bean.pay.result.WxPayUnifiedOrderResult;
|
||||
import me.chanjar.weixin.mp.bean.pay.result.*;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@@ -20,6 +18,7 @@ import java.io.File;
|
||||
/**
|
||||
* 测试支付相关接口
|
||||
* Created by Binary Wang on 2016/7/28.
|
||||
*
|
||||
* @author binarywang (https://github.com/binarywang)
|
||||
*/
|
||||
@Test
|
||||
@@ -34,6 +33,9 @@ public class WxMpPayServiceImplTest {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#refund(WxPayRefundRequest, File)} .
|
||||
*/
|
||||
@Test
|
||||
public void testRefund() throws Exception {
|
||||
WxPayRefundRequest request = new WxPayRefundRequest();
|
||||
@@ -46,33 +48,64 @@ public class WxMpPayServiceImplTest {
|
||||
System.err.println(result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#refundQuery(String, String, String, String)} .
|
||||
*/
|
||||
@Test
|
||||
public void testRefundQuery() throws Exception {
|
||||
WxPayRefundQueryResult result = this.wxService.getPayService().refundQuery("1", "", "", "");
|
||||
result = this.wxService.getPayService().refundQuery("", "2", "", "");
|
||||
System.err.println(result);
|
||||
result = this.wxService.getPayService().refundQuery("", "", "3", "");
|
||||
System.err.println(result);
|
||||
result = this.wxService.getPayService().refundQuery("", "", "", "4");
|
||||
System.err.println(result);
|
||||
//测试四个参数都填的情况,应该报异常的
|
||||
result = this.wxService.getPayService().refundQuery("1", "2", "3", "4");
|
||||
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
|
||||
public void testSendRedpack() throws Exception {
|
||||
WxPaySendRedpackRequest request = new WxPaySendRedpackRequest();
|
||||
request.setActName("abc");
|
||||
request.setClientIp("aaa");
|
||||
request.setMchBillno("aaaa");
|
||||
request.setMchBillNo("aaaa");
|
||||
request
|
||||
.setReOpenid(((WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage()).getOpenid());
|
||||
.setReOpenid(((WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage()).getOpenid());
|
||||
File keyFile = new File("E:\\dlt.p12");
|
||||
WxPaySendRedpackResult redpackResult = this.wxService.getPayService().sendRedpack(request, keyFile);
|
||||
System.err.println(redpackResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#queryRedpack(String, File)}.
|
||||
*/
|
||||
@Test
|
||||
public void testQueryRedpack() throws Exception {
|
||||
File keyFile = new File("E:\\dlt.p12");
|
||||
WxPayRedpackQueryResult redpackResult = this.wxService.getPayService().queryRedpack("aaaa", keyFile);
|
||||
System.err.println(redpackResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#unifiedOrder(WxPayUnifiedOrderRequest)}.
|
||||
*/
|
||||
@Test
|
||||
public void testUnifiedOrder() throws WxErrorException {
|
||||
WxPayUnifiedOrderResult result = this.wxService.getPayService()
|
||||
.unifiedOrder(WxPayUnifiedOrderRequest.builder().body("1111111")
|
||||
.totalFee(1).spbillCreateIp("111111").notifyURL("111111")
|
||||
.tradeType("JSAPI").openid("122").outTradeNo("111111").build());
|
||||
.unifiedOrder(WxPayUnifiedOrderRequest.builder().body("1111111")
|
||||
.totalFee(1).spbillCreateIp("111111").notifyURL("111111")
|
||||
.tradeType("JSAPI").openid("122").outTradeNo("111111").build());
|
||||
System.err.println(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import me.chanjar.weixin.mp.bean.template.WxMpTemplate;
|
||||
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
|
||||
import me.chanjar.weixin.mp.bean.template.WxMpTemplateIndustry;
|
||||
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
@@ -28,7 +29,7 @@ public class WxMpTemplateMsgServiceImplTest {
|
||||
@Inject
|
||||
protected WxMpService wxService;
|
||||
|
||||
@Test(invocationCount = 10, threadPoolSize = 10)
|
||||
@Test(invocationCount = 5, threadPoolSize = 3)
|
||||
public void testSendTemplateMsg() throws WxErrorException {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(
|
||||
"yyyy-MM-dd HH:mm:ss.SSS");
|
||||
@@ -38,7 +39,10 @@ public class WxMpTemplateMsgServiceImplTest {
|
||||
.toUser(configStorage.getOpenid())
|
||||
.templateId(configStorage.getTemplateId()).build();
|
||||
templateMessage.addWxMpTemplateData(
|
||||
new WxMpTemplateData("first", dateFormat.format(new Date())));
|
||||
new WxMpTemplateData("first", dateFormat.format(new Date()),"#FF00FF"));
|
||||
templateMessage.addWxMpTemplateData(
|
||||
new WxMpTemplateData("remark", RandomStringUtils.randomAlphanumeric(100), "#FF00FF"));
|
||||
templateMessage.setUrl(" ");
|
||||
String msgId = this.wxService.getTemplateMsgService().sendTemplateMsg(templateMessage);
|
||||
Assert.assertNotNull(msgId);
|
||||
System.out.println(msgId);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-parent</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<version>2.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>weixin-java-osgi</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user