本文将记载在SpringBoot开发中怎么装备国际化,怎么装备Validator数据校验,以及怎么将两者合作在一起运用。
国际化装备
什么是i18n目录
i18n目录内含三个装备文件:(全称是internationalization,国际化)
- messages.properties
- messages_en_US.properties
- message_zh_CN.properties
这些装备文件保护了一些键值对,如not.null=* 有必要填写
等,便利咱们在反常处理、日志打印、数据校验等场景下回来对应言语的过错音讯。国家化装备还能够结合Validator注解进行运用,如user.username.length.valid=账户长度有必要在{min}到{max}个字符之间
,将在下文解说怎么装备。
假如需求装备其它言语,能够依照国际化资源文件命名标准命名。如日本:ja_JP
等,然后写上对应言语的提示音讯即可。
Yml文件装备
装备Spring的国际化资源文件途径。
spring:
message:
basename: i18n/messages
国际化装备类
国际化装备类I18nConfig
主要做了以下几件事情:
- 注入I18nLocaleResolver国际化解析器。它完成了LocaleResolver区域解析器。里面有两个办法,只需求重写一个即可。
- 重写resolveLocale办法,大致原理:
- 拿到Request请求头的content-language,运用下划线分割,分别是言语和国家。
- 实例化Locale目标并回来。
@Configuration
public class I18nConfig {
@Bean
public LocaleResolver localeResolver() {
return new I18nLocaleResolver();
}
/**
* 获取请求头国际化信息
*/
static class I18nLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
String language = httpServletRequest.getHeader("content-language");
Locale locale = Locale.getDefault();
if (StrUtil.isNotBlank(language)) {
String[] split = language.split("_");
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
}
封装国际化东西类
咱们还能够封装一个国际化东西类,可用于记载日志的时候获取直接获取国际化内的报错信息。
具体步骤:
- 从容器拿到MessageSource。
- 封装一个静态办法,调用MessageSource的getMessage办法,传入code、参数、区域即可获取国际化音讯。其间code对应properties文件中的key,args对应音讯中的占位符。
值得一提的的是:LocaleContextHolder是Spring的区域上下文持有者,在i18n装备文件中咱们会将请求头的Locale注入到上下文,这样这里就能够拿得到。检查源码咱们能够得知LocaleContextHolder是和当时线程关联的,这就意味着MessageUtils是在当时线程才有效的,假如切换线程,是不会发收作用的。
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MessageUtils {
private static final MessageSource MESSAGE_SOURCE = SpringUtils.getBean(MessageSource.class);
/**
* 依据音讯键和参数 获取音讯 托付给spring messageSource
* * @param code 音讯键
* @param args 参数
* @return 获取国际化翻译值
*/
public static String message(String code, Object... args) {
return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
}
}
试验:引入线程池,调查MessageUtils是否收效,结果:发现不会收效。
@RestController
@RequiredArgsConstructor
public class TestController{
private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
public String msg4(){
Future<String> submit = threadPoolTaskExecutor.submit(()->{
String msg = MessageUtils.message("user.username.length.valid","1","0");
log.info("msg:{}",msg);
return message;
});
return submit.get();
}
}
运用场景
-
反常抛出中,用国际化回来过错信息。
- 例如:
throw new UserException("user.not.exists",username)
, - 这里有个不错的实践经验:咱们在反常的基类中重写了getMessage办法,运用MessageUtils通过国际化回来对应的过错信息。
- 例如:
-
打印日志中,能够用国际化的key便利地打印过错信息。
- 能够合作占位符替换参数,只需求传入到MessageUtils内的args数组即可。
- 在国际化的properties文件中,用
{0}
、{1}
等作为参数替换。 - 比方:
MessageUtils.message("user.not.exists","ajaxzhan")
,就会将{0}
替换为ajaxzhan
并回来。
-
合作Validator结构运用,比方
用户长度有必要在{min}到{max}个字符之间
,就运用min和max来替换。
Validator校验结构
JSR-303 是 JAVA EE 6 中的一项子标准,叫做 Bean Validation,官方参阅完成是Hibernate Validator。为了避免在事务代码中参杂过多验证代码,咱们一般运用Validation提供的相关注解进行校验。下面演示怎么在SpringBoot项目中集成Validation相关功能。
Maven装备
<!-- 自定义验证注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
ValidatorConfig装备类
- 注入MessageSource,用于国际化装备。
- 实例化工厂LocalValidatorFactoryBean,设置:
- 设置国际化:将MessageSource设置到ValidationMessageSource
- 设置提供者类(校验器):HibernateValidator
-
设置属性:实例化
Properties
,装备Hibernate的快速反常回来,hibernate.validator.fail_fast
,加入到工厂装备。(快速回来指的是遇到一个不合法的,就不持续往下校验。) - 加载装备:调用factoryBean的afterPropertiesSet
- 回来工厂办法的Validator
这里能够顺便谈谈关于Spring的FactoryBean:
- FactoryBean是接口,完成该接口的类能够自定义创立Bean。一般在结构中用来创立杂乱的Bean。
- 这里的FactoryBean,完成
InitializingBean
接口,在afterPropertiesSet
办法中创立bean,会在 bean 实例化后调用。- FactoryBean让Bean构建进程更灵敏,能够理解为一种策略形式,咱们需求生成什么样的 bean,能够通过完成接口来自定义。
@Configuration
public class ValidatorConfig {
@Autowired
private MessageSource messageSource;
/**
* 装备校验结构 快速回来形式
*/
@Bean
public Validator validator() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
// 国际化
factoryBean.setValidationMessageSource(messageSource);
// 设置运用 HibernateValidator 校验器
factoryBean.setProviderClass(HibernateValidator.class);
Properties properties = new Properties();
// 设置 快速反常回来
properties.setProperty("hibernate.validator.fail_fast", "true");
factoryBean.setValidationProperties(properties);
// 加载装备
factoryBean.afterPropertiesSet();
return factoryBean.getValidator();
}
}
封装ValidatorUtils东西类
- 从IoC容器拿到Validator
- 调用validate办法进行校验。
- 需求合作
javax.validation
相关注解,对实体类加上相关注解。
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ValidatorUtils {
private static final Validator VALID = SpringUtils.getBean(Validator.class);
public static <T> void validate(T object, Class<?>... groups) {
Set<ConstraintViolation<T>> validate = VALID.validate(object, groups);
if (!validate.isEmpty()) {
throw new ConstraintViolationException("参数校验反常", validate);
}
}
}
Validation常见注解:(用于实体类的field上,加多个注解为“且”的联系)
-
@NotBlank(message = "xxx不能为空")
,只能用于String类型 @Size(min=0,max=30,message="xxx长度有必要在{min}和{max}个字符之间")
@NotNull(message="ID不能为空")
-
@NotEmpty
:用于集合、String类不能为空且size>0 -
@Length
:String类型 -
@Pattern(regexp="正则表达式",message="首字母有必要大写")
:正则 -
@Email
:邮箱 @Min(value=0,message="")
@Max
@AssertTrue
完成校验的两种方法:
- 在Controller层的办法参数上,加上
@Validated
注解。(常用) - 运用ValidatorUtils,用编码方法传入实体类进行校验。(在导入导出场景常用)
合作国际化装备运用
假设国际化装备文件中,length.not.valid=长度有必要在{min}和{max}
之间,那么咱们能够直接这样用:
@Size(min=4,max=30,message="length.not.valid")
这样做就能够达到国际化装备的作用。
分组校验
-
需求:接口A需求校验实体的X字段,接口B需求校验实体的Y字段,而咱们直接运用
@Validated
注解,是会全部校验的。 -
分组校验:通过添加一些无意义的空接口,比方
AddGroup
,UpdateGroup
,QueryGroup
,咱们能够用于区分不同的适用场景。 -
具体运用:
- 首先在实体类的注解上,加上group。比方,
@NotNull(message=xxx,groups={AddGroup.class})
-
假如运用ValidatorUtils:直接在第二个参数传入group的clazz目标,例如
ValidatorUtils.validate(sysUser,AddGroup.class)
- 假如运用
@Validated
,只需求加上@Validated(AddGroup.class)
- 首先在实体类的注解上,加上group。比方,