Filter ,Listener和BaseServlet

Filter ,Listener和BaseServlet

一,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 过滤器链

在这里插入图片描述

过滤器链执行顺序,两种方式考虑
1. 使用注解方式配置过滤器,按照过滤器类名的字典顺序对应过滤器链的执行顺序
2. 使用web.xml文件配置filter过滤器,根据在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() {

    }
}

二,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());
    }
}

三,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();
        }
    }
}
发布了41 篇原创文章 · 获赞 0 · 访问量 1730

猜你喜欢

转载自blog.csdn.net/qq_39544980/article/details/105279258