Java自定义异常国际化核心是分离错误键与文案:异常仅持key(如error.user.notfound)和参数,文案由MessageSource按Locale从多语言properties文件动态加载,实现零字符串拼接、无硬编码语言。

Java 自定义异常信息国际化落地,核心是把“错误是什么”和“错误怎么说”彻底分开:异常只携带可查表的键(如 error.user.notfound),文案交给外部资源文件,由运行时根据用户语言动态加载。不拼字符串、不硬编码语言,才能真正支持多语言切换和后期维护。
1. 定义带消息键的自定义异常
异常类本身不存具体文字,只持有一个 key 和可选参数:
- 继承
RuntimeException(业务异常通常是非检查型) - 提供构造方法接收
messageKey和Object... args - 避免重写
getMessage()提前解析——延迟到展示环节才查语言
示例:
public class BusinessException extends RuntimeException {
private final String messageKey;
private final Object[] args;
public BusinessException(String messageKey, Object... args) {
super(messageKey); // 仅作日志兜底用
this.messageKey = messageKey;
this.args = args;
}
public String getMessageKey() { return messageKey; }
public Object[] getArgs() { return args; }
}
2. 配置多语言资源文件
在 src/main/resources/i18n/ 下放置标准命名的 .properties 文件,确保 UTF-8 编码:
立即学习“Java免费学习笔记(深入)”;
-
messages_zh_CN.properties:error.user.notfound=用户 {0} 不存在 -
messages_en_US.properties:error.user.notfound=User {0} not found -
messages_ja_JP.properties:error.user.notfound={0} ユーザーが存在しません
占位符统一用 {0}、{1},与 MessageFormat 兼容;key 名必须严格一致,大小写敏感。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
3. 注册 MessageSource 并启用自动配置
Spring Boot 项目中,在配置类或 application.yml 中声明资源路径:
spring:
messages:
basename: i18n/messages
encoding: UTF-8
fallback-to-system-locale: false
use-code-as-default-message: true
这样 Spring 会自动注册 ResourceBundleMessageSource,支持按 Accept-Language 或自定义请求头(如 X-Lang: en-US)匹配语言。
4. 全局异常处理器中完成最终渲染
使用 @ControllerAdvice 捕获异常,在处理器里调用 MessageSource 解析文案:
- 从
LocaleContextHolder.getLocale()获取当前语言上下文 - 调用
messageSource.getMessage(key, args, locale) - 若 key 未找到,
use-code-as-default-message: true会自动回退为 key 字符串,便于排查
示例响应结构:
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ApiResponse> handleBusinessException(
BusinessException e, HttpServletRequest request) {
Locale locale = LocaleContextHolder.getLocale();
String message = messageSource.getMessage(
e.getMessageKey(), e.getArgs(), locale);
return ResponseEntity.badRequest()
.body(ApiResponse.error(e.getMessageKey(), message));
}
新增语言只需加一个 properties 文件,改提示只改资源文件,加新错误码只需扩枚举或统一管理 key —— 三者完全解耦,落地不复杂但容易忽略关键细节。

















