您的位置:首页 > 编程语言 > Java开发

spring3mvc如何把checkbox的值绑定到model对象的int数据类型

2011-12-04 12:08 567 查看
model对象:User.java:


public class User {
	private int id;
	private String name;
	//0:男,1:女,页面上表现为radiobutton
	private int gender;
	private int age;
	//0:没毕业,1:已经毕业,页面上表现为checkbox
	private int graduted;
	//0:没结婚,1:已经结婚,页面上表现为checkbox
	private int married;
}


form表单:

<form:form id="user" modelAttribute="user" action="save.do">

<table>

<tr><td>用户名:</td><td><form:input path="name" /></td></tr>

<tr><td>性别:</td><td>男:<form:radiobutton path="gender" value="0"/>

女:<form:radiobutton path="gender" value="1"/></td>

</tr>

<tr><td>年龄:</td><td><form:input path="age" /></td></tr>

<!-- Attribute 'value' is required when binding to non-boolean values -->

<tr><td>其他:</td><td>毕业:<form:checkbox path="graduted" value="1"/>婚否:<form:checkbox path="married" value="1"/></td>

</tr>

<tr><td colspan="2"><input type="submit" value="提交"></td></tr>

</table>

</form:form>

UserController:
@Controller
@RequestMapping("/user")
public class UserController{
 private static class IntEditor extends CustomNumberEditor{
  public IntEditor(){
   super(Integer.class,true);
  }
  public void setAsText(String text) throws IllegalArgumentException { 
   if (text==null || text.trim().equals("")) { 
      // Treat empty String as null value. 
      setValue(0); 
   } else { 
      // Use default valueOf methods for parsing text. 
      setValue(Integer.parseInt(text)); 
   } 
  }
 }
 @InitBinder
 public void initBinder(WebDataBinder binder){
  binder.registerCustomEditor(int.class, null, new IntEditor());
 }
 @RequestMapping(value="/add")
 public ModelAndView add(HttpServletRequest request){
  ModelAndView mav = new ModelAndView("useradd");
  //Neither BindingResult nor plain target object for bean name 'user' available as request attribute
  mav.addObject("user", new User());
  return mav;
 }
 @RequestMapping(value="/save")
 public ModelAndView save(HttpServletRequest request,
   @ModelAttribute("user") User user){
  ModelAndView mav = new ModelAndView("redirect:list.do");
  System.out.println(user);
  return mav;
 }
}

浏览器输入:http://localhost:8080/sp3form/user/add.do,会弹出输入页面,如果,两个checkbox都不选中,然后,提交的时候,会报错:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors

Field error in object 'user' on field 'graduted': rejected value [null]; codes [typeMismatch.user.graduted,typeMismatch.graduted,typeMismatch.int,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.graduted,graduted];
arguments []; default message [graduted]]; default message [Failed to convert property value of type 'null' to required type 'int' for property 'graduted'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [null] to required
type [int] for property 'graduted': PropertyEditor [org.springframework.beans.propertyeditors.CustomNumberEditor] returned inappropriate value]

Field error in object 'user' on field 'married': rejected value [null]; codes [typeMismatch.user.married,typeMismatch.married,typeMismatch.int,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.married,married];
arguments []; default message [married]]; default message [Failed to convert property value of type 'null' to required type 'int' for property 'married'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [null] to required
type [int] for property 'married': PropertyEditor [org.springframework.beans.propertyeditors.CustomNumberEditor] returned inappropriate value]

org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:863)

具体的来说就是:null无法转化成int。



然后,上网一通google,基本上是两种解决办法:

(1)使用Integer,而不是int,null不能转化成int,但是可以转化成为Integer。这么做转化虽然没问题,但是,如果把model对象插入到数据库的时候还得把null改成0,麻烦!

(2)添加一个InitBinder,重写setAsText()方法,如同上面的代码那样,可仍然报错!一开始怀疑是setAsText方法没被调用,但是debug的时候发现,有两个值确实调用了setAsText,但是checkbox却并没有调用。也就是说,在setAsText之前就已经出错了!

大家都是你抄我来我抄你,没有一个能解决问题,所谓靠墙墙倒,靠人人跑,本来想偷点懒的,关键时候还得靠自己啊!

然后,就开始debug,看看源码里面是如何处理的。最开始找到的解决办法是重写WebDataBinder里面的getEmptyValue方法:

protected Object getEmptyValue(String field, Class fieldType) {
	if (fieldType != null && boolean.class.equals(fieldType) || Boolean.class.equals(fieldType)) {
		// Special handling of boolean property.
		return Boolean.FALSE;
	}
	else if (fieldType != null && fieldType.isArray()) {
		// Special handling of array property.
		return Array.newInstance(fieldType.getComponentType(), 0);
	}else if(fieldType == int.class || fieldType == long.class){
		return 0;
	}
	else {
		// Default value: try null.
		return null;
	}
}


这样从源头上,就把问题给解决了,但是,这还要修改spring的源代码,貌似不太理想。

继续debug:

TypeConverterDelegate:

/**
 * Convert the given text value using the given property editor.
 * @param oldValue the previous value, if available (may be <code>null</code>)
 * @param newTextValue the proposed text value
 * @param editor the PropertyEditor to use
 * @return the converted value
 */
protected Object doConvertTextValue(Object oldValue, String newTextValue, PropertyEditor editor) {
 try {
  editor.setValue(oldValue);
 }
 catch (Exception ex) {
  if (logger.isDebugEnabled()) {
   logger.debug("PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call", ex);
  }
  // Swallow and proceed.
 }
 editor.setAsText(newTextValue);
 return editor.getValue();
}

到这里才发现,spring首先调用的是自定义的editor的setValue然后才调用的setAsText,因此:

public void setAsText(String text) throws IllegalArgumentException { 
 if (text==null || text.trim().equals("")) { 
    // Treat empty String as null value. 
    setValue(0); 
 } else { 
    // Use default valueOf methods for parsing text. 
    setValue(Integer.parseInt(text)); 
 } 
}

这种方式根本就是行不通的!

既然找到了原因,那么,也就找到了解决办法,我们需要重写setValue,而不是setAsText:

private static class IntEditor extends CustomNumberEditor{
 public IntEditor(){
  super(Integer.class,true);
 }
 @Override
 public void setValue(Object value) {
  if(value == null){
   super.setValue(0);
  }else{
   super.setValue(value);
  }
 }
}
@InitBinder
public void initBinder(WebDataBinder binder){
 binder.registerCustomEditor(int.class, "graduted", new IntEditor());
 binder.registerCustomEditor(int.class, "married", new IntEditor());
}



世界从此清净了!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐