过滤器概念:是一个服务器端的组件,它可以截取用户端的请求与响应信息,并对这些信息过滤
工作原理:过滤器会过滤与在web.xml中配置的匹配的路径,若匹配到,则执行放行(doFilter)的方法,执行过滤链chainFilter知道web资源(jsp或servlet),然后返回执行过滤器剩下的部分
生命周期:实例化 web.xml 服务器启动时加载 初始化init 也是服务器启动时加载一次 doFilter destroy
init() 只是过滤器的初始化方法,Web容器创建过滤器实例后将调用这个方法。这个方法中可以读取web.xml文件中过滤器的参数
doFilter() 这个方法完成实际的过滤操作。这个地方式过滤器的核心方法。当用户请求访问与过滤器关联的URL时,Web容器将先调用过滤器的doFilter方法。FilterChain参数可以调用chain.doFilter放法,将请求传给下一个过滤器(或目标资源),或利用转发,重定向将请求转发到其他资源
Web.xml配置
<filter> <name> <class> <init-param>可以是要过滤的页面,可以设置要过滤的字符集>
<filter-mapping>针对一个filter可以配置多个mapping
<filter-name> <url-pattern>当用户请求的URL和指定的URL匹配时将触发过滤器工作 可使用*来通配
<dispatcher>可以是零对或多对,值为:REQUEST/INCLUDE/FORWORD/ERROR(过滤什么类型的请求) 未设定时默认值为REQUEST
问题1 过滤器是否能改变用户请求的web资源即请求的路径?√
如访问相应界面需首先登录
问题2 过滤器能否直接返回数据,能不能直接处理用户请求?
不能。因为他不是一个标准的Servlet 他只能跳转或重定向到一个web资源
过滤器链 多个过滤器如何实现,以及其对应一个用户请求的执行顺序是怎样的
服务器会按照web.xml中过滤器定义的先后顺序组装成一条链
放行方法chain.doFilter
执行顺序是用户请求到Filter1,执行Filter1中的code1,然后chain.doFilter进行放行,请求接着到了Filter2,执行其中的code1,然后chain.doFilter进行放行直到过滤器链走完到Servlet service(jsp或servlet),处理过程完成,然后返回执行Filter2中剩余代码code2,然后执行Filter1中剩余代码code2
过滤器的分类:REQUEST(通过请求(直接访问)就能直接到达过滤器) FORWORD INCLUDE ERROR ASYNC
重定向:response.setRedirect 会导致一个新的请求,会触发REQUEST监听,地址栏随之改变
转发:request.getReuqestDispatcher(path).forword/include 不会生成新的请求,性能较好,速度较快,会触发FORWORD/INCLUDE监听(jsp:forword/include也会触发)
ERROR
目标资源是通过声明式异常处理机制调用时,过滤器被触发
可以在web.xml中配置一个404错误界面(同理可配置500错误)
<error-page>
<error-code>404
<location>/error.jsp
配置好后,当用户输入错误路径时会自动跳转到error.jsp
这样ERROR过滤器也可以将mapping url设为error.jsp,这样一旦跳转到error.jsp,监听器就可以捕捉到
Servlet 3.0 支持异步处理 ASYNC
@WebFilter(filterName(String) value/urlPattern={String[]} dispatcherTypes={String[],要有DispatcherType.ASYNC} asyncSupported=true) (Dispatcher.async表示支持异步)
好处是不用等到servlet中的逻辑业务执行完后才结束Filter,可以先结束filter,后台继续处理业务。否则在Filter结束前,用户会一直等待页面的资源请求。
示例
Filter:
@WebFilter(filterName="asyncFilter",value={"/servlet/AsyncServlet"},asyncSupported=true,dispatcherTypes={DispatcherType.ASYNC,DispatcherType.REQUEST})
DoFilter:
System.out.println("start----AsyncFilter");
arg2.doFilter(arg0, arg1);
System.out.println("end------AsyncFilter");
Servlet:(要在web.xml设计模式中将该servlet中的async supported选项中的true打上勾)
doGet:(访问该servlet会调用其doGet方法)
System.out.println("servlet开始时间:"+new Date());
AsyncContext context = request.startAsync();//该方法返回AsyncContext类型对象,可以通过他获取request,从而使doGet外的代码通过获得context进而获得request
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;
}
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("业务执行结束时间:"+new Date());
}
}
访问/servlet/AsyncServlet 后台输出:
start----AsyncFilter
servlet开始时间:Mon Oct 02 11:16:58 CST 2017
servlet结束时间:Mon Oct 02 11:16:58 CST 2017
end------AsyncFilter
业务执行结束时间:Mon Oct 02 11:17:08 CST 2017
过滤器在实际项目中的应用场景:
1、对用户请求进行统一认证(如是否已登录)
2、编码转换(防止乱码)
3、对用户发送的数据进行过滤替换(防止攻击,检测参数)
4、转换图像的格式(response)
5、对相应的内容进行压缩(如加密处理)
登录验证:
1、可以在doFilter中对在登录时设置到session上的属性进行判断,并做出相应反映
2、使用/*对所有页面进行登录验证,要对登录页进行改动:在判断session前判断url是否为登录页:if(request.getRequestURL().indexOf(“login.jsp”) != -1){ arg2.doFilter(req,resp); return;}
后台验证用户名密码是否正确的servlet也不要过滤 if又要增加判断条件
而登录失败界面也不要过滤,这样发现也增加了代码量
这时可以利用过滤器中init的FilterConfig ,将不要过滤的地址设置到初始化参数中去并多个网址映射用分号分隔(web.xml design),在doFilter类中声明private FilterConfig config 使doFilter方法能通过config获得地址字符串,代码示例:
IndexOF:如果字符串参数作为一个子字符串在此对象中出现,则返回第一个这种子字符串的第一个字符的索引;如果它不作为一个子字符串出现,则返回 -1。
String noLoginPath = config.getInitParameter(“noLoginPaths”);
If(noLoginPath != null){
String[] strArray = noLoginPath.split(“;”);
For( int i = 0 ; i < strArray.length ; i++){
If(strArray[i] == null || “”.equals(strArrya[i])) //要判断是否为空,如果为空,则也会放行 continue;
If(request.getRequestURL().indexOf(strArray[i] != -1){
Arg2.doFilter(req,resp);
Return;
}
}
}
编码转换案例
表单提交的汉字到servlet会乱码的解决方法:servlet中进行强制转化
String username = request.getParameter(“username”);
System.out.println(new String(username.getBytes(“ISO-8859-1”),”UTF-8”));
这样每次接收参数时都转换格式会很麻烦,这时就可使用过滤器,只需在过滤器中:request.setCharacterEncoding(“UTF-8”);但通常在web.xml中配置一个init参数,然后通过config获得request.setCharacterEncoding(config.getInitParameter(“charset”));
或者接收String charset = config.getInitParameter(“charset”);
If(charset == null){
Charset = “utf-8”;//为空则设置为utf-8,有则使用设定好的字符集
}
Request.setCharacterEncoding(charset);