声明:本文是根据博主学习内容所整理得的笔记,仅作为交流学习使用,需要观看视频的请移步:http://www.atguigu.com/
1.Filter ?什么是过滤器
- Filter 过滤器它是 JavaWeb 的三大组件之一。
三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器 - Filter 过滤器它是 JavaEE 的规范。也就是接口
- Filter 过滤器它的作用是:拦截请求,过滤响应。
拦截请求常见的应用场景有:
1.权限检查 2.日记操作 3.事务管理 ……等等
2.Filter 初体验
要求:在你的 web 工程下,有一个 admin 目录。这个 admin 目录下的所有资源(html 页面、jpg 图片、jsp 文件…等等)都必须是用户登录之后才允许访问。
思考:根据之前我们学过内容。我们知道,用户登录之后都会把用户登录的信息保存到 Session 域中。所以要检查用户是否登录,可以判断 Session 中否包含有用户登录的信息,即可!!!
a.jsp:
<body>
<%
Object user = session.getAttribute("user");
// 如果 user = null; 说明 user 还没有登陆
if (user == null) {
request.getRequestDispatcher("/login.jsp").forward(request,response);
return; // 一般请求转发后,就不允许再执行任何代码,这里就直接return了
}
%>
我是 a.jsp 文件
</body>
但是在 html 页面当中应该怎么写呢? 需要使用 Filter 过滤器
Filter 的工作流程图:
Filter 过滤器的使用步骤:
1.编写一个类去实现 Filter 接口
2.实现过滤方法 doFilter()
3.到 web.xml 中去配置 Filter 的拦截路径
AdminFilter.java(继承了Filter类):
/**
* doFilter 方法,专门用来拦截请求,可以做权限检查
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpServletRequest.getSession();
Object user = session.getAttribute("user");
// 如果 user = null; 说明 user 还没有登陆
if (user == null) {
httpServletRequest.getRequestDispatcher("/login.jsp").forward(httpServletRequest,servletResponse);
return; // 一般请求转发后,就不允许再执行任何代码,这里就直接return了
} else {
// 让程序继续往下访问用户的目标资源
filterChain.doFilter(servletRequest,servletResponse);
}
}
这时候已经有权限检查代码了,但是还不知道要去哪检查,这时候需要去 xml 配置一下检查什么。
<!--filter标签用于配置一个Filter过滤器-->
<filter>
<!--给 filter 起一个别名-->
<filter-name>Adminfilter</filter-name>
<!--配置 filter 全类名-->
<filter-class>com.filter.AdminFilter</filter-class>
</filter>
<!--配置 filter 过滤器的拦截路径-->
<filter-mapping>
<!--表示当前的拦截路径给哪个filter过滤器使用-->
<filter-name>Adminfilter</filter-name>
<!--配置拦截路径
/ 表示请求地址为: http://ip:port/工程路径/ 映射到 IDEA 的 web 目录
/admin/* 表示请求地址为 http://ip:port/工程路径/admin/* (admin 下的全部)
-->
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
完整的用户登录和权限检查:
login.jsp:
<body>
这是登陆页面:login.jsp 页面 <br>
<form action="http://localhost:8080/15_filter/loginServlet" method="get">
用户名:<input type="text" name="username"/> <br>
密码:<input type="password" name="password"/> <br>
<input type="submit" />
</form>
</body>
LoginServlet.java:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=UTF-8"); //解决响应乱码
String username = req.getParameter("username");
String password = req.getParameter("password");
if ("wzg168".equals(username) && "123456".equals(password)) {
req.getSession().setAttribute("user",username);
resp.getWriter().write("登录 成功!!!");
} else {
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}
}
3.Filter 的生命周期
Filter 的生命周期包含几个方法
-
构造器方法
-
init 初始化方法
第 1,2 步,在 web 工程启动的时候执行(Filter 已经创建)
-
doFilter 过滤方法
第 3 步,每次拦截到请求,就会执行(访问 admin 目录下的 a.jsp 页面,访问一次,拦截一次请求)
-
destroy 销毁
第 4 步,停止 web 工程的时候,就会执行(停止 web 工程,也会销毁 Filter 过滤器)
4.FilterConfig 类
FilterConfig 类见名知义,它是 Filter 过滤器的配置文件类。
Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置息。
FilterConfig 类的作用是获取 filter 过滤器的配置内容
- 获取 Filter 的名称 filter-name 的内容
- 获取在 Filter 中 wen.xml 配置的 init-param 初始化参数
- 获取 ServletContext 对象
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("2.Filter 初始化方法 init(FilterConfig filterConfig)");
// 1. 获取 Filter 的名称 filter-name 的内容 (web-xml 中配置的名称)
System.out.println("filter-name:" + filterConfig.getFilterName());
// 2. 获取在 web.xml 中配置的 init-param 初始化参数
System.out.println("初始化参数username的值是:" + filterConfig.getInitParameter("username"));
System.out.println("初始化参数url的值是:" + filterConfig.getInitParameter("url"));
// 3. 获取 ServletContext 对象
System.out.println(filterConfig.getServletContext());
}
5.FilterChain 过滤器链
Filter 过滤器
Chain 链,链条
FilterChain 就是过滤器链(多个过滤器如何一起工作)
FilterChain.doFilter() 方法的作用:
1.执行下一个Filter过滤器(如果有Filter)
2.执行目标资源
Filter过滤器的执行细节:
Filter1.java:
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter1前置代码");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("Filter1后置代码");
}
Filter2.java:
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter2前置代码");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("Filter2后置代码");
}
target.jsp:
<body>
<%
System.out.println("target.jsp页面执行了");
%>
</body>
web.xml:
<filter>
<filter-name>Filter1</filter-name>
<filter-class>com.filter.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter1</filter-name>
<url-pattern>/target.jsp</url-pattern>
</filter-mapping>
<filter>
<filter-name>Filter2</filter-name>
<filter-class>com.filter.Filter2</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter2</filter-name>
<url-pattern>/target.jsp</url-pattern>
</filter-mapping>
访问 target.jsp:
可见其执行顺序。
另外,要是在 xml 中,把 Filter2 放在 Filter1 上面,就会先执行 Filter2,再执行 Filter1。也就是说:在多个 Filter 过滤器执行的时候,他们的优先顺序是由他们在 web.xml 中从上到下配置的顺序决定的!
补充:
多个Filter过滤器执行的特点:
- 所有filter和目标资源默认都执行同一个线程中
- 多个Filter过滤器同时执行的时候,他们都要使用同一个Request对象
补充1演示:在 Filter1 和 Filter2 的 filterChain.doFilter(servletRequest,servletResponse); 的前后,都使用 Thread.currentThread().getName() 获取线程名,另外 target.jsp 页面中也使用 Thread.currentThread().getName() 获取线程名,运行结果显示:
访问:http://localhost:8080/15_filter/target.jsp
结果显示,线程相同。
补充2演示:在 Filter1 和 Filter2 的 filterChain.doFilter(servletRequest,servletResponse); 的前后,都使用servletRequest.getParameter(“username”) 获取 request 对象的 name,target.jsp 中使用 request.getParameter(“username”) 获取 request 对象的 name,运行结果显示:
访问:http://localhost:8080/15_filter/target.jsp?username=12345
结果显示, request 对象相同。
6.Filter 的拦截路径
–精确匹配
<filter-mapping>
<filter-name>Filter2</filter-name>
<url-pattern>/target.jsp</url-pattern> <!--精确匹配-->
</filter-mapping>
以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/target.jsp
–目录匹配
<filter-mapping>
<filter-name>Adminfilter</filter-name>
<url-pattern>/admin/*</url-pattern> <!--目录匹配-->
</filter-mapping>
以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/admin/*
–后缀名匹配
<filter-mapping>
<filter-name>Filter2</filter-name>
<url-pattern>*.html</url-pattern> <!--后缀名匹配-->
</filter-mapping>
以上配置的路径,表示请求地址必须以.html 结尾才会拦截到
<filter-mapping>
<filter-name>Filter2</filter-name>
<url-pattern>*.do</url-pattern> <!--后缀名匹配-->
</filter-mapping>
以上配置的路径,表示请求地址必须以.do 结尾才会拦截到
<filter-mapping>
<filter-name>Filter2</filter-name>
<url-pattern>*.action</url-pattern> <!--后缀名匹配-->
</filter-mapping>
以上配置的路径,表示请求地址必须以.action 结尾才会拦截到
<filter-name>Filter2</filter-name>
<url-pattern>*.do</url-pattern> <!--后缀名匹配-->
```
以上配置的路径,表示请求地址必须以.do 结尾才会拦截到
<filter-mapping>
<filter-name>Filter2</filter-name>
<url-pattern>*.action</url-pattern> <!--后缀名匹配-->
</filter-mapping>
以上配置的路径,表示请求地址必须以.action 结尾才会拦截到
Filter 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在(只看后缀名是否等于,不关心后缀名在现实中是否真的存在)!!!