微信支付部分

This commit is contained in:
menxipeng
2025-11-24 23:42:09 +08:00
parent b29d2c696c
commit c7fd167167
17 changed files with 523 additions and 60 deletions

View File

@@ -93,4 +93,6 @@ public interface ShopUserMapper {
int updateShopUserId(ShopUser shopUser);
int updateDeviceIdByPhone(ShopUserResq shopUser);
int deleteShopUserByUserId(Long userId);
}

View File

@@ -6,6 +6,8 @@ import com.ruoyi.common.core.domain.dto.OrderCreateRequest;
import com.ruoyi.common.core.domain.dto.PaymentRequest;
import com.ruoyi.common.core.domain.dto.RefundRequest;
import com.ruoyi.common.core.domain.vo.OrderInfoVO;
import com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import java.util.List;
@@ -132,4 +134,8 @@ public interface IOrderInfoService
List<OrderInfoVO> selectOrderInfoVOList(OrderInfo orderInfo);
AjaxResult rePayOrder(PaymentRequest request);
AjaxResult wechatPay(String orderId);
AjaxResult processPaymentResult(Transaction transaction);
}

View File

@@ -26,4 +26,6 @@ public interface ShopUserService {
ShopUser selectUserById(Long userId);
int updateShopUserId(ShopUser shopUser);
int removeById(Long userId);
}

View File

@@ -308,6 +308,11 @@ public class CShopUserServiceImpl implements ShopUserService {
return shopUserMapper.updateShopUser(shopUser);
}
@Override
public int removeById(Long userId) {
return shopUserMapper.deleteShopUserByUserId(userId);
}
public ShopUser loginAndRegis(ShopUserResq shopUser) {
ShopUser member = shopUserMapper.selectShopUserByPhone(shopUser.getPhone());
if (shopUser.getPhone() != null && StringUtils.isNull(member)) {

View File

@@ -9,6 +9,7 @@ import com.ruoyi.common.core.domain.entity.PayStatusEnum;
import com.ruoyi.common.core.domain.entity.ShopUser;
import com.ruoyi.common.core.domain.vo.OrderInfoVO;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.OrderStatus;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
@@ -16,6 +17,12 @@ import com.ruoyi.system.mapper.OrderInfoMapper;
import com.ruoyi.system.service.IOrderInfoService;
import com.ruoyi.system.util.AppleyPay;
import com.ruoyi.system.util.PaymentUtil;
import com.ruoyi.system.util.WeChatPayUtil;
import com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import org.checkerframework.checker.units.qual.A;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -32,12 +39,19 @@ import java.util.*;
@Service
public class OrderInfoServiceImpl implements IOrderInfoService
{
private static final Logger log = LoggerFactory.getLogger(OrderInfoServiceImpl.class);
@Autowired
private OrderInfoMapper orderInfoMapper;
@Autowired
private PaymentUtil paymentUtil;
@Autowired
private WeChatPayUtil weChatPayUtil;
/**
* 查询【请填写功能名称】
*
@@ -347,6 +361,104 @@ public class OrderInfoServiceImpl implements IOrderInfoService
return null;
}
@Override
public AjaxResult wechatPay(String orderId) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null) {
return AjaxResult.error(401, "用户未登录");
}
// 参数校验
if (StringUtils.isEmpty(orderId)) {
return AjaxResult.error("订单ID不能为空");
}
// 查询订单
OrderInfo orderInfo = selectOrderByOrderId(orderId);
if (orderInfo == null) {
return AjaxResult.error("订单不存在");
}
// 检查订单状态
if (orderInfo.getPayStatus() != PayStatusEnum.CREATE.getStatus()) {
return AjaxResult.error("订单状态不正确");
}
// 检查用户权限
if (!loginUser.getUserId().equals(orderInfo.getUserId())) {
return AjaxResult.error("无权限操作此订单");
}
PrepayWithRequestPaymentResponse result = weChatPayUtil.prepayWithRequestPayment(orderInfo);
return AjaxResult.success("获取微信支付参数成功",result);
}
@Override
public AjaxResult processPaymentResult(Transaction transaction) {
try {
String outTradeNo = transaction.getOutTradeNo();
String tradeState = transaction.getTradeState().name();
String transactionId = transaction.getTransactionId();
int totalAmount = transaction.getAmount().getTotal();
String successTime = transaction.getSuccessTime();
log.info("订单号: {}交易状态: {}支付金额: {}", outTradeNo, tradeState, totalAmount);
// 1. 根据商户订单号查询本地订单
OrderInfo order = orderInfoMapper.selectOrderByOrderId(outTradeNo);
if (order == null) {
return AjaxResult.error("未找到对应订单");
}
// 2. 检查订单是否已经处理过(防止重复通知)
if ((OrderStatus.PAID.getCode()).equals(order.getPayStatus())) {
return AjaxResult.success("订单已支付,跳过处理");
}
//order.getAmount() 元转分
int amount = order.getAmount().multiply(new BigDecimal(100)).intValue();
// 3. 验证金额是否一致
if (amount != totalAmount) {
return AjaxResult.error("金额不一致");
}
// 4. 根据交易状态处理业务
if ("SUCCESS".equals(tradeState)) {
// 计算服务开始和结束时间
Date startTime = new Date();
// 支付成功
// 设置订单信息
order.setPayStatus(2L); // 2-已完成
order.setPayTime(DateUtils.getNowDate());
order.setStartTime(startTime);
order.setTradeNo(transactionId);
order.setCallbackContent(outTradeNo); // 保存交易ID
order.setCallTime(DateUtils.getNowDate());
order.setUpdateTime(DateUtils.getNowDate());
Date endTime = AppleyPay.calculateEndTime(startTime, order.getPackageType());
order.setEndTime(endTime);
return AjaxResult.success();
} else if ("REFUND".equals(tradeState)) {
// 转入退款
//return handleRefund(order, transaction);
} else if ("CLOSED".equals(tradeState)) {
// 已关闭
//return handleClosedPayment(order, transaction);
} else {
// 其他状态
log.info("未知状态: " + tradeState);
// 仍然返回成功,避免微信重复通知
}
} catch (Exception e) {
log.error("处理订单异常: {}", e.getMessage());
e.printStackTrace();
}
return AjaxResult.error("处理订单异常");
}
@Override
@Transactional
public AjaxResult confirmShipment(String orderId) {

View File

@@ -283,7 +283,7 @@ public class AppleyPay {
}
// 设置订单信息
orderInfo.setPayStatus(2L); // 2-待出货
orderInfo.setPayStatus(2L); // 2-已完成
orderInfo.setPayTime(DateUtils.getNowDate());
orderInfo.setStartTime(startTime);
orderInfo.setTradeNo(transactionId);
@@ -362,7 +362,7 @@ public class AppleyPay {
* @param packageType 套餐类型1-月付, 3-季付, 6-半年付, 12-年付
* @return 结束时间
*/
private Date calculateEndTime(Date startTime, String packageType) {
public static Date calculateEndTime(Date startTime, String packageType) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(startTime);

View File

@@ -1,58 +1,97 @@
package com.ruoyi.system.util;
import cn.hutool.core.util.IdUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.util.PemUtil;
import com.wechat.pay.java.service.payments.app.AppServiceExtension;
import com.wechat.pay.java.service.payments.app.model.CloseOrderRequest;
import com.wechat.pay.java.service.payments.app.model.Amount;
import com.wechat.pay.java.service.payments.app.model.PrepayRequest;
import com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.app.model.QueryOrderByIdRequest;
import com.wechat.pay.java.service.payments.app.model.QueryOrderByOutTradeNoRequest;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.model.Transaction;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
public class WeChatAppServiceExtensionExample {
/**
* 商户号
*/
public static String merchantId = "190000****";
public static String merchantId = "1732990772";
/**
* 商户API私钥路径
*/
public static String privateKeyPath = "/Users/yourname/your/path/apiclient_key.pem";
public static String privateKeyPath = "D:\\musicpro\\apiclient_key.pem";
/**
* 商户证书序列号
*/
public static String merchantSerialNumber = "5157F09EFDC096DE15EBE81A47057A72********";
private static String merchantCertPath = "D:\\musicpro\\apiclient_cert.pem";
private static String wechatPayCertPath = "D:\\musicpro\\pub_key.pem";
/**
* 商户APIV3密钥
*/
public static String apiV3Key = "...";
public static String apiV3Key = "ASSSUNTvttuiwqazuu12tnftANtfb004";
public static AppServiceExtension service;
public static void main(String[] args) {
// 初始化商户配置
public static void main(String[] args) throws CertificateException, FileNotFoundException {
// 2. 加载商户证书并获取序列号
X509Certificate merchantCertificate = PemUtil.loadX509FromPath(merchantCertPath);
String merchantSerialNumber = merchantCertificate.getSerialNumber().toString(16).toUpperCase();
Config config =
new RSAAutoCertificateConfig.Builder()
new RSAPublicKeyConfig.Builder()
.merchantId(merchantId)
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
.privateKeyFromPath(privateKeyPath)
.publicKeyFromPath(wechatPayCertPath)
.publicKeyId("PUB_KEY_ID_0117329907722025112100111619002400")
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
// 初始化服务
service = new AppServiceExtension.Builder().config(config).build();
// // 初始化服务
// service = new AppServiceExtension.Builder().config(config).build();
AppServiceExtension service = new AppServiceExtension.Builder().config(config).build();
// 跟之前下单示例一样,填充预下单参数
PrepayRequest request = new PrepayRequest();
request.setAppid("wx87084c0b6aa7aed6");
request.setDescription("测试");
request.setMchid(merchantId);
request.setOutTradeNo("andhadwdbawqd2");
//request.setTimeExpire("2025-11-24T21:48:31+08:00");
request.setNotifyUrl("https://www.wechat.com");
Amount amount = new Amount();
amount.setTotal(1);
amount.setCurrency("CNY");
request.setAmount(amount);
// response包含了调起支付所需的所有参数可直接用于前端调起支付
PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
System.out.println(response);
try {
// ... 调用接口
PrepayWithRequestPaymentResponse response = prepayWithRequestPayment();
System.out.println(response);
} catch (HttpException e) { // 发送HTTP请求失败
// PrepayWithRequestPaymentResponse response = prepayWithRequestPayment();
// System.out.println(response);
} catch (HttpException e) {
e.printStackTrace();// 发送HTTP请求失败
// 调用e.getHttpRequest()获取请求打印日志或上报监控更多方法见HttpException定义
} catch (ServiceException e) { // 服务返回状态小于200或大于等于300例如500
// 调用e.getResponseBody()获取返回体打印日志或上报监控更多方法见ServiceException定义
@@ -66,41 +105,41 @@ public class WeChatAppServiceExtensionExample {
*/
public static void closeOrder() {
CloseOrderRequest request = new CloseOrderRequest();
// 调用request.setXxx(val)设置所需参数具体参数可见Request定义
// 调用接口
service.closeOrder(request);
// CloseOrderRequest request = new CloseOrderRequest();
// // 调用request.setXxx(val)设置所需参数具体参数可见Request定义
// // 调用接口
// service.closeOrder(request);
}
/**
* APP支付下单并返回APP调起支付数据
*/
public static PrepayWithRequestPaymentResponse prepayWithRequestPayment() {
PrepayRequest request = new PrepayRequest();
// 调用request.setXxx(val)设置所需参数具体参数可见Request定义
// 调用接口
return service.prepayWithRequestPayment(request);
}
/**
* 微信支付订单号查询订单
*/
public static Transaction queryOrderById() {
QueryOrderByIdRequest request = new QueryOrderByIdRequest();
// 调用request.setXxx(val)设置所需参数具体参数可见Request定义
// 调用接口
return service.queryOrderById(request);
}
/**
* 商户订单号查询订单
*/
public static Transaction queryOrderByOutTradeNo() {
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
// 调用request.setXxx(val)设置所需参数具体参数可见Request定义
// 调用接口
return service.queryOrderByOutTradeNo(request);
}
// /**
// * APP支付下单并返回APP调起支付数据
// */
// public static PrepayWithRequestPaymentResponse prepayWithRequestPayment() {
// PrepayRequest request = new PrepayRequest();
// // 调用request.setXxx(val)设置所需参数具体参数可见Request定义
// // 调用接口
// return service.prepayWithRequestPayment(request);
// }
//
// /**
// * 微信支付订单号查询订单
// */
// public static Transaction queryOrderById() {
//
// QueryOrderByIdRequest request = new QueryOrderByIdRequest();
// // 调用request.setXxx(val)设置所需参数具体参数可见Request定义
// // 调用接口
// return service.queryOrderById(request);
// }
//
// /**
// * 商户订单号查询订单
// */
// public static Transaction queryOrderByOutTradeNo() {
//
// QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
// // 调用request.setXxx(val)设置所需参数具体参数可见Request定义
// // 调用接口
// return service.queryOrderByOutTradeNo(request);
// }
}

View File

@@ -0,0 +1,67 @@
package com.ruoyi.system.util;
import com.ruoyi.common.constant.WeChatConfig;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.util.PemUtil;
import com.wechat.pay.java.service.payments.app.AppServiceExtension;
import com.wechat.pay.java.service.payments.app.model.Amount;
import com.wechat.pay.java.service.payments.app.model.PrepayRequest;
import com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.security.cert.X509Certificate;
/**
* 描述:
*
* @author MXP by 2025/11/24
*/
@Component
public class WeChatPayUtil {
public PrepayWithRequestPaymentResponse prepayWithRequestPayment(OrderInfo orderInfo){
// 2. 加载商户证书并获取序列号
X509Certificate merchantCertificate = PemUtil.loadX509FromPath(WeChatConfig.MERCHANT_CERT_PATH);
String merchantSerialNumber = merchantCertificate.getSerialNumber().toString(16).toUpperCase();
Config config =
new RSAPublicKeyConfig.Builder()
.merchantId(WeChatConfig.MERCHANT_ID)
.privateKeyFromPath(WeChatConfig.PRIVATE_KEY_PATH)
.publicKeyFromPath(WeChatConfig.WECHAT_PAY_CERT_PATH)
.publicKeyId(WeChatConfig.PUBLIC_KEY_ID)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(WeChatConfig.API_V3_KEY)
.build();
AppServiceExtension service = new AppServiceExtension.Builder().config(config).build();
// 跟之前下单示例一样,填充预下单参数
PrepayRequest request = new PrepayRequest();
request.setAppid(WeChatConfig.APP_ID);
request.setDescription(orderInfo.getPackageType());
request.setMchid(WeChatConfig.MERCHANT_ID);
request.setOutTradeNo(String.valueOf(orderInfo.getOrderId()));
//request.setTimeExpire("2025-11-24T21:48:31+08:00");
request.setNotifyUrl("https://lingxiapi.mingyuegn.top/prod-api/call/back/wechat");
Amount amount = new Amount();
// orderInfo.getAmount() 元转分
amount.setTotal(orderInfo.getAmount().multiply(new BigDecimal(100)).intValue());
amount.setCurrency("CNY");
request.setAmount(amount);
// response包含了调起支付所需的所有参数可直接用于前端调起支付
return service.prepayWithRequestPayment(request);
// "appid": "wxd678efh567hg6787",
// "partnerid": "190000XXXX",
// "prepayid": "wx26144052643535f4e6f9d125d829730000",
// "package": "Sign=WXPay",
// "noncestr": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
// "timestamp": "1719123456",
// "sign": "A8422B7785FD739A8BC1E5A3F3626XXX"
}
}

View File

@@ -269,4 +269,8 @@
#{userId}
</foreach>
</select>
<delete id="deleteShopUserByUserId">
delete from shop_user where user_id = #{userId}
</delete>
</mapper>