Files
cai-server/ruoyi-cai/src/main/java/com/ruoyi/cai/trdpay/V14Manager.java
2026-01-12 23:17:40 +08:00

250 lines
11 KiB
Java

package com.ruoyi.cai.trdpay;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.domain.PayTrdConfig;
import com.ruoyi.cai.enums.SystemConfigEnum;
import com.ruoyi.cai.manager.SystemConfigManager;
import com.ruoyi.cai.pay.PayManager;
import com.ruoyi.cai.pay.PayOrderInfoDTO;
import com.ruoyi.cai.pay.PayTypeEnum;
import com.ruoyi.cai.service.OrderLogsService;
import com.ruoyi.cai.service.PayTrdConfigService;
import com.ruoyi.cai.trdpay.dto.NotifyResp;
import com.ruoyi.cai.trdpay.dto.extend.V14ExtendMapDTO;
import com.ruoyi.cai.trdpay.dto.v14.NotifyContent;
import com.ruoyi.cai.trdpay.dto.v14.V14Token;
import com.ruoyi.cai.trdpay.dto.v14.wechatJSAPI.WechatJSAPIRequest;
import com.ruoyi.cai.trdpay.dto.v14.wechatJSAPI.WechatJSAPIResponse;
import com.ruoyi.cai.trdpay.dto.v14.wechatJSAPI.WxJsOrderGoods;
import com.ruoyi.cai.trdpay.dto.v14.wechatJSAPI.WxJsOrderInfo;
import com.ruoyi.cai.trdpay.handle.v12new.enums.AsymmetricTypeEnum;
import com.ruoyi.cai.trdpay.handle.v12new.utils.AESUtil;
import com.ruoyi.cai.trdpay.handle.v12new.utils.JacksonUtil;
import com.ruoyi.cai.trdpay.handle.v12new.utils.RSAUtil;
import com.ruoyi.cai.util.OkHttp3Util;
import com.ruoyi.cai.util.RestTemplateUtil;
import com.ruoyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class V14Manager {
@Autowired
private SystemConfigManager systemConfigManager;
@Autowired
private PayTrdConfigService payTrdConfigService;
@Autowired
private OrderLogsService orderLogsService;
@Autowired
private RedissonClient redissonClient;
@Autowired
private PayManager payManager;
private static final String PUBLIC_KEY_PATH = "/home/server/api/sign/v14/EFPS-PublicKey.cer";
private boolean init = false;
private static PrivateKey merchantPrivateKey = null;
public synchronized void init(String privateKeyPath,String privateKeyPassword){
if(!init){
log.info("初始化ETSP SDK privateKeyPath:{} privateKeyPassword:{}", privateKeyPath, privateKeyPassword);
merchantPrivateKey = RSAUtil.getPrivateKeyByPath(privateKeyPath, privateKeyPassword);
init = true;
}
}
public WechatJSAPIResponse pay(PayOrderInfoDTO payOrderInfoDTO, PayTrdConfig payTrdConfig){
String extendData = payTrdConfig.getExtendData();
if(StringUtils.isBlank(extendData)){
throw new ServiceException("参数异常");
}
V14ExtendMapDTO extendMap = JSON.parseObject(extendData, V14ExtendMapDTO.class);
String privateKeyPath = extendMap.getPrivateKeyPath();
String privateKeyPassword = extendMap.getPrivateKeyPassword();
this.init(privateKeyPath, privateKeyPassword);
TrdPayTypeEnum type = TrdPayTypeEnum.V14;
String version = "3.0"; // 版本号
String outTradeNo = payOrderInfoDTO.getOrderNo(); // 交易编号,商户侧唯一
String customerCode = payTrdConfig.getMchId();
long payAmount = payOrderInfoDTO.getPriceFen(); // 支付金额,分为单位
String payCurrency = "CNY"; // 币种,写死
String notifyUrl = payManager.getNotifyUrl(payTrdConfig, type, true);
String transactionStartTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); // 交易开始时间
// String transactionEndTime = ""; // 交易结束时间
WxJsOrderInfo orderInfo = new WxJsOrderInfo();
orderInfo.setId(payOrderInfoDTO.getSubjectId());
orderInfo.setBusinessType("100007");
orderInfo.addGood(new WxJsOrderGoods(payOrderInfoDTO.getSubject(), payOrderInfoDTO.getBody(), payOrderInfoDTO.getPriceFen()));// 填写真实的订单信息如new
WechatJSAPIRequest order = new WechatJSAPIRequest(outTradeNo, customerCode, orderInfo, payAmount, payCurrency,
notifyUrl, transactionStartTime, null);
order.setAppId(extendMap.getMinAppId());
order.setOpenId(payOrderInfoDTO.getOpenId());
order.setNonceStr(RandomUtil.randomString(16));
order.setPayMethod("35");
order.setVersion(version);
order.setChannelMchtNo(extendMap.getLastMchId());
order.setAreaInfo("420100");
Map<String,String> header = new HashMap<>();
header.put("x-efps-sign-no",extendMap.getSignNo());
header.put("x-efps-sign-type","SHA256withRSA");
String requestJson = JacksonUtil.objToJson(order);
String sign = RSAUtil.sign(requestJson, merchantPrivateKey, AsymmetricTypeEnum.RSA);
header.put("x-efps-sign",sign);
header.put("x-efps-timestamp",LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
String gatewayUrl = getGatewayUrl(payTrdConfig);
String createOrderUrl = gatewayUrl + "/api/txs/pay/WxJSAPIPayment";
WechatJSAPIResponse data = getData(payOrderInfoDTO.getOrderNo());
if(data != null){
orderLogsService.createAliPayLogs(payOrderInfoDTO.getOrderNo(), "命中缓存",
JacksonUtil.objToJson(order), JacksonUtil.objToJson(data), false, type, "四方微信支付");
return data;
}
String body = RestTemplateUtil.postJsonData(createOrderUrl, JacksonUtil.objToJson(order), header);
log.info("v14调用支付日志 url:{} body:{} header:{} response:{}", createOrderUrl,JacksonUtil.objToJson(order),JacksonUtil.objToJson(header),body);
WechatJSAPIResponse response = JacksonUtil.jsonToObj(body, WechatJSAPIResponse.class);
if(!response.isSuccess()){
orderLogsService.createAliPayLogs(payOrderInfoDTO.getOrderNo(), createOrderUrl,
JacksonUtil.objToJson(order), body, false, type, "四方微信支付");
throw new ServiceException("调用支付失败");
}
orderLogsService.createAliPayLogs(payOrderInfoDTO.getOrderNo(), createOrderUrl,
JacksonUtil.objToJson(order), body, true, type, "四方微信支付");
this.setRedisData(payOrderInfoDTO.getOrderNo(), response);
return response;
}
public static String REDIS_KEY = "cai:v14:%s";
private String getKey(String orderNo){
return String.format(REDIS_KEY,orderNo);
}
private void setRedisData(String orderNo, WechatJSAPIResponse response){
String redisKey = getKey(orderNo);
RBucket<String> bucket = redissonClient.getBucket(redisKey);
bucket.set(JSON.toJSONString(response),20,TimeUnit.MINUTES);
}
private WechatJSAPIResponse getData(String orderNo){
String redisKey = getKey(orderNo);
RBucket<String> bucket = redissonClient.getBucket(redisKey);
String name = bucket.get();
return JSON.parseObject(name, WechatJSAPIResponse.class);
}
public static void main(String[] args) {
V14Manager v14Manager = new V14Manager();
PayOrderInfoDTO payOrderInfoDTO = new PayOrderInfoDTO();
payOrderInfoDTO.setBody("15钻石");
payOrderInfoDTO.setSubject("15钻石");
payOrderInfoDTO.setSubjectId("1");
payOrderInfoDTO.setPrice(BigDecimal.valueOf(200));
payOrderInfoDTO.setOrderNo("OJSKDJKASDLWBJ22EQKWL123");
payOrderInfoDTO.setOpenId("wx0ca162500b16e82321");
PayTrdConfig config = new PayTrdConfig();
config.setNotifyUrl("https://wewqw.wwiwi.com/ds/asd");
v14Manager.pay(payOrderInfoDTO,config);
}
public String getGatewayUrl(PayTrdConfig payTrdConfig){
TrdPayTypeEnum type = TrdPayTypeEnum.V14;
String gatewayUrl = type.getGatewayUrl();
if (StringUtils.isNotBlank(payTrdConfig.getGatewayUrl())) {
gatewayUrl = payTrdConfig.getGatewayUrl();
}
return gatewayUrl;
}
public String createToken(String orderNo,Long payTrdConfigId,String appId,String secret){
V14Token token = new V14Token();
token.setPayTrdConfigId(payTrdConfigId);
token.setOrderNo(orderNo);
token.setAppId(appId);
token.setSecret(secret);
String uuid = UUID.randomUUID().toString();
RBucket<V14Token> bucket = redissonClient.getBucket(uuid);
bucket.set(token, 40, TimeUnit.MINUTES);
return uuid;
}
public V14Token checkToken(String token){
RBucket<V14Token> bucket = redissonClient.getBucket(token);
return bucket.get();
}
public JSONObject notifyDeal(HttpServletRequest request) throws IOException {
String sign = request.getHeader("x-efps-sign");
BufferedReader br = request.getReader();
String str = "";
StringBuilder wholeStr = new StringBuilder();
while ((str = br.readLine()) != null) {
wholeStr.append(str);
}
String body = wholeStr.toString();
log.info("收到第三方微信支付回调 sign={} {}:{}","V14", sign, wholeStr);
JSONObject jsonObject = new JSONObject();
if (StringUtils.isNotBlank(body) && StringUtils.isNotBlank(sign)) {
boolean verifySign = RSAUtil.verifySign(body, sign, RSAUtil.getPublicKeyByPath(PUBLIC_KEY_PATH), AsymmetricTypeEnum.RSA);
if(!verifySign) {
log.info("v14回调处理失败 验签失败! body={} sign={}", body, sign);
jsonObject.put("returnCode", "0001");
return jsonObject;
}
NotifyContent notify = JSONObject.parseObject(body, NotifyContent.class);
String payState = notify.getPayState();
NotifyResp notifyResp = new NotifyResp();
notifyResp.setOrderNo(notify.getOutTradeNo()); // 商户订单号
notifyResp.setTrdOrderNo(notify.getTransactionNo()); // 平台订单号
notifyResp.setPayTypeEnum(TrdPayTypeEnum.V14);
notifyResp.setSuccess("00".equals(payState));
if(notifyResp.isSuccess()){
JSONObject parse = JSONObject.parse(body);
Map<String,String> javaObject = JsonToMap(parse);
payManager.callBack(notifyResp.getOrderNo(),notifyResp.getTrdOrderNo(),javaObject,notifyResp.getPayTypeEnum().name(), PayTypeEnum.WX);
}
jsonObject.put("returnCode", "0000");
jsonObject.put("returnMsg", "");
return jsonObject;
}
jsonObject.put("returnCode", "0001");
return jsonObject;
}
public static Map<String,String> JsonToMap(JSONObject j){
Map<String,String> map = new HashMap<>();
Set<String> strings = j.keySet();
for (String key : strings) {
Object o = j.get(key);
if(o instanceof String){
map.put(key,(String)o);
}
}
return map;
}
}