五、 Filter过滤器 && Listener监听器
- web的三大组件
- servlet(控制器)
- filter(过滤器)
- listener(监听器)
Filter
概述
-
生活中的过滤器
- 净水器、空气净化器、地铁安检、山大王
-
web中的过滤器
- 当用户访问服务器资源时,过滤器将请求拦截下来,完成一些通用的操作
-
应用场景
- 登录验证、统一编码处理、敏感字符过滤
快速入门
-
需求:编写filter对目标资源servlet进行拦截
-
① 编写java类,实现filter接口
package com.lagou.filter; import javax.servlet.*; import java.io.IOException; public class QuickFilter implements Filter { /* 初始化方法 */ @Override public void init(FilterConfig filterConfig) throws ServletException { } /* 拦截用户请求的方法 servletRequest: 请求对象 servletResponse:响应对象 filterChain:过滤器链(是否放行) */ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("QuickFilter拦截了请求...."); // 放行 filterChain.doFilter(servletRequest,servletResponse); // 再进行拦截 System.out.println("QuickFilter拦截了响应...."); } /* 销毁方法 */ @Override public void destroy() { } }
-
② 配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--TargetServlet--> <servlet> <servlet-name>TargetServlet</servlet-name> <servlet-class>com.lagou.servlet.TargetServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>TargetServlet</servlet-name> <url-pattern>/targetServlet</url-pattern> </servlet-mapping> <!--QuickFilter--> <filter> <filter-name>QuickFilter</filter-name> <filter-class>com.lagou.filter.QuickFilter</filter-class> </filter> <filter-mapping> <filter-name>QuickFilter</filter-name> <!--该拦截器的拦截路径 --> <!--可以用 /* 表示对所有请求进行拦截--> <url-pattern>/targetServlet</url-pattern> </filter-mapping> </web-app>
-
访问的资源
package com.lagou.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class TargetServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("目标资源被访问到了....."); resp.setContentType("text/html;charset=utf-8"); resp.getWriter().write("目标资源被访问到了....."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
工作原理
- 工作原理图
使用细节
生命周期
-
生命周期:指的是一个对象从生(创建)到死(销毁)的一个过程
// 初始化方法 public void init(FilterConfig config); // 执行拦截方法 public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain); // 销毁方法 public void destroy();
* 创建 服务器启动项目加载,创建filter对象,执行init方法(只执行一次) * 运行(过滤拦截) 用户访问被拦截目标资源时,执行doFilter方法 * 销毁 服务器关闭项目卸载时,销毁filter对象,执行destroy方法(只执行一次) * 补充: 过滤器一定是优先于servlet创建的
拦截路径
-
在开发时,我们可以指定过滤器的拦截路径来定义拦截目标资源的范围
* 精准匹配 用户访问指定目标资源(/targetServlet)时,过滤器进行拦截 * 目录匹配 用户访问指定目录下(/user/*)所有资源时,过滤器进行拦截 * 后缀匹配 用户访问指定后缀名(*.html)的资源时,过滤器进行拦截 * 匹配所有 用户访问该网站所有资源(/*)时,过滤器进行拦截
-
代码演示
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <filter> <filter-name>QuickFilter</filter-name> <filter-class>com.lagou.filter.QuickFilter</filter-class> </filter> <filter-mapping> <filter-name>QuickFilter</filter-name> <!--该拦截器的拦截路径 --> <!-- <url-pattern>/targetServlet</url-pattern> --> <!-- <url-pattern>/user/*</url-pattern> --> <!-- <url-pattern>*.html</url-pattern> --> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
过滤器链
- 在一次请求中,若我们请求匹配到了多个filter,通过请求就相当于把这些filter串起来了,形成了过滤器链
* 需求
用户访问目标资源 /targetServlet时,经过 FilterA FilterB
* 过滤器链执行顺序 (先进后出)
1.用户发送请求
2.FilterA拦截,放行
3.FilterB拦截,放行
4.执行目标资源 show.jsp
5.FilterB增强响应
6.FilterA增强响应
7.封装响应消息格式,返回到浏览器
* 过滤器链中执行的先后问题....
配置文件
谁先声明,谁先执行
<filter-mapping>
-
原理图
综合案例
统一网站编码
-
需求
- tomcat8.5版本中已经将get请求的中文乱码解决了,但是post请求还存在中文乱码
- 浏览器发出的任何请求,通过过滤器统一处理中文乱码
-
代码实现
- 真实场景中,过滤器不会统一响应mime类型
- ① bbs.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>LPL季后赛观看留言板</h3> <form action="/filter_demo/wordsServlet" method="post"> <textarea name="content" id="" cols="30" rows="10"></textarea> <input type="submit" value="请留言"> </form> </body> </html>
- ② EncodeFilter
package com.lagou.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class EncodeFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 类型向下转型 HttpServletRequest request= (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // 判断用户发出的请求是否是post请求,是,才设置编码 if(request.getMethod().equalsIgnoreCase("post")){ request.setCharacterEncoding("UTF-8"); } response.setContentType("text/html;charset=utf-8"); filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }
- web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--EncodeFilter--> <filter> <filter-name>EncodeFilter</filter-name> <filter-class>com.lagou.filter.EncodeFilter</filter-class> </filter> <filter-mapping> <filter-name>EncodeFilter</filter-name> <!--该拦截器的拦截路径 /*--> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
Listener【了解】
概述
- 生活中的监听器
- 我们很多商场有摄像头,监听着客户的一举一动。如果客户有违法行为,商场可以采取相应的措施
- javaweb中的监听器
- 在我们的java程序中,有时也需要监视某些事情,一旦被监听的对象发生相应的变化,我们应该采取相应的操作
- 监听web三大域对象
- HttpServletRequest、HttpSession、ServletContext 通过监听器监听三大域对象它们的创建和销毁
- 场景
- 历史访问次数、统计在线人数、系统启动时初始化配置信息
快速入门
-
监听器在web开发中使用的比较少,见的机会就更少了,所以我们就使用ServletContextListenner来带领大家学习下监听器,因为这个监听器是监听器中使用率最高的一个,且监听器的使用方式都差不多
-
这个监听器可以在项目启动和销毁的时候做一些事情;例如,在项目启动的时候加载配置文件
-
ServletContextListener接口的API介绍–重要
void contextDestroyed(ServletContextEvent sce) // 监听servletcontext销毁 void contextInitialized(ServletContextEvent sce) // 监听servletcontext创建
-
使用步骤
- 创建一个类实现ServletContextListenner接口
- 实现ServletContextListenner的contextInitialized和contextDestroyed方法。
- 给这个类在xml中配置
-
代码演示
- ① MyServletContextListener
package com.lagou.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class MyServletContextListener implements ServletContextListener { /* 监听servletContext对象创建的方法 */ @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("监听到servletContext对象创建了....."); } /* 监听servletContext对象销毁的方法 */ @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("监听到servletContext对象销毁了....."); } }
- ② web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--配置MyServletContextListener--> <listener> <listener-class>com.lagou.listener.MyServletContextListener</listener-class> </listener> </web-app>
-
同理:使用如下接口以相同的方式也可以监听到session对象和request对象的创建和销毁
- HttpSessionListener:监听Httpsession域的创建于销毁的监听器
- ServletRequestListener:监听ServletRequest域的创建于销毁的监听器
注:本内容为个人拉勾教育大数据训练营课程笔记