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 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 bucket = redissonClient.getBucket(redisKey); bucket.set(JSON.toJSONString(response),20,TimeUnit.MINUTES); } private WechatJSAPIResponse getData(String orderNo){ String redisKey = getKey(orderNo); RBucket 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 bucket = redissonClient.getBucket(uuid); bucket.set(token, 40, TimeUnit.MINUTES); return uuid; } public V14Token checkToken(String token){ RBucket 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 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 JsonToMap(JSONObject j){ Map map = new HashMap<>(); Set strings = j.keySet(); for (String key : strings) { Object o = j.get(key); if(o instanceof String){ map.put(key,(String)o); } } return map; } }