Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码、做一些业务逻辑判断等。其工作原理是,只要你在web.xml文件配置好要拦截的客户端请求,它都会帮你拦截到请求,此时你就可以对请求或响应(Request、Response)统一设置编码,简化操作;同时还可进行逻辑判断,如用户是否已经登陆、有没有权限访问该页面等等工作。它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁。

简单来说,过滤器filter的作用,它就相当于公路上的一个关卡,对要通过的拦截下来进行相关操作或放行。

dofilter作用【request -> filter1 -> filter2 ->filter3 -> .... -> request resource。】

看一个简单的没有filter的登录例子,当用户名和密码都是admin时,能跳转到success页面,否则到fail页面。

1、eclipse建立一个web project ,结果目录如下

其中,jsp很简单。在login.jsp为一个form表单

   <form action="<%=request.getContextPath() %>/servlet/LoginServlet" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
<input type="submit" value="提交">
</form>

配置文件xml中为

   <servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.imooc.serlvet.LoginServlet</servlet-class>
</servlet> <servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/servlet/LoginServlet</url-pattern>
</servlet-mapping>

LoginServlet.java中主要是

     public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password"); System.out.println(username); if("admin".equals(username) && "admin".equals(password)){
//校验通过
HttpSession session = request.getSession();
session.setAttribute("username", username);
response.sendRedirect(request.getContextPath()+"/sucess.jsp");
}else{
//校验失败
response.sendRedirect(request.getContextPath()+"/fail.jsp");
} }
public void init() throws ServletException {
// Put your code here
}

运行后浏览器地址栏进入:...8080/LoginFilter/login.jsp

当用户名和密码都输入admin,按下submit,就会进入action对应的servlet,然后重定向到success.jsp页面;用户名密码不对就到fail.jsp。

小例子结束。

仔细想会想到,可以直接在地址输入8080/LoginFilter/success.jsp不就进入了成功的页面了吗,还有类似页面。这样时不安全的,所以要加入拦截器

2、在此项目加入拦截器filter,也就是对其url进行拦截,不让其用url随便访问,结构中多了个类文件

在xml中添加

  <filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.imooc.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/success.jsp</url-pattern>
</filter-mapping>

这样,url输入...8080/LoginFilter/success.jsp就会进行拦截,进入LoginFilter.java

里面主要为:

   @Override
public void destroy() {
System.out.println("销毁...");
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
HttpSession session = request.getSession();
//因为登录后保存了username,所以可以先检查username判断是否登录
if(session.getAttribute("username")!=null){
arg2.doFilter(arg0, arg1);//已登录,则放行,
}else{
response.sendRedirect("login.jsp");//未登录,重定向到登录页面
}
}
public void init(FilterConfig arg0) throws ServletException
{ System.out.println("初始化..."); }

【过滤器Filter生命周期:init()->doFilter()->destroy()】

【 出现了 arg.doFailter(arg0,arg1),他表示好像放行、通过这样,继续往下到LoginServlet.java中,如果没有写 arg.doFailter(arg0,arg1)。那就是,把他拦截下来后,什么都不做,也不让它通过,那就会卡在那里不能往下了。】

【在这里只是request -> filter1 -> request resource。】

这样的思路,就可以拦截一些不能随便访问的页面,但如果这类页面很多,可访问的页面相对少,则可以把拦截的地址改为/*,也就是

    <filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/success.jsp</url-pattern>
</filter-mapping>
改成
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

再对本不用拦截的,比如login.jsp 在LoginFilter进行判断

      public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
HttpSession session = request.getSession();
//如果是login.jsp,则不拦截,直接放行,不用进行其他操作
if(request.getRequestURI().indexOf("login.jsp")!=-1 ){
arg2.doFilter(arg0, arg1);
return;
} //因为登录后保存了username,所以可以先检查username判断是否登录
if(session.getAttribute("username")!=null){
arg2.doFilter(arg0, arg1);//已登录,则放行,
}else{
response.sendRedirect("login.jsp");//未登录,重定向到登录页面
}

仔细想想,其他问题也来了,因为拦截所有页面,所以按下submit时都过不去(action="<%=request.getContextPath() %>/servlet/LoginServlet" 也要拦截,过不去),则要添加一些不需拦截的url

 //如果是下面3个url,则不拦截,直接放行,不用进行其他操作
if(request.getRequestURI().indexOf("login.jsp")!=-1
||request.getRequestURI().indexOf("servlet/LoginServlet")!=-1
||request.getRequestURI().indexOf("fail.jsp")!=-1
){
arg2.doFilter(arg0, arg1);
return;
}

但这样也有问题,当不需拦截的url多了,if语句也屡屡需要修改,很麻烦,则可以用 FilterConfig对象。先在xml添加配置,有新的不需要拦截的url,秩序在配置里添加即可。

     <filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.imooc.filter.LoginFilter</filter-class>
<init-param>
<param-name>noLoginPaths</param-name>
<param-value>login.jsp;fail.jsp;LoginServlet</param-value> //在此添加不需拦截的url
</init-param>
<init-param>
<param-name>charset</param-name> //防止中文乱码
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

在dofilter中得到此对象 LoginFilter.java

 public class LoginFilter implements Filter {
private FilterConfig config; //这里定义一下
@Override
public void destroy() { }
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
HttpSession session = request.getSession();
String noLoginPaths = config.getInitParameter("noLoginPaths"); //已获取filterconfig对象,可以获取其中属性 String charset = config.getInitParameter("charset");
if(charset==null){
charset = "UTF-8";
}
request.setCharacterEncoding(charset); if(noLoginPaths!=null){
String[] strArray = noLoginPaths.split(";"); //对属性的值分割。分别放行
for (int i = 0; i < strArray.length; i++) {
if(strArray[i]==null || "".equals(strArray[i]))continue;
if(request.getRequestURI().indexOf(strArray[i])!=-1 ){
arg2.doFilter(arg0, arg1);
return;
}
}
}
if(session.getAttribute("username")!=null){
arg2.doFilter(arg0, arg1);
}else{
response.sendRedirect("login.jsp");
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
config = arg0; //在初始化时把次对象赋值
} }
//执行顺序:最先初始化init(),然后dofilter函数 最后destory()

这里,这个登录案例就完成了。

那【request -> filter1 -> filter2 ->filter3 -> .... -> request resource。】是什么呢

就是一个url-partten对应了多个filter,一个url,被拦截了好几次。

   <filter>
<filter-name>FirstFilter</filter-name>
<filter-class>com.imooc.filter.FirstFilter</filter-class>
</filter>
<filter>
<filter-name>SecondFilter</filter-name>
<filter-class>com.imooc.filter.SecondFilter</filter-class>
</filter> <filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>SecondFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>

这样就存在一个过滤器链,按xml中顺序执行。

index.jsp

   <body>
This is my JSP page. <br>
<%
System.out.println("到了index.jsp");
%>
</body>

FirstFilter.java

 public class FirstFilter implements Filter {

     @Override
public void destroy() {
System.out.println("destroy---FirstFilter");
} @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("start----doFilter--FirstFilter");
chain.doFilter(request, response);
HttpServletRequest req =(HttpServletRequest) request;
HttpServletResponse response2 =(HttpServletResponse) response; System.out.println("end------doFilter--FirstFilter");
} @Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init----FirstFilter");
} }

SecondFilter.java

 public class SecondFilter implements Filter {

     @Override
public void destroy() {
System.out.println("destroy-----SecondFilter");
} @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("start---doFilter--SecondFilter");
chain.doFilter(request, response);
System.out.println("end---doFilter--SecondFilter");
} @Override
public void init(FilterConfig filterConfig) throws ServletException { System.out.println("init-----SecondFilter");
} }

过滤器链具体的执行顺序:

在运行项目时,两个filter类都执行了init()初始化,控制台输出:

init-----FirstFilter
init-----SecondFilter

当访问index.jsp时,进入FirstFilter.java的dofilter函数,控制台会依次输出:

start---doFilter--FirstFilter
start---doFilter--SecondFilter
到了index.jsp
end---doFilter--FirstFilter
end---doFilter--SecondFilter

在dofilter函数中,先执行chain.doFilter(request, response);前的代码,然后下一个filter链的下一个filter,然后进入index.jsp。再继续依次执行chain.doFilter(request, response);后面的代码

Code1表示ilter(request, response);之前的代码Code2表示ilter(request, response);之后的代码。

文章为学习记录,若有错误,望指正。

过滤器中的chain.doFilter(request,response)的更多相关文章

  1. 过滤器chain.doFilter(request,response)的含义

    过滤器的生命周期一般都要经过下面三个阶段: 初始化: 当容器第一次加载该过滤器时,init() 方法将被调用.该类在这个方法中包含了一个指向 Filter Config 对象的引用.我们的过滤器实际上 ...

  2. 过滤器链chain.doFilter(request,response)含义

    过滤器的生命周期一般都要经过下面三个阶段: 初始化 当容器第一次加载该过滤器时,init() 方法将被调用.该类在这个方法中包含了一个指向 Filter Config 对象的引用. 过滤 过滤器的大多 ...

  3. //可以不保存在session中, 并且前面我保存在request,这里session也可以获取 chain.doFilter(request, response); //只有登录名不为空时放行,防止直接登录 成功的页面

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOE ...

  4. 对chain.doFilter(request,response)的理解

    他的作用是将请求转发给过滤器链上下一个对象.这里的“下”指的是哪里 ? 指的是下一个filter,如果没有filter那就是你请求的资源. 一般filter都是一个链,web.xml 里面配置了几个就 ...

  5. chain.doFilter(request,response)含义

    过滤器的生命周期一般都要经过下面三个阶段: 初始化 当容器第一次加载该过滤器时,init() 方法将被调用.该类在这个方法中包含了一个指向 Filter Config 对象的引用.我们的过滤器实际上并 ...

  6. Java filter中的chain.doFilter详解

    转载: 一.chain.doFilter作用 1.一般filter都是一个链,web.xml 里面配置了几个就有几个.一个一个的连在一起 request -> filter1 -> fil ...

  7. 使用filter导致服务器返回的页面始终是空白---在doFilter中漏写了chain.doFilter()

    今天调代码的时候,突然发现,服务器开着,什么都没有问题,当我把下面这个filter给deploy了以后,访问所有的页面就都是空白. 后来发现,是因为在代码路径中,有一条路径没有调用filterChai ...

  8. Servlet中编码在过滤器中的使用

    1.先配置web.xml ->配置过滤器 // filter-class 为写的过滤器类 实现 Filter 接口 <filter> <filter-name>Encod ...

  9. chain.doFilter(req, resp)

    web中的Filiter过滤器: 当req不改变时,filiter在web中的配置和顺序没有关系: 但当在filiter中将其改变类型时,会导致其改变的request类型包装层次过多,无法获取其中的参 ...

随机推荐

  1. Connect to EC2 if losing Private Key

    http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#replacing-lost-key-pair

  2. 【Android UI】Android开发之View的几种布局方式及实践

    引言 通过前面两篇: Android 开发之旅:又见Hello World! Android 开发之旅:深入分析布局文件&又是“Hello World!” 我们对Android应用程序运行原理 ...

  3. (转)为什么用ls和du显示出来的文件大小有差别?

    曾经有几次,我用ls和du查看一个文件的大小,发现二者显示出来的大小并不一致,例如: bl@d3:~/test/sparse_file$ ls -l fs.img-rw-r--r-- 1 bl bl ...

  4. Font Awesome图标库

    Font Awesome 是一个非常方便的图标库.这些图标都是矢量图形,被保存在 .svg 的文件格式中.这些图标就和字体一样,你可以通过像素单位指定它们的大小,它们将会继承其父HTML元素的字体大小 ...

  5. PHPExcel(1.8.0) 帮助代码

    以下代码不能直接运行,只是提供各种方法调用写法. require_once dirname(__FILE__) . '/Classes/PHPExcel.php'; $objPHPExcel = ne ...

  6. java多线程(精华版)

    在 Java 程序中使用多线程要比在 C 或 C++ 中容易得多,这是因为 Java 编程语言提供了语言级的支持.本文通过简单的编程示例来说明 Java 程序中的多线程是多么直观.读完本文以后,用户应 ...

  7. Windows Server 2008 系统设置集合

    1.禁用IPV6 netsh interface teredo set state disabled netsh interface 6to4 set state disabled netsh int ...

  8. 将SQL SERVER数据库改成MySql

    (www.helpqy.com) 架构在阿里云上,最先想采用SQL SERVER,想大家都是微软家族的嘛.但是发现SQL SERVER需要的配置比较高,需要的银子也比较多,最后在纠结之下换成了MySq ...

  9. Java设计模式11:外观模式

    外观模式 外观模式是对象的结构模式,外部与一个子系统的通信必须通过一个统一的外观对象进行.外观模式是一个高层次的接口,使得子系统更易于使用. 医院的例子 现代的软件系统都是比较复杂的.假如把医院比作一 ...

  10. 【MVC】bootstrap-paginator 分页插件笔记

    bootstrap-paginator基于bootstrap框架,使用起来非常简单.github地址:https://github.com/lyonlai/bootstrap-paginator 在b ...