我们以评论系统为例: 要实现这个需求,你可以按照以下步骤来完成。我们将实现一个自定义注解、一个拦截器、以及在Redis中存储和更新幂等性计数。
步骤1:添加必要的依赖
确保在你的 pom.xml
文件中包含 Spring Boot 和 Redis 的依赖:
xml
代码解读
复制代码
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
步骤2:定义自定义注解
创建一个自定义注解,用于标记需要进行幂等性检查的Controller方法:
java
代码解读
复制代码
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Idempotent { long expireTime() default 60; // 默认过期时间,单位:秒 }
步骤3:创建幂等性检查的拦截器
创建一个拦截器,拦截带有 @Idempotent
注解的方法,并进行幂等性检查:
java
代码解读
复制代码
import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; import java.security.Principal; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; @Component public class IdempotencyInterceptor implements HandlerInterceptor { @Autowired private StringRedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); Idempotent idempotent = method.getAnnotation(Idempotent.class); if (idempotent != null) { // 获取当前用户ID Principal principal = request.getUserPrincipal(); String username = principal.getName(); // 或从SecurityContext中获取 String comment = request.getParameter("comment"); // 生成Redis的Key String key = "idempotent:" + username + ":" + comment; Long expireTime = idempotent.expireTime(); // 检查Redis中是否存在 String value = redisTemplate.opsForValue().get(key); if (value == null) { // 不存在,存入Redis redisTemplate.opsForValue().set(key, "1", expireTime, TimeUnit.SECONDS); } else { // 存在,进行计数 int count = Integer.parseInt(value); if (count >= 3) { // 超过次数限制 response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.getWriter().write("重复评论已达到上限"); return false; } else { redisTemplate.opsForValue().increment(key); } } } } return true; } }
步骤4:注册拦截器
在配置类中注册这个拦截器:
java
代码解读
复制代码
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private IdempotencyInterceptor idempotencyInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(idempotencyInterceptor).addPathPatterns("/**"); } }
步骤5:在Controller方法���使用自定义注解
最后,在需要幂等性检查的方法上使用 @Idempotent
注解:
java
代码解读
复制代码
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/comments") public class CommentController { @PostMapping @Idempotent(expireTime = 60) public String addComment(@RequestBody CommentRequest commentRequest) { // 处理添加评论的逻辑 return "评论添加成功"; } }
总结
通过上述步骤,我们创建了一个自定义注解 @Idempotent
,一个拦截器 IdempotencyInterceptor
,并在拦截器中使用Redis进行幂等性检查。最后在需要检查幂等性的Controller方法上添加该注解即可实现功能