Spring Validation和Hibernate Validator結(jié)合國際化代碼實(shí)例
一、Spring Validation是什么?
日常開發(fā)中, 我們需要對(duì)請求參數(shù)進(jìn)行非空、長度、正確性進(jìn)行校驗(yàn), 如果不使用Spring Validation,那我們會(huì)在代碼中寫很多的if來校驗(yàn), 這樣做也可以,但不優(yōu)雅, 為了優(yōu)雅的進(jìn)行入?yún)⑿r?yàn), 此時(shí)我們就需要Spring Validation.
二、項(xiàng)目說明
1.引入依賴
依賴如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--lombok插件--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--驗(yàn)證包--> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <!--hibernate validator依賴--> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.1.6.Final</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.74</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.0-jre</version> </dependency>
2.代碼介紹
多語言和Spring Validation Bean初始化:
package com.zzb.valid.config; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.validation.Validator; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.nio.charset.StandardCharsets; /** * @author create by zhouzongbo on 2020/10/27. */ @Configuration public class MessageConfig implements WebMvcConfigurer { /** * 初始化多語言 * @return MessageSource */ @Bean public MessageSource resourceBundleMessageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setDefaultEncoding(StandardCharsets.UTF_8.toString()); // 多語言文件地址. messageSource.addBasenames("i18n/valid"); return messageSource; } /** * 本地校驗(yàn)工廠bean * @return LocalValidatorFactoryBean */ @Bean public LocalValidatorFactoryBean localValidatorFactoryBean() { LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean(); // 設(shè)置消息源 bean.setValidationMessageSource(resourceBundleMessageSource()); return bean; } @Bean public MethodValidationPostProcessor validationPostProcessor() { MethodValidationPostProcessor processor = new MethodValidationPostProcessor(); processor.setValidator(localValidatorFactoryBean().getValidator()); return processor; } @Override public Validator getValidator() { return localValidatorFactoryBean(); } }
全局異常處理代碼片段: Spring Validation 如果在校驗(yàn)時(shí)出現(xiàn)了異常, 會(huì)拋出org.springframework.web.bind.MethodArgumentNotValidException, 因此這里對(duì)MethodArgumentNotValidException進(jìn)行攔截, 然后重新組裝返回信息.
@ExceptionHandler(value = MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ResultEntity<?> test(MethodArgumentNotValidException ex) { String errorMessage = buildErrorMessage(ex.getBindingResult()); return ResultEntity.failure(errorMessage); }
重新組裝異常信息
private String buildErrorMessage(BindingResult result) { StringBuilder builder = new StringBuilder(); for (FieldError error : result.getFieldErrors()) { final String defaultMessage = error.getDefaultMessage(); if (hasDefaultMessage(error)) { builder.append(defaultMessage).append("\n"); } else { // 提取錯(cuò)誤屬性值. 比如@Range 那么錯(cuò)誤屬性值包含min 和max final Object[] arguments = error.getArguments(); Object[] args; if (arguments == null || 1 == arguments.length) { args = new Object[0]; } else { args = new Object[arguments.length - 1]; System.arraycopy(arguments, 1, args, 0, args.length); } // 獲取錯(cuò)誤信息. final String code = I18nUtil.getMessage(error.getCode(), args); final String field = I18nUtil.getMessage(error.getField(), "", args); if (StringUtils.isEmpty(field)) { builder.append("[").append(error.getField()).append("]: "); } else { builder.append(field); } builder.append(StringUtils.isEmpty(code) ? defaultMessage : code).append("\n"); } } for (ObjectError globalError : result.getGlobalErrors()) { builder.append(globalError.getDefaultMessage()).append("\n"); } return builder.toString(); }
3.自定義約束注解
用戶名長度校驗(yàn)注解:
@Target(value = { ElementType.FIELD, ElementType.METHOD }) @Retention(value = RetentionPolicy.RUNTIME) @Repeatable(UsernameLength.List.class) @Constraint(validatedBy = UsernameLengthValidator.class) // public @interface UsernameLength { String message() default "{com.zzb.valid.util.validator.UsernameLength}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; /** * 允許添加多個(gè)重復(fù)注解. */ @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List { UsernameLength[] value(); } }
用戶名長度校驗(yàn)Validator: 這里需要實(shí)現(xiàn)javax.validation.ConstraintValidator用于定義具體的校驗(yàn)規(guī)則,這里只校驗(yàn)了字符串的長度.
public class UsernameLengthValidator implements ConstraintValidator<UsernameLength, String> { public static final int MAX_LENGTH = 20; public static final int MIN_LENGTH = 1; @Override public boolean isValid(String value, ConstraintValidatorContext context) { return !StringUtils.isEmpty(value) && value.length() >= MIN_LENGTH && value.length() <= MAX_LENGTH; } }
4.測試用例
從valid.properties中讀取異常提示信息,從而適配多語言.
4.1中文環(huán)境異常提示信息
4.2 英文環(huán)境異常提示信息.
此處與中文唯一不同的地方是把Accept-Language 設(shè)置為英文環(huán)境.
5.調(diào)用鏈
org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#resolveArgument org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#resolveArgument org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver#validateIfApplicable org.springframework.validation.DataBinder#validate(java.lang.Object...) org.springframework.validation.DataBinder#getInternalBindingResult org.springframework.validation.beanvalidation.LocalValidatorFactoryBean # 使用個(gè)factoryBean進(jìn)行校驗(yàn). org.springframework.boot.autoconfigure.validation.ValidatorAdapter#validate(java.lang.Object, org.springframework.validation.Errors) org.springframework.validation.beanvalidation.SpringValidatorAdapter#validate(java.lang.Object, org.springframework.validation.Errors) org.springframework.validation.beanvalidation.SpringValidatorAdapter#determineField
到此這篇關(guān)于Spring Validation和Hibernate Validator結(jié)合國際化代碼實(shí)例的文章就介紹到這了,更多相關(guān)Validation和Validator結(jié)合國際化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談Java中常用數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)類 Collection和Map
下面小編就為大家?guī)硪黄獪\談Java中常用數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)類 Collection和Map。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-09-09Netty分布式NioEventLoop優(yōu)化selector源碼解析
這篇文章主要介紹了Netty分布式NioEventLoop優(yōu)化selector源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03從零開始學(xué)Java之關(guān)系運(yùn)算符
今天帶大家復(fù)習(xí)Java關(guān)系運(yùn)算符,文中對(duì)Java運(yùn)算符相關(guān)知識(shí)作了詳細(xì)總結(jié),對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們很有幫助,需要的朋友可以參考下2021-08-08Java實(shí)現(xiàn)學(xué)生信息管理界面
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)學(xué)生信息管理界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06關(guān)于SpringBoot簡介、官網(wǎng)構(gòu)建、快速啟動(dòng)的問題
SpringBoot 是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來簡化Spring應(yīng)用的初始搭建以及開發(fā)過程,這篇文章主要介紹了SpringBoot簡介、官網(wǎng)構(gòu)建、快速啟動(dòng),需要的朋友可以參考下2022-07-07