zj
2025-03-12 16805dfa320dfb18587128d699ee809dbee96c0e
第三方充值
4 files modified
6 files added
390 ■■■■■ changed files
src/main/java/com/nq/common/interceptor/ApiUserAuthorityInterceptor.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/controller/protol/UserController.java 46 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/dao/PaymentRechargeMapper.java 9 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/pojo/PaymentRecharge.java 32 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/pojo/PaymentResponse.java 88 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/pojo/RechargeCallbackVo.java 33 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/service/IPayService.java 4 ●●●● patch | view | raw | blame | history
src/main/java/com/nq/service/PaymentRechargeService.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/service/impl/PayServiceImpl.java 146 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/service/impl/PaymentRechargeServiceImpl.java 19 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/common/interceptor/ApiUserAuthorityInterceptor.java
@@ -72,6 +72,12 @@
        if ("/user/pay/flyPay.do".equals(url)) {
            return true;
        }
        if ("/user/thirdPartyRecharge.do".equals(url)) {
            return true;
        }
        if ("/user/rechargeCallback.do".equals(url)) {//支付回调
            return true;
        }
        User currentUser = getCurrentUser(httpServletRequest);
        GoogleTranslateUtil googleTranslateUtil = new GoogleTranslateUtil();
        String lang = httpServletRequest.getHeader("lang");
src/main/java/com/nq/controller/protol/UserController.java
@@ -1,22 +1,26 @@
package com.nq.controller.protol;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.nq.common.ServerResponse;
import com.nq.enums.EStockType;
import com.nq.pojo.ApplyLever;
import com.nq.pojo.StockSubscribe;
import com.nq.pojo.UserStockSubscribe;
import com.nq.pojo.*;
import com.nq.service.*;
import com.nq.service.impl.PayServiceImpl;
import com.nq.utils.PropertiesUtil;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.nq.utils.translate.GoogleTranslateUtil;
import com.nq.vo.stock.UserStockSubscribeAddIn;
import org.apache.ibatis.annotations.Property;
import org.slf4j.Logger;
@@ -61,7 +65,8 @@
    @Autowired
    IUserRechargeService iUserRechargeService;
    @Autowired
    PayServiceImpl payService;
    @Autowired
    IApplyLeverServices iApplyLeverServices;
@@ -71,6 +76,9 @@
    private static final ThreadLocal<Boolean> buyOrderCreated = ThreadLocal.withInitial(() -> false);
    private final Lock buyLock = new ReentrantLock();
    private static final ThreadLocal<Boolean> payCreated = ThreadLocal.withInitial(() -> false);
    private final Lock payLock = new ReentrantLock();
    //添加到自选股
    @RequestMapping({"addOption.do"})
@@ -402,5 +410,35 @@
        return iApplyLeverServices.applyLever(applyLever,request);
    }
    /**
     * 充值第三方支付
     */
    @RequestMapping({"thirdPartyRecharge.do"})
    @ResponseBody
    public ServerResponse thirdPartyRecharge(@RequestParam("tradeAmoun") String tradeAmoun,HttpServletRequest request) {
        payLock.lock();
        try {
            if (payCreated.get()) {
                return ServerResponse.createByErrorMsg("当前充值人数过多,请稍后重试", request);
            }
            payCreated.set(true);
            return payService.thirdPartyRecharge(request,tradeAmoun);
        } catch (Exception e) {
            e.printStackTrace();
            return ServerResponse.createByErrorMsg("获取充值链接异常,请稍后重试", request);
        }  finally{
            payLock.unlock();
            payCreated.set(false);
        }
    }
    /**
     * 充值异步接收地址
     */
    @RequestMapping({"rechargeCallback.do"})
    @ResponseBody
    public void rechargeCallback(HttpServletResponse response,RechargeCallbackVo rechargeCallbackVo) throws IOException {
        payService.rechargeCallback(response,rechargeCallbackVo);
    }
}
src/main/java/com/nq/dao/PaymentRechargeMapper.java
New file
@@ -0,0 +1,9 @@
package com.nq.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.nq.pojo.PaymentRecharge;
import com.nq.pojo.StockDz;
import org.hamcrest.core.Is;
public interface PaymentRechargeMapper extends BaseMapper<PaymentRecharge> {
}
src/main/java/com/nq/pojo/PaymentRecharge.java
New file
@@ -0,0 +1,32 @@
package com.nq.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
 * @program: dabaogp
 * @description: 支付下单
 * @create: 2025-03-12 12:00
 **/
@Data
@TableName("payment_recharge")
public class PaymentRecharge {
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id; // 充值记录的唯一标识符
    private Integer userId; // 用户ID
    private String orderNo; // 订单号
    private String mchOrderNo; // 商家订单号
    private BigDecimal amount; // 充值金额
    private Integer status; // 1:已获取  2.已完成
    private Date paymentTime; // 支付时间
    private Date createdAt; // 记录创建时间
    private String notifyUrl; // 支付平台的回调通知URL
    private String payInfo; // 支付信息
}
src/main/java/com/nq/pojo/PaymentResponse.java
New file
@@ -0,0 +1,88 @@
package com.nq.pojo;
import lombok.Data;
/**
 * @program: dabaogp
 * @description:支付响应
 * @create: 2025-03-12 11:50
 **/
@Data
public class PaymentResponse {
    /**
     * 响应状态
     * - SUCCESS: 响应成功
     * - FAIL: 响应失败
     */
    private String respCode;
    /**
     * 响应失败原因
     * - 仅当respCode为"FAIL"时返回该字段
     */
    private String tradeMsg;
    /**
     * 签名方式
     * - MD5 不参与签名
     */
    private String signType;
    /**
     * 签名
     * - 不参与签名
     */
    private String sign;
    /**
     * 商户号
     * - 唯一标识商户身份的编号
     */
    private String mchId;
    /**
     * 商家订单号
     * - 商家生成的订单号,唯一标识商家的交易
     */
    private String mchOrderNo;
    /**
     * 实际金额
     * - 订单的实际支付金额,单位:元
     * - 与订单金额一致
     */
    private String oriAmount;
    /**
     * 订单金额
     * - 客户订单的原始金额,单位:元
     */
    private String tradeAmount;
    /**
     * 订单时间
     * - 下单时间,格式:yyyyMMddHHmmss
     */
    private String orderDate;
    /**
     * 平台转账单号
     * - 由支付平台生成的唯一转账编号
     */
    private String orderNo;
    /**
     * 下单状态
     * - 1:下单成功
     * - 其他:下单失败
     */
    private String tradeResult;
    /**
     * 付款链接
     * - 当交易成功时返回,供用户跳转付款
     */
    private String payInfo;
}
src/main/java/com/nq/pojo/RechargeCallbackVo.java
New file
@@ -0,0 +1,33 @@
package com.nq.pojo;
import lombok.Data;
/**
 * @program: dabaogp
 * @description: 充值回调
 * @create: 2025-03-12 11:44
 **/
@Data
public class RechargeCallbackVo {
    //订单状态
    private String tradeResult;
    //原始订单金额
    private String oriAmount;
    //交易金额
    private String amount;
    //商户号
    private String mchId;
    //平台支付订单号
    private String orderNo;
    //商家订单号
    private String mchOrderNo;
    //签名
    private String sign;
    //签名方式
    private String signType;
    //订单时间
    private String orderDate;
}
src/main/java/com/nq/service/IPayService.java
@@ -2,8 +2,10 @@
import com.nq.common.ServerResponse;
import com.nq.pojo.RechargeCallbackVo;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@@ -25,4 +27,6 @@
  ServerResponse flyNotify(HttpServletRequest paramHttpServletRequest,String key) throws IOException;
  ServerResponse withdrawNotify(HttpServletRequest paramHttpServletRequest,String key) throws IOException;
    void rechargeCallback(HttpServletResponse response, RechargeCallbackVo rechargeCallbackVo) throws IOException;
}
src/main/java/com/nq/service/PaymentRechargeService.java
New file
@@ -0,0 +1,7 @@
package com.nq.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.nq.pojo.PaymentRecharge;
public interface PaymentRechargeService extends IService<PaymentRecharge> {
}
src/main/java/com/nq/service/impl/PayServiceImpl.java
@@ -1,6 +1,11 @@
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;
import com.nq.common.CmcPayConfig;
import com.nq.common.ServerResponse;
@@ -13,22 +18,29 @@
import com.nq.utils.pay.CmcPayOuterRequestUtil;
import com.nq.utils.pay.CmcPayTool;
import com.nq.utils.timeutil.DateTimeUtil;
import com.nq.utils.translate.GoogleTranslateUtil;
import com.nq.vo.pay.GuoPayVO;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
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;
import net.sf.json.JSONObject;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections.map.LinkedMap;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,12 +75,111 @@
    IUserAssetsServices iUserAssetsServices;
    @Resource
    UserWithdrawMapper userWithdrawMapper;
    UserAssetsMapper userAssetsMapper;
    @Resource
    UserWithdrawMapper userWithdrawMapper;
    @Autowired
    ISiteInfoService siteInfoService;
    @Autowired
    PaymentRechargeService paymentRechargeService;
    public ServerResponse thirdPartyRecharge(HttpServletRequest request, String tradeAmount) throws UnsupportedEncodingException, JsonProcessingException {
        String reqUrl = "https://api.watchglbpay.com/pay/web";
//        User user = userService.getCurrentRefreshUser(request);
//        if(ObjectUtils.isNotEmpty(user)){
//            GoogleTranslateUtil googleTranslateUtil = new GoogleTranslateUtil();
//            String lang = request.getHeader("lang");
//            return ServerResponse.createByErrorMsg(new Gson().toJson(ServerResponse.createByErrorCodeMsg(401,googleTranslateUtil.translate("请登录",lang ))));
//        }
        Map<String, String> params = new TreeMap<String, String>();
        //版本号 需同步返回JSON 必填,固定值 1.0
        params.put("version", "1.0");
        //商品名称
//        params.put("goods_name", "用户:"+user.getId()+",充值");
        params.put("goods_name", "用户充值");
        //商户号  平台分配唯一
        params.put("mch_id", "222887002");
        //商家订单号 保证每笔订单唯一
        params.put("mch_order_no", generatePayOrderId());
        //异步通知地址 不超过 200 字节,支付成功后发起,不能携带参数
        params.put("notify_url", "http://api.durocaspitall.com/user/rechargeCallback.do");
        // 订单时间  时间格式yyyy-MM-dd HH:mm:ss
        params.put("order_date", getOrderTime());
        //支付类型 请查阅商户后台通道编码
        params.put("pay_type", "104");
        //交易金额 以元为单位
        params.put("trade_amount", tradeAmount);
        //商户秘钥必填
        String merchant_key = "8979d78b437948f18c14628ff1ad5f41";
        String signInfo = SignUtil.sortData(params);
        // 签名   signInfo签名参数排序,  merchant_key商户私钥
        String sign = SignAPI.sign(signInfo, merchant_key);
        params.put("sign", sign);
        //固定值 MD5,不参与签名
        params.put("sign_type", "MD5");
        System.out.println("请求参数:" + params.toString());
        String result = HttpClientUtil.doPost(reqUrl, params, "utf-8");
        System.out.println("签名参数排序:" + signInfo.length() + " --> " + signInfo);
        System.out.println("sign值:" + sign.length() + " --> " + sign);
        System.out.println("result值:" + result);
        if(StringUtils.isEmpty(result)){
            return ServerResponse.createByErrorMsg("获取充值链接失败",request);
        }
        // 创建 ObjectMapper 实例
        ObjectMapper objectMapper = new ObjectMapper();
        // 将 JSON 字符串转换为实体类对象
        PaymentResponse payResponse = objectMapper.readValue(result, PaymentResponse.class);
        if(payResponse.getRespCode().equals("FAIL")){
            log.error("充值下单失败:"+result);
            return ServerResponse.createByErrorMsg("获取充值链接失败",request);
        }
        PaymentRecharge paymentRecharge = new PaymentRecharge();
        paymentRecharge.setUserId(1);
        paymentRecharge.setOrderNo(payResponse.getOrderNo());
        paymentRecharge.setMchOrderNo(payResponse.getMchOrderNo());
        paymentRecharge.setAmount(new BigDecimal(payResponse.getOriAmount()));
        paymentRecharge.setStatus(1);
        paymentRecharge.setPaymentTime(DateUtil.parse(payResponse.getOrderDate(),"yyyy-MM-dd HH:mm:ss"));
        paymentRecharge.setCreatedAt(new Date());
        paymentRecharge.setNotifyUrl(payResponse.getPayInfo());
        paymentRecharge.setPayInfo(payResponse.toString());
        paymentRechargeService.save(paymentRecharge);
        return ServerResponse.createBySuccessMsg(result);
    }
    public String generatePayOrderId() {
        // 获取当前时间戳(毫秒)
        long timestamp = System.currentTimeMillis();
        // 生成一个随机的UUID并截取前8位
        String randomUUID = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
        // 将时间戳和随机UUID结合生成订单号
        return timestamp + randomUUID;
    }
    public static String getOrderTime() {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 定义输出格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 格式化当前时间
        return now.format(formatter);
    }
@@ -530,6 +641,39 @@
        return ServerResponse.createByError();
    }
    @Override
    public void rechargeCallback(HttpServletResponse response,RechargeCallbackVo rechargeCallbackVo) throws IOException {
        synchronized (rechargeCallbackVo.getOrderNo()){
            PrintWriter pw = response.getWriter();
            if(!rechargeCallbackVo.getTradeResult().equals("1")){
                log.error("充值回调失败:"+rechargeCallbackVo.toString());
                return;
            }
            PaymentRecharge paymentRecharge = paymentRechargeService.getOne(new LambdaQueryWrapper<>(PaymentRecharge.class)
                    .eq(PaymentRecharge::getOrderNo, rechargeCallbackVo.getOrderNo())
                    .eq(PaymentRecharge::getMchOrderNo, rechargeCallbackVo.getMchOrderNo())
                    .eq(PaymentRecharge::getStatus,1)
                    .last("limit 1")
            );
            if(ObjectUtils.isEmpty(paymentRecharge)){
                pw.print("未找到充值订单");
                return;
            }
            UserAssets userAssets = userAssetsMapper.selectOne(new LambdaQueryWrapper<>(UserAssets.class)
                    .eq(UserAssets::getUserId, paymentRecharge.getUserId())
                    .eq(UserAssets::getAccectType, "IN")
            );
            ServerResponse serverResponse = iUserAssetsServices.updateUserAssets(userAssets.getId(), rechargeCallbackVo.getAmount().toString(), "2");
            if(serverResponse.getStatus() == 0){
                paymentRecharge.setStatus(2);
                paymentRecharge.setAmount(new BigDecimal(rechargeCallbackVo.getAmount()));
                paymentRecharge.setPayInfo(rechargeCallbackVo.toString());
                paymentRechargeService.updateById(paymentRecharge);
            }
            pw.print("success");
        }
    }
    private ServerResponse doSuccess(String orderId, String amount) {
        UserRecharge userRecharge = this.userRechargeMapper.findUserRechargeByOrderSn(orderId);
src/main/java/com/nq/service/impl/PaymentRechargeServiceImpl.java
New file
@@ -0,0 +1,19 @@
package com.nq.service.impl;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nq.dao.FundLogMapper;
import com.nq.dao.PaymentRechargeMapper;
import com.nq.pojo.FundLog;
import com.nq.pojo.PaymentRecharge;
import com.nq.service.PaymentRechargeService;
import org.springframework.stereotype.Service;
/**
 * @program: dabaogp
 * @description:
 * @create: 2025-03-12 13:48
 **/
@Service
public class PaymentRechargeServiceImpl  extends ServiceImpl<PaymentRechargeMapper, PaymentRecharge>  implements PaymentRechargeService {
}