以前项目中并本身并无怎么使用到过@ModelAttribute这个注解,接手一个老项目的时候发现项目中大量使用@ModelAttribute这个注解,在这里就整理下这个注解经常使用的方式,也为本身作个记录,以避免久了不用又忘记了
@ModelAttribute使用大体有有两种,一种是是直接标记在方法上,一种是标记在方法的参数中,两种标记方法产生的效果也各不相同,这里就列举下两种标记所产生的效果javascript
首先先作点简单的准备工做,写一个只包含一个button的jsp页面,这里能够看见,只是写了个简单按钮事件,跳转的modelTest.do这个路径css
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> <script type="text/javascript" src="<%=basePath%>static/js/jquery.min.js"></script> </head> <script type="text/javascript"> $(function () { $("#modelTest").on("click", function () { window.location.href = "<%=basePath%>model/modelTest.do"; }) }); </script> <body> <input type="button" id="modelTest" value="测试"> </body> </html>
下面,再让咱们写一个controller控制器,这里咱们再控制器中写两个方法,其中一个使用@RequestMapping方法路径标记为modelTest.do,另一个方法不标记路径,使用@ModelAttribute标记html
package com.lovo.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping(value = "model") public class ModelAttributeTest { @ModelAttribute public void init() { System.out.println("最早执行的方法"); } @ModelAttribute public void init02() { System.out.println("最早执行的方法02"); } @RequestMapping(value = "modelTest.do") public String modelTest() { System.out.println("而后执行的方法"); return "modelTest"; } @ModelAttribute public void init03() { System.out.println("最早执行的方法03"); } }
部署后运行,点击页面测试按钮,查看控制台输出,这个时候你会发现,后台控制器并无直接进入modelTest.do的路径,而是先执行了被@ModelAttribute标记的init方法。应该这么理解,当同一个controller中有任意一个方法被@ModelAttribute注解标记,页面请求只要进入这个控制器,无论请求那个方法,均会先执行被@ModelAttribute标记的方法,因此咱们能够用@ModelAttribute注解的方法作一些初始化操做。当同一个controller中有多个方法被@ModelAttribute注解标记,全部被@ModelAttribute标记的方法均会被执行,按前后顺序执行,而后再进入请求的方法。java
下面方法作一些变形,变形为带有参数的返回,这样也是实际开发中常常会操做的
首先像建立个pojo对象,对象包含userName,sex两个属性。并对JSP及控制器代码作一些修改jquery
页面使用EL表达式接受返回参数web
<script type="text/javascript"> $(function () { $("#modelTest").on("click", function () { window.location.href = "<%=basePath%>model/modelTest.do"; }) }); </script> <body> <input type="button" id="modelTest" value="测试"> <input type="text" value="${pojo.userName }"> <input type="text" value="${pojo.sex }"> </body>
@ModelAtterbute方法无返回值状况spring
@Controller @RequestMapping(value = "model") public class ModelAttributeTest { @ModelAttribute public void init(Model mode) { PojoTest pojo = new PojoTest(null, "小明", "男"); mode.addAttribute("pojo", pojo); } @RequestMapping(value = "modelTest.do") public String modelTest() { return "modelTest"; } }
访问ModelTest.jsp页面并点击测试app
出现以下结果jsp
从执行结果看出,当访问请求时,会首先访问init方法,而后再对test方法进行访问,而且是同一个请求,由于model模型数据的做用域与request相同,因此能够用此标记直接标记在方法上对实际要访问的方法进行一些初始化操做函数
@ModelAttribute标记方法有返回值
@Controller @RequestMapping(value = "model") public class ModelAttributeTest { @ModelAttribute public String init(Model mode) { System.out.println("进入init方法"); PojoTest pojo = new PojoTest(null, "小明", "男"); mode.addAttribute("pojo", pojo); return "model/befor.do"; } @RequestMapping(value = "befor.do") public String befor() { System.out.println("进入befor方法"); return "index"; } @RequestMapping(value = "modelTest.do") public String modelTest() { System.out.println("进入modelTest方法"); return "modelTest"; } }
这里稍微作了点变形,能够看到在被@ModelAttribute方法中设值了返回路径为befor方法,可是在在代码运行的过程当中并不会跳转befor方法,而是在代码执行完成return以前直接跳转了实际请求的方法。
当@RequestMapping标记和@ModelAttribute同时标记在一个方法上
@Controller @RequestMapping(value = "model") public class ModelAttributeTest { @RequestMapping(value = "modelTest.do") @ModelAttribute(value = "pojo") public String modelTest() { System.out.println("进入modelTest方法"); return "modelTest"; } }
点击测试页面发现进入控制器后返回,页面报404,这是由于当两个注解标记到同一个方法上时,逻辑视图名并非返回值,而是返回请求的路径,根据model/modelTest.do生成逻辑视图。在这里咱们修改下代码,把controller上的@RequestMapping标记去掉,并修改下页面的请求路径,让生成的视图路径和访问的页面路径相同
@Controller //@RequestMapping(value = "model") public class ModelAttributeTest { @RequestMapping(value = "modelTest.do") @ModelAttribute(value = "pojo") public String modelTest() { System.out.println("进入modelTest方法"); return "modelTest"; } }
<script type="text/javascript"> $(function () { $("#modelTest").on("click", function () { window.location.href = "<%=basePath%>modelTest.do"; }) }); </script> <body> <input type="button" id="modelTest" value="测试"> <input type="text" value="${pojo}"> </body>
点击测试页面,会发现当两个注解同时注解到一个方法上时,方法的返回值会变成model模型的返回值,key是标记的名
从from表单或url地址中取值,这里就以url地址为例,为了不url地址中文乱码问题,这里调用了encodeURL函数
<script type="text/javascript"> $(function () { $("#modelTest").on("click", function () { window.location.href="<%=basePath%>model/modelTest.do?userName="+encodeURI('小明')+"&sex="+encodeURI('男'); }) }); </script> <body> <input type="button" id="modelTest" value="测试"> <input type="text" value="${pojo.userName }"> <input type="text" value="${pojo.sex }"> </body>
@Controller @RequestMapping(value = "model") public class ModelAttributeTest { @RequestMapping(value = "modelTest.do") public String modelTest(@ModelAttribute("pojo") PojoTest pojo) { try { pojo.setUserName(new String(pojo.getUserName().getBytes("iso-8859-1"), "utf-8")); pojo.setSex(new String(pojo.getSex().getBytes("iso-8859-1"), "utf-8")); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(pojo); return "modelTest"; } }
点击页面测试,页面文本框会显示URL地址传递过来的参数,由于SpringMVC会自动匹匹配页面传递过来的参数的name属性和后台控制器中的方法中的参数名,若是参数名相同,会自动匹配,若是控制器中方法是封装的bean,会自动匹配bean中的属性,其实这种取值方式不须要用@ModelAttribute注解,只要知足匹配要求,也能拿获得值
从model对象中取值
@Controller @RequestMapping(value = "model") public class ModelAttributeTest { @ModelAttribute("pojo") public PojoTest init(PojoTest pojo) { pojo.setSex("男"); return pojo; } @RequestMapping(value = "modelTest.do") public String modelTest(@ModelAttribute("pojo") PojoTest pojo) { pojo.setUserName("小明"); return "modelTest"; } }
点击测试发现,modelTest拿到inint方法中的pojo对象,合并两次set的参数后返回页面