Spring @ModelAttribute
正文开始之前,先介绍个东西,Spring能够自动将请求参数封装到对应JavaBean上!
代码比较简单,也没有什么配置要记录,只是开启了<mvc:annotation-driven/>,可以看到达到了这样的效果:
请求中属性name age 自动映射到 User对象上,返回视图时 属性又自动封装填充到 request属性域中. 填充的属性 键值key默认为类名首字母小写.
记录下,请求中参数是如何绑定到User对象上并且填充到request属性域中.
Spring抽象出来一个接口HandlerMethodArgumentResolver,这个接口主要实现两个功能:判断我们能否完成对这种参数类型的转换工作,以及我们如何去完成参数类型转换的工作? 等等,完成什么参数类型转换工作? 当然是完成@RequestMapping方法入参的参数转换工作啊!
那我们肯定需要一堆的HandlerMethodArgumentResolver这个接口实现类吧,肯定要有顺序吧,肯定用ArrayList来存储这个实现类。
Spring<mvc:annotation-driven/>肯定偷偷帮我们注册了一系列的HandlerMethodArgumentResolver实现类吧!没错,SpringMvc偷偷注册了十来个这样的HandlerMethodArgumentResolver,具体怎么工作的这里不叙述了,
其中专门用来解析自定义对象JavaBean的是ArrayList的最后一个HandlerMethodArgumentResolver :ServletModelAttributeMethodProcessor, 前面HandlerMethodArgumentResolver 都没用,才考虑到我,┭┮﹏┭┮
(其实也不是最后一个,因为注册了两个ServletModelAttributeMethodProcessor,只是这种情况我们用的是最后一个).
上面提及的两个工作,肯定是先判断我们能否完成对这种参数类型的转换工作:
我们现在讨论的不带 ModelAttribute注解,所以前面条件返回false , 后面条件 : this指代ServletModelAttributeMethodProcessor,annotationNotRequired为 true (这就是注册两个ServletModelAttributeMethodProcessor的原因,排在前面只 解析@ModelAttribute的参数,而排在后面的解析自定义 JavaBean对象的转换)
annotationNotRequired为true的情况下,后面条件判断的是 进一步限定 参数类型, 不是Date、数组、URI、URL、Number这种类型的,我才有必要进行 属性映射到对象上;
代码片段位于:org.springframework.web.method.annotation.ModelAttributeMethodProcessor#supportsParameter
这么看来 自定义对象完全满足使用 ServletModelAttributeMethodProcessor 来进行参数转换,下一步就是请求参数 转换到 JavaBean对象的事儿了.
逐行简单介绍下作用:Line100 检测方法入参parameter上是否有ModelAttribute注解,有就以@ModelAttribute(value=”xx”)的value作为name,没有就以parameter的class属性,类名转小写作为name 例如User--->user
Line101. 首先判断现在的ModelMap中是否有该name属性, 有就直接取出来作为attribute(ModelMap可以通过@ModelAttribute标注在普通方法上预先绑定一些属性);
没有就尝试创建,首先看是不是可以通过 URI中的PathVariable、request中直接getAttribute获取啊,都行不通的情况就直接构造这个class的实例,构造总要有构造器,采用默认的空参构造器,你没有空参构造器就会抛出异常!
这也告诉我们,参数类型需要有默认的空参构造器;
Line104 判断下这个属性是不是被列入黑名单,bindingDisabled, 加入黑名单方式目前暂知 通过@ModelAttribute(binding=false)设置,暂时不考虑这种情况;
Line111 WebDataBinder对象,这里也涉及了@InitBinder注解的解析,可以看之前的博客记录; target就是存的上面的attribute
Line112 attribute不为空,Line114行完成了属性的绑定,name、age映射到User上,映射方式按照名称映射,支持 . 进行级联等复杂映射,映射方式具体API可以看我下面的例子.
这里完成调用了ConversionService进行一定的转换,比如支持@DateTimeFormat等等.
Line116 @Valid注解解析过程,这里跳过; Line127 底层使用converter进行类型转换,我想不明白为啥还要再转换一次? 上面已经完成了请求参数绑定到JavaBean中.
完成请求方法参数--->JavaBean以后,ModelMap中的值最终都会存到ModelAndView视图的model属性, InternalResourceView的renderMergedOutputModel方法进行将 model属性一个个存入request的属性中;
跳转到对应的视图比如jsp一般都是request.getRequestDispatcher进行跳转; 假如@RequestMapping方法返回值不是前往某个视图JSP, 不会将属性存入request中。
另外注意:存储在request中的 key为 name,当前情况也就是 类名首字母小写。
代码片段位于:org.springframework.web.method.annotation.ModelAttributeMethodProcessor#resolveArgument
展示下如何利用Spring Api完成这样的请求参数绑定生成具体的实例
- public class SimpleTest {
- public static void main(String[] args) {
- //接受Pojo对象
- BeanWrapperImpl bw = new BeanWrapperImpl(new Form7Pojo());
- PropertyValues pvs=new MutablePropertyValues();
- ((MutablePropertyValues) pvs).add("name","HelloWorld BeanWrapper");
- ((MutablePropertyValues) pvs).add("age",24);
- bw.setPropertyValues(pvs,false,false);
- Object target = bw.getWrappedInstance();
- System.out.println(target);
- BeanWrapperImpl bw2 = new BeanWrapperImpl(new Address());
- bw2.setAutoGrowNestedPaths(true);
- PropertyValues pvs2=new MutablePropertyValues();
- ((MutablePropertyValues) pvs2).add("city.name","南京");
- ((MutablePropertyValues) pvs2).add("location","鼓楼区");
- bw2.setPropertyValues(pvs2,false,false);
- Object target2 = bw2.getWrappedInstance();
- System.out.println(target2);
- }
- }
- @Setter
- @Getter
- @ToString
- public class Form7Pojo {
- private String name;
- private Integer age;
- }
- @Setter
- @Getter
- @ToString
- public class Address {
- private City city;
- private String location;
- }
- @Setter
- @ToString
- public class City {
- private String name;
- }
记录@ModelAttribute用法:
用法一: 单单用在 @RequestMapping中的方法参数中, 作用将当前对象以 “user2”的名字存入request ,展示在视图界面,默认是 “user”的名字.
用法二. 单单用在 @Controller方法中,不加@RequestMapping注解 ,作用: 该@ModelAttribute方法会在每个@RequestMapping方法执行之前执行一次, 在每个@RequestMapping方法中获取的方式:注入modelMap属性,modelMap.get(“skill”)的方式获取属性。
效果等同于如下方法:
用法三: 这种方式比较奇葩,先直接说结论,跳转到默认的JSP页面,比如我的默认JSP页面就是 /WEB-INF/jsp/demo5.jsp,request中存储属性{professionalSkill=hello}.
这个时候返回值类型String已经不重要了,反正都要存到request的attribute属性域中,key就是 @ModelAttribute注解的 value , value就是@RequestMapping方法返回值;
至于为啥跳转到/WEB-INF/jsp/demo5.jsp呢, DispatcherServlet的applyDefaultViewName方法是计算默认展示界面
SpringMvc计算默认展示界面规则:视图解析器前缀 + 请求相对路径 + 视图解析器后缀 ,请求相对路径就是/demo5
验证:下面是一个不含视图名的ModelAndView返回给前端,结果如下(因为Controller上有@RequestMapping为/modelAttri ):
用法四. 比如demoa方法,入参a就是demoaaaaaaa,其实通过注入ModelMap,然后get(“strA”)方法一样可以达到效果; 但是JSP页面上仍然可以使用 ${strA} ${strB}访问到对应属性;
简单记录下:SpringMvc @ModelAttribute注解解析位置:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getModelFactory
总结:
感觉@ModelAttribute不是个很实用的注解,映射到JavaBean的时候吧,不需要它也能存入到request中,用它大概就是为了自定义存入request的key值吧.
在每个@RequestMapping方法之前做些处理吧,感觉有点像拦截器,但是每个@ModelAttribute都要执行一遍,有点多余哈,还不能指定只执行一个,有点搞不明白能用来做啥┭┮﹏┭┮.
Spring @ModelAttribute的更多相关文章
- spring @ModelAttribute 注解
@ModelAttribute // 表示请求该类的每个Action前都会首先执行它,也可以将一些准备数据的操作放置在该方法里面. public void setReqAndRes(HttpServl ...
- Spring ModelAttribute注解失效原因
public String test(@RequestParam(value = "test") @ModelAttribute("test") String ...
- Spring MVC 中使用 Swagger2 构建动态 RESTful API
当多终端(WEB/移动端)需要公用业务逻辑时,一般会构建 RESTful 风格的服务提供给多终端使用. 为了减少与对应终端开发团队频繁沟通成本,刚开始我们会创建一份 RESTful API 文档来记录 ...
- springMVC @ModelAttribute学习
springMVC @ModelAttribute学习 博客分类: Spring @ModelAttribute 绑定请求参数到命令对象 @ModelAttribute一个具有如下三个作用: ①绑 ...
- spring中JavaConfig相关的注解
在spring3.0中增加配置spring beans的新方式JavaConfig,可以替换spring的applicataion.xml配置.也即@Configuration对等<beans/ ...
- Spring MVC 对于@ModelAttribute 、@SessionAttributes 的详细处理流程
初学 Spring MVC , 感觉对于 @ModelAttribute 和 @SessionAttributes 是如何被Spring MVC处理的,这一流程不是很清楚, 经过Google资料,有了 ...
- [Spring MVC] - @ModelAttribute使用
在Spring MVC里,@ModelAttribute通常使用在Controller方法的参数注解中,用于解释model entity,但同时,也可以放在方法注解里. 如果把@ModelAttrib ...
- spring3 jsp页面使用<form:form modelAttribute="xxxx" action="xxxx">报错,附连接数据库的spring MVC annotation 案例
在写一个使用spring3 的form标签的例子时,一直报错,错误信息为:java.lang.IllegalStateException: Neither BindingResult nor plai ...
- spring mvc:@RequestParam与@ModelAttribute异同
关于spring mvc中的两个注解:@RequestParam.@ModelAttribute区别,原先并没有特别注意,直到最近找别人开发的一个小模块的bug时,才有意识的比较了两者的区别. 1.@ ...
随机推荐
- DataStage 的优化原则
DataStage Job优化指导原则之一:算法的优化. 任何程序的优化,第一点首先都是算法的优化.当然这一点并不仅仅局限于计算机程序的优化,实际生活中也处处可以体现这一点.条条大路通罗 ...
- ios调用系统界面显示英文
调用系统相册界面 UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.sourceType ...
- C#调用接口注意要点
在用C#调用接口的时候,遇到需要通过调用登录接口才能调用其他的接口,因为在其他的接口需要在登录的状态下保存Cookie值才能有权限调用, 所以首先需要通过调用登录接口来保存cookie值,再进行其他接 ...
- C#实现枚举的相关操作
枚举中的Descript()描述值,以及枚举值是一种一一对应的关系.我们可以获取其描述值和枚举值,存放到字典中, 在实际的使用中我们就可以轻松的根据枚举值来获取其描述值,也可以通过枚举的描述值来获取其 ...
- 企业项目开发--cookie(2)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2.1.3.CookieUtil:(cookie的基本操作:增删查,注意没有改) 1 package co ...
- 【mock】后端不来过夜半,闲敲mock落灯花 (mockjs+Vuex+Vue实战)
mock的由来[假] 赵师秀:南宋时期的一位前端工程师 诗词背景:在一个梅雨纷纷的夜晚,正处于项目编码阶段,书童却带来消息:写后端的李秀才在几个时辰前就赶往临安度假去了,!此时手头仅有一个简单 ...
- git常用命令常用场景
在使用git之前,一直用的是svn版本管理:与svn最大不同的是,git有两个仓库,一个是本地仓库,一个是服务器上共享的仓库:本地仓库是每个开发者自己独有的,即使commit提交也只是提交到本地仓库: ...
- 201621123018《Java程序设计》第6周学习报告
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结. 2. 书面作业 1. clone方法 1.1 在 ...
- adb shell pm list packages的用法
abd shell pm list packages ####查看当前连接设备或者虚拟机的所有包 adb shell pm list packages -d #####只输出禁用的包. ...
- Spring Boot中使用Swagger2构建RESTful API文档
在开发rest api的时候,为了减少与其他团队平时开发期间的频繁沟通成本,传统做法我们会创建一份RESTful API文档来记录所有接口细节,然而这样的做法有以下几个问题: 1.由于接口众多,并且细 ...