Browse Source

11.23 消息推送完善

huangqizheng/feature-20251119150446-退款合并后
huangqizhen 2 days ago
parent
commit
7e9e5e164b
  1. 6
      pom.xml
  2. 39
      src/main/java/com/example/demo/config/RateLimitUtil.java
  3. 58
      src/main/java/com/example/demo/controller/cash/CashRefundController.java
  4. 20
      src/main/java/com/example/demo/serviceImpl/cash/CashAuditServiceImpl.java
  5. 2
      src/main/java/com/example/demo/serviceImpl/cash/CashCollectionServiceImpl.java
  6. 28
      src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java

6
pom.xml

@ -70,6 +70,12 @@
<artifactId>hutool-all</artifactId>
<version>5.8.24</version>
</dependency>
<!-- Guava:提供缓存+过期时间功能,适合本地限流 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version> <!-- 推荐稳定版 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

39
src/main/java/com/example/demo/config/RateLimitUtil.java

@ -0,0 +1,39 @@
package com.example.demo.config;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;
/**
* 本地限流工具类基于Guava Cache
*/
public class RateLimitUtil {
// 缓存key=限流标识用户ID/IPvalue=占位符无实际意义
private static final Cache<String, Object> RATE_LIMIT_CACHE = CacheBuilder.newBuilder()
.expireAfterWrite(3, TimeUnit.SECONDS) // 3秒后自动过期时间窗口
.maximumSize(5000) // 最大缓存容量防止内存溢出根据用户量调整
.build();
/**
* 判断是否允许请求
* @param key 限流唯一标识如用户IDIP
* @return true=允许请求false=限流中
*/
public static boolean isAllowed(String key) {
// 1. 尝试从缓存获取key存在则说明3秒内已请求过限流
if (RATE_LIMIT_CACHE.getIfPresent(key) != null) {
return false;
}
// 2. 缓存中不存在存入缓存占位符用new Object()即可
RATE_LIMIT_CACHE.put(key, new Object());
return true;
}
/**
* 手动移除限流标识如接口执行失败时释放限流
* @param key 限流唯一标识
*/
public static void removeKey(String key) {
RATE_LIMIT_CACHE.invalidate(key);
}
}

58
src/main/java/com/example/demo/controller/cash/CashRefundController.java

@ -2,6 +2,7 @@ package com.example.demo.controller.cash;
import com.example.demo.Util.JWTUtil;
import com.example.demo.config.RateLimitUtil;
import com.example.demo.domain.entity.Admin;
import com.example.demo.domain.vo.cash.CashRecordDTO;
import com.example.demo.domain.vo.cash.CashRecordDone;
@ -26,6 +27,7 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* @program: GOLD
@ -196,9 +198,38 @@ public class CashRefundController {
}
}
@PostMapping("/finalReview")
public Result finalReview(@RequestBody CashRecordDone cashRecordDone) {
return Result.success(refundService.finalreview(cashRecordDone));
}
public Result finalReview(@RequestBody CashRecordDone cashRecordDone,HttpServletRequest request) {
{
// --------------- 限流逻辑开始 ---------------
String limitKey = null;
try {
// 1. 优先用用户ID作为限流标识从token解析精准限流
HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = req.getHeader("token");
Admin admin = (Admin) JWTUtil.getUserDetailsList(String.valueOf(token), Admin.class);
if (admin != null && admin.getId() != null) {
limitKey = "finalReview_" + admin.getId(); // 格式接口名_用户ID
}
} catch (Exception e) {
// token解析失败用户未登录降级用IP地址限流
limitKey = "finalReview_" + getIpAddress(request); // 格式接口名_IP
}
// 2. 校验限流3秒内同一key不允许重复请求
if (Objects.isNull(limitKey) || !RateLimitUtil.isAllowed(limitKey)) {
return Result.error("3秒内只能请求一次,请稍后再试"); // 限流提示
}
// --------------- 限流逻辑结束 ---------------
try {
// 原有业务逻辑执行最终审核
return Result.success(refundService.finalreview(cashRecordDone));
} catch (Exception e) {
// 接口执行失败时移除限流标识允许用户重新尝试
RateLimitUtil.removeKey(limitKey);
return Result.error("审核失败:" + e.getMessage());
}
}}
@PostMapping("/executor")
public Result executor(@RequestBody CashRecordDone cashRecordDone) throws Exception {
try {
@ -239,4 +270,25 @@ public class CashRefundController {
public Result ceshi() {
return Result.success("测试消息");
}
/**
* 辅助方法获取用户真实IP处理反向代理/负载均衡场景
*/
private String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 多IP场景如多层代理取第一个非unknown的IP
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
return ip;
}
}

20
src/main/java/com/example/demo/serviceImpl/cash/CashAuditServiceImpl.java

@ -6,6 +6,7 @@ import com.example.demo.domain.entity.CashRecord;
import com.example.demo.domain.entity.User;
import com.example.demo.domain.entity.UserGoldRecord;
import com.example.demo.domain.vo.cash.CashCollectionMessage;
import com.example.demo.domain.vo.coin.Messages;
import com.example.demo.mapper.cash.CashAuditMapper;
import com.example.demo.mapper.cash.CashCollectionMapper;
import com.example.demo.mapper.coin.AuditMapper;
@ -130,17 +131,16 @@ public class CashAuditServiceImpl implements CashAuditService {
//更新订单
cashAuditMapper.updateOrder(updateOrder);
// 创建消息队列用于发送审核结果通知
CashCollectionMessage message = new CashCollectionMessage();
message.setId(order.getId());
message.setOrderCode(orderCode);
Messages message = new Messages();
message.setJwcode(order.getJwcode());
message.setName(order.getName());
message.setStatus(updateOrder.getStatus());
message.setStatusDescription(action == 1 ? "线下财务审核通过待填手续费" : "线下财务审核驳回");
message.setMessage(action == 1 ? "收款订单审核通过" : "收款订单审核驳回");
message.setSubmitterId(order.getSubmitterId());
message.setAuditId(auditId);
message.setAuditName(auditName);
message.setTimestamp(LocalDateTime.now());
message.setDesc(order.getJwcode() + action==1?"收款记录需补充手续费,前往填写":"现金收款申请已被驳回,前往查看驳回理");
message.setTitle(action==1?"收款订单审核通过":"收款订单审核驳回");
message.setType(1);
message.setTypeId(order.getId());
message.setMarket(Integer.valueOf(order.getMarket()));
rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_COLLECTION_EXCHANGE, "cash.collection.save", message);
// 根据审核结果发送不同的消息
if (action == 1) {
// 发送审核通过消息

2
src/main/java/com/example/demo/serviceImpl/cash/CashCollectionServiceImpl.java

@ -132,7 +132,7 @@ public class CashCollectionServiceImpl implements CashCollectionService {
message.setJwcode(cashRecord.getJwcode());
message.setName(cashRecord.getName());
message.setStatus(cashRecord.getStatus());
message.setDesc(cashRecord.getJwcode()+"用户有条收款订单需审核");
message.setDesc(cashRecord.getJwcode()+"用户的现金收款申请待审核,请前往审核");
message.setTitle("现金收款--新增收款");
message.setType(1);
message.setTypeId(cashRecord.getId());

28
src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java

@ -204,7 +204,7 @@ public class CashRefundServiceImpl implements RefundService {
message.setJwcode(cashRecordRefund.getJwcode());
message.setName(cashRecordRefund.getName());
message.setStatus(cashRecordRefund.getStatus());
message.setDesc(cashRecordRefund.getJwcode()+"用户有条退款订单需审核");
message.setDesc(cashRecordRefund.getJwcode()+"用户的客服退款申请待审核,前往处理");
message.setTitle("现金退款--新增退款");
message.setType(0);
message.setTypeId(cashRecordRefund.getId());
@ -239,7 +239,21 @@ public class CashRefundServiceImpl implements RefundService {
cashRecordDone.setNewRefundFree(BigDecimal.valueOf(0));
}
int result = cashRefundMapper.update(cashRecordDone);
return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
CashRecordDTO cashRecordDTO = cashRefundMapper.selectById(cashRecordDone.getId());
if (result > 0) {
// 发送审核消息
Messages message = new Messages();
message.setJwcode(cashRecordDTO.getJwcode());
message.setName(cashRecordDTO.getName());
message.setStatus(cashRecordDTO.getStatus());
message.setDesc(cashRecordDTO.getJwcode() + "用户的退款申请待审核,前往处理");
message.setTitle("现金退款--当地退款审核(编辑后提交)");
message.setType(1);
message.setTypeId(cashRecordDTO.getId());
message.setMarket(cashRecordDTO.getMarket());
rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message);
}
return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
}
@Override
@ -269,15 +283,14 @@ CashRecordDone cashRecordDone1 = new CashRecordDone();
message.setJwcode(cashRecordDTO.getJwcode());
message.setName(cashRecordDTO.getName());
message.setStatus(cashRecordDTO.getStatus());
message.setDesc(cashRecordDTO.getJwcode()+"用户有条退款订单需审核");
message.setDesc(cashRecordDTO.getJwcode()+cashRecordDTO.getStatus()!=12|| cashRecordDTO.getStatus()!=22?"用户的退款申请待审核,前往处理":"用户的现金退款申请已被驳回,前往查看详情");
message.setTitle("现金退款--当地退款审核");
message.setType(1);
message.setTypeId(cashRecordDTO.getId());
message.setMarket(cashRecordDTO.getMarket());
if (cashRecordDTO.getStatus() != 12 || cashRecordDTO.getStatus() != 22) {
rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message);
}
}
return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
@ -378,15 +391,12 @@ CashRecordDone cashRecordDone1 = new CashRecordDone();
message.setJwcode(cashRecordDTO.getJwcode());
message.setName(cashRecordDTO.getName());
message.setStatus(cashRecordDTO.getStatus());
message.setDesc(cashRecordDTO.getJwcode()+"用户有条退款订单需审核");
message.setDesc(cashRecordDTO.getJwcode()+cashRecordDTO.getStatus()!=32?"用户的退款申请待审核,前往处理":"用户的现金退款申请已被驳回,前往查看详情");
message.setTitle("现金退款--执行人退款提交");
message.setType(1);
message.setTypeId(cashRecordDTO.getId());
message.setMarket(cashRecordDTO.getMarket());
if (cashRecordDTO.getStatus() != 32) {
rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message);
}
}
return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
}

Loading…
Cancel
Save