zoukankan      html  css  js  c++  java
  • spring3mvc如何把checkbox的值绑定到model对象的int数据类型

    1. model对象:User.java:  

    1. public class User {  
    2.     private int id;  
    3.     private String name;  
    4.     //0:男,1:女,页面上表现为radiobutton  
    5.     private int gender;  
    6.     private int age;  
    7.     //0:没毕业,1:已经毕业,页面上表现为checkbox  
    8.     private int graduted;  
    9.     //0:没结婚,1:已经结婚,页面上表现为checkbox  
    10.     private int married;  
    11. }  

    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>

    1. UserController:  
    2. @Controller  
    3. @RequestMapping("/user")  
    4. public class UserController{  
    5.  private static class IntEditor extends CustomNumberEditor{  
    6.   public IntEditor(){  
    7.    super(Integer.class,true);  
    8.   }  
    9.   public void setAsText(String text) throws IllegalArgumentException {   
    10.    if (text==null || text.trim().equals("")) {   
    11.       // Treat empty String as null value.   
    12.       setValue(0);   
    13.    } else {   
    14.       // Use default valueOf methods for parsing text.   
    15.       setValue(Integer.parseInt(text));   
    16.    }   
    17.   }  
    18.  }  
    19.  @InitBinder  
    20.  public void initBinder(WebDataBinder binder){  
    21.   binder.registerCustomEditor(int.class, null, new IntEditor());  
    22.  }  
    23.  @RequestMapping(value="/add")  
    24.  public ModelAndView add(HttpServletRequest request){  
    25.   ModelAndView mav = new ModelAndView("useradd");  
    26.   //Neither BindingResult nor plain target object for bean name 'user' available as request attribute  
    27.   mav.addObject("user", new User());  
    28.   return mav;  
    29.  }  
    30.  @RequestMapping(value="/save")  
    31.  public ModelAndView save(HttpServletRequest request,  
    32.    @ModelAttribute("user") User user){  
    33.   ModelAndView mav = new ModelAndView("redirect:list.do");  
    34.   System.out.println(user);  
    35.   return mav;  
    36.  }  
    37. }  

    浏览器输入: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方法:

    1. protected Object getEmptyValue(String field, Class fieldType) {  
    2.     if (fieldType != null && boolean.class.equals(fieldType) || Boolean.class.equals(fieldType)) {  
    3.         // Special handling of boolean property.  
    4.         return Boolean.FALSE;  
    5.     }  
    6.     else if (fieldType != null && fieldType.isArray()) {  
    7.         // Special handling of array property.  
    8.         return Array.newInstance(fieldType.getComponentType(), 0);  
    9.     }else if(fieldType == int.class || fieldType == long.class){  
    10.         return 0;  
    11.     }  
    12.     else {  
    13.         // Default value: try null.  
    14.         return null;  
    15.     }  
    16. }  

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

    继续debug:
    TypeConverterDelegate:

    1. /** 
    2.  * Convert the given text value using the given property editor. 
    3.  * @param oldValue the previous value, if available (may be <code>null</code>) 
    4.  * @param newTextValue the proposed text value 
    5.  * @param editor the PropertyEditor to use 
    6.  * @return the converted value 
    7.  */  
    8. protected Object doConvertTextValue(Object oldValue, String newTextValue, PropertyEditor editor) {  
    9.  try {  
    10.   editor.setValue(oldValue);  
    11.  }  
    12.  catch (Exception ex) {  
    13.   if (logger.isDebugEnabled()) {  
    14.    logger.debug("PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call", ex);  
    15.   }  
    16.   // Swallow and proceed.  
    17.  }  
    18.  editor.setAsText(newTextValue);  
    19.  return editor.getValue();  
    20. }  

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

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

    这种方式根本就是行不通的!
    既然找到了原因,那么,也就找到了解决办法,我们需要重写setValue,而不是setAsText:

    1. private static class IntEditor extends CustomNumberEditor{  
    2.  public IntEditor(){  
    3.   super(Integer.class,true);  
    4.  }  
    5.  @Override  
    6.  public void setValue(Object value) {  
    7.   if(value == null){  
    8.    super.setValue(0);  
    9.   }else{  
    10.    super.setValue(value);  
    11.   }  
    12.  }  
    13. }  
    14. @InitBinder  
    15. public void initBinder(WebDataBinder binder){  
    16.  binder.registerCustomEditor(int.class, "graduted", new IntEditor());  
    17.  binder.registerCustomEditor(int.class, "married", new IntEditor());  
    18. }  

     

    世界从此清净了!

  • 相关阅读:
    迭代加深搜索 codevs 2541 幂运算
    二叉树结构 codevs 1029 遍历问题
    深搜+DP剪枝 codevs 1047 邮票面值设计
    2016.6.10 深度优先搜索练习
    二分+动态规划 POJ 1973 Software Company
    tarjan算法求桥双连通分量 POJ 3177 Redundant Paths
    tarjan算法+缩点:求强连通分量 POJ 2186
    tarjan算法求割点cojs 8
    关键路径 SDUTOJ 2498
    第二章 STM32的结构和组成
  • 原文地址:https://www.cnblogs.com/chenying99/p/2504683.html
Copyright © 2011-2022 走看看