`
jinnianshilongnian
  • 浏览: 21434891 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2405130
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:2997788
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5631528
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:257583
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1593212
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:248982
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5847622
Group-logo
跟我学Nginx+Lua开...
浏览量:698184
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:780495
社区版块
存档分类
最新评论

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

 
阅读更多

第一章 Web MVC简介 —— 跟开涛学SpringMVC

第二章 Spring MVC入门 —— 跟开涛学SpringMVC

第三章 DispatcherServlet详解 ——跟开涛学SpringMVC

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

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

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

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

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

第四章 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代码:
package cn.javass.chapter4.model;
//省略import
public class DataBinderTestModel {
	private String username;
	private boolean bool;//Boolean值测试
	private SchoolInfoModel schooInfo;
	private List hobbyList;//集合测试,此处可以改为数组/Set进行测试
	private Map map;//Map测试
	private PhoneNumberModel phoneNumber;//String->自定义对象的转换测试
	private Date date;//日期类型测试
	private UserState state;//String——>Enum类型转换测试
    //省略getter/setter
}

package cn.javass.chapter4.model;
//如格式010-12345678
public class PhoneNumberModel {
	private String areaCode;//区号
	private String phoneNumber;//电话号码
    //省略getter/setter
}

(2PhoneNumber属性编辑器

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

 

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

PropertyEditorSupport一个PropertyEditor的支持类;

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

getAsText表示将PhoneNumberModel——>String。

 

3、控制器

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

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

 

java代码:
package cn.javass.chapter4.web.controller;
//省略import
public class DataBinderTestController extends AbstractCommandController {
	public DataBinderTestController() {
		setCommandClass(DataBinderTestModel.class); //设置命令对象
		setCommandName("dataBinderTest");//设置命令对象的名字
	}
	@Override
	protected ModelAndView handle(HttpServletRequest req, HttpServletResponse resp, Object command, BindException errors) throws Exception {
		//输出command对象看看是否绑定正确
		System.out.println(command);
		return new ModelAndView("bindAndValidate/success").addObject("dataBinderTest", command);
	}
	@Override
	protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
		super.initBinder(request, binder);
		//注册自定义的属性编辑器
		//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.class, new PhoneNumberEditor());
	}
}

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代码:
<bean name="/dataBind" 
class="cn.javass.chapter4.web.controller.DataBinderTestController"/>

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


java代码:
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


java代码:
package cn.javass.chapter4.web.controller.support.initializer;
//省略import
public class MyWebBindingInitializer implements WebBindingInitializer {
	@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.class, new PhoneNumberEditor());
	}
}

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

 

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

 

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

 

java代码:
<!-- 注册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提供了更强大的类型转换(TypeConversion)支持,它可以在任意对象之间进行类型转换,不仅仅是String<——>Object。

 

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

 

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

 

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

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

29
12
分享到:
评论
11 楼 redcoatjk 2015-03-05  
和上一节博客没有很好的衔接.
比如这一节说的是什么 做什么用的. 以场景来带入.
10 楼 呆呆DE萌萌 2014-10-21  
TAO哥,getAsText这个函数怎么触发?
9 楼 Motte2010 2013-06-11  
Motte2010 写道
jinnianshilongnian 写道
Motte2010 写道
你好:
   在测试这里例子的时候,有几个疑问
   1、在PhoneNumberModelEditor设置断点,为什么代码不会跟进去呢?
   2、号码输入错误时,代码中有抛出一个异常,但是测试的日志中没有发现异常信息,只是页面上没有显示处理而已,这个是spring的容错机制吗?
   3、在PhoneNumberModelEditor 中打印的语句也没有输出。

那说明没执行 仔细检查下 注册是否正确

但是验证的规则却是成功的,匹配正则表达式的正常显示,不匹配的,显示为空,断点不进。
运行你的程序4,也是一样。。。
handle方法断点有效
没明白验证为什么没有进断点。。。很奇怪。。。

用注册PropertyEditor的方式 断点可进
8 楼 Motte2010 2013-06-11  
jinnianshilongnian 写道
Motte2010 写道
你好:
   在测试这里例子的时候,有几个疑问
   1、在PhoneNumberModelEditor设置断点,为什么代码不会跟进去呢?
   2、号码输入错误时,代码中有抛出一个异常,但是测试的日志中没有发现异常信息,只是页面上没有显示处理而已,这个是spring的容错机制吗?
   3、在PhoneNumberModelEditor 中打印的语句也没有输出。

那说明没执行 仔细检查下 注册是否正确

但是验证的规则却是成功的,匹配正则表达式的正常显示,不匹配的,显示为空,断点不进。
运行你的程序4,也是一样。。。
handle方法断点有效
没明白验证为什么没有进断点。。。很奇怪。。。
7 楼 jinnianshilongnian 2013-06-11  
Motte2010 写道
你好:
   在测试这里例子的时候,有几个疑问
   1、在PhoneNumberModelEditor设置断点,为什么代码不会跟进去呢?
   2、号码输入错误时,代码中有抛出一个异常,但是测试的日志中没有发现异常信息,只是页面上没有显示处理而已,这个是spring的容错机制吗?
   3、在PhoneNumberModelEditor 中打印的语句也没有输出。

那说明没执行 仔细检查下 注册是否正确
6 楼 Motte2010 2013-06-11  
你好:
   在测试这里例子的时候,有几个疑问
   1、在PhoneNumberModelEditor设置断点,为什么代码不会跟进去呢?
   2、号码输入错误时,代码中有抛出一个异常,但是测试的日志中没有发现异常信息,只是页面上没有显示处理而已,这个是spring的容错机制吗?
   3、在PhoneNumberModelEditor 中打印的语句也没有输出。
5 楼 xydqluck 2013-02-17  
4 楼 李庆辉 2012-10-26  
感觉有点晕了。
3 楼 zhuifeng2215 2012-08-22  
人才啊!支持楼主!
2 楼 jinnianshilongnian 2012-08-21  
free0007 写道
很好   

谢谢
1 楼 free0007 2012-08-21  
很好   

相关推荐

    源代码下载 第五章 处理器拦截器详解——跟着开涛学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