重复提交不再是问题!SpringBoot自定义注解+AOP巧妙解决

随着前后端分离开发的逐渐流行,后端接口的安全性也变得越来越重要。其中,防止重复提交是接口安全性的一个重要方面。如果用户在短时间内多次提交相同的请求,可能会导致系统状态异常或者产生不必要的资源浪费。

本文将介绍如何使用SpringBoot自定义注解和AOP技术,实现防止重复提交的功能。

一、SpringBoot自定义注解

SpringBoot是一款快速开发框架,它提供了丰富的注解,可以让开发者快速构建应用程序。在这里,我们可以通过自定义注解来实现防止重复提交的功能。

首先,我们定义一个@NoRepeatSubmit注解,用于标识需要防止重复提交的方法:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {
 
    /**
     * 过期时间,单位为秒,默认为5秒
     */
    int expireTime() default 5;
 
}

这个注解有一个属性expireTime,用于设置防重复提交的时间,单位为秒,默认为5秒。如果在这个时间内用户再次提交相同的请求,服务器会认为是重复提交,拒绝处理。

二、AOP技术

AOP(Aspect-Oriented Programming)是一种编程范式,它可以在程序运行期间动态地将额外的行为织入到代码中,比如日志、安全、事务等。

在本例中,我们可以使用AOP技术,通过拦截方法并检查是否有@NoRepeatSubmit注解来实现防止重复提交的功能。

首先,我们定义一个切面类NoRepeatSubmitAspect:

@Aspect
@Component
public class NoRepeatSubmitAspect {
 
    @Autowired
    private RedisTemplate redisTemplate;
 
    @Pointcut("@annotation(com.example.demo.annotation.NoRepeatSubmit)")
    public void noRepeatSubmit() {
    }
 
    @Around("noRepeatSubmit()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader("token");
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("token不能为空");
        }
        String path = request.getServletPath();
        String key = "NoRepeatSubmit:" + token + ":" + path;
        boolean isExist = redisTemplate.hasKey(key);
        if (isExist) {
            throw new RuntimeException("请勿重复提交");
        }
        redisTemplate.opsForValue().set(key, "0", expireTime(), TimeUnit.SECONDS);
        Object result = joinPoint.proceed();
        return result;
    }
 
    /**
     * 获取注解中的过期时间
     */
    private int expireTime() {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        NoRepeatSubmit annotation = method.getAnnotation(NoRepeatSubmit.class);
        return annotation.expireTime();
    }
 
}

这个切面类主要完成了两个方法:noRepeatSubmit()和around()。

noRepeatSubmit()方法用于定义切入点,即拦截所有被@NoRepeatSubmit注解修饰的方法。

around()方法用于实现防止重复提交的逻辑。它首先从HttpServletRequest中获取token和path,然后在Redis中查找是否有对应的key。如果找到了,就说明用户在短时间内重复提交了相同的请求,此时会抛出异常并拒绝处理。如果没有找到,就说明是第一次提交,此时会在Redis中设置对应的key,并执行原来的方法。

注意,这里使用了Redis来存储重复提交的信息,因为Redis是一种高性能的内存数据库,能够快速地存取数据。另外,我们在key的前面加上了一个前缀,这样可以方便地区分不同的用户和路径。

最后,我们需要在SpringBoot启动类上添加@EnableAspectJAutoProxy注解,来启用AOP功能:

@SpringBootApplication
@EnableAspectJAutoProxy
public class DemoApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
 
}

三、测试

现在,我们已经完成了防止重复提交的代码。下面,我们来测试一下它的效果。

首先,我们定义一个UserController,其中有一个方法addUser(),用于添加用户信息:

@RestController
public class UserController {
 
    @PostMapping("/user")
    @NoRepeatSubmit(expireTime = 10)
    public String addUser(@RequestBody User user) throws InterruptedException {
        Thread.sleep(5000);
        return "success";
    }
 
}

这个方法使用了@NoRepeatSubmit注解,并设置了expireTime属性为10秒。这意味着,如果用户在10秒内重复提交相同的请求,服务器会认为是重复提交,拒绝处理。

我们可以使用Postman工具来测试这个接口。首先,我们向服务器发送一次请求:

POST http://localhost:8080/user
Content-Type: application/json
{
    "name": "Tom",
    "age": 18
}

服务器返回了"success",这意味着第一次提交成功了。接着,我们再次发送相同的请求:

POST http://localhost:8080/user
Content-Type: application/json
{
    "name": "Tom",
    "age": 18
}

这次,服务器返回了一个异常:

{
    "timestamp": "2023-03-13T09:28:27.058+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "请勿重复提交",
    "path": "/user"
}

这说明我们的防重复提交功能已经生效了。在第一次提交之后,如果用户在10秒内再次提交相同的请求,服务器会拒绝处理,并返回一个错误信息。

四、总结

本文介绍了如何使用SpringBoot自定义注解和AOP技术,实现防止重复提交的功能。通过定义一个@NoRepeatSubmit注解,并编写一个AOP切面,我们能够轻松地在SpringBoot项目中添加防重复提交的功能,提高应用的稳定性和安全性。

在实现过程中,我们使用了Redis来存储重复提交的信息。Redis是一种高性能的内存数据库,能够快速地存取数据,非常适合用来存储一些需要快速读写的信息。在实际项目中,如果需要存储大量的数据,可以考虑使用其他数据库,比如MySQL、MongoDB等。

另外,我们在@NoRepeatSubmit注解中添加了一个expireTime属性,用于设置重复提交信息在Redis中的过期时间。这样可以避免Redis中存储过多的无用数据,提高系统的性能。

最后,需要注意的是,防止重复提交只是应用程序中的一个小功能,它并不能完全保证应用程序的安全性。在实际项目中,还需要加强其他方面的安全性,比如用户认证、数据加密等。

展开阅读全文

页面更新:2024-06-04

标签:注解   切面   巧妙   安全性   定义   快速   功能   服务器   方法   数据   用户

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top