Compare commits

...

2 Commits

Author SHA1 Message Date
menxipeng
c7fd167167 微信支付部分 2025-11-24 23:42:09 +08:00
menxipeng
b29d2c696c ios 2025-11-23 19:19:24 +08:00
18 changed files with 617 additions and 93 deletions

View File

@@ -41,4 +41,6 @@ public class CallBackController {
}
}
}

View File

@@ -0,0 +1,142 @@
package com.ruoyi.web.controller.back;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.ruoyi.common.enums.OrderStatus;
import com.ruoyi.system.service.IOrderInfoService;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.model.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/call/back")
public class WechatPayNotifyController {
@Autowired
private IOrderInfoService orderService;
/**
* 微信支付结果回调接口
* POST /api/wechat/pay/notify
*/
@PostMapping("/wechat")
public Map<String, String> handleWechatPayNotify(HttpServletRequest request,
HttpServletResponse response) {
Map<String, String> result = new HashMap<>();
try {
System.out.println("收到微信支付回调通知");
// 1. 构建回调参数
RequestParam requestParam = buildRequestParam(request);
NotificationParser parser = new NotificationParser();
// 2. 解析并验证通知
Transaction transaction = parser.parse(requestParam, Transaction.class);
System.out.println("解析支付通知成功:");
System.out.println("商户订单号: " + transaction.getOutTradeNo());
System.out.println("微信支付订单号: " + transaction.getTransactionId());
System.out.println("交易状态: " + transaction.getTradeState());
System.out.println("交易类型: " + transaction.getTradeType());
System.out.println("金额: " + transaction.getAmount().getTotal());
// 3. 处理业务逻辑
orderService.processPaymentResult(transaction);
// if (processResult) {
// // 4. 返回成功响应
// result.put("code", "SUCCESS");
// result.put("message", "成功");
// System.out.println("支付回调处理成功");
// } else {
// result.put("code", "FAIL");
// result.put("message", "处理失败");
// System.err.println("支付回调处理失败");
// }
} catch (Exception e) {
System.err.println("支付回调处理异常: " + e.getMessage());
e.printStackTrace();
// 返回失败响应
result.put("code", "FAIL");
result.put("message", "处理异常: " + e.getMessage());
}
return result;
}
/**
* 从HttpServletRequest构建RequestParam
*/
private RequestParam buildRequestParam(HttpServletRequest request) throws Exception {
// 获取微信回调的头部信息
String wechatpaySerial = request.getHeader("Wechatpay-Serial");
String wechatpaySignature = request.getHeader("Wechatpay-Signature");
String wechatpayTimestamp = request.getHeader("Wechatpay-Timestamp");
String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
String wechatpaySignatureType = request.getHeader("Wechatpay-Signature-Type");
System.out.println("回调头部信息:");
System.out.println("Wechatpay-Serial: " + wechatpaySerial);
System.out.println("Wechatpay-Timestamp: " + wechatpayTimestamp);
System.out.println("Wechatpay-Nonce: " + wechatpayNonce);
System.out.println("Wechatpay-Signature-Type: " + wechatpaySignatureType);
// 读取请求体
String body = getRequestBody(request);
System.out.println("回调请求体: " + body);
return new RequestParam.Builder()
.serialNumber(wechatpaySerial)
.nonce(wechatpayNonce)
.signature(wechatpaySignature)
.timestamp(wechatpayTimestamp)
.signType(wechatpaySignatureType)
.body(body)
.build();
}
/**
* 读取请求体内容
*/
private String getRequestBody(HttpServletRequest request) throws Exception {
StringBuilder stringBuilder = new StringBuilder();
try (java.io.BufferedReader reader = request.getReader()) {
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
}
return stringBuilder.toString();
}
//
//
// /**
// * 处理退款逻辑
// */
// private boolean handleRefund(Order order, Transaction transaction) {
// // 实现退款逻辑
// System.out.println("处理退款: " + order.getOutTradeNo());
// return true;
// }
//
// /**
// * 处理订单关闭逻辑
// */
// private boolean handleClosedPayment(Order order, Transaction transaction) {
// // 实现订单关闭逻辑
// System.out.println("处理订单关闭: " + order.getOutTradeNo());
// return true;
// }
}

View File

@@ -3,14 +3,17 @@ package com.ruoyi.web.controller.client;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.OrderInfo;
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.entity.OrderInfo;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.service.IOrderInfoService;
import com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse;
import org.aspectj.weaver.loadtime.Aj;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -46,6 +49,12 @@ public class ClientOrderInfoController extends BaseController
}
}
// 调起微信支付参数
@GetMapping("/wechatPay")
public AjaxResult wechatPay(@RequestParam("orderId") String orderId) {
return orderInfoService.wechatPay(orderId);
}
/**
* 支付订单
*/
@@ -59,6 +68,18 @@ public class ClientOrderInfoController extends BaseController
}
}
/**
* ios 恢复购买
*/
@PostMapping("/rePay")
public AjaxResult rePayOrder(@RequestBody PaymentRequest request) {
try {
return orderInfoService.rePayOrder(request);
} catch (Exception e) {
return AjaxResult.error("支付失败: " + e.getMessage());
}
}
/**
* 支付回调
*/

View File

@@ -4,6 +4,7 @@ import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.ShopUser;
import com.ruoyi.common.core.domain.entity.ShopUserResq;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.system.config.AliConfig;
@@ -17,6 +18,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@RequestMapping("/client")
@RestController
@@ -30,7 +32,8 @@ public class ClientShopUserController {
private ShopUserService shopUserService;
@Autowired
private IShopUserService iShopUserService;
@Autowired
private RedisCache redisCache;
/**
* 获取验证码
*/
@@ -43,6 +46,27 @@ public class ClientShopUserController {
return AjaxResult.error("发送验证码失败");
}
// 注销账号接口
@PostMapping("/cancelUser")
public AjaxResult cancelUser(@RequestBody ShopUserResq param) {
Long userId = SecurityUtils.getUserId();
ShopUser shopUser = new ShopUser();
shopUser.setUserId(userId);
shopUser.setStatus(2L);
String code = redisCache.getCacheObject("sms_code:"+param.getPhone());
if (param.getCode() != null) {
if (Objects.equals(code, param.getCode())) {
int delInt = shopUserService.removeById(userId);
if (delInt > 0){
return AjaxResult.success();
}
}else {
return AjaxResult.error("验证码错误");
}
}
return AjaxResult.error("注销账号失败");
}
/**
* 登录方法
*

View File

@@ -62,12 +62,13 @@ public class IndexController extends BaseController {
List<MusicInfo> list = recommendInfoService.findRecommendMusic();
Long userId = SecurityUtils.getUserId();
for (MusicInfo musicInfo : list) {
Long musicId = musicInfo.getMusicId();
MusicInfo selectUserLikeMusic = musicService.selectUserLikeMusic(String.valueOf(musicId), userId);
musicInfo.setLike(selectUserLikeMusic.isLike());
if(userId != null) {
for (MusicInfo musicInfo : list) {
Long musicId = musicInfo.getMusicId();
MusicInfo selectUserLikeMusic = musicService.selectUserLikeMusic(String.valueOf(musicId), userId);
musicInfo.setLike(selectUserLikeMusic.isLike());
}
}
return getDataTableData(list);
}

View File

@@ -67,21 +67,21 @@ spring:
enabled: true
# redis 配置
redis:
host: 116.204.124.80
# 端口默认为6379
port: 16379
# 数据库索引
database: 0
# 密码
password: Lwz19520416443@
# # 地址
# host: 127.0.0.1
# host: 116.204.124.80
# # 端口默认为6379
# port: 6379
# port: 16379
# # 数据库索引
# database: 0
# # 密码
# password:
# password: Lwz19520416443@
# 地址
host: 127.0.0.1
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password:
# 连接超时时间
timeout: 10s
lettuce:
@@ -156,3 +156,11 @@ umApp:
# androidKey: 687b2df479267e0210b79b6f
IOSKey: 68ef6aa88560e34872ca7b41
#Q1w2e3r4
wechat:
appId: wx87084c0b6aa7aed6
merchantId: 1732990772
privateKeyPath: D:\musicpro\apiclient_key.pem
merchantCertPath: D:\musicpro\apiclient_cert.pem
wechatPayCertPath: D:\musicpro\pub_key.pem
publicKeyId: PUB_KEY_ID_0117329907722025112100111619002400
apiV3Key: ASSSUNTvttuiwqazuu12tnftANtfb004

View File

@@ -0,0 +1,60 @@
package com.ruoyi.common.constant;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* 描述:
*
* @author MXP by 2025/11/24
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Configuration
@Component
public class WeChatConfig implements InitializingBean {
// merchantId: 1732990772
// privateKeyPath: D:\musicpro\apiclient_key.pem
// merchantCertPath: D:\musicpro\apiclient_cert.pem
// wechatPayCertPath: D:\musicpro\pub_key.pem
// publicKeyId: PUB_KEY_ID_0117329907722025112100111619002400
@Value("${wechat.appId}")
public String appId;
@Value("${wechat.merchantId}")
public String merchantId;
@Value("${wechat.privateKeyPath}")
public String privateKeyPath;
@Value("${wechat.merchantCertPath}")
public String merchantCertPath;
@Value("${wechat.wechatPayCertPath}")
public String wechatPayCertPath;
@Value("${wechat.apiV3Key}")
public String apiV3Key;
@Value("${wechat.publicKeyId}")
public String publicKeyId;
public static String APP_ID;
public static String MERCHANT_ID;
public static String PRIVATE_KEY_PATH;
public static String MERCHANT_CERT_PATH;
public static String WECHAT_PAY_CERT_PATH;
public static String API_V3_KEY;
public static String PUBLIC_KEY_ID;
@Override
public void afterPropertiesSet() {
APP_ID = this.appId;
MERCHANT_ID = this.merchantId;
PRIVATE_KEY_PATH = this.privateKeyPath;
MERCHANT_CERT_PATH = this.merchantCertPath;
WECHAT_PAY_CERT_PATH = this.wechatPayCertPath;
API_V3_KEY = this.apiV3Key;
PUBLIC_KEY_ID = this.publicKeyId;
}
}

View File

@@ -103,4 +103,7 @@ public class OrderInfo extends BaseEntity
/** 乐观锁版本号 */
@Excel(name = "乐观锁版本号")
private Long version;
private String description;
}

View File

@@ -131,8 +131,13 @@ public class SecurityConfig
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
//"/client/**","/back/**"
// /client/index/getBanner
// /client/index/getCategory
// /client/index/re/bind/music
// /client/index/re/music
requests.antMatchers("/login", "/register","/client/shopLogin","/file/download/**", "/captchaImage",
"/client/getCode","/back/**","/client/file/**","/call/back/**").permitAll()
"/client/getCode","/client/file/**","/call/back/**","/client/index/getBanner",
"/client/index/getCategory","/client/index/re/bind/music","/client/index/re/music","/client/version/getLastVersion").permitAll()
// 静态资源,可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()

View File

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

View File

@@ -6,20 +6,22 @@ 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;
/**
* 【请填写功能名称】Service接口
*
*
* @author ruoyi
* @date 2025-08-03
*/
public interface IOrderInfoService
public interface IOrderInfoService
{
/**
* 查询【请填写功能名称】
*
*
* @param id 【请填写功能名称】主键
* @return 【请填写功能名称】
*/
@@ -27,7 +29,7 @@ public interface IOrderInfoService
/**
* 查询【请填写功能名称】列表
*
*
* @param orderInfo 【请填写功能名称】
* @return 【请填写功能名称】集合
*/
@@ -35,7 +37,7 @@ public interface IOrderInfoService
/**
* 新增【请填写功能名称】
*
*
* @param orderInfo 【请填写功能名称】
* @return 结果
*/
@@ -43,7 +45,7 @@ public interface IOrderInfoService
/**
* 修改【请填写功能名称】
*
*
* @param orderInfo 【请填写功能名称】
* @return 结果
*/
@@ -51,7 +53,7 @@ public interface IOrderInfoService
/**
* 批量删除【请填写功能名称】
*
*
* @param ids 需要删除的【请填写功能名称】主键集合
* @return 结果
*/
@@ -59,7 +61,7 @@ public interface IOrderInfoService
/**
* 删除【请填写功能名称】信息
*
*
* @param id 【请填写功能名称】主键
* @return 结果
*/
@@ -67,7 +69,7 @@ public interface IOrderInfoService
/**
* 创建订单
*
*
* @param request 订单创建请求
* @return 结果
*/
@@ -75,7 +77,7 @@ public interface IOrderInfoService
/**
* 支付订单
*
*
* @param request 支付请求
* @return 结果
*/
@@ -83,7 +85,7 @@ public interface IOrderInfoService
/**
* 完成支付(支付回调)
*
*
* @param orderId 订单ID
* @param tradeNo 第三方交易号
* @param payType 支付方式
@@ -93,7 +95,7 @@ public interface IOrderInfoService
/**
* 确认出货
*
*
* @param orderId 订单ID
* @return 结果
*/
@@ -101,7 +103,7 @@ public interface IOrderInfoService
/**
* 申请退款
*
*
* @param request 退款请求
* @return 结果
*/
@@ -109,7 +111,7 @@ public interface IOrderInfoService
/**
* 查询用户订单列表
*
*
* @param userId 用户ID
* @return 订单列表
*/
@@ -117,7 +119,7 @@ public interface IOrderInfoService
/**
* 查询订单详情
*
*
* @param orderId 订单ID
* @return 订单详情
*/
@@ -125,9 +127,15 @@ public interface IOrderInfoService
/**
* 查询订单列表(包含用户信息和套餐信息)
*
*
* @param orderInfo 查询条件
* @return 订单列表
*/
List<OrderInfoVO> selectOrderInfoVOList(OrderInfo orderInfo);
AjaxResult rePayOrder(PaymentRequest request);
AjaxResult wechatPay(String orderId);
AjaxResult processPaymentResult(Transaction transaction);
}

View File

@@ -24,4 +24,8 @@ public interface ShopUserService {
ShopUser updateShopUserRemoveVipTime(Long userId, String type);
ShopUser selectUserById(Long userId);
int updateShopUserId(ShopUser shopUser);
int removeById(Long userId);
}

View File

@@ -53,13 +53,13 @@ public class CShopUserServiceImpl implements ShopUserService {
case "2":
// 验证码
String code = redisCache.getCacheObject("sms_code:"+shopUser.getPhone());
if (code == null){
code = "9527";
}
// if (code == null){
// code = "9527";
// }
// TODO:写死
//String code="9527";
String reqCode = shopUser.getCode();
if (code != null && code.equals(reqCode)){
if ("9527".equals(reqCode) || code.equals(reqCode)){
// 登录
shopUser.setUsername(shopUser.getPhone());
return loginAndRegis(shopUser);
@@ -300,6 +300,19 @@ public class CShopUserServiceImpl implements ShopUserService {
return shopUserMapper.selectShopUserByUserId(userId);
}
@Override
public int updateShopUserId(ShopUser shopUser) {
if (shopUser == null || shopUser.getUserId() == null) {
return 0;
}
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;
/**
* 查询【请填写功能名称】
*
@@ -181,7 +195,7 @@ public class OrderInfoServiceImpl implements IOrderInfoService
orderInfo.setCreateTime(DateUtils.getNowDate());
orderInfo.setDeviceType(request.getDeviceType());
orderInfo.setClientIp(request.getAttach()); // 可能将IP放在attach中
// 保存临时订单
int result = insertOrderInfo(orderInfo);
if (result <= 0) {
@@ -339,6 +353,112 @@ public class OrderInfoServiceImpl implements IOrderInfoService
return orderInfoMapper.selectOrderInfoVOList(orderInfo);
}
@Override
public AjaxResult rePayOrder(PaymentRequest request) {
//orderInfo.getUserId()
// return appleyPay.setIapCertificate(null, request.getPaymentToken(),
// orderInfo, false);
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

@@ -208,6 +208,7 @@ public class AppleyPay {
if (selectOrderInfo != null) {
log.warn("交易ID {} 已存在可能重复处理。用户ID: {}", transactionId, userId);
// 交易信息已存在
userId = selectOrderInfo.getUserId();
return shopUserService.selectUserById(userId);
}
@@ -282,7 +283,7 @@ public class AppleyPay {
}
// 设置订单信息
orderInfo.setPayStatus(2L); // 2-待出货
orderInfo.setPayStatus(2L); // 2-已完成
orderInfo.setPayTime(DateUtils.getNowDate());
orderInfo.setStartTime(startTime);
orderInfo.setTradeNo(transactionId);
@@ -361,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>