欢迎来到徐庆高(Tea)的个人博客网站
磨难很爱我,一度将我连根拔起。从惊慌失措到心力交瘁,我孤身一人,但并不孤独无依。依赖那些依赖我的人,信任那些信任我的人,帮助那些给予我帮助的人。如果我愿意,可以分裂成无数面镜子,让他们看见我,就像看见自己。察言观色和模仿学习是我的领域。像每个深受创伤的人那样,最终,我学会了随遇而安。
当前位置: 日志文章 > 详细内容

如何在Spring Boot 项目中自定义 Validation 注解

2025年07月13日 Java
在spring boot项目中自定义validation注解,可按以下步骤实现,以手机号格式校验(支持多地区)为例:一、定义自定义注解import javax.validation.constrain

在spring boot项目中自定义validation注解,可按以下步骤实现,以手机号格式校验(支持多地区)为例:

一、定义自定义注解

import javax.validation.constraint;
import javax.validation.payload;
import java.lang.annotation.*;
@target({elementtype.field, elementtype.parameter}) // 作用于字段和方法参数
@retention(retentionpolicy.runtime) // 运行时生效
@constraint(validatedby = phonevalidator.class) // 关联校验器
public @interface phone {
    string message() default "手机号格式错误"; // 错误提示
    class<?>[] groups() default {}; // 分组校验(如新增、更新)
    class<? extends payload>[] payload() default {}; // 负载信息(可选)
    string region() default "cn"; // 自定义属性:地区(默认中国)
}

二、实现校验逻辑(constraintvalidator)

import javax.validation.constraintvalidator;
import javax.validation.constraintvalidatorcontext;
public class phonevalidator implements constraintvalidator<phone, string> {
    private string region; // 存储注解的region属性
    @override
    public void initialize(phone constraintannotation) {
        this.region = constraintannotation.region(); // 初始化,获取地区配置
    }
    @override
    public boolean isvalid(string value, constraintvalidatorcontext context) {
        if (value == null) return true; // 允许为空(若必填需额外处理,如@notblank配合使用)
        // 根据地区校验格式
        switch (region) {
            case "cn": // 中国手机号:11位,以1开头,第二位3-9
                return value.matches("^1[3-9]\\d{9}$");
            case "us": // 美国手机号:+1开头,后跟10位数字
                return value.matches("^\\+1\\d{10}$");
            default:
                return false; // 未知地区,校验失败
        }
    }
}

三、应用自定义注解

1. 在dto中使用

public class userdto {
    @notblank
    private string username;
    @phone(region = "cn") // 校验中国手机号
    private string phone;
    // 若需校验美国手机号,可设置region="us"
    // @phone(region = "us")
    // private string usphone;
    // getters/setters
}

2. 在controller中触发校验

import org.springframework.validation.annotation.validated;
import org.springframework.web.bind.annotation.*;
@restcontroller
public class usercontroller {
    @postmapping("/register")
    public string register(@validated @requestbody userdto dto) {
        // 校验通过,执行注册逻辑
        return "注册成功";
    }
}

四、处理校验异常(全局异常处理器)

import org.springframework.http.httpstatus;
import org.springframework.http.responseentity;
import org.springframework.validation.bindingresult;
import org.springframework.validation.fielderror;
import org.springframework.web.bind.methodargumentnotvalidexception;
import org.springframework.web.bind.annotation.controlleradvice;
import org.springframework.web.bind.annotation.exceptionhandler;
@controlleradvice
public class globalexceptionhandler {
    @exceptionhandler(methodargumentnotvalidexception.class)
    public responseentity<errorresponse> handlevalidationerror(methodargumentnotvalidexception ex) {
        bindingresult result = ex.getbindingresult();
        stringbuilder errormsg = new stringbuilder();
        for (fielderror error : result.getfielderrors()) {
            errormsg.append(error.getfield()).append(": ").append(error.getdefaultmessage()).append("; ");
        }
        return responseentity
                .status(httpstatus.bad_request)
                .body(new errorresponse(httpstatus.bad_request.value(), errormsg.tostring()));
    }
    static class errorresponse {
        private int code;
        private string message;
        public errorresponse(int code, string message) {
            this.code = code;
            this.message = message;
        }
        // getters
    }
}

五、扩展功能

1. 分组校验(如新增和更新场景)

// 定义分组接口
public interface creategroup {}
public interface updategroup {}
// 在dto中指定分组
@phone(region = "cn", groups = creategroup.class) // 新增时校验手机号
private string phone;
// controller中使用分组
@postmapping("/create")
public string create(@validated(creategroup.class) @requestbody userdto dto) { ... }
@putmapping("/update")
public string update(@validated(updategroup.class) @requestbody userdto dto) { ... }

2. 国际化错误消息

src/main/resources下创建validationmessages.properties

phone.message=手机号格式错误(中文)
phone.message_en=invalid phone number format(英文)

spring boot会根据accept-language头自动匹配语言。

3. 复杂业务校验(如手机号唯一性)

// 校验器中注入service(需将校验器标记为@component,由spring管理)
@component
public class phonevalidator implements constraintvalidator<phone, string> {
    @autowired
    private userservice userservice; // 假设userservice提供手机号唯一性查询
    @override
    public boolean isvalid(string value, constraintvalidatorcontext context) {
        // 先校验格式,再校验唯一性
        if (!isformatvalid(value)) return false;
        return !userservice.existsbyphone(value); // 假设existsbyphone查询数据库
    }
    private boolean isformatvalid(string value) {
        // 复用之前的格式校验逻辑
        return value.matches("^1[3-9]\\d{9}$");
    }
}

六、验证效果

  • 合法请求phone=13812345678,校验通过,正常处理。
  • 非法请求phone=123(格式错误),返回:
    {
      "code": 400,
      "message": "phone: 手机号格式错误; "
    }

总结

自定义validation注解的关键步骤为:

  1. 定义注解:通过@constraint关联校验器,设置属性(如地区、错误消息)。
  2. 实现校验逻辑:在constraintvalidator中编写具体规则(格式、唯一性等)。
  3. 应用注解:在dto/参数上标注,结合@validated触发校验。
  4. 处理异常:通过全局异常处理器返回标准化错误,提升用户体验。

这种方式可灵活扩展spring boot的校验能力,满足复杂业务需求(如多地区格式、业务规则校验),确保输入数据的合法性,是微服务架构中参数校验的重要实践。

到此这篇关于聊一聊在 spring boot 项目中自定义 validation 注解的文章就介绍到这了,更多相关spring boot 自定义 validation 注解内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!