1
0
mirror of synced 2026-10-18 05:16:10 +08:00

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+TIMEZONE,YYYY-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+TIMEZONE,YYYY-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;