引用百度的數據綁定定義:
簡單綁定是將一個用戶界面元素(控件)的屬性綁定到一個類型(對象)實例上的某個屬性的方法。例如,若是一個開發者有一個Customer類型的實例,那麼他就能夠把Customer的「Name」屬性綁定到一個TextBox的「Text」屬性上。「綁定」了這2個屬性以後,對TextBox的Text屬性的更改將「傳播」到Customer的Name屬性,而對Customer的Name屬性的更改一樣會「傳播」到TextBox的Text屬性。javascript
SpringMVC的各類參數包括對象java對象,集合,Map以及基本數據類型的綁定方式html
基本類型的數據綁定須要注意的是:後臺請求方法中聲明的參數前臺是必需傳的,其次是類型必須相同java
controller類:web
@Controller public class DataBind { // http://localhost:8080/dataBind/test.do?age=11 @RequestMapping("/test") public String test(int age){ System.out.println(age); return "success"; } }
form表單ajax
<form action="test.do" method="post"> <input name="age" value="11" type="text"/> ...... </form>
注意:
1.參數名一致:表單中input的name值和Controller的參數變量名保持一致 ,就能完成基本數據類型的數據綁定. spring
2.參數類型一致:若是在後臺參數定義的是int類型,那麼前臺傳的值也只能是int類型不然springMVC會進行攔截報一個400參數錯誤(數據轉換的異常)json
3.參數不能爲空:從jsp提交過來的數據爲null或者""的話,會出現500異常。也就是說,必須保證表單傳遞過來的數據不能爲null或"".數組
對於以上問題能夠採用@RequestParam註解來解決spring-mvc
@Controller public class DataBind { // @RequestMapping("/test") public String test(@RequestParam(value ="age" ,required = false) int userAge){ System.out.println(userAge); return "success"; } }
@RequestParam(value ="name" ,required = false) value值是參數別名與表單一致,required 默認值true爲必傳.mvc
controller類:
@RequestMapping("/test3") public String test3(Integer age){ System.out.println(age); }
form表單:
<form action="test.do" method="post"> <input name="age" value="10" type="text"/> ...... </form>
和基本數據類型基本同樣,不一樣之處在於,JSP表單傳遞過來的數據能夠爲null或"",以上面代碼爲例,若是jsp中num爲""或者表單中無age這個input,那麼,Controller方法參數中的num值則爲null。
1. 簡單POJO類對象:
public class User { private String firstName; private String lastName; //省略get&set ... }
controller類
@RequestMapping("/test4") public String test4(User user){ System.out.println(user); return "success"; }
form表單
<form action="test.do" method="post"> <input name="firstName" value="張" type="text"/> <input name="lastName" value="三" type="text"/> ...... </form>
簡單對象:請求方式的參數Key即爲對象屬性名,不用加「對象名.」的前綴
2.多層對象
POJO對象
public class ContactInfo { private String tel; private String address; //。。。省略get&set } public class User { private String firstName; private String lastName; private ContactInfo contactInfo; // 。。。 省略get&set
controller類和簡單對象沒有什麼區別,參數類型都是User(pojo類型對象)
form表單
<form action="<%=basePath%>test5.do" method="get"> 姓:<input name="firstName"/> 名:<input name="lastName"/> 地址:<input name="contactInfo.address"/> ... </form>
多層級對象:第二級以上對象必須加「對象名.」的前綴。
同屬性的多對象 在control中聲明@initBinder的WebDataBinder的前綴
當兩個對象含有相同屬性時,爲了精確的匹配綁定一種方法是經過命名的規範去規避,另外一中解決辦法使用@InitBinder對請求參數加前綴
java代碼
@Controller public class dataBind{ @InitBinder("teacher") public void initBinder1(WebDataBinder binder){ binder.setFieldDefaultPrefix("teacher."); } @InitBinder("student") public void initBinder2(WebDataBinder binder){ binder.setFieldDefaultPrefix("student."); } //URL映射 @RequestMapping(value="/save", method = RequestMethod.GET) public ModelAndView save(Teacher teacher,Student student) { System.out.println(teacher.getName()+" "+student.getName()); return null; }
注意:當save的參數名與對象名不一致(即參數名不爲類名的小寫)時,須要在參數前加@ModelAttribute()註解,同時保證@InitBinder的value值與@ModelAttribute的value值一致,若是不指定value值,那麼全部的都將使用。
這種方式的缺點:
一、不支持Path variable的綁定,如/test1/{user1.id}這種狀況的綁定;
二、不支持如集合/數組的綁定;
@InitBinder("user1") public void initUser(WebDataBinder binder){ binder.setFieldDefaultPrefix("user."); } @InitBinder("student1") public void initStudent(WebDataBinder binder){ binder.setFieldDefaultPrefix("student."); } @RequestMapping("/test6") public String test6(@ModelAttribute("student1")Student a,@ModelAttribute("user1")User b){ System.out.println(a); System.out.println(b); return "success"; }
springMVC 不支持list類型的直接轉換,需包裝成object。
public class User { private String firstName; private String lastName; // 。。。 省略get&set } public class UserListForm { private List<User> users; // 。。。 省略get&set }
@RequestMapping("test") public void test(UserListForm userForm) { for (User user : userForm.getUsers()) { System.out.println(user.getFirstName() + " - " + user.getLastName()); } }
form表單
<form action="test.do" method="post"> <table> <thead> <tr> <th>First Name</th> <th>Last Name</th> </tr> </thead> <tfoot> <tr> <td colspan="2"><input type="submit" value="Save" /></td> </tr> </tfoot> <tbody> <tr> <td><input name="users[0].firstName" value="aaa" /></td> <td><input name="users[0].lastName" value="bbb" /></td> </tr> <tr> <td><input name="users[1].firstName" value="ccc" /></td> <td><input name="users[1].lastName" value="ddd" /></td> </tr> <tr> <td><input name="users[2].firstName" value="eee" /></td> <td><input name="users[2].lastName" value="fff" /></td> </tr> </tbody> </table> </form>
這裏的UserListForm對象裏面的屬性被定義成List,而不是普通自定義對象。因此,在JSP中須要指定List的下標。值得一提的是,Spring會建立一個以最大下標值爲size的List對象,因此,若是JSP表單中有動態添加行、刪除行的狀況,就須要特別注意,譬如一個表格,用戶在使用過程當中通過屢次刪除行、增長行的操做以後,下標值就會與實際大小不一致,這時候,List中的對象,只有在jsp表單中對應有下標的那些纔會有值,不然會爲null.
list集合綁定的時候 下標最好是連續的 不然可能形成後臺資源浪費
Set和List相似,也須要綁定在對象上,而不能直接寫在Controller方法的參數中。可是,綁定Set數據時,必須先在Set對象中add相應的數量的,即Set綁定時需初始化
public class User { private String firstName; private String lastName; //...省略set&get } public class UserSetForm { private Set<User> users = new HashSet<User>(); public UserSetForm(){ users.add(new User()); users.add(new User()); users.add(new User()); } //...省略set&get }
要使用Set的排重功能必須在對象中覆寫hashcode和equals方法,至於爲何要重寫hashcode和equals方法可參見:http://www.javashuo.com/article/p-drelupuc-hb.html
<form action="test.do" method="post"> <table> <thead> <tr> <th>First Name</th> <th>Last Name</th> </tr> </thead> <tfoot> <tr> <td colspan="2"><input type="submit" value="Save" /></td> </tr> </tfoot> <tbody> <tr> <td><input name="users[0].firstName" value="aaa" /></td> <td><input name="users[0].lastName" value="bbb" /></td> </tr> <tr> <td><input name="users[1].firstName" value="ccc" /></td> <td><input name="users[1].lastName" value="ddd" /></td> </tr> <tr> <td><input name="users[2].firstName" value="eee" /></td> <td><input name="users[2].lastName" value="fff" /></td> </tr> </tbody> </table> </form>
基本和List綁定相似。
要特別提醒的是,若是最大下標值大於Set的size,則會拋出org.springframework.beans.InvalidPropertyException異常
spingMVC在對集合進行綁定時,優先選擇List
Map類型的數據綁定也能用在對象的去重,由於Map的key值是惟一的.
public class User { private String firstName; private String lastName; 。。。 } public class UserMapForm { private Map<String, User> users; 。。。 } @RequestMapping("test") public void test(UserMapForm userForm) { for (Map.Entry<String, User> entry : userForm.getUsers().entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue().getFirstName() + " - " + entry.getValue().getLastName()); } }
<form action="test.do" method="post"> <table> <thead> <tr> <th>First Name</th> <th>Last Name</th> </tr> </thead> <tfoot> <tr> <td colspan="2"><input type="submit" value="Save" /></td> </tr> </tfoot> <tbody> <tr> <td><input name="users['x'].firstName" value="aaa" /></td> <td><input name="users['x'].lastName" value="bbb" /></td> </tr> <tr> <td><input name="users['y'].firstName" value="ccc" /></td> <td><input name="users['y'].lastName" value="ddd" /></td> </tr> <tr> <td><input name="users['z'].firstName" value="eee" /></td> <td><input name="users['z'].lastName" value="fff" /></td> </tr> </tbody> </table> </form>
x即爲Map的key,firstName即爲User對象的屬相
@RequestBody把傳過來的Json數據反序列化綁定到控制器參數上
對於JOSN類型的參數綁定通常應用的場景是在使用AJax請求.而在SpringMVC環境中,@RequestBody接收的是一個Json對象的字符串,而不是一個Json對象.能夠用 JSON.stringify(data)的方式就能將對象變成字符串。同時ajax請求的時候也要指定dataType: "json",contentType:"application/json" 這樣就能夠輕易的將一個對象或者List傳到Java端,使用@RequestBody便可綁定對象或者List.
JavaScript 代碼:
<script type="text/javascript"> $(document).ready(function(){ var saveDataAry=[]; var data1={"userName":"test","address":"gz"}; var data2={"userName":"ququ","address":"gr"}; saveDataAry.push(data1); saveDataAry.push(data2); $.ajax({ type:"POST", url:"user/saveUser", dataType:"json", contentType:"application/json", data:JSON.stringify(saveData), success:function(data){ //...tosomething } }); }); </script>
controller方法:
@RequestMapping(value = "test", method = {RequestMethod.POST }}) @ResponseBody public void saveUser(@RequestBody List<User> users) { userService.batchSave(users); }
1.SpingMVC對象Xml類型的數據綁定須要spring-oxm jar包支持.一樣也是@RequestBody把傳過來的Xml數據反序列化綁定到控制器參數上
2.xml 數據綁定:必須在實體類裏面加註解@XmlRootElement(根節點),在屬性上添加XmlElement (子節點)ex:@XmlElement(name="age"):此時就會將xml 裏面對應的age數據添加到實體類中的age屬性中去。
model對象的處理:
@XmlRootElement(name="admin")//根節點別名 public class Admin { private String name; private String age; @XmlElement(name="name")//在get方法在夾@XmlElement 子節點別名 public String getName() { return name; } public void setName(String name) { this.name = name; } @XmlElement(name ="age") public String getAge() { return age; } public void setAge(String age) { this.age = age; } }
xml數據
<? version="1.0" encoding="utf-8" ?> <admin> <name>張三</name> <age>22</age> </admin>
先來看Sun提供的PropertyEditor屬性編輯器
PropertyEditor是java提供的屬性編輯器接口,PropertyEditorSupport是直接實現類,一般都是繼承該實現類並重寫setAsText(String) 方法,實現從String類型到自定類型的裝換.
spring中也有繼承了PropertyEditorSupport並重寫了setAsText的自定義的屬相編輯器,都在spring-beans包下的org.springframework.beans.propertyeditors包裏:
在SpringMVC中主要是WebDataBinder實現對數據的轉換
PropertyEditorRegistyr封裝方法來給JavaBean註冊對應的屬性編輯器。
實現方式代碼;
/** * 在controller層中加入一段數據綁定代碼 * @param webDataBinder */ @InitBinder public void initBinder(WebDataBinder webDataBinder) throws Exception{ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm"); simpleDateFormat.setLenient(false); webDataBinder.registerCustomEditor(Date.class , new CustomDateEditor(simpleDateFormat , true)); //CustomDateEditor是spring提供的繼承PropertyEditorSupport的類,也能夠換成自定義的MyCustomPropertyEditor類 } //備註:自定義類型轉換器必須實現PropertyEditor接口或者繼承PropertyEditorSupport類 MyCustomPropertyEditor extends propertyEditorSupport{ public void setAsText(String text){ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy -MM-dd hh:mm"); Date date = simpleDateFormat.parse(text); this.setValue(date); } public String getAsTest(){ Date date = (Date)this.getValue(); return this.dateFormat.format(date); } }
這種使用Property屬性編輯器的方法須要在controller層加一段數據綁定的代碼,不夠靈活,不具備全局性
要使用全局的數據轉換器,在Spring 3.0後可使用Converter和Formatter,都是用來作數據轉換的
Formatter繼承了Printer和Parser接口
public interface Formatter<T> extends Printer<T>, Parser<T> { }
Printer用來打印轉換後的對象
public interface Printer<T> { /** * Print the object of type T for display. * @param object the instance to print * @param locale the current user locale * @return the printed text string */ String print(T object, Locale locale); }
,Parser用來從String類型轉換爲指定類型值
public interface Parser<T> { /** * Parse a text String to produce a T. * @param text the text string * @param locale the current user locale * @return an instance of T * @throws ParseException when a parse exception occurs in a java.text parsing library * @throws IllegalArgumentException when a parse exception occurs */ T parse(String text, Locale locale) throws ParseException; }
從方法上,能夠看分出Formatter是從String類型轉換爲任意目標類型<T>,有點相似PropertyEditor
代碼實現:
public class MyDateFormatter implements Formatter<Date> { @Override public String print(Date object, Locale locale) { return null; } //只需重寫parse方法 實現類型轉換爲目標類型<T> @Override public Date parse(String text, Locale locale) throws ParseException { return new SimpleDateFormat("yyyy-MM-dd").parse(text); } }
在spring-mvc.xml的配置文件中須要註冊自定義的轉換器實現全局轉換
<mvc:annotation-driven conversion-service="MyDateFormatter"/> <bean id="MyDateFormatter" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="formatters"> <set> <bean class="com.chuyu.ssm.controller.MyDateFormatter"/> </set> </property> </bean>
雖然這個方法能夠實現全局的數據轉換,可是支持的類型也只能是從String類型轉換爲任意目標類型<T>.
public interface Converter<S, T> { /** * Convert the source object of type {@code S} to target type {@code T}. * @param source the source object to convert, which must be an instance of {@code S} (never {@code null}) * @return the converted object, which must be an instance of {@code T} (potentially {@code null}) * @throws IllegalArgumentException if the source cannot be converted to the desired target type */ T convert(S source); }
從源碼能夠看出去,Converter接口能夠從任意源類型,轉換爲任意目標類型
代碼實現:
package com.chuyu.ssm.controller; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.core.convert.converter.Converter; /** * 全局類型轉換器 * @author acer * */ public class DateConvert implements Converter<String, Date>{ @Override public Date convert(String text) { Date date = null; try { if(text.contains("-")){ SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd"); date = sf.parse(text); }else { SimpleDateFormat sf = new SimpleDateFormat("dd/MM/yyyy"); date = sf.parse(text); } } catch (ParseException e) { e.printStackTrace(); } return date; } }
類型轉換器須要在配置文件中配置:
<!--開啓註解 --> <mvc:annotation-driven conversion-service="MyDataConverterService" /> <!--類型轉換器工廠 --> <bean id="MyDataConverterService" class="org.springframework.context.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="com.cy.springannotation.controller.DateConvert" /> </list> </property> </bean>