Java三大器之拦截器(Interceptor)的实现原理及代码示例

2023-11-12

前言:前面2篇博客,我们分析了Java中过滤器和监听器的实现原理,今天我们来看看拦截器。




1,拦截器的概念
    java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action
执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截
然后再之前或者之后加入某些操作。目前,我们需要掌握的主要是Spring的拦截器,Struts2的拦截器不用深究,知道即可。

2,拦截器的原理
    大部分时候,拦截器方法都是通过代理的方式来调用的。Struts2的拦截器实现相对简单。当请求到达Struts2的ServletDispatcher时,Struts2
会查找配置文件,并根据配置实例化相对的拦截器对象,然后串成一个列表(List),最后一个一个的调用列表中的拦截器。Struts2的拦截器是可
插拔的,拦截器是AOP的一个实现。Struts2拦截器栈就是将拦截器按一定的顺序连接成一条链。在访问被拦截的方法或者字段时,Struts2拦截器链
中的拦截器就会按照之前定义的顺序进行调用。

3,自定义拦截器的步骤
    第一步:自定义一个实现了Interceptor接口的类,或者继承抽象类AbstractInterceptor。
    第二步:在配置文件中注册定义的拦截器。
    第三步:在需要使用Action中引用上述定义的拦截器,为了方便也可以将拦截器定义为默认的拦截器,这样在不加特殊说明的情况下,所有的
Action都被这个拦截器拦截。

4,过滤器与拦截器的区别
    过滤器可以简单的理解为“取你所想取”,过滤器关注的是web请求;拦截器可以简单的理解为“拒你所想拒”,拦截器关注的是方法调用,比如拦截
敏感词汇。
4.1,拦截器是基于java反射机制来实现的,而过滤器是基于函数回调来实现的。(有人说,拦截器是基于动态代理来实现的)
4.2,拦截器不依赖servlet容器,过滤器依赖于servlet容器。
4.3,拦截器只对Action起作用,过滤器可以对所有请求起作用。
4.4,拦截器可以访问Action上下文和值栈中的对象,过滤器不能。
4.5,在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时调用一次。

5,Spring拦截器
5.1,抽象类HandlerInterceptorAdapter
    我们如果在项目中使用了Spring框架,那么,我们可以直接继承HandlerInterceptorAdapter.java这个抽象类,来实现我们自己的拦截器。

Spring框架,对java的拦截器概念进行了包装,这一点和Struts2很类似。HandlerInterceptorAdapter继承了抽象接口HandlerInterceptor。

package org.springframework.web.servlet.handler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public abstract class HandlerInterceptorAdapter implements HandlerInterceptor{
    // 在业务处理器处理请求之前被调用
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
        return true;
    }
    // 在业务处理器处理请求完成之后,生成视图之前执行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
      throws Exception{
    }
    // 在DispatcherServlet完全处理完请求之后被调用,可用于清理资源
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
      throws Exception{
    }
}

    接下来我们看一下Spring框架实现的一个简单的拦截器UserRoleAuthorizationInterceptor,UserRoleAuthorizationInterceptor继承了
抽象类HandlerInterceptorAdapter,实现了用户登录认证的拦截功能,如果当前用户没有通过认证,会报403错误。

package org.springframework.web.servlet.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class UserRoleAuthorizationInterceptor extends HandlerInterceptorAdapter{
    // 字符串数组,用来存放用户角色信息
    private String[] authorizedRoles;
    public final void setAuthorizedRoles(String[] authorizedRoles){
        this.authorizedRoles = authorizedRoles;
    }
    public final boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws ServletException, IOException{
        if (this.authorizedRoles != null) {
            for (int i = 0; i < this.authorizedRoles.length; ++i) {
                if (request.isUserInRole(this.authorizedRoles[i])) {
                    return true;
                }
            }
        }
        handleNotAuthorized(request, response, handler);
        return false;
    }
    protected void handleNotAuthorized(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws ServletException, IOException{
          // 403表示资源不可用。服务器理解用户的请求,但是拒绝处理它,通常是由于权限的问题
          response.sendError(403);
    }
}

    下面,我们利用Spring框架提供的HandlerInterceptorAdapter抽过类,来实现一个自定义的拦截器。我们这个拦截器叫做
UserLoginInterceptorBySpring,进行登录拦截控制。工作流程是这样的:如果当前用户没有登录,则跳转到登录页面;登录成功后,跳转到
之前访问的URL页面。

import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
/**
 * @description 利用spring框架提供的HandlerInterceptorAdapter,实现自定义拦截器
 */
public class UserLoginInterceptorBySpring extends HandlerInterceptorAdapter{
    // 在业务处理器处理请求之前被调用
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
        // equalsIgnoreCase 与 equals的区别?
        if("GET".equalsIgnoreCase(request.getMethod())){
            //RequestUtil.saveRequest();
        }
        System.out.println("preHandle...");
        String requestUri = request.getRequestURI();
        String contextPath = request.getContextPath();
        String url = requestUri.substring(contextPath.length());
        System.out.println("requestUri" + requestUri);
        System.out.println("contextPath" + contextPath);
        System.out.println("url" + url);
        String username = (String) request.getSession().getAttribute("username");
        if(null == username){
            // 跳转到登录页面
            request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
            return false;
        }
        else{
            return true;
        }
    }
    // 在业务处理器处理请求完成之后,生成视图之前执行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception{
        System.out.println("postHandle...");
        if(modelAndView != null){
            Map<String, String> map = new HashMap<String, String>();
            modelAndView.addAllObjects(map);
        }
    }
    // 在DispatcherServlet完全处理完请求之后被调用,可用于清理资源
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception{
        System.out.println("afterCompletion...");
    }
}

    拦截器是依赖Java反射机制来实现的。拦截器的实现,用到的是JDK实现的动态代理,我们都知道,JDK实现的动态代理,需要依赖接口。拦截器
是在面向切面编程中应用的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法。拦截器不是在web.xml,比如struts在
struts.xml中配置。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
    Object result = null;  
    System.out.println("方法调用前,可以执行一段代码" + method.getName());  
    result = method.invoke(this.targetObj, args);  
    System.out.println("方法调用后,可以执行一段代码 " + method.getName());  
    return result;  
}  

总结:
    1.过滤器(Filter):所谓过滤器顾名思义是用来过滤的,Java的过滤器能够为我们提供系统级别的过滤,也就是说,能过滤所有的web请求,
这一点,是拦截器无法做到的。在Java Web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或
者struts的action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者struts
的action前统一设置字符集,或者去除掉一些非法字符(聊天室经常用到的,一些骂人的话)。filter 流程是线性的,url传来之后,检查之后,
可保持原来的流程继续向下执行,被下一个filter, servlet接收。
    2.监听器(Listener):Java的监听器,也是系统级别的监听。监听器随web应用的启动而启动。Java的监听器在c/s模式里面经常用到,它
会对特定的事件产生产生一个处理。监听在很多模式下用到,比如说观察者模式,就是一个使用监听器来实现的,在比如统计网站的在线人数。
又比如struts2可以用监听来启动。Servlet监听器用于监听一些重要事件的发生,监听器对象可以在事情发生前、发生后可以做一些必要的处理。
    3.拦截器(Interceptor):java里的拦截器提供的是非系统级别的拦截,也就是说,就覆盖面来说,拦截器不如过滤器强大,但是更有针对性。
Java中的拦截器是基于Java反射机制实现的,更准确的划分,应该是基于JDK实现的动态代理。它依赖于具体的接口,在运行期间动态生成字节码。
拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其
执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截然后再之前或
者之后加入某些操作。java的拦截器主要是用在插件上,扩展件上比如 Hibernate Spring Struts2等,有点类似面向切片的技术,在用之前先要在
配置文件即xml,文件里声明一段的那个东西。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java三大器之拦截器(Interceptor)的实现原理及代码示例 的相关文章

  • 使用R建立银行贷款违约模型

    一 项目背景及目的 使用R语言对银行的个人贷款是否违约进行预测 帮助业务部门及时发现问题 以避免损失 二 数据说明 本项目数据集来自 数据科学实战 Python篇 数据集包含8个表 账户表accounts 信用卡表card 客户信息表cli
  • 海伯利安Atlas主网映射今日正式启动

    今日21 00时 GMT 8 起 Atlas主网HYN及节点映射将正式开启 从27日15 00时 GMT 8 起 系统将统一进行升级 用户在15 00 21 00 GMT 8 时间段内将无法从交易账户进行提币操作 待主网映射正式开始 将恢复
  • 设计立方体类

    练习案例 设计立方体类 1 设计立方体类 cube 2 求出立方体的面积和体积 3 分别用全局函数和成员函数判断两个立方体是否相等 include
  • 为什么Java有了synchronized之后还造了Lock锁这个轮子?

    众所周知 synchronized和Lock锁是java并发变成中两大利器 但是为什么Java有了synchronized之后还是提供了Lock接口这个api 难道仅仅只是重复造了轮子这么简单么 本文就来探讨一下这个问题 谈到这个问题 其实
  • 手写算法-python代码实现DBSCAN

    手写算法 python代码实现DBSCAN 原理解析 代码实现 实例演示与sklearn对比 总结 原理解析 上篇文章我们优化了Kmeans聚类算法 最后留下一个问题 Kmeans只适合处理凸样本集 不适合处理非凸样本集 这个问题 怎么解决
  • 2023最系统的网络安全学习路线

    什么是网络安全 网络安全是指保护计算机网络及其系统和应用程序的安全性和完整性 防止未经授权的访问 攻击 病毒 恶意软件和其他安全威胁 它是通过技术 管理和教育等综合手段来确保网络信息安全 网络安全包括网络防火墙 入侵检测系统 数据加密 网络
  • 【大模型】开源大模型汇总以及微调策略

    目录 前言 LLaMA stanford Alpaca Guanaco Vicuna Chinese LLaMA Alpaca Chinese Vicuna Luotuo Chinese Falcon OpenBuddy Falcon Ch
  • 数据结构第一章内容(思维导图以及概要)

    思维导图和内容概要 一 数据结构的基本概念 ps 与数据元素本身的形式 内容 相对位置 个数无关的是数据的逻辑结构 通常要求同一逻辑结构中的所有数据元素具有相同的特性 这意味着不仅数据元素所包含的数据项的个数要相同 而且对应数据项的类型要一
  • (一)python爬虫验证码识别(去除干扰线)

    一 python爬虫验证码识别 去除干扰线 1 开发环境与工具 python27 sklearn pytesser opencv等 pycharm windows7 2 数据集 用request库爬虫抓取某一网站验证码1200张 并做好标注
  • 满满的干货!java计算公式引擎

    Spring 全家桶 Spring 原理 Spring面试题 思维导图 面试题 Spring视频 Spring 原理 Spring特点 Spring 核心组件 Spring常用模块 Spring主要包 Spring常用注解 Sping第三方
  • MYSQL数据库锁常用sql(解决锁表,锁库)

    MYSQL数据库锁常用sql 解决锁表 锁库 查询数据库锁 SELECT FROM INFORMATION SCHEMA INNODB LOCKS 查看等待锁的事务 SELECT FROM INFORMATION SCHEMA INNODB
  • 谷歌整体战略:关于人工智能、云服务和登月计划的未来

    转载自我的博客 谷歌整体战略 关于人工智能 云服务和登月计划的未来 CB Insights 今日发布了一篇关于谷歌业务战略的深度分析报告 Google Strategy Teardown Betting The Future On AI C
  • qt自定义标题栏和边框_在Windows 7中自定义标题栏和其他系统字体

    qt自定义标题栏和边框 Would you like to tweak your title bar and menu fonts in Windows 7 Here s how you can change those little se
  • 嵌入式软件国际化(多语言) 点阵字库选择分析

    概述 嵌入式软件国际化 多语言 点阵字库选择分析 多字节字符集与unicode 多字节编码最大的问题在于每一个语种的字符集编码不兼容 unicode的好处在于将所有人类语种字符都有了统一的编码 现在世界上语言基本都包含在了基本多文种平面0上
  • c语言输出字符串显示在屏幕上,C语言输出printf

    C语言输出printf教程 在 在我们使用 printf 函数时 格式占位符的格式个数一定要与后面的需要输出的变量或者字面量的个数匹配 否则程序报错 printf函数详解 语法 int printf const char format 参数
  • Vue中动画的实现 从基本动画,到炫酷动画。看这一篇就够了

    文章目录 Vue中的基本动画实现 动画类名的重定义 使用第三方的动画库 我就选择其中一个库做示范其他都一样 Vue中的基本动画实现 直接一点 基本动画的步骤 在需要加动画的地方 加入transition
  • EXCEL实现多行多列转为一行多列形式,OFFSET函数

    1 需要实现数据多行多列转为一行多列的数据 2 使用函数 OFFSET A 1 COLUMN A1 1 3 MOD COLUMN A1 1 3 可根据实际数据情况替换数字 引用单元格 3 实现效果 4 操作步骤 观察数据 输入公式 点击回车
  • C++中的STL中(容器、迭代器、适配器、配置器)

    首先明确STL中的六大组成部分 容器 迭代器 适配器 算法 仿函数 配置器 一 C 中的容器 顺序容器 关联容器 容器适配器 1 顺序容器 2 关联容器 3 容器适配器 二 STL中 容器 适配器的关系 参考博客如下 C 顺序性容器 关联性
  • QT固定文件名格式串转化为TreeView在界面上展示文件树形目录

    获得的文件串格式 file1 1 sss txt file1 bin zip file2 linpanhu docx qmake vc bat send zip 思路 gt gt gt file1 1 sss txt file1 bin z
  • golang The system cannot find the file specified

    使用io ioutil包读取文件时报错 open abi The system cannot find the file specified 原因是 ioutil ReadFile 这个方法需要传入决绝路径的文件名 代码 abiStr er

随机推荐

  • ESP32 之 ESP-IDF 教学(十一)WiFi篇—— WiFi两种模式

    本文章 来自原创专栏 ESP32教学专栏 基于ESP IDF 讲解如何使用 ESP IDF 构建 ESP32 程序 发布文章并会持续为已发布文章添加新内容 每篇文章都经过了精打细磨 通过下方对话框进入专栏目录页 CSDN 请求进入目录 O
  • 安全模型和业务安全体系

    网络安全和业务安全 网络安全中 攻击者往往通过技术手段 以非正常的技术 XSS Injection Penestrating等 影响业务正常运行 窃取敏感数据 比如 某黑客通过SSRF进入内网 并在内网横向扩张 最终脱库成功 业务安全中 黑
  • 如何理解和解决CXXABI not found问题?

    编译C 程序时 在链接阶段有时会出现CXXABI not found的问题 usr lib64 libstdc so 6 version CXXABI 1 3 8 not found 问题出现的场景 当前编译的程序需要依赖其它已编译的组件
  • vtk中的点云曲面重建

    对于光学扫描设备 如激光雷达 采集到的非规则点云数据 最重要的需求之一就是进行表面重建 Surface Reconstruction 对成片密集分布的点云以三角片拟合 形成连续 精确 良态的曲面表示 目前主流的算法可分为剖分类 组合类和拟合
  • win11管理我的账户提示“无法使用个人帐户在此登录,请改用工作或学校帐户”

    先把所有账户删除 注销Store 重新登陆账户 登录后选择自动登录到所有Microsoft应用就好了
  • 210. 课程表 II

    文章目录 Tag 题目来源 题目解读 解题思路 方法一 拓扑排序 写在最后 Tag 拓扑排序 题目来源 210 课程表 II 题目解读 在选修某些课程之前需要先学习某些课程 先学习的课程有数组 prerequisites 给出 其中 pre
  • NAT和全网互通

    首先在GWserver设备上安装一个 路由和远程访问 然后打开路由和远程访问右键新建nat
  • 怎么用计算机测量一个物体的高度,常用测量工具的使用方法?

    工具分类测量工具通常按用途分为通用测量工具 专类测量工具和专用测量工具3类 测量工具还可按工作原理分为机械 光学 气动 电动和光电等类型 这种分类方法是由测量工具的发展历史形成的 但一些现代测量工具已经发展成为同时采用精密机械 光 电等原理
  • Ubuntu安装SSH服务

    注 安装前需要先将 源 配置好 以下演示为root账号 1 更新软件源 apt get install y update 2 安装openssl apt get install y update apt get install y open
  • Set集合框架

    前言 给大家讲讲Set结合框架 码字不易 点个关注 转载请说明 思维导图 目录 1 List和Set的区别 1 两者的特点 2 两者之间的对比 3 取值 2 Set集合的特点 3 Set集合的循环方式 4 HashSet去重复以及原理 1
  • git修改分支名

    使用git命令操作 1 修改本地分支名称 git branch m oldBranchName newBranchName 2 将本地分支的远程分支删除 git push delete origin oldBranchName 3 将改名后
  • virtual usb multikey安装设备时出现错误_【图解USB】USB 之CDC 程序结构(完结篇)...

    来源 公众号 鱼鹰谈单片机 作者 鱼鹰Osprey ID emOsprey本篇介绍整个例程的结构和程序流程 Github 里面有一个仓库CMSIS DAP https github com x893 CMSIS DAP 该工程可以导入到gi
  • 强化学习 最前沿之graph policy gradients

    强化学习 Zee最前沿系列 深度强化学习作为当前发展最快的方向 可以说是百家争鸣的时代 针对特定问题 针对特定环境的文章也层出不穷 对于这么多的文章和方向 如果能撇一隅 往往也能够带来较多的启发 本系列文章 主要是针对当前较新的深度强化学习
  • 使用SQL语句操作数据表和管理表中的数据

    一 使用SQL语句操作数据表 表名是可以在数据库中唯一确定的一张表 1 创建表 语法 create table 表的名字 列名1 数据类型 列名2 数据类型 列名3 数据类型 注意 创建表之后括号后应该用分号结束 并且在列名和数据类型的最后
  • Windows平台下安装与配置MySQL

    免费下载网址 https dev mysql com downloads windows installer 8 0 html 版本选择 社区版8 0 20 双击安装包 选择Developer Default 下一步 点Execute执行
  • C语言 - static inline

    2019 07 16 今天在看DPDK负载均衡的实例代码中 通过函数跳转 看到官方API后 发现了static inline这个关键字 这个我只是在很早之前知道inline是内联的 可以不进行压栈 但是static毕竟是限制函数的作用域的啊
  • Sentinel实现熔断与限流

    文章目录 一 Sentinel是什么 1 简介 2 对比 3 Linux安装 二 初始化演示工程 1 新建module cloudalibaba sentinel service8401 2 pom文件 3 application yml
  • 个人总结:京东技术体系员工级别划分及薪资区间

    管理层级 序列层级 职衔 对应T序 薪资区间 技术 M5 CXO M5 VP M4 3 高级总监 M4 2 总监 T5 40 50k M4 1 副总监 T5 35 45k M3 高级经理 T4 2 30 40k M2 2 经理 T4 1 2
  • 【ReID】【代码注释】采样器 deep-person-reid/samplers.py

    源码URL https github com michuanhaohao deep person reid blob master samplers py 采样器读源码注释如下 from future import absolute imp
  • Java三大器之拦截器(Interceptor)的实现原理及代码示例

    前言 前面2篇博客 我们分析了Java中过滤器和监听器的实现原理 今天我们来看看拦截器 1 拦截器的概念 java里的拦截器是动态拦截Action调用的对象 它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码 也可以在一个