赞
踩
在Java Web的开发中,最原始和初期的学习都是从Servlet
开始的,Servlet是Java最为耀眼的技术,也是Java EE的技术变革。目前大火主流的框架spring boot也的spring mvc部分也是基于拓展servlet完成的。回到之前的文章spring 实现了对servlet的封装,来构造控制器controller的过程:Spring MVC框架基础知识,以及servlet的相关知识
在Java Web开发的过程中除了servlet还有比较重要的有拦截器和过滤器,监听器。它们具体作用如下:
servlet :web容器是一种运行服务器端的java应用程序,具有独立于平台和协议的特性,并且可以动态的生成web页面,它工作在客户端请求与服务器响应的中间层。
filter:过滤器是一个可以复用的代码片段,可以用来转换HTTP请求、响应和头信息。Filter不像Servlet,它不能产生一个请求或者响应,它只是修改对某一资源的请求,或者修改从某一的响应。
listener:监听器,listener主要用来监听使用。通过listener可以监听web服务器中某一个执行动作,并根据 其要求作出相应的响应。
interceptor: 拦截器主要用于拦截程序并对程序作出相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
servlet、filter、listener在ssm中配置到web.xml中,interceptor不配置到web.xml中。spring的拦截器配置到spring.xml中。在spring boot大多是通过配置类注入。它们的关系如下图所示:
Servlet 过滤器是可用于 Servlet 编程的 Java 类,有以下目的:
根据规范建议的各种类型的过滤器:
(1)身份验证过滤器(Authentication Filters)。
(2)数据压缩过滤器(Data compression Filters)。
(3)加密过滤器(Encryption Filters)。
(4)触发资源访问事件过滤器。
(5)图像转换过滤器(Image Conversion Filters)。
(6)日志记录和审核过滤器(Logging and Auditing Filters)。
(7)mime-TYPE 链过滤器(MIME-TYPE Chain Filters)。
(8)标记化过滤器(Tokenizing Filters)。
(9)XSL/T 过滤器(XSL/T Filters),转换 XML 内容。
过滤器被部署在部署描述符文件 web.xml
中,然后映射到您的应用程序的部署描述符中的 Servlet 名称或 URL 模式。
当 Web 容器启动 Web 应用程序时,它会为您在部署描述符中声明的每一个过滤器创建一个实例。该过滤器执行的顺序是按它们在部署描述符中声明的顺序。
Servlet 过滤器实例:
过滤器是包裹Servlet因此两者都必须存在
//servlet //导入必需的 java 库 import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/demo") //扩展 HttpServlet 类 public class DemoServlet extends HttpServlet { // 处理 GET 方法请求的方法 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置响应内容类型 response.setContentType("text/HTML;charset=UTF-8"); PrintWriter out = response.getWriter(); String title = "HTTP Header 请求实例"; String docType = "<!DOCTYPE html> \n"; out.println(docType + "<html>\n" + "<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n"+ "<body bgcolor=\"#f0f0f0\">\n" + "<h1 align=\"center\">" + title + "</h1>\n" + "<table width=\"100%\" border=\"1\" align=\"center\">\n" + "<tr bgcolor=\"#949494\">\n" + "<th>Header 名称</th><th>Header 值</th>\n"+ "</tr>\n"); Enumeration headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()) { String paramName = (String)headerNames.nextElement(); out.print("<tr><td>" + paramName + "</td>\n"); String paramValue = request.getHeader(paramName); out.println("<td> " + paramValue + "</td></tr>\n"); } out.println("</table>\n</body></html>"); } // 处理 POST 方法请求的方法 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
//Filter过滤器 // 导入必需的 java 库 import java.io.*; import javax.servlet.*; import javax.servlet.Http.*; import java.util.*; // 实现 Filter 类 public class LogFilter implements Filter { public void init(FilterConfig config) throws ServletException { // 获取初始化参数 String site = config.getInitParameter("Site"); // 输出初始化参数 System.out.println("网站名称: " + site); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException { // 获取客户机的 IP 地址 String ipAddress = request.getRemoteAddr(); // 记录 IP 地址和当前时间戳 System.out.println("IP "+ ipAddress + ", Time " + new Date().toString()); // 把请求传回过滤链 chain.doFilter(request,response); } public void destroy( ){ /* 在 Filter 实例被 Web 容器从服务移除之前调用 */ } }
web.xml
配置servlet和Filter以及过滤器和web容器的映射关系//过滤器配置 <filter> <filter-name>LoginFilter</filter-name> <filter-class>com.test.LogFilter</filter-class> <init-param> <param-name>Site</param-name> <param-value>kubiji在线教程</param-value> </init-param> </filter> //servlet配置 <servlet> <!-- 类名 --> <servlet-name>DemoServlet</servlet-name> <!-- 所在的包 --> <servlet-class>com.=test.DemoServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DemoServlet</servlet-name> <!-- 访问的网址 --> <url-pattern>/demo</url-pattern> </servlet-mapping> //Servlet Filter Mapping <filter-mapping> <filter-name>LogFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
过滤器的作用范围:
一个过滤器的作用范围与路径配置有关url-pattern
可以配置/*
所有路径也可以配置某个web容器,所以Web 应用程序可以根据特定的目的定义若干个不同的过滤器链:
<filter> <filter-name>LogFilter</filter-name> <filter-class>com.kubiji.test.LogFilter</filter-class> <init-param> <param-name>test-param</param-name> <param-value>Initialization Paramter</param-value> </init-param> </filter> <filter> <filter-name>AuthenFilter</filter-name> <filter-class>com.kubiji.test.AuthenFilter</filter-class> <init-param> <param-name>test-param</param-name> <param-value>Initialization Paramter</param-value> </init-param> </filter> <filter-mapping> <filter-name>LogFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>AuthenFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
过滤器的应用顺序:
web.xml 中的 filter-mapping 元素的顺序决定了 Web 容器应用过滤器到 Servlet 的顺序。若要反转过滤器的顺序,您只需要在 web.xml 文件中反转 filter-mapping 元素即可。
SpringMVC的过滤器位于spring-web-[xxx].jar工具包下:
如上所示的spring-web.jar
包结构所示, Spring的web包中中提供有很多过滤器,这些过滤器位于org.springframework.web.filter
并且理所当然地实现了javax.servlet.Filter
。
不过实现的方式有以下几类:
(1) 直接实现Filter,这一类过滤器只有CompositeFilter;
(2) 继承抽象类GenericFilterBean,该类实现了javax.servlet.Filter,这一类的过滤器只有一个,即DelegatingFilterProxy;
(3) 继承抽象类OncePerRequestFilter,该类为GenericFilterBean的直接子类,这一类过滤器包括CharacterEncodingFilter、HiddenHttpMethodFilter、HttpPutFormContentFilter、RequestContextFilter和ShallowEtagHeaderFilter;
(4) 继承抽象类AbstractRequestLoggingFilter,该类为OncePerRequestFilter的直接子类,这一类过滤器包括CommonsRequestLoggingFilter、Log4jNestedDiagnosticContextFilter和ServletContextRequestLoggingFilter。
过滤器放在容器结构的什么位置?
过滤器放在web资源之前,可以在请求抵达它所应用的web资源(可以是一个Servlet、一个Jsp页面,甚至是一个HTML页面)之前截获进入的请求,并且在它返回到客户之前截获输出请求。Filter:用来拦截请求,处于客户端与被请求资源之间,目的是重用代码。Filter链,在web.xml中哪个先配置,哪个就先调用。在filter中也可以配置一些初始化参数。
Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。
过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
总结:过滤器包裹住servlet,servlet包裹住拦截器。
doFilter( ServletRequest request, ServletResponse response, FilterChain chain)
的入参是ServletRequest ,而不是httpservletrequest。因为过滤器是在httpservlet之前。@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("before...");
chain.doFilter(request, response);
System.out.println("after...");
}
chain.doFilter(request, response)
这个方法的调用作为分水岭。事实上调用Servlet的doService()方法是在chain.doFilter(request, response)这个方法中进行的。
Spring boot的过滤器
在Spring中,过滤器是配置声明在web.xml文件中的,所有的过滤器在web.xml(web容器的配置文件)中定义,springboot中,web.xml文件消失。各种配置被Java类取代。@Configuration注解标记配置类,代替xml配置文件。
因此过滤器也通过注解注入到IOC容器中,注解@WebFilter
声明一个过滤器,里面的参数,filterName 为过滤器名字,urlPatterns 为过滤器的范围,initParams 为过滤器初始化参数。
@Order(1)
@WebFilter(filterName = "piceaFilter", urlPatterns = "/*" , initParams = {
@WebInitParam(name = "URL", value = "http://localhost:8080")})
使用包扫描@ServletComponentScan("com.example.demofilter.filter")
在启动类自动注册Filter。
@Order(1) @WebFilter(filterName = "myFilter",urlPatterns = {"/*"}) public class MyFilter 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("before filter"); filterChain.doFilter(servletRequest,servletResponse); System.out.println("after filter"); } @Override public void destroy() { System.out.println("过滤器被销毁了"); }
@WebFilter注解,filterName属性表示filter的名称,urlPatter表示要拦截的URL资源,可以是一个或者多个。用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。该注解具有下表给出的一些常用属性 ( 以下所有属性均为可选属性,但是 value、urlPatterns、servletNames 三者必需至少包含一个,且 value 和 urlPatterns 不能共存,如果同时指定,通常忽略 value 的取值
@Order(1)表示如果有多个拦截器的话就是设置这个拦截器的运行等级,数字越小,越先执行。
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean registFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setName("Filter1");
registrationBean.setOrder(1);
return registrationBean;
}
}
@ServletComponentScan
:在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener
可以直接通过@WebServlet、@WebFilter、@WebListener
注解自动注册,无需其他代码。
拦截器方法都是通过代理的方式来调用的,拦截器是基于java反射机制来实现的。
第一个不是,第二个才是,Interceptor
是spring中特有的概念。在 Spring中,当请求发送到 Controller 时,在被Controller处理之前,它必须经过 Interceptors(0或多个)。Spring Interceptor是一个非常类似于Servlet Filter 的概念 。
如下案例:
public class LogInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { long startTime = System.currentTimeMillis(); System.out.println("brefore login --- "); System.out.println("Request URL: " + request.getRequestURL()); System.out.println("Start Time: " + System.currentTimeMillis()); request.setAttribute("startTime", startTime); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("login --- "); System.out.println("Request URL: " + request.getRequestURL()); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("after loggin --- "); long startTime = (Long) request.getAttribute("startTime"); long endTime = System.currentTimeMillis(); System.out.println("Request URL: " + request.getRequestURL()); System.out.println("End Time: " + endTime); System.out.println("Time Taken: " + (endTime - startTime)); } }
@Configuration
public class MyInterceptorConfig extends WebMvcConfigurationSupport {
@Override
protected void addInterceptors(InterceptorRegistry registry) {
// 将上面自定义好的拦截器添加进去。
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
Interceptor的拦截范围其实就是Controller方法,它实际上就相当于基于AOP的方法拦截。因为Interceptor只拦截Controller方法,所以要注意,返回ModelAndView并渲染后,后续处理就脱离了Interceptor的拦截范围。
一个Interceptor必须实现HandlerInterceptor接口,可以选择实现preHandle()、postHandle()和afterCompletion()方法。preHandle()是Controller方法调用前执行,postHandle()是Controller方法正常返回后执行,而afterCompletion()无论Controller方法是否抛异常都会执行,参数ex就是Controller方法抛出的异常(未抛出异常是null)
过滤器和拦截器的区别:
拦截器Interceptor
同 Filter
过滤器一样,它俩都是面向切面编程——AOP 的具体实现
拦截器是基于java的反射机制的,而过滤器是基于函数回调。
拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
拦截器的概念
SpringMVC 中的Interceptor 拦截器的主要作用就是拦截用户的 url 请求,并在执行 handler 方法的前中后加入某些特殊请求。SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断用户是否登陆等。
Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等。
监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。
Servle监听器
在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别 ServletContext, HttpSession和ServletRequest这三个域对象。servlet监听器的注册不是直接注册在事件源上,而是由WEB容器负责注册,开发人员只需在web.xml文件中使用标签配置好监听器。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。