springboot源码解析之Model和Map参数解析

springboot源码解析之Model和Map参数解析

标签:源码:springboot

测试代码

@Controller
public class HelloController {@RequestMapping("/helloModelAndMap")public String helloModelAndMap(HttpServletRequest request, Model model, Map<String, Object> map) {System.out.println(model.getClass().getSimpleName());System.out.println(map.getClass().getSimpleName());System.out.println(model == map);request.setAttribute("message", "Hello World!");model.addAttribute("name", "张三");map.put("age", 18);// 这里拿不到Model和Map中的值,转发后能拿到 在视图渲染阶段才会放到请求域中System.out.println("helloMapAndModel:" + request.getAttribute("name"));System.out.println("helloMapAndModel:" + request.getAttribute("age"));return "forward:/success";}@RequestMapping("/success")@ResponseBodypublic Object success(ServletRequest request) {Map<String, Object> result = new HashMap<>();result.put("message", request.getAttribute("message"));result.put("name", request.getAttribute("name"));result.put("age", request.getAttribute("age"));return result;}}

控制台输出

BindingAwareModelMap
BindingAwareModelMap
true
helloMapAndModel:null
helloMapAndModel:null

请求响应

{"name":"张三","message":"Hello World!","age":18}

结果分析

通过输出可以看到,这里传入的Model对象和Map对象都是BindingAwareModelMap类型,并且指向同一个对象,BindingAwareModelMap既是Model也是Map

ModelAndViewContainer

image-20240306202335477

public class ModelAndViewContainer {// ...private final ModelMap defaultModel = new BindingAwareModelMap();public ModelMap getModel() {if (useDefaultModel()) {return this.defaultModel;}else {if (this.redirectModel == null) {this.redirectModel = new ModelMap();}return this.redirectModel;}}// ... }

MapMethodProcessor

Map是由MapMethodProcessor参数处理器处理的

public class MapMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {@Overridepublic boolean supportsParameter(MethodParameter parameter) {// 参数类型为Map,并且没有啥注解(所以如果想要用map接受前段传递的请求体里的参数,一定要不要忘记加上@RequestBody注解)return Map.class.isAssignableFrom(parameter.getParameterType()) &&parameter.getParameterAnnotations().length == 0;}@Override@Nullablepublic Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");// 解析参数 这里拿到了ModelAndViewContainer 里面的Model 也就是 BindingAwareModelMapreturn mavContainer.getModel();}@Overridepublic boolean supportsReturnType(MethodParameter returnType) {return Map.class.isAssignableFrom(returnType.getParameterType());}@Override@SuppressWarnings({"rawtypes", "unchecked"})public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {if (returnValue instanceof Map){mavContainer.addAllAttributes((Map) returnValue);}else if (returnValue != null) {// should not happenthrow new UnsupportedOperationException("Unexpected return type: " +returnType.getParameterType().getName() + " in method: " + returnType.getMethod());}}}

ModelMethodProcessor

Model参数是由ModelMethodProcessor解析的

public class ModelMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {@Overridepublic boolean supportsParameter(MethodParameter parameter) {// 参数类型是modelreturn Model.class.isAssignableFrom(parameter.getParameterType());}@Override@Nullablepublic Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");// 解析参数 和 MapMethodProcessor 一样,拿到了同一个 BindingAwareModelMap 对象,这也就是为什么测试方法里面model 和 map指向同一个对象的原因return mavContainer.getModel();}@Overridepublic boolean supportsReturnType(MethodParameter returnType) {return Model.class.isAssignableFrom(returnType.getParameterType());}@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {if (returnValue == null) {return;}else if (returnValue instanceof Model) {mavContainer.addAllAttributes(((Model) returnValue).asMap());}else {// should not happenthrow new UnsupportedOperationException("Unexpected return type: " +returnType.getParameterType().getName() + " in method: " + returnType.getMethod());}}}

参数解析过程中只是拿到了 BindingAwareModelMap 对象,执行目标方法的时候只是将key和value设置到了 BindingAwareModelMap 对象里面,那么具体是在哪里将 BindingAwareModelMap 中的key和value设置到请求域中的呢?

AbstractView

org.springframework.web.servlet.view.AbstractView#exposeModelAsRequestAttributes

protected void exposeModelAsRequestAttributes(Map<String, Object> model,HttpServletRequest request) throws Exception {model.forEach((name, value) -> {if (value != null) {// 这样就是为什么给model 和 map中方数据和给request放数据一样的原因request.setAttribute(name, value);}else {request.removeAttribute(name);}});
}

通过调用链我们可以发现是在渲染视图的过程中将BindingAwareModelMap 对象中的值设置到请求域中的

image-20240306204213299

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

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

相关文章

万物皆可Find My,伦茨科技ST17H6x芯片赋能产品苹果Find My功能

苹果的Find My功能使得用户可以轻松查找iPhone、Mac、AirPods以及Apple Watch等设备。如今Find My还进入了耳机、充电宝、箱包、电动车、保温杯等多个行业。苹果发布AirTag发布以来&#xff0c;大家都更加注重物品的防丢&#xff0c;苹果的 Find My 就可以查找 iPhone、Mac、Ai…

[ISP]DCT离散余弦变换及C++代码demo

1.基本定义 离散余弦变换(DCT for Discrete Cosine Transform) DCT&#xff08;Discrete Cosine Transform&#xff0c;离散余弦变换&#xff09;是一种常用的信号处理技术&#xff0c;广泛应用于图像处理、音频处理、视频压缩等领域。DCT将一个信号或数据序列从时域&#xf…

TensorFlow 与pytorch

TensorFlow 与pytorch 介绍 TensorFlow 的基本概念和使用场景python 搭建 tensorflow 介绍 pytorch 的基本概念和使用场景PyTorch中搭建模型 TensorFlow与pytorchTensorFlow与pytorch的区别TensorFlow与pytorch的联系TensorFlow与pytorch各自的开发团队TensorFlow与pytorch之外…

【Tauri】(5):本地运行candle和 qwen 大模型,并测试速度

1&#xff0c;本地运行candle 关于candle项目 https://github.com/huggingface/candle Hugging Face 使用rust开发的高性能推理框架。 语法简单&#xff0c; 风格与 PyTorch 相似。 CPU 和 Cuda Backend&#xff1a;m1、f16、bf16。 支持 Serverless&#xff08;CPU&#xff…

Angular变化检测 2.0版本学习

在学习如何在Angular中实现文字逐字显示的过程中&#xff0c;我发现要保证用户的体验感的关键点在于&#xff1a;如何确保实时更新.html页面的内容显示&#xff0c;保证及时在UI界面反应出后端返回的数据? 那如何解决这个问题呢&#xff1f;其实我在博客中有提到过这个问题的…

简单两步,从补税到退税

大家好&#xff0c;我是拭心。 最近到了一年一度的个人所得税年度申报时期&#xff0c;有人可以退好几千&#xff0c;而有的人则需要补上万元&#xff0c;人类的悲喜这一刻并不相通。 我申报的时候&#xff0c;提示我需要补税一万多&#xff0c;心有不甘但差一点就认了&#xf…

java SSM科研管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM科研管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S…

每天学习一个Linux命令之kill

每天学习一个Linux命令之kill 介绍 在Linux系统中&#xff0c;kill命令用于终止或发送信号给正在运行的进程。它是管理进程的一个重要工具&#xff0c;允许用户通过发送信号来控制进程的行为。本文将详细介绍kill命令可用的选项及其用法。 命令格式 kill [选项] <进程ID…

Python基础面试编程知识-杂

文章目录 1、 循环 1-100求和2、删除字典键 del3、合并字典update4、列表去重5、函数中 (*args,**kwargs)的意义6、python2和python3中的range函数区别7、什么样的语言能够用装饰器8、python内建数据类型9、__init__,__new__10、with 方法11、python 中可变数据类型和不可变数据…

796.子矩阵的和(acwing)

文章目录 796.子矩阵的和题目描述前缀和 796.子矩阵的和 题目描述 输入一个 n 行 m 列的整数矩阵&#xff0c;再输入 q 个询问&#xff0c;每个询问包含四个整数 x1,y1,x2,y2&#xff0c;表示一个子矩阵的左上角坐标和右下角坐标。 对于每个询问输出子矩阵中所有数的和。 输…

selenium鼠标操作实战

鼠标操作实战 鼠标单击操作 click()内置鼠标操作包ActionChains鼠标双击操作double_click()鼠标右击操作context_click()鼠标指针悬浮操作move_to_element(ele)鼠标拖动操作drag_and_drop(source, target)其他鼠标操作汇总 鼠标单击操作 click() from selenium import webdriv…

python中的文件操作2

文件遍历 在Python中&#xff0c;遍历文件通常指的是逐行读取文件中的内容。这种方式对于处理大型文件特别有用&#xff0c;因为它不需要一次性将整个文件加载到内存中。下面是几种常见的遍历文件内容的方法&#xff1a; 1. 使用with语句和for循环 这是最推荐的方式&#xf…

“2024杭州智慧城市及安防展会”将于4月在杭州博览中心盛大召开

2024杭州国际智慧城市及安防展览会&#xff0c;将于4月24日在杭州国际博览中心盛大开幕。这场备受瞩目的盛会&#xff0c;不仅汇集了全球智慧城市与安防领域的顶尖企业&#xff0c;更是展示最新技术、交流创新理念的重要平台。近日&#xff0c;从组委会传来消息&#xff0c;展会…

独孤思维:买了台一千块钱的电脑干副业

01 如何让自己集中精力做一件事情&#xff1f; 之前有个圈内大佬&#xff0c;为了写作集中精力&#xff0c;硬生生买了一个一千多的电脑。 这个电脑能干嘛&#xff1f; 只能写作&#xff0c;打字&#xff0c;连视频都卡&#xff0c;游戏就更不可能了。 为的是&#xff0c;…

【网站项目】089理发店会员管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

设计模式之模版方法实践

模版方法实践案例 实践之前还是先了解一下模版方法的定义 定义 模板方法模式是一种行为设计模式&#xff0c;它定义了一个骨架&#xff0c;并允许子类在不改变结构的情况下重写的特定步骤。模板方法模式通过在父类中定义一个模板方法&#xff0c;其中包含了主要步骤&#xf…

上海亚商投顾:沪指缩量调整 机器人概念股午后大涨

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日缩量震荡&#xff0c;创业板指午后涨超1%&#xff0c;随后上演冲高回落走势。风电、光伏等新能源方向…

Redis第7讲——哨兵模式详解

为了解决主从模式的无法自动容错及恢复的问题&#xff0c;Redis在主从复制的基础上加入了哨兵节点&#xff0c;也就是我们熟悉的哨兵模式。但现在基本不会用到哨兵模式&#xff0c;也就是这种模式只存在于面试中。 一、什么是哨兵模式 ps&#xff1a;主从服务器之间的数据同步…

ping多个IP的工具

Ping Tool 项目地址 python开发的IP搜索小工具 ping一个网段所有IP&#xff0c;显示结果查看某个ip地址开放监听的端口配置可保存