メッセージ管理機能の設定
バックエンドのメッセージ管理方針に関するアーキテクチャについては、こちら をご確認ください。
設定方法
本設定で利用するフォルダーの構成は以下の通りです。
root/ ------------------------------------------- root フォルダー
├ application-core/src/main/resource
│ └ applicationcore ---------------------------- 業務メッセージのプロパティファイルを一元管理するフォルダー
│ └ messages.properties --------------------- 業務メッセージのプロパティファイル
└ system-common/src/main/resource
└ systemcommon ------------------------------- 共通メッセージのプロパティファイルを一元管理するフォルダー
└ messages.properties --------------------- 共通メッセージのプロパティファイル
プロパティファイルの作成
メッセージに関するプロパティファイルは各サブプロジェクトの /src/main/resource/<サブプロジェクト名>
フォルダーに集約します。 以下のように、メッセージ本体を格納するプロパティファイルを作成します。
message.properties |
---|
| systemError=想定外のシステムエラーが発生しました
businessError=想定外の業務エラーが発生しました
|
プロパティファイルの読込
以下のように、 web プロジェクトなどエントリーポイントとなるサブプロジェクトの application.properties にプロパティファイルを読み込む設定を記載します。
application.properties |
---|
| spring.messages.basename=applicationcore.messages,systemcommon.messages
|
読み込むプロパティファイルは src/main/resource
配下の <フォルダー名>.<ファイル名>
で指定します。 プロパティファイルが複数ある場合は、ファイルの間をカンマで区切ります。
メッセージの取得
読み込んだプロパティファイルのメッセージを取得するためには、 MessageSource
インターフェースを利用します。
以下は、プロパティファイルからメッセージを取得し、ログに出力するためのエラーメッセージを整形する ErrorMessageBuilder
クラスの例です。
サンプルアプリケーションの ErrorMessageBuilder.java
ErrorMessageBuilder.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 | package com.dressca.web.log;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Locale;
import org.springframework.context.MessageSource;
import com.dressca.systemcommon.constant.SystemPropertyConstants;
import com.dressca.systemcommon.util.ApplicationContextWrapper;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* ログでエラーメッセージを作成するためのクラスです。
*/
@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;
/**
* ProblemDetails の detail 情報に格納するスタックトレースを作成します。
*
* @return スタックトレース。
*/
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();
}
}
|
また、 @Service
や @Controller
、 @Component
といった Bean 登録されたクラス内で MessageSource
を利用する場合は、 @Autowired
による DI で実装します。
以下は、プロパティファイルからエラーレスポンスに含めるメッセージを整形する ProblemDetailsFactory.java
クラスの例です。
サンプルアプリケーションの ProblemDetailsFactory.java
ProblemDetailsFactory.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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<String, Object> errorProperty = new LinkedHashMap<String, Object>() {
{
put(WebConstants.PROBLEM_DETAILS_EXCEPTION_ID, errorBuilder.getExceptionId());
put(WebConstants.PROBLEM_DETAILS_EXCEPTION_VALUES, errorBuilder.getFrontMessageValue());
}
};
problemDetail.setProperties(errorProperty);
return problemDetail;
}
}
|