参考博客:http://www.cnblogs.com/coderland/p/5902878.htmlhtml
http://www.javashuo.com/article/p-qhrjwvaw-mv.htmljava
基本概念在参考博客中,已经讲的很清楚了。这里,简单总结一下,并贴一个完整实例。web
总结:服务器
1)Filter称为过滤器。它是一个服务器端的组件。经过Filter技术,对web服务器管理的全部web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。session
2)Filter技术主要进行对用户请求的预处理,也能够对服务器响应进行后处理。app
这两种状况都属于直接访问页面(也包括直接访问Servlet),故在配置<filter-mapping>时,能够不写<dispatcher>,使用默认的REQUEST。(也能够写出来直接指定为REQUEST)jsp
通常地,客户端提交请求信息经过HttpServletRequest到达Servlet,而后Servlet进行处理并产生响应,响应经过HttpServletResponse传递到客户端。ide
Filter在HttpServletRequest到达Servlet以前,拦截客户的HttpServletRequest,根据须要检查HttpServletRequest,或者修改HttpServletRequest 头和数据,称为对用户请求的预处理。post
Filer在HttpServletResponse从Servlet到达客户端以前,拦截HttpServletResponse ,根据须要检查HttpServletResponse,或者修改HttpServletResponse头和数据,称为对服务器响应进行后处理。ui
3)Filer的生命周期:
实例化(web.xml)——>初始化(init()方法)——>过滤(doFilter()方法)——>销毁(destroy()方法)
public void init(FilterConfig filterConfig) throws ServletException;//初始化 //filter对象只会建立一次,init方法也只会执行一次 和咱们编写的Servlet程序同样,Filter的建立和销毁由WEB容器负责。 web 应用程序启动时,web 容器读取web.xml配置文件, 将建立Filter 的实例对象,并调用其init方法(这个init方法中能够读取web.xml文件中过滤器的参数)完成对象的初始化功能, 从而为后续的用户请求做好拦截的准备工做。开发人员能够经过init方法的参数FilterConfig对象,得到当前filter配置信息。 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;//拦截请求 //可执行n次 这个方法完成实际的过滤操做。当客户请求访问与过滤器关联的URL的时候执行该方法。FilterChain参数的doFilter方法用于访问后续过滤器或者调用目标资源。 public void destroy();//销毁 //该方法在Filter的生命周期中仅执行一次。 Filter对象建立后会驻留在内存,当web应用移除或服务器中止时才销毁。在Web容器卸载 Filter 对象以前被调用。在这个方法中,能够释放过滤器使用的资源。
4)Filter开发步骤:
(1)编写java类实现javax.servlet.Filter接口,并实现其doFilter方法;
(2)在web.xml文件中对编写的filter类进行注册,并设置它所能拦截的资源。
5)Filter链:
在一个web应用中,能够开发编写多个Filter,这些Filter组合起来称之为一个Filter链。
web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪一个Filter,当第一个Filter的doFilter方法被调用时,web服务器会建立一个表明Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员若是调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,若是有,则调用第2个filter,若是没有,则调用目标资源。
6)FilterConfig接口:
用户在配置filter时,可使用为filter配置一些初始化参数(<init-param>),当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。所以开发人员在编写filter时,经过filterConfig对象的方法获取相关初始化信息。
7)在检查URI路径中的是否含有某个初始值,对于servlet来讲,是指配置servlet时指定的url-pattern的值,而不是servlet类名。
8)在实现Filter的类中的doFilter()方法中,须要将传进来的ServletRequest转换为HttpServletRequest,将传进来的ServletResponse转换为HttpServletResponse,才能进行相关方法的调用。
9)过滤器的分类:
(1)REQUEST:当用户直接访问页面(包括用户请求的预处理和对服务器响应进行后处理)时,Web容器将会调用过滤器。若是目标资源是经过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
(2)INCLUDE:若是目标资源是经过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此以外,该过滤器不会被调用。
(3)FORWARD:若是目标资源是经过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此以外,该过滤器不会被调用。
(4)ERROR:若是目标资源是经过声明式异常处理机制调用时,那么该过滤器将被调用。除此以外,过滤器不会被调用。
贴个例子,实现两个过滤器一个判断用户是否登陆而后跳转指定页面,一个用来处理乱码问题:
login.jsp:
<form action="doLogin" method="post"> 用户名:<input type="text" name="userName"/><br/> 密码:<input type="password" name="password"/><br/> <input type="submit" value="登陆"/> <input type="reset" value="重置"/> </form>
建立一个success.jsp用于展现跳转成功。
建立登陆跳转Servlet:
package com.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @SuppressWarnings("serial") public class DoLoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String userName=req.getParameter("userName"); String password=req.getParameter("password"); System.out.println(userName); if("张三".equals(userName)&&"123".equals(password)){ //校验经过 HttpSession session = req.getSession(); session.setAttribute("userName", userName);
//这里必须使用重定向,不能使用请求转发
//请求转发:request.getRequestDispatcher().forward()是属于FORWARD类型的过滤器,须要在配置过滤器时,写明FORWARD类型的<dispatcher> resp.sendRedirect("success.jsp"); }else { resp.sendRedirect("login.jsp"); } } }
注意:
请求转发:即request.getRequestDispatcher().forward(),是一种服务器的行为,客户端只有一次请求,服务器端转发后会将请求对象保存,地址栏中的URL地址不会改变,获得响应后服务器端再将响应发给客户端;
请求重定向:即response.sendRedirect(),是一种客户端行文,从本质上讲等同于两次请求,前一次请求对象不会保存,地址栏的URL地址会改变。
请求转发与请求重定向的区别,参考博客:http://blog.csdn.net/u012877472/article/details/50804568
建立第一个过滤器(解决乱码):
package com.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; import javax.servlet.http.HttpServletRequest; public class SetEconding implements Filter { @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest)arg0; //解决乱码问题 req.setCharacterEncoding("UTF-8"); //别忘了放行 arg2.doFilter(arg0, arg1); } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
建立第二个过滤器(是否登陆):
package com.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; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class LoginFilter implements Filter {
//定义一个FilterConfig,用于传递出初始化方法init()中的FilterConfig对象 private FilterConfig config=null;
@Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest)arg0; HttpServletResponse resp=(HttpServletResponse)arg1; HttpSession session=req.getSession(); //获取配置文件中配置的初始化参数,在这里是获取不过滤页面名单 String initParam=config.getInitParameter("NotFilter"); String[] notFilterPages=initParam.split(";");
//不过滤的页面直接调用FilterChain的doFilter()方法跳转到下个过滤器或者目标资源 if(notFilterPages!=null){ for(int i=0;i<notFilterPages.length;++i){ //跳过字段为空和空字符串的状况 if(notFilterPages[i]==null||"".equals(notFilterPages[i]))continue; //注意这里是URI路径中的是否含有某个初始值,对于servlet来讲,是指配置servlet时指定的url-pattern的值,而不是servlet类名 if(req.getRequestURI().indexOf(notFilterPages[i])!=-1){ arg2.doFilter(arg0, arg1); return; } } }
//当登陆成功(即session中存在“userName”的值),则跳转到下一个过滤器或者目标资源 //只要未登陆成功,全部的页面跳转请求(免除过滤的页面和servlet处理类除外)都将跳转到登陆页面 if(session.getAttribute("userName")!=null){ arg2.doFilter(arg0, arg1); return; }else{ resp.sendRedirect("login.jsp"); return; } } @Override public void init(FilterConfig arg0) throws ServletException { config=arg0; } }
web.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>javaEE_filter</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> <!-- 第1个过滤器 --> <!-- 配置解决乱码过滤器 --> <filter> <filter-name>SetEcondingFilter</filter-name> <filter-class>com.filter.SetEconding</filter-class> </filter> <!-- 配置解决乱码过滤器映射 --> <filter-mapping> <filter-name>SetEcondingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 第2个过滤器 --> <!-- 配置登陆过滤器 --> <filter> <filter-name>LoginFilter</filter-name> <filter-class>com.filter.LoginFilter</filter-class> <init-param> <param-name>NotFilter</param-name> <param-value>login;doLogin</param-value> </init-param> </filter> <!-- 配置登陆过滤器映射 --> <filter-mapping> <filter-name>LoginFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置处理登陆的Servlet --> <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>com.servlet.DoLoginServlet</servlet-class> </servlet> <!-- 配置处理登陆Servlet的映射 --> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/doLogin</url-pattern> </servlet-mapping> </web-app>
乱码问题的解决方案:
乱码问题的解决代码主要有两种即便用request对象的setCharacterEncoding()方法和String的构造器方法。
例:
req.setCharacterEncoding("UTF-8");
userName=new String(userName.getBytes("ISO-8859-1"),"UTF-8");
1)使用过滤器:
在本例中,为了说明过滤器的执行顺序,而定义了两个过滤器并在配置时将处理乱码的过滤器放在了靠前的位置,可是对于处理乱码的过滤器彻底能够将代码
req.setCharacterEncoding("UTF-8");
放在判断是否登陆的过滤器的doFilter方法体中(最好放在方法体靠前位置,以保证过滤时先进行代码乱码的过滤)。而无需建立第二个过滤器。
2)固然,也可使用javaBean的方式解决代码乱码问题