以前項目中並本身並無怎麼使用到過@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的參數後返回頁面