| .gitignore | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| DriverJYXTravel/guns-admin/pom.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| ManagementJYXTravel/guns-admin/lib/upyzt-sdk-1.3.6.jar | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| UserJYXTravel/guns-admin/lib/upyzt-sdk-1.3.6.jar | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| UserJYXTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/account/controller/ElectronicLedgerController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| UserJYXTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/account/req/UserWithdrawalReq.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| UserJYXTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/huifu/biz/DouGongBasicDataBiz.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| UserJYXTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/UserWithdrawal.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| UserJYXTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/RequestSeqUtil.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
.gitignore
@@ -12,7 +12,6 @@ .mtj.tmp/ # Package Files # *.jar *.war *.nar *.ear DriverJYXTravel/guns-admin/pom.xml
@@ -221,7 +221,12 @@ <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <!--斗拱sdk--> <dependency> <groupId>com.huifu.bspay.sdk</groupId> <artifactId>dg-java-sdk</artifactId> <version>3.0.31</version> </dependency> </dependencies> <build> ManagementJYXTravel/guns-admin/lib/upyzt-sdk-1.3.6.jarBinary files differ
UserJYXTravel/guns-admin/lib/upyzt-sdk-1.3.6.jarBinary files differ
UserJYXTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/account/controller/ElectronicLedgerController.java
@@ -3,6 +3,8 @@ import cn.hutool.core.date.DateUnit; import cn.hutool.core.date.DateUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.http.HttpStatus; import cn.hutool.http.HttpUtil; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.stylefeng.guns.core.shiro.ShiroKit; import com.stylefeng.guns.core.util.ToolUtil; @@ -123,10 +125,14 @@ userWithdrawal.setImgUrlOne(userWithdrawalReq.getIdCardReversePicture()); userWithdrawal.setIdCardFrontPicture(userWithdrawalReq.getCopy1()); userWithdrawal.setIdCardReversePicture(userWithdrawalReq.getCopy2()); userWithdrawal.setCusId((String) resultMap.get("huifu_id")); userWithdrawalService.insert(userWithdrawal); //调用汇付业务入驻接口 todo Map<String, Object> map = douGongBasicDataBiz.userBusinessOpen(userWithdrawalReq); Map<String, Object> map = douGongBasicDataBiz.userBusinessOpen(userWithdrawal); if (!"200".equals((String) map.get("resp_code"))){ return ResultUtil.error((String) map.get("resp_desc")); } UserWithdrawal userWithdrawal1 = new UserWithdrawal(); userWithdrawal1.setId(userWithdrawal.getId()); BeanUtils.copyProperties(cusApplicationResp, userWithdrawal1); UserJYXTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/account/req/UserWithdrawalReq.java
@@ -105,6 +105,10 @@ @ApiModelProperty(value = "身份证反面id") private String copy2; @ApiModelProperty(value = "开户行所在省编码") private String bankCardProvinceCode; @ApiModelProperty(value = "开户行所在市编码") private String bankCardCityCode; } UserJYXTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/huifu/biz/DouGongBasicDataBiz.java
@@ -1,6 +1,7 @@ package com.stylefeng.guns.modular.huifu.biz; import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSONObject; import com.google.gson.JsonObject; import com.huifu.bspay.sdk.opps.core.BasePay; import com.huifu.bspay.sdk.opps.core.config.MerConfig; @@ -126,7 +127,7 @@ * @return * @throws Exception */ public Map<String, Object> userBusinessOpen(UserWithdrawalReq userWithdrawalReq) throws Exception { public Map<String, Object> userBusinessOpen(UserWithdrawal userWithdrawal) throws Exception { // 1. 数据初始化,填入对应的商户配置 MerConfig merConfig = new MerConfig(); merConfig.setProcutId(huiFuProperties.getProductId()); @@ -137,21 +138,39 @@ // 2.组装请求参数 Map<String, Object> paramsInfo = new HashMap<>(); // 汇付ID paramsInfo.put("huifu_id", "6666000105765113"); paramsInfo.put("huifu_id", userWithdrawal.getCusId()); // 请求流水号 paramsInfo.put("req_seq_id", RequestSeqUtil.generateForHuiFu()); // 请求日期 paramsInfo.put("req_date", DateUtil.format(new Date(),"yyyyMMdd")); // 渠道商/商户汇付Id paramsInfo.put("upper_huifu_id", "6666000003084836"); // 乐接活配置当合作平台为乐接活,必填 paramsInfo.put("ljh_data", "test"); // 汇薪云配置当合作平台为汇薪云,必填 paramsInfo.put("hxy_data", "test"); // 结算信息配置 paramsInfo.put("settle_config", "{\"settle_cycle\":\"D1\",\"min_amt\":\"0.01\",\"remained_amt\":\"10.00\",\"settle_abstract\":\"结算摘要\",\"out_settle_flag\":\"2\",\"settle_batch_no\":\"300\",\"fixed_ratio\":\"2\"}"); // 结算卡信息 paramsInfo.put("card_info", "{\"card_type\":\"0\",\"card_name\":\"交通银行股份有限公司\",\"card_no\":\"6217001210064762121\",\"prov_id\":\"310000\",\"area_id\":\"310100\",\"branch_code\":\"105305264815\",\"cert_type\":\"00\",\"cert_no\":\"110101197003077513\",\"cert_validity_type\":\"0\",\"cert_begin_date\":\"20210806\",\"cert_end_date\":\"20410806\",\"mp\":\"15556622368\"}"); paramsInfo.put("upper_huifu_id", huiFuProperties.getUpperHuifuId()); //// 结算信息配置 //paramsInfo.put("settle_config", "{\"settle_cycle\":\"D1\",\"min_amt\":\"0.01\",\"remained_amt\":\"10.00\",\"settle_abstract\":\"结算摘要\",\"out_settle_flag\":\"2\",\"settle_batch_no\":\"300\",\"fixed_ratio\":\"2\"}"); //// 结算卡信息 JSONObject cardInfo = new JSONObject(); cardInfo.put("card_type", "1"); cardInfo.put("card_name", userWithdrawal.getBindAcctName()); cardInfo.put("card_no", userWithdrawal.getBankCardCode()); cardInfo.put("prov_id", userWithdrawal.getBankCardProvinceCode()); cardInfo.put("area_id", userWithdrawal.getBankCardCityCode()); cardInfo.put("cert_type", "00"); String[] certificateExpireDateArr = userWithdrawal.getCertificateExpireTime().split(","); String startDateStr = certificateExpireDateArr[0]; // 个人证件有效期开始日期 cardInfo.put("cert_begin_date", startDateStr.replace("-", "")); // 个人证件有效期截止日期 String endDateStr = certificateExpireDateArr[1]; if (!"长期".equals(endDateStr)) { String formatEndDate = endDateStr.replace("-", ""); cardInfo.put("cert_end_date", formatEndDate); // 个人证件有效期类型 cardInfo.put("cert_validity_type", "0"); }else { // 个人证件有效期类型 cardInfo.put("cert_validity_type", "1"); } paramsInfo.put("card_info", cardInfo.toJSONString()); // 3. 发起API调用 Map<String, Object> response = BasePayRequest.requestBasePay("v2/user/busi/open", paramsInfo, null, false);; log.info("用户业务入驻返回参数:" + response); UserJYXTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/UserWithdrawal.java
@@ -151,6 +151,12 @@ @TableField(exist = false) private String code; @ApiModelProperty(value = "开户行所在省编码") private String bankCardProvinceCode; @ApiModelProperty(value = "开户行所在市编码") private String bankCardCityCode; /* @TableField("companyId") @ApiModelProperty(value = "分公司ID") UserJYXTravel/guns-core/src/main/java/com/stylefeng/guns/core/util/RequestSeqUtil.java
New file @@ -0,0 +1,217 @@ package com.stylefeng.guns.core.util; import java.security.SecureRandom; import java.util.concurrent.atomic.AtomicLong; /** * 请求流水号生成工具类 * * <p>用于生成32位唯一请求流水号,格式:[前缀2位][日期8位][时间6位][毫秒3位][序列号13位]</p> * <p>示例:rQ202511141540078404299875651</p> * * <p>特性:</p> * <ul> * <li>线程安全:使用AtomicLong保证高并发环境下的唯一性</li> * <li>高性能:避免重复创建对象,优化内存使用</li> * <li>可配置:支持自定义前缀适应不同业务场景</li> * <li>高可靠:时间戳+随机数+序列号三重保障唯一性</li> * </ul> * * @author harley * @since 2025-11-14 */ public class RequestSeqUtil { /** * 默认前缀 */ private static final String DEFAULT_PREFIX = "RQ"; /** * 序列号生成器,保证线程安全 */ private static final AtomicLong SEQUENCE_GENERATOR = new AtomicLong(0); /** * 安全随机数生成器 */ private static final SecureRandom SECURE_RANDOM = new SecureRandom(); /** * 流水号总长度 */ private static final int TOTAL_LENGTH = 32; /** * 前缀长度 */ private static final int PREFIX_LENGTH = 2; /** * 日期长度 (yyyyMMdd) */ private static final int DATE_LENGTH = 8; /** * 时间长度 (HHmmss) */ private static final int TIME_LENGTH = 6; /** * 毫秒长度 */ private static final int MILLIS_LENGTH = 3; /** * 序列号长度 */ private static final int SEQUENCE_LENGTH = 13; /** * 私有构造函数,防止实例化 */ private RequestSeqUtil() { throw new UnsupportedOperationException("工具类不允许实例化"); } /** * 生成默认前缀的32位请求流水号 * * @return 32位请求流水号,格式:RQ + 时间信息 + 序列号 */ public static String generate() { return generate(DEFAULT_PREFIX); } /** * 生成指定前缀的32位请求流水号 * * <p>流水号格式:[前缀2位][日期8位][时间6位][毫秒3位][序列号13位]</p> * <p>示例:rQ202511141540078404299875651</p> * * @param prefix 自定义前缀,建议2位字符 * @return 32位请求流水号 * @throws IllegalArgumentException 当前缀为空或长度不符合要求时抛出 */ public static String generate(String prefix) { // 参数校验 if (prefix == null || prefix.isEmpty()) { throw new IllegalArgumentException("前缀不能为空"); } if (prefix.length() != PREFIX_LENGTH) { throw new IllegalArgumentException("前缀长度必须为" + PREFIX_LENGTH + "位"); } long currentTime = System.currentTimeMillis(); // 构建流水号各个部分 String datePart = DateUtil.format(new java.util.Date(currentTime), "yyyyMMdd"); String timePart = DateUtil.format(new java.util.Date(currentTime), "HHmmss"); String millisPart = String.format("%03d", currentTime % 1000); // 生成序列号(时间戳后7位 + 随机数6位) long sequence = SEQUENCE_GENERATOR.incrementAndGet(); String sequencePart = String.format("%013d", Math.abs(sequence % 1000000000000L)); // 组装完整的流水号 StringBuilder seqBuilder = new StringBuilder(TOTAL_LENGTH); seqBuilder.append(prefix) .append(datePart) .append(timePart) .append(millisPart) .append(sequencePart); return seqBuilder.toString(); } /** * 生成带业务标识的流水号 * * <p>常用的业务前缀:</p> * <ul> * <li>rQ - 汇付请求</li> * <li>OR - 订单业务</li> * <li>PY - 支付业务</li> * <li>RF - 退款业务</li> * </ul> * * @param businessCode 业务代码前缀 * @return 32位业务流水号 */ public static String generateForBusiness(String businessCode) { return generate(businessCode); } /** * 生成汇付相关的请求流水号 * * @return 以"rQ"为前缀的32位流水号 */ public static String generateForHuiFu() { return generate("rQ"); } /** * 验证流水号格式是否正确 * * @param sequence 要验证的流水号 * @return 验证结果 */ public static boolean isValid(String sequence) { if (sequence == null || sequence.length() != TOTAL_LENGTH) { return false; } // 验证时间部分格式(第3-16位应该是数字) String timePart = sequence.substring(2, 16); if (!timePart.matches("\\d+")) { return false; } // 验证最后13位序列号是否为数字 String sequencePart = sequence.substring(19); if (!sequencePart.matches("\\d+")) { return false; } return true; } /** * 从流水号中提取前缀 * * @param sequence 流水号 * @return 流水号前缀 */ public static String extractPrefix(String sequence) { if (sequence == null || sequence.length() < PREFIX_LENGTH) { return null; } return sequence.substring(0, PREFIX_LENGTH); } /** * 从流水号中提取时间信息 * * @param sequence 流水号 * @return 格式化的时间字符串,格式:yyyy-MM-dd HH:mm:ss.SSS */ public static String extractDateTime(String sequence) { if (!isValid(sequence)) { return null; } String dateStr = sequence.substring(2, 10); // yyyyMMdd String timeStr = sequence.substring(10, 16); // HHmmss String millisStr = sequence.substring(16, 19); // 毫秒 return dateStr.substring(0, 4) + "-" + dateStr.substring(4, 6) + "-" + dateStr.substring(6, 8) + " " + timeStr.substring(0, 2) + ":" + timeStr.substring(2, 4) + ":" + timeStr.substring(4, 6) + "." + millisStr; } }