`

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、模型对象:

  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。

 
  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,拥有绑定流程。

 
  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.classnew PhoneNumberEditor()):表示如果命令对象是PhoneNumberModel类型,则使用PhoneNumberEditor进行类型转换;

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

1
2
<bean name="/dataBind" 
class="cn.javass.chapter4.web.controller.DataBinderTestController"/>

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

1
2
3
EL phoneNumber:${dataBinderTest.phoneNumber}<br/> 
EL state:${dataBinderTest.state}<br/> 
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

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

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

 

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

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

1
2
3
4
5
6
<!-- 注册WebBindingInitializer实现 -->
<bean id="myWebBindingInitializer"class="cn.javass.chapter4.web.controller.support.initializer.MyWebBindingInitializer"/>
<bean name="/dataBind"class="cn.javass.chapter4.web.controller.DataBinderTestController"
    <!-- 注入WebBindingInitializer实现 -->
    <property name="webBindingInitializer" ref="myWebBindingInitializer"/> 
</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提供了更强大的类型转换(Type Conversion)支持,它可以在任意对象之间进行类型转换,不仅仅是String<——>Object。

 

 

分享到:
评论

相关推荐

    第四章 Controller接口控制器详解 源代码下载

    总的来说,Controller接口控制器是Spring MVC中连接用户请求和业务逻辑的关键组件。通过合理使用@Controller、@RequestMapping等注解,我们可以创建出灵活、可扩展的Web服务。深入学习和理解Controller接口及其工作...

    SpringMVC教程

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

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

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

    Zend Framework教程之请求对象的封装Zend_Controller_Request实例详解

    getControllerName() 和 setControllerName() 方法用于获取和设置控制器名称;getActionName() 和 setActionName() 方法用于获取和设置动作名称。此外,还提供了获取和设置模块、控制器、动作对应的键名的方法。 在...

    跟开涛学SpringMVC(4.6)Controller接

    在本课程"跟开涛学SpringMVC(4.6)Controller接...在学习过程中,结合"跟开涛学SpringMVC(4.6)Controller接口控制器详解(6)Java开发Java经验技巧共10页.pdf"这份资料,你将能深入理解并掌握SpringMVC的核心概念。

    spispispispispi

    - `spi_controller_driver`定义了SPI控制器驱动的接口函数,包括初始化、配置、传输等。 - `spi_register_driver`用于注册SPI设备驱动,`spi_unregister_driver`用于注销。 3. **SPI控制器驱动** - 控制器驱动...

    usb host controller ehci 详解

    USB EHCI主机控制器详解 USB(通用串行总线)技术是计算机和电子设备之间进行数据交换的标准通信协议。EHCI(Enhanced Host Controller Interface)是USB 2.0规范中定义的一种主机控制器接口标准。EHCI的设计允许...

    课题-ASP-NET-MVC-Controller激活系统详解:总体设计.doc编程资料x

    除了设置控制器工厂之外,`ControllerBuilder`还可以用于注册自定义的控制器筛选器(Controller Filters)以及其他相关组件。这使得开发人员能够更加灵活地控制控制器的行为。 #### 实例演示:如何提升命名空间的...

    NFC Controller Interface{NCI} Technical Specification

    本篇将详细介绍《NFC Controller Interface (NCI) Technical Specification》的核心内容和技术要点,旨在帮助读者深入理解NFC控制器接口的设计与实现。 #### 二、NFC控制器接口(NCI)概述 NFC控制器接口(NCI)是...

    跟开涛学SpringMVC(4.3)Controller接

    《跟开涛学SpringMVC(4.3)Controller接口控制器详解》是针对Java开发者的一份深入学习资料,主要探讨了SpringMVC框架中的Controller组件。SpringMVC是Spring框架的一部分,专门用于处理Web应用程序的请求和响应。...

    面向接口编程详解(三)——模式研究.doc

    - 控制器使用策略模式,控制器本身不直接包含业务逻辑,而是根据策略(实现特定接口的类)来决定如何响应视图传递的用户操作。这种设计使得可以有多个控制器,每个具有不同的策略,从而实现对相同视图和模型操作的...

    CAN接口的电平详解

    ### CAN接口的电平详解 #### 一、概述 CAN(Controller Area Network)总线作为一种广泛应用的现场总线协议,其通信方式与电平转换机制是理解CAN接口工作原理的关键。本文将详细介绍CAN接口中显性电平和隐性电平的...

    ACHI接口标准是SATA的控制器接口

    **ACHI(Advanced Host Controller Interface)**是一种标准化的硬件接口规范,用于连接计算机主板上的串行ATA(SATA)控制器与存储设备。它由Intel在2004年提出,并被广泛采纳为下一代硬盘接口的标准之一。ACHI的...

    sata3.0控制器代码

    ** SATA 3.0 控制器代码详解 ** SATA(Serial Advanced Technology Attachment)是一种高速接口标准,用于连接计算机系统和存储设备,如硬盘、光驱等。SATA 3.0是SATA规范的第三版,其最大传输速度可达6 Gbps,理论...

    SpringMVC详解

    3. **Controller接口控制器** Controller是SpringMVC中处理用户请求的核心组件。控制器通常通过实现Controller接口或者使用注解@Controller来标识。它们负责接收请求参数,调用业务逻辑,最后将结果返回给视图层。 ...

    dsi_controller-master.zip

    《DSI控制器在FPGA/CPLD中的应用详解》 DSI(Display Serial Interface)控制器是一种广泛应用于现代显示系统的接口技术,它通过串行方式传输数据,为显示器提供高效、低功耗的数据通信。在本设计示例"dsi_...

    Spring Controller拦截器配置

    - **postHandle**:此方法在控制器方法调用之后、视图渲染之前执行。可以在此方法中添加数据到ModelAndView对象中,以便在视图中使用。 - **afterCompletion**:此方法在DispatcherServlet完成整个请求处理后被调用...

Global site tag (gtag.js) - Google Analytics