diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/CallBackController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/CallBackController.java index 6412fd0..9f14f93 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/CallBackController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/CallBackController.java @@ -41,4 +41,6 @@ public class CallBackController { } } + + } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/WechatPayNotifyController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/WechatPayNotifyController.java new file mode 100644 index 0000000..74e9845 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/WechatPayNotifyController.java @@ -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 handleWechatPayNotify(HttpServletRequest request, + HttpServletResponse response) { + Map 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; + // } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/client/ClientOrderInfoController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/client/ClientOrderInfoController.java index 8b24989..0149b0e 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/client/ClientOrderInfoController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/client/ClientOrderInfoController.java @@ -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); + } + /** * 支付订单 */ diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/client/ClientShopUserController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/client/ClientShopUserController.java index 9146344..e9aa23b 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/client/ClientShopUserController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/client/ClientShopUserController.java @@ -53,14 +53,16 @@ public class ClientShopUserController { ShopUser shopUser = new ShopUser(); shopUser.setUserId(userId); shopUser.setStatus(2L); - String code = redisCache.getCacheObject("sms_code:"+shopUser.getPhone()); + String code = redisCache.getCacheObject("sms_code:"+param.getPhone()); if (param.getCode() != null) { if (Objects.equals(code, param.getCode())) { - shopUserService.updateShopUserId(shopUser); - return AjaxResult.success(); + int delInt = shopUserService.removeById(userId); + if (delInt > 0){ + return AjaxResult.success(); + } + }else { + return AjaxResult.error("验证码错误"); } - }else { - return AjaxResult.error("验证码错误"); } return AjaxResult.error("注销账号失败"); } diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 7efb205..9a0fdca 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -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 diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/WeChatConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/WeChatConfig.java new file mode 100644 index 0000000..72cf81f --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/WeChatConfig.java @@ -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; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/OrderInfo.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/OrderInfo.java index be48d40..3187885 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/OrderInfo.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/OrderInfo.java @@ -103,4 +103,7 @@ public class OrderInfo extends BaseEntity /** 乐观锁版本号 */ @Excel(name = "乐观锁版本号") private Long version; + + + private String description; } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java index 93d4e4b..7b7e87a 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java @@ -137,7 +137,7 @@ public class SecurityConfig // /client/index/re/music requests.antMatchers("/login", "/register","/client/shopLogin","/file/download/**", "/captchaImage", "/client/getCode","/client/file/**","/call/back/**","/client/index/getBanner", - "/client/index/getCategory","/client/index/re/bind/music","/client/index/re/music").permitAll() + "/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() diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ShopUserMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ShopUserMapper.java index b544faf..7b2866c 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ShopUserMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ShopUserMapper.java @@ -93,4 +93,6 @@ public interface ShopUserMapper { int updateShopUserId(ShopUser shopUser); int updateDeviceIdByPhone(ShopUserResq shopUser); + + int deleteShopUserByUserId(Long userId); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderInfoService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderInfoService.java index 8d81509..550352a 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderInfoService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderInfoService.java @@ -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 selectOrderInfoVOList(OrderInfo orderInfo); AjaxResult rePayOrder(PaymentRequest request); + + AjaxResult wechatPay(String orderId); + + AjaxResult processPaymentResult(Transaction transaction); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ShopUserService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ShopUserService.java index 94fa2de..51cdd79 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ShopUserService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ShopUserService.java @@ -26,4 +26,6 @@ public interface ShopUserService { ShopUser selectUserById(Long userId); int updateShopUserId(ShopUser shopUser); + + int removeById(Long userId); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CShopUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CShopUserServiceImpl.java index 8ea7bbf..072f335 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CShopUserServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CShopUserServiceImpl.java @@ -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)) { diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderInfoServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderInfoServiceImpl.java index 31a91b6..218ef12 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderInfoServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderInfoServiceImpl.java @@ -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) { diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/util/AppleyPay.java b/ruoyi-system/src/main/java/com/ruoyi/system/util/AppleyPay.java index 675624e..2cf1087 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/util/AppleyPay.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/util/AppleyPay.java @@ -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); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/util/WeChatAppServiceExtensionExample.java b/ruoyi-system/src/main/java/com/ruoyi/system/util/WeChatAppServiceExtensionExample.java index bc3b12b..4f90f26 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/util/WeChatAppServiceExtensionExample.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/util/WeChatAppServiceExtensionExample.java @@ -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); + // } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/util/WeChatPayUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/util/WeChatPayUtil.java new file mode 100644 index 0000000..c4bb620 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/util/WeChatPayUtil.java @@ -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" + + } + +} diff --git a/ruoyi-system/src/main/resources/mapper/system/ShopUserMapper.xml b/ruoyi-system/src/main/resources/mapper/system/ShopUserMapper.xml index 2c0c4b8..47b3f91 100644 --- a/ruoyi-system/src/main/resources/mapper/system/ShopUserMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/ShopUserMapper.xml @@ -269,4 +269,8 @@ #{userId} + + + delete from shop_user where user_id = #{userId} +