本文将记载在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

  1. FactoryBean是接口,完成该接口的类能够自定义创立Bean。一般在结构中用来创立杂乱的Bean。
  2. 这里的FactoryBean,完成InitializingBean接口,在afterPropertiesSet办法中创立bean,会在 bean 实例化后调用。
  3. 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

完成校验的两种方法

  1. 在Controller层的办法参数上,加上@Validated注解。(常用)
  2. 运用ValidatorUtils,用编码方法传入实体类进行校验。(在导入导出场景常用)

合作国际化装备运用

假设国际化装备文件中,length.not.valid=长度有必要在{min}和{max}之间,那么咱们能够直接这样用:

@Size(min=4,max=30,message="length.not.valid")

这样做就能够达到国际化装备的作用。

分组校验

  • 需求:接口A需求校验实体的X字段,接口B需求校验实体的Y字段,而咱们直接运用@Validated注解,是会全部校验的。
  • 分组校验:通过添加一些无意义的空接口,比方AddGroupUpdateGroupQueryGroup,咱们能够用于区分不同的适用场景。
  • 具体运用

    • 首先在实体类的注解上,加上group。比方,@NotNull(message=xxx,groups={AddGroup.class})
    • 假如运用ValidatorUtils:直接在第二个参数传入group的clazz目标,例如ValidatorUtils.validate(sysUser,AddGroup.class)
    • 假如运用@Validated,只需求加上@Validated(AddGroup.class)

参阅文章

  1. FactoryBean浅显易懂-CSDN博客
  2. SpringBoot国际化装备-CSDN博客
  3. RuoYi-Vue-Plus: 后台管理体系 (gitee.com)