手写Spring框架---MVC实现

news2024/12/25 8:58:00

目录

预备

自研框架MVC的实现

MVC架构草图:

大致流程

实现思路

自定义注解

JavaBean

请求的拦截-建立DispatcherServlet

责任链处理请求

RequestProcessor矩阵

Render矩阵


  • 预备

  • 在DispatcherServlet:
    • 解析请求路径和请求方法
    • 依赖容器,建立并维护Controller方法与请求的映射
    • 用合适的Controller方法去处理特定的请求
  • 参照SpringMVC,仅通过DispatcherServlet进行请求派发这样可以让系统模块更加明确,该类的任务有:
    • 拦截全部请求
    • 解析请求
    • 派发给对应的Controller里面进行处理
  • 通过下面的注解可以拦截到全部请求

  • 由于给DispatcherServlet标记了@WebServlet("/"),所以在tomcat启动之后会将DispatcherServlet给加载进来

  • 因为设置了/匹配所有的的url-pattern,而且在tomcat插件中的设置了项目的根路径,<path>/${project.artifactId}</path>可以获取项目的名字,这样设置之后以项目名为根路径的请求都会经由DispatcherServlet来处理,里面的service方法就是用来处理请求的

  • 相关的请求就会交给DispatcherServlet来处理,在DispatcherServlet加载到tomcat里面之后,在首次接收外部请求的时候,会调用里面init方法来完成自身的初始化,初始化之后调用service来处理相关的请求
  • 后续的请求再到来时不会再执行初始化方法,直接调用service方法来处理请求
  • HttpServletRequest里面包含了请求路径和请求方法以及请求里面的业务参数
  • 通过类似简单工厂方法的模式解析请求方法和请求路径,按照请求路径和请求方法转发到对应的controller方法处理
  • 在实际的使用中可以选择将返回的数据转换为json格式返回给前端,或者也可以生成相关的页面视图返回给前端去做渲染
  • 下面的会对jsp请求也会进行拦截,如果我们在页面中转发到jsp,就依然会被拦截到这个类里

  • 原因在tomcat的web.xml中,反斜杠是Servlet中特殊的匹配模式,优先级最低,比*.jsp优先级低,但是反斜杠星号属于路径匹配,优先级比*.jsp高

  • 自研框架MVC的实现

  • MVC架构草图:

  • 大致流程

  • 获取http请求和需要回发的http响应对象,之后将他们委托给RequestProcessorChain处理
  • 我们只处理get和post方法的请求,RequestProcessorChain参照的是责任链模式的后置处理器的处理逻辑,里面保存了处理RequestProcessor接口的多个不同的实现类,之所以会有多个不同的实现类对应为DispatcherServlet是项目里面所有请求的唯一入口
  • DispatcherServlet[ 调度Servlet ]的作用是将请求分发到不同的处理器
  • 这些请求里即会有获取jsp页面的请求,也会有获取静态资源的请求、直接获取json数据的请求等,针对不同的请求会使用不同的RequestProcessor来处理
  • Spring MVC框架像许多其他MVC框架一样,以请求为驱动,围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)

  • 简要分析执行流程
    • 1-DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心
    • 用户发出请求,DispatcherServlet接收请求并拦截请求
    • 假设请求的url为:http://localhost:8080/SpringMVC/hello
    • 如上url拆分成三部分:
      • http://localhost:8080服务器域名
      • SpringMVC部署在服务器上的web站点
      • hello表示控制器
    • 通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器
    • 2-HandlerMapping为处理器映射;DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler
    • 3-HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello
    • 4-HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等
    • 5-HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler
    • 6-Handler让具体的Controller执行
    • 7-Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView
    • 8-HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet
    • 9-DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名
    • 10-视图解析器将解析的逻辑视图名传给DispatcherServlet
    • 11-DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图
    • 12-最终视图呈现给用户
  • 实现思路

    • 自研框架实现思路定义DispatcherServlet分发器
    • 创建责任链对象实例
    • 通过责任链模式来依次调用请求处理对请求进行处理
    • 对处理结果进行渲染
  • 自定义注解

    • @RequestMapping 标识controller的方法和请求路径和请求方法的映射问题

    • @RequestParam 请求方法参数名

    • @ResponseBody 用于标记自动对返回值进行json处理

  • JavaBean

    • ControllerMethod 待执行的Controller及其方法实例和参数的映射

    • ModelAndView 存储处理完后的结果数据以及显示该数据的视图

    • RequestMethod 框架目前支持的请求方法

    • RequestPathInfo 储存http请求路径和请求方法

  • 请求的拦截-建立DispatcherServlet

    • 初始化容器
    • 初始化请求处理器责任链
    • 通过责任链模式来依次调用请求处理器对请求进行处理
    • 对处理结果进行渲染

    • init方法
      • 对常驻变量进行初始化
      • servlet是程序执行的入口:对容器进行初始化并将相关的bean加载进来,同时完成AOP相关逻辑的织入,以及相关的IoC依赖注入等操作
      • 因为后面是采用责任链模式来实现RequestProcessor矩阵的,要将对应的处理器添加到处理器列表中
      • 将RequestProcessor矩阵按序添加到缓存列表里
      • 之所以按照图示的顺序进行添加,是因为我们的请求经过编码和路径的处理之后才能进行后续的处理
      • 将ControllerRequestProcessor放在最后是因为它的处理会比较耗时,需要将请求和controller的方法实例进行匹配
    • service方法
      • 首先创建责任链对象实例
      • 然后通过责任链模式来依次调用请求处理器对请求进行处理
        • 通过迭代器遍历注册的请求处理器实现类列表
        • 直到某个请求处理器执行后返回false为止
        • 期间如果出现异常,则交由内部异常渲染器处理
      • 最后对处理结果进行渲染
        • 如果请求处理器实现类均未选择合适的渲染器,则使用默认的
        • 调用渲染器的render方法对结果进行渲染
  • 责任链处理请求

  • 以责任链的模式执行注册的请求处理器
  • 委派给特定的Render实例对处理后的结果进行渲染

  • RequestProcessor矩阵

    • PreRequestProcessor处理器(请求预处理器):主要负责对请求的编码以及对路径做一些前置处理

    • 剩余的处理器都会去解析请求,以看看请求是否由该处理器去处理的
    • StaticResourceRequestProcessor处理器(静态资源处理器):对静态资源请求

    • 利用的tomcat默认请求派发器RequestDispatcher处理
    • JspRequestProcessor处理器(JSP处理器):对jsp页面的访问请求进行处理(不仅过controller直接访问页面的请求)

    • 利用的tomcat的jspServlet处理
    • ControllerRequestProcessor处理器(Controller处理器):将请求派发到对应的controller方法里面进行处理
      • 针对特定请求,选择匹配的Controller方法进行处理
      • 解析出请求里的参数及其对应的值,并赋值给Controller方法的参数
      • 选择合适的Render,为后续请求处理结果的渲染做准备

      • 建立Controller方法与请求的映射关系
        • 请求中包含的信息有路径和请求参数,所以需要根据这些信息找到对应的Controller方法
        • 利用RequestPathInfo存储请求的信息,ControllerMethod存储Controller以及方法的信息
        • 建立的映射关系就是RequestPathInfo与ControllerMethod的,这样就可以根据请求定位到对应的方法
      • 然后利用ConverterUtil给需要执行的方法参数赋值
      • 最后利用反射执行获取执行的结果,根据结果设置结果渲染器
  • Render矩阵

    • 渲染,处理了相关的请求之后,需要将结果以不同的形式给展现出来,并且处理的过程中可能会出现各种各样的异常,也需要去做体现
    • Render负责对结果进行包装并展现
    • 当处理器处理完之后就会调用特定的实现了Render接口的实现类,对处理结果进行展现

    • DefaultResultRender(默认结果渲染器):当请求处理成功后,用户只需要返回一个成功的状态码
      • 如果请求处理器实现类均未选择合适的渲染器,则使用默认的结果渲染器
      • 主要将处理的结果状态码返回,默认为200

    • JsonResultRender(Json结果渲染器):用户发送的请求是想要获取json格式的返回结果
      • 当方法上面使用@ResponseBody 注解时,利用Gson将结果转换成Json数据返回

    • ViewResultRender(视图解析器):将逻辑视图转换成用户可以看到的物理视图,类似于ModelAndView对象
      • 视图解析器则根据返回结果的不同,而进行跳转
      • 如果是String数据,则创建一个ModelAndView对象,并将数据加入到视图地址
      • 如果是ModelAndView,则会解析其中的视图地址和数据
      • 针对其他情况,则直接抛出异常

    • InternalErrorResultRender(异常结果渲染器):对异常的处理
      • 以责任链的模式处理请求,期间如果出现异常,则交由内部异常渲染器处理
      • 设置状态码500和异常信息

    • ResourceNotFoundResultRende(找不到路径渲染器):资源无法找到的异常
      • 在根据请求路径转发到Controller时,找不到对应的对象或者方法,则使用该渲染器
      • 返回404和请求的路径及方法

  • 测试成功

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

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

相关文章

最全的 Spring 依赖注入方式,你都会了吗?

Spring 正如其名字&#xff0c;给开发者带来了春天&#xff0c;Spring 是为解决企业级应用开发的复杂性而设计的一款框架&#xff0c;其设计理念就是&#xff1a;简化开发。 Spring 框架中最核心思想就是&#xff1a; IOC&#xff08;控制反转&#xff09;&#xff1a; 即转移…

ChatGPT 最佳实践指南之:使用外部工具

Use external tools 使用外部工具 Compensate for the weaknesses of GPTs by feeding them the outputs of other tools. For example, a text retrieval system can tell GPTs about relevant documents. A code execution engine can help GPTs do math and run code. If a …

45、Spring Boot自动配置原理

Spring Boot自动配置原理 lmport Configuration Spring spi 自动配置类由各个starter提供&#xff0c;使用Configuration Bean定义配置类&#xff0c;放到META-INF/spring.factories下使用Spring spi扫描META-INF/spring.factories下的配置类使用lmport导入自动配置类

通讯录管理系统--进阶(动态开辟内存+保存数据到文件)

文章目录 动态开辟内存优化改进通讯录类型改进初始化通讯录函数改进添加联系人的函数增加销毁通讯录信息的函数 保存数据到文件优化保存通讯录数据到文件读取数据到通讯录 完整的代码展示 在 C语言实现通讯录的所有基本功能详细代码分析中&#xff0c;我们已经实现了通讯录的基…

Linux系统编程:文件系统和inode

目录 一. 磁盘的结构和读写数据的方式 1.1 磁盘级文件和内存级文件 1.2 磁盘的物理结构 1.3 访问磁盘数据的方式 二. 磁盘文件系统 2.1 磁盘的分区管理方法 2.2 文件名和inode的关系 三. 结合文件系统对文件创建和删除的相关问题的理解 3.1 文件创建时操作系统进行的工…

如何给合宙ESP32-C3刷写arduino固件,arduinoIDE的配置,测试代码

视频教程 https://github.com/Yu-1120/ESP32-C3 资料下载地址 合宙ESP32-C3刷写arduino固件 然后点击安装就可以了 arduino-IDE的配置 我用的版本&#xff1a;2.1.1&#xff08;版本不对也多大没关系&#xff09; 下载安装 选择 ESP32C3 Dev Module 安装环境 配置环境&am…

二十六、传输层协议(下)

一、滑动窗口 刚才我们讨论了确认应答策略&#xff0c;对每一个发送的数据段&#xff0c;都要给一个ACK确认应答. 收到ACK后再发送下一个数据段。这样做有一个比较大的缺点, 就是性能较差. 尤其是数据往返的时间较长的时候. 既然这样一发一收的方式性能较低, 那么我们一次发送…

snpEff注释结果解读

目录 1.帮助文档 1.1 常用参数 2. 命令的用法&#xff1a; 3. 结果文件解读 4. SNP下游的分析 利用snpEff软件对 snp.vcf &#xff08;利用gatk软件calling-snp&#xff09;进行注释&#xff0c;运行下述命令&#xff1a; ## 构建好物种的数据库 java -jar /opt/snpEff/s…

基于Spring Boot的扶贫助农商城系统设计与实现(Java+spring boot+MySQL+VUE)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于Spring Boot的扶贫助农商城系统设计与实现&#xff08;Javaspring bootMySQLVUE&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;Java spr…

QTranslator语言转换

//appname的格式 例如通常为&#xff08;QQ为应用的名称&#xff09; QQ_en.ts或QQ_zh_CN.ts QString qmName"zh_CN"; QTranslator trans ; QString qm QString(":/translatoin/qt/appname_%1.qm").arg(qmName); auto ret trans.load(qm); Q_UNUSED(ret)…

CSS高级特性

1.CSS复合选择器 CSS复合选择器&#xff1a;复合选择器是由两个或多个基础选择器通过不同的方式组合而成的 1.1 标签指定式选择器&#xff1a;又称交集选择器&#xff0c;由两个选择器构成&#xff0c;其中第一个选择器为标记选择器&#xff0c;第二个为class选择器或id选择器…

【Spring core学习一】简单认识Spring是什么?

目录 1、为什么要学习Spring&#xff1f; 2、Spring是什么&#xff1f; 1、IoC是什么&#xff1f; 2、进一步通过代码演示理解IoC 3、怎么理解容器&#xff1f; 4、知道DI与IoC的区别&#xff1f; 1、为什么要学习Spring&#xff1f; 我们常说的Spring 指的是 Spring Fra…

地平线旭日x3派40pin引脚控制,点亮小灯,控制舵机

地平线旭日x3派40pin引脚控制&#xff0c;点亮小灯&#xff0c;控制舵机 引脚对照表点亮RGB小灯安装旭日X3派WiringPi使用WiringPi点亮RGB小灯使用软件PWM功能 官方用户手册中只有python控制教程&#xff0c;没有c语言控制教程。且官方的教程中并没有软件pwm功能。本教程在开发…

Linux——动静态库的制作和使用(实操+代码+原理介绍)

动静态库的制作和使用 1️⃣.动静态库介绍&#x1f3c0;静态库⚽️动态库&#x1f3c8;区别&#x1f3d0;使用动态库的优点包括&#xff1a;&#x1f3c9; 使用静态库的优点包括&#xff1a; 2️⃣静态库的制作&#x1f34a;Q:库文件能不能有main()函数&#xff1f;&#x1f34…

imazing是什么软件?2023年imazing官网中文版下载

最近很小伙们&#xff0c;咨询兔八哥&#xff0c;imazing是什么软件&#xff1f;&#xff0c;今天兔八哥爱分享整理一下imazing到底是什么软件&#xff1f;好用吗&#xff1f; imazing是一款iOS设备管理软件,借助 iMazing 的独有 iOS 备份技术&#xff08;无线、隐私和自动&am…

地震正演基础知识

文章目录 地震正演1. 地震正演基础知识1.1 地震波1.2 波动方程1.3 有限差分方法1.4 边界条件1.5 记录数据 2. 公式2.1 泰勒级数回顾2.2 二维声波方程&#xff08;连续的偏微分方程&#xff09;2.2.1 二维声波方程&#xff08;连续的偏微分方程&#xff09;2.2.2 离散化二维声波…

【C++】vector模拟实现

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

Netty 为什么有如此高的性能?

文章首发地址 Netty高性能的三个主题 I/O传输模型&#xff1a;用什么样的通道将数据发送给对方&#xff0c;是BIO、NIO还是AIO&#xff0c;I/O传输模型在很大程度上决定了框架的性能。数据协议&#xff1a;采用什么样的通信协议&#xff0c;是HTTP还是内部私有协议。协议的选…

1767_Perl中的全词匹配

全部学习汇总&#xff1a; GreyZhang/perl_basic: some perl basic learning notes. (github.com) 当我在上一家公司工作的时候遇到过一个问题&#xff0c;为了解决软件接口的冲突我们需要把一个软件工程中的所有变量全都修改加一个前缀。我觉得用Perl处理是一个很好的注意&…

数据库作业3

1.查询student表的所有记录 2.查询student表的第2条到4条记录 3.从student表查询所有学生的学号&#xff08;id&#xff09;、姓名&#xff08;name&#xff09;和院系&#xff08;department&#xff09;的信息 4.从student表中查询计算机系和英语系的学生的信息 5.从student表…