当前位置: 首页 > news >正文

spring高级篇(八)

本篇对Spring MVC 的执行流程做一个简单总结

MVC执行流程总结

        当浏览器发送一个请求,例如http://localhost:8080/hello,请求到达服务器后,一般会进行如下操作:

        1、首先会经过DispatcherServlet,默认映射路径为 /,即会匹配到所有请求 URL,可作为请求的统一入口,也被称之为前控制器(jsp 不会匹配到 DispatcherServlet )

        非Spring Boot 程序,需要手动进行创建,此前的案例中已多次演示:

   /*** 创建DispatcherServlet* @return*/@Beanpublic DispatcherServlet dispatcherServlet(){return new DispatcherServlet();}

        Spring Boot 程序,由 DispatcherServletAutoConfiguration 进行自动装配:

        DispatcherServlet默认是在首次使用时,由tomcat容器初始化,也可以进行设置setLoadOnStartup() 为启动时初始化:

    /*** 注册DispatcherServlet springmvc入口* @param dispatcherServlet* @return*/@Beanpublic DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet,WebMvcProperties webMvcProperties){DispatcherServletRegistrationBean registrationBean = new DispatcherServletRegistrationBean(dispatcherServlet, "/");//设置tomcat容器启动时即进行DispatcherServlet初始化registrationBean.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());return registrationBean;}

        DispatcherServlet 初始化时会优先到容器里寻找各种组件,作为它的成员变量:

        下面的init方法有一个共同点:首先会去父子容器中寻找有无相关组件,如果没有会使用默认的组件:

  • HandlerMapping :初始化时记录映射关系。(初始化时,会收集所有映射信息,封装为 Map)
  • HandlerAdapter :初始化时准备参数解析器、返回值处理器、消息转换器 。(分派请求)
  • HandlerExceptionResolver :初始化时准备参数解析器、返回值处理器、消息转换器。(处理异常)
  • ViewResolver :准备视图处理

        容器初始化时,会收集所有 @RequestMapping 映射信息,封装为 Map:

//        RequestMappingHandlerMapping 初始化时,会收集所有 @RequestMapping 映射信息,封装为 Map
//        k:请求方式 路径{ /test4}  v 方法信息com.itbaima.a18.Controller1#test4()Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();handlerMethods.forEach((k,v)->{System.out.println( k + "=" + v);});

       2、DispatcherServlet 会利用HandlerMapping 的实现去查找控制器方法,我们使用最常用的 RequestMappingHandlerMapping 举例:

  • 根据 /hello 路径找到 @RequestMapping("/hello") 对应的控制器方法
  • 控制器方法会被封装为 HandlerMethod 对象,并结合匹配到的拦截器一起返回给 DispatcherServlet
  • HandlerMethod 和拦截器合在一起称为 HandlerExecutionChain(调用链)对象
//发送请求了,根据路径K 获取RequestMappingHandlerMapping  封装的 Map 对应的V HandlerMethod
//获取的结果会包装在拦截器链中
//HandlerExecutionChain with [com.itbaima.a18.Controller1#test1()] and 0 interceptors
HandlerExecutionChain chain = handlerMapping.getHandler(request);

       3、DispatcherServlet 接下来会:

        调用拦截器的 preHandle 方法:如果与preHandle方法中定义的拦截规则不匹配,就直接返回错误信息,不再向下执行。

        RequestMappingHandlerAdapter 调用 handle 方法,准备数据绑定工厂、模型工厂、ModelAndViewContainer、将 HandlerMethod 完善为 ServletInvocableHandlerMethod:

  • @ControllerAdvice 全局增强点1️:补充模型数据,通过解析@ModelAttribute  标注的方法补充模型数据到container中。
    @ControllerAdvicestatic class MyControllerAdvice {@ModelAttribute("a")public String aa() {return "aa";}}/*** ModelAttribute注解加在参数上,由参数解析器负责解析* 加在方法上,由HandlerAdapt进行解析*/@Controllerstatic class Controller1 {@ResponseStatus(HttpStatus.OK)public ModelAndView foo(@ModelAttribute("u") User user) {System.out.println("foo");return null;}}
  • @ControllerAdvice 全局增强点2:补充自定义类型转换器,通过@InitBinder 注解标记一个用于初始化DataBinder对象,自定义数据绑定行为的方法,它会在控制器处理请求之前被调用。(如果@InitBinder注解加在被@ControllerAdvice 注解标记的控制器类的方法中时,其作用范围是全局的,并且是由RequestMappingHandlerAdapter 在初始化时解析并记录。而@InitBinder 注解加在被@Controller 标记的控制器中的方法上时,会在控制器方法首次执行时解析并记录。
    @ControllerAdvicestatic class MyControllerAdvice {@InitBinderpublic void binder3(WebDataBinder webDataBinder) {webDataBinder.addCustomFormatter(new MyDateFormatter("binder3 转换器"));}}@Controllerstatic class Controller1 {@InitBinderpublic void binder1(WebDataBinder webDataBinder) {webDataBinder.addCustomFormatter(new MyDateFormatter("binder1 转换器"));}public void foo() {}}

        RequestMappingHandlerAdapter中有两个成员变量:

  • private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache:用于存储被@ControllerAdvice标记的控制器中 @InitBinder 标注的方法。
  • private final Map<Class<?>, Set<Method>> initBinderCache:用于存储@Controller 标记的控制器中@InitBinder标注的方法。


        然后会使用 HandlerMethodArgumentResolver 准备参数

  • @ControllerAdvice 全局增强点3:RequestBody 增强        

        调用 ServletInvocableHandlerMethod 、使用 HandlerMethodReturnValueHandler 处理返回值。

  • @ControllerAdvice 全局增强点4:ResponseBody 增强

        ResponseBody返回响应体前包装:

    @ControllerAdvicestatic class MyResponseAdvice implements ResponseBodyAdvice<Object> {/*** 支持的方法** @param returnType    返回值类型* @param converterType 转换类型* @return*/@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {//如果方法上加了ResponseBody注解,或者类上加了ResponseBody/RestController注解,才进行转换if (returnType.getMethodAnnotation(ResponseBody.class) != null|| AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null) {return true;}return false;}/*** 增强的逻辑** @param body                  返回值* @param returnType            返回类型* @param selectedContentType   所选的响应内容类型。* @param selectedConverterType 所选的消息转换器类型。* @param request               当前的请求对象。* @param response              当前的响应对象。* @return*/@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {//如果返回值就是Result类型则直接返回if (body instanceof Result) {return body;}//否则包装成Result类型返回return Result.ok(body);}}

        最后会根据 ModelAndViewContainer 获取 ModelAndView:

  • 返回值处理器调用了 HttpMessageConverter 来将结果转换为 JSON,这时 ModelAndView 就为 null
  • 如果返回的 ModelAndView 为 null,不会进行后续的视图渲染与解析。

        ModelAndView、String、未被@ResponseBody 注解控制的对象类型返回值(无论是否显式声明了@ModelAttribute),都要经历视图渲染的过程。

        ModelAndView找视图,是根据ModelAndView构造中的viewName寻找同名的视图,还会使用.addObject() 方法中指定的数据对视图进行渲染 。

        如果没有指定视图名,则会:

        根据请求路径推断视图名: 如果在处理器方法中没有显式指定视图名,Spring MVC 会根据请求路径来推断视图名。
         根据返回值类型推断视图名: 如果处理器方法的返回值类型是String类型,并且没有使用 @ResponseBody 注解,Spring MVC 会将返回的字符串作为视图名处理。
        默认视图名: 如果以上两种方式都没有找到视图名,Spring MVC 会使用默认的视图名。默认的视图名通常是处理器方法所在的类名转换而来,再加上适当的前后缀。

        String找视图,是根据返回值的名称去找同名的视图。

        未被@ResponseBody 注解控制的对象类型返回值,找视图时,如果方法上使用 @RequestMapping("/") 及其派生注解声明了路径,则按照路径的值去匹配视图。如果没有,则需要手动指定路径。

        HttpEntity、HttpHeaders、加上了@ResponseBody 注解的对象返回值类型,因为对应解析器的handleReturnValue 方法中标记了请求已经被处理,无需继续渲染视图,所以不走渲染视图流程。其区别在于返回的响应头和响应体的完整性。

4、调用拦截器的 postHandle 方法

5、处理异常或视图渲染

  •  @ControllerAdvice 全局增强点5️:@ExceptionHandler 异常处理

6、调用拦截器的 afterCompletion 方法

相关文章:

spring高级篇(八)

本篇对Spring MVC 的执行流程做一个简单总结 MVC执行流程总结 当浏览器发送一个请求&#xff0c;例如http://localhost:8080/hello&#xff0c;请求到达服务器后&#xff0c;一般会进行如下操作&#xff1a; 1、首先会经过DispatcherServlet&#xff0c;默认映射路径为 /&…...

UP互助 帮助UP起号做视频 支持B站和抖音

【软件名字】&#xff1a;UP互助 【软件版本】&#xff1a;1.0 【软件大小】&#xff1a;17.5MB 【软件平台】&#xff1a;安卓 【测试机型】&#xff1a;小米9 1.随便登个邮箱&#xff0c;添加自己平台的频道&#xff0c;然后就可以帮助别人&#xff0c;添加频道后在添加…...

*求问?:为何会超时(TLE)?

D - Grid and Magnet (atcoder.jp) 错误代码&#xff1a; //2024年5月5日14:53:43 #include <bits/stdc.h> #define move mmove //防止与头文件中重复 using namespace std; int h,w; string s[1000]; const int move[4][2]{{1,0},{-1,0},{0,1},{0,-1}}; bool used[100…...

cocosstudio工程文件(.ccs)维护问题

创建cocos工程.bat在多人合作的cocos项目中&#xff0c;大家公用一个ccs文件&#xff0c;存在的问题是如果大家都提交ccs文件比较容易出现冲突&#xff0c;解决冲突麻烦要耗费时间&#xff0c;不提交的话就拉不到其他人更新的csd文件。 方案一 解决冲突&#xff0c;更新提交c…...

Blender动画与云渲染:创造高质量作品的未来路径

Blender作为开源的3D图形软件&#xff0c;在多个领域广受欢迎。但随着项目复杂度提升&#xff0c;传统渲染方式受限。云渲染技术的兴起突破了这些限制&#xff0c;为创作者提供了更自由、高效的创作环境。 一、Blender动画项目的挑战 传统上&#xff0c;Blender动画渲染需要依…...

【MySQL】3.MySQL核心概念解析:数据完整性、事务处理、索引及聚簇索引与非聚簇索引

探索MySQL的内部机制&#xff0c;理解数据完整性、事务处理、索引策略以及聚簇索引与非聚簇索引的区别是至关重要的。这些概念构成了数据库设计和优化的基础&#xff0c;对于确保数据的准确性、提高查询效率、维护数据的一致性和实现复杂的数据库操作至关重要。本文将逐一剖析这…...

【netty系列-03】深入理解NIO的基本原理和底层实现(详解)

Netty系列整体栏目 内容链接地址【一】深入理解网络通信基本原理和tcp/ip协议https://zhenghuisheng.blog.csdn.net/article/details/136359640【二】深入理解Socket本质和BIOhttps://zhenghuisheng.blog.csdn.net/article/details/136549478【三】深入理解NIO的基本原理和底层…...

大数据Scala教程从入门到精通第二篇:Scala入门

一&#xff1a;Scala入门 1&#xff1a;为什么学习Scala Spark新一代内存级大数据计算框架&#xff0c;是大数据的重要内容 Spark就是使用Scala编写的。因此为了更好的学习Spark,需要掌握Scala这门语言 Spark的兴起&#xff0c;带动Scala语言的发展! 2&#xff1a;Scala的发展…...

Spring Data JPA数据批量插入、批量更新真的用对了吗

Spring Data JPA系列 1、SpringBoot集成JPA及基本使用 2、Spring Data JPA Criteria查询、部分字段查询 3、Spring Data JPA数据批量插入、批量更新真的用对了吗 4、Spring Data JPA的一对一、LazyInitializationException异常、一对多、多对多操作 前言 在前两篇文章已经…...

数据结构-线性表-应用题-2.2-12

1&#xff09;算法的基本设计思想&#xff1a;依次扫描数组的每一个元素&#xff0c;将第一个遇到的整数num保存到c中&#xff0c;count记为1&#xff0c;若遇到的下一个整数还是等于num,count,否则count--,当计数减到0时&#xff0c;将遇到的下一个整数保存到c中&#xff0c;计…...

目录页码右对齐快速解决

选择目录–段落–制表符&#xff0c;按图中设置即可...

分红76.39亿,分红率再创新高,成长活力无限的伊利带来丰厚回报

伊利47万股东&#xff0c;又等来了一个好消息。 4月29日&#xff0c;伊利股份发布2023年报&#xff0c;实现营业总收入1261.79亿元&#xff0c;归母净利润104.29亿元&#xff0c;双创历史新高&#xff0c;实现连续31年稳健增长。 在递交亮眼成绩单的同时&#xff0c;乳业巨头伊…...

关于行进线路。

https://map.tianditu.gov.cn/ 作者&#xff1a;Chockhugh 链接&#xff1a;https://www.zhihu.com/question/20545559/answer/494685117 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 以50km&#xff0c;几乎全是…...

Unity 编辑器工具 - 资源引用查找器

目录 1.功能概述 2.完整代码 3. 实现原理 4. 使用预览 5.新增优化版本 在Unity项目开发过程中&#xff0c;管理和维护资源之间的引用关系是至关重要的。当然我们项目也是需要这个功能 毕竟项目大了之后查找资源引用还是交给 资源引用查找器 比较好。 1.功能概述 资源引用…...

MySQL中的批量更新实战

MySQL中的批量更新实战 表结构 mysql> desc dept; --------------------------------------------------------- | Field | Type | Null | Key | Default | Extra | --------------------------------------------------------- | deptno | int(11) …...

为软件教学文档增加实践能力

为了更方便软件教学&#xff0c;我们在凌鲨(OpenLinkSaas)上增加了公共资源引用的功能。 目前可以被引用的公共资源: 微应用常用软件公共知识库Docker模板 引用公共资源 引用微应用 目前微应用包含了主流数据库&#xff0c;终端等工具&#xff0c;可以方便的进行各种相关实…...

39-2 Web应用防火墙 - WAF数据库层绕过

如果你本地没有安装mysql就先安装一下:4-2 MySQL 的下载与安装_mysql5.7.9.1下载-CSDN博客 一、数据库层绕过简介 绕过数据库层通常用于规避Web应用防火墙(WAF)的SQL注入防护规则。攻击者需要利用数据库特性,寻找规避常规安全策略的方法。这里涉及到不同数据库的特性、SQ…...

薪酬激励策略:留住企业核心人才的关键

在竞争激烈的商业环境中&#xff0c;企业为了保持竞争力和市场地位&#xff0c;必须高度重视人才的管理和发展。企业的核心人才是推动企业发展的关键因素&#xff0c;因此&#xff0c;如何有效地激励和留住这些核心人才&#xff0c;成为企业持续发展的关键之一。薪酬激励策略作…...

【bbs02补】注册功能form组件-前端-后端-总结、登录功能(前端、后端、生成验证码)

1 注册功能 1.1 注册功能form组件 1.2 注册功能前端 1.3 注册功能后端 1.4 forms组件和前后端总结 2 登录功能 2.1 登录前端 2.2 生成验证码 1 注册功能 1.1 注册功能form组件 # 注册页面-用户名-密码-确认密码-邮箱-手机号-头像# form组件 可以帮助我们1 快速生成前端页面2 数…...

MindSponge分子动力学模拟——定义一个分子系统

技术背景 在前面两篇文章中&#xff0c;我们分别介绍了分子动力学模拟软件MindSponge的软件架构和安装与使用。这里我们进入到实用化阶段&#xff0c;假定大家都已经在本地部署好了基于MindSpore的MindSponge的编程环境&#xff0c;开始用MindSponge去做一些真正的分子模拟的工…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

对象回调初步研究

_OBJECT_TYPE结构分析 在介绍什么是对象回调前&#xff0c;首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例&#xff0c;用_OBJECT_TYPE这个结构来解析它&#xff0c;0x80处就是今天要介绍的回调链表&#xff0c;但是先不着急&#xff0c;先把目光…...

Qt Quick Controls模块功能及架构

Qt Quick Controls是Qt Quick的一个附加模块&#xff0c;提供了一套用于构建完整用户界面的UI控件。在Qt 6.0中&#xff0c;这个模块经历了重大重构和改进。 一、主要功能和特点 1. 架构重构 完全重写了底层架构&#xff0c;与Qt Quick更紧密集成 移除了对Qt Widgets的依赖&…...

初级程序员入门指南

初级程序员入门指南 在数字化浪潮中&#xff0c;编程已然成为极具价值的技能。对于渴望踏入程序员行列的新手而言&#xff0c;明晰入门路径与必备知识是开启征程的关键。本文将为初级程序员提供全面的入门指引。 一、明确学习方向 &#xff08;一&#xff09;编程语言抉择 编…...