一看就会!一个注解搞定 Spring Boot 接口防刷

本文介绍了如何使用SpringBoot和Redis实现一个访问控制拦截器,通过@AccessLimit注解配置访问频率限制,并结合Redis存储用户访问次数,确保接口安全并发控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,技术要点:Spring Boot的基本知识,Redis基本操作,

首先是写一个注解类:

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
 
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
@Retention(RUNTIME)
@Target(METHOD)
public @interface AccessLimit {
 
    int seconds();
    int maxCount();
    boolean needLogin()default true;
}

接着就是在Interceptor拦截器中实现:

import com.alibaba.fastjson.JSON;
import com.example.demo.action.AccessLimit;
import com.example.demo.redis.RedisService;
import com.example.demo.result.CodeMsg;
import com.example.demo.result.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
 
@Component
public class FangshuaInterceptor extends HandlerInterceptorAdapter {
 
    @Autowired
    private RedisService redisService;
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 
        //判断请求是否属于方法的请求
        if(handler instanceof HandlerMethod){
 
            HandlerMethod hm = (HandlerMethod) handler;
 
            //获取方法中的注解,看是否有该注解
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if(accessLimit == null){
                return true;
            }
            int seconds = accessLimit.seconds();
            int maxCount = accessLimit.maxCount();
            boolean login = accessLimit.needLogin();
            String key = request.getRequestURI();
            //如果需要登录
            if(login){
                //获取登录的session进行判断
                //.....
                key+=""+"1";  //这里假设用户是1,项目中是动态获取的userId
            }
 
            //从redis中获取用户访问的次数
            AccessKey ak = AccessKey.withExpire(seconds);
            Integer count = redisService.get(ak,key,Integer.class);
            if(count == null){
                //第一次访问
                redisService.set(ak,key,1);
            }else if(count < maxCount){
                //加1
                redisService.incr(ak,key);
            }else{
                //超出访问次数
                render(response,CodeMsg.ACCESS_LIMIT_REACHED); //这里的CodeMsg是一个返回参数
                return false;
            }
        }
 
        return true;
 
    }
    private void render(HttpServletResponse response, CodeMsg cm)throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        String str  = JSON.toJSONString(Result.error(cm));
        out.write(str.getBytes("UTF-8"));
        out.flush();
        out.close();
    }
}

再把Interceptor注册到springboot中

import com.example.demo.ExceptionHander.FangshuaInterceptor;
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.WebMvcConfigurerAdapter;

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
 
    @Autowired
    private FangshuaInterceptor interceptor;
 
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor);
    }
}

接着在Controller中加入注解

import com.example.demo.result.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 
@Controller
public class FangshuaController {
 
    @AccessLimit(seconds=5, maxCount=5, needLogin=true)
    @RequestMapping("/fangshua")
    @ResponseBody
    public Result<String> fangshua(){
 
 
        return Result.success("请求成功");
 
    }
<think>好的,用户想在Spring6中通过全注解方式配置MultipartResolver。首先,我需要回忆Spring中处理文件上传的相关知识。记得MultipartResolver是Spring MVC用来处理multipart/form-data请求的接口,主要有两种实现:CommonsMultipartResolver和StandardServletMultipartResolver。不过在Spring Boot中,通常会自动配置StandardServletMultipartResolver,但如果是非BootSpring项目,可能需要手动配置。 用户提到的是全注解方式,所以应该避免XML配置。在Spring6中,可能需要使用基于Java的配置,也就是通过@Configuration类来定义Bean。首先,需要确认使用哪个实现类。由于CommonsMultipartResolver依赖于Apache Commons FileUpload库,而StandardServletMultipartResolver依赖于Servlet 3.0+容器的multipart支持,可能后者更符合现代应用,不需要额外依赖。 接下来,配置步骤应该包括添加依赖(如果是Commons的话需要Apache的库)、创建配置类、定义MultipartResolver的Bean,并设置相关参数,比如最大文件大小、请求大小等。同时,可能需要在Spring Security中配置相关权限,允许文件上传的路径,但用户的问题可能不涉及安全部分,所以可能不需要这部分。 需要注意的是,在Spring Boot中,通常通过application.properties来配置multipart参数,但在全注解方式中,可能需要在Bean定义时设置这些属性。例如,使用StandardServletMultipartResolver的话,可能需要在Servlet容器(如Tomcat)的配置中设置,或者在Spring的配置中通过MultipartConfigElement来配置。不过对于StandardServletMultipartResolver,其实可能不需要额外的配置,因为容器会处理,但为了设置限制参数,可能还是需要配置。 可能还需要检查是否有必要的注解,比如@EnableWebMvc,或者通过WebMvcConfigurer来配置。另外,确保DispatcherServlet正确配置了multipart配置,可能需要注册MultipartConfigElement。 现在,需要整合这些步骤,写出一个配置类示例。假设用户使用StandardServletMultipartResolver,那么配置类应该包含@Bean方法返回该实例,但可能不需要额外参数,因为参数可能通过Servlet容器设置。或者,如果使用CommonsMultipartResolver,则需要设置maxUploadSize等属性。 另外,用户的问题是关于Spring6的全注解配置,所以可能需要参考最新的文档,确认是否有变化。例如,是否还需要在配置类中添加某些特定的注解,或者在定义Bean时使用新的方法。 可能还需要考虑文件上传的控制器示例,展示如何处理上传请求,这样用户可以完整地测试配置是否正确。所以,在回答中应该包括配置类和控制器示例,并说明如何测试。 最后,需要确保所有步骤符合Spring6的要求,例如包结构、注解的正确使用等。还要检查依赖是否正确,比如如果使用CommonsMultipartResolver,需要引入commons-fileupload依赖,而Standard的可能不需要额外依赖,但需要Servlet 3.0+的支持。 总结下,步骤大致是:添加必要依赖、创建配置类定义MultipartResolver的Bean、配置参数、编写控制器处理上传、测试。需要根据用户选择的解析器类型来具体说明。</think>在Spring6中通过全注解方式配置`MultipartResolver`可通过以下步骤实现: --- ### **、配置MultipartResolver的核心步骤** 1. **添加依赖**(若使用`CommonsMultipartResolver`需引入Apache Commons库): ```xml <!-- pom.xml --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.5</version> </dependency> ``` 2. **创建配置类**,使用`@Bean`定义`MultipartResolver`: ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.multipart.commons.CommonsMultipartResolver; @Configuration public class FileUploadConfig { @Bean(name = "multipartResolver") public CommonsMultipartResolver multipartResolver() { CommonsMultipartResolver resolver = new CommonsMultipartResolver(); resolver.setMaxUploadSize(10485760); // 10MB resolver.setDefaultEncoding("UTF-8"); return resolver; } } ``` 3. **替代方案(推荐)**:若使用Servlet 3.0+容器,优先使用`StandardServletMultipartResolver`(无需额外依赖): ```java @Bean public StandardServletMultipartResolver multipartResolver() { return new StandardServletMultipartResolver(); } ``` **参数配置需在`ServletRegistrationBean`中设置**: ```java @Bean public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration() { ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(new DispatcherServlet()); registration.setMultipartConfig(new MultipartConfigElement("", 10485760, 20971520, 0)); return registration; } ``` --- ### **二、文件上传控制器示例** ```java import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; @Controller public class FileUploadController { @PostMapping("/upload") public String handleUpload(@RequestParam("file") MultipartFile file) { if (!file.isEmpty()) { // 处理文件存储逻辑 return "upload-success"; } return "upload-fail"; } } ``` --- ### **三、关键配置解析** 1. **`CommonsMultipartResolver`**:需手动设置最大文件大小和编码,适用于需要精细控制上传参数的场景[^2]。 2. **`StandardServletMultipartResolver`**:依赖Servlet容器配置,更适合现代应用,减少框架侵入性。 3. **`MultipartConfigElement`**:用于设置临时存储路径、单文件大小限制、总请求大小限制等参数[^1]。 --- ### **四、测试验证** 通过Postman或表单提交文件至`/upload`接口,观察是否正常接收文件: ```html <!-- upload.html --> <form method="POST" action="/upload" enctype="multipart/form-data"> <input type="file" name="file"> <button type="submit">上传</button> </form> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值