对 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 当类没有发现抛出 |
√ |
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、模型对象:
- 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类型转换测试
- private PhoneNumberModel phoneNumber2;//String->自定义对象的转换测试
- //省略getter/setter
- }
- package cn.javass.chapter4.model;
- //如格式010-12345678
- public class PhoneNumberModel {
- private String areaCode;//区号
- private String phoneNumber;//电话号码
- //省略getter/setter
- }
(2、PhoneNumber属性编辑器
前台输入如010-12345678自动转换为PhoneNumberModel。
- 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,拥有绑定流程。
- 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());
- //
- binder.registerCustomEditor(PhoneNumberModel.class,"phoneNumber2", new PhoneNumberEditor());
- //第一个属性遇到这个类型就转换,第二个属性遇到这个属性标签就转换
- }
- }
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
- <bean name="/dataBind"
- class="cn.javass.chapter4.web.controller.DataBinderTestController"/>
(5、视图页面(WEB-INF/jsp/bindAndValidate/success.jsp)
- 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
- 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配置文件:
- <!-- 注册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个字符(超长了)那又该怎么处理呢?出错了需要错误消息,那错误消息应该是硬编码?还是可配置呢?
接下来我们来学习一下数据验证器进行数据验证吧。
相关推荐
备注2:我们引⼊了⼀个我们⾃⼰的js⽂件main.js 备注3:ng-controller 是angularJS的⼀个指令,它描述了⼀个控制器,指⽰当前元素是受该控制器控制 备注4:ng-model是angularJS的⼀个指令,它描述数据绑定的模型 备注...
html-Controller的双向数据绑定,在开发中非常常见,也是Angularjs1.x的宣传点之一,使用中并没有太多问题。 1.1数据从html流向controller 也就是从 视图层 流向 模型层 ,原生html中需要使用表单元素(例如 input ...
初步了解DataBinding(数据绑定)关于JetPack中的DataBinding(数据绑定)创建实例布局文件创建ViewModel类在MainActivity.java中声明变量实现效果如下:==使用DataBinding来改写==改善代码部分 关于JetPack中的...
1.Angular.js扩展浏览器的事件循环 浏览器持续等待例如用户交互这样...每当绑定一个数据到view上的时候,$watch队列就会插入一条对应的$watch。例子如下: controller.js: app.controller('MainCtrl', function($sc
假定两个Controller都在同一个工程中。 如果有比较合理的分层设计,这样的需求应该是非常罕见的。因为大部分情况下,调用应该都是限于对业务逻辑层或者数据库层,并不会涉及Controller之间的调用。 本文是讨论...
这个controller包含了一些用于数据绑定,验证,CSS更新,以及数值格式化和解析的服务。它不用来进行DOM渲染或者监听DOM事件。与DOM相关的逻辑都应该包含在其他的指令中,然后让这些指令来试用ngModelController中的...
主要介绍了springMVC如何将controller中数据传递到jsp页面,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
Android 蓝牙 HCI数据收发流程图,host将指令发送给controller,将Android 源码使用流程图的形式画了出来,使Android 蓝牙开发者更清楚数据收发走向,代码流程更加形象生动,能够很快的熟悉Android 蓝牙源码,利于...
里面附带doc使用方法在Controller类继承ControllerUtils类即可
Android 蓝牙 BLE 数据从host发数据到controller,数据流程图(协议栈),非常详细的从btif-bta-btm-hci 数据流程走向,以及从controller收到数据到btm层,将Android 源码使用流程图的形式画了出来,使Android 蓝牙...
前端vue双向数据绑定v-model的详解教学课件 MVVM源自于经典的MVC(Model-View-Controller)模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用 Vue.js是一个MV VM框架, 即数据...
AngularJS有着诸多特性,最为核心的是:MVVM、模块化、自动化双向数据绑定、语义化标签、依赖注入等等。 一.什么是数据双向绑定 Angular实现了双向绑定机制。所谓的双向绑定,无非是从界面的操作能实时反映到数据,...
JBL Intonato Desktop Controller用户数据手册.pdf
MVC2中Controller向View传递数据的三种方式
EMC ViPR Controller虚拟数据中心白皮书.pdf
Angular JS数据的双向绑定 接触AngularJS许了,时常问自己一些问题,如果是我实现它,会在哪些方面选择跟它相同的道路,哪些方面不同。为此,记录了一些思考,给自己回顾,也供他人参考。 初步大致有以下几个方面: ...
Realtek PCIe GBE Family Controller 驱动
opto22 SNAP-PAC-S SERIES controller产品数据手册rar,opto22 SNAP-PAC-S SERIES controller产品数据手册
3、可大大提高开发效率,数据表创建完以后,自动生成entity,mapper.xml,dao,service,controller,vo,dto相关代码。 4、本项目集成了spring,aop,mybatis plus,swagger2,异常处理,分页,freemarker等多种技术。 5、操作...
EMC ViPR Controller虚拟数据中心配置指南.pdf