From 16805dfa320dfb18587128d699ee809dbee96c0e Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Wed, 12 Mar 2025 15:39:12 +0800
Subject: [PATCH] 第三方充值

---
 src/main/java/com/nq/service/PaymentRechargeService.java                 |    7 +
 src/main/java/com/nq/service/IPayService.java                            |    4 
 src/main/java/com/nq/controller/protol/UserController.java               |   46 ++++++
 src/main/java/com/nq/pojo/PaymentRecharge.java                           |   32 ++++
 src/main/java/com/nq/pojo/RechargeCallbackVo.java                        |   33 ++++
 src/main/java/com/nq/service/impl/PaymentRechargeServiceImpl.java        |   19 ++
 src/main/java/com/nq/dao/PaymentRechargeMapper.java                      |    9 +
 src/main/java/com/nq/pojo/PaymentResponse.java                           |   88 ++++++++++++
 src/main/java/com/nq/common/interceptor/ApiUserAuthorityInterceptor.java |    6 
 src/main/java/com/nq/service/impl/PayServiceImpl.java                    |  146 ++++++++++++++++++++
 10 files changed, 385 insertions(+), 5 deletions(-)

diff --git a/src/main/java/com/nq/common/interceptor/ApiUserAuthorityInterceptor.java b/src/main/java/com/nq/common/interceptor/ApiUserAuthorityInterceptor.java
index 9a56c8c..6f7be64 100644
--- a/src/main/java/com/nq/common/interceptor/ApiUserAuthorityInterceptor.java
+++ b/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");
diff --git a/src/main/java/com/nq/controller/protol/UserController.java b/src/main/java/com/nq/controller/protol/UserController.java
index 0b720f5..7baadd5 100644
--- a/src/main/java/com/nq/controller/protol/UserController.java
+++ b/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);
+    }
 }
diff --git a/src/main/java/com/nq/dao/PaymentRechargeMapper.java b/src/main/java/com/nq/dao/PaymentRechargeMapper.java
new file mode 100644
index 0000000..ee55a16
--- /dev/null
+++ b/src/main/java/com/nq/dao/PaymentRechargeMapper.java
@@ -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> {
+}
diff --git a/src/main/java/com/nq/pojo/PaymentRecharge.java b/src/main/java/com/nq/pojo/PaymentRecharge.java
new file mode 100644
index 0000000..e0b5239
--- /dev/null
+++ b/src/main/java/com/nq/pojo/PaymentRecharge.java
@@ -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; // 支付信息
+
+}
diff --git a/src/main/java/com/nq/pojo/PaymentResponse.java b/src/main/java/com/nq/pojo/PaymentResponse.java
new file mode 100644
index 0000000..b2ab37d
--- /dev/null
+++ b/src/main/java/com/nq/pojo/PaymentResponse.java
@@ -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;
+
+}
diff --git a/src/main/java/com/nq/pojo/RechargeCallbackVo.java b/src/main/java/com/nq/pojo/RechargeCallbackVo.java
new file mode 100644
index 0000000..f63f0bf
--- /dev/null
+++ b/src/main/java/com/nq/pojo/RechargeCallbackVo.java
@@ -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;
+
+
+}
diff --git a/src/main/java/com/nq/service/IPayService.java b/src/main/java/com/nq/service/IPayService.java
index 9e42029..e3025c8 100644
--- a/src/main/java/com/nq/service/IPayService.java
+++ b/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;
 }
diff --git a/src/main/java/com/nq/service/PaymentRechargeService.java b/src/main/java/com/nq/service/PaymentRechargeService.java
new file mode 100644
index 0000000..3cd4a2a
--- /dev/null
+++ b/src/main/java/com/nq/service/PaymentRechargeService.java
@@ -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> {
+}
diff --git a/src/main/java/com/nq/service/impl/PayServiceImpl.java b/src/main/java/com/nq/service/impl/PayServiceImpl.java
index e610557..701758b 100644
--- a/src/main/java/com/nq/service/impl/PayServiceImpl.java
+++ b/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);
diff --git a/src/main/java/com/nq/service/impl/PaymentRechargeServiceImpl.java b/src/main/java/com/nq/service/impl/PaymentRechargeServiceImpl.java
new file mode 100644
index 0000000..f8ce4f9
--- /dev/null
+++ b/src/main/java/com/nq/service/impl/PaymentRechargeServiceImpl.java
@@ -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 {
+}

--
Gitblit v1.9.3