一、概述
过滤器:
地漏,滤网,滤纸,口罩,净水机 :过滤掉杂质
servlet 过滤器:
拦截不符合要求的请求进行拦截,使之不能够到达servlet
对请求的数据进行加工处理
作用:
1.拦截 (不符合要求请求拦截,使之不达到servlet)
2.抽取公共代码,对共同的的业务进行抽离,加工数据
二、过滤器使用场景
设置编码格式
//解决当前servlet 接收中文乱码
req.setCharacterEncoding("utf-8");
// 解决响应乱码
resp.setContentType("text/html;charset=utf-8");
记录日志信息
记录所用请求的路径,参数,客户端ip,异常 等信息
为什么记录日志?
在软件的生产/线上环境 只能使用日志排查bug
将鉴权的代码抽离带过滤其中
减少代码冗余
黑白名单,敏感词过滤
举例:一个用户每秒钟访问服务器100次/机器攻击 将用户加入黑名单,拒绝提供服务
三、实现过滤器
实现Filter
编写Java类实现Filter接口
在doFilter方法中编写拦截逻辑
设置拦截路径
import javax.servlet.*;
import java.io.IOException;
/**
* 第一个过滤器
* 1.实现 javax.servlet.Filter
*
* 2.完成 public void doFilter 方法
*
* 3.声明 Filter
* 1.在web.xml
* <!--
* 声明 过滤器
* -->
* <filter>
* <filter-name>MyFilter1</filter-name>
* <filter-class>com.qfedu.servlet.filter.MyFilter1</filter-class>
* </filter>
*
* <!--
* 为MyFilter1 配置感兴趣的路径
* /* 对 / 下所有的路径都惊醒拦截过滤
* /goods/* 只对/goods/ 下的路径 过滤
*
* *.do 只对所有 以.do 结尾的路径匹配
*
* -->
* <filter-mapping>
* <filter-name>MyFilter1</filter-name>
* <url-pattern>/*</url-pattern>
* </filter-mapping>
*
* 2.使用注解声明
*
*/
public class MyFilter1 implements Filter {
// 初始化方法 容器启动时加载调用
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter1 -----init");
}
@Override // 当请求 符合 过滤器拦截的路径 当前方法执行 过滤/拦截 业务逻辑
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("MyFilter1 -----doFilter");
// servletRequest 请求
// servletResponse 响应
// filterChain 过滤器调用连 ,决定者是否放行当前请求到 后面的过滤器 或者 servlet
// 放行当前请求 交给后面 的 过滤器 或者 servlet 进行处理
//如果不写,则默认拦截全部
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("MyFilter1 -----destroy");
}
}
web.xml声明
<!--
声明 过滤器
-->
<filter>
<filter-name>MyFilter1</filter-name>
<filter-class>com.qfedu.servlet.filter.MyFilter1</filter-class>
</filter>
<!--
为MyFilter1 配置感兴趣的路径
/* 对 / 下所有的路径都惊醒拦截过滤
/goods/* 只对/goods/ 下的路径 过滤
*.do 只对所有 以.do 结尾的路径匹配
-->
<filter-mapping>
<filter-name>MyFilter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
web.xml声明的优先级
<!--
声明 过滤器
-->
<filter>
<filter-name>MyFilter1</filter-name>
<filter-class>com.qfedu.servlet.filter.MyFilter1</filter-class>
</filter>
<filter>
<filter-name>MyFilter2</filter-name>
<filter-class>com.qfedu.servlet.filter.MyFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
在web.xml 中声明 的 <filter-mapping> 的顺寻决定 Filter 拦截的顺序
<filter-mapping> 越靠上,优先级越高
-->
<filter-mapping>
<filter-name>MyFilter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
基于注解的声明
基于注解的Filter 过滤的顺序,是按照Filter名称的字典顺序进行加载(也就是按照英文字母)
@WebFilter("/*")// 声明 当前Filter 加入到容器
public class MyFilter1 implements Filter {
。。。。
}
@WebFilter("/*")// 声明 当前Filter 加入到容器
public class MyFilter2 implements Filter {
。。。。
}
设置编码格式过滤器
/**
配置编码格式
使用过滤器结局中文乱码问题
*/
@WebFilter("*.do")// 声明 当前Filter 加入到容器
public class EncodingFilter implements Filter {
// 初始化方法 容器启动时加载调用
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("EncodingFilter -----init");
}
@Override // 当请求 符合 过滤器拦截的路径 当前方法执行 过滤/拦截 业务逻辑
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("EncodingFilter -----doFilter");
servletRequest.setCharacterEncoding("utf-8");
// 设置响应编码格式
// "text/html;charset=utf-8" 告诉浏览器得到响应 使用html 解析该请求
// css js .png .image 不能解析为html
servletResponse.setContentType("text/html;charset=utf-8");
// 放行当前请求交给后面的过滤器或者servlet 进行处理
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("EncodingFilter -----destroy");
}
}
登录鉴权过滤器
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 鉴权用户是否登录 过滤器
*/
@WebFilter("*.do")
public class LoginFilter implements Filter {
// 初始化方法 容器启动时加载调用
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LoginFilter -----init");
}
@Override // 当请求 符合 过滤器拦截的路径 当前方法执行 过滤/拦截 业务逻辑
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("LoginFilter -----doFilter");
// 将 ServletRequest 转化为 HttpServletRequest
HttpServletRequest req = (HttpServletRequest) servletRequest;
// 获取当前浏览器请求的session
HttpSession session = req.getSession();
// 获取标记位
Object result = session.getAttribute("loginFlag");
if (result!=null){ // 鉴权(鉴定用户是否登录)
boolean loginFlag = (boolean) result;
if (loginFlag){ // 鉴权成功 放行
// 放行当前请求 交给后面 的 过滤器 或者 servlet 进行处理
filterChain.doFilter(servletRequest, servletResponse);
return;
}
}
// 鉴权失败 需要登录才可以访问
req.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("LoginFilter -----destroy");
}
}
顺序问题总结
1.基于xml声明的Filter,是按照FilterMapping 进行排序
2.注解:基于注解的Filter 过滤的顺序,是按照Filter名称的字典顺序进行加载
3.xml 和注解 的Filter 顺序,所有的xml顺序都优于 注解的顺序