首页  >  文章  >  Java  >  在 Spring Boot 中处理异常消息本地化的最佳方法

在 Spring Boot 中处理异常消息本地化的最佳方法

WBOY
WBOY原创
2024-09-06 06:03:02443浏览

Best Way to Handle Localization For Exception Messages in Spring Boot

随着应用程序不断发展以服务于全球受众,本地化成为软件开发的一个重要方面。本地化允许应用程序适应不同的语言和地区,提供用户友好的体验。 

在本文中,我将分享我最喜欢的在 Spring Boot 应用程序中处理本地化异常的方法。

为什么我们需要异常消息本地化?

后端异常消息的本地化对于创建无缝的用户体验至关重要,尤其是在面向全球受众的应用程序中。 

通过在后端本地化这些消息并将它们直接发送到前端,我们可以从前端开发人员的肩上承担管理多种语言的责任。这种方法可确保错误消息在所有平台和语言中保持一致,从而使前端开发人员能够专注于以用户友好的方式(例如在错误 toast 中)显示这些消息。 

因此,前端无需处理每种语言的自定义异常消息,从而减少了重复工作和潜在的错误,并确保所有用户都以其首选语言收到清晰且相关的反馈。

后端如何方便的实现我们的目标呢?

请按照以下步骤来实现我们的目标。 

一般异常类

首先创建一个从 RuntimeException 扩展的类,并将其命名为 ResponseException。此自定义异常将允许您以更受控的方式处理特定于应用程序的错误。

public class ResponseException extends RuntimeException {

}

响应错误类别

创建一个单独的类,当发生异常时,该类将在响应中返回。此类可以包含消息、时间戳、错误代码等字段以及您想要传递给前端的任何其他相关信息。

public record ErrorResponse(int status, String message) {

}

全局异常处理程序

使用 Spring 的 @ControllerAdvice 注解实现 GlobalExceptionHandler。在此类中,您可以捕获 ResponseException 并根据用户的区域设置将其映射到适当的本地化消息。

@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

  @ExceptionHandler(value = ResponseException.class)
  public ResponseEntity<ErrorResponse> handleResponseStatusException(
      ResponseException ex
  ) {
    log.error("ResponseException: {}", ex.getMessage());

    String message = ex.getMessage();

    var errorResponse = new ErrorResponse(ex.getStatus().value(), message);

    return new ResponseEntity<>(errorResponse, ex.getStatus());
  }
}

特定于语言的属性文件

要管理本地化消息,请为每种支持的语言创建属性文件,例如英语的 messages_en.properties、阿塞拜疆语的 messages_az.properties 等。这些文件将包含每个异常消息的键值对,允许 Spring 根据用户的区域设置自动解析正确的消息。

在 src/main/resources 文件夹中创建这些属性文件。

err.username_already_exists.msg=User with username: {0} is already exists.

实施本地化部分

我已经创建了在 Spring Boot 中处理异常的最低限度。我想你已经熟悉上面的内容了。我们继续添加翻译部分。

修改ResponseException类:

public class ResponseException extends RuntimeException {
  private final String messageTemplate;
  private final transient Object[] params;
  private final Locale locale;

  public static ResponseException notFound(String messageTemplate, Locale locale) {
    return new ResponseException(HttpStatus.NOT_FOUND, messageTemplate, null, locale);
  }

  public static ResponseException notFound(String messageTemplate, Object[] params, Locale locale) {
    return new ResponseException(HttpStatus.NOT_FOUND, messageTemplate, params, locale);
  }

  public static ResponseException forbidden(String messageTemplate, Locale locale) {
    return new ResponseException(HttpStatus.FORBIDDEN, messageTemplate, null, locale);
  }

  public static ResponseException forbidden(String messageTemplate, Object[] params, Locale locale) {
    return new ResponseException(HttpStatus.FORBIDDEN, messageTemplate, params, locale);
  }  
}

为常用的 HttpStatus 代码创建辅助方法,例如 NOT_FOUNDFORBIDDEN.

您可以通过以下方式使用这些辅助方法:

// some code parts omitted ...
userService.findByUsername(username)
  .orElseThrow(() -> ResponseException.notFound("user_not_found", locale))

在所有属性文件中创建 user_not_found 消息模板。

// file: messages_en.properties
user_not_found=User not found

// file: messages_az.properties
user_not_found=İsdifadəçi tapılmadı

为了在返回前端之前自动替换这些,请更新 GlobalExceptionHandler 类中的方法。

@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

  private final MessageSource messageSource;

  @ExceptionHandler(value = ResponseException.class)
  public ResponseEntity<ErrorResponse> handleResponseStatusException(
      ResponseException ex
  ) {
    log.error("ResponseException: {}", ex.getMessage());

    String message = ex.getMessage();

    String messageTemplate = ex.getMessageTemplate();
    if (StringUtils.isNotBlank(messageTemplate)) {
      message = messageSource.getMessage(messageTemplate, ex.getParams(), ex.getLocale());
    }

    var errorResponse = new ErrorResponse(ex.getStatus().value(), message);

    return new ResponseEntity<>(errorResponse, ex.getStatus());
  }
}

如何在异常消息中使用动态值

这种处理异常的方法非常有用,特别是您必须为异常消息设置动态值。例如,

// file: messages_en.properties
err.invalid_phone_number.msg=The phone: {0} is invalid

为了用动态值替换 {0}。

public static ResponseException badRequest(
      String messageTemplate, 
      Locale locale,
      String... params
) {
  return new ResponseException(
        HttpStatus.BAD_REQUEST, 
        messageTemplate, 
        params, 
        locale
  );
}

我将 varargs 参数放在最后以传递多个动态参数,而无需每次都创建新方法。

我有一篇关于具有动态值的消息的专门文章。

从哪里获取用户的区域设置?

我有两种获取语言环境的方法:

  1. 根据 UI 首选项存储在数据库中的用户区域设置。

  2. 一些控制器方法接受可选的 lang 请求参数。当前端开发人员想要查看 UI 在不同语言中的表现时,这对于测试可能很有用。因为每种语言的句子长度都不一样。

结论

今天就到此为止。我希望你喜欢。

源代码可在我的 GitHub 帐户的存储库中找到。

如果您有任何疑问,请随时通过 LinkedIn 与我联系。

以上是在 Spring Boot 中处理异常消息本地化的最佳方法的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn