文章目录
在容器调用Servlet的
service()
的方法钱,Servlet其实并不会知道有请求的到来,而在service()
方法执行后,容器真正对浏览器进行HTTP响应之前,浏览器也不知道Servlet真正响应是什么。过滤器(Filter
)正如其名称所示,它介于Servlet之前,可拦截浏览器对Servlet的请求,也可以改变Servlet对浏览器的响应。 其实说白了,过滤器就是应用程序的一个额外的组件,为了方便使用并且不改变Servlet源代码,比如用户验证,字符替换,压缩这类的需求,你可能只是暂时的需要这类需求,但是过一段时间又不需要了,如果直接在Servlet中改动源码,那么就太麻烦了。因此此时就需要设置一个独立的组件,在使用的时候直接引用,不需要的时候直接删除即可,这就是过滤器的必要。
想要实现过滤器,那么需要实现
Filter
接口,这个接口中有三个必须实现的方法,分别为init()
,doFilter()
,destroy()
。init(FilterConfig config)
这是一个初始化方法,其中的参数可以获取定义的初始值,这个在后面会详细说destroy()
这个是销毁方法doFilter(HttpServletRequest request,HttpServletResponse response,FilterChain chain)
这是主要的方法,用来执行过滤的作用。当请求来到了web容器中,容器发现了调用Servlet的service()
方法之前可以应用某过滤器的时候就会调用该过滤器的doFilter()
方法。就是在doFilter()方法中进行了service()方法的前置处理,而后根据是否调用FilterChain
中的doFilter()
决定是否执行下一个过滤器,如果没有那么就执行第一个过滤器。 如果执行了FilterChain的doFilter()
方法,那么就会执行下一个过滤器,如果没有就调用指定的Servlet的service()
方法。
service()
方法之前进行的处理,就是Servlet还没有接受到请求的时候,后置处理就是在Servlet执行过service()方法之后,就是Servlet已经处理完请求之后。因此FilterChain
的doFilter()
方法就将过滤器处理分为了前置处理和后置处理,在调用FilterChain
的doFilter()
方法之前的都是对Servlet的前置处理,也就是说这时候Servlet并不知道此时有请求过来,而在其之后的都是对Servlet的后置处理。doFilter(HttpServletRequest request,HttpServletResponse response,FilterChain chain) { //service()的前置处理 chain.doFilter(request,response); //service()的后置处理 }
FilterChain
执行后会一堆栈顺序返回,就是说如果有多个Filter
,那么就先按照顺序执行chain.doFilter(request,response)
之前的代码,即是先前置处理,然后入栈,这样一直到执行到最后一个Filter
,之后就从栈顶开始执行chain.doFilter()
的方法之后的代码,即是后置处理。总的来说就是先执行前置处理,然后入栈,待全部执行完毕之后再从栈顶开始后置处理的代码。
Filter
的doFilter
的方法中的request
,response
和Servlet的doGet()
和doPost()
方法中的是一样的,即是可以设置属性,可以得到表单提交的值,总之是一样的。
package com; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; public class FilterDemo1 implements Filter { public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 根据request获取表单的用户名和密码 String username = request.getParameter("username"); String password = request.getParameter("password"); // 如果用户名和密码正确 if ("陈加兵".equals(username) && "123456".equals("password")) { System.out.println("用户名或者密码错误,请重新输入"); } //继续执行下一个过滤器,如果有就执行 chain.doFilter(request, response); //当所有过滤器的前置处理都执行完毕才执行这个语句 System.out.println("Servlet已经执行完毕"); } public void init(FilterConfig config) throws ServletException { } }
web.xml
中设置过滤器,设置的方式如下:<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>web2</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- 定义FilterDemo1的过滤器 --> <filter> <!--设置过滤器文件的名字--> <filter-name>FilterDemo1</filter-name> <!--设置过滤器类所在的路径,具体到包名--> <filter-class>com.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>FilterDemo3</filter-name> <!--设置作用的url,即是Demo9这个Servlet应用这个过滤器--> <url-pattern>/Demo9</url-pattern> <!-- <servlet-name>Demo9</servlet-name> 这个标签和上面的<url-pattern>是一个效果,直接指明应用的Servlet的名称 --> <!--Demo1也应用这个过滤器--> <servlet-name>Demo1</servlet-name> </filter-mapping> <!-- 定义FilterDemo1的过滤器 --> <!-- 定义FilterDemo2的过滤器 --> <filter> <filter-name>FilterDemo2</filter-name> <filter-class>com.FilterDemo2</filter-class> </filte> <filter-mapping> <filter-name>FilterDemo2</filter-name> <!-- Demo1这个Servlet文件也应用FilterDemo2这个过滤器,那么当请求Demo的时候要按照定义的先后顺序先执行FilterDemo1这个过滤器 --> <url-pattern>/Demo1</url-pattern> </filter-mapping> <!-- 定义FilterDemo2的过滤器 --> </web-app>
<filter-mapping>
中定义多个Servlet文件,表示多个Servlet都应用于这个过滤器这个和
ServletConfig
一样的都存在初始参数,当然定义的方式也是不尽相同,都是在web.xml
中定义的,如下:
<filter> <filter-name>FilterDemo3</filter-name> <filter-class>com.FilterDemo3</filter-class> <!--直接在filter下可以设置初始参数,当然我们可以在过滤器中获取参数--> <init-param> <param-name>username</param-name> <param-value>陈加兵</param-value> </init-param> <init-param> <param-name>password</param-name> <param-value>123456</param-value> </init-param> </filter>
直接利用其中的
init(FilteConfig config)
获取初始化参数
package com; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; public class FilterDemo1 implements Filter { public String username; public String password; public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { } //直接在init方法中利用FilterConfig的方法获取参数的值 public void init(FilterConfig config) throws ServletException { //获取初始值 username=config.getInitParameter("username"); password=config.getInitParameter("password"); } }
当我们直接请求Servlet文件的url或者表单提交的时候使用的都是浏览器默认发出的请求,这个是可以触发过滤器的。但是如果是那些重定向(
sendirect
)或者转发包含(forward
,include
)就不会默认触发,因此我们需要在web.xml
设置触发的时机,定义如下:
<filter-mapping> <filter-name>FilterDemo1</filter-name> <url-pattern>/Demo1</url-pattern> <dispatcher>REQUEST</dispatcher> <!--默认的--> <dispatcher>FORWARD</dispatcher> <!--forward--> <dispatcher>INCLUDE</dispatcher> <!--include--> <dispatcher>ERROR</dispatcher> <!--error --> </filter-mapping>
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句