MessageSource需主动调用解析异常code,自定义异常封装messageCode和args,配置ResourceBundleMessageSource加载messages.properties,全局异常处理器结合Locale调用getMessage()实现国际化。

在 Java Spring 应用中,MessageSource 本身不直接“根据异常中的 code 查找消息”,而是需要你**主动调用**它,并传入异常里携带的 message code(比如 "user.not.found")以及可选的参数(如用户 ID)。关键在于:自定义异常要能提供这个 code 和参数,而业务代码或全局异常处理器要负责用 MessageSource 去解析。
1. 定义自定义异常,携带 messageCode 和 args
你的异常类应封装可被国际化使用的标识和动态值:
- 定义一个字段(如
private final String messageCode)保存 properties 中的 key - 可选:用
Object[] args存放占位符参数(如{userId}) - 构造方法接收 code 和 args,便于统一创建
示例:
public class BusinessException extends RuntimeException {
private final String messageCode;
private final Object[] args;
public BusinessException(String messageCode) {
this(messageCode, new Object[0]);
}
public BusinessException(String messageCode, Object... args) {
super("Business exception with code: " + messageCode);
this.messageCode = messageCode;
this.args = args;
}
// getter 方法供外部使用
public String getMessageCode() { return messageCode; }
public Object[] getArgs() { return args; }
}
2. 配置 MessageSource 并确保 messages.properties 可用
确保 Spring 已加载 MessageSource Bean(通常用 ResourceBundleMessageSource):
- 文件名必须为
messages.properties(默认基础名),放在src/main/resources下 - 支持多语言:如
messages_zh_CN.properties、messages_en_US.properties - 内容示例:
user.not.found=用户【{0}】不存在
配置(Java Config):
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasename("messages"); // 对应 messages.properties
source.setDefaultEncoding("UTF-8");
return source;
}
3. 在异常处理器中调用 MessageSource 解析
使用 @ControllerAdvice + @ExceptionHandler 捕获自定义异常,并用 MessageSource 翻译:
- 注入
MessageSource和当前Locale(通常从请求上下文获取) - 调用
messageSource.getMessage(exception.getMessageCode(), exception.getArgs(), locale) - 若 code 未找到,会抛
NoSuchMessageException,建议 fallback 到 code 本身或日志告警
示例:
@ControllerAdvice
public class GlobalExceptionHandler {
@Autowired
private MessageSource messageSource;
@ExceptionHandler(BusinessException.class)
@ResponseBody
public ResponseEntity<errorresponse> handleBusinessException(
BusinessException e, HttpServletRequest request) {
Locale locale = RequestContextUtils.getLocale(request);
String localizedMsg;
try {
localizedMsg = messageSource.getMessage(
e.getMessageCode(), e.getArgs(), locale);
} catch (NoSuchMessageException ex) {
localizedMsg = e.getMessageCode(); // fallback
log.warn("Missing message key: {}", e.getMessageCode());
}
return ResponseEntity.badRequest()
.body(new ErrorResponse(localizedMsg));
}
}</errorresponse>
4. 使用时只需抛出带 code 的异常
业务逻辑中不再硬编码中文/英文,只关心语义化 code:
throw new BusinessException("user.not.found", userId);throw new BusinessException("order.invalid.status", orderId, expectedStatus);
这样,同一段代码在不同语言环境、不同部署地区,自动返回对应翻译,且 message key 易于统一管理和审计。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











