Skip to content

Commit

Permalink
メッセージ管理機能方針の策定 (#1526)
Browse files Browse the repository at this point in the history
* メッセージプロパティを各サブプロジェクトで管理するよう変更する

* 使用していないimportの削除

* メッセージコードをフロントエンドに合わせて頭文字を小文字にする

* フロントエンド側のメッセージ管理機能実装

* バックエンド側のエラーメッセージ出力を実装

* フロントエンド側のメッセージ管理機能の実装

* 起動方法の修正

* テスト時の警告解除

* type-checkの警告対応

* typecheckの警告回避と日英対応のメッセージ作成

* エラーハンドリング機能の修正

* if文の修正

* ドキュメントの追加

* ドキュメントの追加

* エラーメッセージに関する記載の修正

* 入力値検証のドキュメント修正

* ブラウザーの言語設定の取得方法修正

* ドキュメント指摘事項の修正

* クリップボード機能の修正

* textlintエラーへの対応

* 入力値検証に関するドキュメントの修正

* ドキュメント指摘事項の修正

* ドキュメントのimport文の削除

* 起動方法の修正

* ドキュメントのアプリ起動方法を記載

* 冗長な文章を修正

* ハイライトを修正

* 指摘事項と軽微なドキュメントの修正

* 変数名の修正

* 指摘事項の対応

* リンクの修正

* アセットサポートのエラーメッセージをプロパティファイルに設定する

* OpenAPI 仕様書について ProblemDetailsを考慮した形に修正

* ProblemDetailの出力方法を修正

* プロパティに関するコメントを追加

* 指摘事項の修正

* メッセージ管理機能をADB2Cプロジェクトに導入

* Content-Typeをapplication/problem+jsonに修正

* ADB2CプロジェクトにProblemDetailsの対応を反映

* カスタムエラーハンドラーの修正

* responseにexceptionIdが含まれるかどうかで処理を分岐するよう修正

* 定数クラスの修正

* DIによるメッセージ取得に変更

* ドキュメントの修正とADB2Cサンプルに対する修正

* クラス名の修正

* textlint 対応

* 競合による修正

* 競合箇所の修正

* 重複するコメントの削除
  • Loading branch information
rnakagawa16 authored Dec 27, 2024
1 parent 0698633 commit 1d1c85b
Show file tree
Hide file tree
Showing 70 changed files with 827 additions and 323 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,19 @@ ProblemDetails は、 HTTP API のエラーレスポンスを標準化するた
| 問題が発生したリソースの URI | instance | 任意 | 問題の発生場所を示す URI です。リクエスト先と異なるリソースが問題の発生したリソースである場合、実装の詳細やデータなどの内部情報が漏洩する可能性があるため、追加には注意が必要です。 |
| 任意のパラメータ | | 任意 | 拡張メンバーです。必要に応じて ProblemDetails のプロパティを拡張する場合に利用します。 |

AlesInfiny Maia OSS Edition では、上記のプロパティに加えて拡張メンバーとして以下を定義しています。
ProblemDetails のレスポンスに含める各プロパティは以下のような観点をもとに取捨選択します。

- 環境による判断

- 本番環境の場合には、ユーザーが見て管理者に伝えるための情報のみをプロパティに含めるべきです。
- 開発環境の場合には、開発者がデバッグやテストなどの作業で確認すべき情報を含めるべきです。

- API の用途による判断

- 外部公開 API の場合には、セキュリティやプライバシーを考慮し、必要最低限の情報を提供するようにプロパティを設定します。
- 内部 API の場合には、画面に対応したエラーレスポンスとして含めるべきプロパティを設定します。

また、 AlesInfiny Maia OSS Edition では、フロントエンド側で管理しているメッセージを取得するために以下の拡張メンバーを追加で定義しています。

- exceptionId

Expand All @@ -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",
Expand All @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ description: アプリケーションの形態によらず、 Java アプリケ

プロパティファイルでは、以下のようにメッセージ文字列を識別するメッセージコードとメッセージ文字列本体をペアで管理します。

```properties title="message.properties の例"
```properties title="messages.properties の例"
errorOccurred=エラーが発生しました。
...
```
Expand All @@ -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 --------------------- 共通メッセージのプロパティファイル
```

業務メッセージと共通メッセージとして格納するメッセージの例は以下の通りです。
Expand All @@ -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) を確認してください。
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,7 @@ application-core プロジェクトの `src` 以下にある、 `ApplicationCore
enabled = true
}
```

## メッセージ管理の設定 {#message-management-settings}

application-core プロジェクトで管理する業務メッセージの設定方法については、[こちら](./message-management.md) を参照してください。
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@ description: バックエンドで動作する Java アプリケーションの
1. [プラグイン、依存ライブラリのバージョン定義一元化](./project-version-control.md)

プラグイン、依存ライブラリのバージョン定義を一元的に管理する方法について解説します。

1. [メッセージ管理機能の設定](./message-management.md)

マルチプロジェクト構成におけるメッセージ管理の設定方法について解説します。
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
title: Java 編
description: バックエンドで動作する Java アプリケーションの 開発手順を解説します。
---

<!-- cspell:ignore applicationcore systemcommon -->

# メッセージ管理機能の設定 {#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();
}
}
```

<!-- textlint-disable ja-technical-writing/sentence-length -->
また、 `#!java @Service``#!java @Controller``#!java @Component` といった Bean 登録されたクラス内で `MessageSource` を利用する場合は、 `#!java @Autowired` による DI で実装します。
<!-- textlint-enable ja-technical-writing/sentence-length -->

以下は、プロパティファイルからエラーレスポンスに含めるメッセージを整形する `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()));

...
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,7 @@ system-common プロジェクトの `src` 以下にある、 `SystemCommonApplic
enabled = true
}
```

## メッセージ管理の設定 {#message-management-settings}

system-common プロジェクトで管理する共通メッセージの設定方法については、[こちら](./message-management.md) を参照してください。
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,7 @@ build.dependsOn("generateOpenApiDocs")
## CORS (クロスオリジンリソース共有)環境の設定 {#cors-environment}

Web API を公開するオリジンと、呼び出し元となるクライアントスクリプトを公開するオリジンが異なる場合(クロスオリジン)の設定は、[こちら](../../cors/index.md) を参照してください。

## メッセージ読込に関する設定 {#message-reading-settings}

他サブプロジェクトで管理されているメッセージを読み込む場合の設定は、[こちら](./message-management.md) を参照してください。
1 change: 1 addition & 0 deletions documents/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"console": "internalConsole",
"mainClass": "com.dressca.web.WebApplication",
"projectName": "web",
"args": "",
"args": "--spring.profiles.active=local",
"envFile": "${workspaceFolder}/.env"
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@
"description": "成功."
},
"401": {
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetail"
}
}
},
"description": "未認証エラー."
}
},
Expand All @@ -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": {
Expand Down
Original file line number Diff line number Diff line change
@@ -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";
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
spring.messages.basename=messages
spring.messages.basename=systemcommon.messages
spring.messages.encoding=UTF-8

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
systemError=想定外のシステムエラーが発生しました。
businessError=想定外の業務エラーが発生しました。
unauthorizedError=未認証のエラーが発生しました。
7 changes: 7 additions & 0 deletions samples/azure-ad-b2c-sample/auth-backend/web/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Loading

0 comments on commit 1d1c85b

Please sign in to comment.