web容器(nginx, tomcat等)

过滤器(Filter), 拦截器(Interceptor), 监

2019-07-25  本文已影响0人  suxin1932
#SpringBoot中:
ServletRegistrationBean --注册--> Servlet
FilterRegistrationBean --注册--> Filter
ServletListenerRegistrationBean --注册--> Listener

1.Filter

过滤器是服务端的一个组件,是基于servlet实现从客户端访问服务端web资源的一种拦截机制,
对请求request和响应response都进行过滤,依赖于serverlet容器.
使用时,实现Filter接口,在web.xml里配置对应的class还有mapping-url,
springboot工程可以通FilterRegisteration配置后,设置要过滤的URL
#注意  
两种方式过滤器都是有序的!

定义过滤器后会重写三个方法,分别是init(),doFilter(),和destory():
#init方法
是过滤器的初始化方法,当web容器创建这个bean的时候就会执行,
这个方法可以读取web.xml里面的参数

#doFilter方法
是执行过滤的请求的核心,当客户端请求访问web资源时,
这个时候我们可以拿到request里面的参数,对数据进行处理后,
通过filterChain方法将请求将请求放行,
也可以通过response对响应进行处理(比如压缩响应),然后会传递到下一个过滤器

#destory方法
是当web容器中的过滤器实例被销毁时,会被执行,释放资源

#summary
过滤器的生命周期为:
实例化(web.xml) --> 初始化(init) --> 过滤(doFilter) --> 销毁(destroy)
Filter.png

2.拦截器Interceptor

过滤器依赖serverlet容器,获取request和response处理,是基于函数回调,简单说就是“去取你想取的”;
拦截器是通过java反射机制,动态代理来拦截web请求,是“拒你想拒绝的”,他只拦截web请求,但不拦截静态资源

#拦截器的三个方法,preHandler(),postHandler(),afterCompletion()
#preHandler(): 
这个方法是在controller调用之前调用,通过返回true或者false决定是否进入Controller层

#postHandler():
在请求进入控制层之后调用,但是在处理请求抛出异常时不会调用

#afterCompletion(): 
在请求处理完成之后,也就是在DispatherServlet渲染了视图之后执行,
也就是说这个方法必定是执行,包含异常信息,它的主要作用就是清理资源
Interceptor.png

示例代码

Interceptor.png
package com.zy.netty.config;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println(">>>>>>>>> preHandle");
        // 如果请求URI是c1, 返回false进行拦截, 否则不拦截
        return !"/c1".equals(request.getRequestURI());
    }

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

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println(">>>>>>>>> afterCompletion");
    }
}
package com.zy.netty.config;

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 {

    private final MyInterceptor myInterceptor;

    @Autowired
    public WebConfig(MyInterceptor myInterceptor) {
        this.myInterceptor = myInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor);
    }
}
package com.zy.netty.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping("c1")
    public Object c1() {
        System.out.println(".......c1..........");
        return "c1";
    }
    @RequestMapping("c2")
    public Object c2() {
        System.out.println(".......c2..........");
        return "c2";
    }

}
#访问http://localhost:8080/c1, 被拦截, 打印信息为:
>>>>>>>>> preHandle

#访问http://localhost:8080/c2, 未被拦截, 打印信息为:
>>>>>>>>> preHandle
.......c2..........
>>>>>>>>> postHandle
>>>>>>>>> afterCompletion

summary

>> 拦截器是基于Java反射机制的, 过滤器是基于接口回调的
>> 过滤器依赖于servlet容器, 而拦截器不依赖servlet容器
>> 过滤器可以对所有请求起作用, 拦截器只对Action请求起作用
>> 拦截器可以访问Action上下文, 值栈里的对象, 过滤器不能

3.Listener

参考:
https://www.jianshu.com/p/a766267be3c6

java.util.EventListener
javax.servlet.http.HttpSessionListener
javax.servlet.ServletRequestListener
javax.servlet.ServletContextListener
package com.zy.netty.listener;

import lombok.AllArgsConstructor;
import lombok.Data;
/**
 * 自定义事件
 */
@Data
@AllArgsConstructor
public class OrderEvent {
    private String msg;
}
package com.zy.netty.listener;

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
 * 事件处理程序: 监听器
 */
@Component
public class OrderEventListener {
    @EventListener
    public void handlerOrderEvent(OrderEvent event) {
        System.out.println("监听到orderEvent, 开始处理msg: " + event.getMsg());
    }
}
package com.zy.netty.listener;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
/**
 * 事件触发
 */
@Service
public class OrderService {
    @Autowired
    private ApplicationContext context;
    public void publishOrder(OrderEvent event) {
        context.publishEvent(event);
    }
}
package com.zy.netty;
import com.zy.netty.listener.OrderEvent;
import com.zy.netty.listener.OrderService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootNettyDemoApplicationTests {
    @Autowired
    private OrderService orderService;
    @Test
    public void fn01() {
        orderService.publishOrder(new OrderEvent("order01"));
    }
}

4.Filter

package com.zy.eureka.filter;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * SpringMVC 中自定义 Filter, 并设置 Filter 的执行顺序 (优先级)
 */
@SuppressWarnings("all")
@Configuration
public class FilterConfiguration {

    @Bean
    public FilterRegistrationBean xssFilterRegistration() {
        FilterRegistrationBean xssFilterRegistration = new FilterRegistrationBean();
        xssFilterRegistration.setFilter(new XssFilter());
        xssFilterRegistration.setName("xssFilter");
        // order数字越小越先执行
        xssFilterRegistration.setOrder(2);
        xssFilterRegistration.addUrlPatterns("/*");
        xssFilterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
        return xssFilterRegistration;
    }

    @Bean
    public FilterRegistrationBean csrfFilterRegistration() {
        FilterRegistrationBean csrfFilterRegistration = new FilterRegistrationBean();
        csrfFilterRegistration.setFilter(new CsrfFilter());
        csrfFilterRegistration.setName("csrfFilter");
        csrfFilterRegistration.setOrder(1);
        csrfFilterRegistration.addUrlPatterns("/*");
        csrfFilterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
        return csrfFilterRegistration;
    }

    private static class XssFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest request1 = (HttpServletRequest) request;
            if ((Objects.isNull(request1.getHeader("reqHeader01")))) {
                return;
            }
            HttpServletResponse response1 = (HttpServletResponse) response;
            response1.setHeader("xssHeader", "xss");
            chain.doFilter(request, response);
        }
    }

    private static class CsrfFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletResponse response1 = (HttpServletResponse) response;
            response1.setHeader("csrfHeader", "csrf");
            chain.doFilter(request, response);
        }
    }
}

当访问一个 controller 时, 其调用堆栈信息为:

FilterChain.png FilterChain中的filters.png

https://blog.csdn.net/jjkang_/article/details/88548120
https://blog.csdn.net/WoddenFish/article/details/84836824 (filter)

上一篇下一篇

猜你喜欢

热点阅读