你的位置:首页 > Java教程

[Java教程]springMVC参数绑定


默认支持的参数类型

处理器形参中添加如下类型的参数处理注解适配器会默认识别并进行赋值。
1 HttpServletRequest
通过request对象获取请求信息
2 HttpServletResponse
通过response处理响应信息
3 HttpSession
通过session对象得到session中存放的对象
4 Model
通过model向页面传递数据,如下:
//调用service查询商品信息
Items item = itemService.findItemById(id);
model.addAttribute("item", item);
页面通过${item.XXXX}获取item对象的属性值。
model也可以通过modelMap或map将数据传到页面(这是因为底层就是这个类型,具体可以看看底层代码)。

参数绑定介绍

         注解适配器对RequestMapping标记的方法进行适配,对方法中的形参会进行参数绑定,早期springmvc采用PropertyEditor(属性编辑器)进行参数绑定将request请求的参数绑定到方法形参上,3.X之后springmvc就开始使用Converter进行参数绑定。
 
1@RequestParam:用于绑定单个请求参数。
 
           value:参数名字,即入参的请求参数名字,如value=“item_id”表示请求的参数区中的名字为item_id的参数的值将传入;
注意:如果请求参数中没有item_id将跑出异常:HTTP Status 500 - Required Integer parameter 'item_id' is not present
          required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报;TTP Status 400 - Required Integer parameter 'XXXX' is not present
          defaultValue:默认值,表示如果请求中没有同名参数时的默认值(即使required=true也可以不传item_id参数值)
 
定义如下:
public String editItem(@RequestParam(value="item_id",required=true) String id) {
 
}
如果request请求的参数名和controller方法的形参数名称一致,适配器自动进行参数绑定(不需要手动进行绑定了)。
如果不一致可以通过@RequestParam 指定request请求的参数名绑定到哪个方法形参上。

简单类型

当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定。
整型
public String editItem(Model model,Integer id) throws Exception{

字符串
    例子略
单精度/双精度
    例子略
布尔型
    处理器方法:
    public String editItem(Model model,Integer id,Boolean status) throws Exception
请求url:
http://localhost:8080/springmvc_mybatis/item/editItem.action?id=2&status=false
说明:对于布尔类型的参数,请求的参数值为true或false。
需要注意的是,如果Controller方法参数中定义的是基本数据类型,但是从页面提交过来的数据为null或者”"的话,会出现数据转换的异常。也就是必须保证表单传递过来的数据不能为null或”",所以,在开发过程中,对可能为空的数据,最好将参数数据类型定义成包装类型,具体参见下面的例子。
 @RequestMapping("saysth.do")
public void test(Integer count) { }
}
表单代码:
<form action="saysth.do" method="post"><input name="count" value="10"type="text"/>
......
</form>
和基本数据类型基本一样,不同之处在于,表单传递过来的数据可以为null或”",以上面代码为例,如果表单中count为”"或者表单中无count这个input,那么,Controller方法参数中的count值则为null。
 


简单pojo
简单pojo类型只包括简单类型的属性。
将pojo对象中的属性名与传递进来的属性名对应,如果传进来的参数名称和对象中的属性名称一致则将参数值设置在pojo对象中。
页面定义如下;
<input type="text" name="name"/>
<input type="text" name="price"/>
Contrller方法定义如下:
@RequestMapping("/editItemSubmit")
    public String editItemSubmit(Items items)throws Exception{
    System.out.println(items);
请求的参数名称和pojo的属性名称一致,会自动将请求参数赋值给pojo的属性。

包装pojo
问题:
如果controller方法形参中有多个pojo且pojo中有重复的属性,使用简单pojo绑定无法有针对性的绑定,
比如:方法形参有items和User,pojo同时存在name属性,从http请求过程的name无法有针对性的绑定到items或user。
 
这个时候需要将pojo对象作为一个包装对象的属性,action中以该包装对象作为形参。
 
包装对象定义(包装的pojo里边包括了pojo如下:
Public class QueryVo {
private Items items;
 
}
页面定义:
<input type="text" name="items.name" />
<input type="text" name="items.price" />
Controller方法定义如下:
public String useraddsubmit(Model model,QueryVo  queryVo)throws Exception{
System.out.println(queryVo.getItems());


数组
页面定义如下:
页面选中多个checkbox向controller方法传递
<input type="checkbox" name="item_id" value="001"/>
<input type="checkbox" name="item_id" value="002"/>
<input type="checkbox" name="item_id" value="002"/>
 
传递到controller方法中的格式是:001,002,003
Controller方法中可以用String[]接收,定义如下:
public String deleteitem(String[] item_id)throws Exception{
        System.out.println(item_id);


 List绑定:
List需要绑定在对象上,而不能直接写在Controller方法的参数中。
Model代码:
public class User { 
    private String firstName; 
    private String lastName; 
}
public class UserListForm { 
    private List<User> users; 
}
Controller代码:
@RequestMapping("saysth.do") 
public void test(UserListForm userForm) { 
        for (User user : userForm.getUsers()) { System.out.println(user.getFirstName() 
System.out.println(user.getFirstName() + " - " + user.getLastName()); } }
}
}
表单代码:

<input name="users[0].firstName" value="aaa" />
<input name="users[0].lastName" value="bbb" />
<input name="users[1].firstName" value="ccc" />
<input name="users[1].lastName" value="ddd" />
在表单中需要指定List的下标。值得一提的是,Spring会创建一个以最大下标值为size的List对象,所以,如果表单中有动态添加行、删除行的情况,就需要特别注意,譬如一个表格,用户在使用过程中经过多次删除行、增加行的操作之后,下标值就会与实际大小不一致,这时候,List中的对象,只有在表单中对应有下标的那些才会有值,否则会为null,看个例子:
表单代码:

<input name="users[0].firstName" value="aaa" />
<input name="users[0].lastName" value="bbb" />
<input name="users[1].firstName" value="ccc" />
<input name="users[1].lastName" value="ddd" />
<input name="users[20].firstName" value="eee" />
<input name="users[20].lastName" value="fff" />
这个时候,Controller中的userForm.getUsers()获取到List的size为21,而且这21个User对象都不会为null,但是,第2到第19的User对象中的firstName和lastName都为null。打印结果:
aaa - bbb
ccc - ddd
null - null
null - null
......
null - null
null - null
eee - fff
 
6. Set绑定:
Set和List类似,也需要绑定在对象上,而不能直接写在Controller方法的参数中。但是,绑定Set数据时,必须先在Set对象中add相应的数量的模型对象。
Model代码:
public class User { 
 private String firstName; 
 private String lastName; 
}
public class UserSetForm { 
 private Set<User> users = new HashSet<User>(); 
}
Controller代码:
@RequestMapping("saysth.do") 
public void test(UserSetForm userForm) { 
 for (User user : userForm.getUsers()) { System.out.println(user.getFirstName() 
System.out.println(user.getFirstName() + " - " + user.getLastName()); } }
}
}
表单代码:

<input name="users[0].firstName" value="aaa" />
<input name="users[0].lastName" value="bbb" />
<input name="users[1].firstName" value="ccc" />
<input name="users[1].lastName" value="ddd" />
<input name="users[2].firstName" value="eee" />
<input name="users[2].lastName" value="fff" />
基本和List绑定类似。
需要特别提醒的是,如果最大下标值大于Set的size,则会抛出org.springframework.beans.InvalidPropertyException异常。所以,在使用时有些不便。
 
7. Map绑定:
Map最为灵活,它也需要绑定在对象上,而不能直接写在Controller方法的参数中。
Model代码:
public class User { 
 private String firstName; 
 private String lastName; 
}
public class UserMapForm { 
 private Map<String, User> users; 
}
Controller代码:
@RequestMapping("saysth.do") 
public void test(UserMapForm userForm) { 
 for (Map.Entry<String, User> entry : userForm.getUsers().entrySet()) { System.out.println(entry.getKey() 
System.out.println(entry.getKey() + ": " + entry.getValue().getFirstName() + " - " +
entry.getValue().getLastName());
}
}
表单代码:
<input name="users['x'].firstName" value="aaa" />
<input name="users['x'].lastName" value="bbb" />
<input name="users['y'].firstName" value="ccc" />
<input name="users['y'].lastName" value="ddd" />
<input name="users['z'].firstName" value="eee" />
<input name="users['z'].lastName" value="fff" />
打印结果:
x: aaa - bbb
y: ccc - ddd
z: eee - fff
 


1.1.1  自定义参数绑定
1.1.1.1 需求
根据业务需求自定义日期格式进行参数绑定。springmvc没有提供默认的对日期类型的绑定,需要自定义日期类型的绑定。
1.1.1.2 propertyEditor(了解)
1.1.1.2.1使用WebDataBinder 
在controller方法中通过@InitBinder标识方法为参数绑定方法,通过WebDataBinder注册属性编辑器,问题是此方法只能在单个controller类中注册。
/**注册属性编辑器(字符串转换为日期)*/
    @InitBinder
    public void initBinder(WebDataBinder binder) throws Exception {
       binder.registerCustomEditor(Date.classnew CustomDateEditor(newSimpleDateFormat("yyyy-MM-dd"),true));
    }
1.1.1.2.2使用WebBindingInitializer
如果想多个controller需要共同注册相同的属性编辑器,可以实现PropertyEditorRegistrar接口,并注入webBindingInitializer中。
如下:
编写CustomPropertyEditor:
 
public class CustomPropertyEditorimplements PropertyEditorRegistrar {
    public void registerCustomEditors(PropertyEditorRegistry registry) {
       registry.registerCustomEditor(Date.classnewCustomDateEditor(new
               SimpleDateFormat("yyyy-MM-dd HH-mm-ss"),true));
    }
}
 
配置如下:
 
<!-- 注册属性编辑器 -->
    <beanid="customPropertyEditor"class="cn.itcast.ssm.propertyeditor.CustomPropertyEditor"></bean> 
<!-- 自定义webBinder -->
    <bean id="customBinder"
      class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
       <property name="propertyEditorRegistrars">
           <list>
              <ref bean="customPropertyEditor"/>
           </list>
       </property>
    </bean>
<!--注解适配器 -->
    <bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="webBindingInitializer"ref="customBinder"></property> 
    </bean>
 
 Converter转换器(架构师掌握)
自定义Converter
public class CustomDateConverter implements Converter<String, Date> {
    public Date convert(String source) {
       try {
           SimpleDateFormat simpleDateFormat = newSimpleDateFormat("yyyy-MM-dd HH-mm-ss");
           return simpleDateFormat.parse(source);
       } catch (Exception e) {
           e.printStackTrace();
       }
       return null;
    }
}
配置方式1
<!--注解适配器 -->

    <!-- conversionService -->
    <bean id="conversionService"
   class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
       <!-- 转换器 -->
       <property name="converters">
           <list>
              <beanclass="cn.itcast.ssm.controller.converter.CustomDateConverter"/>
           </list>
       </property>
    </bean>
配置方式2
<mvc:annotation-driven conversion-service="conversionService">
</mvc:annotation-driven>
<!-- conversionService -->
    <bean id="conversionService"
   class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
       <!-- 转换器 -->
       <property name="converters">
           <list>
              <beanclass="cn.itcast.ssm.controller.converter.CustomDateConverter"/>
           </list>
       </property>
    </bean>