JSR-303 注解字段效验

JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。

一、引入maven

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

二、常用注解

111.jpg

注意事项:

  1. Controller类上需要加@Validated注解

  2. 入参是对象时,需要加上@Valid

    @RestController @RequestMapping( "/test") @Validated public class TestController {

     @RequestMapping(value = "/queryName", method = RequestMethod.GET)
     public String queryName(@NotNull(message = "name not null") String name) {
         return name;
     }
    
     @RequestMapping(value = "/queryMan", method = RequestMethod.POST)
     public Man queryMan(@Valid Man man, BindingResult bindingResult) {
         return man;
     }
    

    }

三、统一异常处理

  • 校验注解使用在实体参数上时,spring抛出org.springframework.web.bind.MethodArgumentNotValidException异常。
  • 校验注解使用在方法入参上时,spring抛出javax.validation.ConstraintViolationException异常。

针对上述两种情况,可以做统一的拦截并封装成统一的系统异常

import lombok.extern.slf4j.Slf4j;
import org.linbo.demo.validator.bean.HttpResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

@ControllerAdvice
@ResponseBody
@Slf4j
public class DefaultExceptionHandler {

    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public HttpResult<Object> springValidException(MethodArgumentNotValidException e) {
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        StringBuilder buf = new StringBuilder();
        allErrors.forEach(error -> {
            String objectName = ((FieldError) error).getField();
            String message = error.getDefaultMessage();
            buf.append(objectName).append(":").append(message).append(", ");
        });
        int len = buf.length();
        if (len > 1) {
            buf.delete(len - 2, len);
        }
        HttpResult<Object> data = HttpResult.builder()
                .code("400")
                .message(buf.toString())
                .build();
        log.warn("参数校验错误: {}", data);
        return data;
    }

    @ExceptionHandler(value = {ConstraintViolationException.class})
    public HttpResult<Object> jsr303ValidException(ConstraintViolationException e) {
        HttpResult<Object> data = HttpResult.builder()
                .code("400")
                .message(e.getMessage())
                .build();
        log.warn("参数校验错误: {}", data);
        return data;
    }

}

四、分组解决校验

//1、定义Groups
public class Groups {
    public interface Add{}
    public interface Update{}
}


//2、定义接口Validated的Groups
@RequestMapping(value = "/queryMan", method = RequestMethod.POST)
public Man queryMan(@Validated(Groups.Add.class) Man man, BindingResult bindingResult) {
    return man;
}

//3、实体类定义groups
@Getter
@Setter
public class Man{
    @NotNull(message = "name cannot not null",groups = Groups.Add.class)
    @Null(message = "name must null",groups = Groups.Update.class)
    private String name;

    @Email
    private String email;
}

五、自定义校验注解

//1、创建自定义注解
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

/**
 * 无敏感词校验注解
 */
@Documented
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NoSensitiveWordsValidator.class)
public @interface NoSensitiveWords {

    String message() default "包含敏感词";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

//2、自定义注解对应的校验类
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;

/**
 * 敏感词校验逻辑
 **/
public class NoSensitiveWordsValidator implements ConstraintValidator<NoSensitiveWords, String> {

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null || "".equals(value.trim())) {
            return true;
        }
        // 这里只简单举例校验
        Set<String> sensitiveWords = new HashSet<>();
        sensitiveWords.add("毛泽东");
        sensitiveWords.add("邓小平");
        for (String word : sensitiveWords) {
            if (value.contains(word)) {
                return false;
            }
        }
        return true;
    }
}

//3、在类属性或方法入参上使用自定义注解
@Data
public class Account {

    /** 昵称 */
    @Length(min = 2, max = 20)
    @NoSensitiveWords
    private String nickName;
}

六、国际化

标签需要加在属性上,NotEmpty标签String的参数不能为空

@Data
public class DemoDto {

    @NotEmpty(message = "{demo.key.null}")
    @Length(min = 5, max = 25, message = "{demo.key.length}")
    private String key;
}

添加上ValidationMessages文件

国际化配置文件必须放在classpath的根目录下,即src/java/resources的根目录下。 国际化配置文件必须以ValidationMessages开头,比如ValidationMessages.properties 或者 ValidationMessages_en.properties。

demo.key.null=demo的key不能为空,这里是validationMessage
demo.key.length=demo的key长度不正确

返回结果

{
    "code": 500,
    "msg": "demo的key不能为空,这里是validationMessage;",
    "content": null
}

自定义properties文件 SpringBoot 国际化验证 @Validated 的 message 国际化资源文件默认必须放在 resources/ValidationMessages.properties 中。 想把资源文件放到 resources/message/messages_zh.properties 中,需要重写WebMvcConfigurerAdapter 的 getValidator 方法,但WebMvcConfigurerAdapter在springboot2中已经废弃了,可以改为使用WebMvcConfigurationSupport。

@Configuration
public class ValidatorConfiguration extends WebMvcConfigurationSupport {
    @Autowired
    private MessageSource messageSource;

    @Override
    public Validator getValidator() {
        return validator();
    }

    @Bean
    public Validator validator() {
        LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
        validator.setValidationMessageSource(messageSource);
        return validator;
    }
}

最后得到结果为:

{
    "code": 500,
    "msg": "demo的key不能为空ID:{0};",
    "content": null
}

已有 0 条评论

    欢迎您,新朋友,感谢参与互动!