Commit a98df19f authored by 刘李鹏's avatar 刘李鹏

微信支付宝、退款完成

parent 5c04db5f
...@@ -4,10 +4,7 @@ import cn.quant.baa.pay.acquirer.AcquirerProperties; ...@@ -4,10 +4,7 @@ import cn.quant.baa.pay.acquirer.AcquirerProperties;
import cn.quant.baa.pay.acquirer.MerchantAcquirer; import cn.quant.baa.pay.acquirer.MerchantAcquirer;
import cn.quant.baa.pay.dict.AccessCode; import cn.quant.baa.pay.dict.AccessCode;
import cn.quant.baa.pay.jpa.entity.PayHistoryEntity; import cn.quant.baa.pay.jpa.entity.PayHistoryEntity;
import cn.quant.baa.pay.model.web.CheckPayRequestData; import cn.quant.baa.pay.model.web.*;
import cn.quant.baa.pay.model.web.CheckRefundRequestData;
import cn.quant.baa.pay.model.web.CloseRequestData;
import cn.quant.baa.pay.model.web.PayRequestData;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
...@@ -158,6 +155,16 @@ public class AlipayMerchantAcquirer extends MerchantAcquirer { ...@@ -158,6 +155,16 @@ public class AlipayMerchantAcquirer extends MerchantAcquirer {
return doExecute(bodyNode); return doExecute(bodyNode);
} }
@Override
public JsonNode refund(RefundRequestData refundRequestData) {
ObjectNode bodyNode = objectMapper.createObjectNode();
bodyNode.put("out_trade_no", refundRequestData.getOutTradeNo());
bodyNode.put("refund_amount", refundRequestData.getRefundAmount());
bodyNode.put("refund_reason", refundRequestData.getRefundReason());
bodyNode.put("out_request_no", refundRequestData.getOutRefundNo());
return doExecute(bodyNode);
}
/** /**
* App支付发起请求 * App支付发起请求
* *
......
...@@ -3,10 +3,7 @@ package cn.quant.baa.pay.acquirer.weixin; ...@@ -3,10 +3,7 @@ package cn.quant.baa.pay.acquirer.weixin;
import cn.quant.baa.pay.acquirer.AcquirerProperties; import cn.quant.baa.pay.acquirer.AcquirerProperties;
import cn.quant.baa.pay.acquirer.MerchantAcquirer; import cn.quant.baa.pay.acquirer.MerchantAcquirer;
import cn.quant.baa.pay.jpa.entity.PayHistoryEntity; import cn.quant.baa.pay.jpa.entity.PayHistoryEntity;
import cn.quant.baa.pay.model.web.CheckPayRequestData; import cn.quant.baa.pay.model.web.*;
import cn.quant.baa.pay.model.web.CheckRefundRequestData;
import cn.quant.baa.pay.model.web.CloseRequestData;
import cn.quant.baa.pay.model.web.PayRequestData;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
...@@ -141,6 +138,23 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer { ...@@ -141,6 +138,23 @@ public class WeiXinMerchantAcquirer extends MerchantAcquirer {
return doExecute(payAccess, bodyNode); return doExecute(payAccess, bodyNode);
} }
@Override
public JsonNode refund(RefundRequestData refundRequestData) {
// 转换金额为分
BigInteger amount = new BigDecimal(refundRequestData.getRefundAmount()).multiply(new BigDecimal(100)).toBigInteger();
ObjectNode bodyNode = objectMapper.createObjectNode();
bodyNode.put("out_trade_no", refundRequestData.getOutTradeNo());
bodyNode.put("out_refund_no", refundRequestData.getOutRefundNo());
bodyNode.put("reason", refundRequestData.getRefundReason());
// bodyNode.put("notify_url", "");
bodyNode.putObject("amount")
.put("refund", amount)
.put("total", amount)
.put("currency", "CNY");
String payAccess = properties.getPayAccess();
return doExecute(payAccess, bodyNode);
}
/** /**
* *
* @param payAccess * @param payAccess
......
...@@ -24,8 +24,8 @@ public class CheckRefundRequestData implements Serializable { ...@@ -24,8 +24,8 @@ public class CheckRefundRequestData implements Serializable {
/** /**
* 退款订单号 * 退款订单号
*/ */
@Size(min = 6, max = 64, message = "ILLEGAL_REQ_OUT_TRADE_NO") @Size(min = 6, max = 64, message = "ILLEGAL_REQ_OUT_REFUND_NO")
@NotNull(message = "ILLEGAL_REQ_OUT_TRADE_NO") @NotNull(message = "ILLEGAL_REQ_OUT_REFUND_NO")
private String outRefundNo; private String outRefundNo;
/** /**
......
...@@ -21,6 +21,13 @@ public class RefundRequestData implements Serializable { ...@@ -21,6 +21,13 @@ public class RefundRequestData implements Serializable {
@NotNull(message = "ILLEGAL_REQ_CHAN_ID") @NotNull(message = "ILLEGAL_REQ_CHAN_ID")
private String chanId; private String chanId;
/**
* 退款订单号
*/
@Size(min = 6, max = 64, message = "ILLEGAL_REQ_OUT_REFUND_NO")
@NotNull(message = "ILLEGAL_REQ_OUT_REFUND_NO")
private String outRefundNo;
/** /**
* 商户订单号 * 商户订单号
*/ */
...@@ -28,6 +35,19 @@ public class RefundRequestData implements Serializable { ...@@ -28,6 +35,19 @@ public class RefundRequestData implements Serializable {
@NotNull(message = "ILLEGAL_REQ_OUT_TRADE_NO") @NotNull(message = "ILLEGAL_REQ_OUT_TRADE_NO")
private String outTradeNo; private String outTradeNo;
/**
* 退款原因
*/
@NotNull(message = "ILLEGAL_REQ_REFUND_REASON")
private String refundReason;
/**
* 退款金额
*/
@NotNull(message = "ILLEGAL_REQ_REFUND_AMOUNT")
private String refundAmount;
public String getChanId() { public String getChanId() {
return chanId; return chanId;
} }
...@@ -36,6 +56,14 @@ public class RefundRequestData implements Serializable { ...@@ -36,6 +56,14 @@ public class RefundRequestData implements Serializable {
this.chanId = chanId; this.chanId = chanId;
} }
public String getOutRefundNo() {
return outRefundNo;
}
public void setOutRefundNo(String outRefundNo) {
this.outRefundNo = outRefundNo;
}
public String getOutTradeNo() { public String getOutTradeNo() {
return outTradeNo; return outTradeNo;
} }
...@@ -43,4 +71,20 @@ public class RefundRequestData implements Serializable { ...@@ -43,4 +71,20 @@ public class RefundRequestData implements Serializable {
public void setOutTradeNo(String outTradeNo) { public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo; this.outTradeNo = outTradeNo;
} }
public String getRefundReason() {
return refundReason;
}
public void setRefundReason(String refundReason) {
this.refundReason = refundReason;
}
public String getRefundAmount() {
return refundAmount;
}
public void setRefundAmount(String refundAmount) {
this.refundAmount = refundAmount;
}
} }
...@@ -130,7 +130,7 @@ public class TransactionService extends BusinessService { ...@@ -130,7 +130,7 @@ public class TransactionService extends BusinessService {
} }
@Transactional(propagation = Propagation.NOT_SUPPORTED) @Transactional(propagation = Propagation.NOT_SUPPORTED)
public JsonNode checkRefund(RefundRequestData data) { public JsonNode refund(RefundRequestData data) {
return acquirer.refund(data); return acquirer.refund(data);
} }
......
...@@ -67,6 +67,16 @@ ...@@ -67,6 +67,16 @@
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.16.21.ALL</version>
</dependency>
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.2.2</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
package cn.quant.baa.pay.rest;
import cn.quant.baa.pay.annotation.BusinessMapping;
import cn.quant.baa.pay.context.TransactionSession;
import cn.quant.spring.rest.AbstractController;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import org.springframework.web.bind.annotation.*;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.util.UUID;
/**
* Created with IntelliJ IDEA.
* Author: Lipeng Liu
* Date: 2021/8/31
* Time: 上午10:36
* Description: No Description
*/
@RestController
@RequestMapping("alipay")
public class AlipayController extends AbstractController {
@ResponseBody
@GetMapping("/h5")
public String h5() {
try {
// 1. 创建AlipayClient实例
AlipayClient alipayClient = new DefaultAlipayClient(getClientParams());
// 2. 创建使用的Open API对应的Request请求对象
AlipayTradeWapPayRequest request = getRequestH5();
// 3. 发起请求并处理响应
AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
if (response.isSuccess()) {
System.out.println("调用成功。");
return response.getBody();
} else {
System.out.println("调用失败,原因:" + response.getMsg() + "," + response.getSubMsg());
}
} catch (Exception e) {
System.out.println("调用遭遇异常,原因:" + e.getMessage());
throw new RuntimeException(e.getMessage(), e);
}
return null;
}
@ResponseBody
@GetMapping("/web")
public String web() {
try {
// 1. 创建AlipayClient实例
AlipayClient alipayClient = new DefaultAlipayClient(getClientParams());
// 2. 创建使用的Open API对应的Request请求对象
AlipayTradePagePayRequest request = getRequestWeb();
// 3. 发起请求并处理响应
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
if (response.isSuccess()) {
System.out.println("调用成功。");
return response.getBody();
} else {
System.out.println("调用失败,原因:" + response.getMsg() + "," + response.getSubMsg());
}
} catch (Exception e) {
System.out.println("调用遭遇异常,原因:" + e.getMessage());
throw new RuntimeException(e.getMessage(), e);
}
return null;
}
@ResponseBody
@GetMapping("/app")
public String app() {
try {
// 1. 创建AlipayClient实例
AlipayClient alipayClient = new DefaultAlipayClient(getClientParams());
// 2. 创建使用的Open API对应的Request请求对象
AlipayTradePagePayRequest request = getRequestWeb();
// 3. 发起请求并处理响应
AlipayTradePagePayResponse response = alipayClient.sdkExecute(request);
if (response.isSuccess()) {
System.out.println("调用成功。");
return response.getBody();
} else {
System.out.println("调用失败,原因:" + response.getMsg() + "," + response.getSubMsg());
}
} catch (Exception e) {
System.out.println("调用遭遇异常,原因:" + e.getMessage());
throw new RuntimeException(e.getMessage(), e);
}
return null;
}
private static CertAlipayRequest getClientParams() {
CertAlipayRequest certParams = new CertAlipayRequest();
certParams.setServerUrl("https://openapi.alipay.com/gateway.do");
//请更换为您的AppId
certParams.setAppId("2021002106644714");
//请更换为您的PKCS8格式的应用私钥
certParams.setPrivateKey("MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC3rgHa/x67gaY08RJoeVWLghAiQooLG/dOojW+639RAuirhxLyeuawbcch291uj/90MPTQy86nNKKQBbet41MQtS8L6ts/5Bjp2GYgzsQlmPCRWE7Il94/6R18fg9ZZQ4rx280BrX60hKTFcM+rn6IuNAiT7wHMcsjonRLsbWW/ZaSmMwqJcfhRU2/8Slznw2AX8jHs3X/ZZtM8usm3Hd41U9m7DIRPgejo4wlgTmUrFJrgQIWdsuSCYm88a4BzFc3Wfa2No5stqkHZizsshx52UGOgvgJdxF6PUqC9af+qQSdldTcbOeQjgQbJOLfiZoPQzyO8DaszIzJkB8FB38DAgMBAAECggEBAIbZ7qzMjtCU3+SQdLZVFlQFGjk85sI/NvL5LkJL/T4Jx65eza9OQd2XyxH1rH1GpQK2CpbceozRnOPl/rNgaRSkILU8KNmgahYM9PXzN5huz3e2AKlOrjH3wNksZ7J2+c90bRUiNCrAXji0SpLTYzyXit8V8PLLQNuZoo4MG0iNCJy8riZwUn8ZQLJnCMv1VD0yUyGSr/6LAEJjJZTrrnpibw/99hqFO8Z6UvIs9JewfvjdzamT3UxF0gURSncieQwvsq3mYlq6ppcWqzBrEqJHZJOGzZrxtsOALmOFr7KCp6qRziareK/9vb9RLnZtBSrLZqhJF/MU1oFWpHixRoECgYEA3yKt0rT2v1rjaOlMQDF7pKKfnGmRHGps9214Smsj/wOwWdlwwixWZA2DUFLOUpPQRu3dPp3ZZQdcg21NejvEbtu4CcN0lrvnVlBIrExQmm9zqjDWijljtNvf+POqMkwyLumtNtdNxWLZxdiDClosShEX9kv4ttdlF5bEc2z3V8ECgYEA0rumR+zUnvT6OS6l6msUXgZ/f/XBgcW8BLdZV6pSJJVh3I9CVgc55MlTTGTd0yNfrDPVbwloDpjVVPSNI9YNL0h9i0vfMTHolWOR7RCcqBoquvt66NjtaV70PjBm1pxNVVDaUSgCva+oOFaRnoHjOSA+jyZkKRHjwnEWlcyRZ8MCgYBnZCtE6gM3cYbUEt35FLSk+ZGZqTTLBOlO0NOfL/vy6yOozl84KdEx9Sz2aBggHUuxwf/1RrD35ixQ3bG7xLvlXjvtkjqQqaqszPCPnaDvnlrq7kxKqgLwR72FHmqrebD7Gd3f/m2T25Tq3sMBZf0FqNwAjP1Gw5GdF4gZr9EAQQKBgQCQrWgxxTUMlOAd1hru3+kxzIBIl67sq5a0HjTmbPbMSwrO5EQE0B09J8NalX198bFDhqqn+utH6kG8e9FSoyiWJ8yZj9OB8OPffGa5PUhwWNaxXOo7ZoNIbnp9H7na6aBmTIY2ZaPMGwcA9t4u1rnrhGmu2gq176RQ4FdDLRk/BQKBgQDU+Oab3jL2MoDMtGk4ZGYQUcTMB/ILtG4O1bx8BhJZ/Rula3Rt7dYPrRng3uZ0sTVh7/QRSn02hLY72UoItge3POZMEbNQLb+gzhIuU4v4hLT3H6WK2MSaLftsb9mPyW9LX76xQS4ayf5xZqeKK2jOtIZCsiLmC/ALvIytcr2DHA==");
//请更换为您使用的字符集编码,推荐采用utf-8
certParams.setCharset("utf-8");
certParams.setFormat("json");
certParams.setSignType("RSA2");
//请更换为您的应用公钥证书文件路径
certParams.setCertPath("/Users/liulipeng/Web/lianghuapai/baa-pay/baa-pay-server/src/main/resources/alipay/appCertPublicKey_2021002106644714.crt");
//请更换您的支付宝公钥证书文件路径
certParams.setAlipayPublicCertPath("/Users/liulipeng/Web/lianghuapai/baa-pay/baa-pay-server/src/main/resources/alipay/alipayCertPublicKey_RSA2.crt");
//更换为支付宝根证书文件路径
certParams.setRootCertPath("/Users/liulipeng/Web/lianghuapai/baa-pay/baa-pay-server/src/main/resources/alipay/alipayRootCert.crt");
return certParams;
}
private static AlipayTradeWapPayRequest getRequestH5() {
// 初始化Request,并填充Model属性。实际调用时请替换为您想要使用的API对应的Request对象。
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo(UUID.randomUUID().toString().replace("-", ""));
model.setProductCode("QUICK_WAP_WAY");
model.setTotalAmount("0.01");
model.setSubject("这是订单标题");
model.setBody("这是订单描述");
request.setBizModel(model);
request.setNotifyUrl("");
request.setReturnUrl("");
return request;
}
private static AlipayTradePagePayRequest getRequestWeb() {
// 初始化Request,并填充Model属性。实际调用时请替换为您想要使用的API对应的Request对象。
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
AlipayTradePagePayModel model = new AlipayTradePagePayModel();
model.setOutTradeNo(UUID.randomUUID().toString().replace("-", ""));
model.setProductCode("FAST_INSTANT_TRADE_PAY");
model.setTotalAmount("0.01");
model.setSubject("这是订单标题");
model.setBody("这是订单描述");
request.setBizModel(model);
request.setNotifyUrl("");
request.setReturnUrl("");
return request;
}
private static AlipayTradeAppPayRequest getRequestApp() {
// 初始化Request,并填充Model属性。实际调用时请替换为您想要使用的API对应的Request对象。
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setOutTradeNo(UUID.randomUUID().toString().replace("-", ""));
model.setProductCode("QUICK_MSECURITY_PAY");
model.setTotalAmount("0.01");
model.setSubject("这是订单标题");
model.setBody("这是订单描述");
request.setBizModel(model);
request.setNotifyUrl("");
request.setReturnUrl("");
return request;
}
}
...@@ -3,10 +3,7 @@ package cn.quant.baa.pay.rest; ...@@ -3,10 +3,7 @@ package cn.quant.baa.pay.rest;
import cn.quant.baa.pay.annotation.BusinessMapping; import cn.quant.baa.pay.annotation.BusinessMapping;
import cn.quant.baa.pay.jpa.entity.PayHistoryEntity; import cn.quant.baa.pay.jpa.entity.PayHistoryEntity;
import cn.quant.baa.pay.model.BusinessRequest; import cn.quant.baa.pay.model.BusinessRequest;
import cn.quant.baa.pay.model.web.CheckPayRequestData; import cn.quant.baa.pay.model.web.*;
import cn.quant.baa.pay.model.web.CheckRefundRequestData;
import cn.quant.baa.pay.model.web.CloseRequestData;
import cn.quant.baa.pay.model.web.PayRequestData;
import cn.quant.baa.pay.service.TransactionService; import cn.quant.baa.pay.service.TransactionService;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -71,5 +68,16 @@ public class TransactionController extends BusinessController { ...@@ -71,5 +68,16 @@ public class TransactionController extends BusinessController {
return res; return res;
} }
@ResponseBody
@BusinessMapping(session = 1)
@PostMapping("/refund")
public JsonNode refund(@RequestBody BusinessRequest<RefundRequestData> request) {
RefundRequestData data = request.getData();
JsonNode res = transactionService.refund(data);
System.currentTimeMillis();
return res;
}
} }
package cn.quant.baa.pay.rest;
import cn.quant.baa.pay.acquirer.AcquirerConfiguration;
import cn.quant.baa.pay.acquirer.AcquirerProperties;
import cn.quant.baa.pay.dict.AccessCode;
import cn.quant.baa.pay.jpa.entity.PayHistoryEntity;
import cn.quant.baa.pay.model.BusinessRequest;
import cn.quant.baa.pay.model.web.PayRequestData;
import cn.quant.baa.pay.service.TransactionService;
import cn.quant.spring.rest.AbstractController;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import sun.misc.BASE64Encoder;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.http.entity.ContentType.APPLICATION_JSON;
/**
* Created with IntelliJ IDEA.
* Author: Lipeng Liu
* Date: 2021/8/31
* Time: 上午10:36
* Description: No Description
*/
@RestController
@RequestMapping("wxpay")
public class WxpayController extends AbstractController {
@Autowired
private TransactionService transactionService;
@Autowired
private AcquirerConfiguration acquirerConfiguration;
String TOKEN_PATTERN = "mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\"";
String SCHEMA = "WECHATPAY2-SHA256-RSA2048 ";
WebClient webClient = WebClient.builder()
.defaultHeader("Accept", "application/json")
.defaultHeader("User-Agent", "QuantGroup Java Api")
.build();
// public HttpEntity buildHttpEntity(String url, String body, String method) {
// String nonceStr = SignTextUtils.randomStr();
// long timestamp = DateUtils.toEpochSecond();
// String canonicalUrl = UriVariables.getCanonicalUrl(url);
// //签名信息
// String signText = StringUtils.joining("\n", method, canonicalUrl, String.valueOf(timestamp), nonceStr, body);
// String sign = wxPayService.createSign(signText, payConfigStorage.getInputCharset());
// String serialNumber = payConfigStorage.getCertEnvironment().getSerialNumber();
// // 生成token
// String token = String.format(WxConst.TOKEN_PATTERN, payConfigStorage.getMchId(), nonceStr, timestamp, serialNumber, sign);
// HttpStringEntity entity = new HttpStringEntity(body, ContentType.APPLICATION_JSON);
// entity.addHeader(new BasicHeader("Authorization", WxConst.SCHEMA.concat(token)));
// entity.addHeader(new BasicHeader("User-Agent", "Pay-Java-Parent"));
// entity.addHeader(new BasicHeader("Accept", APPLICATION_JSON.getMimeType()));
// return entity;
// }
@ResponseBody
@GetMapping("/webClient")
public String webClient() throws Exception {
String chanId = "75772285618946307";
AcquirerProperties profile = acquirerConfiguration.get(Long.valueOf(chanId));
ObjectMapper objectMapper = new ObjectMapper();
String outTradeNo = UUID.randomUUID().toString().replace("-", "");
ObjectNode rootNode = new ObjectMapper().createObjectNode();
rootNode.put("mchid", profile.getPayAcctId())
.put("appid", profile.getPayAppId())
.put("description", "Image形象店-深圳腾大-QQ公仔")
.put("notify_url", "https://www.weixin.qq.com/wxpay/pay.php")
.put("out_trade_no", outTradeNo);
rootNode.putObject("amount")
.put("total", 1);
if (profile.getAccessCode().equals(AccessCode.JS)) {
rootNode.putObject("payer")
.put("openid", "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o");
} else if (profile.getAccessCode().equals(AccessCode.H5)) {
rootNode.putObject("scene_info")
.put("payer_client_ip", "127.0.0.1")
.putObject("h5_info").put("type", "Wap");
}
String body = rootNode.toString();
long timestamp = System.currentTimeMillis() / 1000;
String nonceStr = UUID.randomUUID().toString().replace("-", "");
String signText = joining("\n", "POST", profile.getPayAccess(), String.valueOf(timestamp), nonceStr, body);
String sign = sign(signText, getPrivateKey(profile.getPrivateKey()), profile.getSignType());
String token = String.format(TOKEN_PATTERN, profile.getPayAcctId(), nonceStr, timestamp, profile.getPayCertNo(), sign);
String uri = String.format("%s%s", profile.getDomain(), profile.getPayAccess());
WebClient.RequestBodySpec requestHeadersSpec = webClient.method(HttpMethod.POST).uri(uri)
.header("Authorization", SCHEMA.concat(token))
;
// Mono<String> mono = requestHeadersSpec.bodyValue(rootNode).retrieve().bodyToMono(String.class);
Mono<ClientResponse> mono = requestHeadersSpec.bodyValue(rootNode).exchange();
ClientResponse response = mono.block();
mono.subscribe(System.out::println);
if (response.statusCode() == HttpStatus.OK) {
//当前使用的微信平台证书序列号
String serial = response.headers().asHttpHeaders().getFirst("Wechatpay-Serial");
//微信服务器的时间戳
String wxTimestamp = response.headers().asHttpHeaders().getFirst("Wechatpay-Timestamp");
//微信服务器提供的随机串
String nonce = response.headers().asHttpHeaders().getFirst("Wechatpay-Nonce");
//微信平台签名
String signature = response.headers().asHttpHeaders().getFirst("Wechatpay-Signature");
Mono<String> resultMono = response.bodyToMono(String.class);
//签名信息
String wsSignText = joining("\n", wxTimestamp, nonce, resultMono.block());
X509Certificate x509Certificate = loadCertificate(profile.getPayCertKey());
if (verify(wsSignText, signature, x509Certificate, profile.getSignType())) {
return resultMono.block();
}
throw new Exception("");
}
return "";
}
public static void main(String[] args) {
String str = "{\"alipay_trade_query_response\":{\"code\":\"40004\",\"msg\":\"Business Failed\",\"sub_code\":\"ACQ.TRADE_NOT_EXIST\",\"sub_msg\":\"交易不存在\",\"buyer_pay_amount\":\"0.00\",\"invoice_amount\":\"0.00\",\"out_trade_no\":\"123123123\",\"point_amount\":\"0.00\",\"receipt_amount\":\"0.00\"},\"alipay_cert_sn\":\"dbffe2eea8c336d4bdfece3e78b295f2\",\"sign\":\"HOJvXeUMzuMAAcV2SEtOHC1/8CG2ycbytAQyIoqGwSlKnNIwmGVna2gGWAQskNrufm8nhO5y9oCrC8biwVL2rGdkxTTYCNiSV9uKdGYVZhTutxaKgrJH9VQ5oV5ur24mZQO4rG5xAI6hyExr0vZeDOe7L5Io7xs3YajdcJOvdQVCqdqCyMY7ZDhoptRMxtbpBJwy28KjTRwAEpW687+4Xd2zmCm1HLcFrcO34inMip6jQlkD9a8l5ehjIlidfLGDCRXveIAHJ6RzhfGNdHYauuHP1os66eH3J7IoqJCRsUtNQYoXQWhzR3YzPv8k7l71IOPNrxVuuweM64hGZB27Iw==\"}";
Pattern pattern = Pattern.compile("[a-zA-Z_0-9]*_response"); //去掉空格符合换行符
Matcher matcher = pattern.matcher(str);
String result = matcher.replaceAll("response");
System.out.println(result);
}
@ResponseBody
@GetMapping("/h5")
public String h5() throws Exception {
String chanId = "75772285618946307";
AcquirerProperties profile = acquirerConfiguration.get(Long.valueOf(chanId));
// PayHistoryEntity pay = transactionService.pay(data);
// // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
// AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
// new WechatPay2Credentials(profile.getPayAcctId(), new PrivateKeySigner(certEnvironment.getSerialNumber(), certEnvironment.getPrivateKey())),
// profile.getSecretKey().getBytes("utf-8")
// );
List<X509Certificate> certificates = new ArrayList<>();
X509Certificate x509Certificate = loadCertificate(profile.getPayCertKey());
// PublicKey publicKey = getPublicKey(profile.getPayPublicKey());
certificates.add(x509Certificate);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(profile.getPayAcctId(), profile.getPayCertNo(), getPrivateKey(profile.getPrivateKey()))
.withWechatpay(certificates);
//
// // ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient
// // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
CloseableHttpClient httpClient = builder.build();
// 初始化httpClient
// CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create()
// .withMerchant(profile.getPayAcctId(), certEnvironment.getSerialNumber(), certEnvironment.getPrivateKey())
// .withValidator(new WechatPay2Validator(verifier)).build();
String uri = String.format("%s%s", profile.getDomain(), profile.getPayAccess());
HttpPost httpPost = new HttpPost(uri);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
String outTradeNo = UUID.randomUUID().toString().replace("-", "");
ObjectNode rootNode = objectMapper.createObjectNode();
rootNode.put("mchid", profile.getPayAcctId())
.put("appid", profile.getPayAppId())
.put("description", "Image形象店-深圳腾大-QQ公仔")
.put("notify_url", "https://www.weixin.qq.com/wxpay/pay.php")
.put("out_trade_no", outTradeNo);
rootNode.putObject("amount")
.put("total", 1);
if (profile.getAccessCode().equals(AccessCode.JS)) {
rootNode.putObject("payer")
.put("openid", "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o");
} else if (profile.getAccessCode().equals(AccessCode.H5)) {
rootNode.putObject("scene_info")
.put("payer_client_ip", "127.0.0.1")
.putObject("h5_info").put("type", "Wap");
}
objectMapper.writeValue(bos, rootNode);
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
String bodyAsString = EntityUtils.toString(response.getEntity());
System.out.println(bos.toString("UTF-8"));
response.close();
httpClient.close();
if (profile.getAccessCode().equals(AccessCode.H5)) {
return "<html><head><meta name=\"referrer\" content=\"always\"></dead><body>"
+ "订单号:" + outTradeNo + "<br />"
+ "<a href=\"" + JSON.parseObject(bodyAsString).getString("h5_url") + "\">去支付</a></body>";
}
return bodyAsString;
}
@ResponseBody
@PostMapping("/app")
public String app(@RequestBody BusinessRequest<PayRequestData> request) throws Exception {
PayRequestData data = request.getData();
String chanId = data.getChanId();
AcquirerProperties profile = acquirerConfiguration.get(Long.valueOf(chanId));
// PayHistoryEntity pay = transactionService.pay(data);
FileInputStream inputStream = new FileInputStream("/Users/liulipeng/Web/lianghuapai/baa-pay/baa-pay-server/src/main/resources/wxpay/apiclient_cert_1604055791.p12");
String keyAlias = "Tenpay Certificate";
CertEnvironment certEnvironment = initCertification(inputStream, keyAlias, profile.getPayAcctId());
// // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(profile.getPayAcctId(), new PrivateKeySigner(certEnvironment.getSerialNumber(), certEnvironment.getPrivateKey())),
profile.getSecretKey().getBytes("utf-8")
);
// List<X509Certificate> certificates = new ArrayList<>();
// X509Certificate certificate = getCertificate("/Users/liulipeng/Web/lianghuapai/baa-pay/baa-pay-server/src/main/resources/wxpay/apiclient_cert.p12");
// certificates.add(certificate);
// WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
// .withMerchant(profile.getPayAcctId(), certEnvironment.getSerialNumber(), certEnvironment.getPrivateKey())
// .withWechatpay(certificates);
//
// // ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient
// // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
// CloseableHttpClient httpClient = builder.build();
// 初始化httpClient
CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create()
.withMerchant(profile.getPayAcctId(), certEnvironment.getSerialNumber(), certEnvironment.getPrivateKey())
.withValidator(new WechatPay2Validator(verifier)).build();
String uri = String.format("%s%s", profile.getDomain(), profile.getPayAccess());
HttpPost httpPost = new HttpPost(uri);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
String outTradeNo = UUID.randomUUID().toString().replace("-", "");
ObjectNode rootNode = objectMapper.createObjectNode();
rootNode.put("mchid", profile.getPayAcctId())
.put("appid", profile.getPayAppId())
.put("description", "Image形象店-深圳腾大-QQ公仔")
.put("notify_url", "https://www.weixin.qq.com/wxpay/pay.php")
.put("out_trade_no", outTradeNo);
rootNode.putObject("amount")
.put("total", 1);
if (profile.getAccessCode().equals(AccessCode.JS)) {
rootNode.putObject("payer")
.put("openid", "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o");
} else if (profile.getAccessCode().equals(AccessCode.H5)) {
rootNode.putObject("scene_info")
.put("payer_client_ip", "127.0.0.1")
.putObject("h5_info").put("type", "Wap");
}
objectMapper.writeValue(bos, rootNode);
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
String bodyAsString = EntityUtils.toString(response.getEntity());
System.out.println(bos.toString("UTF-8"));
response.close();
httpClient.close();
if (profile.getAccessCode().equals(AccessCode.H5)) {
return "<html><head><meta name=\"referrer\" content=\"always\"></dead><body><a href=\"" + JSON.parseObject(bodyAsString).getString("h5_url") + "\"></a></body>";
}
return bodyAsString;
}
/**
* 获取公私钥.
*
* @param keyCertStream 商户API证书
* @param keyAlias 证书别名
* @param keyPass 证书对应的密码
* @return 证书信息集合
*/
public static CertEnvironment initCertification(InputStream keyCertStream, String keyAlias, String keyPass) {
char[] pem = keyPass.toCharArray();
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(keyCertStream, pem);
X509Certificate certificate = (X509Certificate) keyStore.getCertificate(keyAlias);
certificate.checkValidity();
String serialNumber = certificate.getSerialNumber().toString(16).toUpperCase();
PublicKey publicKey = certificate.getPublicKey();
PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, pem);
BASE64Encoder base64Encoder = new BASE64Encoder();
String privateKeyString = base64Encoder.encode(privateKey.getEncoded());
String publicKeyString = base64Encoder.encode(publicKey.getEncoded());
System.out.println(publicKeyString);
return new CertEnvironment(privateKey, publicKey, serialNumber);
} catch (GeneralSecurityException e) {
// throw new PayErrorException(new WxPayError(WxConst.FAILURE, "获取公私钥失败"), e);
} catch (IOException e) {
// throw new PayErrorException(new WxPayError(WxConst.FAILURE, "私钥证书流加载失败"), e);
}
return null;
}
/**
* 字符串数组拼接为字符串
*
* @param separator 分隔符
* @param str 字符数组
* @return 字符串
*/
public static String joining(String separator, String... str) {
StringBuilder builder = new StringBuilder();
for (String s : str) {
if (s == null || s.length() == 0) {
continue;
}
builder.append(s).append(separator);
}
return builder.toString();
}
/**
* RSA验签名检查
*
* @param content 待签名数据
* @param signature 签名值
* @param signAlgorithms 签名算法
* @return 布尔值
*/
public static boolean verify(String content, String signature, X509Certificate certificate, String signAlgorithms) {
try {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initVerify(certificate);
sign.update(content.getBytes());
return sign.verify(Base64.getDecoder().decode(signature));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
} catch (SignatureException e) {
throw new RuntimeException("签名验证过程发生了错误", e);
} catch (InvalidKeyException e) {
throw new RuntimeException("无效的证书", e);
}
}
public static String sign(String content, PrivateKey privateKey, String signAlgorithms) {
try {
java.security.Signature signature = java.security.Signature.getInstance(signAlgorithms);
signature.initSign(privateKey);
signature.update(content.getBytes());
byte[] signed = signature.sign();
return Base64.getEncoder().encodeToString(signed);
}
catch (GeneralSecurityException e) {
}
return null;
}
/**
* 获取证书。
*
* @param certString 证书内容
* @return X509证书
*/
public static X509Certificate loadCertificate(String certString) {
try {
ByteArrayInputStream fis = new ByteArrayInputStream(certString.getBytes());
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(fis);
cert.checkValidity();
return cert;
} catch (CertificateExpiredException var3) {
throw new RuntimeException("证书已过期", var3);
} catch (CertificateNotYetValidException var4) {
throw new RuntimeException("证书尚未生效", var4);
} catch (CertificateException var5) {
throw new RuntimeException("无效的证书", var5);
}
}
/**
* 获取私钥。
*
* @param certString 公钥文件内容(required)
* @return 私钥对象
*/
public static PublicKey getPublicKey(String certString) throws IOException {
try {
String publicKey = certString
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(
new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("无效的密钥格式");
}
}
/**
* 获取私钥。
*
* @param certString 私钥文件内容(required)
* @return 私钥对象
*/
public static PrivateKey getPrivateKey(String certString) throws IOException {
try {
String privateKey = certString
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("无效的密钥格式");
}
}
}
class CertEnvironment {
/**
* 存放私钥
*/
private PrivateKey privateKey;
/**
* 存放公钥
*/
private PublicKey publicKey;
/**
* 公钥序列
*/
private String serialNumber;
public CertEnvironment() {
}
public CertEnvironment(PrivateKey privateKey, PublicKey publicKey, String serialNumber) {
this.privateKey = privateKey;
this.publicKey = publicKey;
this.serialNumber = serialNumber;
}
public PrivateKey getPrivateKey() {
return privateKey;
}
public void setPrivateKey(PrivateKey privateKey) {
this.privateKey = privateKey;
}
public PublicKey getPublicKey() {
return publicKey;
}
public void setPublicKey(PublicKey publicKey) {
this.publicKey = publicKey;
}
public String getSerialNumber() {
return serialNumber;
}
public void setSerialNumber(String serialNumber) {
this.serialNumber = serialNumber;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment