zj
2025-04-16 29cf7e39947e2bf5ccef57542041c65f0083aea5
支付通道
9 files modified
6 files added
784 ■■■■ changed files
src/main/java/com/nq/controller/backend/AdminWithDrawController.java 1 ●●●● patch | view | raw | blame | history
src/main/java/com/nq/controller/protol/UserBankController.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/controller/protol/UserController.java 26 ●●●● patch | view | raw | blame | history
src/main/java/com/nq/pojo/ApiResponse.java 26 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/pojo/PaymentCallbackTwo.java 24 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/pojo/PayoutResponse.java 23 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/pojo/TransactionStatusVo.java 21 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/service/IUserBankService.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/service/IUserWithdrawService.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/service/impl/PayServiceImpl.java 121 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/service/impl/UserBankServiceImpl.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/service/impl/UserWithdrawServiceImpl.java 351 ●●●● patch | view | raw | blame | history
src/main/java/com/nq/utils/SignatureGeneratorUtil.java 72 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/utils/UserNameUtil.java 38 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/ws/WebSocketClientBeanConfig.java 52 ●●●● patch | view | raw | blame | history
src/main/java/com/nq/controller/backend/AdminWithDrawController.java
@@ -75,6 +75,7 @@
            serverResponse = this.iUserWithdrawService.updateState(withId, state, authMsg,request,response);
        } catch (Exception e) {
            log.error("admin修改充值订单状态出错 ,异常 = {}", e);
            return ServerResponse.createByErrorMsg("操作失败");
        }
        return serverResponse;
    }
src/main/java/com/nq/controller/protol/UserBankController.java
@@ -11,6 +11,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@@ -27,6 +28,12 @@
        return this.iUserBankService.addBank(bank, request);
    }
    @RequestMapping({"delete.do"})
    @ResponseBody
    public ServerResponse delete(@RequestParam("id") String id, HttpServletRequest request) {
        return this.iUserBankService.delete(id, request);
    }
    //修改银行卡信息
    @RequestMapping({"update.do"})
    @ResponseBody
src/main/java/com/nq/controller/protol/UserController.java
@@ -416,7 +416,7 @@
     */
    @RequestMapping({"thirdPartyRecharge.do"})
    @ResponseBody
    public ServerResponse thirdPartyRecharge(@RequestParam("tradeAmoun") String tradeAmoun,HttpServletRequest request) {
    public ServerResponse thirdPartyRecharge(@RequestParam("tradeAmoun") String tradeAmoun,@RequestParam("type") Integer type,HttpServletRequest request) {
        payLock.lock();
        try {
            if (payCreated.get()) {
@@ -425,11 +425,15 @@
            if (!isIntegerGreaterThan100(tradeAmoun)) {
                return ServerResponse.createByErrorMsg("请输入整数!",request);
            }
            if(null == type){
                return ServerResponse.createByErrorMsg("请选择支付通道!",request);
            }
            if(new BigDecimal(tradeAmoun).compareTo(new BigDecimal("1000")) < 0){
                return ServerResponse.createByErrorMsg("请重新输入,最低充值金额:1000", request);
            }
            payCreated.set(true);
            return payService.thirdPartyRecharge(request,tradeAmoun);
            return payService.thirdPartyRecharge(request,tradeAmoun,type);
        } catch (Exception e) {
            e.printStackTrace();
            return ServerResponse.createByErrorMsg("获取充值链接异常,请稍后重试", request);
@@ -449,11 +453,19 @@
    }
    /**
     * 充值异步接收地址
     * 充值1异步接收地址
     */
    @PostMapping({"rechargeCallback.do"})
    public void rechargeCallback(PaymentResponse vo, HttpServletResponse response) throws IOException {
        payService.rechargeCallback(vo,response);
    }
    /**
     * 充值2异步接收地址
     */
    @PostMapping({"rechargeCallbackTwo.do"})
    public void rechargeCallbackTwo(TransactionStatusVo vo, HttpServletResponse response) throws IOException {
        payService.rechargeCallbackTwo(vo,response);
    }
    /**
@@ -463,4 +475,12 @@
    public void noticePayment(TradeResultVO vo,HttpServletResponse response) throws IOException {
        iUserWithdrawService.noticePayment(vo,response);
    }
    /**
     * 代付2回调通知
     */
    @PostMapping({"noticePaymentTwo.do"})
    public void noticePaymentTwo(PaymentCallbackTwo vo,HttpServletResponse response) throws IOException {
        iUserWithdrawService.noticePaymentTwo(vo,response);
    }
}
src/main/java/com/nq/pojo/ApiResponse.java
New file
@@ -0,0 +1,26 @@
package com.nq.pojo;
import lombok.Data;
/**
 * @program: dabaogp
 * @description: 支付2返回
 * @create: 2025-04-02 17:29
 **/
@Data
public class ApiResponse {
    private int code;
    private String message;
    private ApiResponseData data;
    private int errno;
    @Data
    public static class ApiResponseData {
        private String url;
        private String real_fee;// 实际支付金额
        private String order_number;  // 平台订单号
    }
}
src/main/java/com/nq/pojo/PaymentCallbackTwo.java
New file
@@ -0,0 +1,24 @@
package com.nq.pojo;
import lombok.Data;
/**
 * @program: dabaogp
 * @description: 支付2回调
 * @create: 2025-04-03 11:47
 **/
@Data
public class PaymentCallbackTwo {
    private String order_number;  // 系统订单号
    private String status;        // 状态(交易中:payout_ing,交易成功:payout_success,交易失败:payout_fail)
    private String merchantid;    // 商户号
    private String out_trade_no;  // 商户订单号
    private String total_fee;     // 交易金额
    private String poundage;      // 交易手续费
    private String account_fee;   // 到账金额
    private String fail_info;     // 失败信息
    private String utr;           // UTR回调凭证
    private String sign;          // 签名
}
src/main/java/com/nq/pojo/PayoutResponse.java
New file
@@ -0,0 +1,23 @@
package com.nq.pojo;
import lombok.Data;
/**
 * @program: dabaogp
 * @description: 代付2回调
 * @create: 2025-04-02 18:31
 **/
@Data
public class PayoutResponse {
    private int code;
    private String message;
    private PayoutData data;
    private int errno;
    @Data
    public static class PayoutData {
        private String result;
        private String orderNumber;
    }
}
src/main/java/com/nq/pojo/TransactionStatusVo.java
New file
@@ -0,0 +1,21 @@
package com.nq.pojo;
import lombok.Data;
/**
 * @program: dabaogp
 * @description: 支付2回调   收到回调信息返回小写的success
 * @create: 2025-04-02 17:38
 **/
@Data
public class TransactionStatusVo {
    private String status;        // 状态(payin_ing:交易中;payin_success:交易完成;payin_fail:交易失败)
    private String merchantid;    // 商户号
    private String out_trade_no;    // 商户订单号
    private String total_fee;      // 交易金额(用户实际充值金额)
    private String poundage;      // 交易手续费
    private String account_fee;    // 到账金额
    private String sign;          // 签名
}
src/main/java/com/nq/service/IUserBankService.java
@@ -17,4 +17,6 @@
  ServerResponse updateBankByAdmin(UserBank paramUserBank);
  
  ServerResponse getBank(Integer paramInteger);
  ServerResponse delete(String id, HttpServletRequest request);
}
src/main/java/com/nq/service/IUserWithdrawService.java
@@ -3,6 +3,7 @@
import com.github.pagehelper.PageInfo;
import com.nq.common.ServerResponse;
import com.nq.pojo.PaymentCallbackTwo;
import com.nq.pojo.TradeResultVO;
import com.nq.pojo.UserWithdraw;
@@ -23,8 +24,7 @@
  
  ServerResponse<PageInfo> listByAdmin(Integer paramInteger1, Integer paramInteger2, String paramString1, Integer paramInteger3, String paramString2, String paramString3, HttpServletRequest paramHttpServletRequest, int paramInt1, int paramInt2);
  
  ServerResponse updateState(Integer paramInteger1, Integer paramInteger2, String paramString,
                             HttpServletRequest request, HttpServletResponse response) throws Exception;
  ServerResponse updateState(Integer paramInteger1, Integer paramInteger2, String paramString,HttpServletRequest request, HttpServletResponse response) throws Exception;
  
  int deleteByUserId(Integer paramInteger);
  
@@ -37,4 +37,6 @@
  List<UserWithdraw> exportByAdmin( Integer agentId, Integer userId, String realName, Integer state, String beginTime, String endTime, HttpServletRequest request);
  void noticePayment(TradeResultVO vo, HttpServletResponse response) throws IOException;
  void noticePaymentTwo(PaymentCallbackTwo vo, HttpServletResponse response) throws IOException;
}
src/main/java/com/nq/service/impl/PayServiceImpl.java
@@ -1,9 +1,7 @@
package com.nq.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.cron.timingwheel.SystemTimer;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
@@ -32,7 +30,6 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -86,9 +83,11 @@
    @Autowired
    PaymentRechargeService paymentRechargeService;
    public ServerResponse thirdPartyRecharge(HttpServletRequest request, String tradeAmount) throws UnsupportedEncodingException, JsonProcessingException {
    public ServerResponse thirdPartyRecharge(HttpServletRequest request, String tradeAmount, Integer type) throws UnsupportedEncodingException, JsonProcessingException, NoSuchAlgorithmException {
        // 支付1
        String reqUrl = "https://api.watchglbpay.com/pay/web";
        // 支付2
        String uipReqRul = "https://v2.fastechservicepro.com/payin/unifiedorder";
        User user = userService.getCurrentRefreshUser(request);
        if(ObjectUtils.isEmpty(user)){
@@ -96,6 +95,66 @@
            String lang = request.getHeader("lang");
            return ServerResponse.createByErrorCodeMsg(401,googleTranslateUtil.translate("请登录",lang ));
        }
        if(type == 1){//支付1
            return getPaymentOne(tradeAmount, reqUrl,user,request);
        }else if(type == 2){//支付2
            return getPaymentTwo(tradeAmount, uipReqRul, user,request);
        }
        return ServerResponse.createByErrorMsg("获取支付方式失败",request);
    }
    //支付2
    private ServerResponse getPaymentTwo(String tradeAmount, String uipReqRul, User user, HttpServletRequest request) throws UnsupportedEncodingException, NoSuchAlgorithmException, JsonProcessingException {
        // 示例参数
        Map<String, String> params = new HashMap<>();
        params.put("merchantid", "T805673557385213"); // 商户号
        params.put("out_trade_no", generatePayOrderId()); // 商户订单号
        // 转换为 BigDecimal
        BigDecimal amount = new BigDecimal(tradeAmount);
        // 保留两位小数,四舍五入
        amount = amount.setScale(2, BigDecimal.ROUND_HALF_UP);
        params.put("total_fee", String.valueOf(amount));         // 交易金额(保留两位小数)
        params.put("notify_url", "https://api.durocaspitall.com/user/rechargeCallbackTwo.do"); // 异步通知地址
        params.put("reply_type", "URL");          // 执行方式
        params.put("timestamp", String.valueOf(System.currentTimeMillis()));     // 时间戳
        params.put("customer_name", StringUtils.isEmpty(UserNameUtil.formatCustomerName(user.getNickName())) ? "IsNotSet" : UserNameUtil.formatCustomerName(user.getNickName()));    // 客户姓名
        params.put("customer_mobile", user.getPhone()); // 客户手机号
        params.put("customer_email", "test@gmail.com"); // 客户手机号
        // 生成签名
        String sign = SignatureGeneratorUtil.generateSign(params,"0cfc8e1a446a1e5214b4032f2d6007e2");
        params.put("sign", sign); // 客户邮箱
        // 打印生成的签名
        System.out.println("Generated Sign: " + sign);
        log.info("-------支付2-----:"+params.toString());
        String result = HttpClientUtil.doPost(uipReqRul, params, "utf-8");
        log.info("-------支付2返回参数-----"+result.toString());
        ObjectMapper objectMapper = new ObjectMapper();
        ApiResponse payResponse = objectMapper.readValue(result, ApiResponse.class);
        if(payResponse.getCode() != 0 && !payResponse.getMessage().equals("success")){
            log.error("充值2下单失败:"+params);
            return ServerResponse.createByErrorMsg("获取充值2链接失败",request);
        }
        PaymentRecharge paymentRecharge = new PaymentRecharge();
        paymentRecharge.setUserId(user.getId());
        paymentRecharge.setOrderNo(params.get("out_trade_no"));
        paymentRecharge.setMchOrderNo(payResponse.getData().getOrder_number());
        paymentRecharge.setAmount(new BigDecimal(payResponse.getData().getReal_fee()));
        paymentRecharge.setStatus(1);
        paymentRecharge.setPaymentTime(new Date());
        paymentRecharge.setCreatedAt(new Date());
        paymentRecharge.setNotifyUrl(getOrderTime());
        paymentRecharge.setPayInfo(payResponse.toString());
        paymentRechargeService.save(paymentRecharge);
        return ServerResponse.createBySuccess(payResponse.getData().getUrl());
    }
    //支付1
    private ServerResponse getPaymentOne(String tradeAmount, String reqUrl, User user, HttpServletRequest request) throws JsonProcessingException {
        Map<String, String> params = new TreeMap<String, String>();
        //版本号 需同步返回JSON 必填,固定值 1.0
        params.put("version", "1.0");
@@ -177,8 +236,6 @@
        // 格式化当前时间
        return now.format(formatter);
    }
    public ServerResponse juhe1(String payType, String payAmt, HttpServletRequest request) {
@@ -845,4 +902,54 @@
        return retMap;
    }
    public void rechargeCallbackTwo(TransactionStatusVo vo, HttpServletResponse response) throws IOException {
        log.info("充值回调进来了:"+vo.toString());
        synchronized (vo.getOut_trade_no()){
            PrintWriter pw = response.getWriter();
            PaymentRecharge paymentRecharge = paymentRechargeService.getOne(new LambdaQueryWrapper<>(PaymentRecharge.class)
                    .eq(PaymentRecharge::getMchOrderNo, vo.getOut_trade_no())
                    .eq(PaymentRecharge::getStatus,1)
                    .last("limit 1")
            );
            if(!vo.getStatus().equals("payin_ing")){
                log.error("充值2回调交易中:"+vo.toString());
                return;
            }
            if(!vo.getStatus().equals("payin_fail")){
                paymentRecharge.setStatus(2);
                paymentRecharge.setAmount(new BigDecimal(vo.getAccount_fee()));
                paymentRecharge.setPayInfo(vo.toString());
                paymentRechargeService.updateById(paymentRecharge);
                log.error("充值回调失败:"+vo.toString());
                return;
            }
            if(ObjectUtils.isEmpty(paymentRecharge)){
                log.info("未找到充值订单");
                pw.print("error 未找到充值订单");
                return;
            }
            UserAssets userAssets = userAssetsMapper.selectOne(new LambdaQueryWrapper<>(UserAssets.class)
                    .eq(UserAssets::getUserId, paymentRecharge.getUserId())
                    .eq(UserAssets::getAccectType, "IN")
            );
            ServerResponse serverResponse = iUserAssetsServices.updateUserAssets(userAssets.getId(), vo.getAccount_fee().toString(), "2");
            if(serverResponse.getStatus() == 0){
                paymentRecharge.setStatus(2);
                paymentRecharge.setAmount(new BigDecimal(vo.getAccount_fee()));
                paymentRecharge.setPayInfo(vo.toString());
                paymentRechargeService.updateById(paymentRecharge);
            }
            log.info("充值回调----完成");
            pw.print("success");
            pw.flush();
            pw.close();
        }
    }
}
src/main/java/com/nq/service/impl/UserBankServiceImpl.java
@@ -28,8 +28,9 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
 @Service("iUserBankService")
@Service("iUserBankService")
 public class UserBankServiceImpl extends ServiceImpl<UserBankMapper, UserBank> implements IUserBankService  {
   @Resource
@@ -100,4 +101,15 @@
   public ServerResponse getBank(Integer userId) { return ServerResponse.createBySuccess(this.userBankMapper.selectList(new LambdaQueryWrapper<UserBank>().eq(UserBank::getUserId,userId)));}
   @Override
   public ServerResponse delete(String id, HttpServletRequest request) {
     User user = this.iUserService.getCurrentUser(request);
     UserBank userBank = userBankMapper.selectOne(new LambdaQueryWrapper<>(UserBank.class).eq(UserBank::getId,id).eq(UserBank::getUserId,user.getId()));
     if(ObjectUtils.isEmpty(userBank)){
       return ServerResponse.createByErrorMsg("删除失败,银行卡不存在",request);
     }
     userBankMapper.deleteById(userBank.getId());
     return ServerResponse.createBySuccessMsg("删除成功",request);
   }
 }
src/main/java/com/nq/service/impl/UserWithdrawServiceImpl.java
@@ -6,9 +6,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.nq.dao.*;
import com.nq.enums.EConfigKey;
import com.nq.enums.EUserAssets;
import com.nq.pay.PayUtil;
import com.nq.pojo.*;
import com.nq.service.*;
import com.github.pagehelper.PageHelper;
@@ -19,11 +17,9 @@
import com.nq.utils.*;
import com.nq.utils.http.HttpClientUtil;
import com.nq.utils.stock.WithDrawUtils;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.time.LocalDate;
@@ -35,9 +31,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.nq.utils.timeutil.DateTimeUtil;
import com.nq.utils.timeutil.TimeUtil;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@@ -48,8 +42,6 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
import static com.nq.utils.timeutil.DateTimeUtil.STANDARD_FORMAT;
@Service("iUserWithdrawService")
@@ -343,100 +335,160 @@
    @Transactional
    public ServerResponse updateState(Integer withId, Integer state, String authMsg,
                                      HttpServletRequest request, HttpServletResponse response) throws Exception {
        UserWithdraw userWithdraw = this.userWithdrawMapper.selectByPrimaryKey(withId);
        SiteSetting siteSetting = siteSettingService.getSiteSetting();
        if (userWithdraw == null) {
            return ServerResponse.createByErrorMsg("提现订单不存在");
        }
        log.info("当前系统设置  {}", new Gson().toJson(siteSetting));
        if (userWithdraw.getWithStatus().intValue() != 0) {
            return ServerResponse.createByErrorMsg("提现订单已处理,不要重复操作");
        }
        if (state.intValue() == 3 &&
                StringUtils.isBlank(authMsg)) {
            return ServerResponse.createByErrorMsg("失败信息必填");
        }
        User user = this.userMapper.selectById(userWithdraw.getUserId());
        if (user == null) {
            return ServerResponse.createByErrorMsg("用户不存在");
        }
        UserAssets userAssets = iUserAssetsServices.assetsByTypeAndUserId("IN", user.getId());
        if (userAssets == null) {
            return ServerResponse.createByErrorMsg("用户资金账户不存在");
        }
        if (state == 3) {
            if(userAssets.getAmountToBeCovered().compareTo(BigDecimal.ZERO) > 0){
                BigDecimal subtract = userWithdraw.getWithAmt().subtract(userAssets.getAmountToBeCovered());
                if(subtract.compareTo(BigDecimal.ZERO) > 0){
                    userAssets.setAvailableBalance(userAssets.getAvailableBalance().add(subtract));
                    userAssets.setFreezeMoney(userAssets.getFreezeMoney().subtract(subtract));
                    userAssets.setAmountToBeCovered(BigDecimal.ZERO);
    public ServerResponse updateState(Integer withId, Integer state, String authMsg, HttpServletRequest request, HttpServletResponse response) throws Exception {
        try {
            UserWithdraw userWithdraw = this.userWithdrawMapper.selectByPrimaryKey(withId);
            SiteSetting siteSetting = siteSettingService.getSiteSetting();
            if (userWithdraw == null) {
                return ServerResponse.createByErrorMsg("提现订单不存在");
            }
            log.info("当前系统设置  {}", new Gson().toJson(siteSetting));
            if (userWithdraw.getWithStatus().intValue() != 0) {
                return ServerResponse.createByErrorMsg("提现订单已处理,不要重复操作");
            }
            if (state.intValue() == 3 &&
                    StringUtils.isBlank(authMsg)) {
                return ServerResponse.createByErrorMsg("失败信息必填");
            }
            User user = this.userMapper.selectById(userWithdraw.getUserId());
            if (user == null) {
                return ServerResponse.createByErrorMsg("用户不存在");
            }
            UserAssets userAssets = iUserAssetsServices.assetsByTypeAndUserId("IN", user.getId());
            if (userAssets == null) {
                return ServerResponse.createByErrorMsg("用户资金账户不存在");
            }
            if (state == 3) {
                if(userAssets.getAmountToBeCovered().compareTo(BigDecimal.ZERO) > 0){
                    BigDecimal subtract = userWithdraw.getWithAmt().subtract(userAssets.getAmountToBeCovered());
                    if(subtract.compareTo(BigDecimal.ZERO) > 0){
                        userAssets.setAvailableBalance(userAssets.getAvailableBalance().add(subtract));
                        userAssets.setFreezeMoney(userAssets.getFreezeMoney().subtract(subtract));
                        userAssets.setAmountToBeCovered(BigDecimal.ZERO);
                    }else{
                        userAssets.setAmountToBeCovered(userAssets.getAmountToBeCovered().subtract(userWithdraw.getWithAmt()));
                    }
                }else{
                    userAssets.setAmountToBeCovered(userAssets.getAmountToBeCovered().subtract(userWithdraw.getWithAmt()));
                    userAssets.setAvailableBalance(userAssets.getAvailableBalance().add(userWithdraw.getWithAmt()));
                    userAssets.setFreezeMoney(userAssets.getFreezeMoney().subtract(userWithdraw.getWithAmt()));
                }
            }else{
                userAssets.setAvailableBalance(userAssets.getAvailableBalance().add(userWithdraw.getWithAmt()));
                int updateCount = userAssetsMapper.updateById(userAssets);
                if (updateCount > 0) {
                    log.info("提现失败,返还用户资金成功!");
                } else {
                    log.error("返还用户资金出错,抛出异常");
                    throw new Exception("修改用户资金出错,抛出异常");
                }
                userWithdraw.setWithMsg(authMsg);
                userWithdraw.setWithStatus(2);
                userWithdraw.setTransTime(new Date());
                userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
                return ServerResponse.createBySuccessMsg("操作成功!");
            }else if(state == 2){//手动打款
                userAssets.setFreezeMoney(userAssets.getFreezeMoney().subtract(userWithdraw.getWithAmt()));
                userAssetsMapper.updateById(userAssets);
                userWithdraw.setWithStatus(1);
                userWithdraw.setTransTime(new Date());
                int updateCount = this.userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
                if (updateCount > 0) {
                    return ServerResponse.createBySuccessMsg("操作成功!");
                }
            }else if(state == 1){//走代付
                return getObjectServerResponseOne(withId, request, response, userWithdraw, user, userAssets);
            }else if(state == 4){//代付 2
                return getObjectServerResponseTwo(withId, request, response, userWithdraw, user, userAssets);
            }else{
                return ServerResponse.createBySuccessMsg("请选择对应的操作!");
            }
            int updateCount = userAssetsMapper.updateById(userAssets);
            if (updateCount > 0) {
                log.info("提现失败,返还用户资金成功!");
            } else {
                log.error("返还用户资金出错,抛出异常");
                throw new Exception("修改用户资金出错,抛出异常");
            }
            userWithdraw.setWithMsg(authMsg);
            userWithdraw.setWithStatus(2);
            userWithdraw.setTransTime(new Date());
            userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
        }catch (Exception e){
            log.info("提现失败:"+e.getMessage());
            throw e;
        }
        return ServerResponse.createBySuccessMsg("操作失败!");
    }
    private ServerResponse getObjectServerResponseTwo(Integer withId, HttpServletRequest request, HttpServletResponse response, UserWithdraw userWithdraw, User user, UserAssets userAssets) throws IOException {
        String orderNumber = getOrderTime();
        String result = payForAnOrderTwo(request, response,user, userWithdraw,orderNumber);
        // 创建 ObjectMapper 实例
        ObjectMapper objectMapper = new ObjectMapper();
        // 将 JSON 字符串转换为实体类对象
        PayoutResponse payResponse = objectMapper.readValue(result, PayoutResponse.class);
        if (payResponse.getCode() == 1) {
            log.error("代付打款失败!失败原因:"+payResponse.getMessage());
            return ServerResponse.createByErrorMsg("代付打款失败!失败原因:"+payResponse.getMessage());
        }
        TransferResponse transferResponse = new TransferResponse();
        transferResponse.setRespCode(String.valueOf(payResponse.getCode()));
        transferResponse.setSignType("代付2");
        transferResponse.setSign("代付2");
        transferResponse.setErrorMsg(String.valueOf(payResponse.getErrno()));
        transferResponse.setMerTransferId(orderNumber);
        transferResponse.setTransferAmount(userWithdraw.getWithAmt());
        // 获取当前日期和时间
        LocalDateTime currentDateTime = LocalDateTime.now();
        // 定义日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 将当前时间格式化为字符串
        String formattedDate = currentDateTime.format(formatter);
        transferResponse.setApplyDate(formattedDate);
        transferResponse.setTradeNo(payResponse.getData().getOrderNumber());
        transferResponse.setTradeResult(0);
        transferResponse.setCallbackState(0);
        transferResponse.setUserId(user.getId());
        transferResponse.setCreatedAt(new Date());
        transferResponse.setWithId(withId);
        transferResponseService.save(transferResponse);
        userAssets.setFreezeMoney(userAssets.getFreezeMoney().subtract(userWithdraw.getWithAmt()));
        userAssetsMapper.updateById(userAssets);
        userWithdraw.setWithStatus(4);
        userWithdraw.setTransTime(new Date());
        int updateCount = this.userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
        if (updateCount > 0) {
            return ServerResponse.createBySuccessMsg("操作成功!");
        }else if(state == 2){//手动打款
            userAssets.setFreezeMoney(userAssets.getFreezeMoney().subtract(userWithdraw.getWithAmt()));
            userAssetsMapper.updateById(userAssets);
            userWithdraw.setWithStatus(1);
            userWithdraw.setTransTime(new Date());
            int updateCount = this.userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
            if (updateCount > 0) {
                return ServerResponse.createBySuccessMsg("操作成功!");
            }
        }else if(state == 1){//走代付
            String result = payForAnOrder(request, response, userWithdraw);
            if(StringUtils.isEmpty(result)){
                return ServerResponse.createByErrorMsg("代付打款失败!");
            }
            ObjectMapper objectMapper = new ObjectMapper();
        }
        return ServerResponse.createBySuccessMsg("操作失败!");
    }
            // 将 JSON 字符串转换为实体类对象
            TransferResponseBo transferResponseBo = objectMapper.readValue(result, TransferResponseBo.class);
            if(transferResponseBo.getRespCode().equals("FAIL")){
                log.error("代付下单失败:"+result);
                return ServerResponse.createByErrorMsg("代付下单失败:",request);
            }
            TransferResponse transferResponse = new TransferResponse();
            transferResponse.setRespCode(transferResponseBo.getRespCode());
            transferResponse.setSignType(transferResponseBo.getSignType());
            transferResponse.setSign(transferResponseBo.getSign());
            transferResponse.setMerTransferId(transferResponseBo.getMerTransferId());
            transferResponse.setTransferAmount(new BigDecimal(transferResponseBo.getTransferAmount()));
            transferResponse.setApplyDate(transferResponseBo.getApplyDate());
            transferResponse.setTradeNo(transferResponseBo.getTradeNo());
            transferResponse.setTradeResult(0);
            transferResponse.setCallbackState(0);
            transferResponse.setUserId(user.getId());
            transferResponse.setCreatedAt(new Date());
            transferResponse.setWithId(withId);
            transferResponseService.save(transferResponse);
    private ServerResponse<Object> getObjectServerResponseOne(Integer withId, HttpServletRequest request, HttpServletResponse response, UserWithdraw userWithdraw, User user, UserAssets userAssets) throws IOException {
        String result = payForAnOrder(request, response, userWithdraw);
        if (StringUtils.isEmpty(result)) {
            return ServerResponse.createByErrorMsg("代付打款失败!");
        }
        ObjectMapper objectMapper = new ObjectMapper();
            userAssets.setFreezeMoney(userAssets.getFreezeMoney().subtract(userWithdraw.getWithAmt()));
            userAssetsMapper.updateById(userAssets);
            userWithdraw.setWithStatus(4);
            userWithdraw.setTransTime(new Date());
            int updateCount = this.userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
            if (updateCount > 0) {
                return ServerResponse.createBySuccessMsg("操作成功!");
            }
        // 将 JSON 字符串转换为实体类对象
        TransferResponseBo transferResponseBo = objectMapper.readValue(result, TransferResponseBo.class);
        if(transferResponseBo.getRespCode().equals("FAIL")){
            log.error("代付下单失败:"+result);
            return ServerResponse.createByErrorMsg("代付下单失败:", request);
        }
        TransferResponse transferResponse = new TransferResponse();
        transferResponse.setRespCode(transferResponseBo.getRespCode());
        transferResponse.setSignType(transferResponseBo.getSignType());
        transferResponse.setSign(transferResponseBo.getSign());
        transferResponse.setMerTransferId(transferResponseBo.getMerTransferId());
        transferResponse.setTransferAmount(new BigDecimal(transferResponseBo.getTransferAmount()));
        transferResponse.setApplyDate(transferResponseBo.getApplyDate());
        transferResponse.setTradeNo(transferResponseBo.getTradeNo());
        transferResponse.setTradeResult(0);
        transferResponse.setCallbackState(0);
        transferResponse.setUserId(user.getId());
        transferResponse.setCreatedAt(new Date());
        transferResponse.setWithId(withId);
        transferResponseService.save(transferResponse);
        userAssets.setFreezeMoney(userAssets.getFreezeMoney().subtract(userWithdraw.getWithAmt()));
        userAssetsMapper.updateById(userAssets);
        userWithdraw.setWithStatus(4);
        userWithdraw.setTransTime(new Date());
        int updateCount = this.userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
        if (updateCount > 0) {
            return ServerResponse.createBySuccessMsg("操作成功!");
        }
        return ServerResponse.createBySuccessMsg("操作失败!");
    }
@@ -482,6 +534,37 @@
        return result;
    }
    public String payForAnOrderTwo(HttpServletRequest request, HttpServletResponse response, User user, UserWithdraw userWithdraw, String orderNumber) throws IOException {
        request.setCharacterEncoding("UTF-8");
        // 创建一个Map来存储请求参数
        Map<String, String> reqMap = new HashMap<String, String>();
        // 填充Map参数
        reqMap.put("merchantid", "T805673557385213");             // 商户号
        reqMap.put("out_trade_no",orderNumber );      // 商户订单号
        // 转换为 BigDecimal
        BigDecimal amount = new BigDecimal(String.valueOf(userWithdraw.getWithAmt()));
        // 保留两位小数,四舍五入
        amount = amount.setScale(2, BigDecimal.ROUND_HALF_UP);
        reqMap.put("total_fee", String.valueOf(amount));              // 交易金额(保留两位小数)
        reqMap.put("notify_url", "https://www.example.com/notify"); // 异步通知地址
        reqMap.put("timestamp", String.valueOf(System.currentTimeMillis())); // 时间戳
        reqMap.put("payment_mode", "IMPS");             // 代付模式(IMPS)
        reqMap.put("account_number", userWithdraw.getBankNo());     // 账号
        reqMap.put("ifsc", userWithdraw.getBankName());                 // IFSC
        reqMap.put("customer_name", StringUtils.isEmpty(UserNameUtil.formatCustomerName(user.getNickName())) ? "IsNotSet" : UserNameUtil.formatCustomerName(user.getNickName()));         // 客户姓名(必须是英文,去除空格)
        reqMap.put("customer_mobile", user.getPhone());    // 客户手机号
        reqMap.put("customer_email", "test@gmail.com");    // 客户手机号
        // 生成签名
        String sign = SignatureGeneratorUtil.generateSign(reqMap,"0cfc8e1a446a1e5214b4032f2d6007e2");
        reqMap.put("sign", sign);
        String reqUrl = "https://v2.fastechservicepro.com/payout/unifiedorder";
        String result = HttpClientUtil.doPost(reqUrl, reqMap, "utf-8");
        System.out.println("result值:" + result);
        return result;
    }
    public String generatePayOrderId() {
        // 获取当前时间戳(毫秒)
        long timestamp = System.currentTimeMillis();
@@ -546,13 +629,12 @@
                    .eq(TransferResponse::getTradeResult, 0)
                    .eq(TransferResponse::getCallbackState, 0)
            );
            if(ObjectUtils.isNotEmpty(transferResponse)){
                UserAssets userAssets = iUserAssetsServices.assetsByTypeAndUserId("IN", transferResponse.getUserId());
                UserWithdraw userWithdraw = this.userWithdrawMapper.selectByPrimaryKey(transferResponse.getWithId());
                if (transferResponse.getRespCode().equals("SUCCESS")) {
                if (transferResponse.getRespCode().equals("SUCCESS") && (vo.getTradeResult().equals(1) || vo.getTradeResult().equals("1"))) {
                    transferResponse.setTradeResult(1);
                    transferResponse.setCallbackState(1);
                    transferResponseService.updateById(transferResponse);
@@ -595,7 +677,7 @@
                    } else {
                        log.error("返还用户资金出错,抛出异常");
                    }
                    userWithdraw.setWithMsg("代付验证失败");
                    userWithdraw.setWithMsg("代付验证失败"+",回调信息【"+vo.toString()+"】");
                    userWithdraw.setWithStatus(2);
                    userWithdraw.setTransTime(new Date());
                    userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
@@ -610,6 +692,79 @@
            }
        }
    }
    @Override
    public void noticePaymentTwo(PaymentCallbackTwo vo, HttpServletResponse response) throws IOException {
        log.info("代付回调信息:"+vo.toString());
        synchronized (vo.getOrder_number()){
            TransferResponse transferResponse = transferResponseService.getOne(new LambdaQueryWrapper<>(TransferResponse.class)
                    .eq(TransferResponse::getMerTransferId, vo.getOut_trade_no())
                    .eq(TransferResponse::getTradeNo, vo.getOrder_number())
                    .eq(TransferResponse::getTradeResult, 0)
                    .eq(TransferResponse::getCallbackState, 0)
            );
            if(ObjectUtils.isNotEmpty(transferResponse)){
                UserAssets userAssets = iUserAssetsServices.assetsByTypeAndUserId("IN", transferResponse.getUserId());
                UserWithdraw userWithdraw = this.userWithdrawMapper.selectByPrimaryKey(transferResponse.getWithId());
                if (transferResponse.getRespCode().equals(1) && vo.getStatus().equals("payout_success")) {
                    transferResponse.setTradeResult(1);
                    transferResponse.setCallbackState(1);
                    transferResponseService.updateById(transferResponse);
                    userWithdraw.setWithStatus(1);
                    userWithdraw.setTransTime(new Date());
                    userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
                    log.info("代付回调----成功");
                    PrintWriter pw = response.getWriter();
                    pw.print("success");
                    pw.flush();
                    pw.close(); // 验签成功,响应SUCCESS
                    return;
                } else if(vo.getStatus().equals("payout_fail")){
                    if (userAssets == null) {
                        log.error("用户资金账户不存在!");
                        PrintWriter pw = response.getWriter();
                        pw.print("Signature Error");
                        pw.flush();
                        pw.close();
                        return;
                    }
                    if(userAssets.getAmountToBeCovered().compareTo(BigDecimal.ZERO) > 0){
                        BigDecimal subtract = userWithdraw.getWithAmt().subtract(userAssets.getAmountToBeCovered());
                        if(subtract.compareTo(BigDecimal.ZERO) > 0){
                            userAssets.setAvailableBalance(userAssets.getAvailableBalance().add(subtract));
                            userAssets.setFreezeMoney(userAssets.getFreezeMoney().subtract(subtract));
                            userAssets.setAmountToBeCovered(BigDecimal.ZERO);
                        }else{
                            userAssets.setAmountToBeCovered(userAssets.getAmountToBeCovered().subtract(userWithdraw.getWithAmt()));
                        }
                    }else{
                        userAssets.setAvailableBalance(userAssets.getAvailableBalance().add(userWithdraw.getWithAmt()));
                        userAssets.setFreezeMoney(userAssets.getFreezeMoney().subtract(userWithdraw.getWithAmt()));
                    }
                    int updateCount = userAssetsMapper.updateById(userAssets);
                    if (updateCount > 0) {
                        log.info("提现失败,返还用户资金成功!");
                    } else {
                        log.error("返还用户资金出错,抛出异常");
                    }
                    userWithdraw.setWithMsg("代付2验证失败:"+vo.getFail_info()+",回调信息【"+vo.toString()+"】");
                    userWithdraw.setWithStatus(2);
                    userWithdraw.setTransTime(new Date());
                    userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
                    transferResponse.setTradeResult(2);
                    transferResponse.setCallbackState(2);
                    transferResponseService.updateById(transferResponse);
                    PrintWriter pw = response.getWriter();
                    pw.print("Signature Error");
                    pw.flush();
                    pw.close();
                }
            }
        }
    }
}
src/main/java/com/nq/utils/SignatureGeneratorUtil.java
New file
@@ -0,0 +1,72 @@
package com.nq.utils;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
 * @program: dabaogp
 * @description:  支付2签名
 * @create: 2025-04-02 16:55
 **/
public class SignatureGeneratorUtil {
    /**
     * 签名
     *
     * @param parameter 参数
     * @param secretKey 密钥
     * @return 签名字符串
     */
    public static String generateSign(Map<String, String> parameter, String secretKey) {
        // 移除 'sign' 参数
        parameter.remove("sign");
        // 对参数按照键进行排序
        Map<String, String> sortedParams = new TreeMap<>(parameter);
        StringBuilder signStr = new StringBuilder();
        // 拼接所有参数,格式为 key=value&
        Set<Map.Entry<String, String>> entrySet = sortedParams.entrySet();
        for (Map.Entry<String, String> entry : entrySet) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (value != null && !value.isEmpty()) {
                signStr.append(key).append("=").append(value).append("&");
            }
        }
        // 拼接密钥
        signStr.append("key=").append(secretKey);
        System.out.println(signStr);
        // 生成md5签名并转为小写
        return md5(signStr.toString()).toLowerCase();
    }
    /**
     * 计算 MD5 值
     *
     * @param str 待加密字符串
     * @return MD5 加密后的字符串
     */
    private static String md5(String str) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(str.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : bytes) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
}
src/main/java/com/nq/utils/UserNameUtil.java
New file
@@ -0,0 +1,38 @@
package com.nq.utils;
/**
 * @program: dabaogp
 * @description:
 * @create: 2025-04-02 18:27
 **/
public class UserNameUtil {
    // 去除空格并将非英文字符转换成英文
    public static String formatCustomerName(String customerName) {
        if (customerName == null) {
            return null;  // 如果输入为null,返回null
        }
        // 步骤1: 去除所有空格
        String nameWithoutSpaces = customerName.replaceAll("\\s+", "");
        // 步骤2: 转换所有非英文字符为英文(例如中文转拼音等)
        String formattedName = convertToEnglish(nameWithoutSpaces);
        return formattedName;
    }
    // 假设将所有非英文字符转换为其英文拼音或近似字符
    private static String convertToEnglish(String name) {
        // 这里的转换可以根据具体需要进行调整
        // 例如:假设我们只简单地替换一些常见的中文字符为英文
        name = name.replaceAll("[\\p{IsHan}]", "X"); // 将所有汉字替换为 X
        // 也可以进一步扩展这里的替换规则
        // 例如,处理某些特殊字符:可以做类似下面的替换
        name = name.replaceAll("[^a-zA-Z]", ""); // 删除所有非字母字符
        return name;
    }
}
src/main/java/com/nq/ws/WebSocketClientBeanConfig.java
@@ -17,32 +17,32 @@
public class WebSocketClientBeanConfig {
    @Bean
    public Map<String, WebSocketClient> websocketRunClientMap() {
        Map<String, WebSocketClient> retMap = new HashMap<>(2);
        try {
            WebsocketRunClient websocketRunClient = new WebsocketRunClient(new URI(PropertiesUtil.getProperty("JS_IN_WS_URL")),EStockType.IN);
            websocketRunClient.connect();
            websocketRunClient.setConnectionLostTimeout(0);
            new Thread(() -> {
                while (true) {
                    try {
                        Thread.sleep(8000);
                        websocketRunClient.send("heartbeat".getBytes());
                    } catch (Exception e) {
                        websocketRunClient.reconnect();
                        websocketRunClient.setConnectionLostTimeout(0);
                    }
                }
            }).start();
        } catch (Exception e) {
        }
        return retMap;
    }
//    @Bean
//    public Map<String, WebSocketClient> websocketRunClientMap() {
//
//        Map<String, WebSocketClient> retMap = new HashMap<>(2);
//        try {
//            WebsocketRunClient websocketRunClient = new WebsocketRunClient(new URI(PropertiesUtil.getProperty("JS_IN_WS_URL")),EStockType.IN);
//            websocketRunClient.connect();
//            websocketRunClient.setConnectionLostTimeout(0);
//            new Thread(() -> {
//                while (true) {
//                    try {
//                        Thread.sleep(8000);
//                        websocketRunClient.send("heartbeat".getBytes());
//                    } catch (Exception e) {
//                        websocketRunClient.reconnect();
//                        websocketRunClient.setConnectionLostTimeout(0);
//                    }
//                }
//            }).start();
//        } catch (Exception e) {
//        }
//
//
//
//        return retMap;
//    }
}