正文开始之前,先介绍个东西,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完成这样的请求参数绑定生成具体的实例

  1. public class SimpleTest {
  2. public static void main(String[] args) {
  3. //接受Pojo对象
  4. BeanWrapperImpl bw = new BeanWrapperImpl(new Form7Pojo());
  5. PropertyValues pvs=new MutablePropertyValues();
  6. ((MutablePropertyValues) pvs).add("name","HelloWorld BeanWrapper");
  7. ((MutablePropertyValues) pvs).add("age",24);
  8. bw.setPropertyValues(pvs,false,false);
  9. Object target = bw.getWrappedInstance();
  10. System.out.println(target);
  11.  
  12. BeanWrapperImpl bw2 = new BeanWrapperImpl(new Address());
  13. bw2.setAutoGrowNestedPaths(true);
  14. PropertyValues pvs2=new MutablePropertyValues();
  15. ((MutablePropertyValues) pvs2).add("city.name","南京");
  16. ((MutablePropertyValues) pvs2).add("location","鼓楼区");
  17. bw2.setPropertyValues(pvs2,false,false);
  18. Object target2 = bw2.getWrappedInstance();
  19. System.out.println(target2);
  20. }
  21. }
  22.  
  23. @Setter
  24. @Getter
  25. @ToString
  26. public class Form7Pojo {
  27. private String name;
  28. private Integer age;
  29.  
  30. }
  31.  
  32. @Setter
  33. @Getter
  34. @ToString
  35. public class Address {
  36. private City city;
  37. private String location;
  38. }
  39.  
  40. @Setter
  41. @ToString
  42. public class City {
  43. private String name;
  44. }

记录@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的更多相关文章

  1. spring @ModelAttribute 注解

    @ModelAttribute // 表示请求该类的每个Action前都会首先执行它,也可以将一些准备数据的操作放置在该方法里面. public void setReqAndRes(HttpServl ...

  2. Spring ModelAttribute注解失效原因

    public String test(@RequestParam(value = "test") @ModelAttribute("test") String ...

  3. Spring MVC 中使用 Swagger2 构建动态 RESTful API

    当多终端(WEB/移动端)需要公用业务逻辑时,一般会构建 RESTful 风格的服务提供给多终端使用. 为了减少与对应终端开发团队频繁沟通成本,刚开始我们会创建一份 RESTful API 文档来记录 ...

  4. springMVC @ModelAttribute学习

    springMVC @ModelAttribute学习 博客分类: Spring   @ModelAttribute 绑定请求参数到命令对象 @ModelAttribute一个具有如下三个作用: ①绑 ...

  5. spring中JavaConfig相关的注解

    在spring3.0中增加配置spring beans的新方式JavaConfig,可以替换spring的applicataion.xml配置.也即@Configuration对等<beans/ ...

  6. Spring MVC 对于@ModelAttribute 、@SessionAttributes 的详细处理流程

    初学 Spring MVC , 感觉对于 @ModelAttribute 和 @SessionAttributes 是如何被Spring MVC处理的,这一流程不是很清楚, 经过Google资料,有了 ...

  7. [Spring MVC] - @ModelAttribute使用

    在Spring MVC里,@ModelAttribute通常使用在Controller方法的参数注解中,用于解释model entity,但同时,也可以放在方法注解里. 如果把@ModelAttrib ...

  8. spring3 jsp页面使用<form:form modelAttribute="xxxx" action="xxxx">报错,附连接数据库的spring MVC annotation 案例

    在写一个使用spring3 的form标签的例子时,一直报错,错误信息为:java.lang.IllegalStateException: Neither BindingResult nor plai ...

  9. spring mvc:@RequestParam与@ModelAttribute异同

    关于spring mvc中的两个注解:@RequestParam.@ModelAttribute区别,原先并没有特别注意,直到最近找别人开发的一个小模块的bug时,才有意识的比较了两者的区别. 1.@ ...

随机推荐

  1. DataStage 的优化原则

    DataStage Job优化指导原则之一:算法的优化.        任何程序的优化,第一点首先都是算法的优化.当然这一点并不仅仅局限于计算机程序的优化,实际生活中也处处可以体现这一点.条条大路通罗 ...

  2. ios调用系统界面显示英文

    调用系统相册界面 UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.sourceType ...

  3. C#调用接口注意要点

    在用C#调用接口的时候,遇到需要通过调用登录接口才能调用其他的接口,因为在其他的接口需要在登录的状态下保存Cookie值才能有权限调用, 所以首先需要通过调用登录接口来保存cookie值,再进行其他接 ...

  4. C#实现枚举的相关操作

    枚举中的Descript()描述值,以及枚举值是一种一一对应的关系.我们可以获取其描述值和枚举值,存放到字典中, 在实际的使用中我们就可以轻松的根据枚举值来获取其描述值,也可以通过枚举的描述值来获取其 ...

  5. 企业项目开发--cookie(2)

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2.1.3.CookieUtil:(cookie的基本操作:增删查,注意没有改)  1 package co ...

  6. 【mock】后端不来过夜半,闲敲mock落灯花 (mockjs+Vuex+Vue实战)

      mock的由来[假]   赵师秀:南宋时期的一位前端工程师 诗词背景:在一个梅雨纷纷的夜晚,正处于项目编码阶段,书童却带来消息:写后端的李秀才在几个时辰前就赶往临安度假去了,!此时手头仅有一个简单 ...

  7. git常用命令常用场景

    在使用git之前,一直用的是svn版本管理:与svn最大不同的是,git有两个仓库,一个是本地仓库,一个是服务器上共享的仓库:本地仓库是每个开发者自己独有的,即使commit提交也只是提交到本地仓库: ...

  8. 201621123018《Java程序设计》第6周学习报告

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结. 2. 书面作业 1. clone方法 1.1 在 ...

  9. adb shell pm list packages的用法

    abd shell pm list packages     ####查看当前连接设备或者虚拟机的所有包 adb shell pm list packages -d    #####只输出禁用的包. ...

  10. Spring Boot中使用Swagger2构建RESTful API文档

    在开发rest api的时候,为了减少与其他团队平时开发期间的频繁沟通成本,传统做法我们会创建一份RESTful API文档来记录所有接口细节,然而这样的做法有以下几个问题: 1.由于接口众多,并且细 ...