过滤器的实现及其原理责任链设计模式

news2024/11/17 10:41:17

Filter过滤器

过滤器的应用

DeptServlet,EmpServlet,OrderServlet三个业务类的业务方法执行之前都需要编写判断用户是否登录和解决的中文乱码的代码,代码没有得到重复利用

Filter是过滤器可以用来编写请求的过滤规则和多个Servlet都会执行的公共代码,Filter中的业务代码既可以在目标Servlet程序执行之前也可以在其之后执行

  • Filter的生命周期和Servlet对象生命周期一致,先实例化(一次即单例)–>执行初始化方法(一次)–>处理请求方法(每次请求都会调用)–>销毁方法(一次)
  • Filter默认情况下在服务器启动阶段就会实例化 , Servlet默认在用户发起对应请求的时候才会实例化
  • Filter的优先级天生的就比Servlet优先级高,若Filter和Servlet都可以处理/a.do请求,那么一定是先执行Filter然后再执行Servlet

在这里插入图片描述

/**
 * 处理部门相关的业务类
 */
@WebServlet({"/dept/list", "/dept/detail", "/dept/delete", "/dept/save", "/dept/modify"})
public class DeptServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 低版本的Tomcat还需要解决post请求乱码问题
        request.setCharacterEncoding("UTF-8");
        // 响应中文乱码问题
        response.setContentType("text/html;charset=UTF-8");
        // 获取当前session,这个session是不需要新建的,获取不到就返回null
        HttpSession session = request.getSession(false);
        if(session != null && session.getAttribute("username") != null){
            String servletPath = request.getServletPath();
            if("/dept/list".equals(servletPath)){
                doList(request, response);
            }else if("/dept/detail".equals(servletPath)){
                doDetail(request, response);
            }else if("/dept/delete".equals(servletPath)){
                doDel(request, response);
            }else if("/dept/save".equals(servletPath)){
                doSave(request, response);
            }else if("/dept/modify".equals(servletPath)){
                doModify(request, response);
            }
        }else{
            // 获取不到session或session中没有存储用户的信息就跳转到登录页面
            response.sendRedirect(request.getContextPath() + "/index.jsp"); 
        }
    }
}
/**
 * 处理员工相关的业务类
 */
public class EmpServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 解决post请求乱码问题
        request.setCharacterEncoding("UTF-8");
        // 响应中文乱码问题
        response.setContentType("text/html;charset=UTF-8");
        HttpSession session = request.getSession(false);
        if(session != null && session.getAttribute("username") != null){
            String servletPath = request.getServletPath();
            //...
        }else{
            response.sendRedirect(request.getContextPath() + "/index.jsp");
        }
    }
}
/**
 * 处理订单相关的业务类
 */
public class OrderServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 解决post请求乱码问题
        request.setCharacterEncoding("UTF-8");
        // 解决响应中文乱码问题
        response.setContentType("text/html;charset=UTF-8");
        HttpSession session = request.getSession(false);
        if(session != null && session.getAttribute("username") != null){
            String servletPath = request.getServletPath();
            //...
        }else{
            response.sendRedirect(request.getContextPath() + "/index.jsp");
        }
    }
}

责任链设计模式

传统模式方法调用时在编译阶段已经完全确定了方法的调用顺序,如果想改变方法的调用顺序必须修改源代码,显然违背了OCP原则

public class Test {
    public static void main(String[] args) {
        System.out.println("main begin");
        m1();
        System.out.println("main over");
    }

    private static void m1() {
        System.out.println("m1 begin");
        m2();
        System.out.println("m1 over");
    }

    private static void m2() {
        System.out.println("m2 begin");
        m3();
        System.out.println("m2 over");
    }

    private static void m3() {
        System.out.println("目标正在执行中。。。。");
    }
}

责任链设计模式: 由于方法的调用顺序在程序编译阶段无法确定,需要根据实际情况在程序运行阶段动态的组合方法的调用顺序,实现代码的灵活性

  • Filter使用了责任链设计模式,将Filter的调用顺序配置到了web.xml文件中,想要调整Filter的执行顺序只需要修改配置文件中filter-mapping标签的顺序
<filter>
    <filter-name>filter</filter-name>
    <filter-class>com.bjpowernode.javaweb.servlet.Filter2</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter</filter-name>
    <url-pattern>*.do</url-pattern>
</filter-mapping>

实现过滤器

第一步:编写一个类实现jarkata.servlet.Filter接口,由于接口中的方法都有默认的方法体,我们可以根据需求实现方法

方法名功能
init(FilterConfig filterConfig)在Filter对象第一次被创建之后调用,并且只调用一次
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)编写过滤规则和公共代码的方法,只要用户发送一次请求就执行一次 , 发送N次请求执行N次
destroy()在Filter对象被释放/销毁之前调用,并且只调用一次

第二步: 执行FilterChain类的doFilter方法放行,过滤器只有放行了请求,目标Servlet才有机会执行到

方法名功能
doFilter(request, response)执行下一个过滤器,如果下面没有过滤器了才执行最终处理对应请求路径的Servlet
public class Filter implements Filter {
    public Filter1(){
        System.out.println("无参数构造方法执行");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init方法执行。");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 在请求的时候添加过滤规则
        System.out.println("Filter1 doFilter方法开始执行");
        // 执行下一个过滤器,如果下一个不是过滤器则执行目标程序Servlet
        chain.doFilter(request, response);
        // 在响应的时候添加过滤规则
        System.out.println("Filter1 doFilter方法执行结束");
    }

    @Override
    public void destroy() {
        System.out.println("destroy方法执行");
    }
}

第三步: 编写目标Servlet处理用户的请求

@WebServlet("/a.do")
public class AServlet  extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("AServlet中的doGet方法执行了");
    }
}

@WebServlet("/b.do")
public class BServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("BServlet中的doGet方法执行了");
    }
}

第四步: 配置Filter拦截的请求路径和执行顺序(Filter执行时遵循栈的数据结构),配置过滤器拦截的请求路径时可以使用通配符*

  • 在web.xml文件中配置(常用): Filter的执行顺序取决于filter-mapping标签的配置位置,越靠上优先级越高,和filter标签的位置无关
  • 在@WebFilter注解中配置(修改过滤器执行顺序不方便): Filter的执行顺序取决于Filter的类名(按字典序排序) , 比如在FilterA和FilterB中先执行FilterA
匹配方式举例
精确匹配/a.do、/b.do、/dept/save
模糊匹配*/*表示拦截所有路径
后缀匹配*,不能以/开始*.do表示拦截所有以.do结尾的路径
前缀匹配*,以/开始/dept/*表示拦截/dept/路径及其子路径
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">
    <filter>
        <filter-name>filter</filter-name>
        <filter-class>com.bjpowernode.javaweb.servlet.Filter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter</filter-name>
        <!--<url-pattern>a.do</url-pattern>
  		<url-pattern>b.do</url-pattern>-->
        <url-pattern>*.do</url-pattern>
    </filter-mapping>
</web-app>
//@WebFilter({"/a.do", "/b.do"})
@WebFilter({"*.do"})
public class Filter implements Filter {
    public Filter1(){
        System.out.println("无参数构造方法执行");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init方法执行。");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 在请求的时候添加过滤规则
        System.out.println("Filter1 doFilter方法开始执行");
        // 执行下一个过滤器,如果下一个不是过滤器则执行目标程序Servlet
        chain.doFilter(request, response);
        // 在响应的时候添加过滤规则
        System.out.println("Filter1 doFilter方法执行结束");
    }

    @Override
    public void destroy() {
        System.out.println("destroy方法执行");
    }
}

使用过滤器改造oa项目

第一步: 编写一个过滤器LoginCheckFilter同时指定不需要拦截的路径

  • 当用户访问index.jsp首页,用户已经登录了(session中有用户信息),用户想要登录或退出,用户访问项目根目录即欢迎页的请求不能拦截
public class LoginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        //强制类型转化
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse) resp;
        // 获取请求路径
        String servletPath = request.getServletPath();
        HttpSession session = request.getSession(false);
        if("/index.jsp".equals(servletPath) || "/welcome".equals(servletPath) ||
                "/user/login".equals(servletPath) || "/user/exit".equals(servletPath)
                || (session != null && session.getAttribute("user") != null)){
            // 继续往下走
            chain.doFilter(request, response);
        }else{
            response.sendRedirect(request.getContextPath() + "/index.jsp");
        }
    }
}

第二步: 在web.xml中注册过滤器,/*表示拦截所有的路径

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">
    <!--登录检查的过滤器,过滤所有的路径-->
    <filter>
        <filter-name>loginFilter</filter-name>
        <filter-class>com.bjpowernode.oa.web.filter.LoginCheckFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>loginFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

第三步: 业务类相关的Servlet就不需要再编写代码判断用户是否登录,如果请求能到目标Servlet说明用户一定是登录过了,目标Servlet只需要转发请求即可

@WebServlet({"/dept/list", "/dept/detail", "/dept/delete", "/dept/save", "/dept/modify"})
public class DeptServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String servletPath = request.getServletPath();
        if("/dept/list".equals(servletPath)){
            doList(request, response);
        }else if("/dept/detail".equals(servletPath)){
            doDetail(request, response);
        }else if("/dept/delete".equals(servletPath)){
            doDel(request, response);
        }else if("/dept/save".equals(servletPath)){
            doSave(request, response);
        }else if("/dept/modify".equals(servletPath)){
            doModify(request, response);
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1073247.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker安装Jenkins完整教程

1.docker拉取 Jenkins镜像并启动容器 新版本的Jenkins依赖于JDK11 我们选择docker中jdk11版本的镜像 # 拉取镜像 docker pull jenkins/jenkins:2.346.3-2-lts-jdk11 2.宿主机上创建文件夹 # 创建Jenkins目录文件夹 mkdir -p /data/jenkins_home # 设置权限 chmod 777 -R /dat…

【C/C++】指针与函数传参

1、值传递 2、地址传递 注意&#xff1a;如果实参是一个普通变量&#xff0c;地址传参的话就需要形参是一级指针&#xff0c; 如果实参是一个一级指针&#xff0c;地址传参的话就需要形参是一个二级指针&#xff0c; 以此类推 3、传数组&#xff1a; 将数组作为参数传递给函…

DATA URL:嵌入 URL 中的数据资源

文章目录 参考环境DATA URL概念结构DATA URL 的优缺点优点缺点 DATA URL 与图片获取图片的 Base64 编码结果在 HTML 中应用 DATA URL 以展示图片 DATA URL 与 allow_url_fopen 及 allow_url_include 配置项allow_url_fopen 配置项allow_url_include 配置项allow_url_fopen 与 a…

Word中设置粘贴为纯文本的自定义快捷键

1、依次点击左上角 File(文件)->options(选项)-> Customize ribbon(自定义功能区)->Customize (自定义快捷键) 2、选择 All commands(所有命令)->PasteTextOnly(粘贴纯文本)&#xff0c; 在 Press new shortcut key (键入新快捷键)中输入自己喜欢的快捷键&#xff…

华为云云耀云服务器L实例评测|华为云上的CentOS性能监测与调优指南

目录 引言 ​编辑1 性能调优的基本要素 2 性能监控功能 2.1 监控数据指标 2.2 数据历史记录 2.3 多种统计指标 3 性能优化策略 3.1 资源分配 3.2 磁盘性能优化 3.3 网络性能优化 3.4 操作系统参数和内核优化 结论 引言 在云计算时代&#xff0c;性能优化和调优对于…

视觉效果绝佳的制作电子宣传册的网站

随着数字技术与设计理念的融合&#xff0c;电子宣传册不再是平面的文字与图片堆砌&#xff0c;而是通过多媒体元素、动画效果和交互性功能营造出沉浸式的阅读体验。小编向大家推荐一款名为FLBOOK的制作电子宣传册的网站。 首先&#xff0c;打开FLBOOK电子杂志制作网站然后点击模…

长城网络靶场第五题,流量包分析

关卡描述&#xff1a;1.小利访问最频繁的网站是&#xff1f;&#xff08;只填写一级域名&#xff09; 因为是一级域名所以只要 gamersky.com 关卡描述&#xff1a;2.小利的IP是多少&#xff1f; 看数据包很明显 标准答案&#xff1a;192.168.12.126 关卡描述&#xff1a;3.黑…

Win11通过注册表或者kernel32.dll的SetUserGeoName等方式设置国家或地区后重启过一会就自动变回原来的值...

最近同事 panwangvie 尝试通过代码设置国家或地区&#xff0c;尝试过注册表或者kernel32.dll的SetUserGeoName等方式设置&#xff0c;重启过一会就自动变回原来的值 我也尝试了以下方式均不行&#xff1a; 1. 一开始怀疑是自动时钟影响&#xff0c;所以把自动时钟关闭了 2. 然后…

c++桥接模式,中介者模式应用实现状态跳转

上图为例&#xff0c;按上述两种方式实现的模式跳转&#xff0c;如果在原先的三种模式之间再增加多一种模式&#xff0c;就会引起每个模式都会要求改变&#xff0c;并且逻辑混乱&#xff0c;因此更改模式为桥接中介者访问&#xff0c;将抽象和实现分离&#xff0c;实现之间采用…

STM32单片机裸机程序怎么处理大量网络数据?

STM32单片机裸机程序怎么处理大量网络数据? 无论是在中断中处理数据&#xff0c;还是在主循环里处理数据&#xff0c;你用于处理数据的时间是不变的。 你可以算一下&#xff0c;处理数据的时间&#xff08;速率&#xff09;和单片机的处理能力相差有多大&#xff0c;单片机是…

Android原生实现控件圆角方案(API28及以上)

Android控件的圆角效果的实现方式有很多种&#xff0c;这里介绍一下另一种Android原生的圆角实现方案&#xff08;API28及以上&#xff09;。 我们利用ShapeAppearanceModel、MaterialShapeDrawable来实现一个圆角/切角的Button。 实现效果如下图 我们在为控件添加阴影的基础上…

【软考设计师】S01 数据结构 E01 线性结构 P01 线性表

线性表 前言——线性结构线性表线性表的定义线性表的特点线性表的存储结构顺序存储链式存储单链表双向链表循环链表静态链表 前言——线性结构 线性结构是一种基本的数据结构&#xff0c;主要用于对客观世界中具有单一前驱和后继的数据关系进行描述。线性结构的特点是数据元素…

漏刻有时数据可视化Echarts组件开发(43)水球图svg温度计动画

SVG是一种用XML定义的语言&#xff0c;用来描述二维矢量及矢量/栅格图形。具体来说&#xff0c;SVG图形是可伸缩的矢量图形&#xff0c;其图像质量不会因放大或改变尺寸而损失。 在SVG中&#xff0c;可以创建和修改图像、对图像进行搜索和索引、对其进行脚本化或压缩。此外&am…

【网络安全入门】学习网络安全必须知道的100 个网络基础知识

前言 话不多说&#xff0c;完整的资料已经上传至CSDN官方&#xff0c;需要的可以点击链接自取【282G】网络安全&黑客技术零基础到进阶全套学习大礼包&#xff0c;免费分享&#xff01; 1 什么是链接? 链接是指两个设备之间的连接。它包括用于一个设备能够与另一个设备…

Zabbix“专家坐诊”第206期问答汇总

问题一 Q&#xff1a;老师&#xff0c;我想配置一下监控项和触发器&#xff0c;目前我想要三个&#xff0c;内存的使用情况百分比、磁盘的剩余多少G、CPU的使用情况百分比&#xff0c;用自带的模板修改&#xff0c;该怎么做&#xff1f; A&#xff1a;可以用100减去内置键值cp…

ICCV 2023 | 当尺度感知调制遇上Transformer,会碰撞出怎样的火花?

作者 &#xff5c; AFzzz 1 文章介绍 近年来&#xff0c;基于Transformer和CNN的视觉基础模型取得巨大成功。有许多研究进一步地将Transformer结构与CNN架构结合&#xff0c;设计出了更为高效的hybrid CNN-Transformer Network&#xff0c;但它们的精度仍然不尽如意。本文介绍…

java spring cloud 工程企业管理软件-综合型项目管理软件-工程系统源码

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管…

基于ssm的少儿编程网上报名系统+vue【附PPT|万字文档(LW)和搭建文档】

主要功能 前台登录&#xff1a; 注册用户&#xff1a;用户名、密码、姓名、联系电话 用户&#xff1a; ①首页、课程信息推荐、课程资讯、查看更多 ②课程详情、点我收藏、购买、评论、留言反馈 ③个人中心、修改用户名、密码、姓名、性别、头像、手机号、我的收藏等 后台登录…

Pycharm调试时,到达断点后,一直connected

Pycharm调试时&#xff0c;到达断点后&#xff0c;一直connected&#xff0c;画了一上午时间&#xff0c;最后发现是因为我dataloader使用的是多进程&#xff0c; 选中Gevent兼容后解决。

九方云学堂学员告诉你学习可以掌握哪些内容

在当前的股票市场环境下,存在许多不确定性因素和风险。虽然不少新兴行业的诞生,为投资者带来了更多的投资机会,但是风险同样会与日俱增。在这种情况下,作为一名投资者,想要在不断变化的市场环境中,提高投资胜率,做到复利,完整、科学的投资策略,成为了越来越多投资者关注的焦点。…