1、过滤器的概念
Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。
优点:过滤链的好处是,执行过程中任何时候都可以打断,只要不执行chain.doFilter()就不会再执行后面的过滤器和请求的内容。而在实际使用时,就要特别注意过滤链的执行顺序问题
2、过滤器的作用描述
3、特点
Servlet过滤器是在Java Servlet规范2.3中定义的,它能够对Servlet容器的请求和响应对象进行检查和修改,它在Servlet被调用之前检查Request对象,修改Request Header和Request内容;在Servlet被调用之后检查Response对象,修改Response Header和Response内容。Servlet过滤器负责过滤的Web组件可以是Servlet、JSP或HTML文件,具有以下特点:
4、接口
所有的Servlet过滤器类都必须实现javax.servlet.Filter接口。该接口定义了以下3个方法:
5、Filter过程
它使用户可以改变一个request和修改一个response. Filter 不是一个servlet,它不能产生一个response,它能够在一个request到达servlet之前预处理request,也可以在离开servlet时处理response.换种说法,filter其实是一个”servletchaining”(servlet 链).一个filter 包括:
你能够配置一个filter 到一个或多个servlet;单个servlet或servlet组能够被多个filter 使用.几个实用的filter 包括:用户辨认filter,日志filter,审核filter,加密filter,符号filter,能改变xml内容的XSLTfilter等.
6、Filter建立步骤
过滤器需要在web.xml文件中进行配置
<!-- 配置Filter --> <filter> <filter-name>LogFilter</filter-name> <filter-class>com.mucfc.LogFilter</filter-class> </filter> <filter-mapping> <filter-name>LogFilter</filter-name> <url-pattern>/*</url-pattern><!-- 表示处理根目录下的所有请求 --> </filter-mapping>
或者直接用注解:
@WebFilter(filterName="log",urlPatterns={"/*"}) public class LogFilter implements Filter { ................................. }
7、映射的配置
(1) 映射到一个或多个jsp
<filter-mapping> <filter-name>FilterName</filter-name> <url-pattern>/path/FileName.jsp</url-pattern> </filter-mapping>
(2) 映射到一个或多个servlet
<filter-mapping> <filter-name>FilterName</filter-name> <servlet-name>ServletName1</servlet-name> </filter-mapping> <filter-mapping> <filter-name>FilterName</filter-name> <servlet-name>ServletName2</servlet-name> </filter-mapping>
(3) 映射到任意的url
<filter-mapping> <filter-name>FilterName</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
下面我们要通过Filter来输出一个Hello World,先建立一个web工程。
然后添加一个Filter如下:
package com.mucfc; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebFilter(filterName="log",urlPatterns={"/*"}) public class LogFilter implements Filter { private FilterConfig filterConfig; @Override public void destroy() { filterConfig=null; } @Override public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { //获取ServletContext对象,用于记录日志 ServletContext servletContext=filterConfig.getServletContext(); long before=System.currentTimeMillis(); System.out.println("开始过滤"); HttpServletRequest httpServletRequest=(HttpServletRequest)arg0; //输出信息 System.out.println("Filter已经截获到用户的请求地址"+httpServletRequest.getServletPath()); //Filter 只是链式处理,请求依然放行到目的地址 arg2.doFilter(arg0, arg1); //输出到服务器响应执行后处理 long after=System.currentTimeMillis(); System.out.println("过滤 结束"); System.out.println("请求被定位到"+httpServletRequest.getRequestURI()+" 所花时间为"+(after-before)); } @Override public void init(FilterConfig arg0) throws ServletException { filterConfig=arg0; } }
这里是直接使用注解的方式来配置Filter,也可以在web.xml中配置
然后就是另一个Servlet
package com.mucfc; import java.io.IOException; import java.io.PrintWriter; 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(name="HelloServlet" ,urlPatterns="/HelloServlet") //采用WebServlet注解,不用再到web.xml中配置 public class HelloServlet extends HttpServlet { private static final long serialVersionUID = 1L; public HelloServlet() { super(); } protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("gb2312"); response.setCharacterEncoding("gb2312"); PrintWriter out=response.getWriter(); out.println("你好!hello World "); out.close(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } }
这里也是基于注解实现Servlet。这样子可以省去在web.xml中大量的代码,速度更加的快!
@WebServlet(name="HelloServlet" ,urlPatterns="/HelloServlet")
相当于以下
<!-- 配置servlet --> <servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>com.mucfc.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/HelloServlet</url-pattern> </servlet-mapping>
控制台输出:
页面输出:
1、request过滤器
这种过滤器的工作方式比较简单,大家也经常遇到,如下所示:以下是web.xml文件配置方式:
<filter> <filter-name>myFilter</filter-name> <filter-class>packagename.MyFilterName</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter> <servlet-name> 目标资源</servlet-name> </filter-mapping>
下面我们更改一下web.xml文件的配置,如下方式:
<filter> <filter-name>myFilter</filter-name> <filter-class>packagename.MyFilterName</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter> <servlet-name> 目标资源1</servlet-name> </filter-mapping> <filter-mapping> <filter-name>myFilter</filter> <servlet-name> 目标资源2</servlet-name> </filter-mapping>
答案就在于,目标资源一是客户端直接访问,而目标资源二是被转发过来的,这时过滤器就不能过滤目标资源二。如果你直接访问目标资源二,你会发现该过滤器起到了作用?
我们上面的web.xml文件配置与以下方式等价:
<filter> <filter-name>myFilter</filter-name> <filter-class>packagename.MyFilterName</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter> <servlet-name> 目标资源1</servlet-name> <dispatcher>REQUEST</dispatcher> </filter-mapping> <filter-mapping> <filter-name>myFilter</filter> <servlet-name> 目标资源2</servlet-name> <dispatcher>REQUEST</dispatcher> </filter-mapping>
那如果我想对转发到目标资源二的请求进行过滤,那怎么办呢?答案见,下一种过滤器,forward过滤器。
2、forward过滤器
我们将web.xml文件的配置修改如下:
<filter> <filter-name>myFilter</filter-name> <filter-class>packagename.MyFilterName</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter> <servlet-name> 目标资源1</servlet-name> <dispatcher>REQUEST</dispatcher> </filter-mapping> <filter-mapping> <filter-name>myFilter</filter> <servlet-name> 目标资源2</servlet-name> <dispatcher>FORWARD</dispatcher> </filter-mapping>
3、include过滤器
理解了forward过滤器之后,include过滤器就不难理解了。以下方式:
<filter> <filter-name>myFilter</filter-name> <filter-class>packagename.MyFilterName</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter> <servlet-name> 目标资源1</servlet-name> <dispatcher>REQUEST</dispatcher> </filter-mapping> <filter-mapping> <filter-name>myFilter</filter> <servlet-name> 目标资源2</servlet-name> <dispatcher>INCLUDE</dispatcher> </filter-mapping>
此表示对包含了目标资源二的请求过滤,如果直接访问目标资源二,则此过滤器将不起作用。
在JSP页面中的动作:指令包含,这时此过滤器不工作。
4、error过滤器
当我们访问一个web目标资源时,如果服务器没有找到该目标资源,那么服务器就会给出一个404错误代码。如果我们给404错误代码定义一个页面,那么当404错误发生时就会调用该页面,请看以下web.xml文件的配置:
<filter> <filter-name>myFilter</filter-name> <filter-class>packagename.MyFilterName</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter> <servlet-name> /error.jsp</servlet-name> <dispatcher>ERROR</dispatcher> </filter-mapping> <error-page> <error-code>404</error-code> <location>/error.jsp</location> </error-page>
如果我们访问一个已经存在的页面,会不会调用error.jsp呢?如果这个页面中有response.sendError(404,"出错了!");那么该错误页面仍然会被调用,过滤器也会工作。
现在很多网页都要你用账号登录后才能浏览相关的内容。这里我实现通过登录账号,然后浏览相应的网页。
1、新建一个web工程,最终目录 如下:
2、登陆界面JSP:
<%@ page language="java" contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>登录</title> </head> <body> <form action="http://localhost:8080/ServletLearningChapter2_2/Main.jsp" method="POST"> 用户:<input type="text" name="username" /><br/> 密码:<input type="password" name="password" /><br/> <input type="submit" value="登录" /> </form> </body> </html>
功后进行主界面:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@page import="java.util.*"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <% String name=request.getParameter("username"); %> 欢迎用户: <%=name %> 您已经登录成功,可以尽情浏览本网站 </body> </html>
来访问到Main.jsp的。如下:
但是实际我们是想要得用户登录后才能访问,所以要增加如下的过滤 器
5、过滤器
package com.mucfc; 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.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * * 权限过滤器 * * */ public class AuthorityFilter implements Filter { private FilterConfig config; @Override public void destroy() { this.config=null; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //获取Filter配置参数 String encoding=config.getInitParameter("encoding"); String loginPage=config.getInitParameter("loginPage"); String afterLogin=config.getInitParameter("afterLogin"); //设置request编码 request.setCharacterEncoding(encoding); HttpServletRequest requ=(HttpServletRequest) request; HttpSession session=requ.getSession(); //获取客户请求页面 String requestPath=requ.getServletPath(); String name=requ.getParameter("username"); if(name==""||name==null){ System.out.println("权限拦截器的消息:"+"终止"); HttpServletResponse resq=(HttpServletResponse)response; resq.sendRedirect(requ.getContextPath()+loginPage); }else{ System.out.println("权限拦截器的消息:"+"放行"); request.setCharacterEncoding("UTF-8"); chain.doFilter(request, response); } } @Override public void init(FilterConfig config) throws ServletException { this.config=config; } }
6、然后在web.xml中来配置过滤器(这里也可以直接 用注解的方式 来配置,具体看上面的例子)
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <welcome-file-list> <welcome-file>Login.html</welcome-file> <welcome-file>Login.htm</welcome-file> <welcome-file>Login.jsp</welcome-file> </welcome-file-list> <!-- 权限拦截器 --> <filter> <filter-name>AuthorityFilter</filter-name> <filter-class>com.mucfc.AuthorityFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>GBK</param-value> </init-param> <init-param> <param-name>loginPage</param-name> <param-value>/Login.jsp</param-value> </init-param> <init-param> <param-name>afterLogin</param-name> <param-value>/Main.jsp</param-value> </init-param> </filter> <filter-mapping> <filter-name>AuthorityFilter</filter-name> <url-pattern>/Main.jsp</url-pattern> </filter-mapping> </web-app>
然后什么都不输入,直接点击登录,发现又跳转到Login.jsp
浏览器中直接输入http://localhost:8080/ServletLearningChapter2_2/Main.jsp,它又会自动跳转到Login.jsp
然后输入一个用户名和密码,就可以正确跳转到Main.jsp(这里没做用户名和密码的判断,只做了一个用户判断)
再来看看控制台的输出结果
从控制台的输出结果我们可以知道是正确 的!
原文地址:http://blog.csdn.net/linzhongxia2015/article/details/45694141