This commit is contained in:
777
2025-11-15 13:08:29 +08:00
parent db39c5249e
commit 0c41fdf89d
31 changed files with 1582 additions and 11 deletions

View File

@@ -55,7 +55,9 @@ public class PayTrdConfigController extends BaseController {
@GetMapping("/{id}")
public R<PayTrdConfig> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(payTrdConfigService.getById(id));
PayTrdConfig payTrdConfig = payTrdConfigService.getById(id);
payTrdConfig.refreshSelect();
return R.ok(payTrdConfig);
}
/**
@@ -66,6 +68,7 @@ public class PayTrdConfigController extends BaseController {
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody PayTrdConfig bo) {
bo.refreshUpdateOrSave();
boolean save = payTrdConfigService.save(bo);
payTrdConfigService.resetPayTrdConfig();
return toAjax(save);
@@ -89,6 +92,7 @@ public class PayTrdConfigController extends BaseController {
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PayTrdConfig bo) {
bo.refreshUpdateOrSave();
boolean save = payTrdConfigService.updateById(bo);
payTrdConfigService.resetPayTrdConfig();
return toAjax(save);

View File

@@ -1,12 +1,19 @@
package com.ruoyi.cai.domain;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ruoyi.common.utils.StringUtils;
import lombok.Data;
import org.apache.commons.collections.map.HashedMap;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
/**
* 四方支付配置对象 cai_pay_trd_config
@@ -67,10 +74,28 @@ public class PayTrdConfig implements Serializable {
*/
private Integer deleteFlag;
private String extendData;
@TableField(exist = false)
private Map<String,String> extendMap;
private LocalDateTime createTime;
public String getProductId(boolean wx){
return wx?wxProductId:aliProductId;
}
public void refreshUpdateOrSave(){
if(extendMap != null){
this.extendData = JSON.toJSONString(extendMap);
}
}
public void refreshSelect(){
if(StringUtils.isNotBlank(extendData)){
this.extendMap = JSON.parseObject(this.extendData,Map.class);
}else{
this.extendMap = new HashMap<>();
}
}
}

View File

@@ -27,6 +27,7 @@ public class EncryptionFilter implements Filter {
IGNORE_URL.add("/api/pay/trd/notify/wx/*");
IGNORE_URL.add("/api/pay/trd/notify/ali/*");
IGNORE_URL.add("/api/pay/trd/notify/*");
IGNORE_URL.add("/api/pay/efps/wx");
}
private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();

View File

@@ -184,6 +184,7 @@ public class PayManager {
dto.setOrderNo(vipOrder.getOrderNo());
dto.setAppid(vipOrder.getAppid());
dto.setPlatformType(vipOrder.getPlatformType());
dto.setSubjectId(vipOrder.getVipId()+"");
break;
case RECHARGE_ORDER_SUB:
RechargeOrder rechargeOrder = rechargeOrderService.getByOrderNo(orderNo);
@@ -200,6 +201,7 @@ public class PayManager {
dto.setOrderNo(rechargeOrder.getOrderNo());
dto.setAppid(rechargeOrder.getAppid());
dto.setPlatformType(rechargeOrder.getPlatformType());
dto.setSubjectId(rechargeOrder.getRechargeId()+"");
break;
default:
break;

View File

@@ -9,15 +9,21 @@ import java.math.BigDecimal;
public class PayOrderInfoDTO {
private String body;
private String subject;
private String subjectId;
private BigDecimal price;
private String orderNo;
private String appid;
private String platformType;
private String openId;
public String getPriceFenStr(){
return NumberUtil.mul(price,100).longValue()+"";
}
public Long getPriceFen(){
return NumberUtil.mul(price,100).longValue();
}
public String getPriceYuanStr(){
return price.toString();
}

View File

@@ -1,15 +1,23 @@
package com.ruoyi.cai.pay;
import com.ruoyi.cai.trdpay.handle.v12new.utils.JacksonUtil;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class PayReturnResp {
private String data;
@Schema(description = "H5,APP")
@Schema(description = "H5,APP,DESAN,EFPS")
private String appType;
private String payType;
public static PayReturnResp createEfps(Object data){
PayReturnResp resp = new PayReturnResp();
resp.setData(JacksonUtil.objToJson(data));
resp.setAppType("EFPS");
resp.setPayType("EFPS");
return resp;
}
public static PayReturnResp createDesan(String data){
PayReturnResp resp = new PayReturnResp();

View File

@@ -0,0 +1,9 @@
package com.ruoyi.cai.pay;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
@Data
public class V14PayDTO {
private String wx_code;
}

View File

@@ -135,7 +135,8 @@ public enum TrdPayTypeEnum {
* 1016
* Wsz6yTi6AG5X6Cxt5Zt6rXKGKXitsX5I
*/
V13("https://pp123.bghyvwk.cn","/mapi.php","/api.php","/api/pay/trd/notify/v12","success"),
V13("https://pp123.bghyvwk.cn","/mapi.php","/api.php","/api/pay/trd/notify/v13","success"),
V14("https://efps.epaylinks.cn","/mapi.php","/api.php","/api/pay/trd/notify/v14","success"),
;
private final String gatewayUrl;

View File

@@ -0,0 +1,222 @@
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 = type.getNotifyUrl(payTrdConfig.getNotifyUrl(), 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";
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, "四方微信支付");
return response;
}
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;
}
}

View File

@@ -0,0 +1,15 @@
package com.ruoyi.cai.trdpay.dto.extend;
import lombok.Data;
import java.io.Serializable;
@Data
public class V14ExtendMapDTO implements Serializable {
private String minAppId;
private String minSecret;
private String signNo;
private String lastMchId;
private String privateKeyPath;
private String privateKeyPassword;
}

View File

@@ -0,0 +1,125 @@
package com.ruoyi.cai.trdpay.dto.v14;
import java.util.UUID;
public class NotifyContent {
private String customerCode;
private String outTradeNo;
private String transactionNo;
private String amount;
private String payState;
private String payTime;
private String settCycle;
private String settCycleInterval;
private String procedureFee;
private String attachData;
private String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
public NotifyContent() {
}
public NotifyContent(String customerCode, String outTradeNo, String transactionNo,
String amount, String payState, String payTime, String settCycle,
String settCycleInterval, String procedureFee, String attachData, String nonceStr) {
this.customerCode = customerCode;
this.outTradeNo = outTradeNo;
this.transactionNo = transactionNo;
this.amount = amount;
this.payState = payState;
this.payTime = payTime;
this.settCycle = settCycle;
this.settCycleInterval = settCycleInterval;
this.procedureFee = procedureFee;
this.attachData = attachData;
this.nonceStr = nonceStr;
}
public String getCustomerCode() {
return customerCode;
}
public void setCustomerCode(String customerCode) {
this.customerCode = customerCode;
}
public String getOutTradeNo() {
return outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public String getTransactionNo() {
return transactionNo;
}
public void setTransactionNo(String transactionNo) {
this.transactionNo = transactionNo;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
public String getPayState() {
return payState;
}
public void setPayState(String payState) {
this.payState = payState;
}
public String getPayTime() {
return payTime;
}
public void setPayTime(String payTime) {
this.payTime = payTime;
}
public String getSettCycle() {
return settCycle;
}
public void setSettCycle(String settCycle) {
this.settCycle = settCycle;
}
public String getSettCycleInterval() {
return settCycleInterval;
}
public void setSettCycleInterval(String settCycleInterval) {
this.settCycleInterval = settCycleInterval;
}
public String getProcedureFee() {
return procedureFee;
}
public void setProcedureFee(String procedureFee) {
this.procedureFee = procedureFee;
}
public String getAttachData() {
return attachData;
}
public void setAttachData(String attachData) {
this.attachData = attachData;
}
public String getNonceStr() {
return nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
}

View File

@@ -0,0 +1,53 @@
package com.ruoyi.cai.trdpay.dto.v14;
/**
* @Author : Author
* @Date : 2018/1/29 14:48
* @Description : 下单返回参数封装
*/
public class Response {
/**
* 返回状态码; 0000处理成功; 0000处理成功
*/
private String returnCode;
/**
* 信息
*/
private String returnMsg;
/**
* 打印控制台信息。注意:此属性仅用于页面显示调试信息,实际交易中并不存在
*/
private String consoleMsg;
public boolean isSuccess(){
return "0000".equals(returnCode);
}
public String getReturnCode() {
return returnCode;
}
public void setReturnCode(String returnCode) {
this.returnCode = returnCode;
}
public String getReturnMsg() {
return returnMsg;
}
public void setReturnMsg(String returnMsg) {
this.returnMsg = returnMsg;
}
public String getConsoleMsg() {
return consoleMsg;
}
public void setConsoleMsg(String consoleMsg) {
// this.consoleMsg = consoleMsg;
}
}

View File

@@ -0,0 +1,15 @@
package com.ruoyi.cai.trdpay.dto.v14;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
public class V14PayResp implements Serializable {
private String payToken;
private String orderNo;
private BigDecimal price;
private String subject;
private String sourceMinId = "gh_e126be743731";
}

View File

@@ -0,0 +1,11 @@
package com.ruoyi.cai.trdpay.dto.v14;
import lombok.Data;
@Data
public class V14Token {
private String orderNo;
private Long payTrdConfigId;
private String appId;
private String secret;
}

View File

@@ -0,0 +1,180 @@
package com.ruoyi.cai.trdpay.dto.v14.cashierPay;
public class TerminalInfo {
private String location;
private String network_license;
private String terminal_type;
private String serial_num;
private String terminal_id;//终端设备号
private String encrypt_rand_num;
private String secret_text;
private String app_version;
private String terminal_ip;
private String mobile_country_cd;
private String mobile_net_num;
private String icc_id;
private String location_cd1;
private String lbs_num1;
private String lbs_signal1;
private String location_cd2;
private String lbs_num2;
private String lbs_signal2;
private String location_cd3;
private String lbs_num3;
private String lbs_signal3;
private String telecom_sys_id;
private String telecom_net_id;
private String telecom_lbs;
private String telecom_lbs_signal;
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getNetwork_license() {
return network_license;
}
public void setNetwork_license(String network_license) {
this.network_license = network_license;
}
public String getTerminal_type() {
return terminal_type;
}
public void setTerminal_type(String terminal_type) {
this.terminal_type = terminal_type;
}
public String getSerial_num() {
return serial_num;
}
public void setSerial_num(String serial_num) {
this.serial_num = serial_num;
}
public String getTerminal_id() {
return terminal_id;
}
public void setTerminal_id(String terminal_id) {
this.terminal_id = terminal_id;
}
public String getEncrypt_rand_num() {
return encrypt_rand_num;
}
public void setEncrypt_rand_num(String encrypt_rand_num) {
this.encrypt_rand_num = encrypt_rand_num;
}
public String getSecret_text() {
return secret_text;
}
public void setSecret_text(String secret_text) {
this.secret_text = secret_text;
}
public String getApp_version() {
return app_version;
}
public void setApp_version(String app_version) {
this.app_version = app_version;
}
public String getTerminal_ip() {
return terminal_ip;
}
public void setTerminal_ip(String terminal_ip) {
this.terminal_ip = terminal_ip;
}
public String getMobile_country_cd() {
return mobile_country_cd;
}
public void setMobile_country_cd(String mobile_country_cd) {
this.mobile_country_cd = mobile_country_cd;
}
public String getMobile_net_num() {
return mobile_net_num;
}
public void setMobile_net_num(String mobile_net_num) {
this.mobile_net_num = mobile_net_num;
}
public String getIcc_id() {
return icc_id;
}
public void setIcc_id(String icc_id) {
this.icc_id = icc_id;
}
public String getLocation_cd1() {
return location_cd1;
}
public void setLocation_cd1(String location_cd1) {
this.location_cd1 = location_cd1;
}
public String getLbs_num1() {
return lbs_num1;
}
public void setLbs_num1(String lbs_num1) {
this.lbs_num1 = lbs_num1;
}
public String getLbs_signal1() {
return lbs_signal1;
}
public void setLbs_signal1(String lbs_signal1) {
this.lbs_signal1 = lbs_signal1;
}
public String getLocation_cd2() {
return location_cd2;
}
public void setLocation_cd2(String location_cd2) {
this.location_cd2 = location_cd2;
}
public String getLbs_num2() {
return lbs_num2;
}
public void setLbs_num2(String lbs_num2) {
this.lbs_num2 = lbs_num2;
}
public String getLbs_signal2() {
return lbs_signal2;
}
public void setLbs_signal2(String lbs_signal2) {
this.lbs_signal2 = lbs_signal2;
}
public String getLocation_cd3() {
return location_cd3;
}
public void setLocation_cd3(String location_cd3) {
this.location_cd3 = location_cd3;
}
public String getLbs_num3() {
return lbs_num3;
}
public void setLbs_num3(String lbs_num3) {
this.lbs_num3 = lbs_num3;
}
public String getLbs_signal3() {
return lbs_signal3;
}
public void setLbs_signal3(String lbs_signal3) {
this.lbs_signal3 = lbs_signal3;
}
public String getTelecom_sys_id() {
return telecom_sys_id;
}
public void setTelecom_sys_id(String telecom_sys_id) {
this.telecom_sys_id = telecom_sys_id;
}
public String getTelecom_net_id() {
return telecom_net_id;
}
public void setTelecom_net_id(String telecom_net_id) {
this.telecom_net_id = telecom_net_id;
}
public String getTelecom_lbs() {
return telecom_lbs;
}
public void setTelecom_lbs(String telecom_lbs) {
this.telecom_lbs = telecom_lbs;
}
public String getTelecom_lbs_signal() {
return telecom_lbs_signal;
}
public void setTelecom_lbs_signal(String telecom_lbs_signal) {
this.telecom_lbs_signal = telecom_lbs_signal;
}
}

View File

@@ -0,0 +1,48 @@
package com.ruoyi.cai.trdpay.dto.v14.split;
/**
* @Author : Author
* @Date : 2018/2/6 17:18
*/
public class SplitInfo {
private String customerCode;//分账目标商户在EFPS的客户编码
private long amount;//分账金额,单位分
private Integer isProcedureCustomer;//在分账中必填且保证只有一个客户的该值为1。在包含分账信息的退款中不填。
public SplitInfo() { }
public SplitInfo(String customerCode, long amount) {
this.customerCode = customerCode;
this.amount = amount;
}
public SplitInfo(String customerCode, long amount, Integer isProcedureCustomer) {
this.customerCode = customerCode;
this.amount = amount;
this.isProcedureCustomer = isProcedureCustomer;
}
public String getCustomerCode() {
return customerCode;
}
public void setCustomerCode(String customerCode) {
this.customerCode = customerCode;
}
public Long getAmount() {
return amount;
}
public void setAmount(Long amount) {
this.amount = amount;
}
public Integer getIsProcedureCustomer() {
return isProcedureCustomer;
}
public void setIsProcedureCustomer(Integer isProcedureCustomer) {
this.isProcedureCustomer = isProcedureCustomer;
}
}

View File

@@ -0,0 +1,263 @@
package com.ruoyi.cai.trdpay.dto.v14.wechatJSAPI;
import com.ruoyi.cai.trdpay.dto.v14.cashierPay.TerminalInfo;
import com.ruoyi.cai.trdpay.dto.v14.split.SplitInfo;
import java.util.List;
/**
* @Author : Author
* @Date : 2018/1/29 11:27
* @Description :
*/
public class WechatJSAPIRequest {
private String outTradeNo;
private String customerCode;
private String terminalCode;
private String clientIp;
private WxJsOrderInfo orderInfo;
private long payAmount;
private String payCurrency;
private String version;
private String notifyUrl;
private String attachData;
private String transactionStartTime;
private String transactionEndTime;
private String nonceStr ;
private String appId;
private String openId;
private Boolean needSplit;
private List<SplitInfo> splitInfoList;
private String splitNotifyUrl;
private String splitAttachData;
private String rechargeMemCustCode;
private Boolean noCreditCards;
private String payMethod;
private String channelMchtNo;
public String getChannelMchtNo() {
return channelMchtNo;
}
public void setChannelMchtNo(String channelMchtNo) {
this.channelMchtNo = channelMchtNo;
}
public String getPayMethod() {
return payMethod;
}
public void setPayMethod(String payMethod) {
this.payMethod = payMethod;
}
private TerminalInfo terminalInfo;
private String areaInfo;
public String getAreaInfo() {
return areaInfo;
}
public void setAreaInfo(String areaInfo) {
this.areaInfo = areaInfo;
}
public TerminalInfo getTerminalInfo() {
return terminalInfo;
}
public void setTerminalInfo(TerminalInfo terminalInfo) {
this.terminalInfo = terminalInfo;
}
public WechatJSAPIRequest() {
}
public WechatJSAPIRequest(String outTradeNo, String customerCode,
WxJsOrderInfo orderInfo, long payAmount, String payCurrency, String notifyUrl,
String transactionStartTime, String transactionEndTime) {
this.outTradeNo = outTradeNo;
this.customerCode = customerCode;
this.orderInfo = orderInfo;
this.payAmount = payAmount;
this.payCurrency = payCurrency;
this.notifyUrl = notifyUrl;
this.transactionStartTime = transactionStartTime;
this.transactionEndTime = transactionEndTime;
}
public String getOutTradeNo() {
return outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public String getCustomerCode() {
return customerCode;
}
public void setCustomerCode(String customerCode) {
this.customerCode = customerCode;
}
public String getTerminalCode() {
return terminalCode;
}
public void setTerminalCode(String terminalCode) {
this.terminalCode = terminalCode;
}
public String getClientIp() {
return clientIp;
}
public void setClientIp(String clientIp) {
this.clientIp = clientIp;
}
public WxJsOrderInfo getOrderInfo() {
return orderInfo;
}
public void setOrderInfo(WxJsOrderInfo orderInfo) {
this.orderInfo = orderInfo;
}
public long getPayAmount() {
return payAmount;
}
public void setPayAmount(long payAmount) {
this.payAmount = payAmount;
}
public String getPayCurrency() {
return payCurrency;
}
public void setPayCurrency(String payCurrency) {
this.payCurrency = payCurrency;
}
public String getVersion() {
return version;
}
public void setVersion(String Version) {
this.version = Version;
}
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
public String getAttachData() {
return attachData;
}
public void setAttachData(String attachData) {
this.attachData = attachData;
}
public String getTransactionStartTime() {
return transactionStartTime;
}
public void setTransactionStartTime(String transactionStartTime) {
this.transactionStartTime = transactionStartTime;
}
public String getTransactionEndTime() {
return transactionEndTime;
}
public void setTransactionEndTime(String transactionEndTime) {
this.transactionEndTime = transactionEndTime;
}
public String getNonceStr() {
return nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public Boolean getNeedSplit() {
return needSplit;
}
public void setNeedSplit(Boolean needSplit) {
this.needSplit = needSplit;
}
public List<SplitInfo> getSplitInfoList() {
return splitInfoList;
}
public void setSplitInfoList(List<SplitInfo> splitInfoList) {
this.splitInfoList = splitInfoList;
}
public String getSplitNotifyUrl() {
return splitNotifyUrl;
}
public void setSplitNotifyUrl(String splitNotifyUrl) {
this.splitNotifyUrl = splitNotifyUrl;
}
public String getSplitAttachData() {
return splitAttachData;
}
public void setSplitAttachData(String splitAttachData) {
this.splitAttachData = splitAttachData;
}
public String getRechargeMemCustCode() {
return rechargeMemCustCode;
}
public void setRechargeMemCustCode(String rechargeMemCustCode) {
this.rechargeMemCustCode = rechargeMemCustCode;
}
public Boolean getNoCreditCards() {
return noCreditCards;
}
public void setNoCreditCards(Boolean noCreditCards) {
this.noCreditCards = noCreditCards;
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.cai.trdpay.dto.v14.wechatJSAPI;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.cai.trdpay.dto.v14.Response;
import java.util.List;
public class WechatJSAPIResponse extends Response {
private WxJsapiParam wxJsapiParam;
private String outTradeNo;
private Long amount;
private String nonceStr;
private List<JSONObject> couponDetails;
public WxJsapiParam getWxJsapiParam() {
return this.wxJsapiParam;
}
public void setWxJsapiParam(WxJsapiParam wxJsapiParam) {
this.wxJsapiParam = wxJsapiParam;
}
public String getOutTradeNo() {
return this.outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public Long getAmount() {
return this.amount;
}
public void setAmount(Long amount) {
this.amount = amount;
}
public String getNonceStr() {
return this.nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
public List<JSONObject> getCouponDetails() {
return this.couponDetails;
}
public void setCouponDetails(List<JSONObject> couponDetails) {
this.couponDetails = couponDetails;
}
}

View File

@@ -0,0 +1,22 @@
package com.ruoyi.cai.trdpay.dto.v14.wechatJSAPI;
public class WxJsOrderGoods {
private String name;
private String number;
private long amount;
public WxJsOrderGoods(){ }
public WxJsOrderGoods(String name, String number, long amount) {
this.setName(name);
this.setNumber(number);
this.setAmount(amount);
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getNumber() { return number; }
public void setNumber(String number) { this.number = number; }
public long getAmount() { return amount; }
public void setAmount(long amount) { this.amount = amount; }
}

View File

@@ -0,0 +1,17 @@
package com.ruoyi.cai.trdpay.dto.v14.wechatJSAPI;
import java.util.ArrayList;
import java.util.List;
public class WxJsOrderInfo {
private String id;
private String businessType;
private List<WxJsOrderGoods> goodsList = new ArrayList<WxJsOrderGoods>(10);
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getBusinessType() { return businessType; }
public void setBusinessType(String businessType) { this.businessType = businessType; }
public List<WxJsOrderGoods> getGoodsList() { return goodsList; }
public void setGoodsList(List<WxJsOrderGoods> list) { this.goodsList = list; }
public void addGood(WxJsOrderGoods good) { this.goodsList.add(good); }
}

View File

@@ -0,0 +1,111 @@
package com.ruoyi.cai.trdpay.dto.v14.wechatJSAPI;
import java.util.UUID;
/**
* @Author : Author
* @Date : 2018/1/29 11:27
* @Description :
*/
public class WxJsOrderNotify {
private String customerCode ;//商户在EFPS的编号
private String outTradeNo ;//商户订单号
private String transactionNo ;//EFPS订单号
private Long amount ;//支付金额
private String payState ;//支付结果
private String payTime ;//支付完成时间
private String settCycle ;//该支付交易所属的清算周期
private Long settCycleInterval ;//清算周期长度
private Long procedureFee ;//手续费
private String attachData ;//附加数据
private String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
public String getCustomerCode() {
return customerCode;
}
public void setCustomerCode(String customerCode) {
this.customerCode = customerCode;
}
public String getOutTradeNo() {
return outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public String getTransactionNo() {
return transactionNo;
}
public void setTransactionNo(String transactionNo) {
this.transactionNo = transactionNo;
}
public Long getAmount() {
return amount;
}
public void setAmount(Long amount) {
this.amount = amount;
}
public String getPayState() {
return payState;
}
public void setPayState(String payState) {
this.payState = payState;
}
public String getPayTime() {
return payTime;
}
public void setPayTime(String payTime) {
this.payTime = payTime;
}
public String getSettCycle() {
return settCycle;
}
public void setSettCycle(String settCycle) {
this.settCycle = settCycle;
}
public Long getSettCycleInterval() {
return settCycleInterval;
}
public void setSettCycleInterval(Long settCycleInterval) {
this.settCycleInterval = settCycleInterval;
}
public Long getProcedureFee() {
return procedureFee;
}
public void setProcedureFee(Long procedureFee) {
this.procedureFee = procedureFee;
}
public String getAttachData() {
return attachData;
}
public void setAttachData(String attachData) {
this.attachData = attachData;
}
public String getNonceStr() {
return nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
}

View File

@@ -0,0 +1,82 @@
package com.ruoyi.cai.trdpay.dto.v14.wechatJSAPI;
/* */
/* */ import com.alibaba.fastjson.annotation.JSONField;
/* */
/* */ public class WxJsapiParam {
/* */ private String appId;
/* */
/* */ private String timeStamp;
/* */
/* */ private String nonceStr;
/* */
/* */ private String signType;
/* */
/* */ private String wxPackage;
/* */
/* */ @JSONField(name = "package")
/* */ private String Package;
/* */
/* */ private String paySign;
/* */
/* */ public String getAppId() {
/* 20 */ return this.appId;
/* */ }
/* */
/* */ public void setAppId(String appId) {
/* 23 */ this.appId = appId;
/* */ }
/* */
/* */ public String getTimeStamp() {
/* 26 */ return this.timeStamp;
/* */ }
/* */
/* */ public void setTimeStamp(String timeStamp) {
/* 29 */ this.timeStamp = timeStamp;
/* */ }
/* */
/* */ public String getNonceStr() {
/* 32 */ return this.nonceStr;
/* */ }
/* */
/* */ public void setNonceStr(String nonceStr) {
/* 35 */ this.nonceStr = nonceStr;
/* */ }
/* */
/* */ public String getSignType() {
/* 38 */ return this.signType;
/* */ }
/* */
/* */ public void setSignType(String signType) {
/* 41 */ this.signType = signType;
/* */ }
/* */
/* */ public String getWxPackage() {
/* 44 */ return this.wxPackage;
/* */ }
/* */
/* */ public void setWxPackage(String wxPackage) {
/* 47 */ this.wxPackage = wxPackage;
/* */ }
/* */
/* */ public String getPaySign() {
/* 50 */ return this.paySign;
/* */ }
/* */
/* */ public void setPaySign(String paySign) {
/* 53 */ this.paySign = paySign;
/* */ }
/* */
/* */ public String getPackage() {
/* 57 */ return this.Package;
/* */ }
/* */
/* */ public void setPackage(String aPackage) {
/* 61 */ this.Package = aPackage;
/* */ }
/* */ }
/* Location: D:\1H\更新联调\TXS-6.10.18-3\BOOT-INF\classes\!\com\epaylinks\efps\txs\transaction\domain\wxJSAPI\WxJsapiParam.class
* Java compiler version: 8 (52.0)
* JD-Core Version: 1.1.3
*/

View File

@@ -0,0 +1,60 @@
package com.ruoyi.cai.trdpay.handle;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.domain.PayTrdConfig;
import com.ruoyi.cai.pay.PayOrderInfoDTO;
import com.ruoyi.cai.pay.PayReturnResp;
import com.ruoyi.cai.trdpay.PayTrdService;
import com.ruoyi.cai.trdpay.TrdPayTypeEnum;
import com.ruoyi.cai.trdpay.V14Manager;
import com.ruoyi.cai.trdpay.dto.NotifyResp;
import com.ruoyi.cai.trdpay.dto.extend.V14ExtendMapDTO;
import com.ruoyi.cai.trdpay.dto.v14.V14PayResp;
import com.ruoyi.cai.trdpay.handle.v12new.utils.JacksonUtil;
import com.ruoyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
@Slf4j
public class PayTrdV14Service implements PayTrdService {
@Autowired
private V14Manager v14Manager;
@Override
public TrdPayTypeEnum getType() {
return TrdPayTypeEnum.V14;
}
@Override
public PayReturnResp createOrderAli(PayOrderInfoDTO payOrderInfoDTO, PayTrdConfig payTrdConfig, boolean wx) {
V14PayResp v14PayResp = new V14PayResp();
String extendData = payTrdConfig.getExtendData();
V14ExtendMapDTO extendMap = JSON.parseObject(extendData, V14ExtendMapDTO.class);
v14PayResp.setPayToken(v14Manager.createToken(payOrderInfoDTO.getOrderNo(), payTrdConfig.getId(),extendMap.getMinAppId(),extendMap.getMinSecret()));
v14PayResp.setPrice(payOrderInfoDTO.getPrice());
v14PayResp.setSubject(payOrderInfoDTO.getSubject());
v14PayResp.setOrderNo(payOrderInfoDTO.getOrderNo());
return PayReturnResp.createEfps(v14PayResp);
}
@Override
public NotifyResp getNotifyResp(Map<String, String> sourceData) {
throw new ServiceException("V14回调不走这里");
}
@Override
public JSONObject queryOrder(String orderNo, PayTrdConfig payTrdConfig) {
throw new ServiceException("V14不支持订单查询");
}
@Override
public JSONObject resetOrder(String orderNo, PayTrdConfig payTrdConfig, boolean updateData) {
throw new ServiceException("V14不支持订单查询");
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.cai.util;
import com.ruoyi.cai.trdpay.handle.v12new.utils.JacksonUtil;
import com.squareup.okhttp.logging.HttpLoggingInterceptor;
import okhttp3.*;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class OkHttp3Util {
/**
* 发送 JSON 格式的 POST 请求
* @param url 请求地址
* @param object 请求体对象(将被序列化为 JSON
* @param headers 自定义请求头(可为 null
* @return 响应体字符串
* @throws IOException 当请求失败或序列化出错时抛出
*/
public static String postJsonData(String url, Object object, Map<String, String> headers) throws IOException {
// 1. 将请求对象序列化为 JSON 字符串
String jsonBody = JacksonUtil.objToJson(object);
// 2. 构建 JSON 类型的请求体
RequestBody requestBody = RequestBody.create(jsonBody, MediaType.parse("application/json; charset=utf-8"));
// 3. 构建请求 builder
Request.Builder requestBuilder = new Request.Builder()
.url(url)
.post(requestBody); // 设置 POST 方法和请求体
// 4. 添加自定义请求头(若有)
if (headers != null && !headers.isEmpty()) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
requestBuilder.addHeader(entry.getKey(), entry.getValue());
}
}
// 5. 发送同步请求并获取响应
try (Response response = OK_HTTP_CLIENT.newCall(requestBuilder.build()).execute()) {
// 检查响应状态200-299 为成功)
if (!response.isSuccessful()) {
throw new IOException("请求失败: 状态码=" + response.code() + ", 原因=" + response.message());
}
// 获取响应体注意response.body() 只能调用一次,且需确保非空)
ResponseBody responseBody = response.body();
return responseBody != null ? responseBody.string() : null;
}
}
// 日志拦截器(控制日志打印级别)
private static final HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(
message -> System.out.println("OkHttp Log: " + message) // 日志输出到控制台
);
// 全局 OkHttpClient 实例(单例模式,推荐复用)
private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS) // 连接超时
.readTimeout(15, TimeUnit.SECONDS) // 读取超时
.writeTimeout(15, TimeUnit.SECONDS) // 写入超时
.build();
}

View File

@@ -1,5 +1,12 @@
package com.ruoyi.cai.util;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.cai.trdpay.handle.v12new.utils.JacksonUtil;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
@@ -9,15 +16,20 @@ import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class RestTemplateUtil {
public static RestTemplate restTemplate;
public static RestTemplate restTemplateNoNull;
public static RestTemplate NO_SSL_REST_TEMPLATE;
static {
@@ -34,6 +46,26 @@ public class RestTemplateUtil {
}
}
restTemplateNoNull = new RestTemplate(new BufferingClientHttpRequestFactory(requestFactory));
List<HttpMessageConverter<?>> messageConvertersNoneNull = restTemplate.getMessageConverters();
//添加转换器
for (HttpMessageConverter<?> messageConverter : messageConvertersNoneNull) {
if (messageConverter instanceof StringHttpMessageConverter) {
StringHttpMessageConverter converter = (StringHttpMessageConverter) messageConverter;
converter.setDefaultCharset(StandardCharsets.UTF_8);
}
}
// 替换默认的 Jackson 消息转换器
ObjectMapper objectMapper = new ObjectMapper();
// 只序列化非 null 字段(若需忽略空字符串,需额外处理,见下方扩展)
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
jackson2HttpMessageConverter.setObjectMapper(objectMapper); // 使用自定义的 ObjectMapper
restTemplate.getMessageConverters().removeIf(converter1 ->
converter1 instanceof MappingJackson2HttpMessageConverter
);
restTemplate.getMessageConverters().add(jackson2HttpMessageConverter);
CloseableHttpClient httpClient = null;
try {
httpClient = CustomHttpClient.createClient();
@@ -85,4 +117,16 @@ public class RestTemplateUtil {
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
return NO_SSL_REST_TEMPLATE.postForObject(url, request, String.class);
}
public static String postJsonData(String url, Object object, Map<String,String> header) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
for (Map.Entry<String, String> entry : header.entrySet()) {
headers.add(entry.getKey(),entry.getValue());
}
HttpEntity<Object> request = new HttpEntity<>(object, headers);
return restTemplate.postForObject(url, request, String.class);
}
}