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

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 @Bean
protected Config config() throws Exception { protected Config alipayBaseConfig() throws Exception {
// 设置参数全局只需设置一次 // 设置参数全局只需设置一次
Config config = new Config(); Config config = new Config();
config.protocol = "https"; config.protocol = "https";

View File

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

View File

@ -1,25 +1,36 @@
package com.ruoyi.pay.wx.config; 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.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties; 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.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 * @author ZlH
*/ */
@Data
@Configuration @Configuration
@ConfigurationProperties(prefix = "wechat") @ConfigurationProperties(prefix = "wechat")
public class WxPayAppConfig { public class WxPayAppConfig {
@Value("${pay.wechat.merchantId}") @Value("${pay.wechat.merchantId}")
private String wxchantId; private String wxchantId;
@Value("${pay.wechat.merchantSerialNumber}") @Value("${pay.wechat.merchantSerialNumber}")
private String wxchantSerialNumber; private String wxchantSerialNumber;
@Value("${pay.wechat.apiV3Key}") @Value("${pay.wechat.apiV3Key}")
private String wxapiV3Key; private String wxapiV3Key;
@Value("${pay.wechat.privateKeyPath}") @Value("${pay.wechat.privateKeyPath}")
@ -29,4 +40,81 @@ public class WxPayAppConfig {
@Value("${pay.wechat.notifyUrl}") @Value("${pay.wechat.notifyUrl}")
private String 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; 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.beans.factory.annotation.Autowired;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; 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.RequestMapping;
import org.springframework.web.bind.annotation.RestController; 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.domain.PayOrder;
import com.ruoyi.pay.service.IPayOrderService; import com.ruoyi.pay.service.IPayOrderService;
import com.ruoyi.pay.wx.config.WxPayAppConfig; import com.ruoyi.pay.wx.config.WxPayAppConfig;
import com.wechat.pay.java.core.Config; import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.RSAAutoCertificateConfig; 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.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount; 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.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse; 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.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 * @author zlh
*/ */
@Slf4j
@RestController @RestController
@RequestMapping("/wxPay") @RequestMapping("/wxPay")
public class WxAppPayController extends BaseController { public class WxAppPayController extends BaseController {
@ -31,22 +44,18 @@ public class WxAppPayController extends BaseController {
private WxPayAppConfig wxPayAppConfig; private WxPayAppConfig wxPayAppConfig;
@Autowired @Autowired
private IPayOrderService payOrderService; private IPayOrderService payOrderService;
@Anonymous
@Autowired
private NativePayService nativePayService;
@Autowired
private NotificationParser notificationParser;
@Operation(summary = "微信支付") @Operation(summary = "微信支付")
@Parameters({
@Parameter(name = "orderNumber", description = "订单号", required = true)
})
@GetMapping("/pay/{orderNumber}") @GetMapping("/pay/{orderNumber}")
public AjaxResult pay(@PathVariable String orderNumber) { public AjaxResult pay(@PathVariable String orderNumber) throws Exception {
// 使用自动更新平台证书的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定义
PayOrder aliPay = payOrderService.selectPayOrderByOrderNumber(orderNumber); PayOrder aliPay = payOrderService.selectPayOrderByOrderNumber(orderNumber);
String amountStr = aliPay.getTotalAmount(); String amountStr = aliPay.getTotalAmount();
double amountDouble = Double.parseDouble(amountStr); double amountDouble = Double.parseDouble(amountStr);
@ -60,48 +69,44 @@ public class WxAppPayController extends BaseController {
request.setDescription(aliPay.getOrderContent()); request.setDescription(aliPay.getOrderContent());
request.setNotifyUrl(wxPayAppConfig.getNotifyUrl()); request.setNotifyUrl(wxPayAppConfig.getNotifyUrl());
request.setOutTradeNo(aliPay.getOrderNumber()); request.setOutTradeNo(aliPay.getOrderNumber());
// 调用下单方法得到应答 PrepayResponse response = nativePayService.prepay(request);
PrepayResponse response = service.prepay(request);
// 使用微信扫描 code_url 对应的二维码即可体验Native支付
return AjaxResult.success(response.getCodeUrl()); return AjaxResult.success(response.getCodeUrl());
} }
// @Anonymous @Anonymous
// @Operation(summary = "微信支付查询订单") @Operation(summary = "微信支付查询订单")
// @GetMapping("/notify") @PostMapping("/notify")
// public AjaxResult WxPayList() { public AjaxResult WxPayList(HttpServletRequest servletRequest, HttpServletResponse response)
// System.out.println("=========支付宝异步回调========"); throws Exception {
// // 构造 RequestParam log.info("=========微信异步回调========");
// RequestParam requestParam = new RequestParam.Builder()
// .serialNumber("wechatPaySerial") String timeStamp = servletRequest.getHeader("Wechatpay-Timestamp");
// .nonce("wechatpayNonce") String nonce = servletRequest.getHeader("Wechatpay-Nonce");
// .signature("wechatSignature") String signature = servletRequest.getHeader("Wechatpay-Signature");
// .timestamp("wechatTimestamp") String certSn = servletRequest.getHeader("Wechatpay-Serial");
// .body("requestBody")
// .build(); try {
// String requestBody = StreamUtils.copyToString(servletRequest.getInputStream(), StandardCharsets.UTF_8);
//// 如果已经初始化了 RSAAutoCertificateConfig可直接使用 RequestParam requestParam = new RequestParam.Builder()
//// 没有的话则构造一个 .serialNumber(certSn)
// NotificationConfig config = new RSAAutoCertificateConfig.Builder() .nonce(nonce)
// .merchantId(merchantId) .signature(signature)
// .privateKeyFromPath(privateKeyPath) .timestamp(timeStamp)
// .merchantSerialNumber(merchantSerialNumber) .body(requestBody)
// .apiV3Key(apiV3Key) .build();
// .build();
// try {
//// 初始化 NotificationParser Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
// NotificationParser parser = new NotificationParser(config); String orderNumber = transaction.getOutTradeNo();
// payOrderService.updateStatus(orderNumber, "已支付");
// try { return success();
// // 以支付通知回调为例验签解密并转换成 Transaction } catch (ValidationException e) {
// Transaction transaction = parser.parse(requestParam, Transaction.class); return error();
// } catch (ValidationException e) { }
// // 签名验证失败返回 401 UNAUTHORIZED 状态码 } catch (IOException e) {
// logger.error("sign verification failed", e); log.error("Error reading request body", e);
// return AjaxResult.success(HttpStatus.UNAUTHORIZED); throw new RuntimeException("Error reading request body", e);
// } }
//// 处理成功返回 200 OK 状态码 }
// return AjaxResult.success(HttpStatus.OK);
// }
} }