美文网首页java基础
java基础-day42-Filter、Listener和Bas

java基础-day42-Filter、Listener和Bas

作者: 触手不可及 | 来源:发表于2021-07-02 09:00 被阅读0次

    Filter ,Listener和BaseServlet

    1. Filter过滤器

    1.1 Filter过滤器的配置方式
    1.1.1 注解方式配置
    关注
        String[] value() default {};
        String[] urlPatterns() default {};
        设置当前过滤器Filter限制过滤的条件路径
    @WebFilter(urlPatterns = {"/Day45/user", "/Day45/admin"})
    
    @WebFilter("/Day45/user") ==> 注解中的value属性
    
    1.1.2 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_3_1.xsd"
             version="3.1">
        <filter>
            <!-- 当前过滤器名字 -->
            <filter-name>BFilter</filter-name>
            <!-- 对应当前过滤器的.class文件 -->
            <filter-class>com.qfedu.a_filter.BFilter</filter-class>
        </filter>
        <filter-mapping>
            <!-- 对应过滤器的名字 -->
            <filter-name>BFilter</filter-name>
            <!-- 限制过滤路径 -->
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <!-- 对应过滤器的名字 -->
            <filter-name>BFilter</filter-name>
            <!-- 限制过滤路径 -->
            <url-pattern>/Day45/user</url-pattern>
        </filter-mapping>
    </web-app>
    
    1.1.3 配置方式总结
    1. 关注的重点是需要过滤的URL-Pattern,那些资源那需要进行过滤操作
    2. 允许多个Filter同时过滤限制一个路径,例如 机场安检,过安检需要同时完成三次安检
    
    1.2 过滤器链
    image.png
    过滤器链执行顺序,两种方式考虑
        1. 使用注解方式配置过滤器,按照过滤器类名的字典顺序对应过滤器链的执行顺序
        2. 使用web.xml文件配置filter过滤器,根据<filter-mapping>在web.xml文件中的顺序来觉得过滤器链的执行流程。
    
    1.3 Filter过滤器初始化参数
    指定加载一定的资源
        敏感词汇过滤,跟当前的过滤器进行绑定,这里可以使用初始化参数
        1. 通过注解方式完成配置
        2. 通过web.xml
    
    // 注解方式完成
    @WebFilter(value = "/*",
            initParams = {@WebInitParam(name = "filename", value = "saolei.properties")})
    
    <!-- XML配置方式完成  -->
    <filter>
        <filter-name>EFilter</filter-name>
        <filter-class>com.qfedu.a_filter.EFilter</filter-class>
        <!-- 初始化参数 -->
        <init-param>
            <param-name>filename</param-name>
            <param-value>saolei.xml</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>EFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    1.4 案例
    1.4.1 过滤器辅助完成对应Request和Response编码集处理
    package com.qfedu.util;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * 访问服务器请求和对应的响应编码集处理
     * Apache Tomcat/7.0.103
     * Apache Tomcat/8.5.41
     * Apache Tomcat/9.0.33
     *
     * Tomcat 7 以及 一下版本存在ISO-8859-1
     *
     * @author MI 2020/4/2 11:03
     */
    @WebFilter("/*")
    public class AEncodingFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            // 获取当前Tomcat服务器版本信息
            String serverInfo = request.getServletContext().getServerInfo();
    
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
    
            if (serverInfo.startsWith("Apache Tomcat/7") || serverInfo.startsWith("Apache Tomcat/6")) {
                // 存在ISO-8859-1
                // 留下一个小问题
                System.out.println("Tomcat 6 or 7");
            } else {
                // Tomcat 8以及以上处理POST请求中文乱码问题和对应Response响应乱码问题
                System.out.println("Tomcat 8 or 9");
                httpServletRequest.setCharacterEncoding("utf-8");
                httpServletResponse.setContentType("text/html;charset=utf-8");
            }
    
            chain.doFilter(httpServletRequest, httpServletResponse);
        }
    
        @Override
        public void destroy() {
    
        }
    }
    
    1.4.2 登录过滤
    package com.qfedu.util;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import java.io.IOException;
    
    /**
     * 判断是否登录,如果登录状态才可以访问对应的资源,未登录不能访问
     * 当前过滤器的路径是整个项目
     *      需要考虑
     *          imgServlet,indexServlet,logout 不可以访问
     *          login,login.html 可以访问
     *      判断登录条件
     *          HttpSession
     * @author MI 2020/4/2 11:20
     */
    @WebFilter("/*")
    public class BLoginFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
    
            // 1. 判断申请访问的资源名
            String requestURI = req.getRequestURI();
            System.out.println(requestURI);
            // 2. 用户当前访问的登录操作,可以放行
            if (requestURI.contains("login")) {
                System.out.println("登录操作放行\n");
                chain.doFilter(req, resp);
            } else {
                // 3. 检查用户登录状态
                HttpSession session = req.getSession(false);
    
                // Session不存在,获取信息不对称
                if (null == session || !"骚磊".equals(session.getAttribute("name"))) {
                    System.out.println("资源不匹配\n");
                    resp.sendRedirect("login.html");
                } else {
                    // 放行
                    System.out.println("登录状态放行\n");
                    chain.doFilter(req, resp);
                }
            }
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    2. Listener 监听器

    2.1 什么是监听器
        监听器如果考虑生活中的常见案例,安检通道,数据抓取。对于一种事件的监听机制,同时会触发一些操作。
        WEB Application中监听器Listener来监听WEB服务对象创建, 信息的创建,修改,删除,增加... 发现以上问题,可以【触发】监听器,从而进行一系列的其他操作。
        例如: 
            1. WEB Application项目启动,ServletContext会被创建,可以监听
            ServletContext对象创建过程,触发一些对于当前WEB Application项目的初
            始化过程。
            2. 监听当前一些Session信息,可以获取当前网站的访问量,当时的用户量...
            3. 属性修改,可以保存日志记录
    
    2.2 监听器类型
    2.2.1 监听ServletContext变化
    ServletContextListener
    public void contextInitialized(ServletContextEvent sce);
        监听ServletContext初始化操作
            用于ServletContext对象在创建过程中,其实就是整个WEB Application加载
            的过程中初始化一定的参数,例如 资源信息,数据操作,驱动加载...
            
    public void contextDestroyed(ServletContextEvent sce);
        监听ServletContext销毁操作
            用于ServletContext对象销毁过程中,也就是整个WEB Application关闭,可
            以使用该方法销毁资源内容
    
    2.2.2 静态ServletContext属性变化
    ServletContextAttributeListener
    public void attributeAdded(ServletContextAttributeEvent scae);
        监听ServletContext对象中属性添加操作。  
    
    public void attributeRemoved(ServletContextAttributeEvent scae);
        监听ServletContext对象中属性删除操作。
        
    public void attributeReplaced(ServletContextAttributeEvent scae);
        监听ServletContext对象中属性更改操作。
    
    2.2.3 监听HttpSession对象变化
    HttpSessionListener
    public void sessionCreated(HttpSessionEvent se);
        监听Session被创建
    public void sessionDestroyed(HttpSessionEvent se);
        监听Session被销毁
    
    2.2.4 监听HttpSession属性值变化
    HttpSessionAttributeListener
    public void attributeAdded(HttpSessionBindingEvent se);
        监听HttpSession对象中属性添加操作。 
    
    public void attributeRemoved(HttpSessionBindingEvent se);
        监听HttpSession对象中属性删除操作。
        
    public void attributeReplaced(HttpSessionBindingEvent se);
        监听HttpSession对象中属性更改操作。
    
    2.2.5 监听HttpSession存储和读取
     HttpSessionActivationListener
     public void sessionWillPassivate(HttpSessionEvent se);
        监听HttpSession对象存储操作 
     public void sessionDidActivate(HttpSessionEvent se);
        监听HttpSession对象读取操作 
    
    2.2.6 监听ServletRequest对象变化
    ServletRequestListener
    public void requestDestroyed(ServletRequestEvent sre);
        ServletRequest销毁
    public void requestInitialized(ServletRequestEvent sre);
        ServletRequest对象初始化过程
    
    2.2.7 监听ServletRequest对象属性变化
    ServletRequestAttributeListener
    public void attributeAdded(ServletRequestAttributeEvent srae);
        Request对象属性添加操作监听
    public void attributeRemoved(ServletRequestAttributeEvent srae);
        Request对象属性删除操作监听
    public void attributeReplaced(ServletRequestAttributeEvent srae);
        Request对象属性更新操作监听
    
    2.3 监听器的两种配置方式
    2.3.1 注解方式
    /**
     * 当前类实现ServletContextListener接口,完成方法,但是没有注册
     *
     * @author MI 2020/4/2 14:55
     */
    @WebListener
    public class ApplicationLifeListener implements ServletContextListener {
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            System.out.println("Servlet Context Object Initialized...");
            try {
                Class.forName("com.qfedu.c_listener.TestDriver");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            System.out.println("Servlet Context Object Destroyed...");
        }
    }
    
    2.3.2 web.xml配置
    <!-- 在web.xml标注当前监听器使用的是哪一个类 -->
    <listener>
        <listener-class>com.qfedu.c_listener.HttpSessionLiftListener</listener-class>
    </listener>
    
    2.4 小案例
    2.4.1 ServletRequest属性变化监听演示
    package com.qfedu.d_requestAttr;
    
    import javax.servlet.ServletRequestAttributeEvent;
    import javax.servlet.ServletRequestAttributeListener;
    import javax.servlet.annotation.WebListener;
    
    /**
     * @author MI 2020/4/2 15:08
     */
    @WebListener
    public class ServletRequestAttrListener implements ServletRequestAttributeListener {
        @Override
        public void attributeAdded(ServletRequestAttributeEvent srae) {
            System.out.println("Add Name : " + srae.getName());
            System.out.println("Add value : " + srae.getValue());
        }
    
        @Override
        public void attributeRemoved(ServletRequestAttributeEvent srae) {
            System.out.println("Remove Name:" + srae.getName());
            System.out.println("Remove value:" + srae.getValue());
        }
    
        @Override
        public void attributeReplaced(ServletRequestAttributeEvent srae) {
            System.out.println("Replace Name:" + srae.getName());
            System.out.println("Replace value:" + srae.getValue());
        }
    }
    
    

    3. BaseServlet封装

    3.1 目前面临的问题
        目前WEB Application中每一个业务逻辑都需要一个对应的Servlet进行操作,而且Servlet中处理的方法都是一直的,doGet和doPost,这里会导致一些问题
        1. Servlet过多,服务器有压力 
            a. URL-Pattern 匹配压力
            b. 内存压力
            c. 处理压力
        2. 程序员也有压力的
            a. 一个业务操作一个Servlet
            b. 匹配原则一大堆
            c. 代码冗余
            
    一个核心Servlet完成操作的分发
    
    3.2 当前创建Servlet的方式
    自定义Servlet程序继承HttpServlet,重写doGet和doPost方法,重复性太高!!!
    
    StudentSystem学生管理系统
        请求URL   
            http://localhost:8080/ss/addStudent
            http://localhost:8080/ss/deleteStudent      
            http://localhost:8080/ss/updateStudent      
            http://localhost:8080/ss/removeStudent      
            http://localhost:8080/ss/listStudent        
        
        代码中需要5个Servlet来满足操作。
    
        每一个Servlet对应一个Student操作业务逻辑,是否可以规划到一个Servlet中,在URL请求上做出约束,约束完成方法
        改变URL策略
            http://localhost:8080/ss/studentServlet?method=addStudent
            http://localhost:8080/ss/studentServlet?method=deleteStudent
            http://localhost:8080/ss/studentServlet?method=updateStudent        http://localhost:8080/ss/studentServlet?method=removeStudent
            http://localhost:8080/ss/studentServlet?method=listStudent
    
    3.3 优化URL,操作方法
        在每一个Servlet,利用方法实现功能代码,利用doGet和doPost作为转发操作是可以完成代码,但是复杂度较高,重复性较大
    
    package com.qfedu.studentsystem.servlet;
    
    import com.qfedu.studentsystem.dao.StudentDao;
    import com.qfedu.studentsystem.dao.impl.StudentDaoImpl;
    import com.qfedu.studentsystem.entity.Student;
    import org.apache.commons.beanutils.BeanUtils;
    
    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;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.List;
    import java.util.Map;
    
    /**
     * http://localhost:8080/ss/studentServlet?method=addStudent
     * http://localhost:8080/ss/studentServlet?method=deleteStudent
     * http://localhost:8080/ss/studentServlet?method=updateStudent
     * http://localhost:8080/ss/studentServlet?method=modifyStudent
     * http://localhost:8080/ss/studentServlet?method=listStudent
     *
     * @author MI 2020/4/2 16:01
     */
    @WebServlet("/studentServlet")
    public class StudentServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String method = req.getParameter("method");
    
            try {
                Method method1 = this.getClass().getMethod(method, HttpServletRequest.class, HttpServletResponse.class);
                method1.invoke(this, req, resp);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    
        public void addStudent(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            Map<String, String[]> parameterMap = req.getParameterMap();
            Student student = new Student();
    
            try {
                BeanUtils.populate(student, parameterMap);
                StudentDao studentDao = new StudentDaoImpl();
    
                studentDao.addStudent(student);
    
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
    
            // 回到所有学生信息页面中 重定向到学生列表中
            resp.sendRedirect("studentServlet?method=listStudent");
        }
    
        public void deleteStudent(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            String id = req.getParameter("id");
            System.out.println(id);
    
            new StudentDaoImpl().deleteStudent(Integer.parseInt(id));
    
            // 重定向到ListStudentServlet中
            resp.sendRedirect("studentServlet?method=listStudent");
        }
    
        public void updateStudent(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            String id = req.getParameter("id");
    
            Student student = new StudentDaoImpl().findStudentById(Integer.parseInt(id));
            resp.getWriter().append(html);
        }
    
        public void modifyStudent(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            Map<String, String[]> parameterMap = req.getParameterMap();
    
            Student student = new Student();
            try {
                BeanUtils.populate(student, parameterMap);
    
                new StudentDaoImpl().updateStudent(student);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
    
            resp.sendRedirect("studentServlet?method=listStudent");
        }
    
        public void listStudent(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            // 找出所有学生的List集合
            List<Student> allStudent = new StudentDaoImpl().findAllStudent();
    
        }
    }
    
    3.4 剥离Servlet核心操作
    package com.qfedu.studentsystem.util;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    /**
     * 完成一个BaseServlet操作
     *
     * @author MI 2020/4/2 16:23
     */
    public abstract class BaseServlet extends HttpServlet {
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 从用户请求url中获取对应的method参数,也就是需要执行的方法
            String methodName = req.getParameter("method");
    
            try {
                /*
                this是谁???
                    abstract修饰的类是没有自己的类对象的,this不能表示BaseServlet对象
                    this对应的是执行当前service方法的类对象,其实就是BaseServlet子类对象
                 */
                System.out.println("BaseServlet this : " + this);
                Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
                method.invoke(this, req, resp);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:java基础-day42-Filter、Listener和Bas

        本文链接:https://www.haomeiwen.com/subject/sfreultx.html