`

第四章 Controller接口控制器详解(6)——跟着开涛学SpringMVC

阅读更多

4.16、数据类型转换和数据验证

流程:

1、首先创建数据绑定器,在此此会创建ServletRequestDataBinder类的对象,并设置messageCodesResolver(错误码解析器);

2、提供第一个扩展点,初始化数据绑定器,在此处我们可以覆盖该方法注册自定义的PropertyEditor(请求参数——>命令对象属性的转换);

3、进行数据绑定,即请求参数——>命令对象的绑定;

4、提供第二个扩展点,数据绑定完成后的扩展点,此处可以实现一些自定义的绑定动作;

5、验证器对象的验证,验证器通过validators注入,如果验证失败,需要把错误信息放入Errors(此处使用BindException实现);

6、提供第三个扩展点,此处可以实现自定义的绑定/验证逻辑;

7、将errors传入功能处理方法进行处理,功能方法应该判断该错误对象是否有错误进行相应的处理。

 

4.16.1、数据类型转换

请求参数(String)——>命令对象属性(可能是任意类型)的类型转换,即数据绑定时的类型转换,使用PropertyEditor实现绑定时的类型转换。

 

一、Spring内建的PropertyEditor如下所示:

类名

说明

默认是否注册

ByteArrayPropertyEditor

String<——>byte[]

ClassEditor

String<——>Class

当类没有发现抛出IllegalArgumentException

CustomBooleanEditor

String<——>Boolean

true/yes/on/1转换为true,false/no/off/0转换为false

CustomCollectionEditor

数组/Collection——>Collection

普通值——>Collection(只包含一个对象)

如String——>Collection

不允许Collection——>String(单方向转换)

CustomNumberEditor

String<——>Number(Integer、Long、Double)

FileEditor

String<——>File

InputStreamEditor

String——>InputStream

单向的,不能InputStream——>String

LocaleEditor

String<——>Locale,

(String的形式为[语言]_[国家]_[变量],这与Local对象的toString()方法得到的结果相同)

PatternEditor

String<——>Pattern

PropertiesEditor

String<——>java.lang.Properties

URLEditor

String<——>URL

StringTrimmerEditor

一个用于trim 的 String类型的属性编辑器

如默认删除两边的空格,charsToDelete属性:可以设置为其他字符

emptyAsNull属性:将一个空字符串转化为null值的选项。

×

CustomDateEditor

String<——>java.util.Date

×

 

二、Spring内建的PropertyEditor支持的属性(符合JavaBean规范)操作:

表达式

设值/取值说明

username

属性username

设值方法setUsername()/取值方法getUsername() 或 isUsername()

schooInfo.schoolType

属性schooInfo的嵌套属性schoolType

设值方法getSchooInfo().setSchoolType()/取值方法getSchooInfo().getSchoolType()

hobbyList[0]

属性hobbyList的第一个元素

索引属性可能是一个数组、列表、其它天然有序的容器。

map[key]

属性map(java.util.Map类型)

map中key对应的值

 

三、示例:

接下来我们写自定义的属性编辑器进行数据绑定:

1、模型对象:

 

java代码:
Java代码  收藏代码
  1. package cn.javass.chapter4.model;  
  2. //省略import  
  3. public class DataBinderTestModel {  
  4.     private String username;  
  5.     private boolean bool;//Boolean值测试  
  6.     private SchoolInfoModel schooInfo;  
  7.     private List hobbyList;//集合测试,此处可以改为数组/Set进行测试  
  8.     private Map map;//Map测试  
  9.     private PhoneNumberModel phoneNumber;//String->自定义对象的转换测试  
  10.     private Date date;//日期类型测试  
  11.     private UserState state;//String——>Enum类型转换测试  
  12.     //省略getter/setter  
  13. }  
  14.   
  15. package cn.javass.chapter4.model;  
  16. //如格式010-12345678  
  17. public class PhoneNumberModel {  
  18.     private String areaCode;//区号  
  19.     private String phoneNumber;//电话号码  
  20.     //省略getter/setter  
  21. }  

(2PhoneNumber属性编辑器

前台输入如010-12345678自动转换为PhoneNumberModel。

 

java代码:
Java代码  收藏代码
  1. package cn.javass.chapter4.web.controller.support.editor;  
  2. //省略import  
  3. public class PhoneNumberEditor extends PropertyEditorSupport {  
  4.     Pattern pattern = Pattern.compile("^(\\d{3,4})-(\\d{7,8})$");  
  5.     @Override  
  6.     public void setAsText(String text) throws IllegalArgumentException {  
  7.         if(text == null || !StringUtils.hasLength(text)) {  
  8.             setValue(null); //如果没值,设值为null  
  9.         }  
  10.         Matcher matcher = pattern.matcher(text);  
  11.         if(matcher.matches()) {  
  12.             PhoneNumberModel phoneNumber = new PhoneNumberModel();  
  13.             phoneNumber.setAreaCode(matcher.group(1));  
  14.             phoneNumber.setPhoneNumber(matcher.group(2));  
  15.             setValue(phoneNumber);  
  16.         } else {  
  17.             throw new IllegalArgumentException(String.format("类型转换失败,需要格式[010-12345678],但格式是[%s]", text));  
  18.         }  
  19.     }  
  20.     @Override  
  21.     public String getAsText() {  
  22.         PhoneNumberModel phoneNumber = ((PhoneNumberModel)getValue());  
  23.         return phoneNumber == null ? "" : phoneNumber.getAreaCode() + "-" + phoneNumber.getPhoneNumber();  
  24.     }  
  25. }  

PropertyEditorSupport一个PropertyEditor的支持类;

setAsText表示将String——>PhoneNumberModel,根据正则表达式进行转换,如果转换失败抛出异常,则接下来的验证器会进行验证处理;

getAsText表示将PhoneNumberModel——>String。

 

3、控制器

需要在控制器注册我们自定义的属性编辑器。

此处我们使用AbstractCommandController,因为它继承了BaseCommandController,拥有绑定流程。

 

java代码:
Java代码  收藏代码
  1. package cn.javass.chapter4.web.controller;  
  2. //省略import  
  3. public class DataBinderTestController extends AbstractCommandController {  
  4.     public DataBinderTestController() {  
  5.         setCommandClass(DataBinderTestModel.class); //设置命令对象  
  6.         setCommandName("dataBinderTest");//设置命令对象的名字  
  7.     }  
  8.     @Override  
  9.     protected ModelAndView handle(HttpServletRequest req, HttpServletResponse resp, Object command, BindException errors) throws Exception {  
  10.         //输出command对象看看是否绑定正确  
  11.         System.out.println(command);  
  12.         return new ModelAndView("bindAndValidate/success").addObject("dataBinderTest", command);  
  13.     }  
  14.     @Override  
  15.     protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {  
  16.         super.initBinder(request, binder);  
  17.         //注册自定义的属性编辑器  
  18.         //1、日期  
  19.         DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  20.         CustomDateEditor dateEditor = new CustomDateEditor(df, true);  
  21.         //表示如果命令对象有Date类型的属性,将使用该属性编辑器进行类型转换  
  22.         binder.registerCustomEditor(Date.class, dateEditor);  
  23.         //自定义的电话号码编辑器  
  24.         binder.registerCustomEditor(PhoneNumberModel.classnew PhoneNumberEditor());  
  25.     }  
  26. }  

initBinder:第一个扩展点,初始化数据绑定器,在此处我们注册了两个属性编辑器;

CustomDateEditor自定义的日期编辑器,用于在String<——>日期之间转换;

    binder.registerCustomEditor(Date.class, dateEditor):表示如果命令对象是Date类型,则使用dateEditor进行类型转换;

PhoneNumberEditor自定义的电话号码属性编辑器用于在String<——> PhoneNumberModel之间转换;

    binder.registerCustomEditor(PhoneNumberModel.classnewPhoneNumberEditor()):表示如果命令对象是PhoneNumberModel类型,则使用PhoneNumberEditor进行类型转换;

(4、spring配置文件chapter4-servlet.xml

 

java代码:
Java代码  收藏代码
  1. <bean name="/dataBind"   
  2. class="cn.javass.chapter4.web.controller.DataBinderTestController"/>  

5、视图页面(WEB-INF/jsp/bindAndValidate/success.jsp

 

java代码:
Java代码  收藏代码
  1. EL phoneNumber:${dataBinderTest.phoneNumber}<br/>  
  2. EL state:${dataBinderTest.state}<br/>  
  3. EL date:${dataBinderTest.date}<br/>  

视图页面的数据没有预期被格式化,如何进行格式化显示呢?请参考【第七章  注解式控制器的数据验证、类型转换及格式化】。

 

6、测试:

1、在浏览器地址栏输入请求的URL,如

http://localhost:9080/springmvc-chapter4/dataBind?username=zhang&bool=yes&schooInfo.specialty=computer&hobbyList[0]=program&hobbyList[1]=music&map[key1]=value1&map[key2]=value2&phoneNumber=010-12345678&date=2012-3-18 16:48:48&state=blocked

 

2、控制器输出的内容:

DataBinderTestModel [username=zhang, bool=true, schooInfo=SchoolInfoModel [schoolType=null, schoolName=null, specialty=computer], hobbyList=[program, music], map={key1=value1, key2=value2}, phoneNumber=PhoneNumberModel [areaCode=010, phoneNumber=12345678], date=Sun Mar 18 16:48:48 CST 2012, state=锁定]

 

类型转换如图所示:

 

四、注册PropertyEditor

1、使用WebDataBinder进行控制器级别注册PropertyEditor(控制器独享)

如“【三、示例】”中所使用的方式,使用WebDataBinder注册控制器级别的PropertyEditor,这种方式注册的PropertyEditor只对当前控制器独享,即其他的控制器不会自动注册这个PropertyEditor,如果需要还需要再注册一下。

 

2、使用WebBindingInitializer批量注册PropertyEditor

如果想在多个控制器同时注册多个相同的PropertyEditor时,可以考虑使用WebBindingInitializer。

 

示例:

(1、实现WebBindingInitializer

 

java代码:
Java代码  收藏代码
  1. package cn.javass.chapter4.web.controller.support.initializer;  
  2. //省略import  
  3. public class MyWebBindingInitializer implements WebBindingInitializer {  
  4.     @Override  
  5.     public void initBinder(WebDataBinder binder, WebRequest request) {  
  6.         //注册自定义的属性编辑器  
  7.         //1、日期  
  8.         DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  9.         CustomDateEditor dateEditor = new CustomDateEditor(df, true);  
  10.         //表示如果命令对象有Date类型的属性,将使用该属性编辑器进行类型转换  
  11.         binder.registerCustomEditor(Date.class, dateEditor);  
  12.         //自定义的电话号码编辑器  
  13.         binder.registerCustomEditor(PhoneNumberModel.classnew PhoneNumberEditor());  
  14.     }  
  15. }  

通过实现WebBindingInitializer并通过binder注册多个PropertyEditor。

 

(2、修改【三、示例】中的DataBinderTestController,注释掉initBinder方法;

 

(3、修改chapter4-servlet.xml配置文件:

 

java代码:
Java代码  收藏代码
  1. <!-- 注册WebBindingInitializer实现 -->  
  2. <bean id="myWebBindingInitializer" class="cn.javass.chapter4.web.controller.support.initializer.MyWebBindingInitializer"/>  
  3. <bean name="/dataBind" class="cn.javass.chapter4.web.controller.DataBinderTestController">  
  4.     <!-- 注入WebBindingInitializer实现 -->  
  5.     <property name="webBindingInitializer" ref="myWebBindingInitializer"/>  
  6. </bean>  

(4、尝试访问“【三、示例】”中的测试URL即可成功。

 

使用WebBindingInitializer的好处是当你需要在多个控制器中需要同时使用多个相同的PropertyEditor可以在WebBindingInitializer实现中注册,这样只需要在控制器中注入WebBindingInitializer即可注入多个PropertyEditor。

 

3、全局级别注册PropertyEditor(全局共享)

只需要将我们自定义的PropertyEditor放在和你的模型类同包下即可,且你的Editor命名规则必须是“模型类名Editor”,这样Spring会自动使用标准JavaBean架构进行自动识别,如图所示:

此时我们把“DataBinderTestController”的“binder.registerCustomEditor(PhoneNumberModel.class, new PhoneNumberEditor());”注释掉,再尝试访问“【三、示例】”中的测试URL即可成功。

 

这种方式不仅仅在使用Spring时可用,在标准的JavaBean等环境都是可用的,可以认为是全局共享的(不仅仅是Spring环境)。

 

PropertyEditor被限制为只能String<——>Object之间转换,不能Object<——>Object,Spring3提供了更强大的类型转换(TypeConversion)支持,它可以在任意对象之间进行类型转换,不仅仅是String<——>Object。

 

如果我在地址栏输入错误的数据,即数据绑定失败,Spring Web MVC该如何处理呢?如果我输入的数据不合法呢?如用户名输入100个字符(超长了)那又该怎么处理呢?出错了需要错误消息,那错误消息应该是硬编码?还是可配置呢?

 

接下来我们来学习一下数据验证器进行数据验证吧。

 

私塾在线学习网原创内容(http://sishuok.com

原创内容,转载请注明私塾在线【http://sishuok.com/forum/blogPost/list/5677.html

原文地址:http://jinnianshilongnian.iteye.com/blog/1641351

原作者:开涛

如有侵权请通知我删除!!!

JAVA技术交流群 532101200

分享到:
评论

相关推荐

    源代码下载 第五章 处理器拦截器详解——跟着开涛学SpringMVC

    NULL 博文链接:https://jinnianshilongnian.iteye.com/blog/1679570

    跟着开涛学SpringMVC

    跟着开涛学SpringMVC,很好的MVC教程,简单易懂,PDF高清版本

    SpringMvc开涛.rar

    PDF,源代码 开涛学SpringMVC 第一章源...第四章 Controller接口控制器详解 源代码下载 第五章 处理器拦截器详解——跟着开涛学SpringMVC 第六章 注解式控制器详解 第七章 注解式控制器的数据验证、类型转换及格式化

    跟着开涛学SpringMVC.pdf

    跟开涛学springmvc pdf电子文档版 适合学习springmvc 非常好的教程

    跟我学SpringMVC 教程

    第四章 Controller接口控制器详解(4) 第四章 Controller接口控制器详解(5) 第四章 Controller接口控制器详解(6) 第五章 处理器拦截器详解 第六章 注解式控制器详解 注解式控制器运行流程及处理器定义 第...

    跟开涛学 SpringMVC

    跟开涛学 SpringMVC跟开涛学 SpringMVC跟开涛学 SpringMVC跟开涛学 SpringMVC

    跟我学SpringMVC

    第四章 Controller接口控制器详解(4) 第四章 Controller接口控制器详解(5) 第四章 Controller接口控制器详解(6) 第五章 处理器拦截器详解 第六章 注解式控制器详解 注解式控制器运行流程及处理器定义 第六章 ...

    SpringMVC教程

    第四章 Controller接口控制器详解 (6).pdf 第四章 Controller接口控制器详解(7 完).pdf 第五章 处理器拦截器详解.pdf 第六章 注解式控制器详解1(注解式控制器运行流程及处理器定义).pdf 第六章 注解式控制器详解...

    跟开涛学SpringMVC-高清版

    跟开涛学SpringMVC-高清版,找了好久的,分享给大家。

    Spring MVC学习(四)-------Controller接口控制器详解1

    Spring MVC学习(四)-------Controller接口控制器详解1

    跟开涛学SpringMVC(4.6)Controller接

    跟开涛学SpringMVC(4.6)Controller接口控制器详解(6)Java开发Java经验技巧共10页.pdf.zip

    跟开涛学SpringMVC源代码

    跟开涛学SpringMVC源代码汇总

    跟开涛学SpringMVC

    跟开涛学SpringMVC 高清 带书签 pdf 通过策略接口,Spring 框架是高度可配置的,而且包含多种视图技术,例如 JavaServer Pages(JSP)技术、Velocity、Tiles、iText和POI。Spring MVC 框架并不知道使用的视图,所以...

    跟开涛学SpringMVC(4.3)Controller接

    跟开涛学SpringMVC(4.3)Controller接口控制器详解(3)Java开发Java经验技巧共9页.pdf.zip

    跟开涛学springmvc

    开涛写的中文springmvc开发文档 , 初学者可以下载学习,或者当做字典用。

    跟开涛学习springmvc spring 3 pdf

    跟开涛学习springmvc spring 3 pdf ,非常好的资料。我将原文档的spring合并为一份,查看更方便一些。

    跟开涛学SpringMVC(5)处理器拦截器详解Java开

    跟开涛学SpringMVC(5)处理器拦截器详解Java开发Java经验技巧共13页.pdf.zip

    SpringMVC入门——跟开涛学SpringMVC

    SpringWebMVC是一种基于Java的实现了WebMVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行...应用控制器其实拆为处理器映射器(HandlerMapping)进行处理器管理和视图解析器(ViewResolv

Global site tag (gtag.js) - Google Analytics