Java Web开发技术应用——过滤器

1.过滤器简介

过滤器定义:
过滤器是一个服务器端的组件,它可以截取用户端的请求与相应信息,并对这些信息过滤

2.[Java Web] 过滤器的工作原理和生命周期

过滤器的工作原理:
在没有过滤器的时候,用户发出请求,直接访问我们web资源,假如说存在过滤器,直接访问是不行的。
过滤器是在web应用程序启动的时候就加载了,用户发送请求到过滤器,过滤器来判断用户请求是否合法,之后将请求发送至web资源,资源响应之后又发送给过滤器,再从过滤器将web资源的响应发送给客户
这里写图片描述
过滤器生命周期
实例化(web.xml配置)只执行一次
初始化(init())只执行一次
过滤(doFilter())获取请求均会执行该方法
销毁(destroy())在web容器关闭时会执行销毁
这里写图片描述

3.[Java Web] 第一个过滤器案例

这里创建web项目,src文件夹下创建包,接口Filter,会自动生成

  • init()方法,web容器在创建过滤器的实例后会进行初始化,调用这个方法,该方法可以读取web.xml文件中过滤器的参数;
  • doFilter()方法,进行实际的过滤操作,这是过滤器的核心方法,当用户请求访问与过滤器关联的URL时,web容器将先调用doFilter方法。FileChain参数可以调用chain.doFilter方法,将请求传给下一个过滤器或目标资源,或利用转发重定向将请求转发到其他资源
  • destroy()方法,销毁过滤器前会调用该方法,释放占用的资源,一般用不到。

如何自动生成web.xml,在web项目生成时最后有一个选项打钩即可。
web.xml配置
这里写图片描述
其中filter标签里的是过滤器类,上面是过滤器名过滤器类,类名需要包含包名也就是完整名称,而init-param是初始化参数信息,可以向浏览器传递零对或者多对参数值。
filter-mapping是过滤器映射,可以设置一个或者多个url地址,dispatcher是过滤器的类型,可以设置过滤什么请求,默认是request。在设置web.xml时,eclipse提供了一个快捷方法,点击design设置,然后选择filter,可以添加一个filter Add new filter或者添加一个filter映射 Add new Filter Mapping,分别设置完成配置,如果过滤所有浏览器则在映射url地址填入“/*”,如果是某些前缀的地址则比如“/index *”之后这样我们第一个过滤器也就配置成功了

<?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>ImoocFilterOne</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <filter>
    <filter-name>FirstFilter</filter-name>
    <filter-class>com.imooc.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


</web-app>

FirstFilter类

package com.imooc.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 FirstFilter implements Filter {

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
            throws IOException, ServletException {
        // TODO 自动生成的方法存根
        System.out.println("开始?");
        arg2.doFilter(arg0, arg1);
        System.out.println("结尾");
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException{
        System.out.println("init");
    }
}

这里有两个问题,过滤器是否能改变用户请求的web资源呢?也就是能否改变用户请求的路径,这个是可以的,不符合要求比如可以跳转到注册界面等等。
过滤器能否直接返回数据呢?能不能处理用户请求,这个是不能的,不是servlet,它可以重定向。

4.[Java Web] 过滤链

这里我们来学习一下,web项目中多个过滤器是如何实现的?多个过滤器对应同一个用户路径执行顺序如何?
首先过滤器是支持多个过滤器的,我们可以声明过滤器1,也可以声明过滤器2,那么每个过滤器都有自己对应的url地址,这里面我们可以用来过滤用户的请求,假如说我们过滤器1和过滤器2没有交集,并不相等。
多个过滤器的情况
1:多个过滤器过滤的URL不同,那么此时的多个过滤器是互不相干的,各过滤各的,互不干扰
2:多个多虑期过滤的URL相同,那么此时的多个过滤器就形成了一个过滤器链,根据在Web.xml文件中配置的声明的顺序来决定,哪个先过滤哪个后过滤

这里写图片描述
核心方法是 doFilter()方法
这里写图片描述
第二个过滤器范例,过滤器链

package com.imooc.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 SecondFilter implements Filter {
    @Override
    public void destroy() {
        System.out.println("结束--secondFilter");
    }

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
            throws IOException, ServletException {
        // TODO 自动生成的方法存根
        System.out.println("secondFilter--doFilter--start");
        arg2.doFilter(arg0, arg1);
        System.out.println("secondFilter--doFilter--end");
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException{
        System.out.println("初始化---seconFilter");
    }

}

控制台输出结果:
调用service之前执行一段代码-doFilter-FirstFilter–start
secondFilter–doFilter–start
处理过程完成
secondFilter–doFilter–end
调用service之后执行一段代码-doFilter-FirstFilter–end
这里可以观察到,首先指定的是第一个过滤器的放行前方法,之后是第二个过滤器的放行前方法,之后到达我们的web资源,也就是index.jsp进行业务处理。之后执行的是第二个过滤器的放行后方法,然后是第一个过滤器的放行后方法

5.[Java Web] 过滤器的分类1

在servlet2.5中过滤器分为4种类别,它包括request、forward、include以及error,首先我们先讲解request这个过滤器的使用,它主要是用户直接访问页面时,Web容器将会调用过滤器。
这里我们先将上节第二个过滤器注释在web.xml中注释掉,下面来增加一点难度,我们再给第一个过滤器增加一个映射main.jsp,然后我们在1过滤器中取消放行方法,直接强行跳转到main.jsp。这里我们思考一下,我们访问index时会执行过滤操作,跳转到main.jsp,同时main.jsp同样也设置了过滤映射,一样会进行过滤操作,而再进行操作时又会进行跳转,这里会出现死循环,下面实际操作来验证一下。

public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) 
            throws IOException, ServletException {
        // TODO 自动生成的方法存根
        System.out.println("调用service之前执行一段代码-doFilter-FirstFilter--start");
        //arg2.doFilter(arg0, arg1);

        HttpServletRequest request=(HttpServletRequest)arg0;
        HttpServletResponse response=(HttpServletResponse)arg1;
        request.getRequestDispatcher("main.jsp").forward(request,response);
        //response.sendRedirect("main.jsp");

        System.out.println("调用service之后执行一段代码-doFilter-FirstFilter--end");
    }

使用send重定向出现了无限循环,走的是request。也可以理解成它告诉了浏览器我们要访问一个新的地址了。
而使用转发forward结果则是进入main.jsp界面后结束,也就是第二个过滤映射没有起作用,这是重定向和转发的区别,前者url栏已经变成了main.jsp,有一个新的请求在访问,而转发则还是原来的请求,浏览器不关心你到底访问哪个地址,请求转发到了main.jsp,url地址栏不变。这是自己的看法不知道对不对,而后面就将介绍forward类型的过滤器。
forward过滤器,目标资源是通过RequestDispatcher的forward()访问时,该过滤器将被调用。
此时我们修改过滤器类型为forward,然后看一下转发的结果有异常吗
在映射中添加<dispatcher>FORWARD</dispatcher>

<filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <url-pattern>/index.jsp</url-pattern>

  </filter-mapping>
  <filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <url-pattern>/main.jsp</url-pattern>
    <dispatcher>FORWARD</dispatcher> 
  </filter-mapping>

此时又出现了死循环结果
include和jsp同理

request.getRequestDispatcher("main.jsp").include(request,response);
<jsp:forward page="main.jsp"></jsp:forward>
<jsp:include page="main.jsp"></jsp:include>

include过滤器,目标资源是通过RequestDispatcher的include方法()调用时,该过滤器将被调用。

6.[Java Web] 过滤器的分类2

ERROR类过滤器:目标资源是通过声明式异常处理机制调用时,过滤器将被调用。
比如说我们访问一个路径的时候,出现一个错误,那么这个时候系统会给出一个错误提示,那么这个错误给用户之后,用户看不懂这个错误是什么概念,这个时候我们就需要给出一个人性化的提示,下面我们来进行演示。我们将之前案例中的第二个main.jsp映射注释掉,使用重定向mian.jsp。此时我们测试,如果访问mian1.jsp则会出现404报错。这时我们就可以使用error功能了。
在web.xml中添加一个标签

<error-page>
    <error-code>404</error-code>
    <location>/error.jsp</location>
  </error-page>

有了此标签,如果访问地址是404错误就会直接显示error.jsp
然后我们要用过滤器,应该再添加一个过滤器标签和过滤器类

<filter>
    <filter-name>ErrorFilter</filter-name>
    <filter-class>com.imooc.filter.ErrorFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>ErrorFilter</filter-name>
    <url-pattern>/error.jsp</url-pattern>
    <dispatcher>ERROR</dispatcher>
  </filter-mapping>

添加一个ErrorFilter类

public class ErrorFilter implements Filter {

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
            throws IOException, ServletException {
        // TODO 自动生成的方法存根
        System.out.println("捕捉到异常!");
        arg2.doFilter(arg0, arg1);
    }
}

这里记得要设置放行就会显示error.jsp页面。
在servlet2.5中是四个选项,REQUEST FORWARD INCLUDE ERROR。在3.0中又添加了一个功能ASYNC,支持异步处理。
在3.0之中,它加入了@WebFilter
@WebFilter这是用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。例如:

@WebFilter(servletNames={"SimpleServlet"},filterName="SimpleFilter")
public class LessThanSixFilter implements Filter{...}

@WebFilter的常用属性
这里写图片描述

7.[Java Web] 过滤器的分类3

这里我们首先来设置一个过滤器

package com.imooc.filter;

import java.io.IOException;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter(filterName="AsynFilter",value="/asyn.jsp",dispatcherTypes= {
DispatcherType.REQUEST,DispatcherType.ASYNC
})

public class AsynFilter implements Filter {

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
            throws IOException, ServletException {
        // TODO 自动生成的方法存根
        System.out.println("start...asynfilter");
        arg2.doFilter(arg0, arg1);
        System.out.println("end...asynfilter");
    }

}

创建jsp页面后我们发现过滤器有了,但是实际的异步我们这里还没有具体实现,下面开始补充。这里我们创建一个新的包servlet包里建立AsynServlet文件,重写doGet()方法,这个时候我们就需要线程的操作,在线程里模拟异步的操作,创建一个内部线程类

package com.imooc.servlet;

import java.io.IOException;
import java.util.Date;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class AsynServlet
 */

public class AsynServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public AsynServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        System.out.println("servlet开始时间"+new Date());
        AsyncContext context =request.startAsync();// 将context对象传入到run方法里,在执行线程的时候是没办法获取request和response
        new Thread(new Executor(context)).start();
        System.out.println("servlet结束时间"+new Date());
    }
    public class Executor implements Runnable{
        private AsyncContext context;
        public Executor(AsyncContext context) {
            this.context=context;
            context.getRequest();
            context.getResponse();
            //可以通过它来获取
        }
        @Override
        public void run() {
            // TODO 自动生成的方法存根
            try {
                Thread.sleep(1000*10);
                System.out.println("业务执行完成时间"+new Date());      
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
        }   
    }


    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

web.xml配置

<servlet>   
    <servlet-name>AsynServlet</servlet-name>   
    <servlet-class>com.imooc.servlet.AsynServlet</servlet-class>   
    <async-supported>true</async-supported>   
  </servlet> 
  <servlet-mapping>
    <servlet-name>AsynServlet</servlet-name>   
    <url-pattern>/AsynServlet</url-pattern>
  </servlet-mapping>

过滤器设置

@WebFilter(filterName="AsynFilter",value="/AsynServlet",
asyncSupported=true,dispatcherTypes= {DispatcherType.REQUEST,DispatcherType.ASYNC
})

控制台结果:
start…asynfilter
servlet开始时间Wed Dec 27 19:39:57 CST 2017
servlet结束时间Wed Dec 27 19:39:57 CST 2017
end…asynfilter
业务执行完成时间Wed Dec 27 19:40:07 CST 2017

最后一条晚了10秒钟,异步。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值