ひこぽんのーと

覚書と雑記です。

JavaEE 7をやってみよう。 JSF 画面遷移 その1 navigation-rule

前回、簡単な画面を作成したので、
今回はそれを拡張して、新規登録画面への画面遷移を作る。
サイドメニューの「艦艇登録」リンクを押下して、登録画面へ遷移するイメージ。

通常であれば、HTMLのリンクには、遷移先のURLを記載すればOKなのだが、
それではミもフタもないので、JSFの機能であるNavigation-ruleを使ってみる。

Navigation-ruleはfaces-config.xmlに記載する画面遷移設定のことで、
条件をXMLに記載しておけば、
JSF側のソースにURLを書かずとも画面遷移を構築できる。
遷移元→遷移先のURLを設定ファイルに持つため、
URL変更の手間も軽減できる*1……かもしれない。

といったところで、実装開始。
まず、遷移元のソースはあるので、遷移先のソースを作る。
はじめに書いた通り、新規登録の入力画面を作る。

jsf/contents/warship/insert.xhtml

入力項目である艦種と艦名、登録ボタンを持つ画面を画面部品として作る。
画面項目などの項目名、ボタン名はリソースファイルに持たせた。
入力値の格納や登録処理を行うManaged Beanはまだ未作成のため、
画面のソースにも処理は記載していない。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://java.sun.com/jsf/facelets" 
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:f="http://java.sun.com/jsf/core">
    <h2><h:outputLabel value="#{staticText['warship.reg.lblSreenTitle']}" /></h2>
    <hr/>
    <h:messages id="errorText" layout="table" errorClass="error-message"/>
    <h:outputLabel value="#{staticText['warship.reg.lblWarshipType']}" />
    <h:selectOneMenu id="warshipType" value="" styleClass="warship-type-select" >
    </h:selectOneMenu>
    <h:outputLabel value="#{staticText['warship.reg.lblWarshipName']}" />
    <h:inputText id="warshipName" value="" styleClass="warship-name-input" required="true" autocomplete="off" />
    <br/>
    <h:commandButton value="#{staticText['warship.reg.btnRegister']}" action="catalog" />
    <h:commandButton value="#{staticText['warship.reg.btnRegisterAndRegister']}" />
</ui:composition>
site-title= 艦艇これくしょん
copyright=(C) ひこぽん(nagamitsu1976)
# 画面ラベル
# サイドメニュー
warship.menu.lnkCatalog=艦艇図鑑
warship.menu.lnkRegister=艦艇登録
warship.menu.lnkEdit=艦艇編集
warship.menu.lnkRemove=艦艇削除

# 艦艇登録
warship.reg.lblSreenTitle=艦艇登録
warship.reg.lblWarshipType=艦種
warship.reg.lblWarshipName=艦名
warship.reg.btnRegister=登録
warship.reg.btnRegisterAndRegister=連続登録
warship.reg.btnEdit=編集
warship.reg.btnBack=戻る
.warship-type-select {
    width: 120px;
    margin: 10px;
}
.warship-name-input {
    width: 220px;
    margin: 10px;
}

jsf/view/warship/insert.xhtml

上で書いた入力画面部品をレイアウトに適用した登録画面のソース。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition 
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:h="http://java.sun.com/jsf/html"
        template="/jsf/layout/common/layout.xhtml">

    <ui:define name="title">#{staticText['warship.menu.lnkRegister']}</ui:define>

    <ui:define name="content"> 
        <ui:include src="/jsf/contents/warship/insert.xhtml"/>           
    </ui:define>

</ui:composition>

jsf/contents/common/menu.xhtml

メニューの画面部品。
commandLinkタグを使って、メニューのリンクを追加した。
また、文字列をリソースファイルから取得するように合わせて修正。
ここで注目するのは、リンク先の指定について。
URLはタグ内に一切含めていない。action属性に文字列を設定しただけ。
comandLinkやcommandButtonタグのaction属性には基本、文字列を定義する。
JSFではリンクやボタンを押した時、action属性の値を使ってnavigation-ruleを参照し、
条件に該当するルールを特定する。
特定できたnaviation-ruleから遷移先のURLを取得して画面遷移を行う、というわけ。
ここでは"catalog", "register", "edit", "remove"というルールがあると想定している。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:h="http://java.sun.com/jsf/html">
    <div><h:commandLink action="catalog" value="#{staticText['warship.menu.lnkCatalog']}" immediate="true"/></div>
    <div><h:commandLink action="register" value="#{staticText['warship.menu.lnkRegister']}" immediate="true" /></div>
    <div><h:commandLink action="edit" value="#{staticText['warship.menu.lnkEdit']}" immediate="true" /></div>
    <div><h:commandLink action="remove" value="#{staticText['warship.menu.lnkRemove']}" immediate="true" /></div>
</ui:composition>

faces-config.xml

navigation-ruleをfaces-config.xmlに追加した。
navigation-ruleタグで囲った部分が今回の追加部分。

from-view-idタグはこのルールを適用するページのURLを指定する。
サンプルのようにアスタリスクを使ったりして条件範囲を指定することも可能。
サンプルではサイドメニュー用のnavigation-ruleなので、
遷移元画面が/jsf/view/配下すべての画面が対象となっている。

navigation-caseタグに囲われたブロックに
判定条件であるfrom-outcomeタグと
遷移先を指定するためのto-view-idを記載する。

from-outcomeタグに定義した値を
HTML側のcommandLinkタグのaction属性に設定すれば、
ここの値を読み取ってサーバーが勝手にリンクを作ってくれる。

<?xml version="1.0" encoding="UTF-8"?>
<faces-config
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
    version="2.2">
    <application>
        <locale-config>
            <default-locale>ja</default-locale>
        </locale-config>
        <resource-bundle>
            <base-name>resources.statictext</base-name>
            <var>staticText</var>
        </resource-bundle>
    </application>

 <navigation-rule>
  <!-- 遷移元のJSP名を記述 -->
  <from-view-id>/jsf/view/*</from-view-id>
  <!-- アクションの結果によって遷移先を変更 -->
  <navigation-case>
   <from-outcome>catalog</from-outcome>
   <to-view-id>/jsf/view/warship.xhtml</to-view-id>
  </navigation-case>
  <navigation-case>
   <from-outcome>register</from-outcome>
   <to-view-id>/jsf/view/insert.xhtml</to-view-id>
  </navigation-case>
 </navigation-rule>

</faces-config>

画面とリンクの定義をしたら、動作確認をしてみる。
サイドメニューから艦艇図鑑や艦艇登録のリンクを押すと、
ルール通り遷移することが確認できる。
艦艇編集や艦艇削除のリンクは、
ルールを定義していないので押下してもなにも起きない。
f:id:nagamitsu1976:20151030145214p:plain
f:id:nagamitsu1976:20151030145622p:plain

次回は登録画面用のManaged Beanを作って、
登録処理のイベントを作る。

といったところで次回へ続く。

*1:軽減可能かどうかは定義次第だと思うよ、実際。