Listener&Filter 逃离我推掉我的手 2023-10-04 13:03 64阅读 0赞 ##### 17.Listener&Filter ##### ###### 17.1.JavaEE规范 ###### * EE规范对于Web组件一共定义了三个标准,其中之一就是我们经常使用的Servlet,除此之外还有另外两个组件 * Listener:监听器。监听某一个对象的创建、销毁、属性的变更等。可以把之前写在某个servlet的init方法里面的代码写在listener里面。 * Filter:过滤器,拦截、过滤。黑名单。订单、个人主页 ###### 17.2.Listener监听器 ###### ###### 17.2.1.介绍 ###### * 概念:web的三大组件(web Component)之一。 * 事件监听机制 * 事件:一件事情 * 事件源 :事件发生的地方 * 监听器 :一个对象 * 注册监听:将事件、事件源、监听器绑定在一起。 当事件源上发生某个事件后,执行监听器代码 ###### 17.2.2.分类 ###### * web中的监听器一共可以分为三大类8种, 1. 三个域对象创建、销毁的监听器 ServletContextListener 2. 三个域对象属性变更的监听器 3. session数据钝化、活化的监听器 ###### 17.2.3.使用 ###### * ServletContextListener:监听ServletContext对象的创建和销毁 * 方法: * void contextDestroyed(ServletContextEvent sce) :ServletContext对象被销毁之前会调用该方法 * void contextInitialized(ServletContextEvent sce) :ServletContext对象创建后会调用该方法 * 步骤: 1. 定义一个类,实现ServletContextListener接口 2. 复写方法 3. 配置 * 方式一:web.xml <listener> <listener-class>cn.itcast.web.listener.ContextLoaderListener</listener-class> </listener> <context-param>指定初始化参数 * 方式二:注解:@WebListener 1. Example import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; @WebListener public class MyServletContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("context init"); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("context destroy"); } } ###### 17.3.Filter过滤器 ###### ###### 17.3.1.介绍 ###### * 过滤器介于客户端与Servlet/JSP等相关的资源之间,对于与过滤器关联的Servlet来说,过滤器可以在Servlet被调用之前检查并且修改request对象。在Servlet调用之后检查并修改response对象。 * 过滤器的作用:一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤等等 ###### 17.3.2.使用 ###### * 步骤: 1. 定义一个类,实现接口Filter 2. 复写方法 3. 配置拦截路径 * 方式一:web.xml * 方式二:注解 @WebFilter("/*")//访问所有资源之前,都会执行该过滤器 public class FilterDemo1 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("filterDemo1被执行了...."); //放行 filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } } ###### 17.3.3.过滤器细节 ###### 1. web.xml配置 <filter> <filter-name>demo1</filter-name> <filter-class>cn.itcast.web.filter.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>demo1</filter-name> <!-- 拦截路径 --> <url-pattern>/*</url-pattern> </filter-mapping> 2. 过滤器执行流程 3. 执行过滤器 4. 执行放行后的资源 5. 回来执行过滤器放行代码下边的代码 6. 过滤器生命周期方法 7. void init(FilterConfig config):在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源 * 用于初始化过滤器,当容器装载并初始化过滤器时调用。Web容器为此方法传递一个FilterConfig对象, * FilterConfig对象可以获取web.xml文件中过滤器初始化参数的配置; * 利用FilterConfig对象也可以获取当前Filter的名称以及相关联的ServletContext对象。 8. void doFilter(ServletRequst request, ServletResponse response, FilterChain chain):每一次请求被拦截资源时,会执行。执行多次 * 此方法是Filter接口的核心方法,用于对请求对象和响应对象进行检查和处理。 * 访问服务器的时候执行chain.doFilter(request, response)上面的,响应的时候执行下面的 * 此方法包括三个输入参数。其中, * ServletRequest对象为请求对象,包括表单数据、Cookie以及HTTP请求头等信息; * ServletResponse对象为响应对象,用于响应使用ServletRequest对象访问的信息; * FilterChain用来调用过滤器链中的下一个资源, * 即将ServletRequest对象以及ServletResponse对象传递给下一个过滤器或者是其它的Servlet/JSP等资源。 9. void destroy( ):在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源 * 此方法用于销毁过滤器,当容器要销毁过滤器实例时调用此方法,Servlet过滤器占用的资源会被释放。 import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter("/filter1") public class FirstFilter implements Filter { //会在应用启动的时候直接实例化一个对象出来,然后执行init方法 @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("filter init"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filter doFilter"); } //应用被卸载、服务器关闭 @Override public void destroy() { System.out.println("filter destroy"); } } 10. 过滤器配置详解 * 拦截路径配置: 1. 具体资源路径: /index.jsp 只有访问index.jsp资源时,过滤器才会被执行2. 拦截目录: /user/\* 访问/user下的所有资源时,过滤器都会被执行3. 后缀名拦截: *.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行4. 拦截所有资源:/* 访问所有资源时,过滤器都会被执行 * 拦截方式配置:资源被访问的方式 * 注解配置: 设置dispatcherTypes属性 1. REQUEST:默认值。浏览器直接请求资源 2. FORWARD:转发访问资源 3. INCLUDE:包含访问资源 4. ERROR:错误跳转资源 5. ASYNC:异步访问资源 * web.xml配置 * 设置<dispatcher></dispatcher>标签即可 1. 过滤器链(配置多个过滤器) * 执行顺序:如果有两个过滤器:过滤器1和过滤器2 1. 过滤器12. 过滤器23. 资源执行4. 过滤器25. 过滤器1 * 过滤器先后顺序问题: 1. 注解配置:按照类名的字符串比较规则比较,值小的先执行 \* 如: AFilter 和 BFilter,AFilter就先执行了。2. web.xml配置: 谁定义在上边,谁先执行 ###### 17.4.Filter关联Servlet ###### * 通过url-pattern产生关联。 * filter和servlet设置相同的url-pattern并不会导致出错。 * servlet:开发动态web资源的组件。一个请求只有一个组件来响应 * filter:拦截器、过滤器。它不是主要去做出响应的组件,所以设置它可以和servlet的url-pattern。 ###### 17.5.工作原理 ###### 1. 客户端将请求发送给Web容器 2. Web容器根据客户端发送的请求生成请求对象request和响应对象response 3. Web容器在调用与过滤器相关联的Web组件(例如Servlet/JSP)之前,先将request对象以及response对象发送给过滤器。 4. 过滤器对request对象进行必要的处理; 5. 过滤器把处理过的reques对象以及response对象传递给Web组件 6. Web组件调用完成后,再次通过过滤器,此时过滤器对response对象进行必要的处理; 7. 过滤器把处理过的response对象传递给Web容器; 8. Web容器将响应的结果返回到客户端,并在浏览器上显示。 ###### 17.6.案例 ###### * 实现只有登录才能打开欢迎界面,即登录过后放行,未登录过滤 //登录的Servlet import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/login") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); request.getSession().setAttribute("username", username); response.setHeader("refresh", "2;url=" + request.getContextPath() + "/info.jsp"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } } //过滤器 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 FirstFilter implements Filter { //会在应用启动的时候直接实例化一个对象出来,然后执行init方法 @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("filter init"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("utf-8"); servletResponse.setContentType("text/html;charset=utf-8"); System.out.println("filter doFilter before"); // 验证页面是否需要被验证权限 HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; String servletPath = request.getServletPath(); if(auth(servletPath)){ //如何判断是否登录 Object username = request.getSession().getAttribute("username"); if(username == null){ //跳转到登录页面 response.sendRedirect(request.getContextPath() + "/login.jsp"); return; } } //如果没有这行代码,那么就是执行的拦截 filterChain.doFilter(servletRequest, servletResponse); System.out.println("filter doFilter after"); } //验证身份、权限 学的知识点落地 /** * 该方法用来验证某个请求路径是否需要验证身份 阿里巴巴编程规范 * @param servletPath * @return <code>true</code>表示需要验证身份,返回值<code>false</code>表示不需要验证身份 */ private boolean auth(String servletPath) { if("/info.jsp".equals(servletPath)){ return true; } return false; } //应用被卸载、服务器关闭 @Override public void destroy() { System.out.println("filter destroy"); } } * 前端页面 <!-- 欢迎界面 --> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> 欢迎您,<%=session.getAttribute("username")%> </body> </html> <!-- 登录界面 --> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form action="<%=request.getContextPath()%>/login" method="post"> <input type="text" name="username"><br> <input type="submit"> </form> </body> </html>
还没有评论,来说两句吧...