上一節咱們在SpringBoot中啓用了Spring MVC最終輸出了HelloWorld,本節咱們來說講Spring MVC中的模型綁定,這個名稱來源於.NET或.NET Core,不知是否恰當,咱們暫且這樣理解吧。javascript
一看註解名稱應該很是好理解,註解@RequestParam主要用來獲取查詢字符串參數,而註解@PathVaruable用於獲取路由參數,下面咱們來看以下一個例子:css
@ResponseBody @RequestMapping(value = "/demo1", method = RequestMethod.GET) public String demo1(@RequestParam(value = "param1", required = true, defaultValue = "jeffcky") String param1, @RequestParam(value = "param2", required = false) String param2) { return param1 + "," + param2; }
如上咱們獲取查詢字符串參數param1和param2,同時呢,咱們要求參數param1必須提供,若爲空,咱們給定默認值爲jeffcky,而參數param2可不提供,則爲其默認值,好比以下:html
咱們知道不管是註解@RequestParam仍是註解@PathVariable,都有屬性required,若爲false,則此參數無需提供,難道事實真的如此嗎,咱們看看以下示例:java
@ResponseBody @RequestMapping(value = "/demo3/{id}", method = RequestMethod.GET) public String demo3(@RequestParam(value = "id") String param1, @PathVariable(value = "id", required = false) String param2) { return param1 + "," + param2; }
咱們設置了路由上的變量id爲可選,當咱們請求時咱們也並未提供該參數,可是結果倒是404,這也證實:註解@RequestParam獲取查詢字符串,而註解@PathVariable獲取路由參數,雖然兩者註解提供參數(required)可選,可是針對註解@PathVariable該參數無效,並且參數必須提供,不然返回404。jquery
上述是咱們針對路由和查詢字符串註解的對比,接下來咱們來看看對於查詢字符串註解各類姿式,看看Spring是如何進行處理的呢,好比咱們有兩個根據註解@RequestParam的請求參數和方法同樣,此時將會發生什麼呢?,以下:spring
@RequestMapping(value = "/user", method = RequestMethod.GET) @ResponseBody public String say() { return "hello world"; } @RequestMapping(value = "/user", method = RequestMethod.GET) public ModelAndView user() { User user = new User(); user.setGender("M"); ModelAndView modelAndView = new ModelAndView("user", "command", user); return modelAndView; }
很顯然會啓動程序後會拋出上述異常,意爲不明確有兩個相同的映射,那麼要是咱們將say方法的請求方法給去掉,此時將代表可此方法的請求不受限制,如此這樣會報錯嗎?如若不報錯,那麼會首先匹配到哪一個呢?數據庫
@RequestMapping(value = "/user") @ResponseBody public String say() { return "hello world"; } @RequestMapping(value = "/user", method = RequestMethod.GET) public ModelAndView user() { User user = new User(); user.setGender("M"); ModelAndView modelAndView = new ModelAndView("user", "command", user); return modelAndView; }
由此咱們能夠知道:註解@RequestParam用於查詢字符串,若請求參數一致, 但一個請求方法未指定(接收全部方法),一個指定對應請求方法,結果將匹配到指定對應的請求方法。那麼要是咱們想讓其匹配到say方法,咱們應該腫麼辦呢?註解@RequestParam的參數爲數組,接下來咱們將say方法進行以下修改便可(參數順序可顛倒):bootstrap
@RequestMapping(value = {"/user", "*"}) @ResponseBody public String say() { return "hello world"; }
既然涉及到參數綁定,那麼咱們就得學習Spring MVC表單提交,順着這個思路咱們來學習Spring MVC表單相關內容,如上圖其實我已經給你們展現了對應方法和視圖,接下來咱們來經過表單提交來說講三者的區別,爲了有些童鞋可能須要親自動手實踐,這裏咱們先給出整個結構,以下:數組
咱們建立以下進行表單提交的用戶實體類瀏覽器
package com.demo.springboot.model; public class User { private String firstName; private String lastName; private String gender; private String email; private String userName; private String password; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
接下來咱們須要在控制器文件目錄下建立UserController控制器,而後呢,咱們返回用戶視圖,以下方法:
@RequestMapping(value = "/user", method = RequestMethod.GET) public ModelAndView user() { User user = new User(); user.setGender("M"); ModelAndView modelAndView = new ModelAndView("user", "command", user); return modelAndView; }
在前面內容咱們經過字符串的形式返回的視圖,而後加上經過配置文件中視圖存放位置和加上後綴查找視圖,可是利用ModelAndView纔是最友好的方式,經過其名稱添加模型和返回視圖應該就很清楚了,就像.NET MVC中的View方法同樣,咱們能夠返回模型數據,同時指定視圖名稱是一個道理。上述咱們設置了性別的默認值爲字符串M,咱們暫且先說到這裏,待會還要回過頭再次進行講解的,接下來咱們去建立user.jsp,以下:
<%@ page language="java" contentType="text/html;" pageEncoding="utf-8" %> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <html> <head> <title>Spring MVC Form</title> <link href="/static/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/css/bootstrap-theme.min.css" rel="stylesheet"> </head> <body> <div class="container"> <div class="col-md-offset-2 col-md-7"> <h2 class="text-center">Spring MVC 5 Form</h2> <div class="panel panel-info"> <div class="panel-heading"> <div class="panel-title">Sign Up</div> </div> <div class="panel-body"> <form:form action="addUser" class="form-horizontal" method="post" modelAttribute="user"> <div class="form-group"> <label for="firstName" class="col-md-3 control-label">First Name</label> <div class="col-md-9"> <form:input path="firstName" class="form-control"/> </div> </div> <div class="form-group"> <label for="lastName" class="col-md-3 control-label">Last Name</label> <div class="col-md-9"> <form:input path="lastName" class="form-control"/> </div> </div> <div class="form-group"> <form:label path="gender" class="col-md-3 control-label">gender</form:label> <div class="col-md-9"> <form:radiobutton path="gender" value="M" label="Male"/> <form:radiobutton path="gender" value="F" label="Female"/> </div> </div> <div class="form-group"> <label for="userName" class="col-md-3 control-label">User Name </label> <div class="col-md-9"> <form:input path="userName" class="form-control"/> </div> </div> <div class="form-group"> <label for="password" class="col-md-3 control-label">Password</label> <div class="col-md-9"> <form:password path="password" class="form-control"/> </div> </div> <div class="form-group"> <label for="email" class="col-md-3 control-label">Email</label> <div class="col-md-9"> <form:input path="email" class="form-control"/> </div> </div> <div class="form-group"> <div class="col-md-offset-3 col-md-9"> <form:button class="btn btn-primary">Submit</form:button> </div> </div> </form:form> </div> </div> </div> </div> <script type="text/javascript" src="/static/js/jquery.min.js"></script> <script type="text/javascript" src="/static/js/bootstrap.min.js"></script> </body> </html>
首先咱們必須在其頂部添加以下這一行代表咱們要使用spring framework框架中的表單,且前綴爲form:
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
在spring framework框架中對於表單中各個標籤的使用經過冒號隔開,以下:
<form:input path="firstName"/> <form:input path="lastName"/>
最終在瀏覽器中將渲染成HTML標籤,仍是很是簡單,這裏咱們只是稍微過一下,沒有太多複雜的東西,咱們只要知道規則便可
<input name="firstName" type="text" value=""/> <input name="lastName" type="text" value=""/>
咱們在後臺方法中返回模型即user,最終利用spring框架將模型上的屬性綁定到表單標籤上,那麼接下來咱們提交表單後,咱們在後臺怎麼獲取到模型數據呢,其實咱們在spring框架的表單標籤上定義了屬性modelAttribute,以下:
接下來咱們在後臺接收表單中的數據,以下:
@RequestMapping(value = "/addUser", method = RequestMethod.POST) public String addUser(@ModelAttribute("user") User user, ModelMap model) { model.addAttribute("firstName", user.getFirstName()); model.addAttribute("lastName", user.getLastName()); model.addAttribute("email", user.getEmail()); model.addAttribute("userName", user.getUserName()); model.addAttribute("password", user.getPassword()); return "users"; }
在後臺咱們一樣經過註解@ModelAttribute("user")與表單上定義的屬性modelAttribute="user"匹配,從而獲取數據,最終將獲取到的數據添加到ModelMap中,並返回視圖users.jsp中,以下:
<%@ page language="java" contentType="text/html;" pageEncoding="utf-8" %> <%@taglib uri = "http://www.springframework.org/tags/form" prefix = "form"%> <html> <head> <title>Spring MVC Form Handling</title> </head> <body> <h2>Submitted User Information</h2> <table> <tr> <td>firstName</td> <td>${firstName}</td> </tr> <tr> <td>lastName</td> <td>${lastName}</td> </tr> <tr> <td>Email</td> <td>${email}</td> </tr> <tr> <td>userName</td> <td>${userName}</td> </tr> <tr> <td>Password</td> <td>${password}</td> </tr> <tr> </tr> </table> </body> </html>
當咱們啓動程序時發現報錯了,根據咱們一路的解釋,彷佛沒有任何毛病,這是何緣故, 上述異常大概是代表特性user出了問題,其實緣由出在後臺獲取用戶視圖上,以下這一行上:
ModelAndView modelAndView = new ModelAndView("user", "command", user);
如上構造函數中的第一個參數表明要渲染的視圖名稱,而第三個參數是在視圖中要綁定的模型,那麼第二個參數是個什麼鬼呢?通常狀況下這個值都會默認設置成command,據查資料這個字符串在spring框架是一個常量,那麼它的做用是什麼呢?我我的猜想若是默認設置成該值,那麼就表明註解@ModelAttribute的參數值就是實體類名稱,好比咱們實體類爲User,那麼默認ModelAttribute參數名就是user,咱們無需在上述表單上指定modelAttribute的值,即便指定爲user也會拋出上述異常。若是在表單上顯式定義了modelAttribute的值,那麼在實例化模型視圖類時,第二個參數必須與其值相等,咱們將上述command修改成user便可解決問題,不信的話,你能夠試試。同時在接收表單提交的參數時,通過測試,後臺的註解@ModelAttribute可去除參數名稱也可綁定。最終根據咱們填寫表單的內容和渲染結果,以下:
上述咱們是經過ModelAndView返回模型和視圖,這只是實現方式之一,其餘實現將又會引來問題,接下來咱們直接返回該模型,此時將以該模型名稱做爲做爲表單上屬性modelAttribute的名稱,此時必須顯式設置modelAttribute="user",以下:
@RequestMapping(value = "/user", method = RequestMethod.GET) public User user() { User user = new User(); user.setGender("M"); user.setFavorites(new String[]{"乒乓球", "羽毛球", "檯球"}); return user; }
如若在上述表單上沒有顯式設置modelAttribute="user"且值不能爲其餘值,不然將拋出以下異常:
若咱們想將上述表單上的屬性modelAttribute的值user,設置爲其餘值,好比modelAttribute="User",此時必須在該視圖對應方法上經過註解@ModelAttribute顯式設置名稱爲User,不然一樣將拋出上述異常,以下:
@ModelAttribute("User") @RequestMapping(value = "/user", method = RequestMethod.GET) public User user() { User user = new User(); user.setGender("M"); user.setFavorites(new String[]{"乒乓球", "羽毛球", "檯球"}); return user; }
到此爲止咱們學習到了ModelAndView用來設置模型和視圖名稱,而註解@ModelAttribute則是控制器和視圖綁定數據的橋樑,該註解既可做爲方法參數接收視圖模型數據,也可修改控制器方法將模型數據綁定到視圖。ModelMap則是映射模型數據,固然也支持集合和合並特性等等。咱們再來演示經過對方法進行註解@ModelAttribute,而後綁定到視圖中,在User類中咱們再定義一個屬性country,以下:
private String country; public String getCountry() { return country; } public void setCountry(String country) { this.country = country; }
在控制器中經過註解@ModelAttribute定義國家元數據,並綁定到視圖上,以下:
@ModelAttribute("countryList") public Map<String, String> getCountryList() { Map<String, String> countryList = new HashMap<>(); countryList.put("CHI", "中國"); countryList.put("CH", "英國"); countryList.put("SG", "新加坡"); return countryList; }
<div class="form-group"> <label for="country" class="col-md-3 control-label">Country</label> <div class="col-md-9"> <form:select path = "country"> <form:option value = "無" label = "請選擇"/> <form:options items = "${countryList}" /> </form:select> </div> </div>
在視圖中咱們經過$符號渲染數據,固然我麼也能夠在視圖中寫Java代碼,這和.NET或.NET Core中的Razor視圖同樣,只不過在JSP中經過<% 代碼 %>來寫代碼,咱們一樣也來演示下,在User中再定義一個數組,以下:
private String[] favorites; public String[] getFavorites(){ return favorites; } public void setFavorites(String[] favorites) { this.favorites = favorites; }
在獲取user.jsp視圖對應後臺方法中,咱們設置上述定義的愛好列表默認值,以下:
user.setFavorites(new String[]{"乒乓球", "羽毛球", "檯球"});
同時在控制器中咱們定義愛好列表,而後綁定到視圖中,對默認設置的愛好列表經過checkbox進行選中
@ModelAttribute("favorites") public Object[] getfavoriteList() { List<String> favorites = new ArrayList<>(); favorites.add("足球"); favorites.add("乒乓球"); favorites.add("羽毛球"); favorites.add("檯球"); return favorites.toArray(); }
再在user.jsp視圖中,添加對愛好列表數據的綁定和選中,以下:
<div class="form-group"> <label for="favorites" class="col-md-3 control-label">Favorites</label> <div class="col-md-9"> <form:checkboxes class="f" items = "${favorites}" path = "favorites" /> </div> </div>
而後在獲取提交表單的方法中,獲取上述咱們添加的城市和選中的愛好列表,以下:
最後在渲染提交表單的視圖users.jsp中,當獲取愛好列表時,此時經過代碼的形式進行渲染,以下:
<tr> <td>Country</td> <td>${country}</td> </tr> <tr> <td> <% String[] favorites = (String[])request.getAttribute("favorites"); for(String favorite: favorites) { out.println(favorite); } %> </td> </tr>
本節咱們詳細分析了在Spring MVC中對於參數的綁定,最須要注意的是在模型綁定到視圖中的問題,這裏咱們下個結論: 若經過ModelAndView設置模型和視圖時,若此時第二個參數爲command,則表單上的屬性modelAttribute默認值爲模型名稱,此時若顯式設置值爲模型名稱將拋出異常,若顯式設置該屬性的值不爲模型名稱,此時須要將command設置與其同樣,不然將拋出異常。若直接返回模型時,此時表單上的屬性modelAttribute的值必須顯式設置爲模型名稱,不然將拋出異常,若表單上的屬性modelAttribute值不爲模型名稱時,此時必須在該視圖對應方法上顯式設置註解@ModelAttribute其名稱與其一致,不然將拋出異常。其餘的地方咱們只須要了解對應使用規則沒有什麼難點,好了,本節的內容咱們到此爲止,下一節咱們陸續開始於數據庫打交道,感謝您的閱讀,咱們下節見。