アプリケーションが世界中のユーザーにサービスを提供できるように成長するにつれて、ローカリゼーションはソフトウェア開発の重要な側面になります。ローカリゼーションにより、アプリケーションがさまざまな言語や地域に適応できるようになり、ユーザー フレンドリーなエクスペリエンスが提供されます。
この記事では、Spring Boot アプリケーションでローカライズされた例外を処理する私のお気に入りの方法を共有します。
バックエンド側での例外メッセージのローカライズは、特に世界中のユーザーを対象とするアプリケーションでシームレスなユーザー エクスペリエンスを作成するために不可欠です。
これらのメッセージをバックエンドでローカライズし、フロントエンドに直接送信することで、フロントエンド開発者の肩から複数の言語を管理する責任を負うことができます。このアプローチにより、エラー メッセージがすべてのプラットフォームおよび言語で一貫していることが保証され、フロントエンド開発者はエラー トーストなどでこれらのメッセージをユーザー フレンドリーな方法で表示することに集中できるようになります。
その結果、フロントエンドで各言語のカスタム例外メッセージを処理する必要がなくなり、作業の重複やエラーの可能性が減り、すべてのユーザーが明確で適切なフィードバックを希望する言語で確実に受け取ることができます。
目標を達成するには、以下の手順に従ってください。
まず、RuntimeException を拡張するクラスを作成し、それに ResponseException という名前を付けます。このカスタム例外を使用すると、アプリケーション固有のエラーをより制御された方法で処理できるようになります。
public class ResponseException extends RuntimeException { }
例外が発生したときに応答で返される別のクラスを作成します。このクラスには、メッセージ、タイムスタンプ、errorCode、およびフロントエンドに渡したいその他の関連情報などのフィールドを含めることができます。
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); } }
NOT_FOUND、FORBIDDEN など、頻繁に使用される HttpStatus コードのヘルパー メソッドを作成します。
これらのヘルパー メソッドは次の方法で使用できます:
// 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 パラメータを最後に置きました。
動的値を含むメッセージに関する専用の記事があります。
ロケールを取得するには 2 つの方法があります:
UI 設定に基づいてデータベースに保存されるユーザーのロケール。
一部のコントローラー メソッドは、オプションの lang リクエスト パラメーターを受け入れます。これは、フロントエンド開発者が UI がさまざまな言語でどのようになるかを確認したい場合のテストに役立つ可能性があります。なぜなら、各言語の文の長さは同じではないからです。
今日はここまでです。楽しんでいただければ幸いです。
ソース コードは、私の GitHub アカウントのリポジトリで利用できます。
ご質問がございましたら、LinkedIn 経由でお気軽にお問い合わせください。
以上がSpring Boot で例外メッセージのローカライゼーションを処理する最良の方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。