优化微信支付和支付宝支付的配置文件的结构

This commit is contained in:
Dftre 2024-06-05 02:32:59 +08:00
parent 1c5b40771d
commit bbceb171eb
5 changed files with 180 additions and 94 deletions

View File

@ -58,7 +58,7 @@ public class AliPayConfig {
}
@Bean
protected Config config() throws Exception {
protected Config alipayBaseConfig() throws Exception {
// 设置参数全局只需设置一次
Config config = new Config();
config.protocol = "https";

View File

@ -64,7 +64,6 @@ public class AliPayController {
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
// System.out.println(name + " = " + request.getParameter(name));
}
String orderNumber = params.get("out_trade_no");

View File

@ -25,10 +25,10 @@ import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
public class HttpUtil {
public static String httpPostWithoutException(String url, String string,String sign,String sn) {
public static String httpPostWithoutException(String url, String string, String sign, String sn) {
String xmlRes = "{}";
try {
xmlRes = httpPost(url, string,sign,sn);
xmlRes = httpPost(url, string, sign, sn);
} catch (UnrecoverableKeyException e) {
} catch (NoSuchAlgorithmException e) {
@ -40,36 +40,33 @@ public class HttpUtil {
}
return xmlRes;
}
/**
* http POST 请求
*
* @param url:请求地址
* @param body: body实体字符串
* @param sign:签名
* @param sn: 序列号
* @return
*/
public static String httpPost(String url, String body,String sign,String sn) throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
public static String httpPost(String url, String body, String sign, String sn)
throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
String xmlRes = "{}";
HttpClient client = createSSLClientDefault();
HttpPost httpost = new HttpPost(url);
try {
System.out.println("Request string: " + body);
//所有请求的body都需采用UTF-8编码
StringEntity entity = new StringEntity(body,"UTF-8");//
// 所有请求的body都需采用UTF-8编码
StringEntity entity = new StringEntity(body, "UTF-8");//
entity.setContentType("application/json");
httpost.setEntity(entity);
//支付平台所有的API仅支持JSON格式的请求调用HTTP请求头Content-Type设为application/json
httpost.addHeader("Content-Type","application/json");
//支付平台所有的API调用都需要签名验证,签名首部: Authorization: sn + " " + sign
httpost.addHeader("Authorization",sn + " " + sign);
System.out.println("Authorization" + sn + " " + sign);
// 支付平台所有的API仅支持JSON格式的请求调用HTTP请求头Content-Type设为application/json
httpost.addHeader("Content-Type", "application/json");
// 支付平台所有的API调用都需要签名验证,签名首部: Authorization: sn + " " + sign
httpost.addHeader("Authorization", sn + " " + sign);
HttpResponse response = client.execute(httpost);
//所有响应也采用UTF-8编码
// 所有响应也采用UTF-8编码
xmlRes = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println("Response string: " + xmlRes);
} catch (ClientProtocolException e) {
} catch (IOException e) {
@ -81,7 +78,7 @@ public class HttpUtil {
public static CloseableHttpClient createSSLClientDefault() {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
//信任所有
// 信任所有
public boolean isTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
return true;
@ -99,23 +96,20 @@ public class HttpUtil {
return HttpClients.createDefault();
}
public static String doGet(String url,String parameter)
{
String uriAPI =url+"?"+parameter ; //"http://XX?str=I+am+get+String";
String result= "";
public static String doGet(String url, String parameter) {
String uriAPI = url + "?" + parameter; // "http://XX?str=I+am+get+String";
String result = "";
HttpClient client = createSSLClientDefault();
HttpGet httpRequst = new HttpGet(uriAPI);
try {
HttpResponse httpResponse = client.execute(httpRequst);//其中HttpGet是HttpUriRequst的子类
if(httpResponse.getStatusLine().getStatusCode() == 200)
{
HttpResponse httpResponse = client.execute(httpRequst);// 其中HttpGet是HttpUriRequst的子类
if (httpResponse.getStatusLine().getStatusCode() == 200) {
HttpEntity httpEntity = httpResponse.getEntity();
result = EntityUtils.toString(httpEntity);//取出应答字符串
result = EntityUtils.toString(httpEntity);// 取出应答字符串
// 一般来说都要删除多余的字符
result.replaceAll("\r", "");//去掉返回结果中的"\r"字符否则会在结果字符串后面显示一个小方格
}
else
result.replaceAll("\r", "");// 去掉返回结果中的"\r"字符否则会在结果字符串后面显示一个小方格
} else
httpRequst.abort();
} catch (ClientProtocolException e) {
e.printStackTrace();

View File

@ -1,17 +1,27 @@
package com.ruoyi.pay.wx.config;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import lombok.Data;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
/**
* 配置我们自己的信息
*
* @author ZlH
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "wechat")
public class WxPayAppConfig {
@ -20,6 +30,7 @@ public class WxPayAppConfig {
private String wxchantId;
@Value("${pay.wechat.merchantSerialNumber}")
private String wxchantSerialNumber;
@Value("${pay.wechat.apiV3Key}")
private String wxapiV3Key;
@Value("${pay.wechat.privateKeyPath}")
@ -29,4 +40,81 @@ public class WxPayAppConfig {
@Value("${pay.wechat.notifyUrl}")
private String notifyUrl;
@Bean
public RSAAutoCertificateConfig wxpayBaseConfig() throws Exception {
return new RSAAutoCertificateConfig.Builder()
.merchantId(getWxchantId())
.privateKeyFromPath(getWxcertPath())
.merchantSerialNumber(getWxchantSerialNumber())
.apiV3Key(getWxapiV3Key())
.build();
}
@Bean
public NativePayService nativePayService() throws Exception {
return new NativePayService.Builder().config(wxpayBaseConfig()).build();
}
@Bean
public NotificationParser notificationParser() throws Exception {
return new NotificationParser(wxpayBaseConfig());
}
@Autowired
private ApplicationContext applicationContext;
public String getWxcertPath() throws Exception {
if (wxcertPath.startsWith("classpath:")) {
Resource resource = applicationContext.getResource(wxcertPath);
String tempFilePath = System.getProperty("java.io.tmpdir") + "/temp_wxcert.pem";
try (InputStream inputStream = resource.getInputStream()) {
Files.copy(inputStream, Paths.get(tempFilePath), StandardCopyOption.REPLACE_EXISTING);
wxcertPath = tempFilePath;
} catch (Exception e) {
Files.deleteIfExists(Paths.get(tempFilePath));
throw new RuntimeException("微信支付证书文件读取失败", e);
}
}
return wxcertPath;
}
public String getWxchantId() {
return wxchantId;
}
public void setWxchantId(String wxchantId) {
this.wxchantId = wxchantId;
}
public String getWxchantSerialNumber() {
return wxchantSerialNumber;
}
public void setWxchantSerialNumber(String wxchantSerialNumber) {
this.wxchantSerialNumber = wxchantSerialNumber;
}
public String getWxapiV3Key() {
return wxapiV3Key;
}
public void setWxapiV3Key(String wxapiV3Key) {
this.wxapiV3Key = wxapiV3Key;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
}

View File

@ -1,8 +1,13 @@
package com.ruoyi.pay.wx.controller;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -12,18 +17,26 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.pay.domain.PayOrder;
import com.ruoyi.pay.service.IPayOrderService;
import com.ruoyi.pay.wx.config.WxPayAppConfig;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import com.wechat.pay.java.service.wexinpayscoreparking.model.Transaction;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
/**
* @author zlh
*/
@Slf4j
@RestController
@RequestMapping("/wxPay")
public class WxAppPayController extends BaseController {
@ -31,22 +44,18 @@ public class WxAppPayController extends BaseController {
private WxPayAppConfig wxPayAppConfig;
@Autowired
private IPayOrderService payOrderService;
@Anonymous
@Autowired
private NativePayService nativePayService;
@Autowired
private NotificationParser notificationParser;
@Operation(summary = "微信支付")
@Parameters({
@Parameter(name = "orderNumber", description = "订单号", required = true)
})
@GetMapping("/pay/{orderNumber}")
public AjaxResult pay(@PathVariable String orderNumber) {
// 使用自动更新平台证书的RSA配置
// 一个商户号只能初始化一个配置否则会因为重复的下载任务报错
Config config =
new RSAAutoCertificateConfig.Builder()
.merchantId(wxPayAppConfig.getWxchantId())
.privateKeyFromPath(wxPayAppConfig.getWxcertPath())
.merchantSerialNumber(wxPayAppConfig.getWxchantSerialNumber())
.apiV3Key(wxPayAppConfig.getWxapiV3Key())
.build();
// 构建service
NativePayService service = new NativePayService.Builder().config(config).build();
// request.setXxx(val)设置所需参数具体参数可见Request定义
public AjaxResult pay(@PathVariable String orderNumber) throws Exception {
PayOrder aliPay = payOrderService.selectPayOrderByOrderNumber(orderNumber);
String amountStr = aliPay.getTotalAmount();
double amountDouble = Double.parseDouble(amountStr);
@ -60,48 +69,44 @@ public class WxAppPayController extends BaseController {
request.setDescription(aliPay.getOrderContent());
request.setNotifyUrl(wxPayAppConfig.getNotifyUrl());
request.setOutTradeNo(aliPay.getOrderNumber());
// 调用下单方法得到应答
PrepayResponse response = service.prepay(request);
// 使用微信扫描 code_url 对应的二维码即可体验Native支付
PrepayResponse response = nativePayService.prepay(request);
return AjaxResult.success(response.getCodeUrl());
}
// @Anonymous
// @Operation(summary = "微信支付查询订单")
// @GetMapping("/notify")
// public AjaxResult WxPayList() {
// System.out.println("=========支付宝异步回调========");
// // 构造 RequestParam
// RequestParam requestParam = new RequestParam.Builder()
// .serialNumber("wechatPaySerial")
// .nonce("wechatpayNonce")
// .signature("wechatSignature")
// .timestamp("wechatTimestamp")
// .body("requestBody")
// .build();
//
//// 如果已经初始化了 RSAAutoCertificateConfig可直接使用
//// 没有的话则构造一个
// NotificationConfig config = new RSAAutoCertificateConfig.Builder()
// .merchantId(merchantId)
// .privateKeyFromPath(privateKeyPath)
// .merchantSerialNumber(merchantSerialNumber)
// .apiV3Key(apiV3Key)
// .build();
//
//// 初始化 NotificationParser
// NotificationParser parser = new NotificationParser(config);
//
// try {
// // 以支付通知回调为例验签解密并转换成 Transaction
// Transaction transaction = parser.parse(requestParam, Transaction.class);
// } catch (ValidationException e) {
// // 签名验证失败返回 401 UNAUTHORIZED 状态码
// logger.error("sign verification failed", e);
// return AjaxResult.success(HttpStatus.UNAUTHORIZED);
// }
//// 处理成功返回 200 OK 状态码
// return AjaxResult.success(HttpStatus.OK);
// }
@Anonymous
@Operation(summary = "微信支付查询订单")
@PostMapping("/notify")
public AjaxResult WxPayList(HttpServletRequest servletRequest, HttpServletResponse response)
throws Exception {
log.info("=========微信异步回调========");
String timeStamp = servletRequest.getHeader("Wechatpay-Timestamp");
String nonce = servletRequest.getHeader("Wechatpay-Nonce");
String signature = servletRequest.getHeader("Wechatpay-Signature");
String certSn = servletRequest.getHeader("Wechatpay-Serial");
try {
String requestBody = StreamUtils.copyToString(servletRequest.getInputStream(), StandardCharsets.UTF_8);
RequestParam requestParam = new RequestParam.Builder()
.serialNumber(certSn)
.nonce(nonce)
.signature(signature)
.timestamp(timeStamp)
.body(requestBody)
.build();
try {
Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
String orderNumber = transaction.getOutTradeNo();
payOrderService.updateStatus(orderNumber, "已支付");
return success();
} catch (ValidationException e) {
return error();
}
} catch (IOException e) {
log.error("Error reading request body", e);
throw new RuntimeException("Error reading request body", e);
}
}
}