Java自定义异常通过错误码+国际化资源+Locale绑定实现多语言提示:异常类仅存code和args,文案由ResourceBundle或MessageSource按当前Locale动态加载。

Java 自定义异常本身不直接支持多语言提示,但可以通过“异常类 + 国际化资源 + 运行时 Locale 绑定”组合实现。核心思路是:异常类只保存错误码(code)和参数(args),不硬编码提示文本;实际提示文案从 ResourceBundle 或 Spring 的 MessageSource 动态加载,由当前线程的 Locale 决定语言。
1. 定义带错误码的自定义异常
异常类不存具体消息,只存可定位的唯一 code 和用于填充模板的参数(如用户名、ID):
- 继承
RuntimeException(或Exception,按需选择检查/非检查异常) - 提供 code 字段、参数数组(Object... args)、可选的 cause
- 重写
getMessage()仅作调试用(返回 code + args),**不拼接真实提示**
public class BusinessException extends RuntimeException {
private final String code;
private final Object[] args;
public BusinessException(String code, Object... args) {
this(code, null, args);
}
public BusinessException(String code, Throwable cause, Object... args) {
super(cause);
this.code = code;
this.args = args != null ? args : new Object[0];
}
public String getCode() { return code; }
public Object[] getArgs() { return args; }
// 仅用于日志或调试,不用于前端展示
@Override
public String getMessage() {
return "BusinessException[code=" + code + ", args=" + Arrays.toString(args) + "]";
}
}
2. 准备多语言资源文件(.properties)
按标准命名放在 src/main/resources 下,例如:
-
messages_zh_CN.properties:user.not.found=用户【{0}】不存在 -
messages_en_US.properties:user.not.found=User [{0}] not found -
messages_ja_JP.properties:user.not.found={0}というユーザーは存在しません
注意:使用 {0}, {1} 占位符,与 MessageFormat.format() 兼容。
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
3. 在运行时动态解析国际化消息
推荐两种主流方式:
-
Spring 环境(推荐):注入
MessageSource(如ReloadableResourceBundleMessageSource),通过getMessage(code, args, locale)获取提示 -
纯 Java SE / 非 Spring:用
ResourceBundle.getBundle(baseName, locale)+MessageFormat.format(bundle.getString(code), args)
示例(Spring):
@Service
public class UserService {
@Autowired
private MessageSource messageSource;
public void checkUserExists(Long id) {
if (!userRepository.existsById(id)) {
throw new BusinessException("user.not.found", id);
}
}
// 获取当前语言的提示(通常从请求头或用户配置获取 locale)
public String getLocalizedMessage(BusinessException e, Locale locale) {
return messageSource.getMessage(
e.getCode(),
e.getArgs(),
locale // 如:LocaleContextHolder.getLocale()
);
}
}
4. 前端或 API 层统一处理异常响应
全局异常处理器(如 Spring 的 @ControllerAdvice)捕获自定义异常,调用消息解析逻辑,并返回结构化 JSON:
@ResponseBody
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ApiResponse> handleBusinessException(
BusinessException e, HttpServletRequest request) {
Locale locale = RequestContextUtils.getLocale(request); // 或从 token/header 解析
String message = messageSource.getMessage(e.getCode(), e.getArgs(), locale);
return ResponseEntity.badRequest().body(
ApiResponse.error(e.getCode(), message)
);
}
响应示例(zh_CN):{"code":"user.not.found","message":"用户【123】不存在"}
响应示例(en_US):{"code":"user.not.found","message":"User [123] not found"}
不复杂但容易忽略:确保资源文件编码为 UTF-8;占位符顺序与 args 严格对应;locale 传递要贯穿调用链(如用 LocaleContextHolder 绑定到当前线程)。

















