@@ -6,7 +6,7 @@ | |||||
<modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>wx-java</artifactId> | <artifactId>wx-java</artifactId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
<packaging>pom</packaging> | <packaging>pom</packaging> | ||||
<name>WxJava - Weixin/Wechat Java SDK</name> | <name>WxJava - Weixin/Wechat Java SDK</name> | ||||
<description>微信开发Java SDK</description> | <description>微信开发Java SDK</description> | ||||
@@ -126,11 +126,10 @@ | |||||
<artifactId>qrcode-utils</artifactId> | <artifactId>qrcode-utils</artifactId> | ||||
<version>1.1</version> | <version>1.1</version> | ||||
</dependency> | </dependency> | ||||
<!-- 由于jodd-http较新的3.8版本需要jdk8,故而此处采用较低版本 --> | |||||
<dependency> | <dependency> | ||||
<groupId>org.jodd</groupId> | <groupId>org.jodd</groupId> | ||||
<artifactId>jodd-http</artifactId> | <artifactId>jodd-http</artifactId> | ||||
<version>3.7.1</version> | |||||
<version>5.2.0</version> | |||||
<scope>provided</scope> | <scope>provided</scope> | ||||
</dependency> | </dependency> | ||||
<dependency> | <dependency> | ||||
@@ -163,7 +162,7 @@ | |||||
<dependency> | <dependency> | ||||
<groupId>org.apache.commons</groupId> | <groupId>org.apache.commons</groupId> | ||||
<artifactId>commons-lang3</artifactId> | <artifactId>commons-lang3</artifactId> | ||||
<version>3.5</version> | |||||
<version>3.10</version> | |||||
</dependency> | </dependency> | ||||
<dependency> | <dependency> | ||||
<groupId>org.slf4j</groupId> | <groupId>org.slf4j</groupId> | ||||
@@ -6,7 +6,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>wx-java</artifactId> | <artifactId>wx-java</artifactId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<packaging>pom</packaging> | <packaging>pom</packaging> | ||||
<artifactId>wx-java-spring-boot-starters</artifactId> | <artifactId>wx-java-spring-boot-starters</artifactId> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<artifactId>wx-java-spring-boot-starters</artifactId> | <artifactId>wx-java-spring-boot-starters</artifactId> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<artifactId>wx-java-spring-boot-starters</artifactId> | <artifactId>wx-java-spring-boot-starters</artifactId> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<artifactId>wx-java-spring-boot-starters</artifactId> | <artifactId>wx-java-spring-boot-starters</artifactId> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
@@ -5,7 +5,7 @@ | |||||
<parent> | <parent> | ||||
<artifactId>wx-java-spring-boot-starters</artifactId> | <artifactId>wx-java-spring-boot-starters</artifactId> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
@@ -50,6 +50,14 @@ public class WxPayAutoConfiguration { | |||||
payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId())); | payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId())); | ||||
payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath())); | payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath())); | ||||
//以下是apiv3以及支付分相关 | |||||
payConfig.setServiceId(StringUtils.trimToNull(this.properties.getServiceId())); | |||||
payConfig.setPayScoreNotifyUrl(StringUtils.trimToNull(this.properties.getPayScoreNotifyUrl())); | |||||
payConfig.setPrivateKeyPath(StringUtils.trimToNull(this.properties.getPrivateKeyPath())); | |||||
payConfig.setPrivateCertPath(StringUtils.trimToNull(this.properties.getPrivateCertPath())); | |||||
payConfig.setCertSerialNo(StringUtils.trimToNull(this.properties.getCertSerialNo())); | |||||
payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiv3Key())); | |||||
wxPayService.setConfig(payConfig); | wxPayService.setConfig(payConfig); | ||||
return wxPayService; | return wxPayService; | ||||
} | } | ||||
@@ -43,4 +43,34 @@ public class WxPayProperties { | |||||
* apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定. | * apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定. | ||||
*/ | */ | ||||
private String keyPath; | private String keyPath; | ||||
/** | |||||
* 微信支付分serviceId | |||||
*/ | |||||
private String serviceId; | |||||
/** | |||||
* 证书序列号 | |||||
*/ | |||||
private String certSerialNo; | |||||
/** | |||||
* apiV3秘钥 | |||||
*/ | |||||
private String apiv3Key; | |||||
/** | |||||
* 微信支付分回调地址 | |||||
*/ | |||||
private String payScoreNotifyUrl; | |||||
/** | |||||
* apiv3 商户apiclient_key.pem | |||||
*/ | |||||
private String privateKeyPath; | |||||
/** | |||||
* apiv3 商户apiclient_cert.pem | |||||
*/ | |||||
private String privateCertPath; | |||||
} | } |
@@ -6,7 +6,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>wx-java</artifactId> | <artifactId>wx-java</artifactId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-graal</artifactId> | <artifactId>weixin-graal</artifactId> | ||||
@@ -6,7 +6,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>wx-java</artifactId> | <artifactId>wx-java</artifactId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-common</artifactId> | <artifactId>weixin-java-common</artifactId> | ||||
@@ -9,6 +9,12 @@ import java.util.Map; | |||||
* @author Daniel Qian & binarywang | * @author Daniel Qian & binarywang | ||||
*/ | */ | ||||
public class WxConsts { | public class WxConsts { | ||||
/** | |||||
* 微信接口返回的参数errcode. | |||||
*/ | |||||
public static final String ERR_CODE = "errcode"; | |||||
/** | /** | ||||
* 微信推送过来的消息的类型,和发送给微信xml格式消息的消息类型. | * 微信推送过来的消息的类型,和发送给微信xml格式消息的消息类型. | ||||
*/ | */ | ||||
@@ -88,7 +88,7 @@ public class WxError implements Serializable { | |||||
return "错误代码:" + this.errorCode + ", 错误信息:" + this.errorMsg; | return "错误代码:" + this.errorCode + ", 错误信息:" + this.errorMsg; | ||||
} | } | ||||
return "错误代码:" + this.errorCode + ", 错误信息:" + this.errorMsg + ",微信原始报文:" + this.json; | |||||
return "错误代码:" + this.errorCode + ", 错误信息:" + this.errorMsg + ",原始报文:" + this.json; | |||||
} | } | ||||
} | } |
@@ -0,0 +1,23 @@ | |||||
package me.chanjar.weixin.common.error; | |||||
/** | |||||
* WxJava专用的runtime exception. | |||||
* | |||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
* @date 2020-09-26 | |||||
*/ | |||||
public class WxRuntimeException extends RuntimeException { | |||||
private static final long serialVersionUID = 4881698471192264412L; | |||||
public WxRuntimeException(Throwable e) { | |||||
super(e); | |||||
} | |||||
public WxRuntimeException(String msg) { | |||||
super(msg); | |||||
} | |||||
public WxRuntimeException(String msg, Throwable e) { | |||||
super(msg, e); | |||||
} | |||||
} |
@@ -1,15 +1,20 @@ | |||||
package me.chanjar.weixin.common.util.http.apache; | package me.chanjar.weixin.common.util.http.apache; | ||||
import lombok.extern.slf4j.Slf4j; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
import me.chanjar.weixin.common.util.http.RequestHttp; | import me.chanjar.weixin.common.util.http.RequestHttp; | ||||
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | ||||
import me.chanjar.weixin.common.util.http.WxDnsResolver; | |||||
import org.apache.http.Header; | |||||
import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
import org.apache.http.client.config.RequestConfig; | import org.apache.http.client.config.RequestConfig; | ||||
import org.apache.http.client.methods.CloseableHttpResponse; | import org.apache.http.client.methods.CloseableHttpResponse; | ||||
import org.apache.http.client.methods.HttpGet; | import org.apache.http.client.methods.HttpGet; | ||||
import org.apache.http.impl.client.CloseableHttpClient; | import org.apache.http.impl.client.CloseableHttpClient; | ||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
@@ -20,6 +25,7 @@ import java.io.IOException; | |||||
* @date 2017/5/4 | * @date 2017/5/4 | ||||
*/ | */ | ||||
public class ApacheHttpClientSimpleGetRequestExecutor extends SimpleGetRequestExecutor<CloseableHttpClient, HttpHost> { | public class ApacheHttpClientSimpleGetRequestExecutor extends SimpleGetRequestExecutor<CloseableHttpClient, HttpHost> { | ||||
protected final Logger log = LoggerFactory.getLogger(this.getClass()); | |||||
public ApacheHttpClientSimpleGetRequestExecutor(RequestHttp requestHttp) { | public ApacheHttpClientSimpleGetRequestExecutor(RequestHttp requestHttp) { | ||||
super(requestHttp); | super(requestHttp); | ||||
} | } | ||||
@@ -39,6 +45,11 @@ public class ApacheHttpClientSimpleGetRequestExecutor extends SimpleGetRequestEx | |||||
} | } | ||||
try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet)) { | try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet)) { | ||||
// Header[] allHeaders = response.getAllHeaders(); | |||||
// for (Header header:allHeaders) { | |||||
// log.info("\n【header】:"+header.getName()+"="+header.getValue()); | |||||
// } | |||||
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); | String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); | ||||
WxError error = WxError.fromJson(responseContent, wxType); | WxError error = WxError.fromJson(responseContent, wxType); | ||||
if (error.getErrorCode() != 0) { | if (error.getErrorCode() != 0) { | ||||
@@ -4,7 +4,6 @@ import jodd.http.HttpConnectionProvider; | |||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.util.StringPool; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
@@ -19,6 +18,8 @@ import java.io.ByteArrayInputStream; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.nio.charset.StandardCharsets; | |||||
/** | /** | ||||
* . | * . | ||||
@@ -47,7 +48,7 @@ public class JoddHttpMediaDownloadRequestExecutor extends BaseMediaDownloadReque | |||||
request.withConnectionProvider(requestHttp.getRequestHttpClient()); | request.withConnectionProvider(requestHttp.getRequestHttpClient()); | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
String contentType = response.header("Content-Type"); | String contentType = response.header("Content-Type"); | ||||
if (contentType != null && contentType.startsWith("application/json")) { | if (contentType != null && contentType.startsWith("application/json")) { | ||||
@@ -4,7 +4,6 @@ import jodd.http.HttpConnectionProvider; | |||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.util.StringPool; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
@@ -14,6 +13,7 @@ import me.chanjar.weixin.common.util.http.RequestHttp; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.nio.charset.StandardCharsets; | |||||
/** | /** | ||||
* . | * . | ||||
@@ -35,7 +35,7 @@ public class JoddHttpMediaUploadRequestExecutor extends MediaUploadRequestExecut | |||||
request.withConnectionProvider(requestHttp.getRequestHttpClient()); | request.withConnectionProvider(requestHttp.getRequestHttpClient()); | ||||
request.form("media", file); | request.form("media", file); | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
String responseContent = response.bodyText(); | String responseContent = response.bodyText(); | ||||
WxError error = WxError.fromJson(responseContent, wxType); | WxError error = WxError.fromJson(responseContent, wxType); | ||||
@@ -4,7 +4,6 @@ import jodd.http.HttpConnectionProvider; | |||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.util.StringPool; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
@@ -12,6 +11,7 @@ import me.chanjar.weixin.common.util.http.RequestHttp; | |||||
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.nio.charset.StandardCharsets; | |||||
/** | /** | ||||
* . | * . | ||||
@@ -39,7 +39,7 @@ public class JoddHttpSimpleGetRequestExecutor extends SimpleGetRequestExecutor<H | |||||
} | } | ||||
request.withConnectionProvider(requestHttp.getRequestHttpClient()); | request.withConnectionProvider(requestHttp.getRequestHttpClient()); | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
String responseContent = response.bodyText(); | String responseContent = response.bodyText(); | ||||
@@ -4,7 +4,6 @@ import jodd.http.HttpConnectionProvider; | |||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.util.StringPool; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
@@ -12,6 +11,7 @@ import me.chanjar.weixin.common.util.http.RequestHttp; | |||||
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; | import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.nio.charset.StandardCharsets; | |||||
/** | /** | ||||
* . | * . | ||||
@@ -38,7 +38,7 @@ public class JoddHttpSimplePostRequestExecutor extends SimplePostRequestExecutor | |||||
request.bodyText(postEntity); | request.bodyText(postEntity); | ||||
} | } | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
String responseContent = response.bodyText(); | String responseContent = response.bodyText(); | ||||
if (responseContent.isEmpty()) { | if (responseContent.isEmpty()) { | ||||
@@ -0,0 +1,26 @@ | |||||
package me.chanjar.weixin.common.util.json; | |||||
import com.google.gson.JsonObject; | |||||
import com.google.gson.JsonParser; | |||||
import com.google.gson.stream.JsonReader; | |||||
import java.io.Reader; | |||||
/** | |||||
* @author niefy | |||||
*/ | |||||
public class GsonParser { | |||||
private static final JsonParser JSON_PARSER = new JsonParser(); | |||||
public static JsonObject parse(String json) { | |||||
return JSON_PARSER.parse(json).getAsJsonObject(); | |||||
} | |||||
public static JsonObject parse(Reader json) { | |||||
return JSON_PARSER.parse(json).getAsJsonObject(); | |||||
} | |||||
public static JsonObject parse(JsonReader json) { | |||||
return JSON_PARSER.parse(json).getAsJsonObject(); | |||||
} | |||||
} |
@@ -18,9 +18,18 @@ public class WxErrorAdapter implements JsonDeserializer<WxError> { | |||||
if (wxErrorJsonObject.get("errcode") != null && !wxErrorJsonObject.get("errcode").isJsonNull()) { | if (wxErrorJsonObject.get("errcode") != null && !wxErrorJsonObject.get("errcode").isJsonNull()) { | ||||
errorBuilder.errorCode(GsonHelper.getAsPrimitiveInt(wxErrorJsonObject.get("errcode"))); | errorBuilder.errorCode(GsonHelper.getAsPrimitiveInt(wxErrorJsonObject.get("errcode"))); | ||||
} else if(wxErrorJsonObject.get("err_no") != null && !wxErrorJsonObject.get("err_no").isJsonNull()) { | |||||
errorBuilder.errorCode(GsonHelper.getAsPrimitiveInt(wxErrorJsonObject.get("err_no"))); | |||||
} else if(wxErrorJsonObject.get("error_code") != null && !wxErrorJsonObject.get("error_code").isJsonNull()){ | |||||
errorBuilder.errorCode(GsonHelper.getAsPrimitiveInt(wxErrorJsonObject.get("error_code"))); | |||||
} | } | ||||
if (wxErrorJsonObject.get("errmsg") != null && !wxErrorJsonObject.get("errmsg").isJsonNull()) { | if (wxErrorJsonObject.get("errmsg") != null && !wxErrorJsonObject.get("errmsg").isJsonNull()) { | ||||
errorBuilder.errorMsg(GsonHelper.getAsString(wxErrorJsonObject.get("errmsg"))); | errorBuilder.errorMsg(GsonHelper.getAsString(wxErrorJsonObject.get("errmsg"))); | ||||
} else if (wxErrorJsonObject.get("err_tips") != null && !wxErrorJsonObject.get("err_tips").isJsonNull()) { | |||||
errorBuilder.errorMsg(GsonHelper.getAsString(wxErrorJsonObject.get("err_tips"))); | |||||
} else if (wxErrorJsonObject.get("description") != null && !wxErrorJsonObject.get("description").isJsonNull()) { | |||||
errorBuilder.errorMsg(GsonHelper.getAsString(wxErrorJsonObject.get("description"))); | |||||
} | } | ||||
errorBuilder.json(json.toString()); | errorBuilder.json(json.toString()); | ||||
@@ -7,7 +7,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>wx-java</artifactId> | <artifactId>wx-java</artifactId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-cp</artifactId> | <artifactId>weixin-java-cp</artifactId> | ||||
@@ -3,8 +3,8 @@ package me.chanjar.weixin.cp.api.impl; | |||||
import jodd.http.HttpConnectionProvider; | import jodd.http.HttpConnectionProvider; | ||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.JoddHttp; | |||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.http.net.SocketHttpConnectionProvider; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.bean.WxAccessToken; | import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
@@ -68,7 +68,7 @@ public class WxCpServiceJoddHttpImpl extends BaseWxCpServiceImpl<HttpConnectionP | |||||
configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); | configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); | ||||
} | } | ||||
httpClient = JoddHttp.httpConnectionProvider; | |||||
httpClient = new SocketHttpConnectionProvider(); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -7,7 +7,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>wx-java</artifactId> | <artifactId>wx-java</artifactId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-miniapp</artifactId> | <artifactId>weixin-java-miniapp</artifactId> | ||||
@@ -0,0 +1,62 @@ | |||||
package cn.binarywang.wx.miniapp.api; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaGetLiveInfo; | |||||
import me.chanjar.weixin.common.error.WxErrorException; | |||||
import java.util.List; | |||||
/** | |||||
* <pre> | |||||
* 直播相关操作接口. | |||||
* Created by yjwang on 2020/4/5. | |||||
* </pre> | |||||
* | |||||
* @author <a href="https://github.com/yjwang3300300">yjwang</a> | |||||
*/ | |||||
public interface WxMaLiveService { | |||||
String GET_LIVE_INFO = "https://api.weixin.qq.com/wxa/business/getliveinfo"; | |||||
/** | |||||
* 获取直播房间列表.(分页) | |||||
* | |||||
* @param start 起始拉取房间,start = 0 表示从第 1 个房间开始拉取 | |||||
* @param limit 每次拉取的个数上限,不要设置过大,建议 100 以内 | |||||
* @return . | |||||
* @throws WxErrorException . | |||||
*/ | |||||
WxMaGetLiveInfo getLiveInfo(Integer start, Integer limit) throws WxErrorException; | |||||
/** | |||||
* 获取所有直播间信息(没有分页直接获取全部) | |||||
* @return | |||||
* @throws WxErrorException | |||||
*/ | |||||
List<WxMaGetLiveInfo.RoomInfo> getLiveinfos() throws WxErrorException; | |||||
/** | |||||
* | |||||
* 获取直播房间回放数据信息. | |||||
* | |||||
* @param action 获取回放 | |||||
* @param room_id 直播间 id | |||||
* @param start 起始拉取视频,start = 0 表示从第 1 个视频片段开始拉取 | |||||
* @param limit 每次拉取的个数上限,不要设置过大,建议 100 以内 | |||||
* @return | |||||
* @throws WxErrorException | |||||
*/ | |||||
WxMaGetLiveInfo getLiveReplay(String action, Integer room_id, Integer start, Integer limit) throws WxErrorException; | |||||
/** | |||||
* | |||||
* 获取直播房间回放数据信息. | |||||
* | |||||
* 获取回放 (默认:get_replay) | |||||
* @param room_id 直播间 id | |||||
* @param start 起始拉取视频,start = 0 表示从第 1 个视频片段开始拉取 | |||||
* @param limit 每次拉取的个数上限,不要设置过大,建议 100 以内 | |||||
* @return | |||||
* @throws WxErrorException | |||||
*/ | |||||
WxMaGetLiveInfo getLiveReplay(Integer room_id, Integer start, Integer limit) throws WxErrorException; | |||||
} |
@@ -0,0 +1,36 @@ | |||||
package cn.binarywang.wx.miniapp.api; | |||||
import cn.binarywang.wx.miniapp.bean.scheme.WxMaGenerateNfcSchemeRequest; | |||||
import cn.binarywang.wx.miniapp.bean.scheme.WxMaGenerateSchemeRequest; | |||||
import me.chanjar.weixin.common.error.WxErrorException; | |||||
/** | |||||
* <pre> | |||||
* 小程序Scheme码相关操作接口. | |||||
* | |||||
* | |||||
* </pre> | |||||
* | |||||
* @author : cofedream | |||||
* created on : 2021-01-26 | |||||
*/ | |||||
public interface WxMaSchemeService { | |||||
String GENERATE_SCHEME_URL = "https://api.weixin.qq.com/wxa/generatescheme"; | |||||
String GENERATE_NFC_SCHEME_URL = "https://api.weixin.qq.com/wxa/generatenfcscheme"; | |||||
/** | |||||
* 获取小程序scheme码 | |||||
*文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.generate.html | |||||
* @param request 请求参数 | |||||
* @throws WxErrorException 生成失败时抛出,具体错误码请看文档 | |||||
*/ | |||||
String generate(WxMaGenerateSchemeRequest request) throws WxErrorException; | |||||
/** | |||||
* 获取NFC 的小程序 scheme | |||||
*文档地址:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-scheme/generateNFCScheme.html | |||||
* @param request 请求参数 | |||||
* @throws WxErrorException 生成失败时抛出,具体错误码请看文档 | |||||
*/ | |||||
String generateNFC(WxMaGenerateNfcSchemeRequest request) throws WxErrorException; | |||||
} |
@@ -156,6 +156,13 @@ public interface WxMaService { | |||||
*/ | */ | ||||
WxMaQrcodeService getQrcodeService(); | WxMaQrcodeService getQrcodeService(); | ||||
/** | |||||
* 返回获取小程序scheme码实现对象,以方便调用其各个接口. | |||||
* | |||||
* @return WxMaSchemeService wx ma scheme service | |||||
*/ | |||||
WxMaSchemeService getWxMaSchemeService(); | |||||
/** | /** | ||||
* 返回模板配置相关接口方法的实现类对象, 以方便调用其各个接口. | * 返回模板配置相关接口方法的实现类对象, 以方便调用其各个接口. | ||||
* | * | ||||
@@ -247,4 +254,11 @@ public interface WxMaService { | |||||
* 获取云开发接口服务对象 | * 获取云开发接口服务对象 | ||||
*/ | */ | ||||
WxMaCloudService getCloudService(); | WxMaCloudService getCloudService(); | ||||
/** | |||||
* 获取直播接口服务对象 | |||||
* | |||||
* @return . | |||||
*/ | |||||
WxMaLiveService getLiveService(); | |||||
} | } |
@@ -0,0 +1,100 @@ | |||||
package cn.binarywang.wx.miniapp.api.impl; | |||||
import cn.binarywang.wx.miniapp.api.WxMaLiveService; | |||||
import cn.binarywang.wx.miniapp.api.WxMaService; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaGetLiveInfo; | |||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||||
import com.google.gson.JsonObject; | |||||
import com.google.gson.JsonParser; | |||||
import lombok.AllArgsConstructor; | |||||
import me.chanjar.weixin.common.WxType; | |||||
import me.chanjar.weixin.common.error.WxError; | |||||
import me.chanjar.weixin.common.error.WxErrorException; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
/** | |||||
* <pre> | |||||
* Created by yjwang on 2020/4/5. | |||||
* </pre> | |||||
* | |||||
* @author <a href="https://github.com/yjwang3300300">yjwang</a> | |||||
*/ | |||||
@AllArgsConstructor | |||||
public class WxMaLiveServiceImpl implements WxMaLiveService { | |||||
private static final JsonParser JSON_PARSER = new JsonParser(); | |||||
private WxMaService service; | |||||
@Override | |||||
public WxMaGetLiveInfo getLiveInfo(Integer start, Integer limit) throws WxErrorException { | |||||
JsonObject jsonObject = getJsonObject(start, limit, null); | |||||
return WxMaGetLiveInfo.fromJson(jsonObject.toString()); | |||||
} | |||||
@Override | |||||
public List<WxMaGetLiveInfo.RoomInfo> getLiveinfos() throws WxErrorException { | |||||
List<WxMaGetLiveInfo.RoomInfo> results = new ArrayList<>(); | |||||
Integer start = 0; | |||||
Integer limit = 80; | |||||
Integer tatal = 0; | |||||
WxMaGetLiveInfo liveInfo = null; | |||||
do { | |||||
if (tatal != 0 && tatal <= start) { | |||||
break; | |||||
} | |||||
liveInfo = getLiveInfo(start, limit); | |||||
if (liveInfo == null) { | |||||
return null; | |||||
} | |||||
results.addAll(liveInfo.getRoomInfos()); | |||||
tatal = liveInfo.getTotal(); | |||||
start = results.size(); | |||||
try { | |||||
Thread.sleep(100); | |||||
} catch (InterruptedException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} while (results.size() <= tatal); | |||||
return results; | |||||
} | |||||
@Override | |||||
public WxMaGetLiveInfo getLiveReplay(String action, Integer room_id, Integer start, Integer limit) throws WxErrorException { | |||||
Map<String, Object> map = new HashMap(4); | |||||
map.put("action", action); | |||||
map.put("room_id", room_id); | |||||
JsonObject jsonObject = getJsonObject(start, limit, map); | |||||
return WxMaGetLiveInfo.fromJson(jsonObject.toString()); | |||||
} | |||||
@Override | |||||
public WxMaGetLiveInfo getLiveReplay(Integer room_id, Integer start, Integer limit) throws WxErrorException { | |||||
return getLiveReplay("get_replay", room_id, start, limit); | |||||
} | |||||
/** | |||||
* 包装一下 | |||||
* | |||||
* @param start | |||||
* @param limit | |||||
* @param map | |||||
* @return | |||||
* @throws WxErrorException | |||||
*/ | |||||
private JsonObject getJsonObject(Integer start, Integer limit, Map<String, Object> map) throws WxErrorException { | |||||
if (map == null) { | |||||
map = new HashMap(2); | |||||
} | |||||
map.put("start", start); | |||||
map.put("limit", limit); | |||||
String responseContent = service.post(GET_LIVE_INFO, WxMaGsonBuilder.create().toJson(map)); | |||||
JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); | |||||
if (jsonObject.get("errcode").getAsInt() != 0) { | |||||
throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); | |||||
} | |||||
return jsonObject; | |||||
} | |||||
} |
@@ -0,0 +1,56 @@ | |||||
package cn.binarywang.wx.miniapp.api.impl; | |||||
import cn.binarywang.wx.miniapp.api.WxMaSchemeService; | |||||
import cn.binarywang.wx.miniapp.api.WxMaService; | |||||
import cn.binarywang.wx.miniapp.bean.scheme.WxMaGenerateNfcSchemeRequest; | |||||
import cn.binarywang.wx.miniapp.bean.scheme.WxMaGenerateSchemeRequest; | |||||
import com.google.gson.JsonObject; | |||||
import lombok.AllArgsConstructor; | |||||
import me.chanjar.weixin.common.WxType; | |||||
import me.chanjar.weixin.common.api.WxConsts; | |||||
import me.chanjar.weixin.common.error.WxError; | |||||
import me.chanjar.weixin.common.error.WxErrorException; | |||||
import me.chanjar.weixin.common.util.json.GsonParser; | |||||
/** | |||||
* @author : cofedream | |||||
* created on : 2021-01-28 | |||||
*/ | |||||
@AllArgsConstructor | |||||
public class WxMaSchemeServiceImpl implements WxMaSchemeService { | |||||
private final WxMaService wxMaService; | |||||
/** | |||||
* 获取小程序scheme码 | |||||
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.generate.html | |||||
* | |||||
* @param request 请求参数 | |||||
* @throws WxErrorException 生成失败时抛出,具体错误码请看文档 | |||||
*/ | |||||
@Override | |||||
public String generate(WxMaGenerateSchemeRequest request) throws WxErrorException { | |||||
String responseContent = this.wxMaService.post(GENERATE_SCHEME_URL, request.toJson()); | |||||
JsonObject jsonObject = GsonParser.parse(responseContent); | |||||
if (jsonObject.get(WxConsts.ERR_CODE).getAsInt() != 0) { | |||||
throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); | |||||
} | |||||
return jsonObject.get("openlink").getAsString(); | |||||
} | |||||
/** | |||||
* 获取NFC 的小程序 scheme | |||||
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-scheme/generateNFCScheme.html | |||||
* | |||||
* @param request 请求参数 | |||||
* @throws WxErrorException 生成失败时抛出,具体错误码请看文档 | |||||
*/ | |||||
@Override | |||||
public String generateNFC(WxMaGenerateNfcSchemeRequest request) throws WxErrorException { | |||||
String responseContent = this.wxMaService.post(GENERATE_NFC_SCHEME_URL, request.toJson()); | |||||
JsonObject jsonObject = GsonParser.parse(responseContent); | |||||
if (jsonObject.get(WxConsts.ERR_CODE).getAsInt() != 0) { | |||||
throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); | |||||
} | |||||
return jsonObject.get("openlink").getAsString(); | |||||
} | |||||
} |
@@ -46,6 +46,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
private WxMaMediaService materialService = new WxMaMediaServiceImpl(this); | private WxMaMediaService materialService = new WxMaMediaServiceImpl(this); | ||||
private WxMaUserService userService = new WxMaUserServiceImpl(this); | private WxMaUserService userService = new WxMaUserServiceImpl(this); | ||||
private WxMaQrcodeService qrCodeService = new WxMaQrcodeServiceImpl(this); | private WxMaQrcodeService qrCodeService = new WxMaQrcodeServiceImpl(this); | ||||
private WxMaSchemeService schemeService = new WxMaSchemeServiceImpl(this); | |||||
private WxMaTemplateService templateService = new WxMaTemplateServiceImpl(this); | private WxMaTemplateService templateService = new WxMaTemplateServiceImpl(this); | ||||
private WxMaAnalysisService analysisService = new WxMaAnalysisServiceImpl(this); | private WxMaAnalysisService analysisService = new WxMaAnalysisServiceImpl(this); | ||||
private WxMaCodeService codeService = new WxMaCodeServiceImpl(this); | private WxMaCodeService codeService = new WxMaCodeServiceImpl(this); | ||||
@@ -58,6 +59,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
private WxMaExpressService expressService = new WxMaExpressServiceImpl(this); | private WxMaExpressService expressService = new WxMaExpressServiceImpl(this); | ||||
private WxMaSubscribeService subscribeService = new WxMaSubscribeServiceImpl(this); | private WxMaSubscribeService subscribeService = new WxMaSubscribeServiceImpl(this); | ||||
private WxMaCloudService cloudService = new WxMaCloudServiceImpl(this); | private WxMaCloudService cloudService = new WxMaCloudServiceImpl(this); | ||||
private WxMaLiveService liveService = new WxMaLiveServiceImpl(this); | |||||
private int retrySleepMillis = 1000; | private int retrySleepMillis = 1000; | ||||
private int maxRetryTimes = 5; | private int maxRetryTimes = 5; | ||||
@@ -330,6 +332,11 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
return this.qrCodeService; | return this.qrCodeService; | ||||
} | } | ||||
@Override | |||||
public WxMaSchemeService getWxMaSchemeService() { | |||||
return schemeService; | |||||
} | |||||
@Override | @Override | ||||
public WxMaTemplateService getTemplateService() { | public WxMaTemplateService getTemplateService() { | ||||
return this.templateService; | return this.templateService; | ||||
@@ -389,4 +396,9 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
public WxMaCloudService getCloudService() { | public WxMaCloudService getCloudService() { | ||||
return this.cloudService; | return this.cloudService; | ||||
} | } | ||||
@Override | |||||
public WxMaLiveService getLiveService() { | |||||
return this.liveService; | |||||
} | |||||
} | } |
@@ -0,0 +1,88 @@ | |||||
package cn.binarywang.wx.miniapp.bean; | |||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* 获取直播房间列表 | |||||
* | |||||
* @author yjwang | |||||
* @date 2020/4/5 | |||||
*/ | |||||
@Data | |||||
public class WxMaGetLiveInfo implements Serializable { | |||||
private static final long serialVersionUID = 7285263767524755887L; | |||||
private Integer errcode; | |||||
private String errmsg; | |||||
private Integer total; | |||||
/** | |||||
* 直播间列表 | |||||
*/ | |||||
@SerializedName("room_info") | |||||
private List<RoomInfo> roomInfos; | |||||
/** | |||||
* 获取回放源视频列表 | |||||
*/ | |||||
@SerializedName("live_replay") | |||||
private List<LiveReplay> liveReplay; | |||||
public static WxMaGetLiveInfo fromJson(String json) { | |||||
return WxMaGsonBuilder.create().fromJson(json, WxMaGetLiveInfo.class); | |||||
} | |||||
/** | |||||
* 直播列表 | |||||
*/ | |||||
@Data | |||||
public static class RoomInfo implements Serializable { | |||||
private static final long serialVersionUID = 7745775280267417154L; | |||||
private String name; | |||||
private Integer roomid; | |||||
@SerializedName("cover_img") | |||||
private String coverImg; | |||||
@SerializedName("live_status") | |||||
private Integer liveStatus; | |||||
@SerializedName("start_time") | |||||
private Long startTime; | |||||
@SerializedName("end_time") | |||||
private Long endTime; | |||||
@SerializedName("anchor_name") | |||||
private String anchorName; | |||||
@SerializedName("anchor_img") | |||||
private String anchorImg; | |||||
private List<Goods> goods; | |||||
} | |||||
/** | |||||
* 商品列表 | |||||
*/ | |||||
@Data | |||||
public static class Goods implements Serializable { | |||||
private static final long serialVersionUID = 5769245932149287574L; | |||||
@SerializedName("cover_img") | |||||
private String coverImg; | |||||
private String url; | |||||
private String price; | |||||
private String name; | |||||
} | |||||
/** | |||||
* 回放数据列表 | |||||
*/ | |||||
@Data | |||||
public static class LiveReplay implements Serializable { | |||||
private static final long serialVersionUID = 7683927205627536320L; | |||||
@SerializedName("expire_time") | |||||
private String expireTime; | |||||
@SerializedName("create_time") | |||||
private String createTime; | |||||
@SerializedName("media_url") | |||||
private String mediaUrl; | |||||
} | |||||
} |
@@ -4,6 +4,7 @@ import java.io.Serializable; | |||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | ||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.extern.slf4j.Slf4j; | |||||
/** | /** | ||||
* 微信用户绑定的手机号相关信息 | * 微信用户绑定的手机号相关信息 | ||||
@@ -0,0 +1,75 @@ | |||||
package cn.binarywang.wx.miniapp.bean.scheme; | |||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
/** | |||||
* @author : lyt | |||||
* created on : 2023-07-31 | |||||
*/ | |||||
@Data | |||||
@Builder(builderMethodName = "newBuilder") | |||||
public class WxMaGenerateNfcSchemeRequest { | |||||
/** | |||||
* 跳转到的目标小程序信息。 | |||||
* <pre> | |||||
* 是否必填:否 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("jump_wxa") | |||||
private JumpWxa jumpWxa; | |||||
/** | |||||
* scheme对应的设备model_id | |||||
* <pre> | |||||
* 是否必填:是 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("model_id") | |||||
private String modelId; | |||||
/** | |||||
* scheme对应的设备sn,仅一机一码时填写 | |||||
* <pre> | |||||
* 是否必填:否 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("sn") | |||||
private String sn; | |||||
@Data | |||||
@Builder(builderMethodName = "newBuilder") | |||||
public static class JumpWxa { | |||||
/** | |||||
* 通过scheme码进入的小程序页面路径,必须是已经发布的小程序存在的页面,不可携带query。path为空时会跳转小程序主页。 | |||||
* <pre> | |||||
* 是否必填:是 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("path") | |||||
private String path; | |||||
/** | |||||
* 通过scheme码进入小程序时的query,最大128个字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~ | |||||
* 返回值 | |||||
* <pre> | |||||
* 是否必填:是 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("query") | |||||
private String query; | |||||
/** | |||||
* 要打开的小程序版本。正式版为"release",体验版为"trial",开发版为"develop"默认值:release | |||||
*/ | |||||
@SerializedName("env_version") | |||||
private String envVersion = "release"; | |||||
} | |||||
public String toJson() { | |||||
return WxMaGsonBuilder.create().toJson(this); | |||||
} | |||||
} |
@@ -0,0 +1,94 @@ | |||||
package cn.binarywang.wx.miniapp.bean.scheme; | |||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
/** | |||||
* @author : cofedream | |||||
* created on : 2021-01-26 | |||||
*/ | |||||
@Data | |||||
@Builder(builderMethodName = "newBuilder") | |||||
public class WxMaGenerateSchemeRequest { | |||||
/** | |||||
* 跳转到的目标小程序信息。 | |||||
* <pre> | |||||
* 是否必填:否 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("jump_wxa") | |||||
private JumpWxa jumpWxa; | |||||
/** | |||||
* 生成的scheme码类型,到期失效:true,永久有效:false。 | |||||
* <pre> | |||||
* 是否必填:否 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("is_expire") | |||||
private Boolean isExpire; | |||||
/** | |||||
* 到期失效的scheme码的失效时间,为Unix时间戳。生成的到期失效scheme码在该时间前有效。最长有效期为1年。生成到期失效的scheme时必填。 | |||||
* <pre> | |||||
* 是否必填:否 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("expire_time") | |||||
private Long expireTime; | |||||
/** | |||||
* 到期失效的 scheme 码失效类型,失效时间:0,失效间隔天数:1 | |||||
* <pre> | |||||
* 是否必填:否 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("expire_type") | |||||
private Integer expireType; | |||||
/** | |||||
* 到期失效的 scheme 码的失效间隔天数。 | |||||
* <pre> | |||||
* 生成的到期失效 scheme 码在该间隔时间到达前有效。最长间隔天数为365天。is_expire 为 true 且 expire_type 为 1 时必填 * <pre> | |||||
* 是否必填:否 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("expire_interval") | |||||
private Integer expireInterval; | |||||
@Data | |||||
@Builder(builderMethodName = "newBuilder") | |||||
public static class JumpWxa { | |||||
/** | |||||
* 通过scheme码进入的小程序页面路径,必须是已经发布的小程序存在的页面,不可携带query。path为空时会跳转小程序主页。 | |||||
* <pre> | |||||
* 是否必填:是 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("path") | |||||
private String path; | |||||
/** | |||||
* 通过scheme码进入小程序时的query,最大128个字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~ | |||||
* 返回值 | |||||
* <pre> | |||||
* 是否必填:是 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("query") | |||||
private String query; | |||||
/** | |||||
* 要打开的小程序版本。正式版为"release",体验版为"trial",开发版为"develop"默认值:release | |||||
*/ | |||||
@SerializedName("env_version") | |||||
private String envVersion = "release"; | |||||
} | |||||
public String toJson() { | |||||
return WxMaGsonBuilder.create().toJson(this); | |||||
} | |||||
} |
@@ -0,0 +1,55 @@ | |||||
package cn.binarywang.wx.miniapp.api.impl; | |||||
import cn.binarywang.wx.miniapp.api.WxMaService; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaGetLiveInfo; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; | |||||
import cn.binarywang.wx.miniapp.test.ApiTestModule; | |||||
import cn.binarywang.wx.miniapp.test.TestConfig; | |||||
import com.google.common.collect.ImmutableMap; | |||||
import com.google.gson.JsonObject; | |||||
import com.google.inject.Inject; | |||||
import me.chanjar.weixin.common.error.WxErrorException; | |||||
import org.testng.annotations.Guice; | |||||
import org.testng.annotations.Test; | |||||
import java.util.List; | |||||
import java.util.stream.Collectors; | |||||
import static org.testng.Assert.assertNotNull; | |||||
import static org.testng.Assert.assertTrue; | |||||
/** | |||||
* 测试直播相关的接口 | |||||
* | |||||
* @author <a href="https://github.com/yjwang3300300">yjwang</a> | |||||
*/ | |||||
@Test | |||||
@Guice(modules = ApiTestModule.class) | |||||
public class WxMaLiveServiceImplTest { | |||||
@Inject | |||||
private WxMaService wxService; | |||||
@Test | |||||
public void getLiveInfo() throws Exception { | |||||
WxMaGetLiveInfo list = this.wxService.getLiveService().getLiveInfo(0,10); | |||||
assertNotNull(list); | |||||
System.out.println(list.toString()); | |||||
} | |||||
@Test | |||||
public void getLiveReplay() throws Exception { | |||||
// [12, 11, 10, 9, 8, 7, 6, 5, 3, 2] | |||||
WxMaGetLiveInfo list = this.wxService.getLiveService().getLiveReplay(11,0,10); | |||||
assertNotNull(list); | |||||
System.out.println(list.toString()); | |||||
} | |||||
@Test | |||||
public void getLiveinfos() throws Exception { | |||||
List<WxMaGetLiveInfo.RoomInfo> list = this.wxService.getLiveService().getLiveinfos(); | |||||
assertNotNull(list); | |||||
System.out.println(list.toString()); | |||||
} | |||||
} |
@@ -7,7 +7,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>wx-java</artifactId> | <artifactId>wx-java</artifactId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-mp</artifactId> | <artifactId>weixin-java-mp</artifactId> | ||||
@@ -46,7 +46,7 @@ public class WxMpServiceJoddHttpImpl extends BaseWxMpServiceImpl<HttpConnectionP | |||||
httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); | httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); | ||||
} | } | ||||
httpClient = JoddHttp.httpConnectionProvider; | |||||
httpClient = new SocketHttpConnectionProvider(); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -4,7 +4,6 @@ import jodd.http.HttpConnectionProvider; | |||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.util.StringPool; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
@@ -12,6 +11,7 @@ import me.chanjar.weixin.common.error.WxErrorException; | |||||
import me.chanjar.weixin.common.util.http.RequestHttp; | import me.chanjar.weixin.common.util.http.RequestHttp; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.nio.charset.StandardCharsets; | |||||
/** | /** | ||||
* Created by ecoolper on 2017/5/5. | * Created by ecoolper on 2017/5/5. | ||||
@@ -31,7 +31,7 @@ public class MaterialDeleteJoddHttpRequestExecutor extends MaterialDeleteRequest | |||||
request.query("media_id", materialId); | request.query("media_id", materialId); | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
String responseContent = response.bodyText(); | String responseContent = response.bodyText(); | ||||
WxError error = WxError.fromJson(responseContent, WxType.MP); | WxError error = WxError.fromJson(responseContent, WxType.MP); | ||||
if (error.getErrorCode() != 0) { | if (error.getErrorCode() != 0) { | ||||
@@ -5,7 +5,6 @@ import jodd.http.HttpConnectionProvider; | |||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.util.StringPool; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
@@ -18,6 +17,7 @@ import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.nio.charset.StandardCharsets; | |||||
/** | /** | ||||
* Created by ecoolper on 2017/5/5. | * Created by ecoolper on 2017/5/5. | ||||
@@ -38,7 +38,7 @@ public class MaterialNewsInfoJoddHttpRequestExecutor extends MaterialNewsInfoReq | |||||
.withConnectionProvider(requestHttp.getRequestHttpClient()) | .withConnectionProvider(requestHttp.getRequestHttpClient()) | ||||
.body(WxGsonBuilder.create().toJson(ImmutableMap.of("media_id", materialId))); | .body(WxGsonBuilder.create().toJson(ImmutableMap.of("media_id", materialId))); | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
String responseContent = response.bodyText(); | String responseContent = response.bodyText(); | ||||
this.logger.debug("响应原始数据:{}", responseContent); | this.logger.debug("响应原始数据:{}", responseContent); | ||||
@@ -4,7 +4,6 @@ import jodd.http.HttpConnectionProvider; | |||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.util.StringPool; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
@@ -17,6 +16,7 @@ import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.FileNotFoundException; | import java.io.FileNotFoundException; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.nio.charset.StandardCharsets; | |||||
import java.util.Map; | import java.util.Map; | ||||
/** | /** | ||||
@@ -50,7 +50,7 @@ public class MaterialUploadJoddHttpRequestExecutor extends MaterialUploadRequest | |||||
} | } | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
String responseContent = response.bodyText(); | String responseContent = response.bodyText(); | ||||
WxError error = WxError.fromJson(responseContent, WxType.MP); | WxError error = WxError.fromJson(responseContent, WxType.MP); | ||||
if (error.getErrorCode() != 0) { | if (error.getErrorCode() != 0) { | ||||
@@ -4,7 +4,6 @@ import jodd.http.HttpConnectionProvider; | |||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.util.StringPool; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
@@ -13,6 +12,7 @@ import me.chanjar.weixin.common.util.http.RequestHttp; | |||||
import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; | import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.nio.charset.StandardCharsets; | |||||
/** | /** | ||||
* Created by ecoolper on 2017/5/5. | * Created by ecoolper on 2017/5/5. | ||||
@@ -32,7 +32,7 @@ public class MaterialVideoInfoJoddHttpRequestExecutor extends MaterialVideoInfoR | |||||
request.query("media_id", materialId); | request.query("media_id", materialId); | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
String responseContent = response.bodyText(); | String responseContent = response.bodyText(); | ||||
WxError error = WxError.fromJson(responseContent, WxType.MP); | WxError error = WxError.fromJson(responseContent, WxType.MP); | ||||
if (error.getErrorCode() != 0) { | if (error.getErrorCode() != 0) { | ||||
@@ -37,7 +37,7 @@ public class MaterialVoiceAndImageDownloadJoddHttpRequestExecutor extends Materi | |||||
request.query("media_id", materialId); | request.query("media_id", materialId); | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { | try (InputStream inputStream = new ByteArrayInputStream(response.bodyBytes())) { | ||||
// 下载媒体文件出错 | // 下载媒体文件出错 | ||||
byte[] responseContent = IOUtils.toByteArray(inputStream); | byte[] responseContent = IOUtils.toByteArray(inputStream); | ||||
@@ -4,7 +4,6 @@ import jodd.http.HttpConnectionProvider; | |||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.util.StringPool; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
@@ -14,6 +13,7 @@ import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.nio.charset.StandardCharsets; | |||||
/** | /** | ||||
* Created by ecoolper on 2017/5/5. | * Created by ecoolper on 2017/5/5. | ||||
@@ -39,7 +39,7 @@ public class MediaImgUploadHttpRequestExecutor extends MediaImgUploadRequestExec | |||||
request.form("media", data); | request.form("media", data); | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
String responseContent = response.bodyText(); | String responseContent = response.bodyText(); | ||||
WxError error = WxError.fromJson(responseContent, WxType.MP); | WxError error = WxError.fromJson(responseContent, WxType.MP); | ||||
if (error.getErrorCode() != 0) { | if (error.getErrorCode() != 0) { | ||||
@@ -4,9 +4,8 @@ import jodd.http.HttpConnectionProvider; | |||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.util.MimeTypes; | |||||
import jodd.util.StringPool; | |||||
import jodd.net.MimeTypes; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
@@ -19,6 +18,7 @@ import java.io.File; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.net.URLEncoder; | import java.net.URLEncoder; | ||||
import java.nio.charset.StandardCharsets; | |||||
import java.util.UUID; | import java.util.UUID; | ||||
/** | /** | ||||
@@ -47,7 +47,7 @@ public class QrCodeJoddHttpRequestExecutor extends QrCodeRequestExecutor<HttpCon | |||||
request.withConnectionProvider(requestHttp.getRequestHttpClient()); | request.withConnectionProvider(requestHttp.getRequestHttpClient()); | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
String contentTypeHeader = response.header("Content-Type"); | String contentTypeHeader = response.header("Content-Type"); | ||||
if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { | if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { | ||||
String responseContent = response.bodyText(); | String responseContent = response.bodyText(); | ||||
@@ -7,7 +7,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>wx-java</artifactId> | <artifactId>wx-java</artifactId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-open</artifactId> | <artifactId>weixin-java-open</artifactId> | ||||
@@ -166,6 +166,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService { | |||||
String componentAccessToken = getComponentAccessToken(false); | String componentAccessToken = getComponentAccessToken(false); | ||||
String uriWithComponentAccessToken = uri + (uri.contains("?") ? "&" : "?") + accessTokenKey + "=" + componentAccessToken; | String uriWithComponentAccessToken = uri + (uri.contains("?") ? "&" : "?") + accessTokenKey + "=" + componentAccessToken; | ||||
try { | try { | ||||
this.log.info("wxopencomponent excute url:"+uriWithComponentAccessToken); | |||||
return getWxOpenService().get(uriWithComponentAccessToken, null); | return getWxOpenService().get(uriWithComponentAccessToken, null); | ||||
} catch (WxErrorException e) { | } catch (WxErrorException e) { | ||||
WxError error = e.getError(); | WxError error = e.getError(); | ||||
@@ -246,6 +247,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService { | |||||
@Override | @Override | ||||
public String route(final WxOpenXmlMessage wxMessage) throws WxErrorException { | public String route(final WxOpenXmlMessage wxMessage) throws WxErrorException { | ||||
log.info("wxopencomponent route :"+wxMessage); | |||||
if (wxMessage == null) { | if (wxMessage == null) { | ||||
throw new NullPointerException("message is empty"); | throw new NullPointerException("message is empty"); | ||||
} | } | ||||
@@ -8,6 +8,7 @@ import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; | import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; | ||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; | import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; | ||||
import me.chanjar.weixin.open.api.WxOpenConfigStorage; | import me.chanjar.weixin.open.api.WxOpenConfigStorage; | ||||
import me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage; | |||||
import me.chanjar.weixin.open.util.WxOpenCryptUtil; | import me.chanjar.weixin.open.util.WxOpenCryptUtil; | ||||
import me.chanjar.weixin.open.util.xml.XStreamTransformer; | import me.chanjar.weixin.open.util.xml.XStreamTransformer; | ||||
import org.apache.commons.io.IOUtils; | import org.apache.commons.io.IOUtils; | ||||
@@ -140,6 +141,7 @@ public class WxOpenXmlMessage implements Serializable { | |||||
String timestamp, String nonce, String msgSignature) { | String timestamp, String nonce, String msgSignature) { | ||||
WxOpenCryptUtil cryptUtil = new WxOpenCryptUtil(wxOpenConfigStorage); | WxOpenCryptUtil cryptUtil = new WxOpenCryptUtil(wxOpenConfigStorage); | ||||
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); | String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); | ||||
log.debug("解密后的原始xml消息内容:{}", plainText); | |||||
return WxMpXmlMessage.fromXml(plainText); | return WxMpXmlMessage.fromXml(plainText); | ||||
} | } | ||||
@@ -152,4 +154,31 @@ public class WxOpenXmlMessage implements Serializable { | |||||
throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
} | } | ||||
} | } | ||||
public static void main(String[] args) { | |||||
WxOpenInMemoryConfigStorage wxOpenConfigStorage = new WxOpenInMemoryConfigStorage(); | |||||
wxOpenConfigStorage.setComponentAesKey(""); | |||||
wxOpenConfigStorage.setComponentToken(""); | |||||
wxOpenConfigStorage.setComponentAppId(""); | |||||
WxOpenCryptUtil cryptUtil = new WxOpenCryptUtil(wxOpenConfigStorage); | |||||
/** | |||||
* 接收微信APP回调:[appId=[wx3cb90ab25f132468], openid=[ok9Xtt7rErEqlQKBjaluwroxsHaM], signature=[50e3ddd2d2817cbc309ed0a4b9b6eafe6e4c8648], encType=[aes], msgSignature=[00c9b32600e67276a56e2092fe3dfe1c486318f5], timestamp=[1653534263], nonce=[897774971], requestBody=[ | |||||
* <xml> | |||||
* <ToUserName><![CDATA[gh_ddfa54d85724]]></ToUserName> | |||||
* <Encrypt><![CDATA[EUzw+5L2Vsqs6fxq4ZGw1S/Hu/4Gx04Z4v2ZqE45OM5OHvK/6z0K21D2wdVv20YmswbsxW7bThe2vvoMqf8dktp4MbOqLMACpYt9B1UeQBoG0tnwiQo1PggTLr3iomBVxRERVpLcyIRZHbyGW0sg3zKjecVGlvMgL4fQFCZmi5swzuR8zXsHQ9LlPiB0jSaF37cj0g7YMyYlzZ1GRyleGljLER3P+Plqa727bpJjGwRgSkBBco8vm4bEcOyTiO0Yy5gARMHC2bcQkhqgUgp6XRyz5YM9jW6DwXPhVCY+X/vvTL1gPm/UAZpwY+YUNh+1o+xm45MX+FjHXN/kbdeVV6NqO8VGF0sP0XYBlenBm4a3CmxU5AjNTauM1f6KSpoLV0R1c02l2hbvpwZ32CEgD5uriOh2NWOnWuLD58AScA8xyIUzdENUsYlq60H9tRd4KRbSydcwp2ALCcm0B1KS/GDT/587TntnL+Ai2VrUSnlZej/ByV8D4dvEuAU+5/ky]]></Encrypt> | |||||
* </xml> | |||||
* | |||||
* ] | |||||
*/ | |||||
String msgSignature = "50e3ddd2d2817cbc309ed0a4b9b6eafe6e4c8648"; | |||||
String timestamp = "1653534263"; | |||||
String nonce = "897774971"; | |||||
String encryptedXml = "<xml>\n" + | |||||
" <ToUserName><![CDATA[gh_ddfa54d85724]]></ToUserName>\n" + | |||||
" <Encrypt><![CDATA[EUzw+5L2Vsqs6fxq4ZGw1S/Hu/4Gx04Z4v2ZqE45OM5OHvK/6z0K21D2wdVv20YmswbsxW7bThe2vvoMqf8dktp4MbOqLMACpYt9B1UeQBoG0tnwiQo1PggTLr3iomBVxRERVpLcyIRZHbyGW0sg3zKjecVGlvMgL4fQFCZmi5swzuR8zXsHQ9LlPiB0jSaF37cj0g7YMyYlzZ1GRyleGljLER3P+Plqa727bpJjGwRgSkBBco8vm4bEcOyTiO0Yy5gARMHC2bcQkhqgUgp6XRyz5YM9jW6DwXPhVCY+X/vvTL1gPm/UAZpwY+YUNh+1o+xm45MX+FjHXN/kbdeVV6NqO8VGF0sP0XYBlenBm4a3CmxU5AjNTauM1f6KSpoLV0R1c02l2hbvpwZ32CEgD5uriOh2NWOnWuLD58AScA8xyIUzdENUsYlq60H9tRd4KRbSydcwp2ALCcm0B1KS/GDT/587TntnL+Ai2VrUSnlZej/ByV8D4dvEuAU+5/ky]]></Encrypt>\n" + | |||||
"</xml>"; | |||||
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); | |||||
System.out.println(plainText); | |||||
} | |||||
} | } |
@@ -4,8 +4,7 @@ import jodd.http.HttpConnectionProvider; | |||||
import jodd.http.HttpRequest; | import jodd.http.HttpRequest; | ||||
import jodd.http.HttpResponse; | import jodd.http.HttpResponse; | ||||
import jodd.http.ProxyInfo; | import jodd.http.ProxyInfo; | ||||
import jodd.util.MimeTypes; | |||||
import jodd.util.StringPool; | |||||
import jodd.net.MimeTypes; | |||||
import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||
import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||
import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
@@ -19,6 +18,7 @@ import java.io.File; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.net.URLEncoder; | import java.net.URLEncoder; | ||||
import java.nio.charset.StandardCharsets; | |||||
import java.util.UUID; | import java.util.UUID; | ||||
/** | /** | ||||
@@ -49,7 +49,7 @@ public class MaQrCodeJoddHttpRequestExecutor extends MaQrCodeRequestExecutor<Htt | |||||
request.withConnectionProvider(requestHttp.getRequestHttpClient()); | request.withConnectionProvider(requestHttp.getRequestHttpClient()); | ||||
HttpResponse response = request.send(); | HttpResponse response = request.send(); | ||||
response.charset(StringPool.UTF_8); | |||||
response.charset(StandardCharsets.UTF_8.name()); | |||||
String contentTypeHeader = response.header("Content-Type"); | String contentTypeHeader = response.header("Content-Type"); | ||||
if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { | if (MimeTypes.MIME_TEXT_PLAIN.equals(contentTypeHeader)) { | ||||
String responseContent = response.bodyText(); | String responseContent = response.bodyText(); | ||||
@@ -5,13 +5,25 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>wx-java</artifactId> | <artifactId>wx-java</artifactId> | ||||
<version>3.7.0</version> | |||||
<version>3.7.0.B</version> | |||||
</parent> | </parent> | ||||
<modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
<artifactId>weixin-java-pay</artifactId> | <artifactId>weixin-java-pay</artifactId> | ||||
<name>WxJava - PAY Java SDK</name> | <name>WxJava - PAY Java SDK</name> | ||||
<description>微信支付 Java SDK</description> | <description>微信支付 Java SDK</description> | ||||
<build> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-compiler-plugin</artifactId> | |||||
<configuration> | |||||
<source>8</source> | |||||
<target>8</target> | |||||
</configuration> | |||||
</plugin> | |||||
</plugins> | |||||
</build> | |||||
<dependencies> | <dependencies> | ||||
<dependency> | <dependency> | ||||
@@ -0,0 +1,87 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment; | |||||
import com.github.binarywang.wxpay.bean.applyment.enums.ApplymentStateEnum; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import lombok.experimental.Accessors; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* 查询申请单状态返回对象信息 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
@Accessors(chain = true) | |||||
public class ApplymentStateQueryResult implements Serializable { | |||||
private static final long serialVersionUID = 6539090917423486409L; | |||||
/** | |||||
* 业务申请编号 | |||||
*/ | |||||
@SerializedName("business_code") | |||||
private String businessCode; | |||||
/** | |||||
* 微信支付申请单号 | |||||
*/ | |||||
@SerializedName("applyment_id") | |||||
private String applymentId; | |||||
/** | |||||
* 特约商户号 | |||||
*/ | |||||
@SerializedName("sub_mchid") | |||||
private String subMchid; | |||||
/** | |||||
* 超级管理员签约链接 | |||||
*/ | |||||
@SerializedName("sign_url") | |||||
private String signUrl; | |||||
/** | |||||
* 申请单状态 | |||||
*/ | |||||
@SerializedName("applyment_state") | |||||
private ApplymentStateEnum applymentState; | |||||
/** | |||||
* 申请状态描述 | |||||
*/ | |||||
@SerializedName("applyment_state_msg") | |||||
private String applymentStateMsg; | |||||
/** | |||||
* 驳回原因详情 | |||||
*/ | |||||
@SerializedName("audit_detail") | |||||
private List<AuditDetail> auditDetail; | |||||
/** | |||||
* 驳回原因详情 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
@Accessors(chain = true) | |||||
public static class AuditDetail { | |||||
/** | |||||
* 字段名 | |||||
*/ | |||||
@SerializedName("field") | |||||
private String field; | |||||
/** | |||||
* 字段名称 | |||||
*/ | |||||
@SerializedName("field_name") | |||||
private String fieldName; | |||||
/** | |||||
* 驳回原因 | |||||
*/ | |||||
@SerializedName("reject_reason") | |||||
private String rejectReason; | |||||
} | |||||
} |
@@ -0,0 +1,62 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment; | |||||
import com.github.binarywang.wxpay.bean.applyment.enums.AccountTypeEnum; | |||||
import com.github.binarywang.wxpay.v3.SpecEncrypt; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import lombok.experimental.Accessors; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 修改结算账户请求对象 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
@Accessors(chain = true) | |||||
public class ModifySettlementRequest implements Serializable { | |||||
private static final long serialVersionUID = 4568552340365230872L; | |||||
/** | |||||
* 账户类型 | |||||
*/ | |||||
@SerializedName("account_type") | |||||
private AccountTypeEnum accountType; | |||||
/** | |||||
* 开户名称 | |||||
*/ | |||||
@SpecEncrypt | |||||
@SerializedName("account_name") | |||||
private String accountName; | |||||
/** | |||||
* 开户银行 | |||||
*/ | |||||
@SerializedName("account_bank") | |||||
private String accountBank; | |||||
/** | |||||
* 开户银行省市编码 | |||||
*/ | |||||
@SerializedName("bank_address_code") | |||||
private String bankAddressCode; | |||||
/** | |||||
* 开户银行全称(含支行) | |||||
*/ | |||||
@SerializedName("bank_name") | |||||
private String bankName; | |||||
/** | |||||
* 开户银行联行号 | |||||
*/ | |||||
@SerializedName("bank_branch_id") | |||||
private String bankBranchId; | |||||
/** | |||||
* 银行账号 | |||||
*/ | |||||
@SpecEncrypt | |||||
@SerializedName("account_number") | |||||
private String accountNumber; | |||||
} |
@@ -0,0 +1,62 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment; | |||||
import com.github.binarywang.wxpay.bean.applyment.enums.AccountTypeEnum; | |||||
import com.github.binarywang.wxpay.bean.applyment.enums.SettlementVerifyResultEnum; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import lombok.experimental.Accessors; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 查询结算账户返回对象信息 | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
@Accessors(chain = true) | |||||
public class SettlementInfoResult implements Serializable { | |||||
private static final long serialVersionUID = 4568552340365230872L; | |||||
/** | |||||
* 账户类型 | |||||
*/ | |||||
@SerializedName("account_type") | |||||
private AccountTypeEnum accountType; | |||||
/** | |||||
* 开户银行 | |||||
*/ | |||||
@SerializedName("account_bank") | |||||
private String accountBank; | |||||
/** | |||||
* 开户银行全称(含支行] | |||||
*/ | |||||
@SerializedName("bank_name") | |||||
private String bankName; | |||||
/** | |||||
* 开户银行联行号 | |||||
*/ | |||||
@SerializedName("bank_branch_id") | |||||
private String bankBranchId; | |||||
/** | |||||
* 银行账号 | |||||
*/ | |||||
@SerializedName("account_number") | |||||
private String accountNumber; | |||||
/** | |||||
* 汇款验证结果 | |||||
* | |||||
* @see com.github.binarywang.wxpay.bean.applyment.enums.SettlementVerifyResultEnum | |||||
*/ | |||||
@SerializedName("verify_result") | |||||
private SettlementVerifyResultEnum verifyResult; | |||||
/** | |||||
* 汇款验证失败原因 | |||||
*/ | |||||
@SerializedName("verify_fail_reason") | |||||
private String verifyFailReason; | |||||
} |
@@ -0,0 +1,31 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import lombok.experimental.Accessors; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 特约商户进件 提交申请结果响应 | |||||
* | |||||
* @author zhouyongshen | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
@Accessors(chain = true) | |||||
public class WxPayApplymentCreateResult implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 微信支付申请单号 | |||||
*/ | |||||
@SerializedName("applyment_id") | |||||
private String applymentId; | |||||
} |
@@ -0,0 +1,18 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment.enums; | |||||
/** | |||||
* 银行结算账户枚举类 | |||||
*/ | |||||
public enum AccountTypeEnum { | |||||
/** | |||||
* 对公银行账户 | |||||
*/ | |||||
ACCOUNT_TYPE_BUSINESS, | |||||
/** | |||||
* 经营者个人银行卡 | |||||
*/ | |||||
ACCOUNT_TYPE_PRIVATE, | |||||
; | |||||
} |
@@ -0,0 +1,42 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment.enums; | |||||
/** | |||||
* 申请单状态枚举类 | |||||
* | |||||
* @author zhouyongshen | |||||
*/ | |||||
public enum ApplymentStateEnum { | |||||
/** | |||||
* (编辑中):提交申请发生错误导致,请尝试重新提交。 | |||||
*/ | |||||
APPLYMENT_STATE_EDITTING, | |||||
/** | |||||
* (审核中):申请单正在审核中,超级管理员用微信打开“签约链接”,完成绑定微信号后,申请单进度将通过微信公众号通知超级管理员,引导完成后续步骤。 | |||||
*/ | |||||
APPLYMENT_STATE_AUDITING, | |||||
/** | |||||
* (已驳回):请按照驳回原因修改申请资料,超级管理员用微信打开“签约链接”,完成绑定微信号,后续申请单进度将通过微信公众号通知超级管理员。 | |||||
*/ | |||||
APPLYMENT_STATE_REJECTED, | |||||
/** | |||||
* (待账户验证):请超级管理员使用微信打开返回的“签约链接”,根据页面指引完成账户验证。 | |||||
*/ | |||||
APPLYMENT_STATE_TO_BE_CONFIRMED, | |||||
/** | |||||
* (待签约):请超级管理员使用微信打开返回的“签约链接”,根据页面指引完成签约。 | |||||
*/ | |||||
APPLYMENT_STATE_TO_BE_SIGNED, | |||||
/** | |||||
* (开通权限中):系统开通相关权限中,请耐心等待。 | |||||
*/ | |||||
APPLYMENT_STATE_SIGNING, | |||||
/** | |||||
* (已完成):商户入驻申请已完成。 | |||||
*/ | |||||
APPLYMENT_STATE_FINISHED, | |||||
/** | |||||
* (已作废):申请单已被撤销。 | |||||
*/ | |||||
APPLYMENT_STATE_CANCELED | |||||
} |
@@ -0,0 +1,18 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment.enums; | |||||
/** | |||||
* 银行结算账户枚举类 | |||||
*/ | |||||
public enum BankAccountTypeEnum { | |||||
/** | |||||
* 对公银行账户 | |||||
*/ | |||||
BANK_ACCOUNT_TYPE_CORPORATE, | |||||
/** | |||||
* 经营者个人银行卡 | |||||
*/ | |||||
BANK_ACCOUNT_TYPE_PERSONAL, | |||||
; | |||||
} |
@@ -0,0 +1,64 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment.enums; | |||||
/** | |||||
* 登记证书的类型枚举 | |||||
*/ | |||||
public enum CertTypeEnum { | |||||
/** | |||||
* 事业单位法人证书 | |||||
*/ | |||||
CERTIFICATE_TYPE_2388, | |||||
/** | |||||
* 统一社会信用代码证书 | |||||
*/ | |||||
CERTIFICATE_TYPE_2389, | |||||
/** | |||||
* 有偿服务许可证(军队医院适用) | |||||
*/ | |||||
CERTIFICATE_TYPE_2390, | |||||
/** | |||||
* 医疗机构执业许可证(军队医院适用) | |||||
*/ | |||||
CERTIFICATE_TYPE_2391, | |||||
/** | |||||
* 企业营业执照(挂靠企业的党组织适用) | |||||
*/ | |||||
CERTIFICATE_TYPE_2392, | |||||
/** | |||||
* 组织机构代码证(政府机关适用) | |||||
*/ | |||||
CERTIFICATE_TYPE_2393, | |||||
/** | |||||
* 社会团体法人登记证书 | |||||
*/ | |||||
CERTIFICATE_TYPE_2394, | |||||
/** | |||||
* 民办非企业单位登记证书 | |||||
*/ | |||||
CERTIFICATE_TYPE_2395, | |||||
/** | |||||
* 基金会法人登记证书 | |||||
*/ | |||||
CERTIFICATE_TYPE_2396, | |||||
/** | |||||
* 宗教活动场所登记证 | |||||
*/ | |||||
CERTIFICATE_TYPE_2399, | |||||
/** | |||||
* 其他证书/批文/证明 | |||||
*/ | |||||
CERTIFICATE_TYPE_2400, | |||||
/** | |||||
* 执业许可证/执业证 | |||||
*/ | |||||
CERTIFICATE_TYPE_2520, | |||||
/** | |||||
* 基层群众性自治组织特别法人统一社会信用代码证 | |||||
*/ | |||||
CERTIFICATE_TYPE_2521, | |||||
/** | |||||
* 农村集体经济组织登记证 | |||||
*/ | |||||
CERTIFICATE_TYPE_2522, | |||||
; | |||||
} |
@@ -0,0 +1,17 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment.enums; | |||||
/** | |||||
* 1、主体为“个体工商户/企业/政府机关/事业单位/社会组织”,可选择:LEGAL:经营者/法人,SUPER:经办人 。(经办人:经商户授权办理微信支付业务的人员)。 | |||||
* 枚举值 | |||||
*/ | |||||
public enum ContactTypeEnum { | |||||
/** | |||||
* 法人 | |||||
*/ | |||||
LEGAL, | |||||
/** | |||||
* 经办人 | |||||
*/ | |||||
SUPER, | |||||
; | |||||
} |
@@ -0,0 +1,20 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment.enums; | |||||
/** | |||||
* 1. 主体类型为政府机关、事业单位时选传: | |||||
* (1)若上传的是法人证件,则不需要上传该字段 | |||||
* (2)若因特殊情况,无法提供法人证件时,可上传经办人。 (经办人:经商户授权办理微信支付业务的人员,授权范围包括但不限于签约,入驻过程需完成账户验证)。 | |||||
* 2. 主体类型为企业、个体户、社会组织时,默认为经营者/法人,不需要上传该字段。 | |||||
* 枚举值 | |||||
*/ | |||||
public enum IdHolderEnum { | |||||
/** | |||||
* 法人 | |||||
*/ | |||||
LEGAL, | |||||
/** | |||||
* 经办人 | |||||
*/ | |||||
SUPER, | |||||
; | |||||
} |
@@ -0,0 +1,41 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment.enums; | |||||
/** | |||||
* 个体户/企业/党政、机关及事业单位/其他组织:可选择任一证件类型。 | |||||
* 枚举值 | |||||
*/ | |||||
public enum IdTypeEnum { | |||||
/** | |||||
* 中国大陆居民-身份证 | |||||
*/ | |||||
IDENTIFICATION_TYPE_IDCARD, | |||||
/** | |||||
* 其他国家或地区居民-护照 | |||||
*/ | |||||
IDENTIFICATION_TYPE_OVERSEA_PASSPORT, | |||||
/** | |||||
* 中国香港居民-来往内地通行证 | |||||
*/ | |||||
IDENTIFICATION_TYPE_HONGKONG_PASSPORT, | |||||
/** | |||||
* 中国澳门居民-来往内地通行证 | |||||
*/ | |||||
IDENTIFICATION_TYPE_MACAO_PASSPORT, | |||||
/** | |||||
* 中国台湾居民-来往大陆通行证 | |||||
*/ | |||||
IDENTIFICATION_TYPE_TAIWAN_PASSPORT, | |||||
/** | |||||
* 外国人居留证 | |||||
*/ | |||||
IDENTIFICATION_TYPE_FOREIGN_RESIDENT, | |||||
/** | |||||
* 港澳居民证 | |||||
*/ | |||||
IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT, | |||||
/** | |||||
* 台湾居民证 | |||||
*/ | |||||
IDENTIFICATION_TYPE_TAIWAN_RESIDENT, | |||||
; | |||||
} |
@@ -0,0 +1,20 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment.enums; | |||||
/** | |||||
* 小微经营类型 | |||||
*/ | |||||
public enum MicroBizTypeEnum { | |||||
/** | |||||
* 门店场所 | |||||
*/ | |||||
MICRO_TYPE_STORE, | |||||
/** | |||||
* 流动经营/便民服务 | |||||
*/ | |||||
MICRO_TYPE_MOBILE, | |||||
/** | |||||
* 线上商品/服务交易 | |||||
*/ | |||||
MICRO_TYPE_ONLINE, | |||||
; | |||||
} |
@@ -0,0 +1,32 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment.enums; | |||||
/** | |||||
* 经营场景类型枚举值 | |||||
*/ | |||||
public enum SalesScenesTypeEnum { | |||||
/** | |||||
* 线下门店 | |||||
*/ | |||||
SALES_SCENES_STORE, | |||||
/** | |||||
* 公众号 | |||||
*/ | |||||
SALES_SCENES_MP, | |||||
/** | |||||
* 小程序 | |||||
*/ | |||||
SALES_SCENES_MINI_PROGRAM, | |||||
/** | |||||
* 互联网 | |||||
*/ | |||||
SALES_SCENES_WEB, | |||||
/** | |||||
* APP | |||||
*/ | |||||
SALES_SCENES_APP, | |||||
/** | |||||
* 企业微信 | |||||
*/ | |||||
SALES_SCENES_WEWORK, | |||||
; | |||||
} |
@@ -0,0 +1,23 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment.enums; | |||||
/** | |||||
* 返回特约商户的结算账户-汇款验证结果枚举类 | |||||
* | |||||
* @author zhouyognshen | |||||
*/ | |||||
public enum SettlementVerifyResultEnum { | |||||
/** | |||||
* 系统汇款验证中,商户可发起提现尝试。 | |||||
*/ | |||||
VERIFYING, | |||||
/** | |||||
* 系统成功汇款,该账户可正常发起提现。 | |||||
*/ | |||||
VERIFY_SUCCESS, | |||||
/** | |||||
* 系统汇款失败,该账户无法发起提现,请检查修改。 | |||||
*/ | |||||
VERIFY_FAIL, | |||||
; | |||||
} |
@@ -0,0 +1,34 @@ | |||||
package com.github.binarywang.wxpay.bean.applyment.enums; | |||||
/** | |||||
* 主体类型枚举类 | |||||
* <pre> | |||||
* 商户申请接入时如何选择主体类型? https://kf.qq.com/faq/180910IBZVnQ180910naQ77b.html | |||||
* </pre> | |||||
* | |||||
* @author zhouyongshen | |||||
*/ | |||||
public enum SubjectTypeEnum { | |||||
/** | |||||
* (个体户):营业执照上的主体类型一般为个体户、个体工商户、个体经营; | |||||
*/ | |||||
SUBJECT_TYPE_INDIVIDUAL, | |||||
/** | |||||
* (企业):营业执照上的主体类型一般为有限公司、有限责任公司; | |||||
*/ | |||||
SUBJECT_TYPE_ENTERPRISE, | |||||
/** | |||||
* (党政、机关及事业单位):包括国内各级、各类政府机构、事业单位等(如:公安、党团、司法、交通、旅游、工商税务、市政、医疗、教育、学校等机构); | |||||
*/ | |||||
SUBJECT_TYPE_INSTITUTIONS, | |||||
/** | |||||
* (其他组织):不属于企业、政府/事业单位的组织机构(如社会团体、民办非企业、基金会),要求机构已办理组织机构代码证。 | |||||
*/ | |||||
SUBJECT_TYPE_OTHERS, | |||||
/** | |||||
* (小微):无营业执照、免办理工商注册登记的实体商户 | |||||
*/ | |||||
SUBJECT_TYPE_MICRO, | |||||
; | |||||
} |
@@ -0,0 +1,28 @@ | |||||
package com.github.binarywang.wxpay.bean.bank; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* 对私银行卡号开户银行信息 | |||||
* | |||||
* @author zhongjun | |||||
**/ | |||||
@Data | |||||
public class BankAccountResult implements Serializable { | |||||
private static final long serialVersionUID = -8226859146533243501L; | |||||
/** | |||||
* 根据卡号查询到的银行列表数据的总条数,未查询到对应银行列表时默认返回0,最大不超过两百条。 | |||||
*/ | |||||
@SerializedName("total_count") | |||||
private Integer totalCount; | |||||
@SerializedName("data") | |||||
private List<BankInfo> data; | |||||
} |
@@ -0,0 +1,176 @@ | |||||
package com.github.binarywang.wxpay.bean.bank; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.Getter; | |||||
import lombok.Setter; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* 支行列表 | |||||
* | |||||
* @author hupeng | |||||
**/ | |||||
@Data | |||||
public class BankBranchesResult implements Serializable { | |||||
private static final long serialVersionUID = -3500020131951579476L; | |||||
/** | |||||
* <pre> | |||||
* 字段名:查询数据总条数 | |||||
* 变量名:total_count | |||||
* 是否必填:是 | |||||
* 类型:int | |||||
* 描述: | |||||
* 经过条件筛选,查询到的支行总数 | |||||
* 示例值:10 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("total_count") | |||||
private Integer totalCount; | |||||
/** | |||||
* <pre> | |||||
* 字段名:本次查询条数 | |||||
* 变量名:count | |||||
* 是否必填:是 | |||||
* 类型:int | |||||
* 描述: | |||||
* 本次查询到的支行数据条数 | |||||
* 示例值:10 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("count") | |||||
private Integer count; | |||||
/** | |||||
* <pre> | |||||
* 字段名:支行列表 | |||||
* 变量名:data | |||||
* 是否必填:否 | |||||
* 类型:array | |||||
* 描述: | |||||
* 单次查询返回的支行列表结果数组 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("data") | |||||
private List<BankBranch> data; | |||||
/** | |||||
* <pre> | |||||
* 字段名:本次查询偏移量 | |||||
* 变量名:offset | |||||
* 是否必填:是 | |||||
* 类型:int | |||||
* 描述: | |||||
* 该次请求资源的起始位置,请求中包含偏移量时应答消息返回相同偏移量,否则返回默认值0 | |||||
* 示例值:0 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("offset") | |||||
private Integer offset; | |||||
/** | |||||
* <pre> | |||||
* 字段名:分页链接 | |||||
* 变量名:offset | |||||
* 是否必填:是 | |||||
* 类型:object | |||||
* 描述: | |||||
* 返回前后页和当前页面的访问链接 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("links") | |||||
private PageLink links; | |||||
/** | |||||
* <pre> | |||||
* 字段名:开户银行 | |||||
* 变量名:account_bank | |||||
* 是否必填:是 | |||||
* 类型:string[1, 128] | |||||
* 描述: | |||||
* 查询到的支行所属开户银行的名称,非直连银行统一为其他银行 | |||||
* 示例值:招商银行其他银行 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("account_bank") | |||||
private String accountBank; | |||||
/** | |||||
* <pre> | |||||
* 字段名:开户银行编码 | |||||
* 变量名:account_bank_code | |||||
* 是否必填:是 | |||||
* 类型:int | |||||
* 描述: | |||||
* 查询到的支行所属开户银行的开户银行编码,可用于付款到银行卡等场景中指定银行卡的开户银行 | |||||
* 示例值:1001 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("account_bank_code") | |||||
private Integer accountBankCode; | |||||
/** | |||||
* <pre> | |||||
* 字段名:银行别名 | |||||
* 变量名:bank_alias | |||||
* 是否必填:是 | |||||
* 类型:string[1, 128] | |||||
* 描述: | |||||
* 查询到的支行所属银行的银行别名 | |||||
* 示例值:工商银行深圳前海微众银行 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("bank_alias") | |||||
private String bankAlias; | |||||
/** | |||||
* <pre> | |||||
* 字段名:银行别名编码 | |||||
* 变量名:bank_alias_code | |||||
* 是否必填:是 | |||||
* 类型:string[1, 32] | |||||
* 描述: | |||||
* 查询到的支行所属银行的银行别名编码,用于校验回包 | |||||
* 示例值:1000006247 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("bank_alias_code") | |||||
private String bankAliasCode; | |||||
@Getter | |||||
@Setter | |||||
public static class BankBranch { | |||||
/** | |||||
* <pre> | |||||
* 字段名:开户银行支行名称 | |||||
* 变量名:bank_branch_name | |||||
* 是否必填:是 | |||||
* 类型:string[1, 128] | |||||
* 描述: | |||||
* 开户银行支行名称,用于开户银行为其他银行的情况下,在入驻、修改结算银行卡、企业付款等场景下填写结算银行卡信息。 | |||||
* 示例值:中国工商银行上海市周浦支行 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("bank_branch_name") | |||||
private String bankBranchName; | |||||
/** | |||||
* <pre> | |||||
* 字段名:开户银行支行联行号 | |||||
* 变量名:bank_branch_id | |||||
* 是否必填:是 | |||||
* 类型:string[1, 64] | |||||
* 描述: | |||||
* 开户银行支行的联行号,用于开户银行为其他银行的情况下,在入驻、修改结算银行卡、企业付款等场景下填写结算银行卡信息。 | |||||
* 示例值:102290072311 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("bank_branch_id") | |||||
private String bankBranchId; | |||||
} | |||||
} |
@@ -0,0 +1,39 @@ | |||||
package com.github.binarywang.wxpay.bean.bank; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
/** | |||||
* 银行信息 | |||||
* | |||||
* @author zhongjun | |||||
* @date 2022/5/12 | |||||
**/ | |||||
@Data | |||||
public class BankInfo { | |||||
/** | |||||
* 银行别名 | |||||
*/ | |||||
@SerializedName("bank_alias") | |||||
private String bankAlias; | |||||
/** | |||||
* 银行别名编码 | |||||
*/ | |||||
@SerializedName("bank_alias_code") | |||||
private String bankAliasCode; | |||||
/** | |||||
* 开户银行 | |||||
*/ | |||||
@SerializedName("account_bank") | |||||
private String accountBank; | |||||
/** | |||||
* 开户银行编码 | |||||
*/ | |||||
@SerializedName("account_bank_code") | |||||
private Integer accountBankCode; | |||||
/** | |||||
* 是否需要填写支行 | |||||
*/ | |||||
@SerializedName("need_bank_branch") | |||||
private Boolean needBankBranch; | |||||
} |
@@ -0,0 +1,64 @@ | |||||
package com.github.binarywang.wxpay.bean.bank; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.Getter; | |||||
import lombok.Setter; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* 个人业务的银行列表 | |||||
* | |||||
* @author zhongjun | |||||
**/ | |||||
@Data | |||||
public class BankingResult implements Serializable { | |||||
private static final long serialVersionUID = -8372812998971715894L; | |||||
/** | |||||
* 银行列表数据的总条数,调用方需要根据总条数分页查询 | |||||
*/ | |||||
@SerializedName("total_count") | |||||
private Integer totalCount; | |||||
/** | |||||
* 本次查询银行列表返回的数据条数 | |||||
*/ | |||||
@SerializedName("count") | |||||
private Integer count; | |||||
/** | |||||
* 该次请求资源的起始位置,请求中包含偏移量时应答消息返回相同偏移量,否则返回默认值0。 | |||||
*/ | |||||
@SerializedName("offset") | |||||
private Integer offset; | |||||
@SerializedName("data") | |||||
private List<BankInfo> data; | |||||
@SerializedName("links") | |||||
private Link links; | |||||
@Getter | |||||
@Setter | |||||
public static class Link { | |||||
/** | |||||
* 下一页链接 | |||||
*/ | |||||
@SerializedName("next") | |||||
private String next; | |||||
/** | |||||
* 上一页链接 | |||||
*/ | |||||
@SerializedName("prev") | |||||
private String prev; | |||||
/** | |||||
* 当前链接 | |||||
*/ | |||||
@SerializedName("self") | |||||
private String self; | |||||
} | |||||
} |
@@ -0,0 +1,80 @@ | |||||
package com.github.binarywang.wxpay.bean.bank; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.Getter; | |||||
import lombok.Setter; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* 城市列表 | |||||
* | |||||
* @author hupeng | |||||
**/ | |||||
@Data | |||||
public class CitiesResult implements Serializable { | |||||
private static final long serialVersionUID = -6089905695087974693L; | |||||
/** | |||||
* <pre> | |||||
* 字段名:查询数据总条数 | |||||
* 变量名:total_count | |||||
* 是否必填:是 | |||||
* 类型:int | |||||
* 描述: | |||||
* 查询到的省份数据总条数 | |||||
* 示例值:10 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("total_count") | |||||
private Integer totalCount; | |||||
/** | |||||
* <pre> | |||||
* 字段名:城市列表 | |||||
* 变量名:data | |||||
* 是否必填:否 | |||||
* 类型:array | |||||
* 描述: | |||||
* 查询返回的城市列表结果 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("data") | |||||
private List<CityInfo> data; | |||||
@Getter | |||||
@Setter | |||||
public static class CityInfo { | |||||
/** | |||||
* <pre> | |||||
* 字段名:城市名称 | |||||
* 变量名:city_name | |||||
* 是否必填:是 | |||||
* 类型:string[1, 256] | |||||
* 描述: | |||||
* 城市名称 | |||||
* 示例值:北京市 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("city_name") | |||||
private String cityName; | |||||
/** | |||||
* <pre> | |||||
* 字段名:城市编码 | |||||
* 变量名:city_code | |||||
* 是否必填:是 | |||||
* 类型:int | |||||
* 描述: | |||||
* 城市编码,唯一标识一座城市,用于结合银行别名编码查询支行列表 | |||||
* 示例值:10 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("city_code") | |||||
private Integer cityCode; | |||||
} | |||||
} |
@@ -0,0 +1,59 @@ | |||||
package com.github.binarywang.wxpay.bean.bank; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 支行列表 | |||||
* | |||||
* @author hupeng | |||||
**/ | |||||
@Data | |||||
public class PageLink implements Serializable { | |||||
private static final long serialVersionUID = -2624233403271204837L; | |||||
/** | |||||
* <pre> | |||||
* 字段名:下一页链接 | |||||
* 变量名:next | |||||
* 是否必填:否 | |||||
* 类型:string[1, 2048] | |||||
* 描述: | |||||
* 使用同样的limit进行下一页查询时的相对请求链接,使用方需要自行根据当前域名进行拼接。如果已经到最后时,为空 | |||||
* 示例值:/v3/capital/capitallhh/banks/1001/branches?offset=10&limit=5 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("next") | |||||
private String next; | |||||
/** | |||||
* <pre> | |||||
* 字段名:上一页链接 | |||||
* 变量名:prev | |||||
* 是否必填:否 | |||||
* 类型:string[1, 2048] | |||||
* 描述: | |||||
* 使用同样的limit进行上一页查询时的相对请求链接,使用方需要自行根据当前域名进行拼接。如果是第一页,为空 | |||||
* 示例值:/v3/capital/capitallhh/banks/1001/branchesoffset=0&limit=5 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("prev") | |||||
private String prev; | |||||
/** | |||||
* <pre> | |||||
* 字段名:当前链接 | |||||
* 变量名:self | |||||
* 是否必填:否 | |||||
* 类型:string[1, 2048] | |||||
* 描述: | |||||
* 当前的相对请求链接,使用方需要自行根据当前域名进行拼接 | |||||
* 示例值:/v3/capital/capitallhh/banks/1001/branches?offset=5&limit=5 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("self") | |||||
private String self; | |||||
} |
@@ -0,0 +1,81 @@ | |||||
package com.github.binarywang.wxpay.bean.bank; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.Getter; | |||||
import lombok.Setter; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* 省份列表 | |||||
* | |||||
* @author hupeng | |||||
**/ | |||||
@Data | |||||
public class ProvincesResult implements Serializable { | |||||
private static final long serialVersionUID = -4118613374545722650L; | |||||
/** | |||||
* <pre> | |||||
* 字段名:查询数据总条数 | |||||
* 变量名:total_count | |||||
* 是否必填:是 | |||||
* 类型:int | |||||
* 描述: | |||||
* 查询到的省份数据总条数 | |||||
* 示例值:10 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("total_count") | |||||
private Integer totalCount; | |||||
/** | |||||
* <pre> | |||||
* 字段名:省份列表 | |||||
* 变量名:data | |||||
* 是否必填:否 | |||||
* 类型:array | |||||
* 描述: | |||||
* 查询到的省份列表数组 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("data") | |||||
private List<ProvinceInfo> data; | |||||
@Getter | |||||
@Setter | |||||
public static class ProvinceInfo { | |||||
/** | |||||
* <pre> | |||||
* 字段名:省份名称 | |||||
* 变量名:province_name | |||||
* 是否必填:是 | |||||
* 类型:string[1, 256] | |||||
* 描述: | |||||
* 省份名称 | |||||
* 示例值:广东省 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("province_name") | |||||
private String provinceName; | |||||
/** | |||||
* <pre> | |||||
* 字段名:省份编码 | |||||
* 变量名:province_code | |||||
* 是否必填:是 | |||||
* 类型:int | |||||
* 描述: | |||||
* 省份编码,唯一标识一个省份,用于根据省份编码查询省份下的城市列表数据 | |||||
* 示例值:22 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName("province_code") | |||||
private Integer provinceCode; | |||||
} | |||||
} |
@@ -0,0 +1,93 @@ | |||||
package com.github.binarywang.wxpay.bean.businesscircle; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 智慧商圈回调通知对象 | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/businesscircle/chapter3_1.shtml | |||||
* https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/businesscircle/chapter3_3.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class BusinessCircleNotifyData implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 通知ID | |||||
*/ | |||||
@SerializedName("id") | |||||
private String id; | |||||
/** | |||||
* 通知创建时间 | |||||
*/ | |||||
@SerializedName("create_time") | |||||
private String createTime; | |||||
/** | |||||
* 通知类型 | |||||
*/ | |||||
@SerializedName("event_type") | |||||
private String eventType; | |||||
/** | |||||
* 通知数据类型 | |||||
*/ | |||||
@SerializedName("resource_type") | |||||
private String resourceType; | |||||
/** | |||||
* 回调摘要 | |||||
* summary | |||||
*/ | |||||
@SerializedName("summary") | |||||
private String summary; | |||||
/** | |||||
* 通知数据 | |||||
*/ | |||||
@SerializedName("resource") | |||||
private Resource resource; | |||||
@Data | |||||
public static class Resource implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 加密算法类型 | |||||
*/ | |||||
@SerializedName("algorithm") | |||||
private String algorithm; | |||||
/** | |||||
* 数据密文 | |||||
*/ | |||||
@SerializedName("ciphertext") | |||||
private String cipherText; | |||||
/** | |||||
* 附加数据 | |||||
*/ | |||||
@SerializedName("associated_data") | |||||
private String associatedData; | |||||
/** | |||||
* 随机串 | |||||
*/ | |||||
@SerializedName("nonce") | |||||
private String nonce; | |||||
/** | |||||
* 原始回调类型 | |||||
*/ | |||||
@SerializedName("original_type") | |||||
private String originalType; | |||||
} | |||||
} |
@@ -0,0 +1,52 @@ | |||||
package com.github.binarywang.wxpay.bean.businesscircle; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 商圈授权结果通知内容 | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_6_6.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class MemberCardAuthorizeNotifyResult implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 用户标识 | |||||
* <p> | |||||
* 顾客授权时使用的小程序上的openid | |||||
* 示例值:oUpF8uMuAJ2pxb1Q9zNjWeS6o | |||||
*/ | |||||
@SerializedName("openid") | |||||
private String openid; | |||||
/** | |||||
* 会员在card_id下的唯一标识, | |||||
*/ | |||||
@SerializedName("code") | |||||
private String code; | |||||
/** | |||||
* 用户开会员卡时的商圈商户号 | |||||
*/ | |||||
@SerializedName("mchid") | |||||
private String mchid; | |||||
/** | |||||
* 用户授权类型 | |||||
* REGISTERED_MODE :会员开卡(进卡包) + 未授权会员积分服务 | |||||
* REGISTERED_AND_AUTHORIZATION_MODE:会员开卡(进卡包)+授权会员积分服务 | |||||
*/ | |||||
@SerializedName("auth_type") | |||||
private String authType; | |||||
} |
@@ -0,0 +1,53 @@ | |||||
package com.github.binarywang.wxpay.bean.businesscircle; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 商圈授权结果查询内容 | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_6_4.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class MemberCardAuthorizeResult implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 用户标识 | |||||
* <p> | |||||
* 顾客授权时使用的小程序上的openid | |||||
* 示例值:oUpF8uMuAJ2pxb1Q9zNjWeS6o | |||||
*/ | |||||
@SerializedName("openid") | |||||
private String openid; | |||||
/** | |||||
* 顾客授权商圈积分结果 | |||||
* UNAUTHORIZED:未授权 | |||||
* AUTHORIZED:已授权 | |||||
* DEAUTHORIZED:已取消授权 | |||||
*/ | |||||
@SerializedName("authorize_state") | |||||
private String authorizeState; | |||||
/** | |||||
* 顾客成功授权商圈积分的时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE | |||||
*/ | |||||
@SerializedName("authorize_time") | |||||
private String authorizeTime; | |||||
/** | |||||
* 顾客关闭授权商圈积分的时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE | |||||
*/ | |||||
@SerializedName("deauthorize_time") | |||||
private String deauthorizeTime; | |||||
} |
@@ -0,0 +1,112 @@ | |||||
package com.github.binarywang.wxpay.bean.businesscircle; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 商圈支付结果通知内容 | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/businesscircle/chapter3_1.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class PaidResult implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 商户号 | |||||
* <p> | |||||
* 微信支付分配的商户号 | |||||
* 示例值:1230000109 | |||||
*/ | |||||
@SerializedName("mchid") | |||||
private String mchid; | |||||
/** | |||||
* 商圈商户名称 | |||||
* <p> | |||||
* 商圈商户名称 | |||||
* 示例值:微信支付 | |||||
*/ | |||||
@SerializedName("merchant_name") | |||||
private String merchantName; | |||||
/** | |||||
* 门店名称 | |||||
* <p> | |||||
* 门店名称,商圈在商圈小程序上圈店时填写的门店名称 | |||||
* 示例值:微信支付 | |||||
*/ | |||||
@SerializedName("shop_name") | |||||
private String shopName; | |||||
/** | |||||
* 门店编号 | |||||
* <p> | |||||
* 门店编号,商圈在商圈小程序上圈店时填写的门店编号,用于跟商圈自身已有的商户识别码对齐 | |||||
* 示例值:123456 | |||||
*/ | |||||
@SerializedName("shop_number") | |||||
private String shopNumber; | |||||
/** | |||||
* 小程序APPID | |||||
* <p> | |||||
* 顾客授权积分时使用的小程序的appid | |||||
* 示例值:wxd678efh567hg6787 | |||||
*/ | |||||
@SerializedName("appid") | |||||
private String appid; | |||||
/** | |||||
* 用户标识 | |||||
* <p> | |||||
* 顾客授权时使用的小程序上的openid | |||||
* 示例值:oUpF8uMuAJ2pxb1Q9zNjWeS6o | |||||
*/ | |||||
@SerializedName("openid") | |||||
private String openid; | |||||
/** | |||||
* 交易完成时间 | |||||
* <p> | |||||
* 交易完成时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒(需要增加所有跟时间有关的参数的描述) | |||||
* 示例值:2015-05-20T13:29:35+08:00 | |||||
*/ | |||||
@SerializedName("time_end") | |||||
private String timeEnd; | |||||
/** | |||||
* 金额 | |||||
* <p> | |||||
* 用户实际消费金额,单位(分) | |||||
* 示例值:200 | |||||
*/ | |||||
@SerializedName("amount") | |||||
private Integer amount; | |||||
/** | |||||
* 微信支付订单号 | |||||
* <p> | |||||
* 微信支付订单号 | |||||
* 示例值:1234567890 | |||||
*/ | |||||
@SerializedName("transaction_id") | |||||
private String transactionId; | |||||
/** | |||||
* 手动提交积分标记 | |||||
* <p> | |||||
* 手动提交积分标记,自动提交时无该字段,用于区分用户手动申请后推送的积分数据 | |||||
* 示例值:oUpF8uMuAJ2pxb1Q9zNjWUHsd | |||||
*/ | |||||
@SerializedName("commit_tag") | |||||
private String commitTag; | |||||
} |
@@ -0,0 +1,103 @@ | |||||
package com.github.binarywang.wxpay.bean.businesscircle; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 商圈停车同步 | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_6_5.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
public class ParkingNotifyRequest implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* <pre> | |||||
* 字段名:商圈商户ID | |||||
* 变量名:sub_mchid | |||||
* 是否必填:否 | |||||
* 类型:string[1,64] | |||||
* 描述: | |||||
* 当以服务商模式管理商圈积分能力时,则要带上商圈商户ID,否则留空 | |||||
* 示例值:1234567890 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "sub_mchid") | |||||
private String subMchid; | |||||
/** | |||||
* <pre> | |||||
* 调用方商户号对应的品牌brandid,调用方商户号需为此品牌brandid的品牌主商户号或品牌服务商商户号 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "brandid") | |||||
private String brandid; | |||||
/** | |||||
* <pre> | |||||
* 字段名:小程序appid | |||||
* 变量名:appid | |||||
* 是否必填:是 | |||||
* 类型:string[1,128] | |||||
* 描述: | |||||
* 顾客授权积分时使用的小程序的appid | |||||
* 示例值:wx1234567890abcdef | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "appid") | |||||
private String appid; | |||||
/** | |||||
* <pre> | |||||
* 字段名:用户标识 | |||||
* 变量名:openid | |||||
* 是否必填:是 | |||||
* 类型:string[1,64] | |||||
* 描述: | |||||
* 顾客授权时使用的小程序上的openid | |||||
* 示例值:oWmnN4xxxxxxxxxxe92NHIGf1xd8 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "openid") | |||||
private String openid; | |||||
/** | |||||
* <pre> | |||||
* 首位需为省份的中文简称,第二位起支持大写字母、数字、中文 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "plate_number") | |||||
private String plateNumber; | |||||
/** | |||||
* <pre> | |||||
* 停车状态,服务商模式下必传 | |||||
* IN:入场,用户开车进入商圈 | |||||
* OUT:离场,用户开车离开商圈 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "state") | |||||
private String state; | |||||
/** | |||||
* <pre> | |||||
* 在场状态更新时间,按照使用rfc3339所定义的格式,格式为yyyy-MM-DDThh:mm:ss+TIMEZONE | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "time") | |||||
private String time; | |||||
} |
@@ -0,0 +1,31 @@ | |||||
package com.github.binarywang.wxpay.bean.businesscircle; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 商圈积分状态查询 | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_6_7.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class PointsCommitStatusResult implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 商圈会员待积分状态 | |||||
* PENDING:有积分待提交,商圈会员有待提交的积分记录,可引导会员跳转插件提交积分申请 | |||||
* FINISHED:无积分可提交,商圈会员没有待提交的积分记录 | |||||
*/ | |||||
@SerializedName("points_commit_status") | |||||
private String pointsCommitStatus; | |||||
} |
@@ -0,0 +1,154 @@ | |||||
package com.github.binarywang.wxpay.bean.businesscircle; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 商圈积分同步 | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/businesscircle/chapter3_2.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@Data | |||||
@Builder | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
public class PointsNotifyRequest implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* <pre> | |||||
* 字段名:商圈商户ID | |||||
* 变量名:sub_mchid | |||||
* 是否必填:否 | |||||
* 类型:string[1,64] | |||||
* 描述: | |||||
* 当以服务商模式管理商圈积分能力时,则要带上商圈商户ID,否则留空 | |||||
* 示例值:1234567890 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "sub_mchid") | |||||
private String subMchid; | |||||
/** | |||||
* <pre> | |||||
* 字段名:微信订单号 | |||||
* 变量名:transaction_id | |||||
* 是否必填:是 | |||||
* 类型:string[1,64] | |||||
* 描述: | |||||
* 微信支付推送的商圈内交易通知里携带的微信订单号 | |||||
* 示例值:1217752501201407033233368018 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "transaction_id") | |||||
private String transactionId; | |||||
/** | |||||
* <pre> | |||||
* 字段名:小程序appid | |||||
* 变量名:appid | |||||
* 是否必填:是 | |||||
* 类型:string[1,128] | |||||
* 描述: | |||||
* 顾客授权积分时使用的小程序的appid | |||||
* 示例值:wx1234567890abcdef | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "appid") | |||||
private String appid; | |||||
/** | |||||
* <pre> | |||||
* 字段名:用户标识 | |||||
* 变量名:openid | |||||
* 是否必填:是 | |||||
* 类型:string[1,64] | |||||
* 描述: | |||||
* 顾客授权时使用的小程序上的openid | |||||
* 示例值:oWmnN4xxxxxxxxxxe92NHIGf1xd8 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "openid") | |||||
private String openid; | |||||
/** | |||||
* <pre> | |||||
* 字段名:是否获得积分 | |||||
* 变量名:earn_points | |||||
* 是否必填:是 | |||||
* 类型:boolean | |||||
* 描述: | |||||
* 用于标明此单是否获得积分, | |||||
* true为获得积分, | |||||
* false为未获得 | |||||
* 示例值:true | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "earn_points") | |||||
private Boolean earnPoints; | |||||
/** | |||||
* <pre> | |||||
* 字段名:订单新增积分值 | |||||
* 变量名:increased_points | |||||
* 是否必填:是 | |||||
* 类型:int | |||||
* 描述: | |||||
* 顾客此笔交易新增的积分值 | |||||
* 示例值:100 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "increased_points") | |||||
private Integer increasedPoints; | |||||
/** | |||||
* <pre> | |||||
* 字段名:积分更新时间 | |||||
* 变量名:points_update_time | |||||
* 是否必填:是 | |||||
* 类型:string[1,32] | |||||
* 描述: | |||||
* 为顾客此笔交易成功积分的时间 | |||||
* 示例值:2020-05-20T13:29:35.120+08:00 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "points_update_time") | |||||
private String pointsUpdateTime; | |||||
/** | |||||
* <pre> | |||||
* 字段名:未获得积分的备注信息 | |||||
* 变量名:no_points_remarks | |||||
* 是否必填:否 | |||||
* 类型:string[1,128] | |||||
* 描述: | |||||
* 当未获得积分时,提供未获得积分的原因等备注信息 | |||||
* 示例值:商品不参与积分活动 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "no_points_remarks") | |||||
private String noPointsRemarks; | |||||
/** | |||||
* <pre> | |||||
* 字段名:顾客积分总额 | |||||
* 变量名:total_points | |||||
* 是否必填:否 | |||||
* 类型:int | |||||
* 描述: | |||||
* 当前顾客积分总额 | |||||
* 示例值:888888 | |||||
* </pre> | |||||
*/ | |||||
@SerializedName(value = "total_points") | |||||
private Integer totalPoints; | |||||
} |
@@ -0,0 +1,121 @@ | |||||
package com.github.binarywang.wxpay.bean.businesscircle; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 商圈退款成功通知内容 | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/businesscircle/chapter3_3.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class RefundResult implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 商户号 | |||||
* <p> | |||||
* 微信支付分配的商户号 | |||||
* 示例值:1230000109 | |||||
*/ | |||||
@SerializedName("mchid") | |||||
private String mchid; | |||||
/** | |||||
* 商圈商户名称 | |||||
* <p> | |||||
* 商圈商户名称 | |||||
* 示例值:微信支付 | |||||
*/ | |||||
@SerializedName("merchant_name") | |||||
private String merchantName; | |||||
/** | |||||
* 门店名称 | |||||
* <p> | |||||
* 门店名称,商圈在商圈小程序上圈店时填写的门店名称 | |||||
* 示例值:微信支付 | |||||
*/ | |||||
@SerializedName("shop_name") | |||||
private String shopName; | |||||
/** | |||||
* 门店编号 | |||||
* <p> | |||||
* 门店编号,商圈在商圈小程序上圈店时填写的门店编号,用于跟商圈自身已有的商户识别码对齐 | |||||
* 示例值:123456 | |||||
*/ | |||||
@SerializedName("shop_number") | |||||
private String shopNumber; | |||||
/** | |||||
* 小程序APPID | |||||
* <p> | |||||
* 顾客授权积分时使用的小程序的appid | |||||
* 示例值:wxd678efh567hg6787 | |||||
*/ | |||||
@SerializedName("appid") | |||||
private String appid; | |||||
/** | |||||
* 用户标识 | |||||
* <p> | |||||
* 顾客授权时使用的小程序上的openid | |||||
* 示例值:oUpF8uMuAJ2pxb1Q9zNjWeS6o | |||||
*/ | |||||
@SerializedName("openid") | |||||
private String openid; | |||||
/** | |||||
* 退款完成时间 | |||||
* <p> | |||||
* 退款完成时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒(需要增加所有跟时间有关的参数的描述) | |||||
* 示例值:2015-05-20T13:29:35+08:00 | |||||
*/ | |||||
@SerializedName("refund_time") | |||||
private String refundTime; | |||||
/** | |||||
* 消费金额 | |||||
* <p> | |||||
* 用户实际消费金额,单位(分) | |||||
* 示例值:100 | |||||
*/ | |||||
@SerializedName("pay_amount") | |||||
private Integer payAmount; | |||||
/** | |||||
* 退款金额 | |||||
* <p> | |||||
* 用户退款金额,单位(分) | |||||
* 示例值:100 | |||||
*/ | |||||
@SerializedName("refund_amount") | |||||
private Integer refundAmount; | |||||
/** | |||||
* 微信支付订单号 | |||||
* <p> | |||||
* 微信支付订单号 | |||||
* 示例值:1234567890 | |||||
*/ | |||||
@SerializedName("transaction_id") | |||||
private String transactionId; | |||||
/** | |||||
* 微信支付退款单号 | |||||
* <p> | |||||
* 微信支付退款单号 | |||||
* 示例值:1217752501201407033233368999 | |||||
*/ | |||||
@SerializedName("refund_id") | |||||
private String refundId; | |||||
} |
@@ -0,0 +1,35 @@ | |||||
package com.github.binarywang.wxpay.bean.ecommerce; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 微信通知接口头部信息,需要做签名验证 | |||||
* 文档地址: https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/qian-ming-yan-zheng | |||||
*/ | |||||
@Data | |||||
@NoArgsConstructor | |||||
public class SignatureHeader implements Serializable { | |||||
private static final long serialVersionUID = -6958015499416059949L; | |||||
/** | |||||
* 时间戳 | |||||
*/ | |||||
private String timeStamp; | |||||
/** | |||||
* 随机串 | |||||
*/ | |||||
private String nonce; | |||||
/** | |||||
* 已签名字符串 | |||||
*/ | |||||
private String signed; | |||||
/** | |||||
* 证书序列号 | |||||
*/ | |||||
private String serialNo; | |||||
} |
@@ -0,0 +1,28 @@ | |||||
package com.github.binarywang.wxpay.bean.media; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
/** | |||||
* 媒体文件上传返回结果对象 | |||||
* @author zhouyongshen | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class ImageUploadResult { | |||||
public static ImageUploadResult fromJson(String json) { | |||||
return WxGsonBuilder.create().fromJson(json, ImageUploadResult.class); | |||||
} | |||||
/** | |||||
* 媒体文件标识 Id | |||||
* | |||||
* 微信返回的媒体文件标识Id。 | |||||
* 示例值:6uqyGjGrCf2GtyXP8bxrbuH9-aAoTjH-rKeSl3Lf4_So6kdkQu4w8BYVP3bzLtvR38lxt4PjtCDXsQpzqge_hQEovHzOhsLleGFQVRF-U_0 | |||||
* | |||||
*/ | |||||
@SerializedName("media_id") | |||||
private String mediaId; | |||||
} |
@@ -0,0 +1,29 @@ | |||||
package com.github.binarywang.wxpay.bean.media; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
/** | |||||
* 媒体文件上传返回结果对象 | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class MarketingImageUploadResult { | |||||
public static MarketingImageUploadResult fromJson(String json) { | |||||
return WxGsonBuilder.create().fromJson(json, MarketingImageUploadResult.class); | |||||
} | |||||
/** | |||||
* 媒体文件URL地址 | |||||
* <p> | |||||
* 微信返回的媒体文件标识url。有效期为永久 | |||||
* 示例值:https://qpic.cn/xxx | |||||
*/ | |||||
@SerializedName("media_url") | |||||
private String mediaUrl; | |||||
} |
@@ -0,0 +1,82 @@ | |||||
package com.github.binarywang.wxpay.bean.membercard; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 商圈支付结果通知内容 | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter5_9_32.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class MemberCardActivateResult implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 业务细分事件类型,枚举值: | |||||
* MEMBER_CARD_ACTIVATE:激活会员卡 | |||||
* | |||||
* USER_VIEW_MEMBERCARD:用户查看会员卡详情 | |||||
* USER_DELETE_MEMBERCARD:用户删除会员卡 | |||||
* USER_MODIFY_INFORMATION:用户修改个人信息 | |||||
*/ | |||||
@SerializedName("event_type") | |||||
private String eventType; | |||||
/** | |||||
* 商户创建微信会员卡模板成功后系统返回的会员卡模板id | |||||
*/ | |||||
@SerializedName("card_id") | |||||
private String cardId; | |||||
/** | |||||
* 会员在card_id下的唯一标识, | |||||
*/ | |||||
@SerializedName("code") | |||||
private String code; | |||||
/** | |||||
* 事件发生时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss.sss+TIMEZONE | |||||
*/ | |||||
@SerializedName("event_time") | |||||
private String eventTime; | |||||
/** | |||||
* 激活场景,用于区分用户新开卡激活或删卡后重新领取激活。枚举值: | |||||
* NEW_ACTIVATE 新开卡激活 | |||||
* RECOVER 删卡后重新领取激活 | |||||
*/ | |||||
@SerializedName("activate_scene") | |||||
private String activateScene; | |||||
/** | |||||
* 用户标识 | |||||
* <p> | |||||
* 顾客授权时使用的小程序上的openid | |||||
* 示例值:oUpF8uMuAJ2pxb1Q9zNjWeS6o | |||||
*/ | |||||
@SerializedName("openid") | |||||
private String openid; | |||||
/** | |||||
* 微信用户在同一个微信开放平台账号下的唯一用户标识,unionid获取方式请参见《UnionID机制说明》文档。 | |||||
*/ | |||||
@SerializedName("unionid") | |||||
private String unionid; | |||||
/** | |||||
* 自定义场景值,商户可以用于标记投放场景,如门店/来源等。只能录入数字及中英文/半角标点 | |||||
* 匹配正则表达式: ^[0-9a-zA-Z\u0000-\u00FF\u4e00-\u9fa5]+$ | |||||
*/ | |||||
@SerializedName("outer_str") | |||||
private String outerStr; | |||||
} |
@@ -0,0 +1,93 @@ | |||||
package com.github.binarywang.wxpay.bean.membercard; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 会员卡回调通知对象 | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter5_9_32.shtml | |||||
* https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter5_9_33.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class MemberCardNotifyData implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 通知ID | |||||
*/ | |||||
@SerializedName("id") | |||||
private String id; | |||||
/** | |||||
* 通知创建时间 | |||||
*/ | |||||
@SerializedName("create_time") | |||||
private String createTime; | |||||
/** | |||||
* 通知类型 | |||||
*/ | |||||
@SerializedName("event_type") | |||||
private String eventType; | |||||
/** | |||||
* 通知数据类型 | |||||
*/ | |||||
@SerializedName("resource_type") | |||||
private String resourceType; | |||||
/** | |||||
* 回调摘要 | |||||
* summary | |||||
*/ | |||||
@SerializedName("summary") | |||||
private String summary; | |||||
/** | |||||
* 通知数据 | |||||
*/ | |||||
@SerializedName("resource") | |||||
private Resource resource; | |||||
@Data | |||||
public static class Resource implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 加密算法类型 | |||||
*/ | |||||
@SerializedName("algorithm") | |||||
private String algorithm; | |||||
/** | |||||
* 数据密文 | |||||
*/ | |||||
@SerializedName("ciphertext") | |||||
private String cipherText; | |||||
/** | |||||
* 附加数据 | |||||
*/ | |||||
@SerializedName("associated_data") | |||||
private String associatedData; | |||||
/** | |||||
* 随机串 | |||||
*/ | |||||
@SerializedName("nonce") | |||||
private String nonce; | |||||
/** | |||||
* 原始回调类型 | |||||
*/ | |||||
@SerializedName("original_type") | |||||
private String originalType; | |||||
} | |||||
} |
@@ -0,0 +1,360 @@ | |||||
package com.github.binarywang.wxpay.bean.membercard; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* 查询用户会员卡信息API | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter5_9_6.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class MemberCardResult implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 商户创建微信会员卡模板成功后系统返回的会员卡模板id | |||||
*/ | |||||
@SerializedName("card_id") | |||||
private String cardId; | |||||
/** | |||||
* 会员在card_id下的唯一标识,用户领取会员卡后获得的code | |||||
*/ | |||||
@SerializedName("code") | |||||
private String code; | |||||
/** | |||||
* 用户在会员卡绑定品牌appid下的唯一标识,如通过手机号同步会员身份且用户未领取到卡包,无法查询该字段 | |||||
*/ | |||||
@SerializedName("openid") | |||||
private String openid; | |||||
/** | |||||
* 在用户会员卡上展示的会员卡编号,默认使用会员卡code作为membership_number。只能录入数字/英文/半角标点。商家可通过修改用户单张会员卡信息更新 | |||||
*/ | |||||
@SerializedName("membership_number") | |||||
private String membershipNumber; | |||||
/** | |||||
* 用户会员等级 | |||||
*/ | |||||
@SerializedName("level") | |||||
private String level; | |||||
/** | |||||
* 用户的微信昵称,如通过手机号同步会员身份且用户未领取到卡包,无法查询该字段 | |||||
*/ | |||||
@SerializedName("nickname") | |||||
private String nickname; | |||||
/** | |||||
* 用户的微信头像url,如通过手机号同步会员身份且用户未领取到卡包,无法查询该字段 | |||||
*/ | |||||
@SerializedName("head_image_url") | |||||
private String headImageUrl; | |||||
/** | |||||
* 商家给当前用户设置的会员卡背景图。仅支持通过《图片上传API》接口获取的图片URL地址。支持JPG/JPEG/PNG格式,且图片小于1M。 | |||||
*/ | |||||
@SerializedName("background_picture_url") | |||||
private String backgroundPictureUrl; | |||||
/** | |||||
* 用户储值的最新余额,单位分 | |||||
*/ | |||||
@SerializedName("balance") | |||||
private Integer balance; | |||||
/** | |||||
* 用户当前的卡状态: | |||||
* NOT_ACTIVATE:未激活 | |||||
* EFFECTIVE:生效中 | |||||
* EXPIRE:已过期 | |||||
* UNAVAILABLE:已失效 | |||||
* DELETE:已删除 | |||||
* IMPORTED:已导入 | |||||
*/ | |||||
@SerializedName("user_card_status") | |||||
private String userCardStatus; | |||||
/** | |||||
* 用户开卡时填写的个人信息 | |||||
*/ | |||||
@SerializedName("user_information") | |||||
private UserInformation userInformation; | |||||
/** | |||||
* 用户当前的积分值 | |||||
*/ | |||||
@SerializedName("bonus_value") | |||||
private Integer bonusValue; | |||||
/** | |||||
* 用户当前的积分值 | |||||
*/ | |||||
@SerializedName("service_modules") | |||||
private List<ServiceModule> serviceModules; | |||||
/** | |||||
* 用户会员卡详情页会员优惠栏目中的会员专享价文案 | |||||
*/ | |||||
@SerializedName("member_price_word") | |||||
private String memberPriceWord; | |||||
/** | |||||
*发票栏跳转小程序的引导文案 | |||||
*/ | |||||
@SerializedName("fapiao_jump_word") | |||||
private String fapiaoJumpWord; | |||||
/** | |||||
*设置商家联系人员的名字、头像和联系方式 | |||||
*/ | |||||
@SerializedName("guide") | |||||
private List<Guide> guide; | |||||
@Data | |||||
public static class UserInformation implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 平台提供的通用开卡信息字段 | |||||
* 包含性别、手机、头像、昵称、姓名等基本信息字段 | |||||
*/ | |||||
@SerializedName("common_field_list") | |||||
private List<CommonField> commonFieldList; | |||||
/** | |||||
* 商户自定义的开卡信息字段 | |||||
*/ | |||||
@SerializedName("custom_field_list") | |||||
private List<CustomField> customFieldList; | |||||
} | |||||
@Data | |||||
public static class CommonField implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 平台提供了一些通用的开卡字段供开发者选用 | |||||
* USER_FORM_FLAG_MOBILE:手机号 | |||||
* USER_FORM_FLAG_SEX:性别 | |||||
* USER_FORM_FLAG_NAME:姓名 | |||||
* USER_FORM_FLAG_BIRTHDAY:生日 | |||||
* USER_FORM_FLAG_ADDRESS:地址 | |||||
* USER_FORM_FLAG_EMAIL:邮箱 | |||||
* USER_FORM_FLAG_CITY:城市 | |||||
*/ | |||||
@SerializedName("name") | |||||
private String name; | |||||
/** | |||||
* 平台提供的通用开卡信息字段,用户在开卡时填写的信息 | |||||
*/ | |||||
@SerializedName("value") | |||||
private String value; | |||||
} | |||||
@Data | |||||
public static class CustomField implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 商户自定义的开卡信息字段名称 | |||||
*/ | |||||
@SerializedName("name") | |||||
private String name; | |||||
/** | |||||
* 商户自定义的开卡信息字段值,用户在开卡时需填写。填写项目为单选时的返回 | |||||
*/ | |||||
@SerializedName("value") | |||||
private String value; | |||||
/** | |||||
* 商户自定义的开卡信息字段值,用户在开卡时需填写。填写项目为多选时的返回 | |||||
* 特殊规则:列表最多支持10个,单个列表限制8个字符 | |||||
*/ | |||||
@SerializedName("value_list") | |||||
private List<String> valueList; | |||||
} | |||||
@Data | |||||
public static class ServiceModule implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 会员服务项的唯一识别ID,创建服务项后由微信支付生成的服务项ID。商户可通过服务项id查询服务项的配置信息及用途。 | |||||
*/ | |||||
@SerializedName("service_module_id") | |||||
private String serviceModuleId; | |||||
/** | |||||
* 用户的服务状态设置,这些设置会展示在用户的会员卡详情页。可设置状态的内容字段、按钮、消息内容等 | |||||
*/ | |||||
@SerializedName("state_setting") | |||||
private StateSetting stateSetting; | |||||
} | |||||
@Data | |||||
public static class StateSetting implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 状态的id。一个服务项通常包含多个状态,商户可根据服务流程选择其中的状态进行设置,模板内容展示在用户的会员卡详情页,并支持通过公众号给用户发送触达消息 | |||||
*/ | |||||
@SerializedName("state_id") | |||||
private String stateId; | |||||
/** | |||||
* 用户的服务内容模板设置,这些设置会展示在用户的会员卡详情页。可设置状态的内容字段、按钮等 | |||||
*/ | |||||
@SerializedName("content_template_data") | |||||
private ContentTemplateData contentTemplateData; | |||||
/** | |||||
* 公众号模板消息设置。部分服务项支持给用户发送触达消息,商户可通过模板id选择模板消息样式,并设置字段值。API调用成功后会通过微信公众号自动给用户发送此模板消息。不填则默认不发消息 | |||||
*/ | |||||
@SerializedName("message_template_setting") | |||||
private MessageTemplateSetting messageTemplateSetting; | |||||
} | |||||
@Data | |||||
public static class ContentTemplateData implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 当前服务状态下,可以设置的内容字段列表 | |||||
*/ | |||||
@SerializedName("field_list") | |||||
private List<Field> fieldList; | |||||
/** | |||||
* 服务状态对应的操作设置,可配置跳转文案和跳转小程序路径 | |||||
* 需配置跳转文案及跳转小程序路径时必填 | |||||
*/ | |||||
@SerializedName("action_setting") | |||||
private ActionSetting actionSetting; | |||||
} | |||||
@Data | |||||
public static class Field implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 服务内容列表,最多包含5条内容 | |||||
*/ | |||||
@SerializedName("field_id") | |||||
private String fieldId; | |||||
/** | |||||
* 服务状态字段的值 | |||||
*/ | |||||
@SerializedName("field_value") | |||||
private String fieldValue; | |||||
} | |||||
@Data | |||||
public static class ActionSetting implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 操作名称 | |||||
*/ | |||||
@SerializedName("action_name") | |||||
private String actionName; | |||||
/** | |||||
* 服务状态指定跳转小程序 | |||||
*/ | |||||
@SerializedName("jump_miniprogram") | |||||
private JumpMiniprogram jumpMiniprogram; | |||||
} | |||||
@Data | |||||
public static class JumpMiniprogram implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 小程序的appid | |||||
*/ | |||||
@SerializedName("appid") | |||||
private String appid; | |||||
/** | |||||
* 小程序的页面path | |||||
* 示例值:pages/index/index | |||||
*/ | |||||
@SerializedName("path") | |||||
private String path; | |||||
} | |||||
@Data | |||||
public static class MessageTemplateSetting implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 公众号模板消息的id | |||||
*/ | |||||
@SerializedName("message_template_id") | |||||
private String messageTemplateId; | |||||
/** | |||||
* 模板消息字段列表。商户在此设置模板消息每个字段需展示的内容 | |||||
* 特殊规则:限制最多可提交9条 | |||||
*/ | |||||
@SerializedName("field_list") | |||||
private List<Field> fieldList; | |||||
} | |||||
@Data | |||||
public static class Guide implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 设置商家咨询联系人的名称 | |||||
*/ | |||||
@SerializedName("staff_name") | |||||
private String staffName; | |||||
/** | |||||
* 设置商家咨询联系人的头像。仅支持通过《图片上传API》接口获取的图片URL地址。 | |||||
*/ | |||||
@SerializedName("head_image_url") | |||||
private String headImageUrl; | |||||
/** | |||||
* 展示说明商家咨询联系人的联系方式,例如“微信号”“企业微信号” | |||||
*/ | |||||
@SerializedName("contact_information_name") | |||||
private String contactInformationName; | |||||
/** | |||||
* 展示说明商家咨询联系人的联系方式信息,例如“weixin123”“135266664” | |||||
*/ | |||||
@SerializedName("contact_information_value") | |||||
private String contactInformationValue; | |||||
/** | |||||
* 商家咨询联系人的联系电话 | |||||
*/ | |||||
@SerializedName("phone_number") | |||||
private String phoneNumber; | |||||
} | |||||
} |
@@ -0,0 +1,104 @@ | |||||
package com.github.binarywang.wxpay.bean.membercard; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
/** | |||||
* 设置用户会员权益信息api | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter5_9_23.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class MemberCardRightsRequest implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 变更前的用户的积分值 | |||||
*/ | |||||
@SerializedName("before_bonus_value") | |||||
private Integer beforeBonusValue; | |||||
/** | |||||
* 变更后的用户最新积分值,该值会展示在会员卡详页上 | |||||
*/ | |||||
@SerializedName("bonus_value") | |||||
private Integer bonusValue; | |||||
/** | |||||
* 本次变更的积分值 | |||||
*/ | |||||
@SerializedName("add_bonus_value") | |||||
private Integer addBonusValue; | |||||
/** | |||||
* 商户凭据号。商户自定义,注意保持唯一性,仅供参考的格式:商户id+日期+流水号。可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号。 | |||||
*/ | |||||
@SerializedName("out_request_no") | |||||
private String outRequestNo; | |||||
/** | |||||
* 积分变更时是否触发系统模板消息,默认为true | |||||
*/ | |||||
@SerializedName("need_inform_bonus") | |||||
private Boolean needInformBonus; | |||||
/** | |||||
* 用户会员卡详情页会员优惠栏目中的会员专享价文案 | |||||
*/ | |||||
@SerializedName("member_price_word") | |||||
private String memberPriceWord; | |||||
/** | |||||
*发票栏跳转小程序的引导文案 | |||||
*/ | |||||
@SerializedName("fapiao_jump_word") | |||||
private String fapiaoJumpWord; | |||||
/** | |||||
*设置商家联系人员的名字、头像和联系方式 | |||||
*/ | |||||
@SerializedName("guide") | |||||
private Guide guide; | |||||
@Data | |||||
public static class Guide implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 设置商家咨询联系人的名称 | |||||
*/ | |||||
@SerializedName("staff_name") | |||||
private String staffName; | |||||
/** | |||||
* 设置商家咨询联系人的头像。仅支持通过《图片上传API》接口获取的图片URL地址。 | |||||
*/ | |||||
@SerializedName("head_image_url") | |||||
private String headImageUrl; | |||||
/** | |||||
* 展示说明商家咨询联系人的联系方式,例如“微信号”“企业微信号” | |||||
*/ | |||||
@SerializedName("contact_information_name") | |||||
private String contactInformationName; | |||||
/** | |||||
* 展示说明商家咨询联系人的联系方式信息,例如“weixin123”“135266664” | |||||
*/ | |||||
@SerializedName("contact_information_value") | |||||
private String contactInformationValue; | |||||
/** | |||||
* 商家咨询联系人的联系电话 | |||||
*/ | |||||
@SerializedName("phone_number") | |||||
private String phoneNumber; | |||||
} | |||||
} |
@@ -0,0 +1,95 @@ | |||||
package com.github.binarywang.wxpay.bean.membercard; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* 修改用户会员卡信息API | |||||
* <pre> | |||||
* 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter5_9_8.shtml | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@NoArgsConstructor | |||||
@Data | |||||
public class MemberCardUpdRequest implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 在用户会员卡上展示的会员卡编号,默认使用会员卡code作为membership_number。只能录入数字/英文/半角标点。商家可通过修改用户单张会员卡信息更新 | |||||
*/ | |||||
@SerializedName("membership_number") | |||||
private String membershipNumber; | |||||
/** | |||||
* 商家给当前用户设置的会员卡背景图。仅支持通过《图片上传API》接口获取的图片URL地址。支持JPG/JPEG/PNG格式,且图片小于1M。 | |||||
*/ | |||||
@SerializedName("background_picture_url") | |||||
private String backgroundPictureUrl; | |||||
/** | |||||
* 用户会员等级 | |||||
*/ | |||||
@SerializedName("level") | |||||
private String level; | |||||
/** | |||||
* 商户据号。商户自定义,注意保持唯一性,仅供参考的格式:商户id+日期+流水号。可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号。 | |||||
*/ | |||||
@SerializedName("out_request_no") | |||||
private String outRequestNo; | |||||
/** | |||||
* 用户储值变更信息 | |||||
*/ | |||||
@SerializedName("balance_information") | |||||
private BalanceInformation balanceInformation; | |||||
/** | |||||
* 用户储值变更信息 | |||||
*/ | |||||
@SerializedName("need_inform_balance") | |||||
private Boolean needInformBalance; | |||||
/** | |||||
* 用户储值变更信息 | |||||
*/ | |||||
@SerializedName("need_inform_level") | |||||
private Boolean needInformLevel; | |||||
@Data | |||||
public static class BalanceInformation implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* 用户储值的更新前余额,单位分 | |||||
*/ | |||||
@SerializedName("before_balance") | |||||
private Integer beforeBalance; | |||||
/** | |||||
* 用户储值的更新后余额,单位分 | |||||
*/ | |||||
@SerializedName("balance") | |||||
private Integer balance; | |||||
/** | |||||
* 用户储值余额本次的变动值,单位分,等于balance减去before_balance,传入正数表示余额增加,传入负数表示余额减少 | |||||
*/ | |||||
@SerializedName("add_balance") | |||||
private Integer addBalance; | |||||
/** | |||||
* 商家自定义储值金额消耗记录,不超过30个字 | |||||
*/ | |||||
@SerializedName("balance_remark") | |||||
private String balanceRemark; | |||||
} | |||||
} |
@@ -1,15 +1,27 @@ | |||||
package com.github.binarywang.wxpay.config; | package com.github.binarywang.wxpay.config; | ||||
import com.github.binarywang.wxpay.exception.WxPayException; | import com.github.binarywang.wxpay.exception.WxPayException; | ||||
import com.github.binarywang.wxpay.v3.WxPayV3HttpClientBuilder; | |||||
import com.github.binarywang.wxpay.v3.auth.*; | |||||
import com.github.binarywang.wxpay.v3.util.PemUtils; | |||||
import jodd.util.ResourcesUtil; | |||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.EqualsAndHashCode; | |||||
import lombok.SneakyThrows; | |||||
import org.apache.commons.io.IOUtils; | import org.apache.commons.io.IOUtils; | ||||
import org.apache.commons.lang3.RegExUtils; | |||||
import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
import org.apache.http.impl.client.CloseableHttpClient; | |||||
import org.apache.http.ssl.SSLContexts; | import org.apache.http.ssl.SSLContexts; | ||||
import javax.net.ssl.SSLContext; | import javax.net.ssl.SSLContext; | ||||
import java.io.*; | import java.io.*; | ||||
import java.net.URL; | import java.net.URL; | ||||
import java.nio.charset.StandardCharsets; | |||||
import java.security.KeyStore; | import java.security.KeyStore; | ||||
import java.security.PrivateKey; | |||||
import java.security.cert.X509Certificate; | |||||
import java.util.Collections; | |||||
/** | /** | ||||
* 微信支付配置 | * 微信支付配置 | ||||
@@ -17,8 +29,11 @@ import java.security.KeyStore; | |||||
* @author Binary Wang (https://github.com/binarywang) | * @author Binary Wang (https://github.com/binarywang) | ||||
*/ | */ | ||||
@Data | @Data | ||||
@EqualsAndHashCode(exclude = "verifier") | |||||
public class WxPayConfig { | public class WxPayConfig { | ||||
private static final String DEFAULT_PAY_BASE_URL = "https://api.mch.weixin.qq.com"; | private static final String DEFAULT_PAY_BASE_URL = "https://api.mch.weixin.qq.com"; | ||||
private static final String PROBLEM_MSG = "证书文件【%s】有问题,请核实!"; | |||||
private static final String NOT_FOUND_MSG = "证书文件【%s】不存在,请核实!"; | |||||
/** | /** | ||||
* 微信支付接口请求地址域名部分. | * 微信支付接口请求地址域名部分. | ||||
@@ -85,6 +100,52 @@ public class WxPayConfig { | |||||
*/ | */ | ||||
private String keyPath; | private String keyPath; | ||||
/** | |||||
* apiclient_key.pem证书文件的绝对路径或者以classpath:开头的类路径. | |||||
*/ | |||||
private String privateKeyPath; | |||||
/** | |||||
* apiclient_cert.pem证书文件的绝对路径或者以classpath:开头的类路径. | |||||
*/ | |||||
private String privateCertPath; | |||||
/** | |||||
* apiV3 秘钥值. | |||||
*/ | |||||
private String apiV3Key; | |||||
/** | |||||
* apiV3 证书序列号值 | |||||
*/ | |||||
private String certSerialNo; | |||||
/** | |||||
* 微信支付分serviceId | |||||
*/ | |||||
private String serviceId; | |||||
/** | |||||
* 微信支付分回调地址 | |||||
*/ | |||||
private String payScoreNotifyUrl; | |||||
/** | |||||
* 微信支付分授权回调地址 | |||||
*/ | |||||
private String payScorePermissionNotifyUrl; | |||||
private CloseableHttpClient apiV3HttpClient; | |||||
/** | |||||
* 私钥信息 | |||||
*/ | |||||
private PrivateKey privateKey; | |||||
/** | |||||
* 证书自动更新时间差(分钟),默认一分钟 | |||||
*/ | |||||
private int certAutoUpdateTime = 60; | |||||
/** | /** | ||||
* p12证书文件内容的字节数组. | * p12证书文件内容的字节数组. | ||||
*/ | */ | ||||
@@ -106,8 +167,15 @@ public class WxPayConfig { | |||||
private String httpProxyUsername; | private String httpProxyUsername; | ||||
private String httpProxyPassword; | private String httpProxyPassword; | ||||
/** | |||||
* v3接口下证书检验对象,通过改对象可以获取到X509Certificate,进一步对敏感信息加密 | |||||
* 文档见 https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/min-gan-xin-xi-jia-mi | |||||
*/ | |||||
private Verifier verifier; | |||||
/** | /** | ||||
* 返回所设置的微信支付接口请求地址域名. | * 返回所设置的微信支付接口请求地址域名. | ||||
* | |||||
* @return 微信支付接口请求地址域名 | * @return 微信支付接口请求地址域名 | ||||
*/ | */ | ||||
public String getPayBaseUrl() { | public String getPayBaseUrl() { | ||||
@@ -118,6 +186,15 @@ public class WxPayConfig { | |||||
return this.payBaseUrl; | return this.payBaseUrl; | ||||
} | } | ||||
@SneakyThrows | |||||
public Verifier getVerifier() { | |||||
if (verifier == null) { | |||||
//当改对象为null时,初始化api v3的请求头 | |||||
initApiV3HttpClient(); | |||||
} | |||||
return verifier; | |||||
} | |||||
/** | /** | ||||
* 初始化ssl. | * 初始化ssl. | ||||
* | * | ||||
@@ -136,40 +213,7 @@ public class WxPayConfig { | |||||
if (StringUtils.isBlank(this.getKeyPath())) { | if (StringUtils.isBlank(this.getKeyPath())) { | ||||
throw new WxPayException("请确保证书文件地址keyPath已配置"); | throw new WxPayException("请确保证书文件地址keyPath已配置"); | ||||
} | } | ||||
final String prefix = "classpath:"; | |||||
String fileHasProblemMsg = "证书文件【" + this.getKeyPath() + "】有问题,请核实!"; | |||||
String fileNotFoundMsg = "证书文件【" + this.getKeyPath() + "】不存在,请核实!"; | |||||
if (this.getKeyPath().startsWith(prefix)) { | |||||
String path = StringUtils.removeFirst(this.getKeyPath(), prefix); | |||||
if (!path.startsWith("/")) { | |||||
path = "/" + path; | |||||
} | |||||
inputStream = WxPayConfig.class.getResourceAsStream(path); | |||||
if (inputStream == null) { | |||||
throw new WxPayException(fileNotFoundMsg); | |||||
} | |||||
} else if (this.getKeyPath().startsWith("http://") || this.getKeyPath().startsWith("https://")) { | |||||
try { | |||||
inputStream = new URL(this.keyPath).openStream(); | |||||
if (inputStream == null) { | |||||
throw new WxPayException(fileNotFoundMsg); | |||||
} | |||||
} catch (IOException e) { | |||||
throw new WxPayException(fileNotFoundMsg, e); | |||||
} | |||||
} else { | |||||
try { | |||||
File file = new File(this.getKeyPath()); | |||||
if (!file.exists()) { | |||||
throw new WxPayException(fileNotFoundMsg); | |||||
} | |||||
inputStream = new FileInputStream(file); | |||||
} catch (IOException e) { | |||||
throw new WxPayException(fileHasProblemMsg, e); | |||||
} | |||||
} | |||||
inputStream = this.loadConfigInputStream(this.getKeyPath()); | |||||
} | } | ||||
try { | try { | ||||
@@ -185,4 +229,104 @@ public class WxPayConfig { | |||||
} | } | ||||
} | } | ||||
/** | |||||
* 初始化api v3请求头 自动签名验签 | |||||
* 方法参照微信官方https://github.com/wechatpay-apiv3/wechatpay-apache-httpclient | |||||
* | |||||
* @return org.apache.http.impl.client.CloseableHttpClient | |||||
* @author doger.wang | |||||
**/ | |||||
public CloseableHttpClient initApiV3HttpClient() throws WxPayException { | |||||
String privateKeyPath = this.getPrivateKeyPath(); | |||||
String privateCertPath = this.getPrivateCertPath(); | |||||
String serialNo = this.getCertSerialNo(); | |||||
String apiV3Key = this.getApiV3Key(); | |||||
if (StringUtils.isBlank(privateKeyPath)) { | |||||
throw new WxPayException("请确保privateKeyPath已设置"); | |||||
} | |||||
if (StringUtils.isBlank(privateCertPath)) { | |||||
throw new WxPayException("请确保privateCertPath已设置"); | |||||
} | |||||
// if (StringUtils.isBlank(certSerialNo)) { | |||||
// throw new WxPayException("请确保certSerialNo证书序列号已设置"); | |||||
// } | |||||
if (StringUtils.isBlank(apiV3Key)) { | |||||
throw new WxPayException("请确保apiV3Key值已设置"); | |||||
} | |||||
InputStream keyInputStream = this.loadConfigInputStream(privateKeyPath); | |||||
InputStream certInputStream = this.loadConfigInputStream(privateCertPath); | |||||
try { | |||||
PrivateKey merchantPrivateKey = PemUtils.loadPrivateKey(keyInputStream); | |||||
X509Certificate certificate = PemUtils.loadCertificate(certInputStream); | |||||
if(StringUtils.isBlank(serialNo)){ | |||||
this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase(); | |||||
} | |||||
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier( | |||||
new WxPayCredentials(mchId, new PrivateKeySigner(certSerialNo, merchantPrivateKey)), | |||||
apiV3Key.getBytes(StandardCharsets.UTF_8), this.getCertAutoUpdateTime()); | |||||
CloseableHttpClient httpClient = WxPayV3HttpClientBuilder.create() | |||||
.withMerchant(mchId, certSerialNo, merchantPrivateKey) | |||||
.withWechatpay(Collections.singletonList(certificate)) | |||||
.withValidator(new WxPayValidator(verifier)) | |||||
.build(); | |||||
this.apiV3HttpClient = httpClient; | |||||
this.verifier=verifier; | |||||
this.privateKey = merchantPrivateKey; | |||||
return httpClient; | |||||
} catch (Exception e) { | |||||
throw new WxPayException("v3请求构造异常!", e); | |||||
} | |||||
} | |||||
/** | |||||
* 从配置路径 加载配置 信息(支持 classpath、本地路径、网络url) | |||||
* @param configPath 配置路径 | |||||
* @return | |||||
* @throws WxPayException | |||||
*/ | |||||
private InputStream loadConfigInputStream(String configPath) throws WxPayException { | |||||
InputStream inputStream; | |||||
final String prefix = "classpath:"; | |||||
String fileHasProblemMsg = String.format(PROBLEM_MSG, configPath); | |||||
String fileNotFoundMsg = String.format(NOT_FOUND_MSG, configPath); | |||||
if (configPath.startsWith(prefix)) { | |||||
String path = RegExUtils.removeFirst(configPath, prefix); | |||||
if (!path.startsWith("/")) { | |||||
path = "/" + path; | |||||
} | |||||
try { | |||||
inputStream = ResourcesUtil.getResourceAsStream(path); | |||||
if (inputStream == null) { | |||||
throw new WxPayException(fileNotFoundMsg); | |||||
} | |||||
} catch (Exception e) { | |||||
throw new WxPayException(fileNotFoundMsg, e); | |||||
} | |||||
} else if (configPath.startsWith("http://") || configPath.startsWith("https://")) { | |||||
try { | |||||
inputStream = new URL(configPath).openStream(); | |||||
if (inputStream == null) { | |||||
throw new WxPayException(fileNotFoundMsg); | |||||
} | |||||
} catch (IOException e) { | |||||
throw new WxPayException(fileNotFoundMsg, e); | |||||
} | |||||
} else { | |||||
try { | |||||
File file = new File(configPath); | |||||
if (!file.exists()) { | |||||
throw new WxPayException(fileNotFoundMsg); | |||||
} | |||||
inputStream = new FileInputStream(file); | |||||
} catch (IOException e) { | |||||
throw new WxPayException(fileHasProblemMsg, e); | |||||
} | |||||
} | |||||
return inputStream; | |||||
} | |||||
} | } |
@@ -0,0 +1,74 @@ | |||||
package com.github.binarywang.wxpay.service; | |||||
import com.github.binarywang.wxpay.bean.applyment.*; | |||||
import com.github.binarywang.wxpay.exception.WxPayException; | |||||
/** | |||||
* 特约商户进件 | |||||
* 产品介绍:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/applyment4sub/chapter1_1.shtml | |||||
* | |||||
* @author zhouyongshen | |||||
*/ | |||||
public interface Applyment4SubService { | |||||
/** | |||||
* 提交申请单API | |||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/applyment4sub/chapter3_1.shtml | |||||
* 接口链接:https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/ | |||||
* | |||||
* @param request 请求对象 | |||||
* @return WxPayApplymentCreateResult 响应结果 | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
WxPayApplymentCreateResult createApply(WxPayApplyment4SubCreateRequest request) throws WxPayException; | |||||
/** | |||||
* 通过业务申请编号查询申请状态 | |||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/applyment4sub/chapter3_2.shtml | |||||
* 接口链接:https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/business_code/{business_code} | |||||
* | |||||
* @param businessCode 业务申请编号 | |||||
* 1、只能由数字、字母或下划线组成,建议前缀为服务商商户号。 | |||||
* 2、服务商自定义的唯一编号。 | |||||
* 3、每个编号对应一个申请单,每个申请单审核通过后生成一个微信支付商户号。 | |||||
* 4、若申请单被驳回,可填写相同的“业务申请编号”,即可覆盖修改原申请单信息。 | |||||
* 示例值:1900013511_10000 | |||||
* @return the applyment state query result | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
ApplymentStateQueryResult queryApplyStatusByBusinessCode(String businessCode) throws WxPayException; | |||||
/** | |||||
* 通过申请单号查询申请状态 | |||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/applyment4sub/chapter3_2.shtml | |||||
* 接口链接:https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/applyment_id/{applyment_id} | |||||
* | |||||
* @param applymentId 微信支付分的申请单号。示例值:2000001234567890 | |||||
* @return the applyment state query result | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
ApplymentStateQueryResult queryApplyStatusByApplymentId(String applymentId) throws WxPayException; | |||||
/** | |||||
* 通过商户号查询结算帐号状态 | |||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/applyment4sub/chapter3_4.shtml | |||||
* 接口链接:https://api.mch.weixin.qq.com/v3/apply4sub/sub_merchants/{sub_mchid}/settlement | |||||
* | |||||
* @param subMchid 本服务商进件、已签约的特约商户号。 | |||||
* @return the settlement info result | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
SettlementInfoResult querySettlementBySubMchid(String subMchid) throws WxPayException; | |||||
/** | |||||
* 修改结算帐号 | |||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/applyment4sub/chapter3_3.shtml | |||||
* 接口链接:https://api.mch.weixin.qq.com/v3/apply4sub/sub_merchants/{sub_mchid}/modify-settlement | |||||
* | |||||
* @param subMchid 特约商户号 | |||||
* @param request 修改结算账户请求对象信息 | |||||
* @throws WxPayException the wx pay exception | |||||
* @return | |||||
*/ | |||||
String modifySettlement(String subMchid, ModifySettlementRequest request) throws WxPayException; | |||||
} |
@@ -0,0 +1,121 @@ | |||||
package com.github.binarywang.wxpay.service; | |||||
import com.github.binarywang.wxpay.bean.bank.*; | |||||
import com.github.binarywang.wxpay.exception.WxPayException; | |||||
/** | |||||
* <pre> | |||||
* 微信支付-银行组件 | |||||
* </pre> | |||||
* | |||||
* @author zhongjun | |||||
**/ | |||||
public interface BankService { | |||||
/** | |||||
* <pre> | |||||
* | |||||
* 获取对私银行卡号开户银行 | |||||
* | |||||
* 请求方式:GET(HTTPS) | |||||
* 请求地址:<a href="https://api.mch.weixin.qq.com/v3/capital/capitallhh/banks/search-banks-by-bank-account">https://api.mch.weixin.qq.com/v3/capital/capitallhh/banks/search-banks-by-bank-account</a> | |||||
* | |||||
* 文档地址:<a href="https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_1.shtml">https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_1.shtml</a> | |||||
* </pre> | |||||
* | |||||
* @param accountNumber 银行卡号 该字段需进行加密处理,加密方法详见敏感信息加密说明。(提醒:必须在HTTP头中上送Wechatpay-Serial) | |||||
* @return BankAccountResult 对私银行卡号开户银行信息 | |||||
* @throws WxPayException . | |||||
*/ | |||||
BankAccountResult searchBanksByBankAccount(String accountNumber) throws WxPayException; | |||||
/** | |||||
* <pre> | |||||
* | |||||
* 查询支持个人业务的银行列表 | |||||
* | |||||
* 请求方式:GET(HTTPS) | |||||
* 请求地址:<a href="https://api.mch.weixin.qq.com/v3/capital/capitallhh/banks/personal-banking">https://api.mch.weixin.qq.com/v3/capital/capitallhh/banks/personal-banking</a> | |||||
* | |||||
* 文档地址:<a href="https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_2.shtml">https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_2.shtml</a> | |||||
* </pre> | |||||
* | |||||
* @param offset 本次查询偏移量 | |||||
* @param limit 本次请求最大查询条数,最大值为200 | |||||
* @return PersonalBankingResult 支持个人业务的银行列表信息 | |||||
* @throws WxPayException . | |||||
*/ | |||||
BankingResult personalBanking(Integer offset, Integer limit) throws WxPayException; | |||||
/** | |||||
* <pre> | |||||
* | |||||
* 支持对公业务的银行列表 | |||||
* | |||||
* 请求方式:GET(HTTPS) | |||||
* 请求地址:<a href="https://api.mch.weixin.qq.com/v3/capital/capitallhh/banks/corporate-banking">https://api.mch.weixin.qq.com/v3/capital/capitallhh/banks/corporate-banking</a> | |||||
* | |||||
* 文档地址:<a href="https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_3.shtml">https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_3.shtml</a> | |||||
* </pre> | |||||
* | |||||
* @param offset 本次查询偏移量 | |||||
* @param limit 本次请求最大查询条数,最大值为200 | |||||
* @return BankingResult 支持对公业务的银行列表信息 | |||||
* @throws WxPayException . | |||||
*/ | |||||
BankingResult corporateBanking(Integer offset, Integer limit) throws WxPayException; | |||||
/** | |||||
* <pre> | |||||
* | |||||
* 查询省份列表API | |||||
* 通过本接口获取省份列表数据(不包含中国港澳台地区),可用于省份下的城市数据查询 | |||||
* | |||||
* 请求方式:GET(HTTPS) | |||||
* 请求地址:<a href="https://api.mch.weixin.qq.com/v3/capital/capitallhh/areas/provinces">https://api.mch.weixin.qq.com/v3/capital/capitallhh/areas/provinces</a> | |||||
* | |||||
* 文档地址:<a href="https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_4.shtml">https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_4.shtml</a> | |||||
* </pre> | |||||
* | |||||
* @return ProvincesResult 省份列表信息 | |||||
* @throws WxPayException . | |||||
*/ | |||||
ProvincesResult areasProvinces() throws WxPayException; | |||||
/** | |||||
* <pre> | |||||
* | |||||
* 查询城市列表API | |||||
* 通过本接口根据省份编码获取省份下的城市列表信息,不包含中国港澳台地区城市信息,可用于支行数据过滤查询 | |||||
* | |||||
* 请求方式:GET(HTTPS) | |||||
* 请求地址:<a href="https://api.mch.weixin.qq.com/v3/capital/capitallhh/areas/provinces/{province_code}/cities">https://api.mch.weixin.qq.com/v3/capital/capitallhh/areas/provinces/{province_code}/cities</a> | |||||
* | |||||
* 文档地址:<a href="https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_5.shtml">https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_5.shtml</a> | |||||
* </pre> | |||||
* | |||||
* @return CitiesResult 城市列表信息 | |||||
* @throws WxPayException . | |||||
*/ | |||||
CitiesResult areasCities(Integer provinceCode) throws WxPayException; | |||||
/** | |||||
* <pre> | |||||
* | |||||
* 查询支行列表API | |||||
* 本接口可以用于根据银行别名编码(仅支持需要填写支行的银行别名编码)和城市编码过滤查询支行列表数据 | |||||
* | |||||
* 请求方式:GET(HTTPS) | |||||
* 请求地址:<a href="https://api.mch.weixin.qq.com/v3/capital/capitallhh/banks/{bank_alias_code}/branches">https://api.mch.weixin.qq.com/v3/capital/capitallhh/banks/{bank_alias_code}/branches</a> | |||||
* | |||||
* 文档地址:<a href="https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_5.shtml">https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_5.shtml</a> | |||||
* </pre> | |||||
* | |||||
* @param bankAliasCode 银行别名的编码,查询支行接口仅支持需要填写支行的银行别名编码。示例值:1000006247 | |||||
* @param cityCode 城市编码,唯一标识一座城市,用于结合银行别名编码查询支行列表。示例值:536 | |||||
* @param offset 非负整数,表示该次请求资源的起始位置,从0开始计数。调用方选填,默认为0。offset为20,limit为100时,查询第21-120条数据 | |||||
* @param limit 非0非负的整数,该次请求可返回的最大资源条数。示例值:200 | |||||
* @return BankBranchesResult 城市列表信息 | |||||
* @throws WxPayException . | |||||
*/ | |||||
BankBranchesResult bankBranches(String bankAliasCode, Integer cityCode, Integer offset, Integer limit) throws WxPayException; | |||||
} |
@@ -0,0 +1,59 @@ | |||||
package com.github.binarywang.wxpay.service; | |||||
import com.github.binarywang.wxpay.bean.businesscircle.*; | |||||
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader; | |||||
import com.github.binarywang.wxpay.exception.WxPayException; | |||||
/** | |||||
* <pre> | |||||
* 微信支付智慧商圈API | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
public interface BusinessCircleService { | |||||
/** | |||||
* <pre> | |||||
* 智慧商圈接口-商圈积分同步API | |||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/businesscircle/chapter3_2.shtml | |||||
* 接口链接:https://api.mch.weixin.qq.com/v3/businesscircle/points/notify | |||||
* </pre> | |||||
* | |||||
* @param request 请求对象 | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
String notifyPoints(PointsNotifyRequest request) throws WxPayException; | |||||
BusinessCircleNotifyData parseNotifyData(String data, SignatureHeader header) throws WxPayException; | |||||
PaidResult decryptPaidNotifyDataResource(BusinessCircleNotifyData data) throws WxPayException; | |||||
RefundResult decryptRefundNotifyDataResource(BusinessCircleNotifyData data) throws WxPayException; | |||||
MemberCardAuthorizeNotifyResult decryptMemberCardAuthorizeNotifyDataResource(BusinessCircleNotifyData data) throws WxPayException; | |||||
/** | |||||
* 授权查询 | |||||
* https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_6_4.shtml | |||||
* @return | |||||
* @throws WxPayException | |||||
*/ | |||||
MemberCardAuthorizeResult getAuthorizations(String openid) throws WxPayException; | |||||
/** | |||||
* 查询待积分状态 | |||||
* @param brandid | |||||
* @param openid | |||||
* @return | |||||
* @throws WxPayException | |||||
*/ | |||||
PointsCommitStatusResult getPointsCommitStatus(String brandid,String openid) throws WxPayException; | |||||
/** | |||||
* 停车状态同步 | |||||
* https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_6_5.shtml | |||||
* @param request | |||||
* @throws WxPayException | |||||
*/ | |||||
void notifyParkings(ParkingNotifyRequest request) throws WxPayException; | |||||
} |
@@ -0,0 +1,50 @@ | |||||
package com.github.binarywang.wxpay.service; | |||||
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader; | |||||
import com.github.binarywang.wxpay.bean.membercard.*; | |||||
import com.github.binarywang.wxpay.exception.WxPayException; | |||||
/** | |||||
* <pre> | |||||
* 会员卡相关接口 | |||||
* </pre> | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
public interface MemberCardService { | |||||
MemberCardNotifyData parseNotifyData(String data, SignatureHeader header) throws WxPayException; | |||||
MemberCardActivateResult decryptActivateNotifyDataResource(MemberCardNotifyData data) throws WxPayException; | |||||
/** | |||||
* 查询会员卡信息 | |||||
* https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter5_9_6.shtml | |||||
* @param card_id | |||||
* @param code | |||||
* @return | |||||
* @throws WxPayException | |||||
*/ | |||||
MemberCardResult getMemberCard(String card_id,String code) throws WxPayException; | |||||
/** | |||||
* 修改用户会员卡信息API | |||||
* https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter5_9_8.shtml | |||||
* @param card_id | |||||
* @param code | |||||
* @param request | |||||
* @throws WxPayException | |||||
*/ | |||||
void updMemberCard(String card_id, String code, MemberCardUpdRequest request) throws WxPayException; | |||||
/** | |||||
* 设置用户会员权益信息api | |||||
* https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter5_9_23.shtml | |||||
* @param card_id | |||||
* @param code | |||||
* @param request | |||||
* @throws WxPayException | |||||
*/ | |||||
void setMemberCardRights(String card_id,String code,MemberCardRightsRequest request) throws WxPayException; | |||||
} |
@@ -0,0 +1,46 @@ | |||||
package com.github.binarywang.wxpay.service; | |||||
import com.github.binarywang.wxpay.bean.media.ImageUploadResult; | |||||
import com.github.binarywang.wxpay.exception.WxPayException; | |||||
import java.io.File; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
/** | |||||
* <pre> | |||||
* 微信支付通用媒体接口. | |||||
* </pre> | |||||
* | |||||
* @author zhouyongshen | |||||
*/ | |||||
public interface MerchantMediaService { | |||||
/** | |||||
* <pre> | |||||
* 通用接口-图片上传API | |||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/chapter3_1.shtml | |||||
* 接口链接:https://api.mch.weixin.qq.com/v3/merchant/media/upload | |||||
* </pre> | |||||
* | |||||
* @param imageFile 需要上传的图片文件 | |||||
* @return ImageUploadResult 微信返回的媒体文件标识Id。示例值:6uqyGjGrCf2GtyXP8bxrbuH9-aAoTjH-rKeSl3Lf4_So6kdkQu4w8BYVP3bzLtvR38lxt4PjtCDXsQpzqge_hQEovHzOhsLleGFQVRF-U_0 | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
ImageUploadResult imageUploadV3(File imageFile) throws WxPayException, IOException; | |||||
/** | |||||
* <pre> | |||||
* 通用接口-图片上传API | |||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/chapter3_1.shtml | |||||
* 接口链接:https://api.mch.weixin.qq.com/v3/merchant/media/upload | |||||
* </pre> | |||||
* | |||||
* @param inputStream 需要上传的图片文件流 | |||||
* @param fileName 需要上传的图片文件名 | |||||
* @return ImageUploadResult 微信返回的媒体文件标识Id。示例值:6uqyGjGrCf2GtyXP8bxrbuH9-aAoTjH-rKeSl3Lf4_So6kdkQu4w8BYVP3bzLtvR38lxt4PjtCDXsQpzqge_hQEovHzOhsLleGFQVRF-U_0 | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
ImageUploadResult imageUploadV3(InputStream inputStream, String fileName) throws WxPayException, IOException; | |||||
} |
@@ -9,8 +9,11 @@ import com.github.binarywang.wxpay.bean.request.*; | |||||
import com.github.binarywang.wxpay.bean.result.*; | import com.github.binarywang.wxpay.bean.result.*; | ||||
import com.github.binarywang.wxpay.config.WxPayConfig; | import com.github.binarywang.wxpay.config.WxPayConfig; | ||||
import com.github.binarywang.wxpay.exception.WxPayException; | import com.github.binarywang.wxpay.exception.WxPayException; | ||||
import org.apache.http.client.methods.HttpPost; | |||||
import org.apache.http.client.methods.HttpRequestBase; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.InputStream; | |||||
import java.util.Date; | import java.util.Date; | ||||
import java.util.Map; | import java.util.Map; | ||||
@@ -53,6 +56,87 @@ public interface WxPayService { | |||||
*/ | */ | ||||
String post(String url, String requestStr, boolean useKey) throws WxPayException; | String post(String url, String requestStr, boolean useKey) throws WxPayException; | ||||
/** | |||||
* 发送post请求,得到响应字符串. | |||||
* | |||||
* @param url 请求地址 | |||||
* @param requestStr 请求信息 | |||||
* @return 返回请求结果字符串 string | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
String postV3(String url, String requestStr) throws WxPayException; | |||||
/** | |||||
* 发送patch请求,得到响应字符串. | |||||
* | |||||
* @param url 请求地址 | |||||
* @param requestStr 请求信息 | |||||
* @return 返回请求结果字符串 string | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
String patchV3(String url, String requestStr) throws WxPayException; | |||||
/** | |||||
* 发送post请求,得到响应字符串. | |||||
* <p> | |||||
* 部分字段会包含敏感信息,所以在提交前需要在请求头中会包含"Wechatpay-Serial"信息 | |||||
* | |||||
* @param url 请求地址 | |||||
* @param requestStr 请求信息 | |||||
* @return 返回请求结果字符串 string | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
String postV3WithWechatpaySerial(String url, String requestStr) throws WxPayException; | |||||
/** | |||||
* 发送post请求,得到响应字符串. | |||||
* | |||||
* @param url 请求地址 | |||||
* @param httpPost 请求信息 | |||||
* @return 返回请求结果字符串 string | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
String postV3(String url, HttpPost httpPost) throws WxPayException; | |||||
/** | |||||
* 发送http请求,得到响应字符串. | |||||
* | |||||
* @param url 请求地址 | |||||
* @param httpRequest 请求信息,可以是put,post,get,delete等请求 | |||||
* @return 返回请求结果字符串 string | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
String requestV3(String url, HttpRequestBase httpRequest) throws WxPayException; | |||||
/** | |||||
* 发送get V3请求,得到响应字符串. | |||||
* | |||||
* @param url 请求地址 | |||||
* @return 返回请求结果字符串 string | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
String getV3(String url) throws WxPayException; | |||||
/** | |||||
* 发送get请求,得到响应字符串. | |||||
* <p> | |||||
* 部分字段会包含敏感信息,所以在提交前需要在请求头中会包含"Wechatpay-Serial"信息 | |||||
* | |||||
* @param url 请求地址 | |||||
* @return 返回请求结果字符串 string | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
String getV3WithWechatPaySerial(String url) throws WxPayException; | |||||
/** | |||||
* 发送下载 V3请求,得到响应流. | |||||
* | |||||
* @param url 请求地址 | |||||
* @return 返回请求响应流 input stream | |||||
* @throws WxPayException the wx pay exception | |||||
*/ | |||||
InputStream downloadV3(String url) throws WxPayException; | |||||
/** | /** | ||||
* 获取企业付款服务类. | * 获取企业付款服务类. | ||||
* | * | ||||
@@ -74,6 +158,41 @@ public interface WxPayService { | |||||
*/ | */ | ||||
ProfitSharingService getProfitSharingService(); | ProfitSharingService getProfitSharingService(); | ||||
/** | |||||
* 获取微信支付智慧商圈服务类 | |||||
* | |||||
* @return the business circle service | |||||
*/ | |||||
BusinessCircleService getBusinessCircleService(); | |||||
/** | |||||
* 获取会员卡服务类 | |||||
* | |||||
* @return the business circle service | |||||
*/ | |||||
MemberCardService getMemberCardService(); | |||||
/** | |||||
* 特约商户进件服务 | |||||
* | |||||
* @return | |||||
*/ | |||||
Applyment4SubService getApplyment4SubService(); | |||||
/** | |||||
* 媒体上传服务 | |||||
* | |||||
* @return | |||||
*/ | |||||
MerchantMediaService getMerchantMediaService(); | |||||
/** | |||||
* 获取银行组件服务 | |||||
* | |||||
* @return 银行组件服务 | |||||
*/ | |||||
BankService getBankService(); | |||||
/** | /** | ||||
* 设置企业付款服务类,允许开发者自定义实现类. | * 设置企业付款服务类,允许开发者自定义实现类. | ||||
* | * | ||||
@@ -81,6 +200,7 @@ public interface WxPayService { | |||||
*/ | */ | ||||
void setEntPayService(EntPayService entPayService); | void setEntPayService(EntPayService entPayService); | ||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 查询订单. | * 查询订单. | ||||
@@ -0,0 +1,66 @@ | |||||
package com.github.binarywang.wxpay.service.impl; | |||||
import com.github.binarywang.wxpay.bean.applyment.*; | |||||
import com.github.binarywang.wxpay.exception.WxPayException; | |||||
import com.github.binarywang.wxpay.service.Applyment4SubService; | |||||
import com.github.binarywang.wxpay.service.WxPayService; | |||||
import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil; | |||||
import com.google.gson.Gson; | |||||
import com.google.gson.GsonBuilder; | |||||
import lombok.RequiredArgsConstructor; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import java.security.cert.X509Certificate; | |||||
@Slf4j | |||||
@RequiredArgsConstructor | |||||
public class Applyment4SubServiceImpl implements Applyment4SubService { | |||||
private static final Gson GSON = new GsonBuilder().create(); | |||||
private final WxPayService payService; | |||||
private void encryptFiled(Object request) throws WxPayException { | |||||
X509Certificate validCertificate = payService.getConfig().getVerifier().getValidCertificate(); | |||||
RsaCryptoUtil.encryptFields(request, validCertificate); | |||||
} | |||||
@Override | |||||
public WxPayApplymentCreateResult createApply(WxPayApplyment4SubCreateRequest request) throws WxPayException { | |||||
String url = String.format("%s/v3/applyment4sub/applyment/", this.payService.getPayBaseUrl()); | |||||
encryptFiled(request); | |||||
String result = payService.postV3WithWechatpaySerial(url, GSON.toJson(request)); | |||||
return GSON.fromJson(result, WxPayApplymentCreateResult.class); | |||||
} | |||||
@Override | |||||
public ApplymentStateQueryResult queryApplyStatusByBusinessCode(String businessCode) throws WxPayException { | |||||
String url = String.format("%s/v3/applyment4sub/applyment/business_code/%s", this.payService.getPayBaseUrl(), businessCode); | |||||
String result = payService.getV3(url); | |||||
return GSON.fromJson(result, ApplymentStateQueryResult.class); | |||||
} | |||||
@Override | |||||
public ApplymentStateQueryResult queryApplyStatusByApplymentId(String applymentId) throws WxPayException { | |||||
String url = String.format("%s/v3/applyment4sub/applyment/applyment_id/%s", this.payService.getPayBaseUrl(), applymentId); | |||||
String result = payService.getV3(url); | |||||
return GSON.fromJson(result, ApplymentStateQueryResult.class); | |||||
} | |||||
@Override | |||||
public SettlementInfoResult querySettlementBySubMchid(String subMchid) throws WxPayException { | |||||
String url = String.format("%s/v3/apply4sub/sub_merchants/%s/settlement", this.payService.getPayBaseUrl(), subMchid); | |||||
String result = payService.getV3(url); | |||||
return GSON.fromJson(result, SettlementInfoResult.class); | |||||
} | |||||
@Override | |||||
public String modifySettlement(String subMchid, ModifySettlementRequest request) throws WxPayException { | |||||
String url = String.format("%s/v3/apply4sub/sub_merchants/%s/modify-settlement", this.payService.getPayBaseUrl(), subMchid); | |||||
encryptFiled(request); | |||||
return payService.postV3WithWechatpaySerial(url, GSON.toJson(request)); | |||||
} | |||||
} |
@@ -0,0 +1,68 @@ | |||||
package com.github.binarywang.wxpay.service.impl; | |||||
import com.github.binarywang.wxpay.bean.bank.*; | |||||
import com.github.binarywang.wxpay.exception.WxPayException; | |||||
import com.github.binarywang.wxpay.service.BankService; | |||||
import com.github.binarywang.wxpay.service.WxPayService; | |||||
import com.google.gson.Gson; | |||||
import com.google.gson.GsonBuilder; | |||||
import lombok.RequiredArgsConstructor; | |||||
/** | |||||
* 微信支付-银行组件 | |||||
* | |||||
* @author zhongjun | |||||
**/ | |||||
@RequiredArgsConstructor | |||||
public class BankServiceImpl implements BankService { | |||||
private final WxPayService payService; | |||||
private static final Gson GSON = new GsonBuilder().create(); | |||||
@Override | |||||
public BankAccountResult searchBanksByBankAccount(String accountNumber) throws WxPayException { | |||||
String url = String.format("%s/v3/capital/capitallhh/banks/search-banks-by-bank-account?account_number=%s", this.payService.getPayBaseUrl(), accountNumber); | |||||
String response = payService.getV3WithWechatPaySerial(url); | |||||
return GSON.fromJson(response, BankAccountResult.class); | |||||
} | |||||
@Override | |||||
public BankingResult personalBanking(Integer offset, Integer limit) throws WxPayException { | |||||
offset = offset == null ? 0 : offset; | |||||
limit = limit == null ? 200 : limit; | |||||
String url = String.format("%s/v3/capital/capitallhh/banks/personal-banking?offset=%s&limit=%s", this.payService.getPayBaseUrl(), offset, limit); | |||||
String response = payService.getV3(url); | |||||
return GSON.fromJson(response, BankingResult.class); | |||||
} | |||||
@Override | |||||
public BankingResult corporateBanking(Integer offset, Integer limit) throws WxPayException { | |||||
offset = offset == null ? 0 : offset; | |||||
limit = limit == null ? 200 : limit; | |||||
String url = String.format("%s/v3/capital/capitallhh/banks/corporate-banking?offset=%s&limit=%s", this.payService.getPayBaseUrl(), offset, limit); | |||||
String response = payService.getV3(url); | |||||
return GSON.fromJson(response, BankingResult.class); | |||||
} | |||||
@Override | |||||
public ProvincesResult areasProvinces() throws WxPayException { | |||||
String url = String.format("%s/v3/capital/capitallhh/areas/provinces", this.payService.getPayBaseUrl()); | |||||
String response = payService.getV3WithWechatPaySerial(url); | |||||
return GSON.fromJson(response, ProvincesResult.class); | |||||
} | |||||
@Override | |||||
public CitiesResult areasCities(Integer provinceCode) throws WxPayException { | |||||
String url = String.format("%s/v3/capital/capitallhh/areas/provinces/%s/cities", this.payService.getPayBaseUrl(), provinceCode); | |||||
String response = payService.getV3WithWechatPaySerial(url); | |||||
return GSON.fromJson(response, CitiesResult.class); | |||||
} | |||||
@Override | |||||
public BankBranchesResult bankBranches(String bankAliasCode, Integer cityCode, Integer offset, Integer limit) throws WxPayException { | |||||
offset = offset == null ? 0 : offset; | |||||
limit = limit == null ? 200 : limit; | |||||
String url = String.format("%s/v3/capital/capitallhh/banks/%s/branches?city_code=%s&offset=%s&limit=%s", this.payService.getPayBaseUrl(), bankAliasCode, cityCode, offset, limit); | |||||
String response = payService.getV3(url); | |||||
return GSON.fromJson(response, BankBranchesResult.class); | |||||
} | |||||
} |
@@ -16,10 +16,7 @@ import com.github.binarywang.wxpay.config.WxPayConfig; | |||||
import com.github.binarywang.wxpay.constant.WxPayConstants.SignType; | import com.github.binarywang.wxpay.constant.WxPayConstants.SignType; | ||||
import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType; | import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType; | ||||
import com.github.binarywang.wxpay.exception.WxPayException; | import com.github.binarywang.wxpay.exception.WxPayException; | ||||
import com.github.binarywang.wxpay.service.EntPayService; | |||||
import com.github.binarywang.wxpay.service.ProfitSharingService; | |||||
import com.github.binarywang.wxpay.service.RedpackService; | |||||
import com.github.binarywang.wxpay.service.WxPayService; | |||||
import com.github.binarywang.wxpay.service.*; | |||||
import com.github.binarywang.wxpay.util.SignUtils; | import com.github.binarywang.wxpay.util.SignUtils; | ||||
import com.github.binarywang.wxpay.util.XmlConfig; | import com.github.binarywang.wxpay.util.XmlConfig; | ||||
import com.google.common.base.Joiner; | import com.google.common.base.Joiner; | ||||
@@ -63,6 +60,11 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { | |||||
private EntPayService entPayService = new EntPayServiceImpl(this); | private EntPayService entPayService = new EntPayServiceImpl(this); | ||||
private ProfitSharingService profitSharingService = new ProfitSharingServiceImpl(this); | private ProfitSharingService profitSharingService = new ProfitSharingServiceImpl(this); | ||||
private RedpackService redpackService = new RedpackServiceImpl(this); | private RedpackService redpackService = new RedpackServiceImpl(this); | ||||
private BusinessCircleService businessCircleService = new BusinessCircleServiceImpl(this); | |||||
private MemberCardService memberCardServiceService = new MemberCardServiceImpl(this); | |||||
private Applyment4SubService applyment4SubService = new Applyment4SubServiceImpl(this); | |||||
private MerchantMediaService merchantMediaService = new MerchantMediaServiceImpl(this); | |||||
private BankService bankService = new BankServiceImpl(this); | |||||
/** | /** | ||||
* The Config. | * The Config. | ||||
@@ -79,11 +81,36 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { | |||||
return profitSharingService; | return profitSharingService; | ||||
} | } | ||||
@Override | |||||
public BusinessCircleService getBusinessCircleService() { | |||||
return this.businessCircleService; | |||||
} | |||||
@Override | |||||
public MemberCardService getMemberCardService(){ | |||||
return this.memberCardServiceService; | |||||
} | |||||
@Override | @Override | ||||
public RedpackService getRedpackService() { | public RedpackService getRedpackService() { | ||||
return this.redpackService; | return this.redpackService; | ||||
} | } | ||||
@Override | |||||
public Applyment4SubService getApplyment4SubService() { | |||||
return applyment4SubService; | |||||
} | |||||
@Override | |||||
public MerchantMediaService getMerchantMediaService() { | |||||
return merchantMediaService; | |||||
} | |||||
@Override | |||||
public BankService getBankService() { | |||||
return bankService; | |||||
} | |||||
@Override | @Override | ||||
public void setEntPayService(EntPayService entPayService) { | public void setEntPayService(EntPayService entPayService) { | ||||
this.entPayService = entPayService; | this.entPayService = entPayService; | ||||
@@ -0,0 +1,125 @@ | |||||
package com.github.binarywang.wxpay.service.impl; | |||||
import com.github.binarywang.wxpay.bean.businesscircle.*; | |||||
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader; | |||||
import com.github.binarywang.wxpay.exception.WxPayException; | |||||
import com.github.binarywang.wxpay.service.BusinessCircleService; | |||||
import com.github.binarywang.wxpay.service.WxPayService; | |||||
import com.github.binarywang.wxpay.v3.util.AesUtils; | |||||
import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil; | |||||
import com.google.gson.Gson; | |||||
import com.google.gson.GsonBuilder; | |||||
import lombok.RequiredArgsConstructor; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import java.io.IOException; | |||||
import java.nio.charset.StandardCharsets; | |||||
import java.security.GeneralSecurityException; | |||||
import java.util.Objects; | |||||
/** | |||||
* 微信支付-微信支付智慧商圈service | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@Slf4j | |||||
@RequiredArgsConstructor | |||||
public class BusinessCircleServiceImpl implements BusinessCircleService { | |||||
private static final Gson GSON = new GsonBuilder().create(); | |||||
private final WxPayService payService; | |||||
@Override | |||||
public String notifyPoints(PointsNotifyRequest request) throws WxPayException { | |||||
String url = String.format("%s/v3/businesscircle/points/notify", this.payService.getPayBaseUrl()); | |||||
RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate()); | |||||
return this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request)); | |||||
} | |||||
/** | |||||
* 校验通知签名 | |||||
* | |||||
* @param header 通知头信息 | |||||
* @param data 通知数据 | |||||
* @return true:校验通过 false:校验不通过 | |||||
*/ | |||||
private boolean verifyNotifySign(SignatureHeader header, String data) { | |||||
String beforeSign = String.format("%s%n%s%n%s%n", header.getTimeStamp(), header.getNonce(), data); | |||||
return payService.getConfig().getVerifier().verify(header.getSerialNo(), | |||||
beforeSign.getBytes(StandardCharsets.UTF_8), header.getSigned()); | |||||
} | |||||
@Override | |||||
public BusinessCircleNotifyData parseNotifyData(String data, SignatureHeader header) throws WxPayException { | |||||
if (Objects.nonNull(header) && !this.verifyNotifySign(header, data)) { | |||||
throw new WxPayException("非法请求,头部信息验证失败"); | |||||
} | |||||
return GSON.fromJson(data, BusinessCircleNotifyData.class); | |||||
} | |||||
@Override | |||||
public PaidResult decryptPaidNotifyDataResource(BusinessCircleNotifyData data) throws WxPayException { | |||||
BusinessCircleNotifyData.Resource resource = data.getResource(); | |||||
String cipherText = resource.getCipherText(); | |||||
String associatedData = resource.getAssociatedData(); | |||||
String nonce = resource.getNonce(); | |||||
String apiV3Key = this.payService.getConfig().getApiV3Key(); | |||||
try { | |||||
return GSON.fromJson(AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key), PaidResult.class); | |||||
} catch (GeneralSecurityException | IOException e) { | |||||
throw new WxPayException("解析报文异常!", e); | |||||
} | |||||
} | |||||
@Override | |||||
public RefundResult decryptRefundNotifyDataResource(BusinessCircleNotifyData data) throws WxPayException { | |||||
BusinessCircleNotifyData.Resource resource = data.getResource(); | |||||
String cipherText = resource.getCipherText(); | |||||
String associatedData = resource.getAssociatedData(); | |||||
String nonce = resource.getNonce(); | |||||
String apiV3Key = this.payService.getConfig().getApiV3Key(); | |||||
try { | |||||
return GSON.fromJson(AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key), RefundResult.class); | |||||
} catch (GeneralSecurityException | IOException e) { | |||||
throw new WxPayException("解析报文异常!", e); | |||||
} | |||||
} | |||||
@Override | |||||
public MemberCardAuthorizeNotifyResult decryptMemberCardAuthorizeNotifyDataResource(BusinessCircleNotifyData data) throws WxPayException { | |||||
BusinessCircleNotifyData.Resource resource = data.getResource(); | |||||
String cipherText = resource.getCipherText(); | |||||
String associatedData = resource.getAssociatedData(); | |||||
String nonce = resource.getNonce(); | |||||
String apiV3Key = this.payService.getConfig().getApiV3Key(); | |||||
try { | |||||
return GSON.fromJson(AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key), MemberCardAuthorizeNotifyResult.class); | |||||
} catch (GeneralSecurityException | IOException e) { | |||||
throw new WxPayException("解析报文异常!", e); | |||||
} | |||||
} | |||||
@Override | |||||
public MemberCardAuthorizeResult getAuthorizations(String openid) throws WxPayException { | |||||
String url = String.format("%s/v3/businesscircle/user-authorizations/%s?sub_mchid=%s&appid=%s", | |||||
this.payService.getPayBaseUrl(),openid,this.payService.getConfig().getSubMchId(),this.payService.getConfig().getAppId()); | |||||
String response = this.payService.getV3WithWechatPaySerial(url); | |||||
return GSON.fromJson(response,MemberCardAuthorizeResult.class); | |||||
} | |||||
@Override | |||||
public PointsCommitStatusResult getPointsCommitStatus(String brandid, String openid) throws WxPayException { | |||||
String url = String.format("%s/v3/businesscircle/user/%s/points/commit_status?sub_mchid=%s&brandid=%s&appid=%s", | |||||
this.payService.getPayBaseUrl(),openid,this.payService.getConfig().getSubMchId(),brandid,this.payService.getConfig().getAppId()); | |||||
String response = this.payService.getV3WithWechatPaySerial(url); | |||||
return GSON.fromJson(response,PointsCommitStatusResult.class); | |||||
} | |||||
@Override | |||||
public void notifyParkings(ParkingNotifyRequest request) throws WxPayException { | |||||
request.setAppid(this.payService.getConfig().getAppId()); | |||||
request.setSubMchid(this.payService.getConfig().getSubMchId()); | |||||
String url = String.format("%s/v3/businesscircle/parkings", this.payService.getPayBaseUrl()); | |||||
RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate()); | |||||
this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request)); | |||||
} | |||||
} |
@@ -0,0 +1,87 @@ | |||||
package com.github.binarywang.wxpay.service.impl; | |||||
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader; | |||||
import com.github.binarywang.wxpay.bean.membercard.*; | |||||
import com.github.binarywang.wxpay.exception.WxPayException; | |||||
import com.github.binarywang.wxpay.service.MemberCardService; | |||||
import com.github.binarywang.wxpay.service.WxPayService; | |||||
import com.github.binarywang.wxpay.v3.util.AesUtils; | |||||
import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil; | |||||
import com.google.gson.Gson; | |||||
import com.google.gson.GsonBuilder; | |||||
import lombok.RequiredArgsConstructor; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import java.io.IOException; | |||||
import java.nio.charset.StandardCharsets; | |||||
import java.security.GeneralSecurityException; | |||||
import java.util.Objects; | |||||
/** | |||||
* 会员卡相关 | |||||
* | |||||
* @author thinsstar | |||||
*/ | |||||
@Slf4j | |||||
@RequiredArgsConstructor | |||||
public class MemberCardServiceImpl implements MemberCardService { | |||||
private static final Gson GSON = new GsonBuilder().create(); | |||||
private final WxPayService payService; | |||||
/** | |||||
* 校验通知签名 | |||||
* | |||||
* @param header 通知头信息 | |||||
* @param data 通知数据 | |||||
* @return true:校验通过 false:校验不通过 | |||||
*/ | |||||
private boolean verifyNotifySign(SignatureHeader header, String data) { | |||||
String beforeSign = String.format("%s%n%s%n%s%n", header.getTimeStamp(), header.getNonce(), data); | |||||
return payService.getConfig().getVerifier().verify(header.getSerialNo(), | |||||
beforeSign.getBytes(StandardCharsets.UTF_8), header.getSigned()); | |||||
} | |||||
@Override | |||||
public MemberCardNotifyData parseNotifyData(String data, SignatureHeader header) throws WxPayException { | |||||
if (Objects.nonNull(header) && !this.verifyNotifySign(header, data)) { | |||||
throw new WxPayException("非法请求,头部信息验证失败"); | |||||
} | |||||
return GSON.fromJson(data, MemberCardNotifyData.class); | |||||
} | |||||
@Override | |||||
public MemberCardActivateResult decryptActivateNotifyDataResource(MemberCardNotifyData data) throws WxPayException { | |||||
MemberCardNotifyData.Resource resource = data.getResource(); | |||||
String cipherText = resource.getCipherText(); | |||||
String associatedData = resource.getAssociatedData(); | |||||
String nonce = resource.getNonce(); | |||||
String apiV3Key = this.payService.getConfig().getApiV3Key(); | |||||
try { | |||||
return GSON.fromJson(AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key), MemberCardActivateResult.class); | |||||
} catch (GeneralSecurityException | IOException e) { | |||||
throw new WxPayException("解析报文异常!", e); | |||||
} | |||||
} | |||||
@Override | |||||
public MemberCardResult getMemberCard(String card_id, String code) throws WxPayException { | |||||
String url = String.format("%s/v3/marketing/membercard-open/cards/%s/codes/%s", this.payService.getPayBaseUrl(),card_id,code); | |||||
String response = this.payService.getV3WithWechatPaySerial(url); | |||||
return GSON.fromJson(response,MemberCardResult.class); | |||||
} | |||||
@Override | |||||
public void updMemberCard(String card_id, String code, MemberCardUpdRequest request) throws WxPayException { | |||||
String url = String.format("%s/v3/marketing/membercard-open/cards/%s/codes/%s", this.payService.getPayBaseUrl(),card_id,code); | |||||
RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate()); | |||||
this.payService.patchV3(url, GSON.toJson(request)); | |||||
} | |||||
@Override | |||||
public void setMemberCardRights(String card_id, String code, MemberCardRightsRequest request) throws WxPayException { | |||||
String url = String.format("%s/v3/marketing/membercard-open/cards/%s/codes/%s/rights", this.payService.getPayBaseUrl(),card_id,code); | |||||
RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate()); | |||||
this.payService.patchV3(url, GSON.toJson(request)); | |||||
} | |||||
} |
@@ -0,0 +1,60 @@ | |||||
package com.github.binarywang.wxpay.service.impl; | |||||
import com.github.binarywang.wxpay.bean.media.ImageUploadResult; | |||||
import com.github.binarywang.wxpay.exception.WxPayException; | |||||
import com.github.binarywang.wxpay.service.MerchantMediaService; | |||||
import com.github.binarywang.wxpay.service.WxPayService; | |||||
import com.github.binarywang.wxpay.v3.WechatPayUploadHttpPost; | |||||
import lombok.RequiredArgsConstructor; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.apache.commons.codec.digest.DigestUtils; | |||||
import java.io.*; | |||||
import java.net.URI; | |||||
/** | |||||
* 微信支付-媒体文件上传service | |||||
* @author zhouyongshen | |||||
*/ | |||||
@Slf4j | |||||
@RequiredArgsConstructor | |||||
public class MerchantMediaServiceImpl implements MerchantMediaService { | |||||
private final WxPayService payService; | |||||
@Override | |||||
public ImageUploadResult imageUploadV3(File imageFile) throws WxPayException,IOException { | |||||
String url = String.format("%s/v3/merchant/media/upload", this.payService.getPayBaseUrl()); | |||||
try (FileInputStream s1 = new FileInputStream(imageFile)) { | |||||
String sha256 = DigestUtils.sha256Hex(s1); | |||||
try (InputStream s2 = new FileInputStream(imageFile)) { | |||||
WechatPayUploadHttpPost request = new WechatPayUploadHttpPost.Builder(URI.create(url)) | |||||
.withImage(imageFile.getName(), sha256, s2) | |||||
.build(); | |||||
String result = this.payService.postV3(url, request); | |||||
return ImageUploadResult.fromJson(result); | |||||
} | |||||
} | |||||
} | |||||
@Override | |||||
public ImageUploadResult imageUploadV3(InputStream inputStream, String fileName) throws WxPayException, IOException { | |||||
String url = String.format("%s/v3/merchant/media/upload", this.payService.getPayBaseUrl()); | |||||
try(ByteArrayOutputStream bos = new ByteArrayOutputStream()) { | |||||
byte[] buffer = new byte[2048]; | |||||
int len; | |||||
while ((len = inputStream.read(buffer)) > -1) { | |||||
bos.write(buffer, 0, len); | |||||
} | |||||
bos.flush(); | |||||
byte[] data = bos.toByteArray(); | |||||
String sha256 = DigestUtils.sha256Hex(data); | |||||
WechatPayUploadHttpPost request = new WechatPayUploadHttpPost.Builder(URI.create(url)) | |||||
.withImage(fileName, sha256, new ByteArrayInputStream(data)) | |||||
.build(); | |||||
String result = this.payService.postV3(url, request); | |||||
return ImageUploadResult.fromJson(result); | |||||
} | |||||
} | |||||
} |