- 浏览: 50430 次
- 性别:
- 来自: 南京
文章分类
最新评论
springmvc开发中,经常需将界面日期数据(String)转换成后台模型的日期类型(Date)数据。
不同版本的springmvc可能有不同的处理方法,或者版本越高,处理方法越优化
实验的几种方式
应用场景1:
应用场景2:
1. @InitBinder--initBinder
spring 3.2.2(与标题无关)
UserController extends MultiActionController
springmvc配置:
如果没有配置<mvc:annotation-driven />,@InitBinder将不起作用。此时对于继不继承MultiActionController已经没有意义,请求地址是通过注解的方式注册的
为什么@InitBinder需配合<mvc:annotation-driven />才起作用?
2.@Override--initBinder
UserController extends MultiActionController
springmvc配置:
此时,springmvc的映射器配置为SimpleUrlHandlerMapping,并且继承MultiActionController,覆盖父类中initBinder的定义,如:
3.自定义webBindingInitializer
这个与第二个有异曲同工之处,只不过方式不一样,相比于第二种的继承,这种方式更符合spring的开闭原则
或
还留下其它的一些扩展点如;
validators
对于以上1,3种方式,handlerMapping是通过注解配置,而第二种方式是通过xml配置实现映射器
4.在model中设置注解@DateTimeFormat(pattern = "yyyy-MM-dd")
spring配置
<mvc:annotation-driven />会注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter,由这2个类来处理@DateTimeFormat。
相当于:
上述各种转换方法中,其实有时是相通的,一开始都是用xml去配置,只不过后来优化,直接使用注解配置的方式,代替了纯xml中配置各种bean的过程。
这种简化也是spring迭代升级中的一种趋势,用注解代替xml。但是对于开发者来说,一定程度上,也屏蔽的底端的实现和原理
附:源码分析
MultiActionController#bind
1.
binder.bind(request); 跟踪进去,调用PropertyEditor,conversionService中类型转换
2.
绑定数据结束后,调用校验validators
BeanWrapperImpl#convertIfNecessary
this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);
TypeConverterDelegate#convertIfNecessary
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
首先判断editor是否为空,不为空就用editor进行类型转换,否则如果conversionService不为空,则使用conversionService进行类型转换
TypeConverterDelegate的构造时,传入BeanWrapperImpl实例,即propertyEditorRegistry
参考:
Validation, Data Binding, and Type Conversion
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html
解决java - spring mvc one init binder for all controllers
http://www.itkeyword.com/doc/5230440400468034x402/spring-mvc-one-init-binder-for-all-controllers
https://stackoverflow.com/questions/12486512/spring-mvc-initbinder-is-not-called-when-processing-ajax-request
不同版本的springmvc可能有不同的处理方法,或者版本越高,处理方法越优化
实验的几种方式
public class User { private int id; private String username; private String password; private Date birth; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", password=" + password + ", birth=" + birth + "]"; } }
应用场景1:
@Controller public class UserController { /** * 登陆 * @param request * @param response * @return */ @RequestMapping(value = "/login.do", method = RequestMethod.POST) public ModelAndView login(HttpServletRequest request, HttpServletResponse response, User user){ } }
应用场景2:
public class UserController extends MultiActionController{ /** * 登陆 * @param request * @param response * @return */ public ModelAndView login(HttpServletRequest request, HttpServletResponse response, User user){ } } }
1. @InitBinder--initBinder
spring 3.2.2(与标题无关)
UserController extends MultiActionController
@InitBinder public void initBinder(WebDataBinder binder) { System.out.println("@InitBinder-initBinder"); DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); CustomDateEditor dateEditor = new CustomDateEditor(df, true); binder.registerCustomEditor(Date.class, dateEditor); }
springmvc配置:
<context:component-scan base-package="com.byron.controller" /> <mvc:annotation-driven />
如果没有配置<mvc:annotation-driven />,@InitBinder将不起作用。此时对于继不继承MultiActionController已经没有意义,请求地址是通过注解的方式注册的
为什么@InitBinder需配合<mvc:annotation-driven />才起作用?
2.@Override--initBinder
UserController extends MultiActionController
@Override protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception { /*binder.setAutoGrowNestedPaths(true); binder.setAutoGrowCollectionLimit(1024); */ DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); CustomDateEditor dateEditor = new CustomDateEditor(df, true); binder.registerCustomEditor(Date.class, dateEditor); System.out.println("hi, i am initBinder"); }
springmvc配置:
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/login.do">loginAction</prop> </props> </property> </bean> <bean id="loginAction" class="com.byron.controller.UserController"> <property name="methodNameResolver"> <ref local="methodNameResolver"/> </property> </bean> <bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <property name="paramName"><value>method</value></property> <property name="defaultMethodName"><value>execute</value></property> </bean>
此时,springmvc的映射器配置为SimpleUrlHandlerMapping,并且继承MultiActionController,覆盖父类中initBinder的定义,如:
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception { if (this.webBindingInitializer != null) { this.webBindingInitializer.initBinder(binder, new ServletWebRequest(request)); } }
3.自定义webBindingInitializer
这个与第二个有异曲同工之处,只不过方式不一样,相比于第二种的继承,这种方式更符合spring的开闭原则
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="cacheSeconds" value="0"/> <property name="webBindingInitializer"> <bean class="com.byron.controller.util.MyWebBindingInitializer"/> </property> </bean> <context:component-scan base-package="com.byron.controller" /> <mvc:annotation-driven />
或
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/login.do">loginAction</prop> </props> </property> </bean> <bean id="loginAction" class="com.byron.controller.UserController"> <property name="methodNameResolver"> <ref local="methodNameResolver"/> </property> </bean> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="cacheSeconds" value="0"/> <property name="webBindingInitializer"> <bean class="com.byron.controller.util.MyWebBindingInitializer"/> </property> </bean>
还留下其它的一些扩展点如;
validators
对于以上1,3种方式,handlerMapping是通过注解配置,而第二种方式是通过xml配置实现映射器
4.在model中设置注解@DateTimeFormat(pattern = "yyyy-MM-dd")
spring配置
<context:component-scan base-package="com.byron.controller" /> <mvc:annotation-driven />
<mvc:annotation-driven />会注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter,由这2个类来处理@DateTimeFormat。
相当于:
<mvc:annotation-driven conversion-service="conversionService"/> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <list> <!-- <bean class="com.*.StringToBeanConverter" /> --> </list> </property> </bean>
上述各种转换方法中,其实有时是相通的,一开始都是用xml去配置,只不过后来优化,直接使用注解配置的方式,代替了纯xml中配置各种bean的过程。
这种简化也是spring迭代升级中的一种趋势,用注解代替xml。但是对于开发者来说,一定程度上,也屏蔽的底端的实现和原理
附:源码分析
MultiActionController#bind
protected void bind(HttpServletRequest request, Object command) throws Exception { logger.debug("Binding request parameters onto MultiActionController command"); ServletRequestDataBinder binder = createBinder(request, command); binder.bind(request); if (this.validators != null) { for (Validator validator : this.validators) { if (validator.supports(command.getClass())) { ValidationUtils.invokeValidator(validator, command, binder.getBindingResult()); } } } binder.closeNoCatch(); }
1.
binder.bind(request); 跟踪进去,调用PropertyEditor,conversionService中类型转换
2.
绑定数据结束后,调用校验validators
BeanWrapperImpl#convertIfNecessary
private Object convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<?> requiredType, TypeDescriptor td) throws TypeMismatchException { try { return this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td); } catch (ConverterNotFoundException ex) { PropertyChangeEvent pce = new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue); throw new ConversionNotSupportedException(pce, td.getType(), ex); } catch (ConversionException ex) { PropertyChangeEvent pce = new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue); throw new TypeMismatchException(pce, requiredType, ex); } catch (IllegalStateException ex) { PropertyChangeEvent pce = new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue); throw new ConversionNotSupportedException(pce, requiredType, ex); } catch (IllegalArgumentException ex) { PropertyChangeEvent pce = new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue); throw new TypeMismatchException(pce, requiredType, ex); } }
this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);
TypeConverterDelegate#convertIfNecessary
public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException { Object convertedValue = newValue; // Custom editor for this type? PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName); ConversionFailedException firstAttemptEx = null; // No custom editor but custom ConversionService specified? ConversionService conversionService = this.propertyEditorRegistry.getConversionService(); if (editor == null && conversionService != null && convertedValue != null && typeDescriptor != null) { TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue); TypeDescriptor targetTypeDesc = typeDescriptor; if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) { try { return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc); } catch (ConversionFailedException ex) { // fallback to default conversion logic below firstAttemptEx = ex; } } } // Value not of required type? if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) { if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) { TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor(); if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) { convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue); } } if (editor == null) { editor = findDefaultEditor(requiredType); } convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor); } }
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
首先判断editor是否为空,不为空就用editor进行类型转换,否则如果conversionService不为空,则使用conversionService进行类型转换
TypeConverterDelegate的构造时,传入BeanWrapperImpl实例,即propertyEditorRegistry
参考:
Validation, Data Binding, and Type Conversion
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html
解决java - spring mvc one init binder for all controllers
http://www.itkeyword.com/doc/5230440400468034x402/spring-mvc-one-init-binder-for-all-controllers
https://stackoverflow.com/questions/12486512/spring-mvc-initbinder-is-not-called-when-processing-ajax-request
发表评论
-
spring疑难解惑-循环依赖的解决
2020-06-17 23:27 542AbstractAutowireCapableBeanFact ... -
spring容器
2019-07-14 08:47 305private final ServletContainer ... -
spring容器
2019-07-13 23:35 0spring容器与springmvc容器 73 ... -
spring源码学习系列2.6-spring ioc原理-codes
2019-03-05 22:56 488web.xml <listener> < ... -
spring源码学习系列3.4-spring mvc原理-codes
2019-01-21 22:46 297本篇章从核心类角度解读springmvc的原理 web.xm ... -
spring源码学习系列4.2-spring aop原理-codes
2018-12-04 22:29 562jdk: Proxy InvocationHandler ... -
spring源码学习系列4.1-spring实现对ibatis的事务管理
2018-09-17 15:44 578事务由spring管理,可以理解为由spring管理数据库连接 ... -
spring源码学习系列4-3种常用的自动代理创建器
2018-09-02 15:48 5713种自动代理器是 AnnotationAwareAspectJ ... -
spring源码学习系列1.2-spring事务代理深入分析2
2018-05-27 19:46 452提示: BeanPostProcessor AopUtils ... -
spring源码学习系列2.5-ApplicationContext初始化-设计模式
2018-05-08 15:17 519ApplicationContext容器的初始化可以通过模板方 ... -
spring源码学习系列3.3-DispatcherServlet初始化-设计模式
2018-05-07 11:12 623springmvc的核心是DispatcherServlet ... -
封装spring-security
2018-01-23 19:33 519github地址: https://github.com/ne ... -
eclipse导入spring源码
2018-05-12 07:20 980spring在git上的项目时gradle管理jar包的,所以 ... -
spring源码学习系列3.2.3-异常页面拦截机制
2017-07-29 19:07 768前序:本文的意义在于了解 tomcat处理异常 请求访问 ... -
spring源码学习系列3.2.1-command对象的绑定
2017-05-28 12:00 982在<spring源码学习系列3.2-handlerAda ... -
spring源码学习系列3.2-handlerAdapter执行
2017-05-28 12:01 409DispatcherServlet#doDispatch中调用 ... -
spring源码学习系列3.1-handlerMapping初始化
2017-05-28 11:56 702SimpleUrlHandlerMapping的继承体系 or ... -
spring源码学习系列2.4-finishRefresh会做什么
2017-05-06 16:36 578spring容器初始化完成后,调用finishRresh 该 ... -
spring源码学习系列3-springmvc原理
2017-05-28 11:56 458问题: springmvc是如何控 ... -
spring源码学习系列2-容器初始化入口-refresh
2017-04-23 21:33 477context=XmlWebApplicationContex ...
相关推荐
rubyinstaller-3.2.2-1-x64
azarus-2.2.6-fpc-3.2.2-win64
本次分享的是Collections库的3.2.2版本,即"commons-collections-3.2.2-bin.zip",这是一个二进制发行版,包含了可直接使用的jar文件。 Apache Commons Collections的核心在于其对Java内置集合类的增强和补充。它...
赠送原API文档:commons-collections-3.2.2-javadoc.jar; 赠送源代码:commons-collections-3.2.2-sources.jar; 赠送Maven依赖信息文件:commons-collections-3.2.2.pom; 包含翻译后的API文档:commons-...
`commons-collections-3.2.2-bin.tar`是一个压缩包,它包含了Apache Commons Collections库的3.2.2版本。这个库是Java编程语言中一个非常重要的工具集,专门用于处理集合框架,如列表、映射、集合等。Apache Commons...
这个"commons-collections-3.2.2-"版本是该库的一个特定发行版,主要用于解决WebLogic服务器上的反序列化漏洞问题。 在Java编程中,集合框架是处理对象数组的重要组成部分。Apache Commons Collections扩展了Java...
matplotlib-3.2.2-cp38-cp38-win_amd64
zendoptimizer-3.2.2-windows-i386.exe
"restclient-ui-3.2.2-jar-with-dependencies" 是一个针对RESTful API测试的用户界面工具,它的主要功能是帮助开发者和测试人员便捷地进行接口测试。REST(Representational State Transfer)是一种网络应用程序的...
赠送原API文档:commons-collections-3.2.2-javadoc.jar; 赠送源代码:commons-collections-3.2.2-sources.jar; 赠送Maven依赖信息文件:commons-collections-3.2.2.pom; 包含翻译后的API文档:commons-...
内容概要:由于cdh6.3.2的spark版本为2.4.0,并且spark-sql被阉割,现基于cdh6.3.2,scala2.12.0,java1.8,maven3.6.3,,对spark-3.2.2源码进行编译 应用:该资源可用于cdh6.3.2集群配置spark客户端,用于spark-sql
这个源码包"mybatis-3.2.2-src.rar"包含了完整的Mybatis 3.2.2版本的源代码,对开发者来说是一份宝贵的学习资源。 源码分析可以从以下几个主要方面展开: 1. **架构设计**:Mybatis 的核心组件包括...
《深入解析Spring Framework 3.2.2》 Spring Framework是Java开发领域中不可或缺的开源框架,它以其灵活、强大的特性以及对IoC(Inversion of Control)和AOP(Aspect Oriented Programming)的支持,成为了企业级...
matplotlib-3.2.2-cp37-cp37m-win32
matplotlib-3.2.2-cp37-cp37m-win_amd64
不需要解压,简单粗暴; 使用步骤: 选择External location----->external File------>mybatis-3.2.2-sources.jar(你本地资源),等myeclipse自动加载就直接可以看到源码了
《360 N6-TWRP-3.2.2-0 卡刷包详解及应用》 在智能手机世界中,刷机是一项常见的操作,它可以让用户根据个人喜好定制手机系统,提升性能或修复问题。360 N6-TWRP-3.2.2-0 卡刷包是针对360 N6手机的一款高级定制工具...
资源分类:Python库所属语言:Python资源全名:qt6_applications-6.0.3.2.2-py3-none-win_amd64.whl资源来源:官方安装方法:https://lanzao.blog.csdn.net/article/details/101784059
libzmq3-3.2.2-5.1.x86_64.rpm
官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装