250 lines
11 KiB
Java
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;
|
|
}
|
|
}
|