springboot基础(85): validator验证器

文章目录

  • 内置校验器
      • [**一、`javax.validation.constraints` 包下的常用注解**](#一、javax.validation.constraints 包下的常用注解)
      • [**二、`org.hibernate.validator.constraints` 包下的常用注解(Hibernate Validator扩展)**](#二、org.hibernate.validator.constraints 包下的常用注解(Hibernate Validator扩展))
      • **三、注解使用示例**
      • [**四、在Spring Boot中使用注解**](#四、在Spring Boot中使用注解)
  • 自定义校验器

内置校验器

在Java中,javax.validation.constraints包和org.hibernate.validator.constraints包提供了丰富的注解,用于对Java Bean的字段进行验证。以下是这些注解的详细分类和示例:

一、javax.validation.constraints 包下的常用注解

  1. 空值校验

    • @Null:验证字段必须为null
    • @NotNull:验证字段不能为null
    • @NotEmpty:验证集合、数组或字符串不能为null且长度大于0。
    • @NotBlank:验证字符串不能为null,且去除首尾空格后长度大于0。
  2. 范围校验

    • @Size(min, max):验证字符串、集合或数组的长度在指定范围内。
    • @Min(value):验证数值字段的最小值。
    • @Max(value):验证数值字段的最大值。
    • @DecimalMin(value):验证字符串或数值字段的最小值(支持字符串表示的数值)。
    • @DecimalMax(value):验证字符串或数值字段的最大值(支持字符串表示的数值)。
    • @Digits(integer, fraction):验证数值字段的整数部分和小数部分的位数。
    • @Range(min, max):验证数值或字符串字段在指定范围内(Hibernate Validator扩展)。
  3. 布尔值校验

    • @AssertTrue:验证布尔字段必须为true
    • @AssertFalse:验证布尔字段必须为false
  4. 日期校验

    • @Future:验证日期字段必须是将来时间。
    • @FutureOrPresent:验证日期字段必须是将来或现在时间。
    • @Past:验证日期字段必须是过去时间。
    • @PastOrPresent:验证日期字段必须是过去或现在时间。
  5. 其他校验

    • @Email:验证字符串字段是否为合法的邮箱地址。
    • @Pattern(regexp):验证字符串字段是否符合指定的正则表达式。
    • @URL:验证字符串字段是否为合法的URL地址(Hibernate Validator扩展)。
    • @SafeHtml:验证字符串字段是否包含安全的HTML(防止XSS攻击,Hibernate Validator扩展)。

二、org.hibernate.validator.constraints 包下的常用注解(Hibernate Validator扩展)

  1. 长度校验

    • @Length(min, max):验证字符串字段的长度在指定范围内(与@Size类似,但仅适用于字符串)。
  2. 其他校验

    • @CreditCardNumber:验证字符串字段是否为合法的信用卡号。
    • @Currency:验证字符串字段是否为合法的货币值。
    • @EAN:验证字符串字段是否为合法的商品条码(EAN-13或EAN-8)。
    • @LuhnCheck:验证字符串字段是否通过Luhn算法校验(常用于信用卡号、IMEI等)。
    • @ScriptAssert:通过脚本(如JavaScript)进行复杂校验。
    • @UniqueElements:验证集合中的元素是否唯一。

三、注解使用示例

以下是一个完整的Java Bean示例,展示了如何使用上述注解进行字段验证:

java 复制代码
import javax.validation.constraints.*;
import org.hibernate.validator.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;

public class User {

    // 空值校验
    @NotNull(message = "用户ID不能为空")
    private Long id;

    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度必须在3到20个字符之间")
    private String username;

    // 范围校验
    @Min(value = 18, message = "年龄不能小于18岁")
    @Max(value = 120, message = "年龄不能大于120岁")
    private Integer age;

    @DecimalMin(value = "0.01", message = "金额不能小于0.01")
    @DecimalMax(value = "1000000.00", message = "金额不能大于1000000.00")
    private BigDecimal balance;

    // 日期校验
    @FutureOrPresent(message = "注册日期不能是将来时间")
    private LocalDate registrationDate;

    // 其他校验
    @Email(message = "邮箱格式不正确")
    private String email;

    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;

    @URL(message = "URL格式不正确")
    private String website;

    // Hibernate Validator扩展注解
    @Length(min = 6, max = 12, message = "密码长度必须在6到12个字符之间")
    private String password;

    @CreditCardNumber(message = "信用卡号不合法")
    private String creditCardNumber;

    @UniqueElements(message = "标签列表中不能有重复元素")
    private List<String> tags;

    // Getters and Setters
    // ...
}

四、在Spring Boot中使用注解

在Spring Boot中,可以通过以下方式启用字段验证:

  1. 添加依赖

    xml 复制代码
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
  2. 在Controller方法中使用@Valid@Validated

    java 复制代码
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;
    import javax.validation.Valid;
    
    @RestController
    @RequestMapping("/users")
    public class UserController {
    
        @PostMapping
        public ResponseEntity<String> createUser(@Valid @RequestBody User user) {
            return ResponseEntity.ok("用户创建成功");
        }
    
        @PutMapping("/{id}")
        public ResponseEntity<String> updateUser(
                @PathVariable Long id,
                @Validated(UpdateGroup.class) @RequestBody User user) {
            return ResponseEntity.ok("用户更新成功");
        }
    }
  3. 定义分组(可选)

    java 复制代码
    public interface CreateGroup {}
    public interface UpdateGroup {}
    
    public class User {
        @NotBlank(groups = CreateGroup.class, message = "创建时用户名不能为空")
        @NotBlank(groups = UpdateGroup.class, message = "更新时用户名不能为空")
        private String username;
    
        @Null(groups = CreateGroup.class, message = "创建时ID必须为空")
        @NotNull(groups = UpdateGroup.class, message = "更新时ID不能为空")
        private Long id;
    }
  4. 全局异常处理(捕获验证异常)

    java 复制代码
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    import java.util.HashMap;
    import java.util.Map;
    
    @RestControllerAdvice
    public class GlobalExceptionHandler {
    
        @ExceptionHandler(MethodArgumentNotValidException.class)
        public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
            Map<String, String> errors = new HashMap<>();
            ex.getBindingResult().getAllErrors().forEach(error -> {
                String fieldName = ((FieldError) error).getField();
                String errorMessage = error.getDefaultMessage();
                errors.put(fieldName, errorMessage);
            });
            return ResponseEntity.badRequest().body(errors);
        }
    }

自定义校验器

自定义一个校验器,实现必须以xxx 开头。

java 复制代码
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = PrefixValidator.class) // 关联验证器
public @interface PrefixConstraint {
    String message() default "字符串必须以指定前缀开头"; // 默认错误消息

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

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

    String prefix() default ""; // 自定义开头前缀属性
}
java 复制代码
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class PrefixValidator implements ConstraintValidator<PrefixConstraint, String> {
    private String prefix; // 动态存储用户设置的开头字符串

    @Override
    public void initialize(PrefixConstraint constraintAnnotation) {
        this.prefix = constraintAnnotation.prefix(); // 初始化时获取注解参数
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        // 空值处理(根据业务需求决定是否允许null)
        if (value == null) return true;

        // 核心验证逻辑:检查字符串是否以指定前缀开头
        boolean isValid = value.startsWith(prefix);
        if (!isValid) {
            // 动态设置错误消息(包含实际前缀值)
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate(
                    "必须以'" + prefix + "'开头,实际值:" + value
            ).addConstraintViolation();
        }
        return isValid;
    }
}

通常只会提示一个错误,这里修改全局异常处理。

java 复制代码
@ExceptionHandler(MethodArgumentNotValidException.class)
    public R<Object> doException(MethodArgumentNotValidException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();

        ArrayList<FieldError> fieldErrors1 = new ArrayList<>(fieldErrors);
        Collections.sort(fieldErrors1,(a,b)->a.getField().compareTo(b.getField()));

        FieldError fieldError = fieldErrors1.get(0);
        return R.fail(fieldError.getField() + "  " + fieldError.getDefaultMessage());
    }

使用

运行结果示例

相关推荐
蜗牛^^O^2 小时前
Spark详解
后端
1.14(java)2 小时前
掌握数据库约束:确保数据精准可靠
java·数据库·mysql·数据库约束
Codeking__2 小时前
Redis——value的数据类型与单线程工作模型
java·数据库·redis
人道领域2 小时前
【零基础学java】(等待唤醒机制,线程池补充)
java·开发语言·jvm
wxr06162 小时前
部署Spring Boot项目+mysql并允许前端本地访问
前端·spring boot·mysql·持续部署
名字不好奇2 小时前
在C++中 如何实现java中的Stream
java·c++
alonewolf_992 小时前
Tomcat整体架构深度解析:从设计精髓到实战应用
java·架构·tomcat
摩西蒙2 小时前
阿里云 MaxCompute(原 ODPS)定时任务查询库存快照场景
java·大数据·sql·database
黎雁·泠崖2 小时前
Java入门之吃透基础语法:注释+关键字+字面量+变量全解析
java·开发语言·intellij-idea·intellij idea