SpringBoot 3.0使用自定义注解+Interceptor+Redis实现幂等

我们以评论系统为例: 要实现这个需求,你可以按照以下步骤来完成。我们将实现一个自定义注解、一个拦截器、以及在Redis中存储和更新幂等性计数。

步骤1:添加必要的依赖

确保在你的 pom.xml 文件中包含 Spring Boot 和 Redis 的依赖:

<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方法:

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 注解的方法,并进行幂等性检查:

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:注册拦截器

在配置类中注册这个拦截器:

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 注解:

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方法上添加该注解即可实现功能。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值