@NotBlank(message = “{xxx}“) 注解中花括号的含义

【SpringBoot 实战】@NotBlank(message = "{auth.clientid.not.blank}") 花括号里的是什么?

一、问题场景

最近在看项目的登录代码 LoginBody.java,发现一个很有意思的写法:

复制代码
@NotBlank(message = "{auth.clientid.not.blank}")
private String clientId;

以前我写的校验注解都是这样的:

复制代码
@NotBlank(message = "客户端ID不能为空")
private String clientId;

为什么要用花括号 {} 包起来?直接写文案不好吗? "auth.clientid.not.blank" 这一串是啥意思?


二、答案:这是国际化(i18n)的消息配置写法

花括号 {} 包裹的内容是一个 消息键(Message Key),它的作用是:

告诉校验框架:别直接把 {auth.clientid.not.blank} 当错误文案返回,而是去国际化资源文件中查找对应 key 的实际文案。

用一张图理解:

复制代码
前端传参 clientId 为空
        │
        ▼
@NotBlank 校验失败
        │
        ▼
看到 message = "{auth.clientid.not.blank}"
        │
        ▼
去 messages_zh_CN.properties 找 key
        │
        ├── key: auth.clientid.not.blank = 认证客户端id不能为空
        │
        ▼
返回给前端:认证客户端id不能为空

三、项目中的实际配置

在 SpringBoot 项目的 resources 目录下,通常会有几个 properties 文件:

文件名 语言环境 内容示例
messages.properties 默认(中文) auth.clientid.not.blank=认证客户端id不能为空
messages_zh_CN.properties 简体中文 auth.clientid.not.blank=认证客户端id不能为空
messages_en_US.properties 英文 auth.clientid.not.blank=Auth clientid cannot be blank
messages_ja_JP.properties 日文 auth.clientid.not.blank=認証クライアントIDは空にできません

**校验框架会根据当前请求的语言(请求头 Accept-Language)自动选择对应的文件:

请求头 Accept-Language 返回的错误信息
zh-CN,zh;q=0.9 认证客户端id不能为空
en-US,en;q=0.9 Auth clientid cannot be blank
ja-JP,ja;q=0.9 認証クライアントIDは空にできません

四、两种写法的对比

写法 示例 优缺点
硬编码 @NotBlank(message = "客户端id不能为空") ✅ 写起来简单 ❌ 不支持多语言 ❌ 改文案要改 Java 代码
消息键(推荐) @NotBlank(message = "{auth.clientid.not.blank}") ✅ 支持多语言切换 ✅ 改文案只改 properties 文件 ✅ 文案统一管理,不会漏改 ❌ 多写一层配置

五、花括号语法从哪来的?

这不是 Spring 独创的,而是 **JSR-303 / JSR-380(Bean Validation)规范定义的标准语法:

语法 含义
message = "xxx" 直接返回字符串
message = "{xxx}" 去资源文件查找 key 对应的值
message = "{xxx} {yyy}" 支持拼接,两个 key 都会解析
message = "长度必须在 {min} 到 {max} 之间" 甚至可以引用注解参数

比如 @Size 注解可以这样用:

复制代码
@Size(min = 2, max = 10, message = "用户名长度必须在 {min} 到 {max} 之间")
private String username;

校验失败时会自动替换:

复制代码
用户名长度必须在 2 到 10 之间

六、SpringBoot 中怎么配置?

1. 新建国际化资源文件

resources/i18n/ 目录下(或者直接 resources/):

复制代码
resources/
├── messages.properties         # 默认
├── messages_zh_CN.properties
└── messages_en_US.properties
2. 在 application.yml 配置:
复制代码
spring:
  messages:
    basename: i18n/messages   # 如果在 i18n 目录下
    encoding: UTF-8
3. 配置 LocaleResolver(可选,基于请求头切换语言)
复制代码
@Configuration
public class I18nConfig {

    @Bean
    public LocaleResolver localeResolver() {
        AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver();
        resolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
        return resolver;
    }
}

这样前端在 DTO 上直接用:

复制代码
@NotBlank(message = "{user.username.not.blank}")
private String username;

七、总结

问题 答案
{auth.clientid.not.blank} 是什么? 国际化资源文件中的 **消息 key
为什么用花括号? JSR-303 规范的语法,告诉框架去解析 key
好处是什么? 支持多语言、文案统一管理、改文案不用改代码
相关推荐
码匠许师傅12 分钟前
【C++ 面试真题】聊聊 C++ 的虚函数和多态
java·c++·面试
chuan.bai39 分钟前
Java RAG 实战(第 8 篇):Spring Boot RAG 查询 API
java·spring boot·贪心算法
FlyWIHTSKY40 分钟前
idea中集成claude功能
java·ide·人工智能·intellij-idea·cloudera
Java成神之路-1 小时前
Spring AI 统一结构化返回:ChatModel / ChatClient 两种实现方式
java·springaialibaba
Mr. zhihao1 小时前
深度解析:为什么Java序列化需要搭配ByteArrayOutputStream?IO装饰器模式的精妙设计
java·开发语言·装饰器模式
存在morning1 小时前
【Python 开发实践 一】Python vs Go vs Java 三门语言对比
java·python·golang
vx-程序开发1 小时前
springboot旅游推介平台---附源码24175
java·spring boot·python·spring cloud·eclipse·django·idea
艾莉丝努力练剑1 小时前
【QT:解决问题】Qt5Core.dll:无法定位程序输入点
java·开发语言·qt·学习·面试
小蒜学长2 小时前
“喵汪联盟”宠物领养系统的设计与实现(代码+数据库+LW)
java·spring boot·后端·宠物
程序员黑豆2 小时前
Java字符串常量池完全指南:原理、intern()方法与性能优化最佳实践
java·前端·ai编程