SpringMVC处理模型数据(2)

来源:互联网 发布:java字符串转date 编辑:程序博客网 时间:2024/06/06 05:12

上一篇文章中我们介绍了比较简单,也比较容易理解的处理模型数据的方法;现在我们进入下一个知识点,也是比较复杂的知识点,处理模型数据方法之ModelAttribute注解,我们在这里也就是谈谈对代码使用上的理解,然后再来探讨探讨SpringMVC内部的执行流程;说来尴尬,博主水平有限,源代码理解的不是很透彻,等以后有机会再回来补充吧。

话不多说,我们先上代码(笑,博主一直觉得自己的代码写的很清晰),看完代码,我们再来看内部原理和SpringMVC的处理流程,最后再来谈谈需要注意的地方,没写到的还请各位看客多多包涵。

表单代码部分:

<form action="springmvc/testModelAttribute">id:<input type="text" name="id" value="10001"/><br>name:<input type="text" name="username" value="rgx"/><br>email:<input type="text" name="email" value="rgx@god.com"/><br><input type="submit" value="submit"/></form>

控制器部分:

//@SessionAttributes(value = "user",types = String.class)@RequestMapping("/springmvc")@Controllerpublic class RequestMappingTest {public final static String SUCCESS = "success";@ModelAttributepublic void getUser(@RequestParam(value = "id") Integer id,Map<String, Object> map){// 模仿从数据库查询这条指定id的person的数据if(id != null){Person person = new Person(10001, "rgx", "123456", "rgx@god.com");System.out.println("从数据库获取对象:"+person);map.put("per", person);}}@RequestMapping("/testModelAttribute")public String testModelAttribute(@ModelAttribute(value = "per")Person person){System.out.println("修改:"+person);return SUCCESS;}}

结果显示部分:

这里不需要上代码,哈哈,因为我的结果都在控制台输出了,success.jsp只是一个判断处理是否成功的界面,并无数据显示。


好了,代码就是以上,但是需要说道说道的地方很多。

我们先来讲讲为什么SpringMVC要使用这种机制我们先来举一个例子,现在某系统有一个更改个人信息的功能,但是有一些信息不能要求被更改,比如公司钦定的员工编号,那个信息一人一个,所以不能被员工更改,传统的web开发会怎么做?是我的话,我就会把这个数据一起传过去,如果在表单显示的话就给输入框加一个readonly属性,让它不可被编辑,如果不在表单显示的话就将type属性设置为hidden。不管使用什么方式,最终这些数据都会被放入request域对象中传递给服务器,然后服务端更新数据。但是一旦我们对数据的安全性要求提升或者对系统的效率有了更高的要求,这样的处理方式就显得很蠢了。所以ModelAttribute旨在解决这个问题。

我们再把目光看向代码,代码中一共就是两个方法,一个是控制器目标方法,还有一个是被ModelAttribute修饰的方法,这两个方法有什么关系呢?回答这个问题,我们先来看看ModelAttribute注解都可以干什么。

在方法定义上使用 ModelAttribute 注解:
*Spring MVC在调用目标处理方法前,会先逐个调用在方法上标注了ModelAttribute注解的方法。
在方法的入参前使用 ModelAttribute 注解:
*可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数绑定到对象中,再传入入参
*将方法入参对象添加到模型中

看懂了吗,也就说我完全可以在使用ModelAttribute注解的方法内完成数据库的读操作,然后将数据map对象中去。例如上面的代码中,模拟了从数据库获取客户端请求中指定id的数据项,然后将数据以键值对的方式存入map中,其实也是存在了SpringMVC的隐式对象中。好,下面我们讲解实际的执行流程。


执行的流程是这样的
系统会优先执行ModelAttribute注解修饰的方法,在该方法内可能执行访问数据库查询数据等操作
然后将查询到数据转换为POJO,存放在map集合中(至于指定键时需要注意的地方后文再讲)
然后目标方法通过获取指定key的value值,准确的将客户端传来的数据更新到指定的对象中去
本例中客户端请求中不存在password参数,所以person对象就保持的是数据库原来的数据


OK,现在再来看看SpringMVC底层如何完成这个处理流程的。

 * SpringMVC确定目标方法POJO类型入参的过程 
  * 1.确定一个key

确定key的方式有两种,第一种是直接将POJO的首字母小写的字符串作为key,第二种自定义key

* 2.在impliciModel中查找key 对应的对象,若存在,则作为入参传入 

和上面确定key的方式对应,在隐式对象中查找对象时的key的确定方式也有两种,第一种方式默认使用POJO的首字母小写的字符串作为key,第二种使用ModelAttribute注解,指定具体的key,如本例。
* 3.若impliciModel不存在key 对应的对象,则检查当前的handler是否使用了SessionAttributes注解修饰,
若使用了该注解,且SessionAttributes注解的value属性值中包含了key,则会从HttpSession中获取key所对应的value值,若存在则直接传入到目标方法的入参中。若不存在则将抛出异常(比如本例,我如果将  ModelAttribute修饰的方法去掉,也将目前方法入参的ModelAttribute注解去掉,然后将类上面SessionAttributes注解的注释打开,就会报错。
* 4.若handler没有标识SessionAttributes注解或SessionAttributes注解的value值中不包含key,则会通过反射来创建POJO类型的 的参数,传入为目标方法的参数
* 5.SpringMVC会把key和value保存在到impliciModel中,进而保存到request中。


大部分的注意问题上面都都说完了,但是还有一个问题:就是因为被ModelAttribute修饰的方法会被优先执行,那么问题来了,我上面的方法直接使用了RequestParam注解来获取客户端请求的属性值,如果你的客户端的请求对象中不存在这个属性值,服务端就会报错。

0 0
原创粉丝点击