完善支付模块

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" vendorSn: "vendorSn"
vendorKey: "vendorKey" vendorKey: "vendorKey"
alipay: alipay:
appId: "appId" appId: appId
privateKey: "privateKey" appPrivateKey: appPrivateKey #classpath:pay/alipay/alipay_private_key.pem
publicKey: "publicKey" alipayPublicKey: alipayPublicKey #classpath:pay/alipay/alipay_public_key.pem
notifyUrl: "notifyUrl" 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; 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.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.factory.Factory;
import com.alipay.easysdk.kernel.Config; import com.alipay.easysdk.kernel.Config;
/**
import jakarta.annotation.PostConstruct; * @author zlh
*/
@Component @Configuration
public class AliPayConfig { public class AliPayConfig {
@Value("${pay.alipay.appId}") @Value("${pay.alipay.appId}")
private String appId; private String appId;
@Value("${pay.alipay.privateKey}")
private String privateKey;
@Value("${pay.alipay.publicKey}")
private String publicKey;
@Value("${pay.alipay.notifyUrl}") @Value("${pay.alipay.notifyUrl}")
private String notifyUrl; private String notifyUrl;
@Value("${pay.alipay.appPrivateKey}")
private String appPrivateKey;
@Value("${pay.alipay.alipayPublicKey}")
private String alipayPublicKey;
@PostConstruct @Autowired
public void init() { 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 config = new Config();
config.protocol = "https"; 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.signType = "RSA2";
config.appId = this.appId; config.appId = this.appId;
config.merchantPrivateKey = this.privateKey; config.merchantPrivateKey = getAppPrivateKey();
config.alipayPublicKey = this.publicKey; config.alipayPublicKey = getAlipayPublicKey();
System.out.println(getAlipayPublicKey());
config.notifyUrl = this.notifyUrl; config.notifyUrl = this.notifyUrl;
Factory.setOptions(config); Factory.setOptions(config);
return config;
} }
public String getAppId() { }
return appId;
}
public void setAppId(String appId) { // https://openapi-sandbox.dl.alipaydev.com/gateway.do
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;
}
}

View File

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

View File

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

View File

@ -75,4 +75,5 @@ public interface IPayOrderService {
* @return 结果 * @return 结果
*/ */
public int deletePayOrderByOrderId(Long orderId); 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) { public int deletePayOrderByOrderNumber(String orderNumber) {
return payOrderMapper.deletePayOrderByOrderNumber(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"> <select id="selectPayOrderByOrderId" parameterType="Long" resultMap="PayOrderResult">
<include refid="selectPayOrderVo" /> <include refid="selectPayOrderVo" />
where pay_order.order_id = #{orderId} </select> where pay_order.order_id = #{orderId}
</select>
<select id="selectPayOrderByOrderNumber" parameterType="String" resultMap="PayOrderResult"> <select id="selectPayOrderByOrderNumber" parameterType="String" resultMap="PayOrderResult">
<include refid="selectPayOrderVo" /> <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=","> <insert id="insertPayOrder" parameterType="PayOrder"> insert into pay_order
<if test="orderId != null">order_id,</if> <trim prefix="(" suffix=")" suffixOverrides=",">
<if test="userId != null">user_id,</if> <if test="orderId != null">order_id,</if>
<if test="orderNumber != null">order_number,</if> <if test="userId != null">user_id,</if>
<if test="orderStatus != null"> <if test="orderNumber != null">order_number,</if>
<if test="orderStatus != null">
order_status,</if> order_status,</if>
<if test="totalAmount != null">total_amount,</if> <if test="totalAmount != null">total_amount,</if>
<if test="orderContent != null">order_content,</if> <if test="orderContent != null">order_content,</if>
<if test="orderRemark != null"> <if test="orderRemark != null">
order_remark,</if> order_remark,</if>
<if test="orderMessage != null">order_message,</if> <if test="orderMessage != null">order_message,</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="orderId != null">#{orderId},</if> <if test="orderId != null">#{orderId},</if>
<if test="userId != null">#{userId},</if> <if test="userId != null">#{userId},</if>
<if test="orderNumber != null">#{orderNumber},</if> <if test="orderNumber != null">#{orderNumber},</if>
<if test="orderStatus != null"> <if test="orderStatus != null">
#{orderStatus},</if> #{orderStatus},</if>
<if test="totalAmount != null">#{totalAmount},</if> <if test="totalAmount != null">#{totalAmount},</if>
<if test="orderContent != null">#{orderContent},</if> <if test="orderContent != null">#{orderContent},</if>
<if test="orderRemark != null"> <if test="orderRemark != null">
#{orderRemark},</if> #{orderRemark},</if>
<if test="orderMessage != null">#{orderMessage},</if> <if test="orderMessage != null">#{orderMessage},</if>
</trim> </trim>
</insert> </insert>
<update id="updatePayOrder" parameterType="PayOrder"> update pay_order <trim prefix="SET" suffixOverrides=","> <update id="updatePayOrder" parameterType="PayOrder"> update pay_order
<if test="userId != null">user_id = #{userId},</if> <trim prefix="SET" suffixOverrides=",">
<if test="orderNumber != null">order_number <if test="userId != null">user_id = #{userId},</if>
= #{orderNumber},</if> <if test="orderNumber != null">order_number
<if test="orderStatus != null">order_status = #{orderStatus},</if> = #{orderNumber},</if>
<if test="totalAmount != null">total_amount = #{totalAmount},</if> <if test="orderStatus != null">order_status = #{orderStatus},</if>
<if test="orderContent != null">order_content = #{orderContent},</if> <if test="totalAmount != null">total_amount = #{totalAmount},</if>
<if test="orderRemark != null">order_remark = #{orderRemark},</if> <if test="orderContent != null">order_content = #{orderContent},</if>
<if test="orderMessage != null">order_message = #{orderMessage},</if> <if test="orderRemark != null">order_remark = #{orderRemark},</if>
</trim> <if test="orderMessage != null">order_message = #{orderMessage},</if>
</trim>
where pay_order.order_id = #{orderId} </update> 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 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 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 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} #{orderId}
</foreach> </foreach>
</delete> </delete>
<update id="updateStatus" parameterType="String">
update pay_order set order_status = #{orderStatus} where order_number = #{orderNumber}
</update>
</mapper> </mapper>

View File

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