javaweb——过滤器
过滤器
作用
实现对web资源请求的拦截,完成特殊的操作,尤其是对请求的预处理。
应用场景
- Web资源权限访问控制
- 字符集编码处理
- 内容敏感字符词汇过滤
- 响应信息压缩
工作流程
过滤器的生命周期
- 过滤器的创建和销毁由web服务器负责
- web应用程序启动时,web服务器创建Filter的实例对象 ,以及对象的初始化。(调用
init()
方法,这个方法只在tomcat服务器启动的时候调用一次) - 当请求访问与过滤器关联的web资源时(某个URL),过滤器拦截请求,完成指定功能(完成后交给下一个过滤器或者servlet进行处理)。(调用
doFilter()
方法,web程序运行期间可多次调用) - Filter对象创建后会一直驻留在内存中,在web应用移除或服务器停止时才销毁。(调用
destory()
方法)
过滤器链
-
在一个web应用中,多个过滤器组合起来称之为一个过滤器链。(比如说有的请求不止需要被一个过滤器拦截进行处理[先是字符集编码的处理的过滤器,再是判断是否登录的过滤器],这时就需要编写多个过滤器类来分别处理)
-
过滤器请求预处理的调用顺序取决于过滤器在web.xml文件中的注册顺序,而过滤器响应后处理的调用顺序取决于过滤器注册顺序的逆序。
(web.xml的顺序决定的是执行
doFilter()
的顺序 并不决定init()
的顺序)
过滤器的实现步骤
编写java类实现Filter接口
package filter;
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;
//要实现javax.servlet.Filter接口,重写下面三个方法
public class CharacterEncodingFilter implements Filter {
@Override
public void destroy() {
//在过滤器销毁的时候做一些清理工作
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//完成过滤器的功能
//request是请求预处理
//reponse是响应后处理
//不要忘记调用这个方法,意思是交给下一个过滤器或者servlet(请求本来要到达的地方)进行后续的操作处理
chain.doFilter(request,response);
}
@Override
public void init(FilterConfig config) throws ServletException {
this.config = config;
//在过滤器对象创建的时候做一些初始化操作
//参数中FilterConfig是过滤器配置类,在配置Filter的时候会设置一些初始化参数(设置初始化参数都是在web.xml文件中或者注解中完成),把这些配置封装成配置类对象传入进来
/*在web.xml中
<filter>
.....注册filter
<init-param>
<param-name>version</param-name>
<param-value>2.0</param-value>
</init-param>
</filter>
*/
/*
在init()函数中
通过 config.getInitParameter("version");能获取version的值
*/
}
}
在web.xml文件中对filter类进行注册,并设置所拦截的资源
<!-- 注册过滤器,让web服务器识别到这个过滤器要对一些web请求做拦截处理-->
<filter>
<filter-name>TestFilter</filter-name>
<filter-class>com.lxc.TestFilter</filter-class>
<!--设置过滤器配置类的初始化参数 -->
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!--拦截映射的配置,指定过滤器对哪些请求做拦截处理 -->
<!-- /*代表所有的请求都会被这个过滤器拦截 -->
<filter-mapping>
<filter-name>TestFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
配置要拦截的资源
-
以指定资源匹配。例如
"/index.jsp"
-
以目录匹配。例如
"/servlet/*"
-
以后缀名匹配,例如
"*.jsp"
-
通配符,拦截所有web资源。
"/*"
-
拦截多个页面
<filter> <filter-name>authority</filter-name> <filter-class>com.util.AuthorityFilter</filter-class> </filter> <filter-mapping> <filter-name>authority</filter-name> <url-pattern>/pages/genbill/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>authority</filter-name> <url-pattern>/pages/cmm/*</url-pattern> </filter-mapping>
filter-mapping的子元素dispather
必须写在filter-mapping的最后。dispatcher的前提条件当然是要先满足url-pattern
,然后是dispatcher属性。
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/test2.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
如果不写dispatcher
这个子属性,那么默认是REQUEST
dispatcher有四种可能的属性:
1、REQUEST
只要发起的操作是一次HTTP请求,比如请求某个URL、发起了一个GET请求、表单提交方式为POST的POST请求、表单提交方式为GET的GET请求。一次重定向则前后相当于发起了两次请求,这些情况下有几次请求就会走几次指定过滤器。
2、FOWARD
只有当当前页面是通过请求转发转发过来的情形时,才会走指定的过滤器 (但该过滤器必须指定了<dispatcher>FORWARD</dispatcher>
)
3、INCLUDE
只要是通过<jsp:include page="xxx.jsp" />
,嵌入进来的页面,每嵌入的一个页面,都会走一次指定的过滤器。
4、ERROR
假如web.xml里面配置了<error-page></error-page>
<error-page>
<error-code>400</error-code>
<location>/filter/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/filter/error.jsp</location>
</error-page>
不管这个请求是从哪里发过来的(
jsp
还是过滤器),发送方是什么方式就按什么方式匹配。
也可以把四种可能都写上,四种情况都会拦截
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/test2.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
使用注解配置Filter
@WebFilter(filterName = "CharsetFilter",
urlPatterns = { "/AddServlet","/qiantai/order.jsp","/RemoveServlet", "/UserOrderingServlet" },
dispatcherTypes = {DispatcherType.ASYNC,DispatcherType.ERROR},/*枚举类型*/
initParams = {
@WebInitParam(name = "charset", value = "utf-8"),/*这里可以放一些初始化的参数*/ @WebInitParam(name = "contenttype", value = "text/html;charset=utf-8")
})
使用注解配置的话,filter的执行顺序(过滤器类doFilter()
方法的执行顺序)跟过滤器类的类名的字母顺序有关,例如AFilter.java
会比BFilter.java
先执行
请求和响应字符集编码处理
package filter;
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;
public class CharacterEncodingFilter implements Filter {
//接收过滤配置类对象
private FilterConfig config;
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//不直接设置为UTF-8,而是把编码的信息放在web.xml文件中,以后直接修改web.xml中的初始化参数就行,避免了java代码的重新编译等操作
// 根据过滤器配置字符集,设置请求字符集编码
request.setCharacterEncoding(config.getInitParameter("charset"));
response.setContentType(config.getInitParameter("responsecharset"));
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig config) throws ServletException {
this.config = config;
}
}
web.xml文件
<!-- 字符集编码过滤器配置 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>responsecharset</param-name>
<param-value>text/html;charset=utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
登录验证
使用注解配置过滤器,拦截的时候不能拦截全部页面,不然会出现很多后续的麻烦
@WebFilter(filterName = "LoginFilter", urlPatterns = "*.jsp", dispatcherTypes = {})
public class SessionFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest hrequest = (HttpServletRequest)request;
HttpServletResponse hresponse = (HttpServletResponse)response;
String loginUser = (String)hrequest.getSession().getAttribute("loginUser");//从session对象中获取登录用户名
if(loginUser==null){//登录用户名不存在,用户未登录,强制重定向至登陆页面
hresponse.sendRedirect(hrequest.getContextPath()+"/index.jsp?flag=1");
return;
}else{
chain.doFilter(request, response);//已登录,转入相应的请求处理
return;
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}