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

第四章 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开涛.rar

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

    springmvc系列教程PDF精讲.

    1. **MVC架构**:首先,我们需要了解MVC模式,它是一种设计模式,将应用程序分为三个主要组件——模型(Model)、视图(View)和控制器(Controller)。在SpringMVC中,模型处理业务逻辑,视图负责展示数据,而控制...

    SpringMVC面试专题及答案整理.pdf

    该框架通过将应用程序的不同部分——模型(Model)、视图(View)和控制器(Controller)分离,使得各个部分能够各司其职,从而提高代码的可读性和可维护性。 - **模型(Model)**:负责处理应用程序的数据逻辑,...

    官方推荐——>基于SSM的图书馆管理系统毕业设计,带SQL文件

    《基于SSM的图书馆管理系统毕业设计详解》 SSM(Spring、SpringMVC、MyBatis)是一个在Java开发领域广泛应用的开源框架组合,它在构建企业级Web应用时提供了强大的支持。本毕业设计——“基于SSM的图书馆管理系统”...

    Java语言+基于SSM超市订单管理系统(毕业设计、课程设计使用).zip

    4. 支付模块:与第三方支付平台接口对接,实现在线支付功能,涉及安全支付协议。 5. 库存模块:实时更新库存信息,确保订单执行的准确性。 四、核心技术点 1. Spring框架:利用IoC容器管理对象,实现依赖注入,提升...

    基于SSM+vue的在线教育网站.zip

    2. **SpringMVC**:作为Spring的Web MVC框架,处理HTTP请求和响应,通过DispatcherServlet、Controller、ModelAndView等组件实现模型-视图-控制器模式,使业务逻辑和展示层分离。 3. **MyBatis**:作为持久层框架,...

    官方推荐——>jsp ssm mysql实现的校园二手市场交易平台源码

    2. SpringMVC:作为Spring框架的一部分,SpringMVC是一个用于构建Web应用的模型-视图-控制器(MVC)架构。它简化了HTTP请求的处理,使得业务逻辑与表示层更易于解耦。 3. MyBatis:是一个持久层框架,它简化了SQL...

    基于SSM洗衣店预约管理系统可升级SpringBoot毕业源码案例设计.zip

    在洗衣店预约系统中,SpringMVC扮演着控制器的角色,协调各个组件的工作。 3. **MyBatis**:MyBatis是一个持久层框架,它允许开发者将SQL语句直接写在XML配置文件或注解中,与Java对象进行映射,从而简化了数据访问...

    KTV点歌系统.zip

    《KTV点歌系统——基于SSM框架的Java毕业设计详解》 KTV点歌系统是一种常见的娱乐场所管理系统,主要用于帮助顾客便捷地选择并播放歌曲。在这个项目中,我们将深入探讨一个基于SSM(Spring、SpringMVC、MyBatis)...

    基于ssm+vue海鲜自助餐厅系统.zip

    - SpringMVC:负责处理HTTP请求,通过DispatcherServlet调度控制器,与视图层进行交互,实现了Model-View-Controller的设计模式。 - MyBatis:是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射,...

    基于ssm+vue的KTV包厢管理系统.zip

    4. 支付功能:集成第三方支付接口,如微信支付,实现在线支付功能。 5. 系统设置:管理员可以进行系统配置,如价格设定、营业时间设定等。 在开发过程中,可能会采用Maven或Gradle作为项目构建工具,确保项目的依赖...

    毕设项目-购物商城电商项目

    SpringMVC则是Spring框架的一部分,专门用于处理Web请求,它通过模型-视图-控制器(Model-View-Controller,MVC)的设计模式,将业务逻辑、数据处理和用户界面分离,提升了系统的可扩展性和可测试性。 MyBatis作为...

Global site tag (gtag.js) - Google Analytics