art:微信服务商配置优化

This commit is contained in:
曾浩 2020-08-24 20:12:34 +08:00
parent cee37531c7
commit 10e0ca568e
3 changed files with 433 additions and 5 deletions

View File

@ -0,0 +1,407 @@
package com.github.binarywang.wxpay.bean.ecommerce;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* 合单支付 JSAPI支付
*/
@Data
@NoArgsConstructor
public class CombineTransactionsJsRequest implements Serializable {
/**
* <pre>
* 字段名合单商户appid
* 变量名combine_appid
* 是否必填
* 类型string(32)
* 描述
* 合单发起方的appid
* 示例值wxd678efh567hg6787
* </pre>
*/
@SerializedName(value = "combine_appid")
private String combineAppid;
/**
* <pre>
* 字段名合单商户号
* 变量名combine_mchid
* 是否必填
* 类型string(32)
* 描述
* 合单发起方商户号
* 示例值1900000109
* </pre>
*/
@SerializedName(value = "combine_mchid")
private String combineMchid;
/**
* <pre>
* 字段名合单商户订单号
* 变量名combine_out_trade_no
* 是否必填
* 类型string(32)
* 描述
* 合单支付总订单号要求32个字符内只能是数字大小写字母_-|*@ 且在同一个商户号下唯一
* 示例值P20150806125346
* </pre>
*/
@SerializedName(value = "combine_out_trade_no")
private String combineOutTradeNo;
/**
* <pre>
* 字段名+场景信息
* 变量名scene_info
* 是否必填
* 类型object
* 描述支付场景信息描述
* </pre>
*/
@SerializedName(value = "scene_info")
private SceneInfo sceneInfo;
/**
* <pre>
* 字段名+子单信息
* 变量名sub_orders
* 是否必填
* 类型array
* 描述
* 最多支持子单条数50
*
* </pre>
*/
@SerializedName(value = "sub_orders")
private List<SubOrders> subOrders;
/**
* <pre>
* 字段名+支付者
* 变量名combine_payer_info
* 是否必填
* 类型object
* 描述支付者信息
* </pre>
*/
@SerializedName(value = "combine_payer_info")
private CombinePayerInfo combinePayerInfo;
/**
* <pre>
* 字段名交易起始时间
* 变量名time_start
* 是否必填
* 类型string(14)
* 描述
* 订单生成时间遵循rfc3339标准格式格式为YYYY-MM-DDTHH:mm:ss+TIMEZONEYYYY-MM-DD表示年月日T出现在字符串中表示time元素的开头HH:mm:ss表示时分秒TIMEZONE表示时区+08:00表示东八区时间领先UTC 8小时即北京时间例如2015-05-20T13:29:35+08:00表示北京时间2015年5月20日 13点29分35秒
* 示例值2019-12-31T15:59:60+08:00
* </pre>
*/
@SerializedName(value = "time_start")
private String timeStart;
/**
* <pre>
* 字段名交易结束时间
* 变量名time_expire
* 是否必填
* 类型string(14)
* 描述
* 订单失效时间遵循rfc3339标准格式格式为YYYY-MM-DDTHH:mm:ss+TIMEZONEYYYY-MM-DD表示年月日T出现在字符串中表示time元素的开头HH:mm:ss表示时分秒TIMEZONE表示时区+08:00表示东八区时间领先UTC 8小时即北京时间例如2015-05-20T13:29:35+08:00表示北京时间2015年5月20日 13点29分35秒
* 示例值2019-12-31T15:59:60+08:00
* </pre>
*/
@SerializedName(value = "time_expire")
private String timeExpire;
/**
* <pre>
* 字段名通知地址
* 变量名notify_url
* 是否必填
* 类型string(256)
* 描述
* 接收微信支付异步通知回调地址通知url必须为直接可访问的URL不能携带参数
* 格式: URL
* 示例值https://yourapp.com/notify
* </pre>
*/
@SerializedName(value = "notify_url")
private String notifyUrl;
/**
* <pre>
* 字段名指定支付方式
* 变量名limit_pay
* 是否必填
* 类型array
* 描述
* 指定支付方式
* no_credit指定不能使用信用卡支付
* 特殊规则长度最大限制32个字节
* 示例值no_credit
* </pre>
*/
@SerializedName(value = "limit_pay")
private List<String> limitPay;
@Data
@NoArgsConstructor
public static class SceneInfo implements Serializable{
/**
* <pre>
* 字段名商户端设备号
* 变量名device_id
* 是否必填
* 类型string(16)
* 描述
* 终端设备号门店号或收银设备ID
* 特殊规则长度最小7个字节
* 示例值POS1:1
* </pre>
*/
@SerializedName(value = "device_id")
private String deviceId;
/**
* <pre>
* 字段名用户终端IP
* 变量名payer_client_ip
* 是否必填
* 类型string(45)
* 描述
* 用户端实际ip
* 格式: ip(ipv4+ipv6)
* 示例值14.17.22.32
* </pre>
*/
@SerializedName(value = "payer_client_ip")
private String payerClientIp;
}
@Data
@NoArgsConstructor
public static class SubOrders implements Serializable{
/**
* <pre>
* 字段名子单商户号
* 变量名mchid
* 是否必填
* 类型string(32)
* 描述
* 子单发起方商户号必须与发起方appid有绑定关系
* 示例值1900000109
* 此处一般填写服务商商户号
* </pre>
*/
@SerializedName(value = "mchid")
private String mchid;
/**
* <pre>
* 字段名附加信息
* 变量名attach
* 是否必填
* 类型string(128)
* 描述
* 附加数据在查询API和支付通知中原样返回可作为自定义参数使用
* 示例值深圳分店
* </pre>
*/
@SerializedName(value = "attach")
private String attach;
/**
* <pre>
* 字段名+订单金额
* 变量名amount
* 是否必填
* 类型object
* 描述
* </pre>
*/
@SerializedName(value = "amount")
private Amount amount;
/**
* <pre>
* 字段名子单商户订单号
* 变量名out_trade_no
* 是否必填
* 类型string(32)
* 描述
* 商户系统内部订单号要求32个字符内只能是数字大小写字母_-|*@ 且在同一个商户号下唯一
* 特殊规则最小字符长度为6
* 示例值20150806125346
* </pre>
*/
@SerializedName(value = "out_trade_no")
private String outTradeNo;
/**
* <pre>
* 字段名二级商户号
* 变量名sub_mchid
* 是否必填
* 类型string(32)
* 描述
* 二级商户商户号由微信支付生成并下发
* 注意仅适用于电商平台 服务商
* 示例值1900000109
* </pre>
*/
@SerializedName(value = "sub_mchid")
private String subMchid;
/**
* <pre>
* 字段名商品详情
* 变量名detail
* 是否必填
* 类型string(6000)
* 描述商品详细描述商品列表)
* </pre>
*/
@SerializedName(value = "detail")
private String detail;
/**
* <pre>
* 字段名是否指定分账
* 变量名profit_sharing
* 是否必填
* 类型bool
* 描述
* 是否指定分账
* true
* false
* 示例值true
* </pre>
*/
@SerializedName(value = "profit_sharing")
private Boolean profitSharing;
/**
* <pre>
* 字段名商品描述
* 变量名description
* 是否必填
* 类型string(128)
* 描述
* 商品简单描述需传入应用市场上的APP名字-实际商品名称例如天天爱消除-游戏充值
* 示例值腾讯充值中心-QQ会员充值
* </pre>
*/
@SerializedName(value = "description")
private String description;
/**
* <pre>
* 字段名+结算信息
* 变量名settle_info
* 是否必填
* 类型Object
* 描述结算信息
* </pre>
*/
@SerializedName(value = "settle_info")
private SettleInfo settleInfo;
}
@Data
@NoArgsConstructor
public static class CombinePayerInfo implements Serializable{
/**
* <pre>
* 字段名用户标识
* 变量名openid
* 是否必填
* 类型string(128)
* 描述
* 使用合单appid获取的对应用户openid是用户在商户appid下的唯一标识
* 示例值oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
* </pre>
*/
@SerializedName(value = "openid")
private String openid;
}
@Data
@NoArgsConstructor
public static class Amount implements Serializable {
/**
* <pre>
* 字段名标价金额
* 变量名total_amount
* 是否必填
* 类型int64
* 描述
* 子单金额单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "total_amount")
private Integer totalAmount;
/**
* <pre>
* 字段名标价币种
* 变量名currency
* 是否必填
* 类型string(8)
* 描述
* 符合ISO 4217标准的三位字母代码人民币CNY
* 示例值CNY
* </pre>
*/
@SerializedName(value = "currency")
private String currency;
}
@Data
@NoArgsConstructor
public static class SettleInfo implements Serializable{
/**
* <pre>
* 字段名是否指定分账
* 变量名profit_sharing
* 是否必填
* 类型bool
* 描述
* 是否分账与外层profit_sharing同时存在时以本字段为准
* true
* false
* 示例值true
* </pre>
*/
@SerializedName(value = "profit_sharing")
private Boolean profitSharing;
/**
* <pre>
* 字段名补差金额
* 变量名subsidy_amount
* 是否必填
* 类型int64
* 描述
* SettleInfo.profit_sharing为true时该金额才生效
* 示例值10
* </pre>
*/
@SerializedName(value = "subsidy_amount")
private Integer subsidyAmount;
}
}

View File

@ -0,0 +1,16 @@
package com.github.binarywang.wxpay.bean.ecommerce;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
public class CombineTransactionsJsResult implements Serializable {
@SerializedName("prepay_id")
private String prepayId;
}

View File

@ -19,6 +19,7 @@ import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Collections;
/**
@ -229,7 +230,7 @@ public class WxPayConfig {
public CloseableHttpClient initApiV3HttpClient() throws WxPayException {
String privateKeyPath = this.getPrivateKeyPath();
String privateCertPath = this.getPrivateCertPath();
String certSerialNo = this.getCertSerialNo();
String serialNo = this.getCertSerialNo();
String apiV3Key = this.getApiV3Key();
if (StringUtils.isBlank(privateKeyPath)) {
throw new WxPayException("请确保privateKeyPath已设置");
@ -237,9 +238,9 @@ public class WxPayConfig {
if (StringUtils.isBlank(privateCertPath)) {
throw new WxPayException("请确保privateCertPath已设置");
}
if (StringUtils.isBlank(certSerialNo)) {
throw new WxPayException("请确保certSerialNo证书序列号已设置");
}
// if (StringUtils.isBlank(certSerialNo)) {
// throw new WxPayException("请确保certSerialNo证书序列号已设置");
// }
if (StringUtils.isBlank(apiV3Key)) {
throw new WxPayException("请确保apiV3Key值已设置");
}
@ -248,6 +249,10 @@ public class WxPayConfig {
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)),
@ -255,7 +260,7 @@ public class WxPayConfig {
CloseableHttpClient httpClient = WxPayV3HttpClientBuilder.create()
.withMerchant(mchId, certSerialNo, merchantPrivateKey)
.withWechatpay(Collections.singletonList(PemUtils.loadCertificate(certInputStream)))
.withWechatpay(Collections.singletonList(certificate))
.withValidator(new WxPayValidator(verifier))
.build();
this.apiV3HttpClient = httpClient;