參數綁定,簡單來說就是客戶端發送請求,而請求中包含一些數據,那么這些數據怎么到達 Controller ?這在實際項目開發中也是用到的最多的,那么 SpringMVC 的參數綁定是怎么實現的呢?下面我們來詳細的講解。
1、SpringMVC 參數綁定
在 SpringMVC 中,提交請求的數據是通過方法形參來接收的。從客戶端請求的 key/value 數據,經過參數綁定,將 key/value 數據綁定到 Controller 的形參上,然后在 Controller 就可以直接使用該形參。
這里涉及到參數綁定組件,那么什么是參數組件,這里可以先理解為將請求的數據轉換為我們需要的數據稱為參數綁定組件,也就是參數綁定轉換器。SpringMVC 內置了很多參數轉換器,只有在極少數情況下需要我們自定義參數轉換器。
2、默認支持的類型
SpringMVC 有支持的默認參數類型,我們直接在形參上給出這些默認類型的聲明,就能直接使用了。如下:
①、HttpServletRequest 對象
②、HttpServletResponse 對象
③、HttpSession 對象
④、Model/ModelMap 對象
Controller 代碼:
@RequestMapping("/defaultParameter") public ModelAndView defaultParameter(HttpServletRequest request,HttpServletResponse response, HttpSession session,Model model,ModelMap modelMap) throws Exception{ request.setAttribute("requestParameter", "request類型"); response.getWriter().write("response"); session.setAttribute("sessionParameter", "session類型"); //ModelMap是Model接口的一個實現類,作用是將Model數據填充到request域 //即使使用Model接口,其內部綁定還是由ModelMap來實現 model.addAttribute("modelParameter", "model類型"); modelMap.addAttribute("modelMapParameter", "modelMap類型"); ModelAndView mv = new ModelAndView(); mv.setViewName("view/success.jsp"); return mv; }
表單代碼:(截取主要代碼)
<body> request:${requestParameter} session:${sessionParameter} model:${modelParameter} modelMap:${modelMapParameter} </body>
然后訪問,頁面顯示如下:
這里我們重點說一下 Model/ModelMap,ModelMap是Model接口的一個實現類,作用是將Model數據填充到request域,即使使用Model接口,其內部綁定還是由ModelMap來實現
3、基本數據類型的綁定
哪些是基本數據類型,我們這里重新總結一下:
一、byte,占用一個字節,取值范圍為 -128-127,默認是“\u0000”,表示空 二、short,占用兩個字節,取值范圍為 -32768-32767 三、int,占用四個字節,-2147483648-2147483647 四、long,占用八個字節,對 long 型變量賦值時必須加上"L"或“l”,否則不認為是 long 型 五、float,占用四個字節,對 float 型進行賦值的時候必須加上“F”或“f”,如果不加,會產生編譯錯誤,因為系統 自動將其定義為 double 型變量。double轉換為float類型數據會損失精度。float a = 12.23產生編譯錯誤的,float a = 12是正確的 六、double,占用八個字節,對 double 型變量賦值的時候最好加上“D”或“d”,但加不加不是硬性規定 七、char,占用兩個字節,在定義字符型變量時,要用單引號括起來 八、boolean,只有兩個值“true”和“false”,默認值為false,不能用0或非0來代替,這點和C語言不同
我們以 int 類型為例:
JSP 頁面代碼:
<form action="basicData" method="post"> <input name="username" value="10" type="text"/> <input type="submit" value="提交"> </form>
Controller 代碼:
@RequestMapping("/basicData") public void basicData(int username){ System.out.println(username);//10 }
結果是 打印出了表單里面的 value 的值。
注意:表單中input的name值和Controller的參數變量名保持一致,就能完成數據綁定。那么如果不一致呢?我們使用 @RequestParam 注解來完成,如下:
JSP頁面代碼不變,<input name="username">保持原樣,Controller 代碼如下
使用注解 @RequestParam ,我們可以使用任意形參,但是注解里面的 value 屬性值要和表單的name屬性值一樣。
問題:我們這里的參數是基本數據類型,如果從前台頁面傳遞的值為 null 或者 “”的話,那么會出現數據轉換的異常,就是必須保證表單傳遞過來的數據不能為null或”",所以,在開發過程中,對可能為空的數據,最好將參數數據類型定義成包裝類型,具體參見下面的例子。
4、包裝數據類型的綁定
包裝類型如Integer、Long、Byte、Double、Float、Short,(String 類型在這也是適用的)這里我們以 Integer 為例
Controller 代碼為:
和基本數據類型基本一樣,不同之處在於,表單傳遞過來的數據可以為null或”",以上面代碼為例,如果表單中num為”"或者表單中無num這個input,那么,Controller方法參數中的num值則為null。
5、POJO(實體類)類型的綁定
User.java
package com.ys.po; import java.util.Date; public class User { private Integer id; private String username; private String sex; private Date birthday; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username == null ? null : username.trim(); } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex == null ? null : sex.trim(); } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
JSP頁面:注意輸入框的 name 屬性值和上面 POJO 實體類的屬性保持一致即可映射成功。
<form action="pojo" method="post"> 用戶id:<input type="text" name="id" value="2"></br> 用戶名:<input type="text" name="username" value="Marry"></br> 性別:<input type="text" name="sex" value="女"></br> 出生日期:<input type="text" name="birthday" value="2017-08-25"></br> <input type="submit" value="提交"> </form>
注意看:這里面我們數據都寫死了,直接提交。有Integer類型的,String類型的,Date類型的。
Controller :
@RequestMapping("/pojo") public void pojo(User user){ System.out.println(user); }
我們在上面代碼打個斷點,然后輸入URL,進入到這個Controller中:
上面是報錯了,User.java 的birthday 屬性是 Date 類型的,而我們輸入的是字符串類型,故綁定不了
那么問題來了,Date 類型的數據綁定失敗,如何解決這樣的問題呢?這就是我們前面所說的需要自定義Date類型的轉換器。
①、定義由String類型到 Date 類型的轉換器
package com.ys.util; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.core.convert.converter.Converter; //需要實現Converter接口,這里是將String類型轉換成Date類型 public class DateConverter implements Converter<String, Date> { @Override public Date convert(String source) { //實現將字符串轉成日期類型(格式是yyyy-MM-dd HH:mm:ss) SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { return dateFormat.parse(source); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } //如果參數綁定失敗返回null return null; } }
②、在 springmvc.xml 文件中配置轉換器
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <!-- 自定義轉換器的類名 --> <bean class="com.ys.util.DateConverter"></bean> </property> </bean>
輸入 URL,再次查看Controller的形參:
6、復合POJO(實體類)類型的綁定
這里我們增加一個實體類,ContactInfo.java
package com.ys.po; public class ContactInfo { private Integer id; private String tel; private String address; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel == null ? null : tel.trim(); } public String getAddress() { return address; } public void setAddress(String address) { this.address = address == null ? null : address.trim(); } }
然后在上面的User.java中增加一個屬性 private ContactInfo contactInfo
JSP 頁面:注意屬性name的命名,User.java 的復合屬性名.字段名
Controller
User對象中有ContactInfo屬性,但是,在表單代碼中,需要使用“屬性名(對象類型的屬性).屬性名”來命名input的name。
7、數組類型的綁定
需求:我們查詢出所有User 的信息,並且在JSP頁面遍歷顯示,這時候點擊提交按鈕,需要在 Controller 中獲得頁面中顯示 User 類的 id 的所有值的數組集合。
JSP 頁面:注意用戶id的name值定義為 userId
Controller.java
8、List類型的綁定
需求:批量修改 User 用戶的信息
第一步:創建 UserVo.java,封裝 List<User> 屬性
package com.ys.po; import java.util.List; public class UserVo { private List<User> userList; public List<User> getUserList() { return userList; } public void setUserList(List<User> userList) { this.userList = userList; } }
第二步:為了簡化過程,我們直接從 Controller 中查詢所有 User 信息,然后在頁面顯示
Controller
@RequestMapping("selectAllUserAndList") public ModelAndView selectAllUserAndList(){ List<User> listUser = userService.selectAllUser(); ModelAndView mv = new ModelAndView(); mv.addObject("listUser", listUser); mv.setViewName("list.jsp"); return mv; }
JSP 頁面
第三步:修改頁面的值后,點擊提交
由於我們在 JSP 頁面 input 輸入框定義的name屬性名是 userList[${status.index}].id 這種形式的,這里我們直接用 UserVo 就能獲取頁面批量提交的 User信息
8、Map類型的綁定
首先在 UserVo 里面增加一個屬性 Map<String,User> userMap
第二步:JSP頁面,注意看 <input >輸入框 name 的屬性值
第三步:Controller 中獲取頁面的屬性
9、遇到的問題
①、form表單無法提交input輸入框屬性設置為 disabled 的內容
比如:
<input type="text" disabled="disabled" name="metadataName" maxlength="50" placeholder="這里輸入模型英文名稱" title="模型英文名稱" "/>
具有 disabled="disabled" 的屬性,提交到 Controller后,metadataName 的值為null
解決辦法:改為 readonly="readonly"
readonly:針對input(text / password)和textarea有效,在設置為true的情況下,用戶可以獲得焦點,但是不能編輯,在提交表單時,輸入項會作為form的內容提交。
disabled:針對所有表單元素(select,button,input,textarea等),在設置為disabled為true的情況下,表單輸入項不能獲得焦點,用戶的所有操作無意義,在提交表單時,表單輸入項不會被提交。