Spring拦截器
内容纲要

拦截器

拦截器(Interceptor)同 Filter 过滤器一样,它俩都是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)。

你可以使用 Interceptor 来执行某些任务,例如在 Controller 处理请求之前编写日志,添加或更新配置…

在 Spring中,当请求发送到 Controller 时,在被Controller处理之前,它必须经过 Interceptors(0或多个)。

Spring Interceptor是一个非常类似于Servlet Filter 的概念 。

自定义拦截器

具体方法:

​ 自定义类实现 org.springframework.web.servlet.HandlerInterceptor接口或继承 org.springframework.web.servlet.handler.HandlerInterceptorAdapter

方法执行顺序:

  1. 如果拦截成功:prehandler 之后不再执行
  2. 如果拦截失败:prehandler -> controller -> posthandler -> afterCompletion
@Slf4j
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("PreHandler");
        log.info("PreHandler");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("PostHandle");
        log.info("PostHandler");
        return;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("After");
        log.info("After");
        HandlerInterceptor.super.afterCompletion(request,response,handler,ex);
    }
}

配置注册拦截器

对于每个拦截器,要配置其拦截的对象,和拦截优先级。

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 配置接口路径
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/*/testHandler").order(0);
    }
}

如何在拦截器中注册普通Bean

​ 今天我有个想法,想将一个普通Bean注册到拦截器中,但是发现怎么都拿不到这个Bean,后来才知道是拦截器在Context初始化之前就注册了。

​ 因为拦截器是在上下文容器 Spring Context 初始化之前执行,所以没有办法直接在拦截器中注入普通Bean。

解决方法

// 拦截器,这类我想注入httpUtils和showEntity
public class Interceptor implements HandlerInterceptor {
    /**
     * 配置拦截器,拦截相应的路径,转发请求
     */
    @Resource
    HttpUtils httpUtils;
    @Resource
    ShowEntity showEntity;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
}

将拦截器也通过当作普通Bean,使用@Bean注入,而不是在配置中直接new一个拦截器对象,

// 一般来说会这样配拦截器,但是这样在context初始化之前就注入拦截器了,当然拿不到httpUtils和showEntity。
@Configuration
public class Config implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new Interceptor()).addPathPatterns("/testa/needToProcess");
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedHeaders("*");
    }
}

正确做法,这样就可以在Interceptor中注入httpUtils和showEntity了。

@Configuration
public class Config implements WebMvcConfigurer {
    @Bean
    public Interceptor interceptor(){
        return new Interceptor();
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor()).addPathPatterns("/testa/needToProcess");
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedHeaders("*");
    }
}

拦截器拦截请求后,拿到请求体中的参数,并传递给请求的原方法

​ 拦截器中,一个RequestgetReader()getInputStream()只能调用一次。如果在拦截器中读了请求体,那么到Controller就取不到原Request中的请求体数据了。

解决方法:

​ 重写一个RequestWrapper,将从request中读取的body保存下来,再通过重写Filter传递RequestWrapperCongtroller

public class RequestWrapper extends HttpServletRequestWrapper {

    private final String body;

    public RequestWrapper(HttpServletRequest request){
        super(request);
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader =null;
        InputStream inputStream = null;
        try {
            inputStream = request.getInputStream();
            if(inputStream != null){
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[128];
                int byteRead = -1;
                while((byteRead = bufferedReader.read(charBuffer)) > 0){
                    stringBuilder.append(charBuffer,0,byteRead);
                }
            }else {
                stringBuilder.append("");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if(inputStream != null){
                try{
                    inputStream.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
            if(bufferedReader != null){
                try{
                    bufferedReader.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
        body = stringBuilder.toString();
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletInputStream = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
        return servletInputStream;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
    public String getBody(){
        return this.body;
    }
}
public class RepeatedlyReadFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if(servletRequest instanceof HttpServletRequest){
            requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
        }
        if(requestWrapper == null){
            filterChain.doFilter(servletRequest,servletResponse);
        }else {
            filterChain.doFilter(requestWrapper,servletResponse);
        }
    }

    @Override
    public void destroy() {

    }
}

修改配置类,注册Filter

@Configuration
public class WebConfig implements WebMvcConfigurer {
    /**
     * 拦截器
     */
    @Bean
    public Interceptor interceptor(){
        return new Interceptor();
    }

    /**
     * 过滤器
     */
    @Bean
    public FilterRegistrationBean<RepeatedlyReadFilter> repeatedlyReadFilter(){
        FilterRegistrationBean<RepeatedlyReadFilter> registrationBean = new FilterRegistrationBean<>();
        RepeatedlyReadFilter repeatedlyReadFilter = new RepeatedlyReadFilter();
        registrationBean.setFilter(repeatedlyReadFilter);
        registrationBean.addUrlPatterns("/*");
        return registrationBean;
    }

    /**
     * 拦截器配置
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor()).addPathPatterns("/testa/needToProcess");
    }

    /**
     * 跨域配置
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedHeaders("*");
    }

}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇