JBoss Seamとは、Java EEベースで、JSF(JavaServer Faces)からEJB(Enterprise Java Bean) 3.0、JPA(Enterprise Java Bean)まで一貫したコンポーネントモデルで「つなぐ」Webアプリケーション開発用フレームワークで、いくつかのアノテーションを使うだけでEJBとJSFをつなぎ合わせることができるようになっている。
今回は、JBoss Seamアプリケーションで入力画面・確認画面・完了画面の3画面を含み、HTMLオブジェクトとしてテキストボックス・ラジオボタン・チェックボックス等を含むWEBアプリケーションを作成してみたので、そのサンプルプログラムを共有する。
前提条件
下記記事に記載した、JBoss Seamアプリケーションで初期表示画面(input.xhtml)の追加が完了していること。
さらに、以下の手順に従って、Lombokの導入が完了していること。
サンプルプログラムの作成
作成したサンプルプログラムの構成は、以下の通り。

なお、上記の赤枠は、前提条件のプログラムから追加・変更したプログラムである。
入力画面(input.xhtml)、確認画面(confirm.xhtml)、完了画面(complete.xhtml)の内容は、以下の通り。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<!-- h:head,h:bodyタグを使うとエラーになるため、head,bodyタグにそれぞれ変更 -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>入力画面</title>
</head>
<body>
<p>下記必要事項を記載の上、「確認」ボタンを押下してください。</p><br/>
<h:form>
<table border="0">
<tr>
<td align="left" valign="top">名前:</td>
<td><h:inputText value="#{inputFormAction.name}" /></td>
</tr>
<tr>
<td align="left" valign="top">生年月日:</td>
<td>
<h:inputText value="#{inputFormAction.birthYear}" size="4" maxlength="4" />年
<h:selectOneMenu value="#{inputFormAction.birthMonth}">
<f:selectItems value="#{inputFormAction.birthMonthItems}"/>
</h:selectOneMenu>月
<h:selectOneMenu value="#{inputFormAction.birthDay}">
<f:selectItems value="#{inputFormAction.birthDayItems}"/>
</h:selectOneMenu>日
</td>
</tr>
<tr>
<td align="left" valign="top">性別:</td>
<td>
<h:selectOneRadio value="#{inputFormAction.sex}">
<f:selectItems value="#{inputFormAction.sexItems}"/>
</h:selectOneRadio>
</td>
</tr>
<tr>
<td align="left" valign="top">メモ:</td>
<td><h:inputTextarea value="#{inputFormAction.memo}"
cols="40" rows="6" /></td>
</tr>
<tr>
<td align="left" valign="top">入力確認:</td>
<td><h:selectBooleanCheckbox
value="#{inputFormAction.checked}" /></td>
</tr>
</table>
<br/>
<h:commandButton value="確認" action="#{inputFormAction.confirm()}" />
</h:form>
</body>
</html><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:a4j="http://richfaces.org/a4j">
<!-- h:head,h:bodyタグを使うとエラーになるため、head,bodyタグにそれぞれ変更 -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>確認画面</title>
<!-- cssファイルの読み込みをseams用に変更 -->
<a4j:loadStyle src="resource:///stylesheet/demoJsf.css" />
</head>
<body>
<p>入力内容を確認し、問題なければ「送信」ボタンを押下してください。</p><br/>
<h:form>
<table border="0">
<tr>
<td align="left" valign="top">名前:</td>
<td><h:outputText value="#{inputFormAction.name}" /></td>
</tr>
<tr>
<td align="left" valign="top">生年月日:</td>
<td><h:outputText
value="#{inputFormAction.birthYear}年 #{inputFormAction.birthMonth}月 #{inputFormAction.birthDay}日"
/></td>
</tr>
<tr>
<td align="left" valign="top">性別:</td>
<td><h:outputText value="#{inputFormAction.sexLabel}" /></td>
</tr>
<tr>
<td align="left" valign="top">メモ:</td>
<td><h:outputText value="#{inputFormAction.memo}"
styleClass="lineBreakFormat" /></td>
</tr>
<tr>
<td align="left" valign="top">確認チェック:</td>
<td>
<h:outputText value="確認済"
rendered="#{inputFormAction.checked}" />
<h:outputText value="未確認"
rendered="#{inputFormAction.checked == false}" />
</td>
</tr>
</table>
<br/>
<h:commandButton value="送信" action="#{inputFormAction.send()}" />
<h:outputText value=" "/>
<!-- で半角空白が設定されないため、上記のように変更 -->
<h:commandButton value="戻る" action="#{inputFormAction.back()}" />
</h:form>
</body>
</html><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<!-- h:head,h:bodyタグを使うとエラーになるため、head,bodyタグにそれぞれ変更 -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>完了画面</title>
</head>
<body>
<p>お申し込みが完了しました。</p>
</body>
</html>上記XHTMLファイルは、以下の記事のinput.xhtml、confirm.xhtml、complete.xhtmlのソースコードをそれぞれ流用していて、それぞれ、h:head,h:bodyタグをhead,bodyタグに変更している。また、確認画面のCSSファイル読込方法を変更している。
また、各画面のForm値と画面遷移処理を定義したクラスの内容は、以下の通り。
package faces;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.model.SelectItem;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import common.CommonUtil;
import lombok.Data;
import lombok.ToString;
/**
* 画面のフォーム値と画面遷移メソッドを定義.
*/
// 会話スコープを指定
// 会話スコープの開始・終了タイミングはpages.xmlで指定
@Scope(ScopeType.CONVERSATION)
// @Nameアノテーションは、JSFのXHTMLファイルから#{inputFormAction}で
// Javaクラスを参照できるようにしている(→バッキングビーン)
// ただし、org.jboss.seam.annotations.Nameクラスなので注意
@Name("inputFormAction")
@Data
@ToString(exclude={"birthMonthItems","birthDayItems","sexItems"})
public class InputFormAction implements Serializable {
// シリアルバージョンUID
private static final long serialVersionUID = 7283339629129432007L;
/** 名前 */
private String name;
/** 生年月日_年 */
private String birthYear;
/** 生年月日_月 */
private String birthMonth;
/** 生年月日_日 */
private String birthDay;
/** 性別 */
private String sex;
/** 性別(ラベル) */
private String sexLabel;
/** メモ */
private String memo;
/** 確認チェック */
private Boolean checked;
/** 生年月日_月(選択リスト) */
private List<SelectItem> birthMonthItems;
/** 生年月日_日(選択リスト) */
private List<SelectItem> birthDayItems;
/** 性別(選択リスト) */
private List<SelectItem> sexItems;
/**
* コンストラクタ生成時に選択リストの値を設定.
*/
public InputFormAction(){
// 生年月日_月(選択リスト)
birthMonthItems = new ArrayList<SelectItem>();
birthMonthItems.add(new SelectItem("", ""));
for(Integer i = 1; i <= 12; i++){
birthMonthItems.add(new SelectItem(String.valueOf(i), String.valueOf(i)));
}
// 生年月日_日(選択リスト)
birthDayItems = new ArrayList<SelectItem>();
birthDayItems.add(new SelectItem("", ""));
for(Integer i = 1; i <= 31; i++){
birthDayItems.add(new SelectItem(String.valueOf(i), String.valueOf(i)));
}
// 性別(選択リスト)
sexItems = new ArrayList<SelectItem>();
sexItems.add(new SelectItem(String.valueOf(1),"男"));
sexItems.add(new SelectItem(String.valueOf(2),"女"));
}
/**
* 確認画面への遷移.
* @return 確認画面へのパス
*/
public String confirm(){
// 性別(ラベル)を設定
if(!CommonUtil.isBlank(sex)){
this.setSexLabel(this.getSexItems().get(
Integer.parseInt(this.getSex())-1).getLabel());
}
// Formに設定された値を出力
System.out.println(this.toString());
// 確認画面に遷移
return "confirm";
}
/**
* 入力画面に戻る.
* @return 入力画面へのパス
*/
public String back(){
// 入力画面に戻る
return "back";
}
/**
* 完了画面への遷移.
* @return 完了画面へのパス
*/
public String send(){
// 確認画面に表示された値を出力
System.out.println(this.toString());
// 完了画面への遷移
return "send";
}
}上記Actionファイルは、以下の記事のInputFormAction.javaをそれぞれ流用していて、クラスの先頭に、seamの@Scopeアノテーションと@Nameアノテーションを付与するよう、変更している。また、確認チェックをString型からBoolean型に変更している。
さらに、画面遷移を定義したpages.xmlの定義は以下の通りで、会話スコープの開始・終了タイミングも定義している。
<?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd">
<!-- 入力画面から確認画面への遷移 -->
<page view-id="/input.xhtml">
<!-- 確認画面に遷移する直前に、会話スコープを開始 -->
<!-- 既に会話スコープを開始している場合は、その会話スコープをそのまま使う -->
<begin-conversation join="true"/>
<navigation from-action="#{inputFormAction.confirm()}">
<rule if-outcome="confirm">
<redirect view-id="/confirm.xhtml"/>
</rule>
</navigation>
</page>
<!-- 確認画面から完了画面・入力画面への遷移 -->
<page view-id="/confirm.xhtml">
<navigation from-action="#{inputFormAction.send()}">
<rule if-outcome="send">
<!-- 完了画面にリダイレクト遷移する直前に、会話スコープを終了 -->
<end-conversation before-redirect="true"/>
<redirect view-id="/complete.xhtml"/>
</rule>
</navigation>
<navigation from-action="#{inputFormAction.back()}">
<rule if-outcome="back">
<redirect view-id="/input.xhtml"/>
</rule>
</navigation>
</page>
<!-- 以下はSeamプロジェクト作成時に記載された内容となる -->
<exception class="org.jboss.seam.framework.EntityNotFoundException">
<redirect view-id="/error.xhtml">
<message severity="warn">Record not found</message>
</redirect>
</exception>
<exception class="javax.persistence.EntityNotFoundException">
<redirect view-id="/error.xhtml">
<message severity="warn">Record not found</message>
</redirect>
</exception>
<exception class="javax.persistence.EntityExistsException">
<redirect view-id="/error.xhtml">
<message severity="warn">Duplicate record</message>
</redirect>
</exception>
<exception class="javax.persistence.OptimisticLockException">
<end-conversation/>
<redirect view-id="/error.xhtml">
<message severity="warn">
Another user changed the same data, please try again
</message>
</redirect>
</exception>
<exception class="org.jboss.seam.security.AuthorizationException">
<redirect view-id="/error.xhtml">
<message severity="error">
You don't have permission to access this resource
</message>
</redirect>
</exception>
<exception class="org.jboss.seam.security.NotLoggedInException">
<redirect view-id="/login.xhtml">
<message severity="warn">
#{messages['org.jboss.seam.NotLoggedIn']}
</message>
</redirect>
</exception>
<exception class="javax.faces.application.ViewExpiredException">
<redirect view-id="/error.xhtml">
<message severity="warn">
Your session has timed out, please try again
</message>
</redirect>
</exception>
<exception class="org.jboss.seam.ConcurrentRequestTimeoutException"
log-level="trace">
<http-error error-code="503" />
</exception>
<exception>
<redirect view-id="/error.xhtml">
<message severity="error">Unexpected error, please try again</message>
</redirect>
</exception>
</pages>その他、確認画面(confirm.xhtml)で読んでいるCSSファイル、共通ユーティリティクラスの内容は、以下の記事と同じ内容となっている。
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/seam-web-somescreen/demoSeam
サンプルプログラムの実行結果
サンプルプログラムの実行結果は以下の通りで、画面遷移が行えることが確認できる。
1) JBoss ASサーバーを再起動し、「http://localhost:8082/demoSeam/」とアクセスすると、以下の画面が起動することが確認できる。

2) 以下のように、データを指定し「確認」ボタンを押下すると、確認画面に入力画面の内容が表示される。さらに「戻る」ボタンを押下すると、入力画面に戻り入力値が復旧されることが確認できる。


3) 以下のように、メモを入力しないで「確認」ボタンを押下した場合も、確認画面に入力画面の内容が表示される。さらに「送信」ボタンを押下すると、完了画面に遷移することが確認できる。


4) 2)3)の動作で、以下のように、コンソールに赤枠のログが出力されることが確認できる。

要点まとめ
- JBoss Seamアプリケーションの画面遷移定義は、pages.xmlで指定する。
- JBoss Seamアプリケーションのバッキングビーンには、クラスの先頭に、seamの@Nameアノテーションを付与する必要がある。また、スコープの指定は、クラスの先頭に、seamの@Scopeアノテーションを付与することで行う。
- JBoss Seamアプリケーションで会話スコープを利用するには、バッキングビーンでスコープ指定をすると共に、pages.xmlに、会話スコープの開始・終了タイミングを指定する必要がある。





