new:合单支付
This commit is contained in:
@@ -1,30 +0,0 @@
|
|||||||
package com.github.binarywang.wxpay.bean.ecommerce;
|
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 合单支付 JSAPI支付结果响应
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class CombineTransactionsJsResult implements Serializable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* 字段名:预支付交易会话标识
|
|
||||||
* 变量名:prepay_id
|
|
||||||
* 是否必填:是
|
|
||||||
* 类型:string(64)
|
|
||||||
* 描述:
|
|
||||||
* 数字和字母。微信生成的预支付会话标识,用于后续接口调用使用。
|
|
||||||
* 示例值:wx201410272009395522657a690389285100
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
@SerializedName("prepay_id")
|
|
||||||
private String prepayId;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -8,11 +8,11 @@ import java.io.Serializable;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 合单支付 JSAPI支付
|
* 合单支付 对象
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class CombineTransactionsJsRequest implements Serializable {
|
public class CombineTransactionsRequest implements Serializable {
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
* 字段名:合单商户appid
|
* 字段名:合单商户appid
|
||||||
@@ -85,7 +85,7 @@ public class CombineTransactionsJsRequest implements Serializable {
|
|||||||
* <pre>
|
* <pre>
|
||||||
* 字段名:+支付者
|
* 字段名:+支付者
|
||||||
* 变量名:combine_payer_info
|
* 变量名:combine_payer_info
|
||||||
* 是否必填:是
|
* 是否必填:否(JSAPI必填)
|
||||||
* 类型:object
|
* 类型:object
|
||||||
* 描述:支付者信息
|
* 描述:支付者信息
|
||||||
* </pre>
|
* </pre>
|
||||||
@@ -136,25 +136,10 @@ public class CombineTransactionsJsRequest implements Serializable {
|
|||||||
@SerializedName(value = "notify_url")
|
@SerializedName(value = "notify_url")
|
||||||
private String notifyUrl;
|
private String notifyUrl;
|
||||||
|
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* 字段名:指定支付方式
|
|
||||||
* 变量名:limit_pay
|
|
||||||
* 是否必填:否
|
|
||||||
* 类型:array
|
|
||||||
* 描述:
|
|
||||||
* 指定支付方式
|
|
||||||
* no_credit:指定不能使用信用卡支付
|
|
||||||
* 特殊规则:长度最大限制32个字节
|
|
||||||
* 示例值:no_credit
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
@SerializedName(value = "limit_pay")
|
|
||||||
private List<String> limitPay;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public static class SceneInfo implements Serializable{
|
public static class SceneInfo implements Serializable {
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
* 字段名:商户端设备号
|
* 字段名:商户端设备号
|
||||||
@@ -185,11 +170,23 @@ public class CombineTransactionsJsRequest implements Serializable {
|
|||||||
@SerializedName(value = "payer_client_ip")
|
@SerializedName(value = "payer_client_ip")
|
||||||
private String payerClientIp;
|
private String payerClientIp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:H5场景信息
|
||||||
|
* 变量名:h5_info
|
||||||
|
* 是否必填:否(H5支付必填)
|
||||||
|
* 类型:object
|
||||||
|
* 描述:
|
||||||
|
* H5场景信息
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "h5_info")
|
||||||
|
private H5Info h5Info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public static class SubOrders implements Serializable{
|
public static class SubOrders implements Serializable {
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
* 字段名:子单商户号
|
* 字段名:子单商户号
|
||||||
@@ -261,34 +258,6 @@ public class CombineTransactionsJsRequest implements Serializable {
|
|||||||
@SerializedName(value = "sub_mchid")
|
@SerializedName(value = "sub_mchid")
|
||||||
private String subMchid;
|
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>
|
* <pre>
|
||||||
* 字段名:商品描述
|
* 字段名:商品描述
|
||||||
@@ -319,7 +288,7 @@ public class CombineTransactionsJsRequest implements Serializable {
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public static class CombinePayerInfo implements Serializable{
|
public static class CombinePayerInfo implements Serializable {
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
* 字段名:用户标识
|
* 字段名:用户标识
|
||||||
@@ -404,4 +373,83 @@ public class CombineTransactionsJsRequest implements Serializable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class H5Info implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:场景类型
|
||||||
|
* 变量名:type
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string(32)
|
||||||
|
* 描述:
|
||||||
|
* 场景类型,枚举值:
|
||||||
|
* iOS:IOS移动应用;
|
||||||
|
* Android:安卓移动应用;
|
||||||
|
* Wap:WAP网站应用;
|
||||||
|
* 示例值:iOS
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "type")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:应用名称
|
||||||
|
* 变量名:app_name
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(64)
|
||||||
|
* 描述:
|
||||||
|
* 应用名称
|
||||||
|
* 示例值:王者荣耀
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "app_name")
|
||||||
|
private String appName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:网站URL
|
||||||
|
* 变量名:app_url
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(128)
|
||||||
|
* 描述:
|
||||||
|
* 网站URL
|
||||||
|
* 示例值:https://pay.qq.com
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "app_url")
|
||||||
|
private String appUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:iOS平台BundleID
|
||||||
|
* 变量名:bundle_id
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(128)
|
||||||
|
* 描述:
|
||||||
|
* iOS平台BundleID
|
||||||
|
* 示例值:com.tencent.wzryiOS
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "bundle_id")
|
||||||
|
private String bundleId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:Android平台PackageName
|
||||||
|
* 变量名:package_name
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(128)
|
||||||
|
* 描述:
|
||||||
|
* Android平台PackageName
|
||||||
|
* 示例值:com.tencent.tmgp.sgame
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "package_name")
|
||||||
|
private String packageName;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package com.github.binarywang.wxpay.bean.ecommerce;
|
||||||
|
|
||||||
|
import com.github.binarywang.wxpay.bean.ecommerce.enums.TradeTypeEnum;
|
||||||
|
import com.github.binarywang.wxpay.v3.util.AesUtils;
|
||||||
|
import com.github.binarywang.wxpay.v3.util.SignUtils;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合单支付 JSAPI支付结果响应
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class CombineTransactionsResult implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:预支付交易会话标识 (APP支付、JSAPI支付 会返回)
|
||||||
|
* 变量名:prepay_id
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string(64)
|
||||||
|
* 描述:
|
||||||
|
* 数字和字母。微信生成的预支付会话标识,用于后续接口调用使用。
|
||||||
|
* 示例值:wx201410272009395522657a690389285100
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName("prepay_id")
|
||||||
|
private String prepayId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:支付跳转链接 (H5支付 会返回)
|
||||||
|
* 变量名:h5_url
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string(512)
|
||||||
|
* 描述:
|
||||||
|
* 支付跳转链接
|
||||||
|
* 示例值:https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx2016121516420242444321ca0631331346&package=1405458241
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName("h5_url")
|
||||||
|
private String h5Url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:二维码链接 (NATIVE支付 会返回)
|
||||||
|
* 变量名:h5_url
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string(512)
|
||||||
|
* 描述:
|
||||||
|
* 二维码链接
|
||||||
|
* 示例值:weixin://pay.weixin.qq.com/bizpayurl/up?pr=NwY5Mz9&groupid=00
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName("code_url")
|
||||||
|
private String codeUrl;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public static class JsapiResult implements Serializable {
|
||||||
|
private String appId;
|
||||||
|
private String timeStamp;
|
||||||
|
private String nonceStr;
|
||||||
|
private String packageValue;
|
||||||
|
private String signType;
|
||||||
|
private String paySign;
|
||||||
|
|
||||||
|
private String getSignStr(){
|
||||||
|
return String.format("%s\n%s\n%s\n%s\n", appId, timeStamp, nonceStr, packageValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public static class AppResult implements Serializable {
|
||||||
|
private String appid;
|
||||||
|
private String partnerid;
|
||||||
|
private String prepayid;
|
||||||
|
private String packageValue;
|
||||||
|
private String noncestr;
|
||||||
|
private String timestamp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getPayInfo(TradeTypeEnum tradeType, String appId, String mchId, PrivateKey privateKey){
|
||||||
|
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||||
|
String nonceStr = SignUtils.genRandomStr();
|
||||||
|
switch (tradeType){
|
||||||
|
case JSAPI:
|
||||||
|
JsapiResult jsapiResult = new JsapiResult();
|
||||||
|
jsapiResult.setAppId(appId).setTimeStamp(timestamp)
|
||||||
|
.setPackageValue("prepay_id=" + this.prepayId).setNonceStr(nonceStr)
|
||||||
|
//签名类型,默认为RSA,仅支持RSA。
|
||||||
|
.setSignType("RSA").setPaySign(SignUtils.sign(jsapiResult.getSignStr(), privateKey));
|
||||||
|
return (T) jsapiResult;
|
||||||
|
case H5:
|
||||||
|
return (T) this.h5Url;
|
||||||
|
case APP:
|
||||||
|
AppResult appResult = new AppResult();
|
||||||
|
appResult.setAppid(appId).setPrepayid(this.prepayId).setPartnerid(mchId)
|
||||||
|
.setNoncestr(nonceStr).setTimestamp(timestamp)
|
||||||
|
//暂填写固定值Sign=WXPay
|
||||||
|
.setPackageValue("Sign=WXPay");
|
||||||
|
return (T) appResult;
|
||||||
|
case NATIVE:
|
||||||
|
return (T) this.codeUrl;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.github.binarywang.wxpay.bean.ecommerce.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付方式
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum TradeTypeEnum {
|
||||||
|
|
||||||
|
APP("/v3/combine-transactions/app","/v3/pay/partner/transactions/app"),
|
||||||
|
JSAPI("/v3/combine-transactions/jsapi","/v3/pay/partner/transactions/jsapi"),
|
||||||
|
NATIVE("/v3/combine-transactions/native","/v3/pay/partner/transactions/native"),
|
||||||
|
H5("/v3/combine-transactions/h5","/v3/pay/partner/transactions/h5")
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合单url
|
||||||
|
*/
|
||||||
|
private String combineUrl;
|
||||||
|
/**
|
||||||
|
* 单独下单url
|
||||||
|
*/
|
||||||
|
private String partnerUrl;
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.github.binarywang.wxpay.service;
|
package com.github.binarywang.wxpay.service;
|
||||||
|
|
||||||
import com.github.binarywang.wxpay.bean.ecommerce.*;
|
import com.github.binarywang.wxpay.bean.ecommerce.*;
|
||||||
|
import com.github.binarywang.wxpay.bean.ecommerce.enums.TradeTypeEnum;
|
||||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,5 +64,6 @@ public interface EcommerceService {
|
|||||||
* @param request 请求对象
|
* @param request 请求对象
|
||||||
* @return 预支付交易会话标识, 数字和字母。微信生成的预支付会话标识,用于后续接口调用使用。
|
* @return 预支付交易会话标识, 数字和字母。微信生成的预支付会话标识,用于后续接口调用使用。
|
||||||
*/
|
*/
|
||||||
CombineTransactionsJsResult combineTransactions(CombineTransactionsJsRequest request) throws WxPayException;
|
<T> T combineTransactions(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.github.binarywang.wxpay.service.impl;
|
package com.github.binarywang.wxpay.service.impl;
|
||||||
|
|
||||||
import com.github.binarywang.wxpay.bean.ecommerce.*;
|
import com.github.binarywang.wxpay.bean.ecommerce.*;
|
||||||
|
import com.github.binarywang.wxpay.bean.ecommerce.enums.TradeTypeEnum;
|
||||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||||
import com.github.binarywang.wxpay.service.EcommerceService;
|
import com.github.binarywang.wxpay.service.EcommerceService;
|
||||||
import com.github.binarywang.wxpay.service.WxPayService;
|
import com.github.binarywang.wxpay.service.WxPayService;
|
||||||
@@ -8,6 +9,7 @@ import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
@@ -40,10 +42,12 @@ public class EcommerceServiceImpl implements EcommerceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CombineTransactionsJsResult combineTransactions(CombineTransactionsJsRequest request) throws WxPayException {
|
public <T> T combineTransactions(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException {
|
||||||
String url = String.format("%s/v3/combine-transactions/jsapi", this.payService.getPayBaseUrl());
|
String url = this.payService.getPayBaseUrl() + tradeType.getCombineUrl();
|
||||||
String response = this.payService.postV3(url, GSON.toJson(request));
|
String response = this.payService.postV3(url, GSON.toJson(request));
|
||||||
return GSON.fromJson(response, CombineTransactionsJsResult.class);
|
CombineTransactionsResult result = GSON.fromJson(response, CombineTransactionsResult.class);
|
||||||
|
return result.getPayInfo(tradeType, request.getCombineAppid(),
|
||||||
|
request.getCombineMchid(), payService.getConfig().getPrivateKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.github.binarywang.wxpay.v3.util;
|
||||||
|
|
||||||
|
import java.security.*;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class SignUtils {
|
||||||
|
|
||||||
|
public static String sign(String string, PrivateKey privateKey){
|
||||||
|
try {
|
||||||
|
Signature sign = Signature.getInstance("SHA256withRSA");
|
||||||
|
sign.initSign(privateKey);
|
||||||
|
sign.update(string.getBytes());
|
||||||
|
|
||||||
|
return Base64.getEncoder().encodeToString(sign.sign());
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
|
||||||
|
} catch (SignatureException e) {
|
||||||
|
throw new RuntimeException("签名计算失败", e);
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new RuntimeException("无效的私钥", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机生成32位字符串.
|
||||||
|
*/
|
||||||
|
public static String genRandomStr(){
|
||||||
|
return genRandomStr(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成随机字符串
|
||||||
|
* @param length 字符串长度
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String genRandomStr(int length) {
|
||||||
|
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
Random random = new Random();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
int number = random.nextInt(base.length());
|
||||||
|
sb.append(base.charAt(number));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user