Spring Boot 的Servlet、Filter 、 Listener和Interceptor
先上两个网上找到的图,大家先有个大概认识1、Servlet回顾下javaEE的开发步骤(这里是大致配置和流程):1.在web.xml中配置servlet和servletMapping2.书写servlet标签里面配置的类,类需要继承HttpServlet,然后复写里面的doGet,doPost方法(当然还有init,des...
先上两个网上找到的图,大家先有个大概认识
1、Servlet
回顾下javaEE的开发步骤(这里是大致配置和流程):
1.在web.xml中配置servlet和servletMapping
2.书写servlet标签里面配置的类,类需要继承HttpServlet,然后复写里面的doGet,doPost方法(当然还有init,destory方法)
3.启动tomcat服务器,访问对应的路径就能访问到对应的doGet,doPost方法
但是这个web.xml和对应的类以及tomcat到底有什么关系呢?在后面到底做了什么呢?
首先我们要理清一个逻辑:浏览器http请求------>tomcat服务器------->到达servlet----->执行doGet,doPost方法---->返回数据
从这个逻辑可以看出tomcat才是和客户端打交道的:
他监听了端口,请求过来后,根据url信息和web.xml配置文件匹配,确定要将请求交给哪个servlet去处理,servlet处理请求然后返回给tomcat,tomcat在把数据返回给用户。
也就是说Servlet接口是处理网络请求的一套规范,他负责连接web服务器(如tomcat服务器),交互式的生成动态的web内容
2、过滤器
过滤器是在请求进入tomcat容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
理解上面这句话我们就可以知道,进入servlet之前,主要是两个参数:ServletRequest,ServletResponse 那我们得到这两个测试可以干哪些事呢?
我们可以通过ServletRequest得到HttpServletRequest,此时你就可以请求或响应(Request、Response),就可以对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息、字符集统一等一些高级功能。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁。(每次热部署后,都会销毁)。
3、拦截器
从上图我们可以看出过滤器只在servlet前后起作用,所以它既不能捕获异常,获得bean对象等,这些是只能是进入servlet里面的拦截器能过做到。拦截器中用于在某个方法或字段被访问之前,进行拦截然后,在之前或之后加入某些操作。比如日志,安全等。一般拦截器方法都是通过动态代理的方式实现。可以通过它来进行权限验证,或者判断用户是否登陆,或者是像12306 判断当前时间是否是购票时间。
对比一下其实我们可以发现,过滤器能做的事拦截器都能做,拦截器做的事过滤器不一定做的了。
4、监听器
listener是servlet规范中定义的一种特殊类。用于监听servletContext、HttpSession和servletRequest等域对象的创建和销毁事件。监听域对象的属性发生修改的事件。用于在事件发生前、发生后做一些必要的处理。其主要可用于以下方面:
- 统计在线人数和在线用户
- 系统启动时加载初始化信息
- 统计网站访问量
- 记录用户访问路径。
常用的监听器 servletContextListener、httpSessionListener、servletRequestListener
spring boot使用Servlet
两种方式:
1、使用spring boot提供的ServletRegistrationBean 注册Servlet
2、使用原生servlet注解定义Servlet
两种方式的本质都是一样的,都是去ServletRegistrationBean 注册自定义Servlet
方式一:
①、先定义Servlet:
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(">>>>>>>>>>doGet()<<<<<<<<<<<");
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(">>>>>>>>>>doPost()<<<<<<<<<<<");
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("自定义 Servlet");
}
}
②、注册 Servlet
将 Servelt 注册成 Bean。在上文创建的 WebConfig 类中添加如下代码:
@Configuration
public class WebConfig {
@Bean
public ServletRegistrationBean servletRegistrationBean() {
return new ServletRegistrationBean(new MyServlet(), "/mv");//匹配要处理的url
}
}
结果如下:
方式二:
1)启动类里面增加 @ServletComponentScan,进行扫描
2)新建一个Servlet类,extends HttpServlet ,并实现对应的接口
3)@WebServlet标记一个类为servlet,被spring进行扫描
@Component
@WebServlet(urlPatterns = "/map", description = "Servlet的说明")
public class MyServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(">>>>>>>>>>doGet()<<<<<<<<<<<");
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(">>>>>>>>>>doPost()<<<<<<<<<<<");
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>大家好,我的名字叫Servlet</h1>");
out.println("</body>");
out.println("</html>");
}
}
spring boot 使用过滤器
两种方式:
1、使用spring boot提供的FilterRegistrationBean注册Filter
2、使用原生servlet注解定义Filter
两种方式的本质都是一样的,都是去FilterRegistrationBean注册自定义Filter
方式一:
①、先定义Filter:
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("=======初始化过滤器MyFilter =========");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
long start = System.currentTimeMillis();
filterChain.doFilter(request, response);
System.out.println("filter 耗时:" + (System.currentTimeMillis() - start));
}
@Override
public void destroy() {
System.out.println("=======销毁过滤器MyFilter =========");
}
}
②、注册自定义Filter
@Configuration
public class WebConfig{
@Bean
public FilterRegistrationBean registrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
filterRegistrationBean.addUrlPatterns("/mv");
return filterRegistrationBean;
}
}
方式二:
1)启动类里面增加 @ServletComponentScan,进行扫描
2)新建一个Filter类,implements Filter,并实现对应的接口
3) @WebFilter 标记一个类为filter,被spring进行扫描
@WebFilter(filterName = "myFilter2", urlPatterns = "/map")
public class MyFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("执行过滤操作");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("过滤器销毁");
}
}
return registrationBean;
}
spring boot 使用监听器
同样也是两种方式,不废话了
①、编写监听器
public class MyHttpSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("Session 被创建");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("ServletContex初始化");
}
}
②、注册监听器
注册监听器为 Bean,在 WebConfig 配置类中添加如下代码:
@Bean
public ServletListenerRegistrationBean<MyHttpSessionListener> listenerRegistrationBean() {
return new ServletListenerRegistrationBean<>(new MyHttpSessionListener());
}
方式二:
@WebListener //使用注解方式注册
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("ServletContex初始化");
System.out.println(servletContextEvent.getServletContext().getServerInfo());
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("ServletContex销毁");
}
}
spring boot 使用拦截器
1、创建我们自己的拦截器类并实现 HandlerInterceptor 接口。
2、创建一个Java类继承WebMvcConfigurerAdapter,并重写 addInterceptors 方法。
3、实例化我们自定义的拦截器,然后将对像手动添加到拦截器链中(在addInterceptors方法中添加)。
①、定义拦截器:
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("========preHandle=========");
System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
System.out.println(((HandlerMethod)handler).getMethod().getName());
request.setAttribute("startTime", System.currentTimeMillis());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
System.out.println("========postHandle=========");
Long start = (Long) request.getAttribute("startTime");
System.out.println("耗时:"+(System.currentTimeMillis() - start));
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
throws Exception {
System.out.println("========afterCompletion=========");
Long start = (Long) request.getAttribute("startTime");
System.out.println("耗时:"+(System.currentTimeMillis() - start));
System.out.println(exception);
}
}
②、注册拦截器
编写拦截器后,我们还需要将其注册到拦截器链中,如下配置:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter{
@Autowired
private TimeInterceptor timeInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timeInterceptor);
}
}
请求一个 controller ,结果如下:
最后说明下,我们上面用到的 WebMvcConfigurerAdapter 并非只是注册添加拦截器使用,其顾名思义是做Web配置用的,它还可以有很多其他作用,通过下面截图便可以大概了解,具体每个方法都是干什么用的,留给大家自己研究(其实都大同小异也很简单)。
针对自定义 Servlet、Filter 和 Listener 的配置,还有另一种方式:
@SpringBootApplication
public class SpringbootWebApplication implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// 配置 Servlet
servletContext.addServlet("servlet",new MyServlet())
.addMapping("/**");
// 配置过滤器
servletContext.addFilter("filter",new MyFilter()) .addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST),true,"/**");
// 配置监听器
servletContext.addListener(new ListenerTest());
}
public static void main(String[] args) {
SpringApplication.run(SpringbootWebApplication.class, args);
}
}
最后强调一点:只有经过DispatcherServlet 的请求,才会走拦截器链,我们自定义的Servlet 请求是不会被拦截的,比如我们自定义的Servlet地址 http://localhost:8080/myservlet 是不会被拦截器拦截的。不管是属于哪个Servlet 只要符合过滤器的过滤规则,过滤器都会拦截。
源码
参考:
http://blog.csdn.net/catoop/article/details/50501696
https://www.cnblogs.com/moonlightL/p/7891806.html
https://www.cnblogs.com/higherman/p/8631182.html
https://blog.csdn.net/yudiandemingzi/article/details/80399971
https://blog.csdn.net/heweimingming/article/details/79993591
更多推荐
所有评论(0)