一.Filter
1. Filter概述
Filter:一个实现了特殊接口(Filter)的Java类. 实现对请求资源(Servlet,JSP,HTML,CSS…)的过滤的功能.
过滤器是一个运行在服务器的程序, 优先于请求资源(Servlet或者jsp,html)之前执行. 过滤器是javaweb技术中最为实用的技术.
2.过滤器的作用
对目标资源(Servlet,jsp)进行过滤.
应用场景:登录权限检查,解决网站乱码,过滤敏感字符 ...
3. Filter使用
3.1 配置文件方式
- 创建一个类实现Filter接口
public class FilterDemo01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterDemo01 收到了请求...");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
- 在web.xml里面进行配置
<!--注册filter-->
<filter>
<filter-name>FilterDemo01</filter-name>
<filter-class>com.filter.FilterDemo01</filter-class>
</filter>
<!--配置filter过滤器-->
<filter-mapping>
<filter-name>FilterDemo01</filter-name>
<url-pattern>/demo01</url-pattern>
</filter-mapping>
3.2注解方式
- 创建一个类实现Filter接口
- 在这个类上面添加@WebFilter(“拦截的路径”)
@WebFilter("/demo02")
public class FilterDemo02 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterDemo02 收到了请求...");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
4. Filter的生命周期
4.1Filter生命周期介绍
过滤器从 创建 到 销毁 的过程
4.2 生命周期方法
init(FilterConfig):初始化
doFilter(ServletReqeust req,ServletResponse resp,FilterChain chain):执行过滤的方法
destroy():销毁
4.3Filter生命周期描述
- 服务器启动的时候, 调用init()方法进行初始化【调用一次】
- 任何一次请求资源, 都会调用doFilter()方法进行过滤【前提是过滤器的路径和请求资源路径相匹配】
- 服务器正常关闭或者项目从服务器移除, 会调用destory()方法进行销毁【调用一次】
4.4 FilterConfig
获得过滤器的初始化参数
- 配置初始化参数
<filter>
<filter-name>FilterDemo03</filter-name>
<filter-class>com.filter.FilterDemo03</filter-class>
<!--配置过滤器的初始化参数-->
<init-param>
<param-name>aKey</param-name>
<param-value>aaa</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>FilterDemo03</filter-name>
<url-pattern>/demo03</url-pattern>
</filter-mapping>
public class FilterDemo03 implements Filter {
/**
* 初始化的方法
* 调用时机:服务器启动时,调用init()方法,初始化过滤器
* 调用次数:1次
*
* FilterConfig 过滤器的配置对象
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init()...5555+"+filterConfig.getInitParameter("aKey"));
}
/**
* 过滤的方法
* 调用时机:每一次请求,且请求的路径满足过滤器的配置路径,执行doFilter()方法
* 调用次数:请求几次调用几次
*
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterDemo03 收到了请求..");
filterChain.doFilter(servletRequest,servletResponse);
}
/**
* 销毁的方法
* 调用时机:服务器正常关闭,执行destroy()方法,销毁过滤器
* 调用次数:1次
*/
@Override
public void destroy() {
System.out.println("destroy()...");
}
}
5.映射路径
假设有一个管理员权限的过滤器,它应该对用户发出的管理员功能的请求进行条件的过滤。但是当用户发出登录、注册等请求的时候,不应该进行过滤。所以我们过滤器,应该有选择的过滤器请求。这就需要学习配置过滤器不同的映射路径,从而让过滤器过滤希望过滤器的请求。
-
完全路径匹配, 以"/"开始
/demo01 ---> 过滤器只能拦截路径/demo01;
-
目录匹配:以"/"开始 以 *结束 .
/* --->当前项目下的所有的路径都可以拦截; /aa/* ---> 可以拦截 /aa/bb, /aa/bb/cc
-
扩展名匹配:以"*"开始 例如: *.jsp *.do
*.do--->可以拦截路径的后缀是 do的 ; *.jsp--->拦截所有JSP
6.拦截方式
有了上面学习的映射路径,我们可以控制过滤器过滤指定的内容,但是我们在访问资源的时候,并不是每次都是之间访问,有时是以转发的方式访问的,这就需要我们要让过滤器可以区分不同的访问资源的方式,有不同的拦截方式。 是通过 DispatcherType 来指定的.
-
DispatcherType.REQUEST
默认值,过滤从浏览器发送过来的请求和重定向 不过滤转发
-
DispatcherType.FORWARD
只过滤转发过来的请求
注意:
一般情况下, 我们不会过滤转发的, 因为转发是服务器内部行为, 使用默认值就好了
6. 过滤器链
过滤器链作用:当一个filter收到请求的时候,调用chain.doFilter才可以访问下一个匹配的filter,若当前的filter是最后一个filter,调用chain.doFilter才能访问目标资源
7.统一全网站中文乱码的处理
在整个网站中,可能会有get请求或post请求向服务器提交参数.参数中往往有中文信息.在后台每个Servlet中都需要去处理乱码.
我们想做的是:请求到达Servlet中.就可以直接调用getParameter方法获得请求参数,请求参数已经没有乱码了.
package com.itheima.web.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/*")
public class CodeFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1.强转两个参数
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//2.处理乱码(请求和响应)
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//3.放行
chain.doFilter(request, response);
}
public void destroy() {
}
public void init(FilterConfig config) throws ServletException {
}
}
package com.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@WebFilter("/*")
public class CodeFilter02 implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//强转两个参数
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//1.使用jdk的动态代理创建request代理对象
HttpServletRequest proxyRequest = (HttpServletRequest) Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强getParameter方法
if ("getParameter".equals(method.getName())){
if ("post".equalsIgnoreCase(request.getMethod())){
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
return method.invoke(request,args);
}
return method.invoke(request,args);
}
return method.invoke(request,args);
}
});
//放行
chain.doFilter(proxyRequest, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
}
}