feat:微信支付

This commit is contained in:
dzc committed 2026-03-10 16:42:51 +08:00
1 parent f2b185b731
commit bce4bf9ee3
27 files changed
+1224 -68

No files matched your search

@@ -21,10 +21,46 @@ public class MiniAppConfig {
@Data
public static class WechatConfig {
/**
* 微信公共平台 appId
*/
private String appId;
/**
* 微信公共平台 appSecret
*/
private String appSecret;
/**
* 商户号
*/
private String merchantId;
/**
* 商户证书序列path
*/
private String merchantSerialPath;
/**
* 商户APIV2密钥
*/
private String apiV2Key;
/**
* 退款回调地址
*/
private String refundCallbackUrl;
/**
* 调用ip
*/
private String spbillCreateIp;
/**
* 微信支付接口地址
*/
private String baseUrl;
}
@@ -1,7 +1,9 @@
package com.bsd.pjcloud.thirdparty.controller.oathmini;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMinAppOAth2LoginDto;
import com.bsd.pjcloud.common.security.annotation.Inner;
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppGetUniqueDto;
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppOAth2LoginDto;
import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppService;
import com.bsd.pjcloud.thirdparty.vo.oathmini.ThirdMinAppOAth2LoginVo;
import io.swagger.v3.oas.annotations.Operation;
@@ -20,11 +22,18 @@ public class ThirdMinAppOAth2Cotroller {
private final ThirdMiniAppService thirdMiniAppService;
@Operation(summary = "微信小程序登录")
@Operation(summary = "小程序登录")
@PostMapping("/auto-admin-login")
public R<ThirdMinAppOAth2LoginVo> wechatLogin(@RequestBody ThirdMinAppOAth2LoginDto dto) {
@Inner(value = false)
public R<ThirdMinAppOAth2LoginVo> autoAdminLogin(@RequestBody ThirdMiniAppOAth2LoginDto dto) {
return R.ok(thirdMiniAppService.adminLogin(dto));
}
@Operation(summary = "小程序获取用户唯一编码")
@PostMapping("/get-unique")
@Inner(value = false)
public R<String> getUniqueCode(@RequestBody ThirdMiniAppGetUniqueDto dto) {
return R.ok(thirdMiniAppService.getUniqueCode(dto));
}
}
@@ -1,11 +1,19 @@
package com.bsd.pjcloud.thirdparty.service;
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMinAppOAth2LoginDto;
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppGetUniqueDto;
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppOAth2LoginDto;
import com.bsd.pjcloud.thirdparty.vo.oathmini.ThirdMinAppOAth2LoginVo;
public interface ThirdMiniAppService {
ThirdMinAppOAth2LoginVo adminLogin(ThirdMinAppOAth2LoginDto dto);
/**
* 小程序登录
*/
ThirdMinAppOAth2LoginVo adminLogin(ThirdMiniAppOAth2LoginDto dto);
/**
* 小程序获取用户唯一编码
*/
String getUniqueCode(ThirdMiniAppGetUniqueDto dto);
}
@@ -2,6 +2,18 @@ package com.bsd.pjcloud.thirdparty.service;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechantReverseDto;
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatQueryDto;
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundDto;
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundQueryDto;
import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechantReverseVo;
import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechatQueryVo;
import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechatRefundQueryVo;
import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.ThirdMiniWechatRefundVo;
import org.springframework.http.HttpEntity;
import org.springframework.web.bind.annotation.RequestHeader;
import java.util.Map;
public interface ThirdMiniAppWechatService {
@@ -15,4 +27,29 @@ public interface ThirdMiniAppWechatService {
*/
WxMaPhoneNumberInfo getPhone(String code);
/**
* 查询订单
*/
ThirdMiniWechatQueryVo query(ThirdMiniWechatQueryDto dto);
/**
* 撤销订单
*/
ThirdMiniWechantReverseVo reverse(ThirdMiniWechantReverseDto dto);
/**
* 申请退款
*/
ThirdMiniWechatRefundVo refund(ThirdMiniWechatRefundDto dto);
/**
* 查询退款
*/
ThirdMiniWechatRefundQueryVo refundQuery(ThirdMiniWechatRefundQueryDto dto);
/**
* 退款回调
*/
String refundCallback(HttpEntity<String> httpEntity, @RequestHeader Map<String, String> headers);
}
@@ -6,10 +6,14 @@ import com.bsd.pjcloud.admin.api.dto.UserInfo;
import com.bsd.pjcloud.admin.api.dto.UserTokenDTO;
import com.bsd.pjcloud.admin.api.feign.RemoteTokenService;
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.app.api.constant.AppUserTypeEnum;
import com.bsd.pjcloud.app.api.dto.AppAdminSyncDto;
import com.bsd.pjcloud.app.api.dto.AppUserInfo;
import com.bsd.pjcloud.app.api.feign.RemoteAppUserService;
import com.bsd.pjcloud.thirdparty.constant.miniplatform.MiniPlatformLoginErrorEnum;
import com.bsd.pjcloud.thirdparty.constant.miniplatform.MiniPlatformTypeEnum;
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMinAppOAth2LoginDto;
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppGetUniqueDto;
import com.bsd.pjcloud.thirdparty.dto.oathmini.ThirdMiniAppOAth2LoginDto;
import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppAliPayService;
import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppService;
import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppWechatService;
@@ -19,6 +23,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.net.ssl.*;
import java.util.Map;
/**
@@ -35,28 +40,53 @@ public class ThirdMiniAppServiceImpl implements ThirdMiniAppService {
private final RemoteUserService remoteUserService;
private final RemoteTokenService remoteTokenService;
private final RemoteAppUserService remoteAppUserService;
/**
* 小程序登录
*/
@Override
public ThirdMinAppOAth2LoginVo adminLogin(ThirdMinAppOAth2LoginDto dto) {
public ThirdMinAppOAth2LoginVo adminLogin(ThirdMiniAppOAth2LoginDto dto) {
ThirdMinAppOAth2LoginVo vo = new ThirdMinAppOAth2LoginVo();
// 微信小程序
if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.WECAHT.getType())) {
if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.WECHAT.getType())) {
// 获取手机号
WxMaPhoneNumberInfo phoneInfo = thirdMiniAppWechatService.getPhone(dto.getCode());
WxMaPhoneNumberInfo phoneInfo = thirdMiniAppWechatService.getPhone(dto.getPhoneCode());
if (ObjectUtil.isEmpty(phoneInfo)) {
throw new RuntimeException(MiniPlatformLoginErrorEnum.GET_PHONE_ERROR.getType());
vo.setErrorCode(MiniPlatformLoginErrorEnum.GET_PHONE_ERROR.getType());
return vo;
}
// 根据手机号查询用户
UserInfo userInfo = remoteUserService.getInnerByPhone(phoneInfo.getPurePhoneNumber()).getData();
if (ObjectUtil.isEmpty(userInfo)) {
throw new RuntimeException(MiniPlatformLoginErrorEnum.USER_NOT_EXIST.getType());
vo.setErrorCode(MiniPlatformLoginErrorEnum.USER_NOT_EXIST.getType());
return vo;
}
// 获取用户唯一编号
ThirdMiniAppGetUniqueDto getUniqueDto = new ThirdMiniAppGetUniqueDto();
getUniqueDto.setMiniPlatformType(MiniPlatformTypeEnum.WECHAT);
getUniqueDto.setCode(dto.getPhoneCode());
getUniqueDto.setUserId(userInfo.getSysUser().getUserId());
String uniqueCode = getUniqueCode(getUniqueDto);
// 同步到社交用户
AppAdminSyncDto appAdminSyncDto = new AppAdminSyncDto();
appAdminSyncDto.setUniqueCode(uniqueCode);
appAdminSyncDto.setUserTypeEnum(AppUserTypeEnum.MINI_WECHAT);
appAdminSyncDto.setAdminUserId(userInfo.getSysUser().getUserId());
appAdminSyncDto.setUsername(userInfo.getSysUser().getUsername());
appAdminSyncDto.setAvatarImage(userInfo.getSysUser().getAvatar());
AppUserInfo appUserInfo = remoteAppUserService.syncAdminAccountInfo(appAdminSyncDto).getData();
if (ObjectUtil.isEmpty(appUserInfo)) {
vo.setErrorCode(MiniPlatformLoginErrorEnum.LOGIN_ERROR.getType());
return vo;
}
// 执行登录
UserTokenDTO userTokenDTO = new UserTokenDTO();
userTokenDTO.setSysUser(userInfo.getSysUser());
Map<String, Object> dataMap = (Map<String, Object>) remoteTokenService.generateToken(userTokenDTO).getData();
if (ObjectUtil.isEmpty(dataMap)) {
throw new RuntimeException(MiniPlatformLoginErrorEnum.LOGIN_ERROR.getType());
vo.setErrorCode(MiniPlatformLoginErrorEnum.LOGIN_ERROR.getType());
return vo;
}
vo.setAccessToken(String.valueOf(dataMap.getOrDefault("accessToken", "")));
vo.setRefreshToken(String.valueOf(dataMap.getOrDefault("refreshToken", "")));
@@ -68,4 +98,18 @@ public class ThirdMiniAppServiceImpl implements ThirdMiniAppService {
return vo;
}
/**
* 小程序获取用户唯一编码
*/
@Override
public String getUniqueCode(ThirdMiniAppGetUniqueDto dto) {
String uniqueCode = null;
if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.WECHAT.getType())) {
uniqueCode = thirdMiniAppWechatService.getOpenId(dto.getCode());
} else if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), MiniPlatformTypeEnum.ALI_PAY.getType())) {
}
return uniqueCode;
}
}
@@ -3,14 +3,37 @@ package com.bsd.pjcloud.thirdparty.service.impl.miniapp;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.json.JSONUtil;
import com.bsd.pjcloud.thirdparty.config.MiniAppConfig;
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechantReverseDto;
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatQueryDto;
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundDto;
import com.bsd.pjcloud.thirdparty.dto.oathmini.pay.wechat.ThirdMiniWechatRefundQueryDto;
import com.bsd.pjcloud.thirdparty.service.ThirdMiniAppWechatService;
import com.bsd.pjcloud.thirdparty.utils.miniapp.pay.wechat.ThirdMiniWechantPayConstant;
import com.bsd.pjcloud.thirdparty.vo.oathmini.pay.wechat.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
/**
* 微信小程序(小程序版本)
*/
@@ -20,7 +43,7 @@ import org.springframework.validation.annotation.Validated;
@RequiredArgsConstructor
public class ThirdMiniAppWechatServiceImpl implements ThirdMiniAppWechatService {
private final String TAG = "微信小程序(小程序版本)";
private final String TAG = "微信小程序支付(小程序版本)";
private final MiniAppConfig miniAppConfig;
@@ -62,4 +85,291 @@ public class ThirdMiniAppWechatServiceImpl implements ThirdMiniAppWechatService
}
}
/**
* 查询订单
*/
@Override
public ThirdMiniWechatQueryVo query(ThirdMiniWechatQueryDto dto) {
MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig();
try {
Map<String, Object> params = new HashMap<>();
// 公众账号ID
params.put("appid", wechatConfig.getAppId());
// 商户号
params.put("mch_id", wechatConfig.getMerchantId());
// 微信订单号
params.put("transaction_id", dto.getWechantOrderId());
// 商户订单号
params.put("out_trade_no", dto.getOrderId());
// 随机字符串
params.put("nonce_str", getNonceStr());
// 签名
params.put("sign", "");
// 签名类型
params.put("sign_type", "MD5");
// 生成签名
params.put("sign", generateSign(params));
ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.QUERY);
String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body();
log.debug("查询订单,json,xml|{}", res);
if (ObjectUtil.isEmpty(res)) {
log.error("查询订单,res为空");
return null;
}
ThirdMiniWechatQueryVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechatQueryVo.class);
log.debug("|{}|查询订单,json,res|{}", TAG, JSONUtil.toJsonStr(vo));
if (!vo.isHttpSucess()) {
return null;
}
return vo;
} catch (Exception e) {
log.error("|{}|查询订单,异常", TAG, e);
return null;
}
}
/**
* 撤销订单
*/
@Override
public ThirdMiniWechantReverseVo reverse(ThirdMiniWechantReverseDto dto) {
MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig();
try {
Map<String, Object> params = new HashMap<>();
// 公众账号ID
params.put("appid", wechatConfig.getAppId());
// 商户号
params.put("mch_id", wechatConfig.getMerchantId());
// 微信订单号
params.put("transaction_id", dto.getWechantOrderId());
// 商户订单号
params.put("out_trade_no", dto.getOrderId());
// 随机字符串
params.put("nonce_str", getNonceStr());
// 签名
params.put("sign", "");
// 签名类型
params.put("sign_type", "MD5");
// 生成签名
params.put("sign", generateSign(params));
ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.REVERSE);
api.setSslSocketFactory(createSSLSocketFactory());
String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body();
log.debug("|{}|撤销订单,json,xml|{}", TAG, res);
if (ObjectUtil.isEmpty(res)) {
log.error("|{}|撤销订单,res为空", TAG);
return null;
}
ThirdMiniWechantReverseVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechantReverseVo.class);
log.debug("|{}|撤销订单,json,res|{}", TAG, JSONUtil.toJsonStr(vo));
if (!vo.isHttpSucess()) {
return null;
}
return vo;
} catch (Exception e) {
log.error("|{}|撤销订单,异常", TAG, e);
return null;
}
}
/**
* 申请退款
*/
@Override
public ThirdMiniWechatRefundVo refund(ThirdMiniWechatRefundDto dto) {
MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig();
try {
Map<String, Object> params = new HashMap<>();
// 公众账号ID
params.put("appid", wechatConfig.getAppId());
// 商户号
params.put("mch_id", wechatConfig.getMerchantId());
// 随机字符串
params.put("nonce_str", getNonceStr());
// 签名
params.put("sign", "");
// 签名类型
params.put("sign_type", "MD5");
// 微信支付订单号
params.put("transaction_id", dto.getWechantOrderId());
// 商户订单号
params.put("out_trade_no", dto.getOrderId());
// 商户退款单号
params.put("out_refund_no", dto.getRefundId());
// 订单金额
params.put("total_fee", dto.getOrderPrice());
// 退款金额
params.put("refund_fee", dto.getRefundPrice());
// 退款结果通知url
params.put("notify_url", wechatConfig.getRefundCallbackUrl());
// 生成签名
params.put("sign", generateSign(params));
ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.REFUND);
api.setSslSocketFactory(createSSLSocketFactory());
String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body();
log.debug("|{}|申请退款,json,xml|{}", TAG, res);
if (ObjectUtil.isEmpty(res)) {
log.error("|{}|申请退款,res为空", TAG);
return null;
}
ThirdMiniWechatRefundVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechatRefundVo.class);
log.debug("|{}|申请退款,json,res|{}", TAG, JSONUtil.toJsonStr(vo));
if (!vo.isHttpSucess()) {
return null;
}
return vo;
} catch (Exception e) {
log.error("|{}|申请退款,异常", TAG, e);
return null;
}
}
/**
* 查询退款
*/
@Override
public ThirdMiniWechatRefundQueryVo refundQuery(ThirdMiniWechatRefundQueryDto dto) {
MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig();
try {
Map<String, Object> params = new HashMap<>();
// 公众账号ID
params.put("appid", wechatConfig.getAppId());
// 商户号
params.put("mch_id", wechatConfig.getMerchantId());
// 随机字符串
params.put("nonce_str", getNonceStr());
// 签名
params.put("sign", "");
// 签名类型
params.put("sign_type", "MD5");
// 签名类型
params.put("out_refund_no", dto.getRefundId());
// 生成签名
params.put("sign", generateSign(params));
ThirdMiniWechantPayConstant.Api api = initApi(ThirdMiniWechantPayConstant.REFUND_QUERY);
String res = api.getHttpRequest().body(XmlUtil.mapToXmlStr(params)).execute().body();
log.debug("|{}|查询退款,json,xml|{}", TAG, res);
if (ObjectUtil.isEmpty(res)) {
log.error("|{}|查询退款,res为空", TAG);
return null;
}
ThirdMiniWechatRefundQueryVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(res)), ThirdMiniWechatRefundQueryVo.class);
log.debug("|{}|查询退款,json,res|{}", TAG, JSONUtil.toJsonStr(vo));
if (!vo.isHttpSucess()) {
return null;
}
return vo;
} catch (Exception e) {
log.error("|{}|查询退款,异常", TAG, e);
return null;
}
}
/**
* 退款回调
*/
@Override
public String refundCallback(HttpEntity<String> httpEntity, Map<String, String> headers) {
String body = httpEntity.getBody();
ThirdMiniWechantRefunCallbackVo decrypt = decrypt(body);
if (ObjectUtil.isEmpty(decrypt)) {
// 告诉微信错误
return ThirdMiniWechantRefunCallbackVo.wechantError();
}
boolean isSuccess = true;
return isSuccess ? ThirdMiniWechantRefunCallbackVo.wechantSuccess() : ThirdMiniWechantRefunCallbackVo.wechantError();
}
/**
* 解密回调信息解密
*/
private ThirdMiniWechantRefunCallbackVo decrypt(String xml) {
MiniAppConfig.WechatConfig wechatConfig = miniAppConfig.getWechatConfig();
try {
ThirdMiniWechantRefunCallbackSoureVo vo = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(xml)), ThirdMiniWechantRefunCallbackSoureVo.class);
String reqInfo = vo.getReq_info();
// 1 对加密串A做base64解码,得到加密串B
byte[] encryptedBytes = Base64.decode(reqInfo);
// 2 对商户key做md5,得到32位小写key
String md5Key = DigestUtils.md5Hex(wechatConfig.getApiV2Key()).toLowerCase();
// 3. AES-256-ECB 解密
SecretKeySpec secretKey = new SecretKeySpec(md5Key.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
String json = new String(decryptedBytes, StandardCharsets.UTF_8);
ThirdMiniWechantRefunCallbackVo entity = JSONUtil.toBean(JSONUtil.toJsonStr(XmlUtil.xmlToMap(json)), ThirdMiniWechantRefunCallbackVo.class);
log.debug("|{}|解密回调信息,json|{}", TAG, JSONUtil.toJsonStr(entity));
return entity;
} catch (Exception e) {
e.printStackTrace();
log.error("|{}|解密回调信息解密异常", TAG, e);
return null;
}
}
/**
* 生成微信支付签名
*/
public String generateSign(Map<String, Object> params) {
String apiKey = miniAppConfig.getWechatConfig().getApiV2Key();
Map<String, String> filtered = new TreeMap<>();
for (Map.Entry<String, Object> entry : params.entrySet()) {
if (ObjectUtil.isEmpty(entry.getValue()) || ObjectUtil.equals("sign", entry.getKey())) {
continue;
}
filtered.put(entry.getKey(), String.valueOf(entry.getValue()));
}
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : filtered.entrySet()) {
sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
sb.append("key=").append(apiKey);
try {
String sign = DigestUtils.md5Hex(String.valueOf(sb));
return sign.toUpperCase();
} catch (Exception e) {
log.error("|{}|微信支付签名生成失败", TAG, e);
}
return "";
}
private ThirdMiniWechantPayConstant.Api initApi(ThirdMiniWechantPayConstant.Api api) {
api.setBaseUrl(miniAppConfig.getWechatConfig().getBaseUrl());
return api;
}
private String getNonceStr() {
int length = 32;
return RandomUtil.randomString(length);
}
private SSLSocketFactory createSSLSocketFactory() throws Exception {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream certStream = new FileInputStream(miniAppConfig.getWechatConfig().getMerchantSerialPath());
keyStore.load(certStream, miniAppConfig.getWechatConfig().getMerchantId().toCharArray());
certStream.close();
// 创建KeyManagerFactory
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, miniAppConfig.getWechatConfig().getMerchantId().toCharArray());
// 创建TrustManagerFactory(信任所有证书)
TrustManager[] trustManagers = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// 创建SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagers, new SecureRandom());
return sslContext.getSocketFactory();
}
}
@@ -0,0 +1,67 @@
package com.bsd.pjcloud.thirdparty.utils.miniapp.pay.wechat;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpMethod;
import javax.net.ssl.SSLSocketFactory;
/**
* 微信支付api
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ThirdMiniWechantPayConstant {
public static final Api APY = Api.builder().summary("付款码支付").url("/pay/micropay").method(HttpMethod.POST).isNeedCertificate(false).build();
public static final Api QUERY = Api.builder().summary("查询订单").url("/pay/orderquery").method(HttpMethod.POST).isNeedCertificate(false).build();
public static final Api REVERSE = Api.builder().summary("撤销订单").url("/secapi/pay/reverse").method(HttpMethod.POST).isNeedCertificate(true).build();
public static final Api REFUND = Api.builder().summary("申请退款").url("/secapi/pay/refund").method(HttpMethod.POST).isNeedCertificate(true).build();
public static final Api REFUND_QUERY = Api.builder().summary("查询退款").url("/pay/refundquery").method(HttpMethod.POST).isNeedCertificate(false).build();
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
static public class Api {
private String summary;
private String baseUrl;
private String url;
private String fullUrl;
private HttpMethod method;
private boolean isNeedCertificate = false;
private SSLSocketFactory sslSocketFactory;
public HttpRequest getHttpRequest() {
String fullUrl = baseUrl + url;
HttpRequest req = switch (method.name()) {
case "GET" -> HttpRequest.get(fullUrl);
case "POST" -> HttpRequest.post(fullUrl);
default -> null;
};
if (ObjectUtil.isNotEmpty(req) && ObjectUtil.isNotEmpty(sslSocketFactory) && isNeedCertificate) {
req.setSSLSocketFactory(sslSocketFactory);
}
return req;
}
}
}
@@ -179,5 +179,11 @@ mini-platform:
wechat-config:
app-id: wx11771c7bf2913cb2
app-secret: a6b0d036b229117595687a7c1705d332
merchant-id: 1106210589
api-v2-key: qr0w9WkAu6GG3uuxPjDT7bcdIVoBr0rw
merchant-serial-path: /Users/dengzhangchen/Desktop/backups/pay/cert/apiclient_cert.p12
refund-callback-url: https://rj4jv5rwqs.by.takin.cc/hard/hard-wechant-pay/callback/refund
spbill-create-ip: 59.202.170.152
base-url: https://api.mch.weixin.qq.com
ali-pay-config:
app-id: