`

Controller 数据绑定 WebDataBinder PropertyEditorSupport

 
阅读更多

对 controller方法参数不能用@RequestBody进行标记,标记后转换不了,可能是因为@RequestBody会把数数据转为Json类型 

 

数据类型转换和数据验证

流程:

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.     private PhoneNumberModel phoneNumber2;//String->自定义对象的转换测试  
  13.     //省略getter/setter  
  14. }  
  15.   
  16. package cn.javass.chapter4.model;  
  17. //如格式010-12345678  
  18. public class PhoneNumberModel {  
  19.     private String areaCode;//区号  
  20.     private String phoneNumber;//电话号码  
  21.     //省略getter/setter  
  22. }  

(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.   binder.registerCustomEditor(PhoneNumberModel.class,"phoneNumber2", new PhoneNumberEditor());
  27.   //第一个属性遇到这个类型就转换,第二个属性遇到这个属性标签就转换

 

  1.     }  
  2. }  

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个字符(超长了)那又该怎么处理呢?出错了需要错误消息,那错误消息应该是硬编码?还是可配置呢?

 

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

分享到:
评论

相关推荐

    C#使用数据绑定控件录入数据

    9. 表示层与业务逻辑层分离:数据绑定使得UI与数据模型之间的关系更加清晰,有利于实现MVC(Model-View-Controller)或MVVM(Model-View-ViewModel)架构,提高代码的可维护性和复用性。 10. LINQ to SQL 和 Entity...

    C#数据绑定(DataBinding)简单实现方法

    在实际应用中,数据绑定常用于MVVM(Model-View-ViewModel)或MVC(Model-View-Controller)架构,以便在模型和视图之间建立松散耦合的关系,提高代码的可维护性和复用性。通过数据绑定,开发者可以专注于业务逻辑,...

    asp.net视频数据绑定

    数据绑定可以是单向或双向的,单向数据绑定主要用于呈现数据,而双向数据绑定则支持用户输入的数据回传到数据源。 1. **数据源**:在ASP.NET中,数据源可以是各种类型的,包括但不限于SQL Server数据库、XML文件、...

    flex数据绑定 pdf

    5. **数据绑定与MVC模式**:Flex中的数据绑定与Model-View-Controller(MVC)设计模式的关系,如何通过数据绑定实现MVC的分离关注点。 6. **实用示例**:提供具体的Flex项目实例,展示如何在实际开发中应用数据绑定...

    SpringMVC入门很简单之数据绑定(下)

    在这个过程中,SpringMVC会自动进行数据绑定,将请求参数映射到Controller方法的参数上。 数据绑定分为两种类型:入参绑定和出参绑定。入参绑定是将请求参数值绑定到Controller方法的参数上,例如,如果我们有如下...

    Spring In Action MVC 提交表单(2)-数据绑定和数据校验

    本篇文章将深入探讨Spring MVC中关于数据绑定和数据校验的知识点。 1. **数据绑定** 数据绑定是Spring MVC中一个强大的特性,它允许我们将HTTP请求参数自动映射到控制器方法的参数上。例如,当用户提交一个HTML...

    zk 数据绑定(grid进行嵌套显示数据)

    ZK的数据绑定机制基于MVC(Model-View-Controller)设计模式,通过数据绑定API实现了视图和模型之间的双向同步。这意味着当模型数据发生变化时,视图会自动更新,反之亦然。ZK的数据绑定主要涉及三个类:`Binding`, ...

    详解JavaScript的AngularJS框架中的作用域与数据绑定

    本文将详细解析AngularJS中的作用域与数据绑定机制,包括作用域的创建、作用域的继承以及数据绑定的方式。 作用域(Scope)是AngularJS中的核心概念,它类似于其他编程语言中的作用域,但与页面的DOM结构紧密相关。...

    2、Webdynpro入门之数据绑定【原创】

    ### Webdynpro 数据绑定详解 #### 一、Webdynpro框架概述 Webdynpro for ABAP 是 SAP 提供的一种用于构建基于 Web 的企业应用程序的技术框架。它采用了模型-视图-控制器 (Model-View-Controller, MVC) 设计模式,...

    SpringMVC数据绑定入门.rar

    在这个“SpringMVC数据绑定入门”压缩包中,你将找到一系列资源来帮助你理解并掌握SpringMVC的数据绑定机制,这对于任何Java开发者来说都是一个重要的技能。 1. **SpringMVC概述**: SpringMVC作为Spring框架的一...

    Java培训实战教程之angularJS的双向数据绑定.pdf

    **AngularJS 双向数据绑定详解** AngularJS 是一个基于 JavaScript 的前端框架,它极大地简化了 Web 应用的开发流程。通过与 HTML、CSS 和 JavaScript 的紧密协作,AngularJS 提供了一系列高级特性,比如视图与应用...

    WPF数据绑定

    WPF数据绑定是Windows Presentation Foundation(WPF)框架中的核心特性之一,它允许UI元素与应用程序的业务逻辑或数据模型之间建立动态连接。通过数据绑定,开发者可以轻松地实现视图和模型之间的数据同步,从而...

    Mac下基于IntelliJ IDEA+tomcat+maven,实现web数据前端数据的绑定

    4. 简单对象类型:比如自定义的User类,这种类型的数据绑定通常涉及到对象的属性与前端的表单字段对应,通过setter和getter方法进行数据交换。 5. 复杂对象类型:当需要绑定的对象包含嵌套的对象或者集合时,就需要...

    26 Spring Core 数据绑定之DataBinder实现示例及背后原理探究慕课专栏(1)1

    在Spring框架中,数据绑定是一项核心功能,它使得开发者能够方便地将用户输入的数据与Java对象的属性对应起来。本文将深入探讨Spring Core中的数据绑定,特别是DataBinder的实现示例及其背后的原理。 首先,让我们...

    SpringMVC绑定数据库例子

    SpringMVC是Spring框架的一部分,它提供了处理HTTP请求、视图解析以及模型数据绑定等功能,而MyBatis则是一个轻量级的持久层框架,它简化了SQL操作,使开发者可以直接编写SQL语句并与Java对象进行映射。 1. **...

    Angular数据绑定机制原理

    Angular 数据绑定机制原理 Angular 数据绑定机制原理是指 Angular 框架中实现数据绑定的机制。该机制主要由三个部分组成:扩展浏览器的事件循环、$watch 列表和 $digest 循环。 一、扩展浏览器的事件循环 Angular...

    Avalonjs双向数据绑定与监听的实例代码

    在前端开发中,Avalonjs是一个轻量级的、数据驱动的双向数据绑定的JavaScript框架。使用Avalonjs,开发者可以轻松地实现视图层与数据模型层之间的同步更新,这被称为双向数据绑定。在双向数据绑定中,当数据模型发生...

    详解JavaScript的AngularJS框架中的作用域与数据绑定_.docx

    在JavaScript的AngularJS框架中,作用域(Scope)和数据绑定是两个核心概念,它们极大地简化了前端开发的复杂性,特别是对于构建大型单页面应用(SPA)来说。AngularJS由Google发起,作为一款轻量级的MVC框架,它...

Global site tag (gtag.js) - Google Analytics