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. doxygen的使用(一)配置并生成文档

    原创文章,欢迎阅读,禁止转载. doxygen是个好用的文档生成工具,他的强大功能有很多介绍,我就不说了.自带的chm帮助手册很全面,包括功能.注释规范.怎么配置.工具用法等.doxygen的用法共3 ...

  2. 原生js-焦点图轮播

    首先是html实现页面结构及主程序 <!doctype html> <html> <head> <meta charset="utf-8" ...

  3. win32 COM组件编写

    win32的com组件: 1. 编辑idl,idl文件会生成对应的com class和com interface,例如 [ object, uuid(xxxxxxxx-xxxx-xxxx-xxxx-x ...

  4. VS2010 密钥问题

    密钥:YCFHQ9DWCYDKV88T2TMHG7BHP ①在VS2010安装包中找到setup==>setup.sdb 的Product Key把密钥改为上面的就可以了 ②不想重装那就在控制面 ...

  5. JS变量和函数的一些理解

    今日看了下JS变量的一些文章,有些感触,把自己总结的一些写出来. JS初始化的过程1.JS解释器执行代码之前,创建全局变量2.用预定义的值和函数来初始化全局对象中的属性,3.搜索函数外的var声明,创 ...

  6. 查看上下文切换的多的进程(find which process take the most context switch)

    这是原文链接http://serverfault.com/questions/190049/find-out-which-task-is-generating-a-lot-of-context-swi ...

  7. 项目文件""已被重命名或已不在解决方案中

    如题,这个错误在vs2010里,开始编译的时候出现了,我的解决办法就是把所有的project都移除,然后再添加进来,就不弹这个错误了.

  8. E9相关技术链接

    1.飞思卡尔i.MX6q安装ubuntu14.04操作系统:http://demo.netfoucs.com/bzw073/article/details/42551399 2. DS-5社区版安装: ...

  9. android开发中监控android软件网络请求的软件Charles使用入门

    1.下载并安状软件,官网在此: http://www.charlesproxy.com/ 2.前题条件,电脑和手机必须在同一网段 3.在Charles界面选择菜单 proxy->proxy se ...

  10. 如何在Hdevelop加入自己的算子

    halcon中允许用户编写自定义函数,同时也可以将此函数保存在其他工程中调用.   以halcon12讲解   创建自定义函数     本地程序函数:创建后仅能在当前工程使用 hdevelop函数文件 ...