微信搜索superit|邀请体验:大数据, 数据管理、OLAP分析与可视化平台 | 赞助作者:赞助作者

springmvc中的数据绑定(前后台传递)

springmvc aide_941 41℃

springmvc中的数据绑定(前后台传递)

一:前后端数据的传递过程中肯定会涉及到数据的绑定,因为一个个参数单独接收很费事且代码效率会大大降低,下面就对各种类型的数据进行绑定。

重点:表单大量数据(多对象)的传递绑定

1、基本类型数据绑定

在controller中写一个int参数绑定的方法,

@RequestMapping("/int")
@ResponseBody
public  String getInt(int id){
    return ""+id;
}

发送请求:http://localhost:8080/int?3

响应:此时会报500错误,接收不到名为id的参数

发送请求:http://localhost:8080/int?id=3

响应:3

结论:用基本类型进行参数绑定时,就必须传入key值,且value值必须是声明的基本类型,否则将报错

2、包装类型参数绑定(推荐使用)

@RequestMapping("/integer")
@ResponseBody
public  String getInt(Integer id){
    return ""+id;
}

请求:http://localhost:8080/integer?3

http://localhost:8080/integer

http://localhost:8080/integer?id=

上面的三个请求响应都是:null

请求:http://localhost:8080/integer?id=3

响应:3

结论:包装类型绑定参数时,key的值可以不传,数据也可以为空,但是要想绑定成功绑定,传的key值要和里面绑定的参数名一致

如果想要必须传入某个参数进行绑定,可以用@RequestParam,用了这个只有所需绑定的参数必须传入,否则报错

3、数组元素绑定

@RequestMapping("/array")
@ResponseBody
public String[] getUser(String[] name){
    return  name;
}
请求:http://localhost:8080/user?name=xiaoshu&name=xiaozhang
响应:
["xiaoshu","xiaozhang"]

4、多层级对象的绑定

在user类中加入一个admin的对象属性

@RequestMapping("/user")
@ResponseBody
public User getUser(User user){
    return user;
}

请求:http://localhost:8080/user?name=xiaoshu&id=1&address=hangzhou&admin.name=xiaoli

响应{"id":1,"name":"xiaoshu","address":"hangzhou","admin":{"name":"xiaoli","address":null}}

结论:将参数绑定到对象内层对象的属性中,如这里例子中的加上admin.name
5、同属性对象参数绑定

这里有两个对象user和admin,它们有两个相同的属性name和address

public String list(User user, Admin admin) {
return user.toString()+""+admin.toString();
}

发送请求:http://localhost:8080/list?name=xiaoshu&address=home
得到:User{id=null, name='xiaoshu', address='home'}Admin{name='xiaoshu', address='home'}

发现属性被同时绑定到了两个对象上
我们可以通过在controller中配置一个@InitBinder进行分开绑定

@InitBinder("user")
public void initUser(WebDataBinder binder){
    binder.setFieldDefaultPrefix("user.");
}
@InitBinder("admin")
public void  initAdmin(WebDataBinder binder){
    binder.setFieldMarkerPrefix("admin.");

}

此时发送请求:http://localhost:8080/list?user.name=xiaoshu&user.address=home
得到:User{id=null, name='xiaoshu', address='home'}Admin{name='null', address='null'}
可以看到带user.前缀的参数只绑定到了user对象中

那如果试一下没有配置@InitBinder时用user.和admin.作为前缀进行请求发送
请求:http://localhost:8080/list?user.name=xiaoshu&user.address=home&admin.name=xiaozhang&admin.address=hangzhou
响应:User{id=null, name='null', address='null'}Admin{name='null', address='null'}
发现都是为空,参数未能成功绑定

结论:进行同属性参数绑定时,要区分绑定时需在属性前加上对象前缀,并在controller中配置@InitBinder来明确哪个前缀的属性绑定到哪个对象中
     没有配置@InitBinder加前缀不能成功绑定

6、List绑定

@RequestMapping("/list")
@ResponseBody
public AdminList getUser(AdminList adminList){
    return  adminList;
}

请求:http://localhost:8080/list?admins[0].name=xiaoshu&admins[1].name=xiaozhang
响应:

{"admins":[{"name":"xiaoshu","address":null},{"name":"xiaozhang","address":null}]}

结论:这里不能直接用List去绑定,而是要创建一个类类中创建一个List去绑定,AdminList中创建了一个ArrayList。

7、Map绑定

@RequestMapping("/map")
@ResponseBody
public AdminMap getMap(AdminMap adminMap){
    return  adminMap;
}

AdminMap中维护了一个Hashmap

请求:http://localhost:8080/map?admins[‘X’].name=xiaoshu&admins[‘Y’].name=xiaozhang
响应:

{"admins":{"Y":{"name":"xiaozhang","address":null},"X":{"name":"xiaoshu","address":null}}}

结论:map存放可以保证key的唯一性,过滤冲重复数据8.重点介绍表单多对象传递的绑定(特别是多对象的属性名相同的情况):

问题出现

要在一张表单中提交多个对象,并且还要在后台Controller 中精准的绑定接收。可是,这些对象中的参数名可能相同,后台接收入参时无法像struts那样jsp表单中使用Object.Param形式对表单进行精准绑定入参,我们都知道struts2默认就是这种方案,这是因为struts2采用了OGNL,并通过栈(根对象)进行操作的,而且栈中默认有action实例,所以很自然的没有这种问题。另一方面说,Struts用这种方式绑定入参,却牺牲了性能。虽然springmvc不能像struts那样方便的很直接的入参绑定,当然,spring多对象绑定入参也提供了方法。

今天就以前台表单提交两个对象做实例。为了扩大影响,我让这两个对象的属性相同。

User.Java 和Addr.java

 

  1. public class User implements Serializable{  
  2. String id;
  3. String name;
  4. //get..set….  
  5. }
  6. public class Addr implements Serializable{  
  7. String id;
  8. String name;//set..get…  
  9. }

前台JSP

[html] view plain copy

  1. <form action=“/test/test” method=”post”>  
  2.    <input type=“text” name=”user.id” value=”huo_user_id”>  
  3.    <input type=“text” name=”user.name” value=”huo_user_name”>  
  4.    <input type=“text” name=”addr.id” value=”huo_addr_id”>  
  5.    <input type=“text” name=”addr.name” value=”huo_addr_name”>  
  6.    <input type=“submit” value=”提交”>  
  7. </form>  

若字段过多或者一个属性字段供几个对象使用,则需要前端组装处理:

$(“#submitForm”).attr(“action”, basePath + “xtapply/submitApplyASD?” + new Date().getTime())
.append($(“<input>”).attr(“name”, “creditProductId”).val(“${product.creditProductId}”).hide())
.append($(“<input>”).attr(“name”, “productName”).val(“${product.productName}”).hide())
.append($(“<input>”).attr(“name”, “bankName”).val(“${product.bankName}”).hide())
.append($(“<input>”).attr(“name”, “xtFddbr.identyNoCounty”).val($(“#identyArea option:selected”).text()).hide())
.append($(“<input>”).attr(“name”, “xtQyxx.companyBusinessProvince”).val($(“#qyProvince option:selected”).text()).hide())
.append($(“<input>”).attr(“name”, “xtQyxx.companyBusinessCity”).val($(“#qyCity option:selected”).text()).hide())
.append($(“<input>”).attr(“name”, “xtQyxx.companyBusinessCounty”).val($(“#qyArea option:selected”).text()).hide());
$(“#submitForm”).submit();
看到这种情况,很容易想到struts进行绑定非常方便,可是,谁让我们要使用SpringMVC呢。。。这种情况springMVC直接进行入参,是不能接收到参数的。

 解决思路

使用 @InitBinder 注解进行绑定参数。前台表单中name属性仍然使用Object.Param形式传入。(另一种解决思路:扩展spring的HandlerMethodArgumentResolver以支持自定义的数据绑定方式。)

 

[html] view plain copy

  1. @InitBinder(“user”)
  2.     public void initBinderUser(WebDataBinder binder) {
  3.         binder.setFieldDefaultPrefix(“user.”);
  4.     }

此处使用@InitBinder() 中间的value,用于指定命令/表单属性或请求参数的名字,符合该名字的将使用此处的DataBinder,如我们的@ModelAttribute(“user1”) User user1 将使用@InitBinder(“user1″)指定的DataBinder绑定;如果不指定value值,那么所有的都将使用。

DataBinder.setFieldDefaultPrefix 意思是设置参数的前缀,如我们的是”user1.”,此处不能少了”.”,

这种方式的缺点:

1、不支持Path variable的绑定,如/test1/{user1.id}这种情况的绑定;

2、不支持如集合/数组的绑定;

后台接收 完整代码

 

[java] view plain copy

  1. @Controller  
  2. @RequestMapping(“/test”)  
  3. public class TestController {  
  4. // 绑定变量名字和属性,参数封装进类  
  5.     @InitBinder(“user”)  
  6.     public void initBinderUser(WebDataBinder binder) {  
  7.         binder.setFieldDefaultPrefix(“user.”);  
  8.     }
  9.     // 绑定变量名字和属性,参数封装进类  
  10.     @InitBinder(“addr”)  
  11.     public void initBinderAddr(WebDataBinder binder) {  
  12.         binder.setFieldDefaultPrefix(“addr.”);  
  13.     }
  14.     @RequestMapping(“/test”)  
  15.     @ResponseBody  
  16.     public Map<String,Object> test(HttpServletRequest request,@ModelAttribute(“user”) User user,@ModelAttribute(“addr”) Addr addr){  
  17.         Map<String,Object> map=new HashMap<String,Object>();  
  18.         map.put(“user”, user);  
  19.         map.put(“addr”, addr);  
  20.         return map;  
  21.     }

②第二种方式:上面针对jsp页面表单提交前后台处理方法,若是有保存需求,因为提交后台数据的组装方式变化,在ajax中以data形式请求,则需要使用自定义的反序列化对象来实现;

var params = decodeURIComponent(
$(“#submitForm”)
.append($(“<input>”).attr(“name”, “applyId”).val($(“#applyId”).val()).hide())
.append($(“<input>”).attr(“name”, “creditProductId”).val($(“#creditProductId”).val()).hide())
.append($(“<input>”).attr(“name”, “productName”).val($(“#productName”).val()).hide())
.append($(“<input>”).attr(“name”, “bankName”).val($(“#bankName”).val()).hide())
.append($(“<input>”).attr(“name”, “xtFddbr.identyNoProvince”).val($(“#identyProvince option:selected”).text()).hide())
.append($(“<input>”).attr(“name”, “xtFddbr.identyNoCity”).val($(“#identyCity option:selected”).text()).hide())
.append($(“<input>”).attr(“name”, “xtFddbr.identyNoCounty”).val($(“#identyArea option:selected”).text()).hide())
.append($(“<input>”).attr(“name”, “xtQyxx.companyBusinessProvince”).val($(“#qyProvince option:selected”).text()).hide())
.append($(“<input>”).attr(“name”, “xtQyxx.companyBusinessCity”).val($(“#qyCity option:selected”).text()).hide())
.append($(“<input>”).attr(“name”, “xtQyxx.companyBusinessCounty”).val($(“#qyArea option:selected”).text()).hide())
.serialize().replace(/\+/g,” “)
);

ajax中data组装:

msg:util.formToJson(params)//util.formToJson(decodeURIComponent($(“#submitForm”).serialize().replace(/\+/g,” “)))

后台处理:

调用工具类将json字符串安装自定义的反序列化格式转化为对象(XtyhApplyDeserializer为自定义的反序列化对象

xtApply = jsonUtil.jsonStr2ObjectByCustom(msg, XtApply.class, new XtyhApplyDeserializer());

如上所示为一个完整的自定义反序列化类,在Controller中接收时处理如下:

注:由此完成了提交与保存两个按钮的数据保存工作(两种处理方式),保存则用到自定义的反序列化类类实现。

另外可以通过DataBinder完成如下几件事情:

1、binder.setAllowedFields(“id”)  : 设置允许的字段,比如我只想设置id,那么可以调用这个方法,那么其他属性会忽略;

2、binder.setDisallowedFields(“id”) : 设置不允许的自动,比如我不想设置id,那么可以调用此方法,这个属性将不设置;

3、binder.setRequiredFields() : 表示哪些字段是必填的;

4、binder.setValidator() :设置自定义的验证器,如果如JSR-303不适合,可以使用这个。

注意:1.如果多个对象的属性相同,且没有指定前缀的话,会都匹配或者出错;

转载请注明:SuperIT » springmvc中的数据绑定(前后台传递)

喜欢 (0)or分享 (0)