| | |
| | | |
| | | import cn.hutool.core.date.DateUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.ruoyi.common.core.controller.BaseController; |
| | | import com.ruoyi.common.core.domain.AjaxResult; |
| | |
| | | import com.ruoyi.im.util.RedisDistributedLock; |
| | | import com.ruoyi.im.util.UserPolicyUtils; |
| | | import com.ruoyi.system.domain.*; |
| | | import com.ruoyi.system.domain.dto.PayCallbackDTO; |
| | | import com.ruoyi.system.domain.dto.UserPolicyDto; |
| | | import com.ruoyi.im.service.UserPolicyService; |
| | | import com.ruoyi.system.service.UserAccountService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.transaction.interceptor.TransactionAspectSupport; |
| | | import org.springframework.util.CollectionUtils; |
| | |
| | | import javax.validation.Valid; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.security.MessageDigest; |
| | | import java.security.NoSuchAlgorithmException; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.*; |
| | |
| | | |
| | | @RestController |
| | | @RequestMapping("/userPolicy") |
| | | @Slf4j |
| | | public class UserPolicyController extends BaseController { |
| | | |
| | | @Autowired |
| | |
| | | InsuranceProductService insuranceProductService; |
| | | @Autowired |
| | | private PayService payService; |
| | | |
| | | @Value("${pay.key}") |
| | | private String key; |
| | | |
| | | /** |
| | | * 保险购买申请 |
| | |
| | | wrapper.ne(UserPolicy::getApprovalStatus, 0); |
| | | }else{ |
| | | wrapper.eq(UserPolicy::getApprovalStatus, 0); |
| | | wrapper.eq(UserPolicy::getPayStatus,3) |
| | | .or() |
| | | .eq(UserPolicy::getPayStatus,2); |
| | | wrapper.eq(UserPolicy::getPayStatus,2); |
| | | } |
| | | |
| | | // 按创建时间倒序排列 |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 支付回调接口 - 支付平台会调用这个接口 |
| | | */ |
| | | @PostMapping("/notify") |
| | | public String payNotify(@RequestParam Map<String, String> params) { |
| | | System.out.println("收到支付回调: " + params); |
| | | public String payNotify(@RequestBody PayCallbackDTO callbackDTO) { |
| | | try { |
| | | log.info("收到支付回调通知: {}", JSON.toJSONString(callbackDTO)); |
| | | |
| | | // 验证签名 |
| | | if (!payService.verifySign(params)) { |
| | | System.out.println("签名验证失败"); |
| | | return "fail"; |
| | | // 1. 验证签名 |
| | | if (!verifySign(callbackDTO)) { |
| | | log.error("签名验证失败: {}", callbackDTO.getOrderId()); |
| | | return "签名验证失败"; |
| | | } |
| | | |
| | | // 2. 根据订单号查询保单 |
| | | UserPolicy userPolicy = userPolicyService.getOne(new LambdaQueryWrapper<UserPolicy>() |
| | | .eq(UserPolicy::getOrderNo, callbackDTO.getOrderId())); |
| | | if (userPolicy == null) { |
| | | log.error("订单不存在: {}", callbackDTO.getOrderId()); |
| | | return "订单不存在"; |
| | | } |
| | | if(userPolicy.getPayStatus() == 2){ |
| | | log.error("订单已支付完成: {}", callbackDTO.getOrderId()); |
| | | return "订单已支付完成"; |
| | | } |
| | | // 3. 根据订单状态处理业务逻辑 |
| | | boolean processResult = processPayResult(callbackDTO, userPolicy); |
| | | |
| | | return processResult ? "success" : "fail"; |
| | | |
| | | } catch (Exception e) { |
| | | log.error("支付回调处理异常: {}", e.getMessage(), e); |
| | | return "FAIL"; |
| | | } |
| | | |
| | | // 获取关键参数 |
| | | String orderNo = params.get("mchOrderNo"); |
| | | String status = params.get("status"); |
| | | String amount = params.get("amount"); |
| | | |
| | | System.out.println("订单号: " + orderNo + ", 状态: " + status + ", 金额: " + amount); |
| | | |
| | | // 这里调用您的业务处理逻辑 |
| | | handlePayResult(orderNo, Integer.valueOf(status), params); |
| | | |
| | | return "success"; |
| | | } |
| | | |
| | | private boolean verifySign(PayCallbackDTO callbackDTO) { |
| | | try { |
| | | Map<String, Object> params = new HashMap<>(); |
| | | params.put("channelCode", callbackDTO.getChannelCode()); |
| | | params.put("orderId", callbackDTO.getOrderId()); |
| | | params.put("orderMoney", callbackDTO.getOrderMoney()); |
| | | params.put("orderStatus", callbackDTO.getOrderStatus()); |
| | | params.put("userCode", callbackDTO.getUserCode()); |
| | | |
| | | /** |
| | | * 处理支付结果 - 这里您自己实现业务逻辑 |
| | | */ |
| | | private void handlePayResult(String orderNo, Integer status, Map<String, String> params) { |
| | | UserPolicy userPolicy = userPolicyService.getOne(new LambdaQueryWrapper<UserPolicy>() |
| | | .eq(UserPolicy::getOrderNo,orderNo)); |
| | | if(ObjectUtil.isNotEmpty(userPolicy)){ |
| | | if (status == 2) { |
| | | userPolicy.setPayStatus(status); |
| | | } else if (status == 3) { |
| | | userPolicy.setPayStatus(status); |
| | | } else if (0010 == status) { |
| | | userPolicy.setPayMsg("系统超时或异常"); |
| | | } else if (0014 == status) { |
| | | userPolicy.setPayMsg("mchId是系统分配的商户号,不能自己生成"); |
| | | String generatedSign = generateCallbackSign(params); |
| | | return generatedSign.equalsIgnoreCase(callbackDTO.getSign()); |
| | | } catch (Exception e) { |
| | | log.error("签名验证异常: {}", e.getMessage(), e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | private String generateCallbackSign(Map<String, Object> params) { |
| | | try { |
| | | List<String> keys = new ArrayList<>(params.keySet()); |
| | | Collections.sort(keys); |
| | | |
| | | StringBuilder stringA = new StringBuilder(); |
| | | for (String key : keys) { |
| | | Object value = params.get(key); |
| | | if (value != null && !"".equals(value.toString().trim()) && !"sign".equals(key)) { |
| | | if (stringA.length() > 0) { |
| | | stringA.append("&"); |
| | | } |
| | | stringA.append(key).append("=").append(value.toString()); |
| | | } |
| | | } |
| | | userPolicyService.updateById(userPolicy); |
| | | |
| | | String stringSignTemp = stringA.toString() + "&key=" + key; |
| | | String md5Result = md5(stringSignTemp); |
| | | return md5Result.toLowerCase(); |
| | | |
| | | } catch (Exception e) { |
| | | throw new RuntimeException("生成回调签名失败: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | private boolean processPayResult(PayCallbackDTO callbackDTO, UserPolicy userPolicy) { |
| | | try { |
| | | switch (callbackDTO.getOrderStatus()) { |
| | | case 2: // 已支付 |
| | | return handlePaySuccess(callbackDTO, userPolicy); |
| | | case 3: // 超时/过期 |
| | | return handlePayTimeout(callbackDTO, userPolicy); |
| | | default: |
| | | log.info("订单状态未完成: {}, 状态: {}", callbackDTO.getOrderId(), callbackDTO.getOrderStatus()); |
| | | return true; |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("处理支付结果异常: {}", e.getMessage(), e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | private boolean handlePaySuccess(PayCallbackDTO callbackDTO, UserPolicy userPolicy) { |
| | | if (userPolicy.getPayStatus() == 2) { |
| | | log.info("订单已支付,无需重复处理: {}", callbackDTO.getOrderId()); |
| | | return true; |
| | | } |
| | | |
| | | userPolicy.setPayStatus(2); // 2-支付成功 |
| | | userPolicy.setPolicyStatus(UserPolicy.PolicyStatus.ACTIVE); |
| | | userPolicy.setUpdatedAt(new Date()); |
| | | |
| | | boolean updateResult = userPolicyService.updateById(userPolicy); |
| | | |
| | | if (updateResult) { |
| | | log.info("支付成功处理完成: {}", callbackDTO.getOrderId()); |
| | | return true; |
| | | } else { |
| | | log.error("更新保单状态失败: {}", callbackDTO.getOrderId()); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | private boolean handlePayTimeout(PayCallbackDTO callbackDTO, UserPolicy userPolicy) { |
| | | userPolicy.setPayStatus(3); // 3-支付超时/过期 |
| | | userPolicy.setPolicyStatus(UserPolicy.PolicyStatus.EXPIRED); |
| | | userPolicy.setUpdatedAt(new Date()); |
| | | |
| | | boolean updateResult = userPolicyService.updateById(userPolicy); |
| | | |
| | | if (updateResult) { |
| | | log.info("支付超时处理完成: {}", callbackDTO.getOrderId()); |
| | | return true; |
| | | } else { |
| | | log.error("更新保单超时状态失败: {}", callbackDTO.getOrderId()); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | private String md5(String input) { |
| | | try { |
| | | MessageDigest md = MessageDigest.getInstance("MD5"); |
| | | byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8)); |
| | | |
| | | StringBuilder hexString = new StringBuilder(); |
| | | for (byte b : messageDigest) { |
| | | String hex = Integer.toHexString(0xff & b); |
| | | if (hex.length() == 1) { |
| | | hexString.append('0'); |
| | | } |
| | | hexString.append(hex); |
| | | } |
| | | return hexString.toString(); |
| | | } catch (NoSuchAlgorithmException e) { |
| | | throw new RuntimeException("MD5加密失败", e); |
| | | } |
| | | } |
| | | } |