``\ タグのclassに"alert alert-[メッセージタイプ]"が付与される。
* - | (2)
- | 結果メッセージのリストが\ ``
``\ タグで出力される。
* - | (3)
- | メッセージIDに対応するメッセージが\ ``MessageSource``\ から解決される。
````\ はclassを付けたHTMLを出力するだけであるため、見栄えは出力されたclassに合わせてCSSでカスタマイズする必要がある(後述する)。
.. note::
\ ``ResultMessages.error().add(ResultMessage.fromText("There are inconsistencies in the data."));``\ というように、メッセージの本文をハードコードすることもできるが、保守性を高めるため、メッセージIDを使用して\ ``ResultMessage``\ オブジェクトを作成し、メッセージ本文はプロパティファイルから取得することを推奨する。
|
プレースホルダーを使用した結果メッセージの設定方法
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
以下のように、メッセージにプレースホルダーを指定することができる。
.. code-block:: properties
e.xx.yy.8001=Cannot upload, Because the file size must be less than {0}MB.
メッセージのプレースホルダに値を埋める場合は、次のように\ ``add``\ メソッドの第二引数以降に設定する。
.. code-block:: java
ResultMessages messages = ResultMessages.error().add("e.xx.yy.8001", 1024);
model.addAttribute(messages);
この場合、\ ````\ タグにより、以下のようなHTMLが出力される。
.. code-block:: html
- Cannot upload, Because the file size must be less than 1,024MB.
.. warning:: **terasoluna-gfw-web 1.0.0.RELEASEを使用してプレースホルダに値を埋める場合の注意点**
terasoluna-gfw-web 1.0.0.RELEASEを使用している場合、\ **プレースホルダにユーザの入力値を埋め込むとXSS脆弱性の危険がある。**\
ユーザの入力値にXSS対策が必要な文字が含まれる可能性がある場合は、プレースホルダに値を埋め込まないようにすること。
terasoluna-gfw-web 1.0.1.RELEASE以上を使用している場合は、ユーザの入力値をプレースホルダに埋め込んでもXSS脆弱性は発生しない。
.. note::
\ ``ResourceBundleMessageSource``\ はメッセージを生成する際に\ ``java.text.MessageFormat``\ を使用するため、\ ``1024``\ は
カンマ区切りで\ ``1,024``\ と表示される。カンマが不要な場合は、プロパティファイルには以下のように設定する。
.. code-block:: properties
e.xx.yy.8001=Cannot upload, Because the file size must be less than {0,number,#}MB.
詳細は、\ `Javadoc `_\ を参照されたい。
|
複数の結果メッセージの設定方法
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
以下のように、複数の結果メッセージを設定することもできる。
.. code-block:: java
ResultMessages messages = ResultMessages.error()
.add("e.xx.yy.9001")
.add("e.xx.yy.8001", 1024);
model.addAttribute(messages);
この場合は、次のようなHTMLが出力される(JSPの変更は、不要である)。
.. code-block:: html
- There are inconsistencies in the data.
- Cannot upload, Because the file size must be less than 1,024MB.
|
メッセージタイプの変更方法
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
| 標準では、以下のメッセージタイプが用意されている。
| 標準のメッセージタイプはCSSフレームワークである\ `Bootstrap `_\ の\ `Alertsコンポーネント `_\ に対応しており、\ ````\ のデフォルト設定で利用できる。
.. tabularcolumns:: |p{0.15\linewidth}|p{0.30\linewidth}|p{0.25\linewidth}|p{0.30\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 25 25 10 30
* - メッセージタイプ
- \ ``ResultMessages``\ オブジェクトの作成
- デフォルトで出力されるclass名
- 分類
- 使い分け(例)
* - | success
- | ``ResultMessages.success()``\
- | alert alert-success
- | info
- | 成功メッセージやポジティブな通知。
* - | info
- | \ ``ResultMessages.info()``\
- | alert alert-info
- | info
- | 一般的な情報提供。
* - | primary
- | \ ``ResultMessages.primary()``\
- | alert alert-primary
- | info
- | 主要な情報や重要な通知。
* - | secondary
- | \ ``ResultMessages.secondary()``\
- | alert alert-secondary
- | info
- | 補助的な情報やそれほど重要ではない通知。
* - | warning
- | \ ``ResultMessages.warning()``\
- | alert alert-warning
- | warning
- | 注意喚起や警告メッセージ。
* - | light
- | \ ``ResultMessages.light()``\
- | alert alert-light
- | warning
- | 軽いトーンの通知やメッセージ。
* - | dark
- | \ ``ResultMessages.dark()``\
- | alert alert-dark
- | warning
- | 重いトーンの通知やメッセージ。
* - | danger
- | \ ``ResultMessages.danger()``\
- | alert alert-danger
- | error
- | 深刻なエラーメッセージや重要な警告。
* - | error
- | \ ``ResultMessages.error()``\
- | alert alert-error
- | error
- | 深刻なエラーメッセージや重要な警告。
| errorはBootstrapのAlertsコンポーネントには含まれていない。
メッセージタイプに応じてCSSを定義されたい。以下に、CSSを適用した場合の例を示す。
.. code-block:: css
.alert {
margin-bottom: 15px;
padding: 10px;
border: 1px solid;
border-radius: 4px;
text-shadow: 0 1px 0 #ffffff;
}
.alert-info {
background: #ebf7fd;
color: #2d7091;
border-color: rgba(45, 112, 145, 0.3);
}
.alert-warning {
background: #fffceb;
color: #e28327;
border-color: rgba(226, 131, 39, 0.3);
}
.alert-error {
background: #fff1f0;
color: #d85030;
border-color: rgba(216, 80, 48, 0.3);
}
* \ ``ResultMessages.error().add("e.xx.yy.9001")``\ を\ ````\ で出力した例
.. figure:: ./images_MessageManagement/message-management-resultmessage-error.jpg
:width: 100%
* \ ``ResultMessages.warning().add("w.xx.yy.2001")``\ を\ ````\ で出力した例
.. figure:: ./images_MessageManagement/message-management-resultmessage-warn.jpg
:width: 100%
* \ ``ResultMessages.info().add("i.xx.yy.0001", "XXXX")``\ を\ ````\ で出力した例
.. figure:: ./images_MessageManagement/message-management-resultmessage-info.jpg
:width: 100%
.. caution::
本例では、メッセージIDをハードコードで設定しているが、保守性を高めるためにも、メッセージIDは定数クラスにまとめることを推奨する。
\ :ref:`message-management-messagekeysgen`\ を参照されたい。
|
結果メッセージの属性名指定
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
| \ ``ResultMessages``\ をModelに追加する場合、属性名を省略することが出来る。
| ただし、\ ``ResultMessages``\ は一つのメッセージタイプしか表現できないため、1画面に異なるメッセージタイプの\ ``ResultMessages``\ を同時に表示したい場合は、明示的に属性名を指定してModelに設定する必要がある。
* Controller
.. code-block:: java
@RequestMapping(value = "showMessages", method = RequestMethod.GET)
public String showMessages(Model model) {
model.addAttribute("messages1", ResultMessages.warning().add("w.xx.yy.2001")); // (1)
model.addAttribute("messages2", ResultMessages.error().add("e.xx.yy.9001")); // (2)
return "message/showMessages";
}
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - 項番
- 説明
* - | (1)
- | メッセージタイプが"warning"である\ ``ResultMessages``\ を、属性名"messages1"でModelに追加する。
* - | (2)
- | メッセージタイプが"info"である\ ``ResultMessages``\ を、属性名"messages2"でModelに追加する。
* JSP (WEB-INF/views/message/showMessages.jsp)
.. code-block:: jsp
Result Message
Messages1
Messages2
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - 項番
- 説明
* - | (1)
- | 属性名が"messages1"である\ ``ResultMessages``\ を表示する。
* - | (2)
- | 属性名が"messages2"である\ ``ResultMessages``\ を表示する。
ブラウザで表示すると、以下のように出力される。
.. figure:: ./images_MessageManagement/message-management-multiple-messages.jpg
:width: 80%
|
業務例外メッセージの表示
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
| \ ``org.terasoluna.gfw.common.exception.BusinessException``\ と\ ``org.terasoluna.gfw.common.exception.ResourceNotFoundException``\ は
| 内部で\ ``ResultMessages``\ を保持している。
| 業務例外メッセージを表示する場合は、Serviceクラスで\ ``ResultMessages``\ を設定した\ ``BusinessException``\ をスローすること。
| Controllerクラスでは\ ``BusinessException``\ をキャッチし、例外中の結果メッセージをModelに追加する。
* Serviceクラス
.. code-block:: java
@Service
@Transactional
public class UserServiceImpl implements UserService {
// omitted
public void create(...) {
// omitted...
if (...) {
// illegal state!
ResultMessages messages = ResultMessages.error().add("e.ex.an.9001"); // (1)
throw new BusinessException(messages);
}
}
}
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - 項番
- 説明
* - | (1)
- | エラーメッセージを\ ``ResultMessages``\ で作成し、\ ``BusinessException``\ に設定する。
* Controllerクラス
.. code-block:: java
@RequestMapping(value = "create", method = RequestMethod.POST)
public String create(@Validated UserForm form, BindingResult result, Model model) {
// omitted
try {
userService.create(user);
} catch (BusinessException e) {
ResultMessages messages = e.getResultMessages(); // (1)
model.addAttribute(messages);
return "user/createForm";
}
// omitted
}
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - 項番
- 説明
* - | (1)
- | \ ``BusinessException``\ が保持する\ ``ResultMessages``\ を取得し、Modelに追加する。
通常は、用意されているメッセージタイプのみで十分であるが、採用しているCSSライブラリによってはメッセージタイプを追加したい場合がある。例えば"notice"というメッセージタイプを追加する場合を説明する。
|
How to extend
--------------------------------------------------------------------------------
独自メッセージタイプを作成する
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| メッセージタイプを追加したい場合の、独自メッセージタイプ作成方法について説明する。
| 通常は、用意されているメッセージタイプのみで十分であるが、採用しているCSSライブラリによっては
| メッセージタイプを追加したい場合がある。例えば"notice"というメッセージタイプを追加する場合を説明する。
| まず、以下のように\ ``org.terasoluna.gfw.common.message.ResultMessageType``\ インタフェースを実装した
| 独自メッセージタイプクラスを作成する。
.. code-block:: java
import org.terasoluna.gfw.common.message.ResultMessageType;
public enum ResultMessageTypes implements ResultMessageType { // (1)
NOTICE("notice");
private ResultMessageTypes(String type) {
this.type = type;
}
private final String type;
@Override
public String getType() { // (2)
return this.type;
}
@Override
public String toString() {
return this.type;
}
}
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - 項番
- 説明
* - | (1)
- | \ ``ResultMessageType``\ インタフェースを実装したEnumを定義する。定数オブジェクトで作成してもよいが、Enumで作成することを推奨する。
* - | (2)
- | \ ``getType``\ の返り値が出力されるCSSのclass名に対応する。
| このメッセージタイプを使用して以下のように\ ``ResultMessages``\ を作成する。
.. code-block:: java
ResultMessages messages = new ResultMessages(ResultMessageTypes.NOTICE) // (1)
.add("w.xx.yy.2001");
model.addAttribute(messages);
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - 項番
- 説明
* - | (1)
- | \ ``ResultMessages``\ のコンストラクタに対象の\ ``ResultMessageType``\ を指定する。
この場合、\ ```` \ で以下のようなHTMLが出力される。
.. code-block:: html
- The recommended change interval has passed password. Please change your password.
.. tip::
拡張方法は、\ `org.terasoluna.gfw.common.message.StandardResultMessageType `_\ が参考になる。
|
Appendix
--------------------------------------------------------------------------------
.. _message-management-messagepanel-attribute:
タグの属性変更
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
\ ````\ タグには、表示形式を変更する属性がいくつか用意されている。
.. tabularcolumns:: |p{0.25\linewidth}|p{0.55\linewidth}|p{0.20\linewidth}|
.. list-table:: \ ````\ タグ 属性一覧
:header-rows: 1
:widths: 25 55 20
* - オプション
- 内容
- defaultの設定値
* - panelElement
- 結果メッセージ表示パネルの要素。
- \ ``div``\
* - panelClassName
- 結果メッセージ表示パネルのCSS class名。
- \ ``alert``\
* - panelTypeClassPrefix
- CSS class名の接頭辞。
- \ ``alert-``\
* - messagesType
- メッセージタイプ。この属性が設定された場合。設定されたメッセージタイプが\ ``ResultMessages``\ がもつメッセージタイプより優先されて使用される。
- デフォルト値なし
* - outerElement
- 結果メッセージ一覧を構成するHTMLの外側のタグ。
- \ ``ul``\
* - innerElement
- 結果メッセージ一覧を構成するHTMLの内側のタグ。
- \ ``li``\
* - disableHtmlEscape
- | HTMLエスケープ処理を無効化するためのフラグ。
| \ ``true``\ を指定する事で、出力するメッセージに対してHTMLエスケープ処理が行われなくなる。
| この属性は、出力するメッセージにHTMLを埋め込むことで、メッセージの装飾などができるようにするために用意している。
.. caution::
trueを指定する場合は、XSS対策が必要な文字がメッセージ内に含まれない事が保証されていること。
- | \ ``false``\
|
以下に、属性変更の例を示す。
|
class名の変更
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
例えば、CSSフレームワーク\ `BlueTrip `_\ では以下のようなCSSが用意されている。
.. code-block:: css
.error,.notice,.success {
padding: .8em;
margin-bottom: 1.6em;
border: 2px solid #ddd;
}
.error {
background: #FBE3E4;
color: #8a1f11;
border-color: #FBC2C4;
}
.notice {
background: #FFF6BF;
color: #514721;
border-color: #FFD324;
}
.success {
background: #E6EFC2;
color: #264409;
border-color: #C6D880;
}
| このCSSを使用したい場合、\ ``...
``\ というようにメッセージを出力する必要がある。
| この場合、\ ````\ タグを以下のように使用すればよい(Controllerは修正不要である)。
.. code-block:: jsp
出力されるHTMLは以下のようになる。
.. code-block:: html
- There are inconsistencies in the data.
ブラウザで表示すると、以下のように出力される。
.. figure:: ./images_MessageManagement/message-management-bluetrip-error.jpg
:width: 80%
|
HTML Elementの変更
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
例えば、メッセージ一覧を表示するために\ ````\ タグを使用したくない場合は、\ ``outerElement``\ 属性と\ ``innerElement``\ 属性を使用することでカスタマイズできる。
以下のように属性を設定した場合は、
.. code-block:: jsp
次のようにHTMLが出力される。
.. code-block:: html
There are inconsistencies in the data.
Cannot upload, Because the file size must be less than 1,024MB.
以下のようにCSSを設定することで、
.. code-block:: css
.alert > span {
display: block; /* (1) */
}
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - 項番
- 説明
* - | (1)
- | "alert"クラスの要素の子となる\ ````\ タグをブロックレベル要素にする。
ブラウザで次のように表示される。
.. figure:: ./images_MessageManagement/message-management-messagespanel-span.jpg
:width: 60%
|
HTMLエスケープ処理の無効化
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
| disableHtmlEscape属性を\ ``true``\にした場合、以下のような出力イメージにする事ができる。
| 下記の例では、メッセージの一部のフォントを「16pxの赤字」に装飾している。
- jsp
.. code-block:: jsp
:emphasize-lines: 4
- properties
.. code-block:: properties
i.xx.yy.0001 = Please confirm order content. If this orders submitted, cannot cancel.
- 出力イメージ
.. figure:: ./images_MessageManagement/message-management-disableHtmlEscape-true.png
:width: 100%
disableHtmlEscape属性が\ ``false``\(デフォルト)の場合は、HTMLエスケープされて以下のような出力となる。
.. figure:: ./images_MessageManagement/message-management-disableHtmlEscape-false.png
:width: 100%
ResultMessagesを使用しない結果メッセージの表示
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
\ ````\ タグは\ ``ResultMessages``\ オブジェクト以外にも
* ``java.lang.String``
* ``java.lang.Exception``
* ``java.util.List``
オブジェクトも出力できる。
| 通常は\ ````\ タグは\ ``ResultMessages``\ オブジェクトの出力用に使用するが、
| フレームワークがリクエストスコープに設定した文字列(エラーメッセージなど)を表示する場合にも使用できる。
| 例えば、Spring Securityのデフォルトの設定で使用される、\ ``org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler``\ では、認証エラー時に発生した例外オブジェクトを\ ``SPRING_SECURITY_LAST_EXCEPTION``\ という属性名で、リダイレクト時はセッション、フォワード時はリクエストスコープに格納する。
| この例外メッセージを、結果メッセージ同様に\ ````\ タグで出力したい場合は、以下のように設定すればよい。
.. code-block:: jsp
Login
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}|
.. list-table::
:header-rows: 1
:widths: 10 90
* - 項番
- 説明
* - | (1)
- | 結果メッセージ表示用のCSSを再掲する。実際はCSSファイルに記述することを強く推奨する。
* - | (2)
- | ``Exception``\ オブジェクトが格納されている属性名を\ ``messagesAttributeName``\ 属性で指定する。
| また、\ ``ResultMessages``\ オブジェクトとは異なり、メッセージタイプの情報をもたないため、
| \ ``messagesType``\ 属性で、明示的に、メッセージタイプを指定する必要がある。
認証エラー時に出力されるHTMLは
.. code-block:: html
であり、ブラウザでは以下のように出力される。
.. figure:: ./images_MessageManagement/message-management-login-error.jpg
:width: 60%
\
.. tip::
ログイン用のJSPの内容については、\ :doc:`../../Security/Authentication`\ を参照されたい。
.. _message-management-messagekeysgen:
メッセージID定数クラスの自動生成ツール
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| これまでの例ではメッセージIDを文字列のハードコードで設定していたが、
| メッセージIDは定数クラスにまとめることを推奨する。
| ここでは、簡易ツールとして、propertiesファイルからメッセージID定数クラスを
| 自動生成するプログラムおよび使用方法を紹介する。必要に応じてカスタマイズして利用されたい。
.. raw:: latex
\newpage
#. メッセージID定数クラスの作成
まず空のメッセージID定数クラスを作成する。ここでは\ ``com.example.common.message.MessageIds``\ とする。
.. code-block:: java
package com.example.common.message;
public class MessageKeys {
}
#. 自動生成クラスの作成
次に\ ``MessageKeys``\ クラスと同じパッケージに\ ``MessageKeysGen``\ クラスを作成し、以下のように記述する。
.. code-block:: java
package com.example.common.message;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.springframework.core.io.ClassPathResource;
public class MessageIdsGen {
public static void main(String[] args) throws IOException {
// message properties file
Class> targetClazz = MessageIds.class;
Path output = Paths.get("src/main/java", targetClazz.getName().replace(".", "/") + ".java");
try (InputStream inputStream =
new ClassPathResource("i18n/application-messages-msmn.properties").getInputStream();
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(inputStream));
PrintWriter pw = new PrintWriter(Files.newBufferedWriter(output))) {
pw.println("package " + targetClazz.getPackage().getName() + ";");
pw.println("");
pw.println("/**");
pw.println(" * Message Id");
pw.println(" */");
pw.println("public class " + targetClazz.getSimpleName() + " {");
String line = null;
while ((line = bufferedReader.readLine()) != null) {
String[] vals = line.split("=", 2);
if (vals.length > 1) {
String id = vals[0].trim();
String value = vals[1].trim();
pw.println(" /** " + id + "=" + value + " */");
pw.println(" public static final String "
+ id.toUpperCase().replace(".", "_").replace("-", "_") + " = \"" + id
+ "\";");
}
}
pw.println("");
pw.println(" private " + targetClazz.getSimpleName() + "() {}");
pw.println("}");
}
}
}
#. メッセージプロパティファイルの用意
src/main/resource/i18m/application-messages.propertiesにメッセージを定義する。ここでは例として、以下のように設定する。
.. code-block:: properties
i.xx.yy.0001={0} upload completed.
w.xx.yy.2001=The recommended change interval has passed password. Please change your password.
e.xx.yy.8001=Cannot upload, Because the file size must be less than {0}MB.
e.xx.yy.9001=There are inconsistencies in the data.
#. 自動生成クラスの実行
.. figure:: ./images_MessageManagement/message-management-messagekeysgen.png
:width: 60%
\ ``MessageIds``\ クラスが、以下のように上書きされる。
.. code-block:: java
package com.example.common.message;
/**
* Message Id
*/
public class MessageIds {
/** i.xx.yy.0001={0} upload completed. */
public static final String I_XX_YY_0001 = "i.xx.yy.0001";
/** w.xx.yy.2001=The recommended change interval has passed password. Please change your password. */
public static final String W_XX_YY_2001 = "w.xx.yy.2001";
/** e.xx.yy.8001=Cannot upload, Because the file size must be less than {0}MB. */
public static final String E_XX_YY_8001 = "e.xx.yy.8001";
/** e.xx.yy.9001=There are inconsistencies in the data. */
public static final String E_XX_YY_9001 = "e.xx.yy.9001";
}
.. raw:: latex
\newpage