微信支付部分
This commit is contained in:
@@ -41,4 +41,6 @@ public class CallBackController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
// }
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付订单
|
||||
*/
|
||||
|
||||
@@ -53,15 +53,17 @@ 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);
|
||||
int delInt = shopUserService.removeById(userId);
|
||||
if (delInt > 0){
|
||||
return AjaxResult.success();
|
||||
}
|
||||
}else {
|
||||
return AjaxResult.error("验证码错误");
|
||||
}
|
||||
}
|
||||
return AjaxResult.error("注销账号失败");
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -103,4 +103,7 @@ public class OrderInfo extends BaseEntity
|
||||
/** 乐观锁版本号 */
|
||||
@Excel(name = "乐观锁版本号")
|
||||
private Long version;
|
||||
|
||||
|
||||
private String description;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -93,4 +93,6 @@ public interface ShopUserMapper {
|
||||
int updateShopUserId(ShopUser shopUser);
|
||||
|
||||
int updateDeviceIdByPhone(ShopUserResq shopUser);
|
||||
|
||||
int deleteShopUserByUserId(Long userId);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -26,4 +26,6 @@ public interface ShopUserService {
|
||||
ShopUser selectUserById(Long userId);
|
||||
|
||||
int updateShopUserId(ShopUser shopUser);
|
||||
|
||||
int removeById(Long userId);
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -269,4 +269,8 @@
|
||||
#{userId}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<delete id="deleteShopUserByUserId">
|
||||
delete from shop_user where user_id = #{userId}
|
||||
</delete>
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user