完善支付模块

This commit is contained in:
Dftre 2024-05-21 16:42:21 +08:00
parent 509e771862
commit b401d7be19
10 changed files with 306 additions and 114 deletions

View File

@ -7,7 +7,14 @@ pay:
vendorSn: "vendorSn"
vendorKey: "vendorKey"
alipay:
appId: "appId"
privateKey: "privateKey"
publicKey: "publicKey"
notifyUrl: "notifyUrl"
appId: appId
appPrivateKey: appPrivateKey #classpath:pay/alipay/alipay_private_key.pem
alipayPublicKey: alipayPublicKey #classpath:pay/alipay/alipay_public_key.pem
notifyUrl: http://www.sdaizy.com/prod-api/alipay/notify
wechat:
merchantId: merchantId
privateKeyPath: privateKeyPath
merchantSerialNumber: merchantSerialNumber
apiV3Key: apiV3Key
appId: appId
notifyUrl: http://g5vdrz.natappfree.cc/wxPay/notify

View File

@ -1,66 +1,78 @@
package com.ruoyi.pay.alipay.config;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import jakarta.annotation.PostConstruct;
@Component
/**
* @author zlh
*/
@Configuration
public class AliPayConfig {
@Value("${pay.alipay.appId}")
private String appId;
@Value("${pay.alipay.privateKey}")
private String privateKey;
@Value("${pay.alipay.publicKey}")
private String publicKey;
@Value("${pay.alipay.notifyUrl}")
private String notifyUrl;
@Value("${pay.alipay.appPrivateKey}")
private String appPrivateKey;
@Value("${pay.alipay.alipayPublicKey}")
private String alipayPublicKey;
@PostConstruct
public void init() {
@Autowired
private ApplicationContext applicationContext;
private String getAppPrivateKey() throws Exception {
if (appPrivateKey.startsWith("classpath")) {
Resource resource = applicationContext.getResource(appPrivateKey);
InputStream inputStream = resource.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String appPrivateKeyValue = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator()));
bufferedReader.close();
return appPrivateKeyValue;
} else {
return appPrivateKey;
}
}
private String getAlipayPublicKey() throws Exception {
if (alipayPublicKey.startsWith("classpath")) {
Resource resource = applicationContext.getResource(alipayPublicKey);
InputStream inputStream = resource.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String alipayPublicKeyValue = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator()));
bufferedReader.close();
return alipayPublicKeyValue;
} else {
return alipayPublicKey;
}
}
@Bean
protected Config config() throws Exception {
// 设置参数全局只需设置一次
Config config = new Config();
config.protocol = "https";
config.gatewayHost = "openapi-sandbox.dl.alipaydev.com";
config.gatewayHost = "openapi.alipay.com";// openapi-sandbox.dl.alipaydev.com||openapi.alipay.com
config.signType = "RSA2";
config.appId = this.appId;
config.merchantPrivateKey = this.privateKey;
config.alipayPublicKey = this.publicKey;
config.merchantPrivateKey = getAppPrivateKey();
config.alipayPublicKey = getAlipayPublicKey();
System.out.println(getAlipayPublicKey());
config.notifyUrl = this.notifyUrl;
Factory.setOptions(config);
return config;
}
public String getAppId() {
return appId;
}
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getPrivateKey() {
return privateKey;
}
public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}
public String getPublicKey() {
return publicKey;
}
public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
}
// https://openapi-sandbox.dl.alipaydev.com/gateway.do

View File

@ -5,6 +5,7 @@ import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
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,45 +13,50 @@ 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.pay.alipay.config.AliPayConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.pay.domain.PayOrder;
import com.ruoyi.pay.mapper.PayOrderMapper;
import com.ruoyi.pay.service.IPayOrderService;
import io.swagger.v3.oas.annotations.Operation;
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;
/**
* @author zlh
*/
@RestController
@RequestMapping("/alipay")
@Tag(name = "【支付宝】管理")
public class AliPayController {
@Autowired
private PayOrderMapper payOrderMapper;
@Autowired
private AliPayConfig aliPayConfig;
@GetMapping("/init")
public String init() {
aliPayConfig.init();
return "success";
}
private IPayOrderService payOrderService;
@Anonymous
@GetMapping("/pay")
public String pay(PayOrder payOrder) {
@Operation(summary = "支付宝支付")
@Parameters({
@Parameter(name = "orderId", description = "订单号", required = true)
})
@GetMapping("/pay/{orderNumber}")
public AjaxResult pay(@PathVariable String orderNumber) {
AlipayTradePagePayResponse response;
PayOrder aliPay = payOrderService.selectPayOrderByOrderNumber(orderNumber);
try {
// 发起API调用以创建当面付收款二维码为例
response = Factory.Payment.Page()
.pay(payOrder.getOrderContent(), payOrder.getOrderNumber(), payOrder.getTotalAmount(), "");
.pay(aliPay.getOrderContent(), aliPay.getOrderNumber(), aliPay.getTotalAmount(), "");
} catch (Exception e) {
System.err.println("调用遭遇异常,原因:" + e.getMessage());
throw new RuntimeException(e.getMessage(), e);
}
return response.getBody();
return AjaxResult.success(response.getBody());
}
@Anonymous
@Operation(summary = "支付宝支付回调")
@PostMapping("/notify") // 注意这里必须是POST接口
public String payNotify(HttpServletRequest request) throws Exception {
public AjaxResult payNotify(HttpServletRequest request) throws Exception {
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
System.out.println("=========支付宝异步回调========");
@ -74,11 +80,10 @@ public class AliPayController {
System.out.println("买家付款时间: " + params.get("gmt_payment"));
System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));
PayOrder payOrder = payOrderMapper.selectPayOrderByOrderNumber(orderNumber);
payOrder.setOrderStatus("已支付");
payOrderMapper.updatePayOrder(payOrder);
// // 更新订单未已支付
payOrderService.updateStatus(orderNumber, "已支付");
}
}
return "success";
return AjaxResult.success("success");
}
}

View File

@ -69,4 +69,5 @@ public interface PayOrderMapper
public int deletePayOrderByOrderIds(Long[] orderIds);
public int deletePayOrderByOrderNumber(String orderNumber);
public int updateStatus(String orderNumber, String orderStatus);
}

View File

@ -75,4 +75,5 @@ public interface IPayOrderService {
* @return 结果
*/
public int deletePayOrderByOrderId(Long orderId);
public int updateStatus(String orderNumber, String orderStatus);
}

View File

@ -107,4 +107,9 @@ public class PayOrderServiceImpl implements IPayOrderService {
public int deletePayOrderByOrderNumber(String orderNumber) {
return payOrderMapper.deletePayOrderByOrderNumber(orderNumber);
}
@Override
public int updateStatus(String orderNumber, String orderStatus) {
return payOrderMapper.updateStatus(orderNumber, orderStatus);
}
}

View File

@ -34,62 +34,70 @@
<select id="selectPayOrderByOrderId" parameterType="Long" resultMap="PayOrderResult">
<include refid="selectPayOrderVo" />
where pay_order.order_id = #{orderId} </select>
where pay_order.order_id = #{orderId}
</select>
<select id="selectPayOrderByOrderNumber" parameterType="String" resultMap="PayOrderResult">
<include refid="selectPayOrderVo" />
where pay_order.order_number = #{orderNumber} </select>
where pay_order.order_number = #{orderNumber}
</select>
<insert id="insertPayOrder" parameterType="PayOrder"> insert into pay_order <trim prefix="(" suffix=")" suffixOverrides=",">
<if test="orderId != null">order_id,</if>
<if test="userId != null">user_id,</if>
<if test="orderNumber != null">order_number,</if>
<if test="orderStatus != null">
<insert id="insertPayOrder" parameterType="PayOrder"> insert into pay_order
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="orderId != null">order_id,</if>
<if test="userId != null">user_id,</if>
<if test="orderNumber != null">order_number,</if>
<if test="orderStatus != null">
order_status,</if>
<if test="totalAmount != null">total_amount,</if>
<if test="orderContent != null">order_content,</if>
<if test="orderRemark != null">
<if test="totalAmount != null">total_amount,</if>
<if test="orderContent != null">order_content,</if>
<if test="orderRemark != null">
order_remark,</if>
<if test="orderMessage != null">order_message,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="orderId != null">#{orderId},</if>
<if test="userId != null">#{userId},</if>
<if test="orderNumber != null">#{orderNumber},</if>
<if test="orderStatus != null">
<if test="orderMessage != null">order_message,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="orderId != null">#{orderId},</if>
<if test="userId != null">#{userId},</if>
<if test="orderNumber != null">#{orderNumber},</if>
<if test="orderStatus != null">
#{orderStatus},</if>
<if test="totalAmount != null">#{totalAmount},</if>
<if test="orderContent != null">#{orderContent},</if>
<if test="orderRemark != null">
<if test="totalAmount != null">#{totalAmount},</if>
<if test="orderContent != null">#{orderContent},</if>
<if test="orderRemark != null">
#{orderRemark},</if>
<if test="orderMessage != null">#{orderMessage},</if>
</trim>
</insert>
<if test="orderMessage != null">#{orderMessage},</if>
</trim>
</insert>
<update id="updatePayOrder" parameterType="PayOrder"> update pay_order <trim prefix="SET" suffixOverrides=",">
<if test="userId != null">user_id = #{userId},</if>
<if test="orderNumber != null">order_number
= #{orderNumber},</if>
<if test="orderStatus != null">order_status = #{orderStatus},</if>
<if test="totalAmount != null">total_amount = #{totalAmount},</if>
<if test="orderContent != null">order_content = #{orderContent},</if>
<if test="orderRemark != null">order_remark = #{orderRemark},</if>
<if test="orderMessage != null">order_message = #{orderMessage},</if>
</trim>
<update id="updatePayOrder" parameterType="PayOrder"> update pay_order
<trim prefix="SET" suffixOverrides=",">
<if test="userId != null">user_id = #{userId},</if>
<if test="orderNumber != null">order_number
= #{orderNumber},</if>
<if test="orderStatus != null">order_status = #{orderStatus},</if>
<if test="totalAmount != null">total_amount = #{totalAmount},</if>
<if test="orderContent != null">order_content = #{orderContent},</if>
<if test="orderRemark != null">order_remark = #{orderRemark},</if>
<if test="orderMessage != null">order_message = #{orderMessage},</if>
</trim>
where pay_order.order_id = #{orderId} </update>
<delete id="deletePayOrderByOrderId" parameterType="Long">
<delete id="deletePayOrderByOrderId" parameterType="Long">
delete from pay_order where order_id = #{orderId}
</delete>
</delete>
<delete id="deletePayOrderByOrderNumber" parameterType="String">
<delete id="deletePayOrderByOrderNumber" parameterType="String">
delete from pay_order where order_number= #{orderNumber}
</delete>
</delete>
<delete id="deletePayOrderByOrderIds" parameterType="String">
<delete id="deletePayOrderByOrderIds" parameterType="String">
delete from pay_order where order_id in
<foreach item="orderId" collection="array" open="(" separator="," close=")">
<foreach item="orderId" collection="array" open="(" separator="," close=")">
#{orderId}
</foreach>
</delete>
</foreach>
</delete>
<update id="updateStatus" parameterType="String">
update pay_order set order_status = #{orderStatus} where order_number = #{orderNumber}
</update>
</mapper>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-pay</artifactId>
<groupId>com.ruoyi</groupId>
@ -22,6 +21,12 @@
<artifactId>ruoyi-pay-common</artifactId>
</dependency>
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.12</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,32 @@
package com.ruoyi.pay.wx.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import lombok.Data;
/**
* 配置我们自己的信息
*
* @author ZlH
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "wechat")
public class WxPayAppConfig {
@Value("${pay.wechat.merchantId}")
private String wxchantId;
@Value("${pay.wechat.merchantSerialNumber}")
private String wxchantSerialNumber;
@Value("${pay.wechat.apiV3Key}")
private String wxapiV3Key;
@Value("${pay.wechat.privateKeyPath}")
private String wxcertPath;
@Value("${pay.wechat.appId}")
private String appId;
@Value("${pay.wechat.notifyUrl}")
private String notifyUrl;
}

View File

@ -0,0 +1,116 @@
package com.ruoyi.pay.wx.controller;
import com.ruoyi.common.annotation.Anonymous;
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.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.nativepay.model.QueryOrderByIdRequest;
import com.wechat.pay.java.service.wexinpayscoreparking.model.Transaction;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
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 lombok.extern.slf4j.Slf4j;
/**
* @author zlh
*/
@Slf4j
@RestController
@RequestMapping("/wxPay")
public class WxAppPayController extends BaseController {
@Autowired
private WxPayAppConfig wxPayAppConfig;
@Autowired
private IPayOrderService payOrderService;
@Anonymous
@Operation(summary = "微信支付")
@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定义
PayOrder aliPay = payOrderService.selectPayOrderByOrderNumber(orderNumber);
String amountStr = aliPay.getTotalAmount();
double amountDouble = Double.parseDouble(amountStr);
int totalAmountInt = (int) (amountDouble * 100);
PrepayRequest request = new PrepayRequest();
Amount amount = new Amount();
amount.setTotal(totalAmountInt);
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 = service.prepay(request);
// 使用微信扫描 code_url 对应的二维码即可体验Native支付
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);
// }
}