diff --git a/documents/contents/app-architecture/client-side-rendering/global-function/exception-handling.md b/documents/contents/app-architecture/client-side-rendering/global-function/exception-handling.md index 7099e8f4b..00e26b27c 100644 --- a/documents/contents/app-architecture/client-side-rendering/global-function/exception-handling.md +++ b/documents/contents/app-architecture/client-side-rendering/global-function/exception-handling.md @@ -121,7 +121,19 @@ ProblemDetails は、 HTTP API のエラーレスポンスを標準化するた | 問題が発生したリソースの URI | instance | 任意 | 問題の発生場所を示す URI です。リクエスト先と異なるリソースが問題の発生したリソースである場合、実装の詳細やデータなどの内部情報が漏洩する可能性があるため、追加には注意が必要です。 | | 任意のパラメータ | | 任意 | 拡張メンバーです。必要に応じて ProblemDetails のプロパティを拡張する場合に利用します。 | -AlesInfiny Maia OSS Edition では、上記のプロパティに加えて拡張メンバーとして以下を定義しています。 +ProblemDetails のレスポンスに含める各プロパティは以下のような観点をもとに取捨選択します。 + +- 環境による判断 + + - 本番環境の場合には、ユーザーが見て管理者に伝えるための情報のみをプロパティに含めるべきです。 + - 開発環境の場合には、開発者がデバッグやテストなどの作業で確認すべき情報を含めるべきです。 + +- API の用途による判断 + + - 外部公開 API の場合には、セキュリティやプライバシーを考慮し、必要最低限の情報を提供するようにプロパティを設定します。 + - 内部 API の場合には、画面に対応したエラーレスポンスとして含めるべきプロパティを設定します。 + +また、 AlesInfiny Maia OSS Edition では、フロントエンド側で管理しているメッセージを取得するために以下の拡張メンバーを追加で定義しています。 - exceptionId @@ -139,7 +151,7 @@ AlesInfiny Maia OSS Edition では、上記のプロパティに加えて拡張 ```json title="開発環境の場合のエラーレスポンス" HTTP/1.1 400 Bad Request -Content-Type: application/json; charset=utf-8 +Content-Type: application/problem+json; charset=utf-8 { "type": "https://hoge.com/error/catalogItemIdDoesNotExistInBasket", @@ -153,7 +165,7 @@ Content-Type: application/json; charset=utf-8 ```json title="本番環境の場合のエラーレスポンス" HTTP/1.1 400 Bad Request -Content-Type: application/json; charset=utf-8 +Content-Type: application/problem+json; charset=utf-8 { "type": "https://hoge.com/error/catalogItemIdDoesNotExistInBasket", diff --git a/documents/contents/app-architecture/client-side-rendering/global-function/message-management-policy.md b/documents/contents/app-architecture/client-side-rendering/global-function/message-management-policy.md index 89675769a..80cc317a9 100644 --- a/documents/contents/app-architecture/client-side-rendering/global-function/message-management-policy.md +++ b/documents/contents/app-architecture/client-side-rendering/global-function/message-management-policy.md @@ -109,7 +109,7 @@ JSON ファイルでは、以下のようにメッセージ文字列を識別す OpenAPI 仕様書などの各 JSON ファイルと命名規則を統一するため、メッセージコードをキャメルケースとします。 それに伴い、フロントエンド側に合わせてバックエンドのプロパティファイルのメッセージコードもキャメルケースで記載します。 -バックエンドのプロパティファイルの設定例は、[こちら](../global-function/message-management-policy.md#message-codes-definition) を確認してください。 +バックエンドのプロパティファイルの設定例は、[こちら](../../overview/java-application-processing-system/message-management-policy.md#property-file-management) を確認してください。 ### エラーメッセージ内のパラメータ {#parameter-of-error-messages} diff --git a/documents/contents/app-architecture/overview/java-application-processing-system/message-management-policy.md b/documents/contents/app-architecture/overview/java-application-processing-system/message-management-policy.md index fab227489..33f220e1e 100644 --- a/documents/contents/app-architecture/overview/java-application-processing-system/message-management-policy.md +++ b/documents/contents/app-architecture/overview/java-application-processing-system/message-management-policy.md @@ -17,7 +17,7 @@ description: アプリケーションの形態によらず、 Java アプリケ プロパティファイルでは、以下のようにメッセージ文字列を識別するメッセージコードとメッセージ文字列本体をペアで管理します。 -```properties title="message.properties の例" +```properties title="messages.properties の例" errorOccurred=エラーが発生しました。 ... ``` @@ -30,16 +30,16 @@ errorOccurred=エラーが発生しました。 ## メッセージの管理単位 {#management-unit} -以下のように、ビジネスロジックで発生する業務メッセージと共通処理として発生する共通メッセージを分割して各サブプロジェクトで管理します。 +以下のように、ビジネスロジックで利用する業務メッセージと共通処理として利用する共通メッセージを分割して各サブプロジェクトで管理します。 ```terminal linenums="0" root/ ------------------------------------------ root フォルダー ├ application-core/src/main/resource │ └ applicationcore --------------------------- 業務メッセージのプロパティファイルを一括管理するフォルダー - │ └ message.properties --------------------- 業務メッセージのプロパティファイル + │ └ messages.properties --------------------- 業務メッセージのプロパティファイル └ system-common/src/main/resource └ systemcommon ------------------------------ 共通メッセージのプロパティファイルを一括管理するフォルダー - └ message.properties --------------------- 共通メッセージのプロパティファイル + └ messages.properties --------------------- 共通メッセージのプロパティファイル ``` 業務メッセージと共通メッセージとして格納するメッセージの例は以下の通りです。 @@ -63,14 +63,14 @@ root/ ------------------------------------------ root フォルダー root/ ------------------------------------------ root フォルダー ├ application-core/src/main/resource │ └ applicationcore --------------------------- 業務メッセージのプロパティファイルを一括管理するフォルダー - │ ├ message_en.properties ------------------ 業務メッセージのプロパティファイル(英語) - │ └ message_ja.properties ------------------ 業務メッセージのプロパティファイル(日本語) + │ ├ messages_en.properties ------------------ 業務メッセージのプロパティファイル(英語) + │ └ messages_ja.properties ------------------ 業務メッセージのプロパティファイル(日本語) └ system-common/src/main/resource └ systemcommon ------------------------------ 共通メッセージのプロパティファイルを一括管理するフォルダー - ├ message_en.properties ------------------ 共通メッセージのプロパティファイル(英語) - └ message_ja.properties ------------------ 共通メッセージのプロパティファイル(日本語) + ├ messages_en.properties ------------------ 共通メッセージのプロパティファイル(英語) + └ messages_ja.properties ------------------ 共通メッセージのプロパティファイル(日本語) ``` アプリケーション起動時に使用するメッセージファイルを切り替えることで、開発者に応じた言語を設定します。 -メッセージ管理方針に従った機能の実装方法などの詳細については、[こちら](../../../guidebooks/how-to-develop/java/common-project-settings.md) を確認してください。 +メッセージ管理方針に従った機能の実装方法などの詳細については、[こちら](../../../guidebooks/how-to-develop/java/sub-project-settings/message-management.md) を確認してください。 diff --git a/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/application-core-project-settings.md b/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/application-core-project-settings.md index 59af86e69..fa26c62fd 100644 --- a/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/application-core-project-settings.md +++ b/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/application-core-project-settings.md @@ -112,3 +112,7 @@ application-core プロジェクトの `src` 以下にある、 `ApplicationCore enabled = true } ``` + +## メッセージ管理の設定 {#message-management-settings} + +application-core プロジェクトで管理する業務メッセージの設定方法については、[こちら](./message-management.md) を参照してください。 diff --git a/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/index.md b/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/index.md index 2cc56435e..2f1c812c9 100644 --- a/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/index.md +++ b/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/index.md @@ -38,3 +38,7 @@ description: バックエンドで動作する Java アプリケーションの 1. [プラグイン、依存ライブラリのバージョン定義一元化](./project-version-control.md) プラグイン、依存ライブラリのバージョン定義を一元的に管理する方法について解説します。 + +1. [メッセージ管理機能の設定](./message-management.md) + + マルチプロジェクト構成におけるメッセージ管理の設定方法について解説します。 diff --git a/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/message-management.md b/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/message-management.md new file mode 100644 index 000000000..31747faa6 --- /dev/null +++ b/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/message-management.md @@ -0,0 +1,99 @@ +--- +title: Java 編 +description: バックエンドで動作する Java アプリケーションの 開発手順を解説します。 +--- + + + +# メッセージ管理機能の設定 {#top} + +バックエンドのメッセージ管理方針に関するアーキテクチャについては、[こちら](../../../../app-architecture/overview/java-application-processing-system/message-management-policy.md) をご確認ください。 + +## 設定方法 {#settings} + +本設定で利用するフォルダーの構成は以下の通りです。 + +```terminal linenums="0" +root/ ------------------------------------------ root フォルダー + ├ application-core/src/main/resource + │ └ applicationcore --------------------------- 業務メッセージのプロパティファイルを一元管理するフォルダー + │ └ messages.properties --------------------- 業務メッセージのプロパティファイル + └ system-common/src/main/resource + └ systemcommon ------------------------------ 共通メッセージのプロパティファイルを一元管理するフォルダー + └ messages.properties --------------------- 共通メッセージのプロパティファイル +``` + +### プロパティファイルの作成 {#creating-property-file} + +メッセージに関するプロパティファイルは各サブプロジェクトの `/src/main/resource/<サブプロジェクト名>` フォルダーに集約します。 +以下のように、メッセージ本体を格納するプロパティファイルを作成します。 + +```properties title="message.properties" +systemError=想定外のシステムエラーが発生しました +businessError=想定外の業務エラーが発生しました +``` + +### プロパティファイルの読込 {#reading-property-files} + +以下のように、 web プロジェクトなどエントリーポイントとなるサブプロジェクトの application.properties にプロパティファイルを読み込む設定を記載します。 + +``` properties title="application.properties" +spring.messages.basename=applicationcore.messages,systemcommon.messages +``` + +読み込むプロパティファイルは `src/main/resource` 配下の `<フォルダー名>.<ファイル名>` で指定します。 +プロパティファイルが複数ある場合は、ファイルの間をカンマで区切ります。 + +### メッセージの取得 {#getting-messages} + +読み込んだプロパティファイルのメッセージを取得するためには、 [`MessageSource` :material-open-in-new:](https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/context/MessageSource.html){ target=_blank } クラスを利用します。 + +以下は、プロパティファイルからメッセージを取得し、ログに出力するためのエラーメッセージを整形する `ErrorMessageBuilder` クラスの例です。 + +```java title="ErrorMessageBuilder.java" hl_lines="5 14" +@Getter +@AllArgsConstructor +public class ErrorMessageBuilder { + + private static final MessageSource messageSource = (MessageSource) ApplicationContextWrapper.getBean(MessageSource.class); + + private Exception ex; + private String exceptionId; + private String[] logMessageValue; + private String[] frontMessageValue; + + public String createLogMessageStackTrace() { + StringBuilder builder = new StringBuilder(); + String exceptionMessage = messageSource.getMessage(exceptionId, logMessageValue, Locale.getDefault()); + builder.append(exceptionId).append(" ").append(exceptionMessage).append(SystemPropertyConstants.LINE_SEPARATOR); + StringWriter writer = new StringWriter(); + ex.printStackTrace(new PrintWriter(writer)); + builder.append(writer.getBuffer().toString()); + return builder.toString(); + } +} +``` + + +また、 `#!java @Service` や `#!java @Controller` 、 `#!java @Component` といった Bean 登録されたクラス内で `MessageSource` を利用する場合は、 `#!java @Autowired` による DI で実装します。 + + +以下は、プロパティファイルからエラーレスポンスに含めるメッセージを整形する `ProblemDetailsFactory.java` クラスの例です。 + +```java title="ProblemDetailsFactory.java" hl_lines="4 5 11" +@Component +public class ProblemDetailsFactory { + + @Autowired + private MessageSource messages; + + public ProblemDetail createProblemDetail(ErrorMessageBuilder errorBuilder, String titleId, HttpStatus status) { + + ProblemDetail problemDetail = ProblemDetail.forStatus(status); + + problemDetail.setTitle(messages.getMessage(titleId, new String[] {}, Locale.getDefault())); + + ... + } +} +``` diff --git a/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/system-common-project-settings.md b/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/system-common-project-settings.md index cf544cbdd..6af7f6289 100644 --- a/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/system-common-project-settings.md +++ b/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/system-common-project-settings.md @@ -95,3 +95,7 @@ system-common プロジェクトの `src` 以下にある、 `SystemCommonApplic enabled = true } ``` + +## メッセージ管理の設定 {#message-management-settings} + +system-common プロジェクトで管理する共通メッセージの設定方法については、[こちら](./message-management.md) を参照してください。 diff --git a/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/web-project-settings.md b/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/web-project-settings.md index c942f1ae7..41210075e 100644 --- a/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/web-project-settings.md +++ b/documents/contents/guidebooks/how-to-develop/java/sub-project-settings/web-project-settings.md @@ -278,3 +278,7 @@ build.dependsOn("generateOpenApiDocs") ## CORS (クロスオリジンリソース共有)環境の設定 {#cors-environment} Web API を公開するオリジンと、呼び出し元となるクライアントスクリプトを公開するオリジンが異なる場合(クロスオリジン)の設定は、[こちら](../../cors/index.md) を参照してください。 + +## メッセージ読込に関する設定 {#message-reading-settings} + +他サブプロジェクトで管理されているメッセージを読み込む場合の設定は、[こちら](./message-management.md) を参照してください。 diff --git a/documents/mkdocs.yml b/documents/mkdocs.yml index af0430db4..54b261103 100644 --- a/documents/mkdocs.yml +++ b/documents/mkdocs.yml @@ -90,6 +90,7 @@ nav: - batch プロジェクトの設定: guidebooks/how-to-develop/java/sub-project-settings/batch-project-settings.md - system-common プロジェクトの設定: guidebooks/how-to-develop/java/sub-project-settings/system-common-project-settings.md - プラグイン、依存ライブラリのバージョン定義一元化: guidebooks/how-to-develop/java/sub-project-settings/project-version-control.md + - メッセージ管理機能の設定: guidebooks/how-to-develop/java/sub-project-settings/message-management.md - Vue.js 編: - guidebooks/how-to-develop/vue-js/index.md - 事前準備: guidebooks/how-to-develop/vue-js/preparation.md diff --git a/samples/azure-ad-b2c-sample/auth-backend/.vscode/launch.json b/samples/azure-ad-b2c-sample/auth-backend/.vscode/launch.json index 573e07dab..3f8e820e0 100644 --- a/samples/azure-ad-b2c-sample/auth-backend/.vscode/launch.json +++ b/samples/azure-ad-b2c-sample/auth-backend/.vscode/launch.json @@ -8,7 +8,7 @@ "console": "internalConsole", "mainClass": "com.dressca.web.WebApplication", "projectName": "web", - "args": "", + "args": "--spring.profiles.active=local", "envFile": "${workspaceFolder}/.env" } ] diff --git a/samples/azure-ad-b2c-sample/auth-backend/api-docs/api-specification.json b/samples/azure-ad-b2c-sample/auth-backend/api-docs/api-specification.json index 62399d19f..8087eccf1 100644 --- a/samples/azure-ad-b2c-sample/auth-backend/api-docs/api-specification.json +++ b/samples/azure-ad-b2c-sample/auth-backend/api-docs/api-specification.json @@ -60,6 +60,13 @@ "description": "成功." }, "401": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetail" + } + } + }, "description": "未認証エラー." } }, @@ -77,27 +84,56 @@ }, "components": { "schemas": { - "TimeResponse": { + "ProblemDetail": { "type": "object", "properties": { - "serverTime": { + "detail": { "type": "string" + }, + "instance": { + "type": "string", + "format": "uri" + }, + "properties": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "status": { + "type": "integer", + "format": "int32" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string", + "format": "uri" } - }, + } + }, + "TimeResponse": { "required": [ "serverTime" - ] + ], + "type": "object", + "properties": { + "serverTime": { + "type": "string" + } + } }, "UserResponse": { + "required": [ + "userId" + ], "type": "object", "properties": { "userId": { "type": "string" } - }, - "required": [ - "userId" - ] + } } }, "securitySchemes": { diff --git a/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/java/com/dressca/systemcommon/constant/CommonExceptionIdConstants.java b/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/java/com/dressca/systemcommon/constant/CommonExceptionIdConstants.java new file mode 100644 index 000000000..67bb3a853 --- /dev/null +++ b/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/java/com/dressca/systemcommon/constant/CommonExceptionIdConstants.java @@ -0,0 +1,15 @@ +package com.dressca.systemcommon.constant; + +/** + * 例外ID用定数クラス。 + */ +public class CommonExceptionIdConstants { + /** 想定外のシステムエラーが発生しました。 */ + public static final String E_SYSTEM = "systemError"; + + /** 想定外の業務エラーが発生しました。 */ + public static final String E_BUSINESS = "businessError"; + + /** 未認証のエラーが発生しました。 */ + public static final String E_UNAUTHORIZED = "unauthorizedError"; +} diff --git a/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/java/com/dressca/systemcommon/constant/ExceptionIdConstant.java b/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/java/com/dressca/systemcommon/constant/ExceptionIdConstant.java deleted file mode 100644 index 09bb4aef7..000000000 --- a/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/java/com/dressca/systemcommon/constant/ExceptionIdConstant.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.dressca.systemcommon.constant; - -/** - * 例外ID用定数クラス。 - */ -public class ExceptionIdConstant { - /** 想定外のエラー。 */ - public static final String E_SHARE0000 = "E_SHARE0000"; - - /** 未認証のエラー。 */ - public static final String E_AUTH0001 = "E_AUTH0001"; -} diff --git a/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/java/com/dressca/systemcommon/constant/MessageIdConstant.java b/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/java/com/dressca/systemcommon/constant/MessageIdConstant.java deleted file mode 100644 index 5b0ef0005..000000000 --- a/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/java/com/dressca/systemcommon/constant/MessageIdConstant.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.dressca.systemcommon.constant; - -/** - * メッセージID用定数クラス。 - */ -public class MessageIdConstant { - - // システムエラーメッセージ用 - /** 想定外のエラーが発生しました。 */ - public static final String E_SHARE0000_FRONT = "F_SHARE0000.front"; - public static final String E_SHARE0000_LOG = "F_SHARE0000.log"; - /** 未認証のエラーが発生しました。 */ - public static final String E_AUTH0001_FRONT = "F_AUTH0001.front"; - public static final String E_AUTH0001_LOG = "F_AUTH0001.log"; -} diff --git a/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/resources/application-common.properties b/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/resources/application-common.properties index 9e0815194..8382ded52 100644 --- a/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/resources/application-common.properties +++ b/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/resources/application-common.properties @@ -1,2 +1,2 @@ -spring.messages.basename=messages +spring.messages.basename=systemcommon.messages spring.messages.encoding=UTF-8 diff --git a/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/resources/messages.properties b/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/resources/messages.properties deleted file mode 100644 index 4e1161a1b..000000000 --- a/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/resources/messages.properties +++ /dev/null @@ -1,5 +0,0 @@ -E_SHARE0000.front=想定外のエラーが発生しました -E_SHARE0000.log=想定外のエラーが発生しました - -E_AUTH0001.front=未認証のエラーが発生しました -E_AUTH0001.log=未認証のエラーが発生しました \ No newline at end of file diff --git a/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/resources/systemcommon/messages.properties b/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/resources/systemcommon/messages.properties new file mode 100644 index 000000000..a2febb402 --- /dev/null +++ b/samples/azure-ad-b2c-sample/auth-backend/system-common/src/main/resources/systemcommon/messages.properties @@ -0,0 +1,3 @@ +systemError=想定外のシステムエラーが発生しました。 +businessError=想定外の業務エラーが発生しました。 +unauthorizedError=未認証のエラーが発生しました。 \ No newline at end of file diff --git a/samples/azure-ad-b2c-sample/auth-backend/web/build.gradle b/samples/azure-ad-b2c-sample/auth-backend/web/build.gradle index 42e9580f9..5f1577916 100644 --- a/samples/azure-ad-b2c-sample/auth-backend/web/build.gradle +++ b/samples/azure-ad-b2c-sample/auth-backend/web/build.gradle @@ -56,5 +56,12 @@ openApi { tasks.named('test') { useJUnitPlatform() } +tasks.register('bootRunDev', org.springframework.boot.gradle.tasks.run.BootRun){ + group = 'application' + description = 'Runs this project as a Spring Boot Application using local profile.' + args = ["--spring.profiles.active=local"] + main = 'com.dressca.web.WebApplication' + classpath = sourceSets.main.runtimeClasspath +} build.dependsOn("generateOpenApiDocs") \ No newline at end of file diff --git a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/constant/ProblemDetailsConstant.java b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/constant/ProblemDetailsConstant.java deleted file mode 100644 index e21098d44..000000000 --- a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/constant/ProblemDetailsConstant.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.dressca.web.constant; - -/** - * ProblemDetail用の定数クラス。 - */ -public class ProblemDetailsConstant { - - /** システムエラーのタイトル。 */ - public static final String SYSTEM_ERROR_TITLE = "システムエラー"; - - /** errorキー。 */ - public static final String ERROR_KEY = "error"; -} diff --git a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/constant/WebConstants.java b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/constant/WebConstants.java new file mode 100644 index 000000000..70c4c5f06 --- /dev/null +++ b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/constant/WebConstants.java @@ -0,0 +1,13 @@ +package com.dressca.web.constant; + +/** + * web プロジェクトで利用する汎用定数クラス。 + */ +public class WebConstants { + + /** Exception ID。 */ + public static final String EXCEPTION_ID = "exceptionId"; + + /** Exception ID に紐づく例外値。 */ + public static final String EXCEPTION_VALUES = "exceptionValues"; +} diff --git a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/controller/UserController.java b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/controller/UserController.java index b2417f41f..6a6e2c458 100644 --- a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/controller/UserController.java +++ b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/controller/UserController.java @@ -1,5 +1,6 @@ package com.dressca.web.controller; +import org.springframework.http.ProblemDetail; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.CrossOrigin; @@ -34,7 +35,7 @@ public class UserController { @SecurityRequirement(name = "Bearer") }) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "成功.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserResponse.class))), - @ApiResponse(responseCode = "401", description = "未認証エラー.", content = @Content) + @ApiResponse(responseCode = "401", description = "未認証エラー.", content = @Content(mediaType = "application/problem+json", schema = @Schema(implementation = ProblemDetail.class))) }) @GetMapping diff --git a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdvice.java b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdvice.java index 274a5a1c0..ac61497d8 100644 --- a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdvice.java +++ b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdvice.java @@ -1,13 +1,12 @@ package com.dressca.web.controller.advice; import jakarta.servlet.http.HttpServletRequest; -import com.dressca.systemcommon.constant.ExceptionIdConstant; +import com.dressca.systemcommon.constant.CommonExceptionIdConstants; import com.dressca.systemcommon.constant.SystemPropertyConstants; -import com.dressca.web.constant.ProblemDetailsConstant; import com.dressca.web.log.ErrorMessageBuilder; -import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ProblemDetail; @@ -25,24 +24,31 @@ public class ExceptionHandlerControllerAdvice extends ResponseEntityExceptionHan private static final Logger apLog = LoggerFactory.getLogger(SystemPropertyConstants.APPLICATION_LOG_LOGGER); + @Autowired + private ProblemDetailsFactory problemDetailsFactory; + /** - * 例外をステータースコード401で返却する。 + * 未認証の例外をステータースコード401で返却する。 * * @param e 未認証の例外 * @param req リクエスト * @return ステータースコード401のレスポンス */ @ExceptionHandler(AccessDeniedException.class) - public ResponseEntity accessDeniedHandleException(AccessDeniedException e, HttpServletRequest req) { - ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, ExceptionIdConstant.E_AUTH0001, null, null); + public ResponseEntity accessDeniedHandleException(AccessDeniedException e, HttpServletRequest req) { + ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, CommonExceptionIdConstants.E_UNAUTHORIZED, null, + null); apLog.error(errorBuilder.createLogMessageStackTrace()); + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail(errorBuilder, + CommonExceptionIdConstants.E_BUSINESS, + HttpStatus.UNAUTHORIZED); return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .contentType(MediaType.APPLICATION_JSON) - .body(null); + .contentType(MediaType.APPLICATION_PROBLEM_JSON) + .body(problemDetail); } /** - * 例外をステータースコード500で返却する。 + * その他の例外をステータースコード500で返却する。 * * @param e その他の例外 * @param req リクエスト @@ -50,19 +56,13 @@ public ResponseEntity accessDeniedHandleException(AccessDeniedException e, Ht */ @ExceptionHandler(Exception.class) public ResponseEntity handleException(Exception e, HttpServletRequest req) { - ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, ExceptionIdConstant.E_SHARE0000, null, null); + ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, CommonExceptionIdConstants.E_SYSTEM, null, null); apLog.error(errorBuilder.createLogMessageStackTrace()); - ProblemDetail problemDetail = createProblemDetail(errorBuilder, ProblemDetailsConstant.SYSTEM_ERROR_TITLE); + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail(errorBuilder, + CommonExceptionIdConstants.E_SYSTEM, + HttpStatus.INTERNAL_SERVER_ERROR); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .contentType(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) .body(problemDetail); } - - private ProblemDetail createProblemDetail(ErrorMessageBuilder errorBuilder, String title) { - Map errorProperty = Map.of(errorBuilder.getExceptionId(), errorBuilder.createFrontErrorMessage()); - ProblemDetail problemDetail = ProblemDetail.forStatus(HttpStatus.INTERNAL_SERVER_ERROR); - problemDetail.setTitle(title); - problemDetail.setProperty(ProblemDetailsConstant.ERROR_KEY, errorProperty); - return problemDetail; - } } diff --git a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/advice/ProblemDetailsCreation.java b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/controller/advice/ProblemDetailsFactory.java similarity index 59% rename from samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/advice/ProblemDetailsCreation.java rename to samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/controller/advice/ProblemDetailsFactory.java index 98c5a3f4d..287bc3635 100644 --- a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/advice/ProblemDetailsCreation.java +++ b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/controller/advice/ProblemDetailsFactory.java @@ -2,54 +2,61 @@ import java.util.Arrays; import java.util.LinkedHashMap; +import java.util.Locale; import java.util.Map; import java.util.Objects; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; import org.springframework.core.env.Environment; import org.springframework.http.HttpStatus; import org.springframework.http.ProblemDetail; import org.springframework.stereotype.Component; -import com.dressca.web.constant.ProblemDetailsConstant; +import com.dressca.web.constant.WebConstants; import com.dressca.web.log.ErrorMessageBuilder; /** * エラーレスポンスに含める ProblemDetails を作成するクラスです。 */ @Component -public class ProblemDetailsCreation { +public class ProblemDetailsFactory { @Autowired private Environment env; + @Autowired + private MessageSource messages; + /** - * その他のシステムエラーをステータースコード500で返却する。 + * エラーレスポンスに含める ProblemDetails を作成する。 * * @param errorBuilder 例外ビルダー - * @param title タイトル + * @param titleId タイトルのメッセージ ID * @param status ステータスコード * @return エラーレスポンスに格納する ProblemDetails */ - public ProblemDetail createProblemDetail(ErrorMessageBuilder errorBuilder, String title, HttpStatus status) { + public ProblemDetail createProblemDetail(ErrorMessageBuilder errorBuilder, String titleId, HttpStatus status) { ProblemDetail problemDetail = ProblemDetail.forStatus(status); - problemDetail.setTitle(title); + problemDetail.setTitle(messages.getMessage(titleId, new String[] {}, Locale.getDefault())); + // 開発環境においては、 detail プロパティにスタックトレースを含める + // 開発環境かどうかの判断は、環境変数の Profile をもとに判断する String[] activeProfiles = env.getActiveProfiles(); if (activeProfiles.length == 0) { activeProfiles = env.getDefaultProfiles(); } - // local 環境においては detail を含める if (Arrays.stream(activeProfiles).filter(profile -> Objects.equals(profile, "local")) .findFirst().isPresent()) { problemDetail.setDetail(errorBuilder.createLogMessageStackTrace()); } + // 拡張メンバーとして exceptionId と exceptionValues を含める Map errorProperty = new LinkedHashMap() { { - put(ProblemDetailsConstant.EXCEPTION_ID, errorBuilder.getExceptionId()); - put(ProblemDetailsConstant.EXCEPTION_VALUES, errorBuilder.getFrontMessageValue()); + put(WebConstants.EXCEPTION_ID, errorBuilder.getExceptionId()); + put(WebConstants.EXCEPTION_VALUES, errorBuilder.getFrontMessageValue()); } }; diff --git a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/log/ErrorMessageBuilder.java b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/log/ErrorMessageBuilder.java index 2b4cd563b..03d8849f0 100644 --- a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/log/ErrorMessageBuilder.java +++ b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/java/com/dressca/web/log/ErrorMessageBuilder.java @@ -10,15 +10,12 @@ import lombok.Getter; /** - * ログやレスポンスでエラーメッセージを作成するためのクラスです。 + * ログでエラーメッセージを作成するためのクラスです。 */ @Getter @AllArgsConstructor public class ErrorMessageBuilder { - private static final String EXCEPTION_MESSAGE_SUFFIX_LOG = "log"; - private static final String EXCEPTION_MESSAGE_SUFFIX_FRONT = "front"; - private static final String PROPERTY_DELIMITER = "."; private static final MessageSource messageSource = (MessageSource) ApplicationContextWrapper .getBean(MessageSource.class); @@ -34,22 +31,11 @@ public class ErrorMessageBuilder { */ public String createLogMessageStackTrace() { StringBuilder builder = new StringBuilder(); - String code = String.join(PROPERTY_DELIMITER, exceptionId, EXCEPTION_MESSAGE_SUFFIX_LOG); - String exceptionMessage = messageSource.getMessage(code, logMessageValue, Locale.getDefault()); + String exceptionMessage = messageSource.getMessage(exceptionId, logMessageValue, Locale.getDefault()); builder.append(exceptionId).append(" ").append(exceptionMessage).append(SystemPropertyConstants.LINE_SEPARATOR); StringWriter writer = new StringWriter(); ex.printStackTrace(new PrintWriter(writer)); builder.append(writer.getBuffer().toString()); return builder.toString(); } - - /** - * ProblemDetailsのerror情報に格納するメッセージを作成します。 - * - * @return エラーメッセージ - */ - public String createFrontErrorMessage() { - String code = String.join(PROPERTY_DELIMITER, exceptionId, EXCEPTION_MESSAGE_SUFFIX_FRONT); - return messageSource.getMessage(code, frontMessageValue, Locale.getDefault()); - } } diff --git a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/resources/application-common.properties b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/resources/application-common.properties index 47dffda0d..eafd01b1f 100644 --- a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/resources/application-common.properties +++ b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/resources/application-common.properties @@ -2,3 +2,7 @@ springdoc.api-docs.path=/api-docs springdoc.swagger-ui.path=/swagger-ui.html springdoc.show-actuator=true + +# messages.properties +spring.messages.basename=systemcommon.messages +spring.messages.encoding=UTF-8 diff --git a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/resources/application.properties b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/resources/application.properties index d672d1a90..9aa1cfe09 100644 --- a/samples/azure-ad-b2c-sample/auth-backend/web/src/main/resources/application.properties +++ b/samples/azure-ad-b2c-sample/auth-backend/web/src/main/resources/application.properties @@ -3,7 +3,7 @@ spring.profiles.group.local=common,dev spring.profiles.group.production=common,prd spring.profiles.group.test=common,ut # 環境情報未指定の場合に使用するプロファイル(環境情報を指定する場合、起動コマンドに「-Dspring.profiles.active=<プロファイル名>'」を追加する) -spring.profiles.default=local +spring.profiles.default=production # AzureADB2Cの呼び出し設定 spring.cloud.azure.active-directory.b2c.enabled=true diff --git a/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/.openapi-generator/FILES b/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/.openapi-generator/FILES index 63d889f91..22748cd65 100644 --- a/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/.openapi-generator/FILES +++ b/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/.openapi-generator/FILES @@ -1,14 +1,15 @@ -.gitignore -.npmignore -.openapi-generator-ignore -api.ts -api/server-time-api.ts -api/user-api.ts -base.ts -common.ts -configuration.ts -git_push.sh -index.ts -models/index.ts -models/time-response.ts -models/user-response.ts +.gitignore +.npmignore +.openapi-generator-ignore +api.ts +api/server-time-api.ts +api/user-api.ts +base.ts +common.ts +configuration.ts +git_push.sh +index.ts +models/index.ts +models/problem-detail.ts +models/time-response.ts +models/user-response.ts diff --git a/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/api/user-api.ts b/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/api/user-api.ts index a758e6e79..8cd9ae5f1 100644 --- a/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/api/user-api.ts +++ b/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/api/user-api.ts @@ -22,6 +22,8 @@ import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObj // @ts-ignore import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base'; // @ts-ignore +import type { ProblemDetail } from '../models'; +// @ts-ignore import type { UserResponse } from '../models'; /** * UserApi - axios parameter creator diff --git a/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/models/index.ts b/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/models/index.ts index a95a0ad25..5c01d1893 100644 --- a/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/models/index.ts +++ b/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/models/index.ts @@ -1,2 +1,3 @@ +export * from './problem-detail'; export * from './time-response'; export * from './user-response'; diff --git a/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/models/problem-detail.ts b/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/models/problem-detail.ts new file mode 100644 index 000000000..3de2e85e2 --- /dev/null +++ b/samples/azure-ad-b2c-sample/auth-frontend/app/src/generated/api-client/models/problem-detail.ts @@ -0,0 +1,60 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Azure AD B2C ユーザー認証 + * Azure AD B2Cを利用したユーザー認証機能を提供するサンプルアプリケーションです。 + * + * The version of the OpenAPI document: v1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface ProblemDetail + */ +export interface ProblemDetail { + /** + * + * @type {string} + * @memberof ProblemDetail + */ + 'detail'?: string; + /** + * + * @type {string} + * @memberof ProblemDetail + */ + 'instance'?: string; + /** + * + * @type {{ [key: string]: object; }} + * @memberof ProblemDetail + */ + 'properties'?: { [key: string]: object; }; + /** + * + * @type {number} + * @memberof ProblemDetail + */ + 'status'?: number; + /** + * + * @type {string} + * @memberof ProblemDetail + */ + 'title'?: string; + /** + * + * @type {string} + * @memberof ProblemDetail + */ + 'type'?: string; +} + diff --git a/samples/web-csr/dressca-backend/api-docs/api-specification.json b/samples/web-csr/dressca-backend/api-docs/api-specification.json index 260c73089..7613fcfa0 100644 --- a/samples/web-csr/dressca-backend/api-docs/api-specification.json +++ b/samples/web-csr/dressca-backend/api-docs/api-specification.json @@ -123,6 +123,13 @@ "description": "成功." }, "404": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetail" + } + } + }, "description": "アセットコードに対応するアセットがない." } }, @@ -171,9 +178,23 @@ "description": "作成完了" }, "400": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetail" + } + } + }, "description": "リクエストエラー" }, "500": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetail" + } + } + }, "description": "サーバーエラー" } }, @@ -203,6 +224,13 @@ "description": "成功." }, "400": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetail" + } + } + }, "description": "リクエストエラー" } }, @@ -232,9 +260,23 @@ "description": "成功." }, "400": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetail" + } + } + }, "description": "リクエストエラー." }, "404": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetail" + } + } + }, "description": "買い物かご内に指定したカタログアイテム Id がない." } }, @@ -352,6 +394,13 @@ "description": "成功" }, "400": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetail" + } + } + }, "description": "リクエストエラー" } }, @@ -442,9 +491,23 @@ "description": "成功." }, "400": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetail" + } + } + }, "description": "リクエストエラー." }, "500": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetail" + } + } + }, "description": "サーバーエラー." } }, @@ -481,6 +544,13 @@ "description": "成功." }, "404": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetail" + } + } + }, "description": "注文IDが存在しない." } }, @@ -826,6 +896,35 @@ } } }, + "ProblemDetail": { + "type": "object", + "properties": { + "detail": { + "type": "string" + }, + "instance": { + "type": "string", + "format": "uri" + }, + "properties": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "status": { + "type": "integer", + "format": "int32" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string", + "format": "uri" + } + } + }, "PutBasketItemsRequest": { "required": [ "catalogItemId", diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/AssetApplicationService.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/AssetApplicationService.java index 63497bcbe..ea62db042 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/AssetApplicationService.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/AssetApplicationService.java @@ -13,7 +13,7 @@ import com.dressca.applicationcore.assets.AssetRepository; import com.dressca.applicationcore.assets.AssetResourceInfo; import com.dressca.applicationcore.assets.AssetStore; -import com.dressca.applicationcore.constant.MessageIdConstant; +import com.dressca.applicationcore.constant.MessageIdConstants; import com.dressca.systemcommon.constant.SystemPropertyConstants; import lombok.AllArgsConstructor; @@ -44,7 +44,7 @@ public class AssetApplicationService { public AssetResourceInfo getAssetResourceInfo(String assetCode) throws AssetNotFoundException { apLog - .debug(messages.getMessage(MessageIdConstant.D_ASSET_GET_ASSET, + .debug(messages.getMessage(MessageIdConstants.D_ASSET_GET_ASSET, new Object[] { assetCode }, Locale.getDefault())); diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/CatalogApplicationService.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/CatalogApplicationService.java index 97ac71827..21be4a3ba 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/CatalogApplicationService.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/CatalogApplicationService.java @@ -14,7 +14,7 @@ import com.dressca.applicationcore.catalog.CatalogCategoryRepository; import com.dressca.applicationcore.catalog.CatalogItem; import com.dressca.applicationcore.catalog.CatalogRepository; -import com.dressca.applicationcore.constant.MessageIdConstant; +import com.dressca.applicationcore.constant.MessageIdConstants; import com.dressca.systemcommon.constant.SystemPropertyConstants; import lombok.AllArgsConstructor; @@ -46,7 +46,7 @@ public class CatalogApplicationService { */ public List getCatalogItems(long brandId, long categoryId, int page, int pageSize) { - apLog.debug(messages.getMessage(MessageIdConstant.D_CATALOG_GET_CATALOG_ITEMS, + apLog.debug(messages.getMessage(MessageIdConstants.D_CATALOG_GET_CATALOG_ITEMS, new Object[] { brandId, categoryId, page, pageSize }, Locale.getDefault())); return this.catalogRepository.findByBrandIdAndCategoryId(brandId, categoryId, page, pageSize); @@ -61,7 +61,7 @@ public List getCatalogItems(long brandId, long categoryId, int page */ public int countCatalogItems(long brandId, long categoryId) { - apLog.debug(messages.getMessage(MessageIdConstant.D_CATALOG_COUNT_CATALOG_ITEMS, + apLog.debug(messages.getMessage(MessageIdConstants.D_CATALOG_COUNT_CATALOG_ITEMS, new Object[] { brandId, categoryId }, Locale.getDefault())); @@ -75,7 +75,7 @@ public int countCatalogItems(long brandId, long categoryId) { */ public List getBrands() { - apLog.debug(messages.getMessage(MessageIdConstant.D_CATALOG_GET_BRANDS, + apLog.debug(messages.getMessage(MessageIdConstants.D_CATALOG_GET_BRANDS, new Object[] {}, Locale.getDefault())); @@ -89,7 +89,7 @@ public List getBrands() { */ public List getCategories() { - apLog.debug(messages.getMessage(MessageIdConstant.D_CATALOG_GET_CATEGORIES, + apLog.debug(messages.getMessage(MessageIdConstants.D_CATALOG_GET_CATEGORIES, new Object[] {}, Locale.getDefault())); diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/OrderApplicationService.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/OrderApplicationService.java index 7036439d0..8cb658b93 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/OrderApplicationService.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/OrderApplicationService.java @@ -1,6 +1,6 @@ package com.dressca.applicationcore.applicationservice; -import com.dressca.applicationcore.constant.MessageIdConstant; +import com.dressca.applicationcore.constant.MessageIdConstants; import com.dressca.applicationcore.order.Order; import com.dressca.applicationcore.order.OrderNotFoundException; import com.dressca.applicationcore.order.OrderRepository; @@ -40,7 +40,7 @@ public class OrderApplicationService { public Order getOrder(long orderId, String buyerId) throws OrderNotFoundException { apLog.debug( - messages.getMessage(MessageIdConstant.D_ORDER_GET_ORDER, + messages.getMessage(MessageIdConstants.D_ORDER_GET_ORDER, new Object[] { orderId, buyerId }, Locale.getDefault())); diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/ShoppingApplicationService.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/ShoppingApplicationService.java index 466289e4c..9e3eb223c 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/ShoppingApplicationService.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/applicationservice/ShoppingApplicationService.java @@ -19,7 +19,7 @@ import com.dressca.applicationcore.catalog.CatalogItem; import com.dressca.applicationcore.catalog.CatalogNotFoundException; import com.dressca.applicationcore.catalog.CatalogRepository; -import com.dressca.applicationcore.constant.MessageIdConstant; +import com.dressca.applicationcore.constant.MessageIdConstants; import com.dressca.applicationcore.order.CatalogItemOrdered; import com.dressca.applicationcore.order.EmptyBasketOnCheckoutException; import com.dressca.applicationcore.order.Order; @@ -27,7 +27,7 @@ import com.dressca.applicationcore.order.OrderItemAsset; import com.dressca.applicationcore.order.OrderRepository; import com.dressca.applicationcore.order.ShipTo; -import com.dressca.systemcommon.constant.CommonExceptionIdConstant; +import com.dressca.systemcommon.constant.CommonExceptionIdConstants; import com.dressca.systemcommon.constant.SystemPropertyConstants; import com.dressca.systemcommon.exception.SystemException; import lombok.AllArgsConstructor; @@ -61,7 +61,7 @@ public class ShoppingApplicationService { public void addItemToBasket(String buyerId, long catalogItemId, int quantity) throws CatalogNotFoundException { - apLog.debug(messages.getMessage(MessageIdConstant.D_SHOPPING_ADD_ITEM_TO_BASKET, + apLog.debug(messages.getMessage(MessageIdConstants.D_SHOPPING_ADD_ITEM_TO_BASKET, new Object[] { buyerId, catalogItemId, quantity }, Locale.getDefault())); Basket basket = getOrCreateBasketForUser(buyerId); @@ -87,7 +87,7 @@ public void addItemToBasket(String buyerId, long catalogItemId, int quantity) public void setQuantities(String buyerId, Map quantities) throws CatalogNotFoundException, CatalogItemInBasketNotFoundException { - apLog.debug(messages.getMessage(MessageIdConstant.D_SHOPPING_SET_BASKET_ITEMS_QUANTITIES, + apLog.debug(messages.getMessage(MessageIdConstants.D_SHOPPING_SET_BASKET_ITEMS_QUANTITIES, new Object[] { buyerId, quantities }, Locale.getDefault())); @@ -124,7 +124,7 @@ public void setQuantities(String buyerId, Map quantities) */ public BasketDetail getBasketDetail(String buyerId) { - apLog.debug(messages.getMessage(MessageIdConstant.D_SHOPPING_GET_BASKET_ITEMS, + apLog.debug(messages.getMessage(MessageIdConstants.D_SHOPPING_GET_BASKET_ITEMS, new Object[] { buyerId }, Locale.getDefault())); Basket basket = getOrCreateBasketForUser(buyerId); @@ -146,7 +146,7 @@ public BasketDetail getBasketDetail(String buyerId) { public Order checkout(String buyerId, ShipTo shipToAddress) throws EmptyBasketOnCheckoutException { - apLog.debug(messages.getMessage(MessageIdConstant.D_SHOPPING_CHECKOUT, + apLog.debug(messages.getMessage(MessageIdConstants.D_SHOPPING_CHECKOUT, new Object[] { buyerId, shipToAddress }, Locale.getDefault())); @@ -189,7 +189,7 @@ private Basket createBasket(String buyerId) { private OrderItem mapToOrderItem(BasketItem basketItem, List catalogItems) { CatalogItem catalogItem = catalogItems.stream() .filter(c -> c.getId() == basketItem.getCatalogItemId()).findFirst() - .orElseThrow(() -> new SystemException(null, CommonExceptionIdConstant.E_BUSINESS, null, null)); + .orElseThrow(() -> new SystemException(null, CommonExceptionIdConstants.E_BUSINESS, null, null)); CatalogItemOrdered itemOrdered = new CatalogItemOrdered(catalogItem.getId(), catalogItem.getName(), catalogItem.getProductCode()); OrderItem orderItem = new OrderItem(itemOrdered, basketItem.getUnitPrice(), basketItem.getQuantity()); diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/assets/Asset.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/assets/Asset.java index 197d276ad..31fc6c12c 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/assets/Asset.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/assets/Asset.java @@ -1,5 +1,9 @@ package com.dressca.applicationcore.assets; +import java.util.Locale; +import org.springframework.context.MessageSource; +import com.dressca.applicationcore.constant.ExceptionIdConstants; +import com.dressca.systemcommon.util.ApplicationContextWrapper; import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; @@ -26,7 +30,11 @@ public class Asset { public Asset(@NonNull String assetCode, @NonNull String assetType) { this.assetCode = assetCode; if (!AssetTypes.isSupportedAssetTypes(assetType)) { - throw new IllegalArgumentException("サポートされていないアセットタイプが指定されました。"); + MessageSource messageSource = (MessageSource) ApplicationContextWrapper.getBean(MessageSource.class); + String message = messageSource.getMessage(ExceptionIdConstants.E_ASSET_TYPE_NOT_SUPPORTED, + new String[] { assetType }, Locale.getDefault()); + + throw new IllegalArgumentException(message); } this.assetType = assetType; } @@ -38,7 +46,11 @@ public Asset(@NonNull String assetCode, @NonNull String assetType) { */ public void setAssetType(String assetType) { if (!AssetTypes.isSupportedAssetTypes(assetType)) { - throw new IllegalArgumentException("サポートされていないアセットタイプが指定されました。"); + MessageSource messageSource = (MessageSource) ApplicationContextWrapper.getBean(MessageSource.class); + String message = messageSource.getMessage(ExceptionIdConstants.E_ASSET_TYPE_NOT_SUPPORTED, + new String[] { assetType }, Locale.getDefault()); + + throw new IllegalArgumentException(message); } this.assetType = assetType; } diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/assets/AssetNotFoundException.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/assets/AssetNotFoundException.java index a406f8fb3..413cb6c55 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/assets/AssetNotFoundException.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/assets/AssetNotFoundException.java @@ -1,6 +1,6 @@ package com.dressca.applicationcore.assets; -import com.dressca.applicationcore.constant.ExceptionIdConstant; +import com.dressca.applicationcore.constant.ExceptionIdConstants; import com.dressca.systemcommon.exception.LogicException; /** @@ -14,7 +14,7 @@ public class AssetNotFoundException extends LogicException { * @param assetCode 見つからなかった買い物かご Id */ public AssetNotFoundException(String assetCode) { - super(null, ExceptionIdConstant.E_ASSET_NOT_FOUND, new String[] { assetCode }, + super(null, ExceptionIdConstants.E_ASSET_NOT_FOUND, new String[] { assetCode }, new String[] { assetCode }); } } diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/baskets/BasketNotFoundException.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/baskets/BasketNotFoundException.java index 6444c967d..54e903f68 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/baskets/BasketNotFoundException.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/baskets/BasketNotFoundException.java @@ -1,14 +1,20 @@ package com.dressca.applicationcore.baskets; -import com.dressca.applicationcore.constant.ExceptionIdConstant; +import com.dressca.applicationcore.constant.ExceptionIdConstants; import com.dressca.systemcommon.exception.LogicException; /** * 買い物かごが存在しないことを表す例外クラスです。 */ public class BasketNotFoundException extends LogicException { + + /** + * 存在しない買い物かご ID を指定して例外を作成します。 + * + * @param basketId 見つからなかった買い物かご ID 。 + */ public BasketNotFoundException(long basketId) { - super(null, ExceptionIdConstant.E_BASKET_IS_NULL_ON_CHECKOUT, new String[] { String.valueOf(basketId) }, + super(null, ExceptionIdConstants.E_BASKET_IS_NULL_ON_CHECKOUT, new String[] { String.valueOf(basketId) }, new String[] { String.valueOf(basketId) }); } } diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/baskets/CatalogItemInBasketNotFoundException.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/baskets/CatalogItemInBasketNotFoundException.java index 798c299b6..0f263e983 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/baskets/CatalogItemInBasketNotFoundException.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/baskets/CatalogItemInBasketNotFoundException.java @@ -2,7 +2,7 @@ import java.util.List; import java.util.StringJoiner; -import com.dressca.applicationcore.constant.ExceptionIdConstant; +import com.dressca.applicationcore.constant.ExceptionIdConstants; import com.dressca.systemcommon.exception.LogicException; /** @@ -17,7 +17,7 @@ public class CatalogItemInBasketNotFoundException extends LogicException { * @param basketId 買い物かごID */ public CatalogItemInBasketNotFoundException(List catalogIds, long basketId) { - super(null, ExceptionIdConstant.E_CATALOG_ITEM_ID_DOES_EXIST_IN_BASKET, + super(null, ExceptionIdConstants.E_CATALOG_ITEM_ID_DOES_NOT_EXIST_IN_BASKET, new String[] { String.valueOf(basketId), convertCatalogIds(catalogIds) }, new String[] { String.valueOf(basketId), convertCatalogIds(catalogIds) }); } diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/catalog/CatalogNotFoundException.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/catalog/CatalogNotFoundException.java index cd9679724..621405d87 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/catalog/CatalogNotFoundException.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/catalog/CatalogNotFoundException.java @@ -1,18 +1,27 @@ package com.dressca.applicationcore.catalog; -import com.dressca.applicationcore.constant.ExceptionIdConstant; +import com.dressca.applicationcore.constant.ExceptionIdConstants; import com.dressca.systemcommon.exception.LogicException; /** * 商品が存在しないことを表す例外です。 */ public class CatalogNotFoundException extends LogicException { + + /** + * 見つからなかったカタログ ID を指定して例外を作成します。 + * + * @param catalogId 見つからなかったカタログ ID 。 + */ public CatalogNotFoundException(long catalogId) { - super(null, ExceptionIdConstant.E_CATALOG_ID_NOT_FOUND, new String[] { String.valueOf(catalogId) }, + super(null, ExceptionIdConstants.E_CATALOG_ID_NOT_FOUND, new String[] { String.valueOf(catalogId) }, new String[] { String.valueOf(catalogId) }); } + /** + * カタログに商品が存在しないことを表す例外を作成します。 + */ public CatalogNotFoundException() { - super(null, ExceptionIdConstant.E_CATALOG_ID_NOT_FOUND, null, null); + super(null, ExceptionIdConstants.E_CATALOG_ID_NOT_FOUND, null, null); } } \ No newline at end of file diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/ExceptionIdConstant.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/ExceptionIdConstants.java similarity index 64% rename from samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/ExceptionIdConstant.java rename to samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/ExceptionIdConstants.java index 05beb283a..388d08b1a 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/ExceptionIdConstant.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/ExceptionIdConstants.java @@ -3,16 +3,22 @@ /** * 業務例外ID用定数クラス。 */ -public class ExceptionIdConstant { +public class ExceptionIdConstants { /** 存在しないアセットコード: {0} のアセットが要求されました。 */ public static final String E_ASSET_NOT_FOUND = "assetNotFound"; + /** サポートされていないアセットタイプ: {0} が指定されました。 */ + public static final String E_ASSET_TYPE_NOT_SUPPORTED = "assetTypeNotSupported"; + + /** "指定したアセットのアセットタイプ: {0} は Content-Type に変換できません。" */ + public static final String E_ASSET_TYPE_NOT_CONVERTED = "assetTypeNotConverted"; + /** 存在しない買い物かごID: {0} の買い物かごが要求されました。 */ public static final String E_BASKET_IS_NULL_ON_CHECKOUT = "basketIsNullOnCheckout"; /** 買い物かごID: {0} に商品ID: {1} の商品が見つかりませんでした。 */ - public static final String E_CATALOG_ITEM_ID_DOES_EXIST_IN_BASKET = "catalogItemIdDoesNotExistInBasket"; + public static final String E_CATALOG_ITEM_ID_DOES_NOT_EXIST_IN_BASKET = "catalogItemIdDoesNotExistInBasket"; /** 注文のチェックアウト時に買い物かごが空でした。 */ public static final String E_BASKET_IS_EMPTY_ON_CHECKOUT = "basketIsEmptyOnCheckout"; diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/MessageIdConstant.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/MessageIdConstants.java similarity index 96% rename from samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/MessageIdConstant.java rename to samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/MessageIdConstants.java index d3b20bd39..1a664352b 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/MessageIdConstant.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/constant/MessageIdConstants.java @@ -3,7 +3,7 @@ /** * 業務メッセージID用定数クラス。 */ -public class MessageIdConstant { +public class MessageIdConstants { /** アセット情報{0}を取得します。 */ public static final String D_ASSET_GET_ASSET = "assetApplicationServiceGetAsset"; diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/order/EmptyBasketOnCheckoutException.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/order/EmptyBasketOnCheckoutException.java index c11c5d8e3..4b3364d4b 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/order/EmptyBasketOnCheckoutException.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/order/EmptyBasketOnCheckoutException.java @@ -1,6 +1,6 @@ package com.dressca.applicationcore.order; -import com.dressca.applicationcore.constant.ExceptionIdConstant; +import com.dressca.applicationcore.constant.ExceptionIdConstants; import com.dressca.systemcommon.exception.LogicException; /** @@ -9,7 +9,7 @@ public class EmptyBasketOnCheckoutException extends LogicException { public EmptyBasketOnCheckoutException(Throwable cause) { - super(cause, ExceptionIdConstant.E_BASKET_IS_EMPTY_ON_CHECKOUT, null, null); + super(cause, ExceptionIdConstants.E_BASKET_IS_EMPTY_ON_CHECKOUT, null, null); } } diff --git a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/order/OrderNotFoundException.java b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/order/OrderNotFoundException.java index 54305b5c8..a161c275d 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/order/OrderNotFoundException.java +++ b/samples/web-csr/dressca-backend/application-core/src/main/java/com/dressca/applicationcore/order/OrderNotFoundException.java @@ -1,6 +1,6 @@ package com.dressca.applicationcore.order; -import com.dressca.applicationcore.constant.ExceptionIdConstant; +import com.dressca.applicationcore.constant.ExceptionIdConstants; import com.dressca.systemcommon.exception.LogicException; /** @@ -17,7 +17,7 @@ public class OrderNotFoundException extends LogicException { * @param buyerId 見つからなかった購入者 Id. */ public OrderNotFoundException(Throwable cause, long orderId, String buyerId) { - super(cause, ExceptionIdConstant.E_ORDER_NOT_FOUND, new String[] { String.valueOf(orderId), buyerId }, + super(cause, ExceptionIdConstants.E_ORDER_NOT_FOUND, new String[] { String.valueOf(orderId), buyerId }, new String[] { String.valueOf(orderId), buyerId }); } diff --git a/samples/web-csr/dressca-backend/application-core/src/main/resources/applicationcore/messages.properties b/samples/web-csr/dressca-backend/application-core/src/main/resources/applicationcore/messages.properties index ca05edab3..9001a65b3 100644 --- a/samples/web-csr/dressca-backend/application-core/src/main/resources/applicationcore/messages.properties +++ b/samples/web-csr/dressca-backend/application-core/src/main/resources/applicationcore/messages.properties @@ -1,18 +1,20 @@ # エラーメッセージ assetNotFound=存在しないアセットコード: {0} のアセットが要求されました。 +assetTypeNotSupported=サポートされていないアセットタイプ: {0} が指定されました。 +assetTypeNotConverted=指定したアセットのアセットタイプ: {0} は Content-Type に変換できません。 +basketIsEmptyOnCheckout=注文のチェックアウト時に買い物かごが空でした。 basketIsNullOnCheckout=存在しない買い物かごID: {0} の買い物かごが要求されました。 +catalogIdNotFound=商品ID: {0} の商品が見つかりませんでした。 catalogItemIdDoesNotExistInBasket=買い物かごID: {0} に商品ID: {1} の商品が見つかりませんでした。 -basketIsEmptyOnCheckout=注文のチェックアウト時に買い物かごが空でした。 orderNotFound=存在しない注文情報(注文ID: {0}, 購入者ID: {1})が要求されました。 -catalogIdNotFound=商品ID: {0} の商品が見つかりませんでした。 # 通知用メッセージ assetApplicationServiceGetAsset=アセット情報{0}を取得します。 -shoppingApplicationServiceAddItemToBasket=買い物かごに商品(顧客ID: {0}, カタログ商品ID: {1}, 数量: {2})を追加します。 -shoppingApplicationServiceSetBasketItemsQuantities=買い物かごの商品の数量(顧客ID: {0}, 数量: {1})を設定します。 -shoppingApplicationServiceGetBasketItems=顧客(顧客ID: {0})の買い物かごと情報とその商品一覧を取得します。 -shoppingApplicationServiceCheckout=注文(顧客ID: {0}, お届け先: {1})を確定します。 -orderApplicationServiceGetOrder=指定した注文ID: {0}, 購入者ID: {1} の注文情報を取得します。 -catalogApplicationServiceGetCatalogItems=条件(ブランドID: {0}, カテゴリID: {1}, ページ: {2}, ページサイズ: {3})に一致するカタログ情報を取得します。 catalogApplicationServiceCountCatalogItems=条件(ブランドID: {0}, カテゴリID: {1})に一致するカテゴリの件数を取得します。 catalogApplicationServiceGetBrands=フィルタリング用のカタログブランドリストを取得します。 -catalogApplicationServiceGetCategories=フィルタリング用のカタログカテゴリリストを取得します。 \ No newline at end of file +catalogApplicationServiceGetCatalogItems=条件(ブランドID: {0}, カテゴリID: {1}, ページ: {2}, ページサイズ: {3})に一致するカタログ情報を取得します。 +catalogApplicationServiceGetCategories=フィルタリング用のカタログカテゴリリストを取得します。 +shoppingApplicationServiceAddItemToBasket=買い物かごに商品(顧客ID: {0}, カタログ商品ID: {1}, 数量: {2})を追加します。 +shoppingApplicationServiceCheckout=注文(顧客ID: {0}, お届け先: {1})を確定します。 +shoppingApplicationServiceGetBasketItems=顧客(顧客ID: {0})の買い物かごと情報とその商品一覧を取得します。 +shoppingApplicationServiceSetBasketItemsQuantities=買い物かごの商品の数量(顧客ID: {0}, 数量: {1})を設定します。 +orderApplicationServiceGetOrder=指定した注文ID: {0}, 購入者ID: {1} の注文情報を取得します。 \ No newline at end of file diff --git a/samples/web-csr/dressca-backend/config/checkstyle/suppressions.xml b/samples/web-csr/dressca-backend/config/checkstyle/suppressions.xml index b072ddb60..ebac9e64c 100644 --- a/samples/web-csr/dressca-backend/config/checkstyle/suppressions.xml +++ b/samples/web-csr/dressca-backend/config/checkstyle/suppressions.xml @@ -10,5 +10,5 @@ - + \ No newline at end of file diff --git a/samples/web-csr/dressca-backend/system-common/src/main/java/com/dressca/systemcommon/constant/CommonExceptionIdConstant.java b/samples/web-csr/dressca-backend/system-common/src/main/java/com/dressca/systemcommon/constant/CommonExceptionIdConstants.java similarity index 54% rename from samples/web-csr/dressca-backend/system-common/src/main/java/com/dressca/systemcommon/constant/CommonExceptionIdConstant.java rename to samples/web-csr/dressca-backend/system-common/src/main/java/com/dressca/systemcommon/constant/CommonExceptionIdConstants.java index 634970cd6..178468ecc 100644 --- a/samples/web-csr/dressca-backend/system-common/src/main/java/com/dressca/systemcommon/constant/CommonExceptionIdConstant.java +++ b/samples/web-csr/dressca-backend/system-common/src/main/java/com/dressca/systemcommon/constant/CommonExceptionIdConstants.java @@ -3,11 +3,11 @@ /** * 例外ID用定数クラス。 */ -public class CommonExceptionIdConstant { - /** 想定外のシステムエラー。 */ +public class CommonExceptionIdConstants { + /** 想定外のシステムエラーが発生しました。 */ public static final String E_SYSTEM = "systemError"; - /** 想定外の業務エラー。 */ + /** 想定外の業務エラーが発生しました。 */ public static final String E_BUSINESS = "businessError"; } diff --git a/samples/web-csr/dressca-backend/system-common/src/main/resources/systemcommon/messages.properties b/samples/web-csr/dressca-backend/system-common/src/main/resources/systemcommon/messages.properties index c9fc1c4bb..3f873bf76 100644 --- a/samples/web-csr/dressca-backend/system-common/src/main/resources/systemcommon/messages.properties +++ b/samples/web-csr/dressca-backend/system-common/src/main/resources/systemcommon/messages.properties @@ -1,2 +1,2 @@ -systemError=想定外のシステムエラーが発生しました -businessError=想定外の業務エラーが発生しました \ No newline at end of file +systemError=想定外のシステムエラーが発生しました。 +businessError=想定外の業務エラーが発生しました。 \ No newline at end of file diff --git a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/constant/ProblemDetailsConstant.java b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/constant/ProblemDetailsConstant.java deleted file mode 100644 index 1f6b53aa7..000000000 --- a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/constant/ProblemDetailsConstant.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.dressca.web.constant; - -/** - * ProblemDetail用の定数クラス。 - */ -public class ProblemDetailsConstant { - - /** 業務エラーのタイトル。 */ - public static final String LOGIC_ERROR_TITLE = "業務エラー"; - - /** システムエラーのタイトル。 */ - public static final String SYSTEM_ERROR_TITLE = "システムエラー"; - - /** Exception ID。 */ - public static final String EXCEPTION_ID = "exceptionId"; - - /** Exception ID に紐づくメッセージ。 */ - public static final String EXCEPTION_VALUES = "exceptionValues"; -} diff --git a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/constant/WebConstants.java b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/constant/WebConstants.java new file mode 100644 index 000000000..66ad1e3f9 --- /dev/null +++ b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/constant/WebConstants.java @@ -0,0 +1,13 @@ +package com.dressca.web.constant; + +/** + * web プロジェクトで利用する汎用定数クラス。 + */ +public class WebConstants { + + /** Exception ID。 */ + public static final String PROBLEM_DETAILS_EXCEPTION_ID = "exceptionId"; + + /** Exception ID に紐づく例外値。 */ + public static final String PROBLEM_DETAILS_EXCEPTION_VALUES = "exceptionValues"; +} diff --git a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/AssetsController.java b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/AssetsController.java index 5e4abae70..e985fe528 100644 --- a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/AssetsController.java +++ b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/AssetsController.java @@ -5,14 +5,18 @@ import com.dressca.applicationcore.assets.AssetNotFoundException; import com.dressca.applicationcore.assets.AssetResourceInfo; import com.dressca.applicationcore.assets.AssetTypes; +import com.dressca.applicationcore.constant.ExceptionIdConstants; +import com.dressca.systemcommon.constant.CommonExceptionIdConstants; import com.dressca.systemcommon.constant.SystemPropertyConstants; import com.dressca.systemcommon.exception.LogicException; -import com.dressca.web.controller.advice.ProblemDetailsCreation; +import com.dressca.web.controller.advice.ProblemDetailsFactory; import com.dressca.web.log.ErrorMessageBuilder; +import java.util.Locale; import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; import org.springframework.core.io.Resource; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -44,7 +48,10 @@ public class AssetsController { private AssetApplicationService service; @Autowired - private ProblemDetailsCreation problemDetailsCreation; + private ProblemDetailsFactory problemDetailsFactory; + + @Autowired + private MessageSource messages; private static final Logger apLog = LoggerFactory.getLogger(SystemPropertyConstants.APPLICATION_LOG_LOGGER); @@ -57,7 +64,8 @@ public class AssetsController { @Operation(summary = "アセットを取得する.", description = "与えられたアセットコードに対応するアセットを返却する.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "成功.", content = @Content(mediaType = "image/*", schema = @Schema(implementation = Resource.class))), - @ApiResponse(responseCode = "404", description = "アセットコードに対応するアセットがない.", content = @Content) }) + @ApiResponse(responseCode = "404", description = "アセットコードに対応するアセットがない.", content = @Content(mediaType = "application/problem+json", schema = @Schema(implementation = ProblemDetail.class))) + }) @GetMapping("{assetCode}") public ResponseEntity get( @Parameter(required = true, description = "アセットコード") @PathVariable("assetCode") String assetCode) @@ -72,12 +80,12 @@ public ResponseEntity get( apLog.debug(ExceptionUtils.getStackTrace(e)); ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, e.getExceptionId(), e.getLogMessageValue(), e.getFrontMessageValue()); - ProblemDetail problemDetail = problemDetailsCreation.createProblemDetail( + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail( errorBuilder, - e.getExceptionId(), + CommonExceptionIdConstants.E_BUSINESS, HttpStatus.NOT_FOUND); return ResponseEntity.status(HttpStatus.NOT_FOUND) - .contentType(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) .body(problemDetail); } } @@ -93,7 +101,9 @@ private MediaType getContentType(Asset asset) { case AssetTypes.png: return MediaType.IMAGE_PNG; default: - throw new IllegalArgumentException("指定したアセットのアセットタイプは Content-Type に変換できません。"); + String errorMessage = messages.getMessage(ExceptionIdConstants.E_ASSET_TYPE_NOT_CONVERTED, + new String[] { asset.getAssetType() }, Locale.getDefault()); + throw new IllegalArgumentException(errorMessage); } } } diff --git a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/BasketItemController.java b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/BasketItemController.java index d62380f7a..3e95f4b0f 100644 --- a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/BasketItemController.java +++ b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/BasketItemController.java @@ -7,7 +7,8 @@ import com.dressca.applicationcore.baskets.CatalogItemInBasketNotFoundException; import com.dressca.applicationcore.catalog.CatalogItem; import com.dressca.applicationcore.catalog.CatalogNotFoundException; -import com.dressca.web.controller.advice.ProblemDetailsCreation; +import com.dressca.systemcommon.constant.CommonExceptionIdConstants; +import com.dressca.web.controller.advice.ProblemDetailsFactory; import com.dressca.web.controller.dto.baskets.BasketItemResponse; import com.dressca.web.controller.dto.baskets.BasketResponse; import com.dressca.web.controller.dto.baskets.PostBasketItemsRequest; @@ -55,7 +56,7 @@ public class BasketItemController { private ShoppingApplicationService shoppingApplicationService; @Autowired - private ProblemDetailsCreation problemDetailsCreation; + private ProblemDetailsFactory problemDetailsFactory; /** * 買い物かごアイテムの一覧を取得します。 @@ -95,7 +96,8 @@ public ResponseEntity getBasketItems(HttpServletRequest req) { + "またシステムに登録されていないカタログアイテム Id を指定した場合も HTTP 400 を返却します.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "成功.", content = @Content), - @ApiResponse(responseCode = "400", description = "リクエストエラー", content = @Content) }) + @ApiResponse(responseCode = "400", description = "リクエストエラー", content = @Content(mediaType = "application/problem+json", schema = @Schema(implementation = ProblemDetail.class))) + }) @PutMapping() public ResponseEntity putBasketItems(@RequestBody List putBasketItems, HttpServletRequest req) { @@ -114,22 +116,22 @@ public ResponseEntity putBasketItems(@RequestBody List ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, e.getExceptionId(), e.getLogMessageValue(), e.getFrontMessageValue()); - ProblemDetail problemDetail = problemDetailsCreation.createProblemDetail( + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail( errorBuilder, - e.getExceptionId(), + CommonExceptionIdConstants.E_BUSINESS, HttpStatus.BAD_REQUEST); return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .contentType(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) .body(problemDetail); } catch (CatalogItemInBasketNotFoundException e) { ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, e.getExceptionId(), e.getLogMessageValue(), e.getFrontMessageValue()); - ProblemDetail problemDetail = problemDetailsCreation.createProblemDetail( + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail( errorBuilder, - e.getExceptionId(), + CommonExceptionIdConstants.E_BUSINESS, HttpStatus.BAD_REQUEST); return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .contentType(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) .body(problemDetail); } return ResponseEntity.noContent().build(); @@ -157,8 +159,9 @@ public ResponseEntity putBasketItems(@RequestBody List + "買い物かご内のカタログアイテムの数量が 0 未満になるように減じることはできません. 計算の結果数量が 0 未満になる場合 HTTP 500 を返却します.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "作成完了", content = @Content), - @ApiResponse(responseCode = "400", description = "リクエストエラー", content = @Content), - @ApiResponse(responseCode = "500", description = "サーバーエラー", content = @Content) }) + @ApiResponse(responseCode = "400", description = "リクエストエラー", content = @Content(mediaType = "application/problem+json", schema = @Schema(implementation = ProblemDetail.class))), + @ApiResponse(responseCode = "500", description = "サーバーエラー", content = @Content(mediaType = "application/problem+json", schema = @Schema(implementation = ProblemDetail.class))) + }) @PostMapping public ResponseEntity postBasketItem(@RequestBody PostBasketItemsRequest postBasketItem, HttpServletRequest req) { @@ -171,10 +174,12 @@ public ResponseEntity postBasketItem(@RequestBody PostBasketItemsRequest post } catch (CatalogNotFoundException e) { ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, e.getExceptionId(), e.getLogMessageValue(), e.getFrontMessageValue()); - ProblemDetail problemDetail = problemDetailsCreation.createProblemDetail( - errorBuilder, e.getExceptionId(), HttpStatus.BAD_REQUEST); + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail( + errorBuilder, + CommonExceptionIdConstants.E_BUSINESS, + HttpStatus.BAD_REQUEST); return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .contentType(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) .body(problemDetail); } return ResponseEntity.created(URI.create("/basket-items")).build(); @@ -197,8 +202,9 @@ public ResponseEntity postBasketItem(@RequestBody PostBasketItemsRequest post + "買い物かご内に指定したカタログアイテムの商品が存在しない場合、 HTTP 404 を返却します.") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "成功.", content = @Content), - @ApiResponse(responseCode = "400", description = "リクエストエラー.", content = @Content), - @ApiResponse(responseCode = "404", description = "買い物かご内に指定したカタログアイテム Id がない.", content = @Content) }) + @ApiResponse(responseCode = "400", description = "リクエストエラー.", content = @Content(mediaType = "application/problem+json", schema = @Schema(implementation = ProblemDetail.class))), + @ApiResponse(responseCode = "404", description = "買い物かご内に指定したカタログアイテム Id がない.", content = @Content(mediaType = "application/problem+json", schema = @Schema(implementation = ProblemDetail.class))) + }) @DeleteMapping("{catalogItemId}") public ResponseEntity deleteBasketItem(@PathVariable("catalogItemId") long catalogItemId, HttpServletRequest req) { @@ -209,18 +215,22 @@ public ResponseEntity deleteBasketItem(@PathVariable("catalogItemId") long ca } catch (CatalogNotFoundException e) { ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, e.getExceptionId(), e.getLogMessageValue(), e.getFrontMessageValue()); - ProblemDetail problemDetail = problemDetailsCreation.createProblemDetail( - errorBuilder, e.getExceptionId(), HttpStatus.BAD_REQUEST); + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail( + errorBuilder, + CommonExceptionIdConstants.E_BUSINESS, + HttpStatus.BAD_REQUEST); return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .contentType(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) .body(problemDetail); } catch (CatalogItemInBasketNotFoundException e) { ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, e.getExceptionId(), e.getLogMessageValue(), e.getFrontMessageValue()); - ProblemDetail problemDetail = problemDetailsCreation.createProblemDetail( - errorBuilder, e.getExceptionId(), HttpStatus.NOT_FOUND); + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail( + errorBuilder, + CommonExceptionIdConstants.E_BUSINESS, + HttpStatus.NOT_FOUND); return ResponseEntity.status(HttpStatus.NOT_FOUND) - .contentType(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) .body(problemDetail); } return ResponseEntity.noContent().build(); diff --git a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/CatalogItemsController.java b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/CatalogItemsController.java index 73402d341..f304abc9c 100644 --- a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/CatalogItemsController.java +++ b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/CatalogItemsController.java @@ -8,6 +8,7 @@ import com.dressca.web.controller.dto.catalog.PagedListOfCatalogItemResponse; import com.dressca.web.mapper.CatalogItemMapper; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ProblemDetail; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -45,7 +46,8 @@ public class CatalogItemsController { @Operation(summary = "カタログアイテムを検索して返します.", description = "カタログアイテムを検索して返します.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "成功", content = @Content(mediaType = "application/json", schema = @Schema(implementation = PagedListOfCatalogItemResponse.class))), - @ApiResponse(responseCode = "400", description = "リクエストエラー", content = @Content) }) + @ApiResponse(responseCode = "400", description = "リクエストエラー", content = @Content(mediaType = "application/problem+json", schema = @Schema(implementation = ProblemDetail.class))) + }) @GetMapping() public ResponseEntity getByQuery( @RequestParam(name = "brandId", defaultValue = "0") long brandId, diff --git a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/OrderController.java b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/OrderController.java index 987e91c08..adaa57ad3 100644 --- a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/OrderController.java +++ b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/OrderController.java @@ -7,10 +7,10 @@ import com.dressca.applicationcore.order.Order; import com.dressca.applicationcore.order.OrderNotFoundException; import com.dressca.applicationcore.order.ShipTo; -import com.dressca.systemcommon.constant.CommonExceptionIdConstant; +import com.dressca.systemcommon.constant.CommonExceptionIdConstants; import com.dressca.systemcommon.constant.SystemPropertyConstants; import com.dressca.systemcommon.exception.SystemException; -import com.dressca.web.controller.advice.ProblemDetailsCreation; +import com.dressca.web.controller.advice.ProblemDetailsFactory; import com.dressca.web.controller.dto.order.OrderResponse; import com.dressca.web.controller.dto.order.PostOrderRequest; import com.dressca.web.log.ErrorMessageBuilder; @@ -55,7 +55,7 @@ public class OrderController { private ShoppingApplicationService shoppingApplicationService; @Autowired - private ProblemDetailsCreation problemDetailsCreation; + private ProblemDetailsFactory problemDetailsFactory; private static final Logger apLog = LoggerFactory.getLogger(SystemPropertyConstants.APPLICATION_LOG_LOGGER); @@ -68,7 +68,8 @@ public class OrderController { @Operation(summary = "注文情報を取得します.", description = "注文情報を取得します.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "成功.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = OrderResponse.class))), - @ApiResponse(responseCode = "404", description = "注文IDが存在しない.", content = @Content) }) + @ApiResponse(responseCode = "404", description = "注文IDが存在しない.", content = @Content(mediaType = "application/problem+json", schema = @Schema(implementation = ProblemDetail.class))) + }) @GetMapping("{orderId}") public ResponseEntity getById(@PathVariable("orderId") long orderId, HttpServletRequest req) { @@ -84,12 +85,12 @@ public ResponseEntity getById(@PathVariable("orderId") long orderId, ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, e.getExceptionId(), e.getLogMessageValue(), e.getFrontMessageValue()); - ProblemDetail problemDetail = problemDetailsCreation.createProblemDetail( + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail( errorBuilder, - e.getExceptionId(), + CommonExceptionIdConstants.E_BUSINESS, HttpStatus.NOT_FOUND); return ResponseEntity.status(HttpStatus.NOT_FOUND) - .contentType(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) .body(problemDetail); } } @@ -102,8 +103,8 @@ public ResponseEntity getById(@PathVariable("orderId") long orderId, */ @Operation(summary = "買い物かごに登録されている商品を注文します.", description = "買い物かごに登録されている商品を注文します.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "成功.", content = @Content), - @ApiResponse(responseCode = "400", description = "リクエストエラー.", content = @Content), - @ApiResponse(responseCode = "500", description = "サーバーエラー.", content = @Content) }) + @ApiResponse(responseCode = "400", description = "リクエストエラー.", content = @Content(mediaType = "application/problem+json", schema = @Schema(implementation = ProblemDetail.class))), + @ApiResponse(responseCode = "500", description = "サーバーエラー.", content = @Content(mediaType = "application/problem+json", schema = @Schema(implementation = ProblemDetail.class))) }) @PostMapping public ResponseEntity postOrder(@RequestBody @Valid PostOrderRequest postOrderInput, HttpServletRequest req) { @@ -116,7 +117,7 @@ public ResponseEntity postOrder(@RequestBody @Valid PostOrderRequest postOrde order = shoppingApplicationService.checkout(buyerId, shipToAddress); } catch (EmptyBasketOnCheckoutException e) { // ここでは発生しえないので、システムエラーとする - throw new SystemException(e, CommonExceptionIdConstant.E_SYSTEM, null, null); + throw new SystemException(e, CommonExceptionIdConstants.E_SYSTEM, null, null); } String requestUri = req.getRequestURL().toString(); diff --git a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdvice.java b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdvice.java index 932bbe879..89ab9e61e 100644 --- a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdvice.java +++ b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdvice.java @@ -1,11 +1,10 @@ package com.dressca.web.controller.advice; import jakarta.servlet.http.HttpServletRequest; -import com.dressca.systemcommon.constant.CommonExceptionIdConstant; +import com.dressca.systemcommon.constant.CommonExceptionIdConstants; import com.dressca.systemcommon.constant.SystemPropertyConstants; import com.dressca.systemcommon.exception.LogicException; import com.dressca.systemcommon.exception.SystemException; -import com.dressca.web.constant.ProblemDetailsConstant; import com.dressca.web.log.ErrorMessageBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,7 +26,7 @@ public class ExceptionHandlerControllerAdvice extends ResponseEntityExceptionHan private static final Logger apLog = LoggerFactory.getLogger(SystemPropertyConstants.APPLICATION_LOG_LOGGER); @Autowired - private ProblemDetailsCreation problemDetailsCreation; + private ProblemDetailsFactory problemDetailsFactory; /** * その他の業務エラーをステータースコード500で返却する。 @@ -38,13 +37,14 @@ public class ExceptionHandlerControllerAdvice extends ResponseEntityExceptionHan */ @ExceptionHandler(LogicException.class) public ResponseEntity handleLogicException(LogicException e, HttpServletRequest req) { - ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, CommonExceptionIdConstant.E_BUSINESS, null, null); + ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, CommonExceptionIdConstants.E_BUSINESS, null, null); apLog.error(errorBuilder.createLogMessageStackTrace()); - ProblemDetail problemDetail = problemDetailsCreation.createProblemDetail(errorBuilder, - ProblemDetailsConstant.LOGIC_ERROR_TITLE, + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail( + errorBuilder, + CommonExceptionIdConstants.E_BUSINESS, HttpStatus.INTERNAL_SERVER_ERROR); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .contentType(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) .body(problemDetail); } @@ -57,13 +57,14 @@ public ResponseEntity handleLogicException(LogicException e, Http */ @ExceptionHandler(SystemException.class) public ResponseEntity handleSystemException(SystemException e, HttpServletRequest req) { - ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, CommonExceptionIdConstant.E_SYSTEM, null, null); + ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, CommonExceptionIdConstants.E_SYSTEM, null, null); apLog.error(errorBuilder.createLogMessageStackTrace()); - ProblemDetail problemDetail = problemDetailsCreation.createProblemDetail(errorBuilder, - ProblemDetailsConstant.SYSTEM_ERROR_TITLE, + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail( + errorBuilder, + CommonExceptionIdConstants.E_SYSTEM, HttpStatus.INTERNAL_SERVER_ERROR); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .contentType(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) .body(problemDetail); } @@ -76,13 +77,13 @@ public ResponseEntity handleSystemException(SystemException e, Ht */ @ExceptionHandler(Exception.class) public ResponseEntity handleException(Exception e, HttpServletRequest req) { - ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, CommonExceptionIdConstant.E_SYSTEM, null, null); + ErrorMessageBuilder errorBuilder = new ErrorMessageBuilder(e, CommonExceptionIdConstants.E_SYSTEM, null, null); apLog.error(errorBuilder.createLogMessageStackTrace()); - ProblemDetail problemDetail = problemDetailsCreation.createProblemDetail(errorBuilder, - ProblemDetailsConstant.SYSTEM_ERROR_TITLE, + ProblemDetail problemDetail = problemDetailsFactory.createProblemDetail(errorBuilder, + CommonExceptionIdConstants.E_SYSTEM, HttpStatus.INTERNAL_SERVER_ERROR); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .contentType(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_PROBLEM_JSON) .body(problemDetail); } } diff --git a/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/advice/ProblemDetailsFactory.java b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/advice/ProblemDetailsFactory.java new file mode 100644 index 000000000..d1a97bf72 --- /dev/null +++ b/samples/web-csr/dressca-backend/web/src/main/java/com/dressca/web/controller/advice/ProblemDetailsFactory.java @@ -0,0 +1,67 @@ +package com.dressca.web.controller.advice; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpStatus; +import org.springframework.http.ProblemDetail; +import org.springframework.stereotype.Component; +import com.dressca.web.constant.WebConstants; +import com.dressca.web.log.ErrorMessageBuilder; + +/** + * エラーレスポンスに含める ProblemDetails を作成するクラスです。 + */ +@Component +public class ProblemDetailsFactory { + + @Autowired + private Environment env; + + @Autowired + private MessageSource messages; + + /** + * エラーレスポンスに含める ProblemDetails を作成する。 + * + * @param errorBuilder 例外ビルダー + * @param titleId タイトルのメッセージ ID + * @param status ステータスコード + * @return エラーレスポンスに格納する ProblemDetails + */ + public ProblemDetail createProblemDetail(ErrorMessageBuilder errorBuilder, String titleId, HttpStatus status) { + + ProblemDetail problemDetail = ProblemDetail.forStatus(status); + + problemDetail.setTitle(messages.getMessage(titleId, new String[] {}, Locale.getDefault())); + + // 開発環境においては、 detail プロパティにスタックトレースを含める + // 開発環境かどうかの判断は、環境変数の Profile をもとに判断する + String[] activeProfiles = env.getActiveProfiles(); + if (activeProfiles.length == 0) { + activeProfiles = env.getDefaultProfiles(); + } + + if (Arrays.stream(activeProfiles).filter(profile -> Objects.equals(profile, "local")) + .findFirst().isPresent()) { + problemDetail.setDetail(errorBuilder.createLogMessageStackTrace()); + } + + // 拡張メンバーとして exceptionId と exceptionValues を含める + Map errorProperty = new LinkedHashMap() { + { + put(WebConstants.PROBLEM_DETAILS_EXCEPTION_ID, errorBuilder.getExceptionId()); + put(WebConstants.PROBLEM_DETAILS_EXCEPTION_VALUES, errorBuilder.getFrontMessageValue()); + } + }; + + problemDetail.setProperties(errorProperty); + + return problemDetail; + } +} diff --git a/samples/web-csr/dressca-backend/web/src/test/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdviceTest.java b/samples/web-csr/dressca-backend/web/src/test/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdviceTest.java index 3cb67f3e0..f61b98c73 100644 --- a/samples/web-csr/dressca-backend/web/src/test/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdviceTest.java +++ b/samples/web-csr/dressca-backend/web/src/test/java/com/dressca/web/controller/advice/ExceptionHandlerControllerAdviceTest.java @@ -9,14 +9,13 @@ import static org.mockito.Mockito.times; import com.dressca.web.controller.AssetsController; -import com.dressca.systemcommon.constant.CommonExceptionIdConstant; +import com.dressca.systemcommon.constant.CommonExceptionIdConstants; import com.dressca.systemcommon.constant.SystemPropertyConstants; import com.dressca.systemcommon.exception.LogicException; import com.dressca.systemcommon.exception.SystemException; import com.dressca.systemcommon.util.ApplicationContextWrapper; import com.dressca.applicationcore.assets.AssetNotFoundException; import com.dressca.web.WebApplication; -import com.dressca.web.constant.ProblemDetailsConstant; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -101,7 +100,8 @@ void testException_01() throws Exception { // テスト用の入力データ String assetCode = "b52dc7f712d94ca5812dd995bf926c04"; // 期待値の設定 - String exceptionId = CommonExceptionIdConstant.E_BUSINESS; + String exceptionId = CommonExceptionIdConstants.E_BUSINESS; + String title = "想定外の業務エラーが発生しました。"; String[] frontMessageValue = null; String[] logMessageValue = null; // モックの戻り値設定 @@ -111,7 +111,7 @@ void testException_01() throws Exception { // APIの呼び出しとエラー時のレスポンスであることの確認 this.mockMvc.perform(get("/api/assets/" + assetCode)) .andExpect(status().isInternalServerError()) - .andExpect(content().json("{\"title\":\"" + ProblemDetailsConstant.LOGIC_ERROR_TITLE + "\"}")) + .andExpect(content().json("{\"title\":\"" + title + "\"}")) .andExpect(jsonPath("$.exceptionId").value(exceptionId)) .andExpect(jsonPath("$.exceptionValues").value(frontMessageValue)) .andExpect(jsonPath("$.detail").doesNotExist()); @@ -128,7 +128,8 @@ void testException_02() throws Exception { // テスト用の入力データ String assetCode = "b52dc7f712d94ca5812dd995bf926c04"; // 期待値の設定 - String exceptionId = CommonExceptionIdConstant.E_SYSTEM; + String exceptionId = CommonExceptionIdConstants.E_SYSTEM; + String title = "想定外のシステムエラーが発生しました。"; String[] frontMessageValue = null; String[] logMessageValue = null; // モックの戻り値設定 @@ -139,7 +140,7 @@ void testException_02() throws Exception { // APIの呼び出しとエラー時のレスポンスであることの確認 this.mockMvc.perform(get("/api/assets/" + assetCode)) .andExpect(status().isInternalServerError()) - .andExpect(content().json("{\"title\":\"" + ProblemDetailsConstant.SYSTEM_ERROR_TITLE + "\"}")) + .andExpect(content().json("{\"title\":\"" + title + "\"}")) .andExpect(jsonPath("$.exceptionId").value(exceptionId)) .andExpect(jsonPath("$.exceptionValues").value(frontMessageValue)) .andExpect(jsonPath("$.detail").doesNotExist()); @@ -156,7 +157,8 @@ void testException_03() throws Exception { // テスト用の入力データ String assetCode = "b52dc7f712d94ca5812dd995bf926c04"; // 期待値の設定 - String exceptionId = CommonExceptionIdConstant.E_SYSTEM; + String exceptionId = CommonExceptionIdConstants.E_SYSTEM; + String title = "想定外のシステムエラーが発生しました。"; String[] frontMessageValue = null; String[] logMessageValue = null; // モックの戻り値設定 @@ -165,7 +167,7 @@ void testException_03() throws Exception { // APIの呼び出しとエラー時のレスポンスであることの確認 this.mockMvc.perform(get("/api/assets/" + assetCode)) .andExpect(status().isInternalServerError()) - .andExpect(content().json("{\"title\":\"" + ProblemDetailsConstant.SYSTEM_ERROR_TITLE + "\"}")) + .andExpect(content().json("{\"title\":\"" + title + "\"}")) .andExpect(jsonPath("$.exceptionId").value(exceptionId)) .andExpect(jsonPath("$.exceptionValues").value(frontMessageValue)) .andExpect(jsonPath("$.detail").doesNotExist()); diff --git a/samples/web-csr/dressca-backend/web/src/test/java/com/dressca/web/controller/advice/LocalExceptionHandlerControllerAdviceTest.java b/samples/web-csr/dressca-backend/web/src/test/java/com/dressca/web/controller/advice/LocalExceptionHandlerControllerAdviceTest.java index feab9e3fb..89488674e 100644 --- a/samples/web-csr/dressca-backend/web/src/test/java/com/dressca/web/controller/advice/LocalExceptionHandlerControllerAdviceTest.java +++ b/samples/web-csr/dressca-backend/web/src/test/java/com/dressca/web/controller/advice/LocalExceptionHandlerControllerAdviceTest.java @@ -9,14 +9,13 @@ import static org.mockito.Mockito.times; import com.dressca.web.controller.AssetsController; -import com.dressca.systemcommon.constant.CommonExceptionIdConstant; +import com.dressca.systemcommon.constant.CommonExceptionIdConstants; import com.dressca.systemcommon.constant.SystemPropertyConstants; import com.dressca.systemcommon.exception.LogicException; import com.dressca.systemcommon.exception.SystemException; import com.dressca.systemcommon.util.ApplicationContextWrapper; import com.dressca.applicationcore.assets.AssetNotFoundException; import com.dressca.web.WebApplication; -import com.dressca.web.constant.ProblemDetailsConstant; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -101,7 +100,8 @@ void testException_01() throws Exception { // テスト用の入力データ String assetCode = "b52dc7f712d94ca5812dd995bf926c04"; // 期待値の設定 - String exceptionId = CommonExceptionIdConstant.E_BUSINESS; + String exceptionId = CommonExceptionIdConstants.E_BUSINESS; + String title = "想定外の業務エラーが発生しました。"; String[] frontMessageValue = null; String[] logMessageValue = null; // モックの戻り値設定 @@ -111,7 +111,7 @@ void testException_01() throws Exception { // APIの呼び出しとエラー時のレスポンスであることの確認 this.mockMvc.perform(get("/api/assets/" + assetCode)) .andExpect(status().isInternalServerError()) - .andExpect(content().json("{\"title\":\"" + ProblemDetailsConstant.LOGIC_ERROR_TITLE + "\"}")) + .andExpect(content().json("{\"title\":\"" + title + "\"}")) .andExpect(jsonPath("$.exceptionId").value(exceptionId)) .andExpect(jsonPath("$.exceptionValues").value(frontMessageValue)) .andExpect(jsonPath("$.detail").exists()); @@ -128,7 +128,8 @@ void testException_02() throws Exception { // テスト用の入力データ String assetCode = "b52dc7f712d94ca5812dd995bf926c04"; // 期待値の設定 - String exceptionId = CommonExceptionIdConstant.E_SYSTEM; + String exceptionId = CommonExceptionIdConstants.E_SYSTEM; + String title = "想定外のシステムエラーが発生しました。"; String[] frontMessageValue = null; String[] logMessageValue = null; // モックの戻り値設定 @@ -138,7 +139,7 @@ void testException_02() throws Exception { // APIの呼び出しとエラー時のレスポンスであることの確認 this.mockMvc.perform(get("/api/assets/" + assetCode)) .andExpect(status().isInternalServerError()) - .andExpect(content().json("{\"title\":\"" + ProblemDetailsConstant.SYSTEM_ERROR_TITLE + "\"}")) + .andExpect(content().json("{\"title\":\"" + title + "\"}")) .andExpect(jsonPath("$.exceptionId").value(exceptionId)) .andExpect(jsonPath("$.exceptionValues").value(frontMessageValue)) .andExpect(jsonPath("$.detail").exists()); @@ -155,7 +156,8 @@ void testException_03() throws Exception { // テスト用の入力データ String assetCode = "b52dc7f712d94ca5812dd995bf926c04"; // 期待値の設定 - String exceptionId = CommonExceptionIdConstant.E_SYSTEM; + String exceptionId = CommonExceptionIdConstants.E_SYSTEM; + String title = "想定外のシステムエラーが発生しました。"; String[] frontMessageValue = null; String[] logMessageValue = null; // モックの戻り値設定 @@ -164,7 +166,7 @@ void testException_03() throws Exception { // APIの呼び出しとエラー時のレスポンスであることの確認 this.mockMvc.perform(get("/api/assets/" + assetCode)) .andExpect(status().isInternalServerError()) - .andExpect(content().json("{\"title\":\"" + ProblemDetailsConstant.SYSTEM_ERROR_TITLE + "\"}")) + .andExpect(content().json("{\"title\":\"" + title + "\"}")) .andExpect(jsonPath("$.exceptionId").value(exceptionId)) .andExpect(jsonPath("$.exceptionValues").value(frontMessageValue)) .andExpect(jsonPath("$.detail").exists()); diff --git a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/.openapi-generator/FILES b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/.openapi-generator/FILES index 7e632acea..7d9ee4e6d 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/.openapi-generator/FILES +++ b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/.openapi-generator/FILES @@ -1,31 +1,32 @@ -.gitignore -.npmignore -.openapi-generator-ignore -api.ts -api/actuator-api.ts -api/assets-api.ts -api/basket-items-api.ts -api/catalog-brands-api.ts -api/catalog-categories-api.ts -api/catalog-items-api.ts -api/orders-api.ts -base.ts -common.ts -configuration.ts -git_push.sh -index.ts -models/account-response.ts -models/basket-item-response.ts -models/basket-response.ts -models/catalog-brand-response.ts -models/catalog-category-response.ts -models/catalog-item-response.ts -models/catalog-item-summary-response.ts -models/index.ts -models/link.ts -models/order-item-response.ts -models/order-response.ts -models/paged-list-of-catalog-item-response.ts -models/post-basket-items-request.ts -models/post-order-request.ts -models/put-basket-items-request.ts +.gitignore +.npmignore +.openapi-generator-ignore +api.ts +api/actuator-api.ts +api/assets-api.ts +api/basket-items-api.ts +api/catalog-brands-api.ts +api/catalog-categories-api.ts +api/catalog-items-api.ts +api/orders-api.ts +base.ts +common.ts +configuration.ts +git_push.sh +index.ts +models/account-response.ts +models/basket-item-response.ts +models/basket-response.ts +models/catalog-brand-response.ts +models/catalog-category-response.ts +models/catalog-item-response.ts +models/catalog-item-summary-response.ts +models/index.ts +models/link.ts +models/order-item-response.ts +models/order-response.ts +models/paged-list-of-catalog-item-response.ts +models/post-basket-items-request.ts +models/post-order-request.ts +models/problem-detail.ts +models/put-basket-items-request.ts diff --git a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/assets-api.ts b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/assets-api.ts index 9f5fb3e95..354a675d0 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/assets-api.ts +++ b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/assets-api.ts @@ -21,6 +21,8 @@ import globalAxios from 'axios'; import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from '../common'; // @ts-ignore import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base'; +// @ts-ignore +import type { ProblemDetail } from '../models'; /** * AssetsApi - axios parameter creator * @export diff --git a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/basket-items-api.ts b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/basket-items-api.ts index 0f58a5f43..47aa89bd2 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/basket-items-api.ts +++ b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/basket-items-api.ts @@ -26,6 +26,8 @@ import type { BasketResponse } from '../models'; // @ts-ignore import type { PostBasketItemsRequest } from '../models'; // @ts-ignore +import type { ProblemDetail } from '../models'; +// @ts-ignore import type { PutBasketItemsRequest } from '../models'; /** * BasketItemsApi - axios parameter creator diff --git a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/catalog-items-api.ts b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/catalog-items-api.ts index c26006b8b..4a1ff594d 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/catalog-items-api.ts +++ b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/catalog-items-api.ts @@ -23,6 +23,8 @@ import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObj import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base'; // @ts-ignore import type { PagedListOfCatalogItemResponse } from '../models'; +// @ts-ignore +import type { ProblemDetail } from '../models'; /** * CatalogItemsApi - axios parameter creator * @export diff --git a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/orders-api.ts b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/orders-api.ts index 669e46bd8..f2719c579 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/orders-api.ts +++ b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/api/orders-api.ts @@ -25,6 +25,8 @@ import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError import type { OrderResponse } from '../models'; // @ts-ignore import type { PostOrderRequest } from '../models'; +// @ts-ignore +import type { ProblemDetail } from '../models'; /** * OrdersApi - axios parameter creator * @export diff --git a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/models/index.ts b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/models/index.ts index 77fbf21ae..8e5fd69f0 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/models/index.ts +++ b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/models/index.ts @@ -11,4 +11,5 @@ export * from './order-response'; export * from './paged-list-of-catalog-item-response'; export * from './post-basket-items-request'; export * from './post-order-request'; +export * from './problem-detail'; export * from './put-basket-items-request'; diff --git a/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/models/problem-detail.ts b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/models/problem-detail.ts new file mode 100644 index 000000000..5fc2e4f83 --- /dev/null +++ b/samples/web-csr/dressca-frontend/consumer/src/generated/api-client/models/problem-detail.ts @@ -0,0 +1,60 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Dressca + * ECサイトDressca + * + * The version of the OpenAPI document: v1 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface ProblemDetail + */ +export interface ProblemDetail { + /** + * + * @type {string} + * @memberof ProblemDetail + */ + 'detail'?: string; + /** + * + * @type {string} + * @memberof ProblemDetail + */ + 'instance'?: string; + /** + * + * @type {{ [key: string]: object; }} + * @memberof ProblemDetail + */ + 'properties'?: { [key: string]: object; }; + /** + * + * @type {number} + * @memberof ProblemDetail + */ + 'status'?: number; + /** + * + * @type {string} + * @memberof ProblemDetail + */ + 'title'?: string; + /** + * + * @type {string} + * @memberof ProblemDetail + */ + 'type'?: string; +} + diff --git a/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/custom-error-handler.ts b/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/custom-error-handler.ts index 78f020399..ecad62cc5 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/custom-error-handler.ts +++ b/samples/web-csr/dressca-frontend/consumer/src/shared/error-handler/custom-error-handler.ts @@ -44,6 +44,10 @@ export function createCustomErrorHandler(): CustomErrorHandler { callback(); if (error instanceof HttpError) { + // 業務処理で発生した HttpError を処理する + if (handlingHttpError) { + handlingHttpError(error); + } // エラーの種類によって共通処理を行う // switch だと instanceof での判定ができないため if 文で判定 if (error instanceof UnauthorizedError) { @@ -75,21 +79,9 @@ export function createCustomErrorHandler(): CustomErrorHandler { } else if (error instanceof NetworkError) { if (handlingNetworkError) { handlingNetworkError(); - } else if (!error.response) { - showToast(t('networkError')); } else { - const message = errorMessageFormat( - error.response.exceptionId, - error.response.exceptionValues, - ); - showToast( - message, - error.response.exceptionId, - error.response.title, - error.response.detail, - error.response.status, - 100000, - ); + // NetworkError ではエラーレスポンスが存在しないため ProblemDetails の処理は実施しない + showToast(t('networkError')); } } else if (error instanceof ServerError) { if (handlingServerError) { @@ -110,8 +102,6 @@ export function createCustomErrorHandler(): CustomErrorHandler { 100000, ); } - } else if (handlingHttpError) { - handlingHttpError(error); } } } else { diff --git a/samples/web-csr/dressca-frontend/consumer/src/views/basket/BasketView.vue b/samples/web-csr/dressca-frontend/consumer/src/views/basket/BasketView.vue index 7664145b6..9a764ee8f 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/views/basket/BasketView.vue +++ b/samples/web-csr/dressca-frontend/consumer/src/views/basket/BasketView.vue @@ -47,7 +47,7 @@ const update = async (catalogItemId: number, newQuantity: number) => { error, () => {}, (httpError: HttpError) => { - if (!httpError.response) { + if (!httpError.response?.exceptionId) { showToast(t('failedToChangeQuantities')); } else { const message = errorMessageFormat( @@ -77,7 +77,7 @@ const remove = async (catalogItemId: number) => { error, () => {}, (httpError: HttpError) => { - if (!httpError.response) { + if (!httpError.response?.exceptionId) { showToast(t('failedToDeleteItems')); } else { const message = errorMessageFormat( @@ -111,7 +111,7 @@ onMounted(async () => { error, () => {}, (httpError: HttpError) => { - if (!httpError.response) { + if (!httpError.response?.exceptionId) { showToast(t('failedToGetCarts')); } else { const message = errorMessageFormat( @@ -166,6 +166,9 @@ onUnmounted(async () => { {{ t('noItemsInBasket') }} + + {{ t('noItemsInBasket') }} +
現在のカートの中身 diff --git a/samples/web-csr/dressca-frontend/consumer/src/views/catalog/CatalogView.vue b/samples/web-csr/dressca-frontend/consumer/src/views/catalog/CatalogView.vue index 033c88404..b87f59a1c 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/views/catalog/CatalogView.vue +++ b/samples/web-csr/dressca-frontend/consumer/src/views/catalog/CatalogView.vue @@ -27,7 +27,6 @@ const { getCategories, getBrands, getItems } = storeToRefs(catalogStore); const router = useRouter(); const customErrorHandler = useCustomErrorHandler(); const { t } = i18n.global; - const state = reactive({ selectedCategory: 0, selectedBrand: 0, @@ -47,7 +46,7 @@ const addBasket = async (catalogItemId: number) => { error, () => {}, (httpError: HttpError) => { - if (!httpError.response) { + if (!httpError.response?.exceptionId) { showToast(t('failedToAddItemToCarts')); } else { const message = errorMessageFormat( @@ -78,7 +77,7 @@ onMounted(async () => { error, () => {}, (httpError: HttpError) => { - if (!httpError.response) { + if (!httpError.response?.exceptionId) { showToast(t('failedToGetItems')); } else { const message = errorMessageFormat( diff --git a/samples/web-csr/dressca-frontend/consumer/src/views/ordering/CheckoutView.vue b/samples/web-csr/dressca-frontend/consumer/src/views/ordering/CheckoutView.vue index 7bf658ca3..76c0cf7b7 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/views/ordering/CheckoutView.vue +++ b/samples/web-csr/dressca-frontend/consumer/src/views/ordering/CheckoutView.vue @@ -42,7 +42,7 @@ const checkout = async () => { router.push({ name: 'error' }); }, (httpError: HttpError) => { - if (!httpError.response) { + if (!httpError.response?.exceptionId) { showToast(t('failedToOrderItems')); } else { const message = errorMessageFormat( diff --git a/samples/web-csr/dressca-frontend/consumer/src/views/ordering/DoneView.vue b/samples/web-csr/dressca-frontend/consumer/src/views/ordering/DoneView.vue index b52f5d87e..224e1358a 100644 --- a/samples/web-csr/dressca-frontend/consumer/src/views/ordering/DoneView.vue +++ b/samples/web-csr/dressca-frontend/consumer/src/views/ordering/DoneView.vue @@ -39,7 +39,7 @@ onMounted(async () => { router.push('/'); }, (httpError: HttpError) => { - if (!httpError.response) { + if (!httpError.response?.exceptionId) { showToast(t('failedToOrderInformation')); } else { const message = errorMessageFormat(