Spring Validation和Hibernate Validator结合国际化代码实例

 更新时间:2023年10月09日 09:45:48   作者:蜡笔小久  
这篇文章主要介绍了Spring Validation和Hibernate Validator结合国际化代码实例,我们需要对请求参数进行非空、长度、正确性进行校验, 本文主要讲解Spring Validation 和 Hibernate Validator, 同时整合i18n(国际化)实现参数校验自动,需要的朋友可以参考下

一、Spring Validation是什么?

日常开发中, 我们需要对请求参数进行非空、长度、正确性进行校验, 如果不使用Spring Validation,那我们会在代码中写很多的if来校验, 这样做也可以,但不优雅, 为了优雅的进行入参校验, 此时我们就需要Spring Validation.

二、项目说明

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>
		<!--验证包-->
		<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;
    }
    /**
     * 本地校验工厂bean
     * @return LocalValidatorFactoryBean
     */
    @Bean
    public LocalValidatorFactoryBean localValidatorFactoryBean() {
        LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
        // 设置消息源
        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 如果在校验时出现了异常, 会抛出org.springframework.web.bind.MethodArgumentNotValidException, 因此这里对MethodArgumentNotValidException进行拦截, 然后重新组装返回信息.

@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 {
                // 提取错误属性值. 比如@Range 那么错误属性值包含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);
                }
                // 获取错误信息.
                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.自定义约束注解

用户名长度校验注解:

@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 {};
    /**
     * 允许添加多个重复注解.
     */
    @Target({ElementType.FIELD, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List {
        UsernameLength[] value();
    }
}

用户名长度校验Validator: 这里需要实现javax.validation.ConstraintValidator用于定义具体的校验规则,这里只校验了字符串的长度.

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中文环境异常提示信息

在这里插入图片描述

4.2 英文环境异常提示信息.

此处与中文唯一不同的地方是把Accept-Language 设置为英文环境.

在这里插入图片描述

5.调用链

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 # 使用个factoryBean进行校验.
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

到此这篇关于Spring Validation和Hibernate Validator结合国际化代码实例的文章就介绍到这了,更多相关Validation和Validator结合国际化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java9学习笔记之模块化详解

    java9学习笔记之模块化详解

    Java 9中最重要的功能,毫无疑问就是模块化(Module),下面这篇文章主要给大家介绍了关于java9学习笔记之模块化的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2018-04-04
  • 浅谈Java中常用数据结构的实现类 Collection和Map

    浅谈Java中常用数据结构的实现类 Collection和Map

    下面小编就为大家带来一篇浅谈Java中常用数据结构的实现类 Collection和Map。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • SpringBoot之使用枚举参数案例详解

    SpringBoot之使用枚举参数案例详解

    这篇文章主要介绍了SpringBoot之使用枚举参数案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • Java中值传递的深度分析

    Java中值传递的深度分析

    这篇文章主要给大家介绍了关于Java中值传递的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-04-04
  • 关于Java的Character类详解

    关于Java的Character类详解

    这篇文章主要介绍了关于Java的Character类详解,Java中的Character类是一个包装类,用于封装一个基本数据类型char的值,它提供了一些静态方法来操作字符,需要的朋友可以参考下
    2023-05-05
  • Netty分布式NioEventLoop优化selector源码解析

    Netty分布式NioEventLoop优化selector源码解析

    这篇文章主要介绍了Netty分布式NioEventLoop优化selector源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • 从零开始学Java之关系运算符

    从零开始学Java之关系运算符

    今天带大家复习Java关系运算符,文中对Java运算符相关知识作了详细总结,对正在学习java基础的小伙伴们很有帮助,需要的朋友可以参考下
    2021-08-08
  • Java实现学生信息管理界面

    Java实现学生信息管理界面

    这篇文章主要为大家详细介绍了Java实现学生信息管理界面,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • 关于SpringBoot简介、官网构建、快速启动的问题

    关于SpringBoot简介、官网构建、快速启动的问题

    SpringBoot 是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程,这篇文章主要介绍了SpringBoot简介、官网构建、快速启动,需要的朋友可以参考下
    2022-07-07
  • Maven访问仓库顺序代码实例解析

    Maven访问仓库顺序代码实例解析

    这篇文章主要介绍了Maven访问仓库顺序实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08

最新评论