当前位置: 代码网 > it编程>编程语言>Java > Spring Validation中9个数据校验工具使用指南

Spring Validation中9个数据校验工具使用指南

2025年05月11日 Java 我要评论
1. bean validation基础注解spring validation集成了jsr-380 (bean validation 2.0)规范,提供了一系列开箱即用的校验注解。常用注解示例@dat

1. bean validation基础注解

spring validation集成了jsr-380 (bean validation 2.0)规范,提供了一系列开箱即用的校验注解。

常用注解示例

@data
public class userdto {
    @notnull(message = "用户id不能为空")
    private long id;
    
    @notblank(message = "用户名不能为空")
    @size(min = 4, max = 20, message = "用户名长度必须在4到20个字符之间")
    private string username;
    
    @email(message = "邮箱格式不正确")
    private string email;
    
    @min(value = 18, message = "年龄必须大于或等于18")
    @max(value = 120, message = "年龄必须小于或等于120")
    private integer age;
    
    @past(message = "出生日期必须是过去的日期")
    private localdate birthdate;
    
    @pattern(regexp = "^1[3-9]\d{9}$", message = "手机号码格式不正确")
    private string phonenumber;
}

在控制器中应用

@restcontroller
@requestmapping("/api/users")
public class usercontroller {
    
    @postmapping
    public responseentity<userdto> createuser(@requestbody @valid userdto userdto, 
                                             bindingresult bindingresult) {
        if (bindingresult.haserrors()) {
            // 处理验证错误
            throw new validationexception(bindingresult);
        }
        // 处理业务逻辑
        return responseentity.ok(userdto);
    }
}

最佳实践:使用有意义的错误消息,保持一致的命名风格,避免在实体类上直接使用验证注解,而是在dto对象上应用验证规则。

2. 自定义约束验证器

spring validation允许开发者创建自定义约束,满足特定业务规则的验证需求。

定义自定义约束注解

@target({elementtype.field, elementtype.parameter})
@retention(retentionpolicy.runtime)
@constraint(validatedby = uniqueusernamevalidator.class)
public @interface uniqueusername {
    string message() default "用户名已存在";
    class<?>[] groups() default {};
    class<? extends payload>[] payload() default {};
}

实现验证器

public class uniqueusernamevalidator implements constraintvalidator<uniqueusername, string> {
    
    @autowired
    private userrepository userrepository;
    
    @override
    public boolean isvalid(string username, constraintvalidatorcontext context) {
        if (username == null) {
            return true;  // 让@notnull处理空值
        }
        return !userrepository.existsbyusername(username);
    }
}

应用自定义约束

public class userregistrationdto {
    
    @notblank
    @size(min = 4, max = 20)
    @uniqueusername
    private string username;
    
    // 其他字段...
}

使用场景:验证业务特定规则,如唯一性约束、密码复杂度、信用卡格式等。

3. 分组验证

分组验证允许根据不同场景应用不同的验证规则,例如创建和更新操作可能需要不同的验证逻辑。

定义验证分组

// 定义验证分组接口
public interface validationgroups {
    interface create {}
    interface update {}
}

应用分组到约束

@data
public class productdto {
    
    @null(groups = validationgroups.create.class, message = "创建产品时id必须为空")
    @notnull(groups = validationgroups.update.class, message = "更新产品时id不能为空")
    private long id;
    
    @notblank(groups = {validationgroups.create.class, validationgroups.update.class})
    private string name;
    
    @positiveorzero(groups = validationgroups.create.class)
    @positive(groups = validationgroups.update.class)
    private bigdecimal price;
}

在控制器中指定分组

@restcontroller
@requestmapping("/api/products")
public class productcontroller {
    
    @postmapping
    public responseentity<productdto> createproduct(
            @requestbody @validated(validationgroups.create.class) productdto productdto) {
        // 创建产品逻辑
        return responseentity.ok(productdto);
    }
    
    @putmapping("/{id}")
    public responseentity<productdto> updateproduct(
            @pathvariable long id,
            @requestbody @validated(validationgroups.update.class) productdto productdto) {
        // 更新产品逻辑
        return responseentity.ok(productdto);
    }
}

提示:注意使用@validated注解而不是@valid,因为只有前者支持分组验证。

4. 嵌套验证

嵌套验证允许验证复杂对象结构中的嵌套对象。

定义嵌套对象

@data
public class orderdto {
    
    @notnull
    private long id;
    
    @notnull
    @valid  // 标记需要级联验证的字段
    private customerdto customer;
    
    @notempty
    @valid  // 验证集合中的每个元素
    private list<orderitemdto> items;
}

@data
public class customerdto {
    
    @notnull
    private long id;
    
    @notblank
    private string name;
    
    @email
    private string email;
    
    @valid  // 进一步嵌套验证
    private addressdto address;
}

关键点:在需要级联验证的字段上添加@valid注解,确保验证深入到嵌套对象中。

5. 方法级别验证

spring validation不仅可以用于控制器参数,还可以应用于服务层的方法。

启用方法级别验证

@configuration
@enablemethodvalidation
public class validationconfig {
    // 配置内容
}

定义带验证的服务方法

@service
public class userservice {
    
    @validated
    public user createuser(@valid userdto userdto) {
        // 业务逻辑
        return new user();
    }
    
    @notnull
    public user findbyid(@min(1) long id) {
        // 查询逻辑
        return new user();
    }
    
    @validated(validationgroups.update.class)
    public void updateuser(@valid userdto userdto) {
        // 更新逻辑
    }
}

应用场景:确保服务层方法接收到的参数和返回的结果符合预期,增强代码的健壮性。

6. 错误消息处理和国际化

spring validation提供了强大的错误消息处理和国际化支持。

自定义错误消息

validationmessages.properties文件中定义:

# validationmessages.properties
javax.validation.constraints.notempty.message=字段不能为空
javax.validation.constraints.email.message=不是有效的电子邮箱地址
user.name.size=用户名长度必须在{min}到{max}个字符之间

国际化错误消息

创建特定语言的属性文件:

# validationmessages_en.properties
javax.validation.constraints.notempty.message=field cannot be empty
javax.validation.constraints.email.message=not a valid email address
user.name.size=username must be between {min} and {max} characters

# validationmessages_zh_cn.properties
javax.validation.constraints.notempty.message=字段不能为空
javax.validation.constraints.email.message=不是有效的电子邮箱地址
user.name.size=用户名长度必须在{min}到{max}个字符之间

使用自定义消息

@size(min = 4, max = 20, message = "{user.name.size}")
private string username;

7. 程序化验证

除了注解驱动的验证,spring validation还支持以编程方式进行验证。

使用validator手动验证对象

@service
public class validationservice {
    
    private final validator validator;

    public validationservice(validator validator) {
        this.validator = validator;
    }
    
    public <t> void validate(t object) {
        set<constraintviolation<t>> violations = validator.validate(object);
        if (!violations.isempty()) {
            throw new constraintviolationexception(violations);
        }
    }
    
    public <t> void validatewithgroup(t object, class<?>... groups) {
        set<constraintviolation<t>> violations = validator.validate(object, groups);
        if (!violations.isempty()) {
            throw new constraintviolationexception(violations);
        }
    }
    
    public <t> list<string> getvalidationerrors(t object) {
        return validator.validate(object).stream()
                .map(constraintviolation::getmessage)
                .collect(collectors.tolist());
    }
}

使用场景:在复杂业务逻辑中需要条件性验证,或者验证非控制器传入的对象时。

8. 组合约束

组合约束允许将多个基本约束组合成一个更复杂的约束,减少代码重复。

创建组合约束

@notnull
@size(min = 8, max = 30)
@pattern(regexp = "^(?=.*[0-9])(?=.*[a-z])(?=.*[a-z])(?=.*[@#$%^&+=]).*$", 
         message = "密码必须包含至少一个数字、小写字母、大写字母和特殊字符")
@target({elementtype.field, elementtype.parameter})
@retention(retentionpolicy.runtime)
@constraint(validatedby = {})
public @interface strongpassword {
    string message() default "密码不符合安全要求";
    class<?>[] groups() default {};
    class<? extends payload>[] payload() default {};
}

应用组合约束

public class passwordchangedto {
    
    @notblank
    private string oldpassword;
    
    @strongpassword
    private string newpassword;
    
    @notblank
    private string confirmpassword;
}

优点:提高代码可读性和可维护性,确保验证规则在整个应用中保持一致。

9. 跨字段验证

跨字段验证允许根据多个字段之间的关系进行验证。

创建类级别约束

@target({elementtype.type})
@retention(retentionpolicy.runtime)
@constraint(validatedby = passwordmatchesvalidator.class)
public @interface passwordmatches {
    string message() default "确认密码与新密码不匹配";
    class<?>[] groups() default {};
    class<? extends payload>[] payload() default {};
    
    string field();
    string fieldmatch();
}

实现验证器

public class passwordmatchesvalidator implements constraintvalidator<passwordmatches, object> {
    
    private string field;
    private string fieldmatch;
    
    @override
    public void initialize(passwordmatches constraintannotation) {
        this.field = constraintannotation.field();
        this.fieldmatch = constraintannotation.fieldmatch();
    }
    
    @override
    public boolean isvalid(object value, constraintvalidatorcontext context) {
        try {
            object fieldvalue = beanutils.getpropertydescriptor(value.getclass(), field)
                    .getreadmethod().invoke(value);
            object fieldmatchvalue = beanutils.getpropertydescriptor(value.getclass(), fieldmatch)
                    .getreadmethod().invoke(value);
            
            return (fieldvalue != null) && fieldvalue.equals(fieldmatchvalue);
        } catch (exception e) {
            return false;
        }
    }
}

应用类级别约束

@data
@passwordmatches(field = "newpassword", fieldmatch = "confirmpassword")
public class passwordchangedto {
    
    @notblank
    private string oldpassword;
    
    @strongpassword
    private string newpassword;
    
    @notblank
    private string confirmpassword;
}

使用场景:验证密码确认、日期范围比较、最小/最大值比较等。

总结

spring validation提供了一套全面而强大的数据校验工具,从基本的注解验证到复杂的自定义约束,从单一字段验证到跨字段关系验证,都有相应的解决方案。

合理利用这些验证工具,不仅能提高应用的健壮性和安全性,还能改善代码质量和可维护性。

以上就是spring validation中9个数据校验工具使用指南的详细内容,更多关于spring validation数据校验工具的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com