up:: 过滤器urlpattern设置过滤范围
一:过滤链简介
如下图,过滤器1,过滤器2,Servlet这三者组成了一个完整的过滤链。
注意事项:即chain.doFilter()向后传递的时候是根据web.xml中<filter-mapping>的书写顺序为依据 的;
二:过滤链案例
案例:包括,FilterA,FilterB,FilterC三个过滤器,web.xml配置文件,HelloServlet这个Servlet:
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 >filter-chain</ 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 >filterAA</ filter-name >
< filter-class >com.imooc.filter.FilterA</ filter-class >
</ filter >
< filter-mapping >
< filter-name >filterAA</ filter-name >
< url-pattern >/*</ url-pattern >
</ filter-mapping >
< filter >
< filter-name >filterBB</ filter-name >
< filter-class >com.imooc.filter.FilterB</ filter-class >
</ filter >
< filter-mapping >
< filter-name >filterBB</ filter-name >
< url-pattern >/*</ url-pattern >
</ filter-mapping >
< filter >
< filter-name >filterCC</ filter-name >
< filter-class >com.imooc.filter.FilterC</ filter-class >
</ filter >
< filter-mapping >
< filter-name >filterCC</ filter-name >
< url-pattern >/*</ url-pattern >
</ filter-mapping >
</ web-app >
HelloServlet.java:这个Servlet不是本篇博客的重点啦
package com.imooc.filter;
import java.io.IOException;
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 HelloServlet
*/
@ WebServlet ( "/hello" )
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L ;
/**
* @see HttpServlet#HttpServlet()
*/
public HelloServlet () {
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
response. getWriter (). println ( "hello world!" );
System.out. println ( "hello nihao!!!" );
}
/**
* @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);
}
}
启动应用后,访问localhost:8080/filter-chain/hello:浏览器页面可以显示HelloServlet返回的内容,这个很简单;
同时,在控制台:按照在web.xml中<filter-mapping>的书写顺序,依次执行三个过滤器;当执行到过滤器C的时候,接下来没有过滤器了,就将请求传递到HelloServlet;
三:第一个需要注意的问题:chain.dofilter()书写位置 与 请求和响应过程中执行的关系
但是如果把FilterA,FilterB,FilterC三个过滤器的chain.doFilter()都写在前面:
此时启动应用,访问localhost:8080/filter-chain/hello时候:
原因解释:FilterA,FilterB,FilterC这三个过滤器的doFilter()方法中,chain.doFilter()都放在了前面,这意思就是,当请求过来的时候,这个过滤器会执行chain.doFilter()方法,当执行到chain.doFilter()这条语句的时候,就会把请求传递给下一个过滤器了,这样从FilterA传到FilterB,从FilterB传到FilterC,控制台就依次打印了A!,B!和C!;一直传给了HelloServlet,输出“hello nihao!!!”;
然后,当 响应的时候,按照反方向,依次执行FilterC中的doFilter()方法中的chain.doFilter()语句后面的内容 ,然后是FilterB,然后是FilterA;这样,控制塔就依次打印出了This is Filter C! ;This is Filter B! 和 This is Filter A!;( _ _ 注解,这个仅仅在这儿ok,并没有经过多次验证哎,但大概率应该是没问题的~~~ __ )
补:控制过滤链中断:阻挡请求(一种简单的防火墙)
启动应用:
这种在程序中刻意控制chain.doFilter()方法调用的场景是比较常见的;比如:互联网安全是非常重要的,比如,开发的网站只对中国的IP开发,外国的IP不能访问,怎么做呐?
可以获取请求的IP,如果IP是中国的,就去调用chain.doFilter()方法,将请求放行;如果IP是外国的,就 通过if else判断,不去执行chain.doFilter()这句话,中断请求 ,从而这个IP为外国的请求就被过滤器挡在了外面;(这也是简单的一种防火墙)
四:第二个需要注意的问题:注解形式时,过滤器执行的顺序(仅供了解,因为在实际工作中基本不会采用这种策略)
关于过滤器的执行顺序:(1)当过滤器采用web.xml配置的方式的时候,按照在web.xml中<filter-mapping>的书写顺序,来依次执行;(2)
过滤器采用注解的时候,过滤器的执行顺序怎么确定呐???
如下:
启动应用,访问localhost:8080/filter-chain/hello:
其实当过滤器采用注解的形式的时候:其按照类名来决定前后顺序的,按照字母升序,从小到大,且字母不区分大小写;所以先执行FilterA,然后执行FilterB,最后执行FilterC;
如,把FilterA过滤器类的类名改成FilterZ时:再次访问的时候: