`

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

 
阅读更多

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. packagecn.javass.chapter4.model;
  2. //省略import
  3. publicclassDataBinderTestModel{
  4. privateStringusername;
  5. privatebooleanbool;//Boolean值测试
  6. privateSchoolInfoModelschooInfo;
  7. privateListhobbyList;//集合测试,此处可以改为数组/Set进行测试
  8. privateMapmap;//Map测试
  9. privatePhoneNumberModelphoneNumber;//String->自定义对象的转换测试
  10. privateDatedate;//日期类型测试
  11. privateUserStatestate;//String——>Enum类型转换测试
  12. //省略getter/setter
  13. }
  14. packagecn.javass.chapter4.model;
  15. //如格式010-12345678
  16. publicclassPhoneNumberModel{
  17. privateStringareaCode;//区号
  18. privateStringphoneNumber;//电话号码
  19. //省略getter/setter
  20. }

(2、PhoneNumber属性编辑器

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

java代码:
Java代码收藏代码
  1. packagecn.javass.chapter4.web.controller.support.editor;
  2. //省略import
  3. publicclassPhoneNumberEditorextendsPropertyEditorSupport{
  4. Patternpattern=Pattern.compile("^(\\d{3,4})-(\\d{7,8})$");
  5. @Override
  6. publicvoidsetAsText(Stringtext)throwsIllegalArgumentException{
  7. if(text==null||!StringUtils.hasLength(text)){
  8. setValue(null);//如果没值,设值为null
  9. }
  10. Matchermatcher=pattern.matcher(text);
  11. if(matcher.matches()){
  12. PhoneNumberModelphoneNumber=newPhoneNumberModel();
  13. phoneNumber.setAreaCode(matcher.group(1));
  14. phoneNumber.setPhoneNumber(matcher.group(2));
  15. setValue(phoneNumber);
  16. }else{
  17. thrownewIllegalArgumentException(String.format("类型转换失败,需要格式[010-12345678],但格式是[%s]",text));
  18. }
  19. }
  20. @Override
  21. publicStringgetAsText(){
  22. PhoneNumberModelphoneNumber=((PhoneNumberModel)getValue());
  23. returnphoneNumber==null?"":phoneNumber.getAreaCode()+"-"+phoneNumber.getPhoneNumber();
  24. }
  25. }

PropertyEditorSupport:一个PropertyEditor的支持类;

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

getAsText:表示将PhoneNumberModel——>String。

(3、控制器

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

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

java代码:
Java代码收藏代码
  1. packagecn.javass.chapter4.web.controller;
  2. //省略import
  3. publicclassDataBinderTestControllerextendsAbstractCommandController{
  4. publicDataBinderTestController(){
  5. setCommandClass(DataBinderTestModel.class);//设置命令对象
  6. setCommandName("dataBinderTest");//设置命令对象的名字
  7. }
  8. @Override
  9. protectedModelAndViewhandle(HttpServletRequestreq,HttpServletResponseresp,Objectcommand,BindExceptionerrors)throwsException{
  10. //输出command对象看看是否绑定正确
  11. System.out.println(command);
  12. returnnewModelAndView("bindAndValidate/success").addObject("dataBinderTest",command);
  13. }
  14. @Override
  15. protectedvoidinitBinder(HttpServletRequestrequest,ServletRequestDataBinderbinder)throwsException{
  16. super.initBinder(request,binder);
  17. //注册自定义的属性编辑器
  18. //1、日期
  19. DateFormatdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");
  20. CustomDateEditordateEditor=newCustomDateEditor(df,true);
  21. //表示如果命令对象有Date类型的属性,将使用该属性编辑器进行类型转换
  22. binder.registerCustomEditor(Date.class,dateEditor);
  23. //自定义的电话号码编辑器
  24. binder.registerCustomEditor(PhoneNumberModel.class,newPhoneNumberEditor());
  25. }
  26. }

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

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

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

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

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

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


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

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


java代码:
Java代码收藏代码
  1. ELphoneNumber:${dataBinderTest.phoneNumber}<br/>
  2. ELstate:${dataBinderTest.state}<br/>
  3. ELdate:${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. packagecn.javass.chapter4.web.controller.support.initializer;
  2. //省略import
  3. publicclassMyWebBindingInitializerimplementsWebBindingInitializer{
  4. @Override
  5. publicvoidinitBinder(WebDataBinderbinder,WebRequestrequest){
  6. //注册自定义的属性编辑器
  7. //1、日期
  8. DateFormatdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");
  9. CustomDateEditordateEditor=newCustomDateEditor(df,true);
  10. //表示如果命令对象有Date类型的属性,将使用该属性编辑器进行类型转换
  11. binder.registerCustomEditor(Date.class,dateEditor);
  12. //自定义的电话号码编辑器
  13. binder.registerCustomEditor(PhoneNumberModel.class,newPhoneNumberEditor());
  14. }
  15. }

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

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

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

java代码:
Java代码收藏代码
  1. <!--注册WebBindingInitializer实现-->
  2. <beanid="myWebBindingInitializer"class="cn.javass.chapter4.web.controller.support.initializer.MyWebBindingInitializer"/>
  3. <beanname="/dataBind"class="cn.javass.chapter4.web.controller.DataBinderTestController">
  4. <!--注入WebBindingInitializer实现-->
  5. <propertyname="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个字符(超长了)那又该怎么处理呢?出错了需要错误消息,那错误消息应该是硬编码?还是可配置呢?

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


分享到:
评论

相关推荐

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

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

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

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

    Spring MVC框架 多动作控制器详解 spring mvc 2.5

    本代码使用了Spring MVC框架(spring2.5架包) 演示了(Controller接口的试用方法)和 MultiActionController多动作控制器 数据库连接试用Spring JDBC 并且着重介绍了MultiActionController多动作控制器的两种方法名...

    详解Spring mvc ant path的使用方法

    详解Spring mvc ant path的使用方法 概要: 任何一个WEB都需要解决URL与请求处理器之间的映射,spring MVC也是一样,但Spring MVC就像Spring所作的一切一样(灵活,可以配置各种东西,但是也造成了很多复杂性),肯定...

    SpringMVC教程

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

    21道Java Spring MVC综合面试题详解含答案(值得珍藏)

    Spring MVC是Spring框架中的一部分,全称是Spring Web MVC,主要用于实现MVC设计模式的Web框架。它分离了控制器、模型对象、过滤器以及处理程序对象的角色,使得它们更容易进行定制。 Spring MVC的优点包括: 基于...

    跟我学SpringMVC 教程

    第四章 Controller接口控制器详解(6) 第五章 处理器拦截器详解 第六章 注解式控制器详解 注解式控制器运行流程及处理器定义 第六章 注解式控制器详解 SpringMVC3强大的请求映射规则详解 第六章 注解式控制器...

    跟我学SpringMVC

    第四章 Controller接口控制器详解(6) 第五章 处理器拦截器详解 第六章 注解式控制器详解 注解式控制器运行流程及处理器定义 第六章 注解式控制器详解 SpringMVC3强大的请求映射规则详解 第六章 注解式控制器详解 ...

    Java之Spring Boot详解

    (2)在 web.xml 文件中配置 Spring mvc 的前端控制器 (3)创建一个 spring mvc 的配置文件 (4)在 spring mvc 的配置文件中进行相关配置   1) 配置注解扫描路径   2)配置处理器映射器   3)配置处理器...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (1)

    10.5 Spring的控制器(Controller) 10.5.1 Controller接口 10.5.2 命令控制器(BaseCommandController) 10.5.3 表单控制器(SimpleFormController) 10.5.4 多动作控制器(MultiActionController) 10.6 Spring的...

    Spring-Reference_zh_CN(Spring中文参考手册)

    标准MVC控制器代码 14.5.1.3. 把模型数据转化为XML 14.5.1.4. 定义视图属性 14.5.1.5. 文档转换 14.5.2. 小结 14.6. 文档视图(PDF/Excel) 14.6.1. 简介 14.6.2. 配置和安装 14.6.2.1. 文档视图定义 14.6.2.2. ...

    详解利用SpringMVC拦截器控制Controller返回值

    主要介绍了详解利用SpringMVC拦截器控制Controller返回值,通过定义一个StringResult注解,在访问方法的时候返回StringResult中的内容,有兴趣的可以了解一下。

    详解Spring MVC如何测试Controller(使用springmvc mock测试)

    主要介绍了详解Spring MVC如何测试Controller(使用springmvc mock测试),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    Java Spring MVC 上传下载文件配置及controller方法详解

    主要介绍了Java Spring MVC 上传下载文件配置及controller方法详解,本文介绍的非常详细,具有参考借鉴价值,需要的朋友可以参考下

    SpringMVC Controller 返回值的可选类型详解

    本篇文章主要介绍了SpringMVC Controller 返回值的可选类型详解 ,spring mvc 支持如下的返回方式:ModelAndView, Model, ModelMap, Map,View, String, void,有兴趣的可以了解一下

    Spring中MVC模块代码详解

    主要介绍了Spring中MVC模块代码详解,涉及Controller的简单介绍,具有一定借鉴价值,需要的朋友可以参考下。

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (3)

    10.5 Spring的控制器(Controller) 10.5.1 Controller接口 10.5.2 命令控制器(BaseCommandController) 10.5.3 表单控制器(SimpleFormController) 10.5.4 多动作控制器(MultiActionController) 10.6 Spring的...

    看透springMvc源代码分析与实践

    第9章 创建Spring MVC之器90 9.1 整体结构介绍90 9.2 HttpServletBean93 9.3 FrameworkServlet95 9.4 DispatcherServlet100 9.5 小结107 第10章 Spring MVC之用108 10.1 HttpServletBean108 10.2 ...

    java Spring MVC4环境搭建实例详解(步骤)

    spring WEB MVC框架提供了一个MVC(model-view-controller)模型-视图-控制器的结构和组件,利用它可以开发更灵活、松耦合的web应用。MVC模式使得整个服务应用的各部分(控制逻辑、业务逻辑、UI界面展示)分离开来,使...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (2)

    10.5 Spring的控制器(Controller) 10.5.1 Controller接口 10.5.2 命令控制器(BaseCommandController) 10.5.3 表单控制器(SimpleFormController) 10.5.4 多动作控制器(MultiActionController) 10.6 Spring的...

Global site tag (gtag.js) - Google Analytics