Spring MVC's data binding
Binding data is bound to one characteristic of the user input field model.
Http request data transmitted to a String, through data binding, data may be filled with different types of object properties.
The basic type binding
@RequestMapping("/int")
@ResponseBody
public String bindInt (int i) {
return "bindInt:" + i;
}
Request:? / Int i = 10
in response to: bindInt: 3
Bad request: / int or / int 2?
Error Code: 500
When the basic types of data binding, it must pass key
and value
.
Package Type Bind
@RequestMapping("/integer")
@ResponseBody
public String bindInteger (Integer i) {
return "bindInteger:" + i;
}
Request:? / Integer i = 5
in response to: bindInteger: 5
请求:/integer or /integer?5 or /integer?i or /integer?i=
响应:bindInteger:null
The type of packaging data binding, key
and value
can be empty.
If the required parameters must be passed, it can be added @RequestParam
.
@RequestMapping("/integer")
@ResponseBody
public String bindInteger (@RequestParam Integer i) {
return "bindInteger:" + i;
}
Bad request: / integer or / integer 5?
Error Code: 400
Request:?? / Integer i or / integer i =
response: bindInteger: null
Array bind
@RequestMapping("/array")
@ResponseBody
public String bindArray (String[] strs) {
StringBuilder sb = new StringBuilder();
sb.append("bindArray:");
for (String str : strs)
sb.append(str + " ");
return sb.toString();
}
Request:? / Array strs = str1 & strs = str2
response: bindArray: str1 str2
Simple Object bind
@RequestMapping("/user")
@ResponseBody
public String bindUser (User user) {
return "bindUser:" + user.toString();
}
public class User {
private String name;
private Integer age;
// getters and setters
// toString
}
Request:? / User name = Tom & age = 15
Response: bindUser: User [name = Tom , age = 15]
Multi-level object bound
public class User {
private String name;
private Integer age;
private ContactInfo info;
// getters and setters
// toString
}
public class ContactInfo {
private String phone;
private String address;
// getters and setters
// toString
}
Request:? / User name = Tom & info.phone = 123456
response: bindUser: User [name = Tom , age = null, info = ContactInfo [phone = 123456, address = null]]
With multi-object binding properties
@RequestMapping("/userandadmin")
@ResponseBody
public String bindUserAndAdmin (User user, Admin admin) {
return "bindUserAndAdmin:\n" + user.toString() + "\n" + admin.toString();
}
public class Admin {
private String name;
private Integer age;
// getters and setters
// toString
}
Request: / userandadmin name = Tom & age = 15?
Response:
bindUserAndAdmin:
the User [name = Tom, Age = 15]
the Admin [name = Tom, Age = 15]
While the data is bound to the two objects have the same properties.
Solution:
@InitBinder("user")
public void initUser(WebDataBinder binder) {
binder.setFieldDefaultPrefix("user.");
}
@InitBinder("admin")
public void initAdmin(WebDataBinder binder) {
binder.setFieldDefaultPrefix("admin.");
}
Request:? / Userandadmin user.name = Tom & age = 15 & admin.name = Jack
response:
bindUserAndAdmin:
the User [name = Tom, Age = 15]
the Admin [name = Jack, Age = 15]
InitBinder
In the role of the controller, the controller first call into the InitBinder
call back RequestMapping
method.
Not configured InitBinder
prefix invalid and can not successfully bind.
WebDataBinder
Parameter used to bind to a specific request JavaBean
.
List Binding
@RequestMapping("/stringlist")
@ResponseBody
public String bindStringList (@RequestParam("name") List<String> strs) {
return "bindStringList:" + strs.toString();
}
Request: / stringlist name = Tom & name = Jack?
Response: bindStringList: [Tom, Jack]
@RequestMapping("/userlist")
@ResponseBody
public String bindUserList(UserListForm userListForm){
return "bindUserList:\n" + usersModel.toString();
}
public class UserListForm {
private List<User> list;
// getters and setters
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (User u : users)
sb.append(u.toString() + "\n");
return sb.toString();
}
}
请求:/userlist?users[0].name=Tom&users[2].name=Jack
响应:
bindList:
User [name=Tom, age=null]
User [name=null, age=null]
User [name=Jack, age=null]
PS: High version of the tomcat [
need to escape %5B
, ]
need to escape to%5D
Set Binding
Set the List Binding basically the same, but in use Set<User>
, the need to initialize the Set capacity.
public class UserSetForm {
private Set<User> users;
private UserSetForm () {
// 设置 set 容量为 2 不能访问 size 外的对象
// 如果覆盖了 User 的 equals 和 hashcode 方法 则 set 容量为 1
users = new HashSet<User>();
users.add(new User());
users.add(new User());
System.out.println(users.size());
}
// getters and setters
// toString
}
// User.java
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
Request:? / Userset users [0] .name = Tom
response:
bindUserSet:
the User [name = Tom, Age = null]
Error Request:? / Userset users [0] .name = Tom & users [1] .name = Jack
Error Code: 500
Error Description: Can not get element with index 1 from Set of size 1, accessed using property path 'users [1]'
Map bindings
@RequestMapping("/usermap")
@ResponseBody
public String bindUserMap (UserMapForm userMapForm) {
return "bindUserMap:\n" + userMapForm.toString();
}
public class UserMapForm {
private Map<String, User> users;
// getters and setters
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (String s : users.keySet())
sb.append("Users[" + s + "] = " + users.get(s) + "\n");
return sb.toString();
}
}
请求:/usermap?users[x].name=Tom&users[y].name=Jack
响应:
bindUserMap:
Users[x] = User [name=Tom, age=null]
Users[y] = User [name=Jack, age=null]
JSON binding
@RequestMapping("/userjson")
@ResponseBody
public String bindUserJson (@RequestBody User user) {
return "bindUserJson:" + user.toString();
}
请求:
Content-Type:application/json
Body:
{
"name":"Tom",
"age":15
}
Response: bindUserJson: User [name = Tom , age = 15]
dependency: jackson-databind
XML Binding
@RequestMapping("/userxml")
@ResponseBody
public String bindUserXml (@RequestBody User user) {
return "bindUserXml:" + user.toString();
}
@XmlRootElement(name="user")
public class User {
private String name;
private Integer age;
@XmlElement(name="name")
public String getName() {
return name;
}
@XmlElement(name="age")
public Integer getAge() {
return age;
}
// setters
// toString
}
Request:
the Content-the Type: file application / XML
Body:
<user>
<name>Tom</name>
<age>15</age>
</user>
Response: bindUserXml: User [name = Tom , age = 15]
dependency: jaxb-api jaxb-impl spring -oxm
PropertyEditor
public interface PropertyEditor {
void setValue(Object value);
Object getValue();
String getAsText();
void setAsText(String text) throws java.lang.IllegalArgumentException;
// ...
}
Use: general use of the built or inherited PropertyEditorSupport(implements PropertyEditor)
, with the WebDataBinder
topical use.
@RequestMapping("/datepe")
@ResponseBody
public String bindDateByPropertyEditor (Date date1) {
return date1.toString();
}
@InitBinder("date1")
public void initDate (WebDataBinder binder) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
Request:? / Datepe date1 = 2019-11-11
Response: Mon Nov 11 00:00:00 CST 2019
Formatter
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
public interface Printer<T> {
String print(T object, Locale locale);
}
public interface Parser<T> {
T parse(String text, Locale locale) throws ParseException;
}
Use: Source type String, can be global or local use.
@RequestMapping("/dateformatter")
@ResponseBody
public String bindDateByFormatter (Date date2) {
return date2.toString();
}
<mvc:annotation-driven conversion-service="formatter"/>
<!-- conversion-service 与 id 对应 -->
<bean id="formatter" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="org.springframework.format.datetime.DateFormatter">
<constructor-arg name="pattern" value="yyyy-MM-dd" />
</bean>
</set>
</property>
</bean>
Request:? / Dateformatter date2 = 2019-12-12
Response: Thu Dec 12 00:00:00 CST 2019
Converter
public interface Converter<S, T> {
@Nullable
T convert(S source);
}
Use: Built implemented as a final class, not extensible, customizable source type and destination type, global or local use.
@RequestMapping("/dateconverter")
@ResponseBody
public String bindDateByConverter (Date date3) {
return date3.toString();
}
public class DateConverter implements Converter<String, Date> {
public Date convert(String source) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
return format.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
<mvc:annotation-driven conversion-service="converter"/>
<!-- 自定义 Converter 类 -->
<bean id="converter" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="common.DateConverter" />
</set>
</property>
</bean>
Request:? / Dateconverter date3 = 2019-10-24
Response: Thu Oct 24 00:00:00 CST 2019
Reference: SpringMVC data binding entry