--微信支付
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
package com.peanut.modules.pay.weChatPay.dto;
|
||||||
|
|
||||||
|
import com.peanut.modules.pay.weChatPay.enums.WxNotifyType;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
@Data
|
||||||
|
public class WeChatBasePayData {
|
||||||
|
/**
|
||||||
|
* 商品描述
|
||||||
|
*/
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商家订单号,对应 out_trade_no
|
||||||
|
*/
|
||||||
|
private String orderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单金额
|
||||||
|
*/
|
||||||
|
private BigDecimal price;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回调地址
|
||||||
|
*/
|
||||||
|
private WxNotifyType notify;
|
||||||
|
|
||||||
|
private Integer buyOrderId;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.peanut.modules.pay.weChatPay.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class WechatDto implements Serializable {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private String orderSn;
|
||||||
|
|
||||||
|
private Integer buyOrderId;
|
||||||
|
|
||||||
|
|
||||||
|
public String getOrderSn() {
|
||||||
|
return orderSn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrderSn(String orderSn) {
|
||||||
|
this.orderSn = orderSn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getBuyOrderId() {
|
||||||
|
return buyOrderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBuyOrderId(Integer buyOrderId) {
|
||||||
|
this.buyOrderId = buyOrderId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package com.peanut.modules.pay.weChatPay.dto;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
/**
|
||||||
|
* @author
|
||||||
|
* @version 1.0
|
||||||
|
* @description 微信支付退款回调返回的数据
|
||||||
|
* @date
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Slf4j
|
||||||
|
public class WxchatCallbackRefundData {
|
||||||
|
/**
|
||||||
|
* 商户订单号
|
||||||
|
*/
|
||||||
|
private String orderId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商户退款单号,out_refund_no
|
||||||
|
*/
|
||||||
|
private String refundId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信支付系统生成的订单号
|
||||||
|
*/
|
||||||
|
private String transactionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信支付系统生成的退款订单号
|
||||||
|
*/
|
||||||
|
private String transactionRefundId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款渠道
|
||||||
|
* ORIGINAL:原路退款
|
||||||
|
* BALANCE:退回到余额
|
||||||
|
* OTHER_BALANCE:原账户异常退到其他余额账户
|
||||||
|
* OTHER_BANKCARD:原银行卡异常退到其他银行卡
|
||||||
|
*/
|
||||||
|
private String channel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款成功时间
|
||||||
|
* 当前退款成功时才有此返回值
|
||||||
|
*/
|
||||||
|
private Date successTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款状态
|
||||||
|
* 退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款。
|
||||||
|
* SUCCESS:退款成功
|
||||||
|
* CLOSED:退款关闭
|
||||||
|
* PROCESSING:退款处理中
|
||||||
|
* ABNORMAL:退款异常
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款金额
|
||||||
|
*/
|
||||||
|
private BigDecimal refundMoney;
|
||||||
|
|
||||||
|
|
||||||
|
public Date getSuccessTime() {
|
||||||
|
return successTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuccessTime(String successTime) {
|
||||||
|
// Hutool工具包的方法,自动识别一些常用格式的日期字符串
|
||||||
|
this.successTime = DateUtil.parse(successTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.peanut.modules.pay.weChatPay.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum WxApiType {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APP下单
|
||||||
|
*/
|
||||||
|
APP_PAY("/v3/pay/transactions/app"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native下单
|
||||||
|
*/
|
||||||
|
NATIVE_PAY_V2("/pay/unifiedorder"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询订单
|
||||||
|
*/
|
||||||
|
ORDER_QUERY_BY_NO("/v3/pay/transactions/out-trade-no/%s"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭订单
|
||||||
|
*/
|
||||||
|
CLOSE_ORDER_BY_NO("/v3/pay/transactions/out-trade-no/%s/close"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请退款
|
||||||
|
*/
|
||||||
|
DOMESTIC_REFUNDS("/v3/refund/domestic/refunds"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询单笔退款
|
||||||
|
*/
|
||||||
|
DOMESTIC_REFUNDS_QUERY("/v3/refund/domestic/refunds/%s"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请交易账单
|
||||||
|
*/
|
||||||
|
TRADE_BILLS("/v3/bill/tradebill"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请资金账单
|
||||||
|
*/
|
||||||
|
FUND_FLOW_BILLS("/v3/bill/fundflowbill");
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private final String type;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.peanut.modules.pay.weChatPay.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum WxNotifyType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付通知
|
||||||
|
* https://192.168.110.100:9100/pb/weChat/payNotify
|
||||||
|
*/
|
||||||
|
NATIVE_NOTIFY("/pay/payNotify"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付通知
|
||||||
|
*/
|
||||||
|
NATIVE_NOTIFY_V2("/api/wx-pay-v2/native/notify"),
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款结果通知
|
||||||
|
*/
|
||||||
|
REFUND_NOTIFY("/api/wx-pay/refunds/notify");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private final String type;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.peanut.modules.pay.weChatPay.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.peanut.modules.book.entity.PayWechatOrderEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public interface WxpayService extends IService<PayWechatOrderEntity> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.peanut.modules.pay.weChatPay.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.peanut.modules.book.dao.PayWechatOrderDao;
|
||||||
|
import com.peanut.modules.book.entity.PayWechatOrderEntity;
|
||||||
|
import com.peanut.modules.pay.weChatPay.service.WxpayService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class WxpayServiceImpl extends ServiceImpl<PayWechatOrderDao ,PayWechatOrderEntity> implements WxpayService {
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package com.peanut.modules.pay.weChatPay.util;
|
||||||
|
|
||||||
|
|
||||||
|
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.DateTimeException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.*;
|
||||||
|
|
||||||
|
public class WechatPayValidatorForRequest {
|
||||||
|
protected static final Logger log = LoggerFactory.getLogger(WechatPayValidatorForRequest.class);
|
||||||
|
/**
|
||||||
|
* 应答超时时间,单位为分钟
|
||||||
|
*/
|
||||||
|
protected static final long RESPONSE_EXPIRED_MINUTES = 5;
|
||||||
|
protected final Verifier verifier;
|
||||||
|
protected final String body;
|
||||||
|
protected final String requestId;
|
||||||
|
|
||||||
|
public WechatPayValidatorForRequest(Verifier verifier, String body, String requestId) {
|
||||||
|
this.verifier = verifier;
|
||||||
|
this.body = body;
|
||||||
|
this.requestId = requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static IllegalArgumentException parameterError(String message, Object... args) {
|
||||||
|
message = String.format(message, args);
|
||||||
|
return new IllegalArgumentException("parameter error: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static IllegalArgumentException verifyFail(String message, Object... args) {
|
||||||
|
message = String.format(message, args);
|
||||||
|
return new IllegalArgumentException("signature verify fail: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean validate(HttpServletRequest request) throws IOException {
|
||||||
|
try {
|
||||||
|
validateParameters(request);
|
||||||
|
|
||||||
|
String message = buildMessage(request);
|
||||||
|
String serial = request.getHeader(WECHAT_PAY_SERIAL);
|
||||||
|
String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
|
||||||
|
|
||||||
|
if (!verifier.verify(serial, message.getBytes(StandardCharsets.UTF_8), signature)) {
|
||||||
|
|
||||||
|
throw verifyFail("serial=[%s] message=[%s] sign=[%s], request-id=[%s]",
|
||||||
|
serial, message, signature, request.getHeader(REQUEST_ID));
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
log.warn(e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void validateParameters(HttpServletRequest request) {
|
||||||
|
|
||||||
|
// NOTE: ensure HEADER_WECHAT_PAY_TIMESTAMP at last
|
||||||
|
String[] headers = {WECHAT_PAY_SERIAL, WECHAT_PAY_SIGNATURE, WECHAT_PAY_NONCE, WECHAT_PAY_TIMESTAMP};
|
||||||
|
|
||||||
|
String header = null;
|
||||||
|
for (String headerName : headers) {
|
||||||
|
header = request.getHeader(headerName);
|
||||||
|
if (header == null) {
|
||||||
|
throw parameterError("empty [%s], request-id=[%s]", headerName, requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String timestampStr = header;
|
||||||
|
try {
|
||||||
|
Instant responseTime = Instant.ofEpochSecond(Long.parseLong(timestampStr));
|
||||||
|
// 拒绝过期应答
|
||||||
|
if (Duration.between(responseTime, Instant.now()).abs().toMinutes() >= RESPONSE_EXPIRED_MINUTES) {
|
||||||
|
throw parameterError("timestamp=[%s] expires, request-id=[%s]", timestampStr, requestId);
|
||||||
|
}
|
||||||
|
} catch (DateTimeException | NumberFormatException e) {
|
||||||
|
throw parameterError("invalid timestamp=[%s], request-id=[%s]", timestampStr, requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final String buildMessage(HttpServletRequest request) throws IOException {
|
||||||
|
String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
|
||||||
|
String nonce = request.getHeader(WECHAT_PAY_NONCE);
|
||||||
|
return timestamp + "\n"
|
||||||
|
+ nonce + "\n"
|
||||||
|
+ body + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.peanut.modules.pay.weChatPay.util;
|
||||||
|
|
||||||
|
|
||||||
|
import com.peanut.modules.pay.weChatPay.dto.WxchatCallbackRefundData;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款处理接口,为了防止项目开发人员,不手动判断退款失败的情况
|
||||||
|
* 退款失败:退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface WechatRefundCallback {
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WxchatCallbackRefundData是微信支付退款回调数据的格式,在退款请求完成后,微信支付会将退款结果发送给商户的服务器,
|
||||||
|
* 以此通知商户退款结果。refundData表示退款回调的数据,包含退款结果的各种信息,如退款金额、退款状态、退款时间等等。
|
||||||
|
* */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款成功处理情况
|
||||||
|
*/
|
||||||
|
void success(WxchatCallbackRefundData refundData);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款失败处理情况
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void find(WxchatCallbackRefundData refundData);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
package com.peanut.modules.pay.weChatPay.util;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
|
||||||
|
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.Signature;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Data
|
||||||
|
public class WxPayUtil {
|
||||||
|
|
||||||
|
public static final String mchId = "1612860909"; // 商户号
|
||||||
|
|
||||||
|
public static final String appId = "wx47134a8f15083734"; // appId
|
||||||
|
|
||||||
|
public static final String apiV3Key = "4aYFklzaULeGlr7oJPZ6rHWKcxjihZUF"; // apiV3秘钥
|
||||||
|
//商户私钥路径
|
||||||
|
public static final String privateKeyUrl = "C:\\Users\\Administrator\\IdeaProjects\\peanut_book\\src\\main\\resources\\cent\\apiclient_key.pem";
|
||||||
|
|
||||||
|
//平台证书路径
|
||||||
|
public static final String wechatPayCertificateUrl = "C:\\Users\\Administrator\\IdeaProjects\\peanut_book\\src\\main\\resources\\cent\\wechatpay_7B5676E3CDF56680D0414A009CE501C844DBE2D6.pem";
|
||||||
|
//第一步申请完证书后,在API证书哪里点击管理证书就能看到
|
||||||
|
public static final String mchSerialNo = "679AECB2F7AC4183033F713828892BA640E4EEE3"; // 商户证书序列号
|
||||||
|
|
||||||
|
private CloseableHttpClient httpClient;
|
||||||
|
|
||||||
|
public void setup() {
|
||||||
|
// PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(privateKey);
|
||||||
|
PrivateKey merchantPrivateKey = null;
|
||||||
|
X509Certificate wechatPayCertificate = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
merchantPrivateKey = PemUtil.loadPrivateKey(
|
||||||
|
new FileInputStream(privateKeyUrl));
|
||||||
|
wechatPayCertificate = PemUtil.loadCertificate(
|
||||||
|
new FileInputStream(wechatPayCertificateUrl));
|
||||||
|
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<X509Certificate> listCertificates = new ArrayList<>();
|
||||||
|
listCertificates.add(wechatPayCertificate);
|
||||||
|
|
||||||
|
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
|
||||||
|
.withMerchant(mchId, mchSerialNo, merchantPrivateKey)
|
||||||
|
.withWechatPay(listCertificates);
|
||||||
|
httpClient = builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wxMchid商户号
|
||||||
|
* wxCertno证书编号
|
||||||
|
* wxCertPath证书地址
|
||||||
|
* wxPaternerKey v3秘钥
|
||||||
|
* url 下单地址
|
||||||
|
* body 构造好的消息体
|
||||||
|
*/
|
||||||
|
public JSONObject doPostWexinV3(String url, String body) {
|
||||||
|
if (httpClient == null) {
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpPost httpPost = new HttpPost(url);
|
||||||
|
httpPost.addHeader("Content-Type", "application/json;chartset=utf-8");
|
||||||
|
httpPost.addHeader("Accept", "application/json");
|
||||||
|
try {
|
||||||
|
if (body == null) {
|
||||||
|
throw new IllegalArgumentException("data参数不能为空");
|
||||||
|
}
|
||||||
|
StringEntity stringEntity = new StringEntity(body, "utf-8");
|
||||||
|
httpPost.setEntity(stringEntity);
|
||||||
|
// 直接执行execute方法,官方会自动处理签名和验签,并进行证书自动更新
|
||||||
|
HttpResponse httpResponse = httpClient.execute(httpPost);
|
||||||
|
HttpEntity httpEntity = httpResponse.getEntity();
|
||||||
|
|
||||||
|
if (httpResponse.getStatusLine().getStatusCode() == 200) {
|
||||||
|
String jsonResult = EntityUtils.toString(httpEntity);
|
||||||
|
|
||||||
|
return JSONObject.parseObject(jsonResult);
|
||||||
|
} else {
|
||||||
|
System.err.println("微信支付错误信息" + EntityUtils.toString(httpEntity));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取签名
|
||||||
|
public String getSign(String appId, long timestamp, String nonceStr, String pack){
|
||||||
|
String message = buildMessage(appId, timestamp, nonceStr, pack);
|
||||||
|
String paySign= null;
|
||||||
|
try {
|
||||||
|
paySign = sign(message.getBytes("utf-8"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return paySign;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildMessage(String appId, long timestamp, String nonceStr, String pack) {
|
||||||
|
return appId + "\n"
|
||||||
|
+ timestamp + "\n"
|
||||||
|
+ nonceStr + "\n"
|
||||||
|
+ pack + "\n";
|
||||||
|
}
|
||||||
|
private String sign(byte[] message) throws Exception{
|
||||||
|
PrivateKey merchantPrivateKey = null;
|
||||||
|
X509Certificate wechatPayCertificate = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
merchantPrivateKey = PemUtil.loadPrivateKey(
|
||||||
|
new FileInputStream(privateKeyUrl));
|
||||||
|
wechatPayCertificate = PemUtil.loadCertificate(
|
||||||
|
new FileInputStream(wechatPayCertificateUrl));
|
||||||
|
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
Signature sign = Signature.getInstance("SHA256withRSA");
|
||||||
|
//这里需要一个PrivateKey类型的参数,就是商户的私钥。
|
||||||
|
sign.initSign(merchantPrivateKey);
|
||||||
|
sign.update(message);
|
||||||
|
return Base64.getEncoder().encodeToString(sign.sign());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user