springmvc如何集成JSR-303进行数据验证在之前的如下文章中已经介绍过了:
SpringMVC数据验证——第七章 注解式控制器的数据验证、类型转换及格式化——跟着开涛学SpringMVC
举个例子:
比如我的验证
@Length(min = 5, max = 200, message = "{message.title.length.not.valid}") @Column(name = "title") private String title;
有朋友想得到min、max及此时的title值,可以在消息文件中通过:
当然也可以使用{value} 获取此时的title值
这到底是怎么工作的呢?
在JSR-303中,使用javax.validation.MessageInterpolator来解析消息,而如果:
<!-- 以下 validator ConversionService 在使用 mvc:annotation-driven 会 自动注册--> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/> <!-- 如果不加默认到 使用classpath下的 ValidationMessages.properties --> <property name="validationMessageSource" ref="messageSource"/> </bean>
即此时使用的hibernate实现,注入了spring的messageSource来解析消息时:
public void setValidationMessageSource(MessageSource messageSource) { this.messageInterpolator = HibernateValidatorDelegate.buildMessageInterpolator(messageSource); }
/** * Inner class to avoid a hard-coded Hibernate Validator 4.1+ dependency. */ private static class HibernateValidatorDelegate { public static MessageInterpolator buildMessageInterpolator(MessageSource messageSource) { return new ResourceBundleMessageInterpolator(new MessageSourceResourceBundleLocator(messageSource)); } }
即内部委托给了org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator#ResourceBundleMessageInterpolator:
并使用如下代码解析消息:
public String interpolate(String message, Context context) { // probably no need for caching, but it could be done by parameters since the map // is immutable and uniquely built per Validation definition, the comparison has to be based on == and not equals though return interpolateMessage( message, context.getConstraintDescriptor().getAttributes(), defaultLocale ); }
此处可以看到context.getConstraintDescriptor().getAttributes(),其作用是获取到注解如@Length上的所有数据,具体代码实现如下:
private Map<String, Object> buildAnnotationParameterMap(Annotation annotation) { final Method[] declaredMethods = ReflectionHelper.getDeclaredMethods( annotation.annotationType() ); Map<String, Object> parameters = new HashMap<String, Object>( declaredMethods.length ); for ( Method m : declaredMethods ) { try { parameters.put( m.getName(), m.invoke( annotation ) ); } catch ( IllegalAccessException e ) { throw log.getUnableToReadAnnotationAttributesException( annotation.getClass(), e ); } catch ( InvocationTargetException e ) { throw log.getUnableToReadAnnotationAttributesException( annotation.getClass(), e ); } } return Collections.unmodifiableMap( parameters ); }
循环每一个方法 并获取值放入map,接着进入方法:
private String interpolateMessage(String message, Map<String, Object> annotationParameters, Locale locale)
具体实现思路如下:
1、首先查询缓存中是否存在,如果存在直接获取缓存中解析的消息:
if ( cacheMessages ) { resolvedMessage = resolvedMessages.get( localisedMessage ); }
2、如果没有,按照JSR-303规定的使用三步获取:
首先委托给ResourceBundle获取消息值:
ResourceBundle userResourceBundle = userResourceBundleLocator .getResourceBundle( locale ); ResourceBundle defaultResourceBundle = defaultResourceBundleLocator .getResourceBundle( locale );
2.1、委托给用户定义的resourceBundle进行解析(即我们之前指定的messageSource),递归的查找消息并替换那些转义的:
// search the user bundle recursive (step1) userBundleResolvedMessage = replaceVariables( resolvedMessage, userResourceBundle, locale, true );
转义的包括:
\\{、\\}、\\\\。
所谓递归的查找意思就是如:
a=hello {b}
b=123
会在解析a时再递归解析b,如果{b}就是一个字符串,而不想被解析,可以通过\\{b\\}转移完成;
替换完转义字符后,还是会再递归的查找下去。
2.2、使用默认的resourceBundle(即默认找org.hibernate.validator.ValidationMessages.properties)按照和2.1一样的步骤执行:
// search the default bundle non recursive (step2) resolvedMessage = replaceVariables( userBundleResolvedMessage, defaultResourceBundle, locale, false ); evaluatedDefaultBundleOnce = true;
2.3、解析完成后,接着替换注解变量值:
// resolve annotation attributes (step 4) resolvedMessage = replaceAnnotationAttributes( resolvedMessage, annotationParameters ); // last but not least we have to take care of escaped literals resolvedMessage = resolvedMessage.replace( "\\{", "{" ); resolvedMessage = resolvedMessage.replace( "\\}", "}" ); resolvedMessage = resolvedMessage.replace( "\\\\", "\\" ); return resolvedMessage;
如之前说的
@Length(min = 5, max = 200, message = "{message.title.length.not.valid}")
消息:
标题长度必须在{min}到{max}个字符之间
那么,如果没有在之前的resourceBundle中得到替换,那么会被注解的值替换掉。
即得到标题长度必须在5到200个字符之间。
此处有一个小问题:
如果你的messageSource添加了:
<property name="useCodeAsDefaultMessage" value="true"/>
意思就是如果找不到key对应的消息,则使用code作为默认消息;这样会引发一个问题就是,根据code找消息,永远能找到,即不可能成功执行【2.3】。
如“标题长度必须在{min}到{max}个字符之间”,如果消息文件中没有min 和 max,实际得到的是:
”标题长度必须在min到max个字符之间“,不是我们期望的;
如“标题长度必须在\\{min\\}到max个字符之间”,实际也会获取到:
”标题长度必须在min到max个字符之间“,也不是我们期望的。
所以实际使用时useCodeAsDefaultMessage应该为false。
相关推荐
总的来说,SpringMVC与JSR-303的集成使得我们可以方便地在Bean级别进行数据验证,减少了手动检查输入数据的工作,提高了代码的可读性和维护性。同时,它提供了丰富的验证注解,满足了各种常见的数据校验需求。通过...
在SpringMVC中集成Spring Data Redis,可以利用Redis的高效特性来提升应用程序的数据处理能力,例如作为session共享的存储、缓存数据或者实现发布/订阅(Pub/Sub)功能。发布/订阅是一种通信模式,允许发送者(pub)将...
SpringMVC ---- HelloWorld ---- 代码 SpringMVC ---- HelloWorld ---- 代码 SpringMVC ---- HelloWorld ---- 代码 SpringMVC ---- HelloWorld ---- 代码 SpringMVC ---- HelloWorld ---- 代码 SpringMVC ---- Hello...
使用SpringMVC结合JSR-303进行数据校验的流程一般包括以下几个步骤: 1. 准备校验时使用的JAR包:在项目中添加validation-api和具体的实现库(如hibernate-validator),用于执行校验规则。 2. 编写需要校验的Java...
《SpringMVC-Mybatis-Shiro-Redis:构建安全高效的Web应用》 在现代Web开发中,构建一个高效且安全的后端系统是至关重要的。本文将深入探讨一个基于SpringMVC、Mybatis、Shiro和Redis的Web应用架构,这四个组件共同...
2. 配置Spring:在Spring配置文件中需要声明一个MessageSource的Bean,用于读取校验时使用的错误消息,同时定义一个LocalValidatorFactoryBean,它是一个实现了JSR-303校验器接口的Bean。通过配置这个校验器,可以...
【标题】"SpringMVC-Mybatis-Shiro-redis-master" 涉及的是一个集成框架项目,这个项目集成了四个关键的技术组件:SpringMVC、MyBatis、Shiro和Redis。这些技术在现代Java Web开发中扮演着重要角色。 **SpringMVC**...
项目中所需的jar包在压缩包中已提供,项目中用到了JSR303和hibernate-validator的技术,大量采用了注解@NotNull,@Email,@Length,@Max,@Pattern,@Size等,此外还采用了自定义注解,验证信息全部配置在属性文件中.
hibernate-validator-5.2.4.Final.jar hibernate-validator-annotation-processor-5.2.4.Final.jar hibernate-validator-cdi-5.2.4.Final.jar validation-api-1.1.0.Final.jar jboss-logging-3.2.1.Final.jar ...
默认情况下,Spring MVC使用了Jackson库来实现这一功能,因为Jackson具有高效且灵活的特性。 二、Jackson库解析 1. `jackson-databind-2.2.1.jar`:这是Jackson的核心模块,提供了对复杂JSON结构映射到Java对象的...
3. **模型绑定与数据验证**:SpringMVC支持模型绑定,可以把HTTP请求参数自动绑定到Java对象,同时提供数据验证功能,通过在模型对象上添加JSR-303/JSR-349注解进行验证。 4. **视图技术**:SpringMVC可以配合多种...
本资源包"SpringMVC精品资源--深入解析SpringMVC核心原理:从手写简易版MVC框架开始(SmartMvc).zip"旨在帮助开发者深入理解SpringMVC的工作机制,并通过构建一个简单的SmartMvc框架来实践这一过程。 1. **MVC模式...
SpringMVC和JAX-RS是两种在Java世界中广泛使用的Web开发框架,它们都用于构建RESTful服务,但有着不同的设计哲学和技术实现。这个压缩包"SpringMVC精品资源--JAX-RS & SpringMVC supported maven build.zip"显然是一...
本资料"springmvc-high-other-05.rar"着重探讨了SpringMVC的一些高级特性和用法,特别是那些不太常见但对提升应用性能和可维护性至关重要的特性。 1. **POM.xml配置解析**:在"pom.xml"文件中,我们可以看到项目...
此外,Spring MVC还支持数据验证,通过实现Validator接口或使用JSR-303/JSR-349 Bean Validation,可以对用户输入进行验证,确保数据的正确性和完整性。 总结来说,Spring MVC通过一系列机制实现了从前端页面到后端...
`@Valid` 注解配合 `JSR-303` 验证规则,可以实现数据的校验。 7. **异常处理** 通过全局异常处理器,如 `@ControllerAdvice` 和 `@ExceptionHandler` 注解,我们可以统一处理应用程序中抛出的异常,提供友好的...
SpringMVC4教程-.pptx SpringMVC4教程-.pptx SpringMVC4教程-.pptx SpringMVC4教程-.pptx SpringMVC4教程-.pptx
【标题】"SpringMVC精品资源--JAX-RS & SpringMVC supported gradle bui.zip" 提供的是一份关于使用Gradle构建支持JAX-RS和SpringMVC的项目资源。这涉及到两个关键的技术栈:SpringMVC,一个用于构建Web应用程序的...
SpringMVC文件上传war包
"springMVC-3.0-file-upload.rar" 包含了一个示例,展示了如何在Spring MVC应用中集成文件上传功能,这个例子的描述表明它是基于注解驱动的,这意味着我们将使用如`@Controller`、`@RequestMapping`等注解来定义控制...