支付模块整理

This commit is contained in:
Dftre 2025-03-09 23:07:08 +08:00
parent d9c06d9bf1
commit 8b777e1913
10 changed files with 213 additions and 130 deletions

View File

@ -1,19 +1,13 @@
package com.ruoyi.pay.alipay.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.transaction.annotation.Transactional;
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;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
@ -26,6 +20,7 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
* @author zlh
@ -37,11 +32,11 @@ import jakarta.servlet.http.HttpServletRequest;
public class AliPayController extends BaseController {
@Autowired
private IPayOrderService payOrderService;
@Autowired(required = false)
private IAliPayService aliPayService;
@Autowired
private IPayOrderService payOrderService;
@Anonymous
@Operation(summary = "支付宝支付")
@Parameters({
@ -49,45 +44,15 @@ public class AliPayController extends BaseController {
})
@GetMapping("/url/{orderNumber}")
public AjaxResult pay(@PathVariable(name = "orderNumber") String orderNumber) {
AlipayTradePagePayResponse response;
PayOrder aliPay = payOrderService.selectPayOrderByOrderNumber(orderNumber);
try {
// 发起API调用以创建当面付收款二维码为例
response = Factory.Payment.Page().pay(
aliPay.getOrderContent(),
aliPay.getOrderNumber(),
aliPay.getActualAmount(),
"");
} catch (Exception e) {
return error(e.getMessage());
}
return success(response.getBody());
return success(aliPayService.payUrl(aliPay));
}
@Anonymous
@Operation(summary = "支付宝支付回调")
@Transactional
@PostMapping("/notify")
public AjaxResult notify(HttpServletRequest request) throws Exception {
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}
String orderNumber = params.get("out_trade_no");
// 支付宝验签
if (Factory.Payment.Common().verifyNotify(params)) {
// // 更新订单未已支付
payOrderService.updateStatus(orderNumber, "已支付");
if (aliPayService != null) {
aliPayService.callback(params);
}
}
}
public AjaxResult notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
aliPayService.notify(request, response);
return success("success");
}
}

View File

@ -2,6 +2,8 @@ package com.ruoyi.pay.alipay.service;
import java.util.Map;
public interface IAliPayService {
import com.ruoyi.pay.service.PayService;
public interface IAliPayService extends PayService {
public void callback(Map<String, String> params);
}

View File

@ -0,0 +1,60 @@
package com.ruoyi.pay.alipay.service.Impl;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.pay.alipay.service.IAliPayService;
import com.ruoyi.pay.domain.PayOrder;
import com.ruoyi.pay.service.IPayOrderService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@Service
public class AliPayService implements IAliPayService {
public void callback(Map<String, String> params) {
}
@Autowired
private IPayOrderService payOrderService;
public String payUrl(PayOrder payOrder) {
try {
AlipayTradePagePayResponse response = Factory.Payment.Page().pay(
payOrder.getOrderContent(),
payOrder.getOrderNumber(),
payOrder.getActualAmount(),
"");
return response.getBody();
} catch (Exception e) {
throw new ServiceException("创建支付宝支付URL失败");
}
}
@Override
public void notify(HttpServletRequest request, HttpServletResponse response) {
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}
String orderNumber = params.get("out_trade_no");
try {
if (Factory.Payment.Common().verifyNotify(params)) {
payOrderService.updateStatus(orderNumber, "已支付");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,12 @@
package com.ruoyi.pay.service;
import com.ruoyi.pay.domain.PayOrder;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public interface PayService {
String payUrl(PayOrder payOrder);
void notify(HttpServletRequest servletRequest, HttpServletResponse response);
}

View File

@ -78,9 +78,6 @@ public class SQBController extends BaseController {
// 验签
// 修改订单状态
// 用户自定义行为
if (sqbPayService != null) {
sqbPayService.callback(jsonObject);
}
return AjaxResult.success();
}

View File

@ -1,7 +1,6 @@
package com.ruoyi.pay.sqb.service;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.pay.service.PayService;
public interface ISqbPayService {
public void callback(JSONObject param);
public interface ISqbPayService extends PayService {
}

View File

@ -15,16 +15,21 @@ import org.springframework.stereotype.Service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.http.HttpClientUtil;
import com.ruoyi.common.utils.sign.Md5Utils;
import com.ruoyi.pay.domain.PayOrder;
import com.ruoyi.pay.sqb.config.SqbConfig;
import com.ruoyi.pay.sqb.service.ISqbPayService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@Service
@ConditionalOnProperty(prefix = "pay.sqb", name = "enabled", havingValue = "true")
public class SQBServiceImpl {
public class SQBServiceImpl implements ISqbPayService {
@Autowired
private SqbConfig sqbConfig;
@ -115,12 +120,12 @@ public class SQBServiceImpl {
String result = httpPost(url, params.toString(), sign, sqbConfig.getTerminalSn());
JSONObject retObj = JSON.parseObject(result);
String resCode = retObj.get("result_code").toString();
if (!"200".equals(resCode)){
if (!"200".equals(resCode)) {
return null;
}
String responseStr = retObj.get("biz_response").toString();
JSONObject terminal = JSON.parseObject(responseStr);
if (terminal.get("terminal_sn") == null || terminal.get("terminal_key") == null){
if (terminal.get("terminal_sn") == null || terminal.get("terminal_key") == null) {
return null;
}
return terminal;
@ -170,7 +175,7 @@ public class SQBServiceImpl {
String result = httpPost(url, params, sign, sqbConfig.getTerminalSn());
JSONObject retObj = JSON.parseObject(result);
String resCode = retObj.get("result_code").toString();
if (!"200".equals(resCode)){
if (!"200".equals(resCode)) {
return null;
}
String responseStr = retObj.get("biz_response").toString();
@ -180,11 +185,12 @@ public class SQBServiceImpl {
}
}
public String payUrl(PayOrder payOrder) throws UnsupportedEncodingException {
@Override
public String payUrl(PayOrder payOrder) {
return payUrl(payOrder, null);
}
public String payUrl(PayOrder payOrder, String notifyBaseUrl) throws UnsupportedEncodingException {
public String payUrl(PayOrder payOrder, String notifyBaseUrl) {
if (payOrder.getRemark() == null) {
payOrder.setRemark("支付");
}
@ -201,6 +207,7 @@ public class SQBServiceImpl {
orderNotifyUrl = "http://" + ServletUtils.getRequest().getServerName() + proxyPath + defaultNotifyUrl;
}
}
String param = "" +
"client_sn=" + payOrder.getOrderNumber() +
"&notify_url=" + orderNotifyUrl +
@ -209,16 +216,22 @@ public class SQBServiceImpl {
"&subject=" + payOrder.getRemark() +
"&terminal_sn=" + sqbConfig.getTerminalSn() +
"&total_amount=" + Long.valueOf(payOrder.getTotalAmount().toString());
String urlParam = "" +
"client_sn=" + payOrder.getOrderNumber() +
"&notify_url=" + URLEncoder.encode(orderNotifyUrl, "UTF-8") +
"&operator=" + URLEncoder.encode(payOrder.getCreateBy(), "UTF-8") +
"&return_url=" + "https://www.shouqianba.com/" +
"&subject=" + URLEncoder.encode(payOrder.getRemark(), "UTF-8") +
"&terminal_sn=" + sqbConfig.getTerminalSn() +
"&total_amount=" + Long.valueOf(payOrder.getTotalAmount().toString());
String sign = getSign(param + "&key=" + sqbConfig.getTerminalKey());
return "https://qr.shouqianba.com/gateway?" + urlParam + "&sign=" + sign.toUpperCase();
String urlParam;
try {
urlParam = "" +
"client_sn=" + payOrder.getOrderNumber() +
"&notify_url=" + URLEncoder.encode(orderNotifyUrl, "UTF-8") +
"&operator=" + URLEncoder.encode(payOrder.getCreateBy(), "UTF-8") +
"&return_url=" + "https://www.shouqianba.com/" +
"&subject=" + URLEncoder.encode(payOrder.getRemark(), "UTF-8") +
"&terminal_sn=" + sqbConfig.getTerminalSn() +
"&total_amount=" + Long.valueOf(payOrder.getTotalAmount().toString());
String sign = getSign(param + "&key=" + sqbConfig.getTerminalKey());
return "https://qr.shouqianba.com/gateway?" + urlParam + "&sign=" + sign.toUpperCase();
} catch (Exception e) {
throw new ServiceException("生成收钱吧支付链接失败");
}
}
/**
@ -268,4 +281,10 @@ public class SQBServiceImpl {
}
}
@Override
public void notify(HttpServletRequest servletRequest, HttpServletResponse response) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'notify'");
}
}

View File

@ -1,11 +1,7 @@
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.boot.autoconfigure.condition.ConditionalOnProperty;
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;
@ -15,19 +11,9 @@ import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.pay.domain.PayOrder;
import com.ruoyi.pay.service.IPayOrderService;
import com.ruoyi.pay.wx.config.WxPayConfig;
import com.ruoyi.pay.wx.service.IWxPayService;
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;
@ -42,72 +28,29 @@ import jakarta.servlet.http.HttpServletResponse;
@ConditionalOnProperty(prefix = "pay.wechat", name = "enabled", havingValue = "true")
@RequestMapping("/pay/wechat")
public class WxPayController extends BaseController {
@Autowired
private WxPayConfig wxPayAppConfig;
@Autowired(required = false)
@Autowired
private IWxPayService wxPayService;
@Autowired
private IPayOrderService payOrderService;
@Autowired
private NativePayService nativePayService;
@Autowired
private NotificationParser notificationParser;
@Operation(summary = "微信支付")
@Parameters({
@Parameter(name = "orderNumber", description = "订单号", required = true)
})
@GetMapping("/url/{orderNumber}")
public R<String> url(@PathVariable(name = "orderNumber") String orderNumber) throws Exception {
PayOrder aliPay = payOrderService.selectPayOrderByOrderNumber(orderNumber);
PrepayRequest request = new PrepayRequest();
Amount amount = new Amount();
amount.setTotal(Integer.parseInt(aliPay.getActualAmount()));
request.setAmount(amount);
request.setAppid(wxPayAppConfig.getAppId());
request.setMchid(wxPayAppConfig.getWxchantId());
request.setDescription(aliPay.getOrderContent());
request.setNotifyUrl(wxPayAppConfig.getNotifyUrl());
request.setOutTradeNo(aliPay.getOrderNumber());
PrepayResponse response = nativePayService.prepay(request);
return R.ok(response.getCodeUrl());
public AjaxResult url(@PathVariable(name = "orderNumber") String orderNumber) throws Exception {
PayOrder payOrder = payOrderService.selectPayOrderByOrderNumber(orderNumber);
return success(wxPayService.payUrl(payOrder));
}
@Anonymous
@Operation(summary = "微信支付查询订单")
@PostMapping("/notify")
public AjaxResult notify(HttpServletRequest servletRequest, HttpServletResponse response)
throws Exception {
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);
if (wxPayService != null) {
wxPayService.callback(transaction);
}
return success();
} catch (ValidationException e) {
return error();
}
} catch (IOException e) {
return error(e.getMessage());
}
public AjaxResult notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
wxPayService.notify(request, response);
return success();
}
}

View File

@ -1,7 +1,8 @@
package com.ruoyi.pay.wx.service;
import com.ruoyi.pay.service.PayService;
import com.wechat.pay.java.service.wexinpayscoreparking.model.Transaction;
public interface IWxPayService {
public interface IWxPayService extends PayService {
public void callback(Transaction transaction);
}

View File

@ -0,0 +1,85 @@
package com.ruoyi.pay.wx.service.Impl;
import java.nio.charset.StandardCharsets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import com.ruoyi.pay.domain.PayOrder;
import com.ruoyi.pay.service.IPayOrderService;
import com.ruoyi.pay.wx.config.WxPayConfig;
import com.ruoyi.pay.wx.service.IWxPayService;
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 jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@Service
public class WxPayService implements IWxPayService {
@Autowired
private IPayOrderService payOrderService;
@Autowired
private NativePayService nativePayService;
@Autowired
private WxPayConfig wxPayAppConfig;
@Autowired
private NotificationParser notificationParser;
public void callback(Transaction transaction) {
}
@Override
public String payUrl(PayOrder payOrder) {
PrepayRequest request = new PrepayRequest();
Amount amount = new Amount();
amount.setTotal(Integer.parseInt(payOrder.getActualAmount()));
request.setAmount(amount);
request.setAppid(wxPayAppConfig.getAppId());
request.setMchid(wxPayAppConfig.getWxchantId());
request.setDescription(payOrder.getOrderContent());
request.setNotifyUrl(wxPayAppConfig.getNotifyUrl());
request.setOutTradeNo(payOrder.getOrderNumber());
PrepayResponse response = nativePayService.prepay(request);
return response.getCodeUrl();
}
@Override
public void notify(HttpServletRequest servletRequest, HttpServletResponse response) {
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();
Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
String orderNumber = transaction.getOutTradeNo();
String otherOrderNumber = transaction.getTransactionId();
String orderState = transaction.getTradeState();
System.out.println("orderNumber: " + orderNumber);
System.out.println("otherOrderNumber: " + otherOrderNumber);
System.out.println("orderState: " + orderState);
} catch (Exception e) {
e.printStackTrace();
}
}
}