<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC
  "-//Apache Software Foundation//DTD XDOC 1.0//EN"
  "http://maven.apache.org/dtd/xdoc_1_0.dtd">

<document>
  <properties>
    <title>コントローラ層 - Controller Layer</title>
    <author email="kurokkie@users.sourceforge.jp">kurokkie</author>
  </properties>
  <body>
    <section name="コントローラ層">
      <p>
コントローラ層は、クライアントからのリクエストを受け付け、ビュー層とドメイン層を調整します。コントローラ層は画面遷
移、セッション管理やメッセージの管理などを担当します。コントローラの実装はプレゼンテーション形態によって異なり
ます。United Front 2 のプレゼンテーションは Web です。Web に関するクラスは <code>org.unitedfront2.web</code>
以下のパッケージに、コントローラの Web 実装は <code>org.unitedfront2.web.controller</code>
に収録しています。
      </p>
      <p>
United Front 2 の Web コントローラ (HTML/XML) は <a href="http://www.springframework.org/webflow">Spring Web Flow</a>
をベースとしています。ウィジェットなどの画面の一部分に対するコントローラは <a href="http://tiles.apache.org/">Apache Tiles 2</a>
を利用しています。ここでは Spring Web Flow や Tiles に関する詳細な説明は避け、サンプルソースコードを中
心に解説します。これらのライブラリの詳細な使用方法は本家のドキュメントを参照して下さい。
      </p>
    </section>
    <section name="画面遷移">
      <p>
Web (HTML) の画面遷移は <a href="http://www.springframework.org/webflow">Spring Web Flow</a>
を採用しています。 
      </p>
      <subsection name="サンプルのシナリオ">
        <p>
サンプルで登場するシナリオはメールアドレスの変更機能で、ユースケースは次のとおりです。メールアドレス変更時に
パスワードを再発行しているのは、入力されたメールアドレスが正しいものであることを確認するためです。
        </p>
        <dl>
          <dt>主成功シナリオ</dt>
          <dd>
          <ol>
            <li>システムはメールアドレスの変更フォームを表示する<div class="source"><a href="images/mailAddrChangeScreen1.png"><img src="images/mailAddrChangeScreen1.png" alt="メールアドレス変更画面"/></a></div></li>
            <li>ユーザは新しいメールアドレスを入力する</li>
            <li>システムは認証フォームを表示する<div class="source"><a href="images/mailAddrChangeScreen2.png"><img src="images/mailAddrChangeScreen2.png" alt="メールアドレス変更画面"/></a></div></li>
            <li>ユーザはログイン ID （旧メールアドレス）とパスワードを入力する</li>
            <li>システムはユーザのデータを新しいメールアドレスに変更し、パスワードも再発行する</li>
            <li>システムは再発行したパスワードが記載されたメールを、ユーザの新しいメールアドレスに送信する</li>
            <li>システムは処理が完了した旨を表示する<div class="source"><a href="images/mailAddrChangeScreen3.png"><img src="images/mailAddrChangeScreen3.png" alt="メールアドレス変更画面"/></a></div></li>
          </ol>
          </dd>
          <dt>例外 a</dt>
          <dd>2 で、ユーザの入力値が不正だった場合は 1 に戻り、エラーメッセージを出力する</dd>
          <dt>例外 b</dt>
          <dd>4 で、ユーザの入力値が不正だった場合は 3 に戻り、エラーメッセージを出力する</dd>
          <dt>例外 c</dt>
          <dd>4 で認証に失敗した場合は 3 に戻り、エラーメッセージを出力する</dd>
          <dt>例外 d</dt>
          <dd>5 で新しいメールアドレスが既に他のユーザによって使用されている場合は 1 に戻り、エラーメッセージを出力する</dd>
        </dl>
        <div><img src="images/scenario.png" alt="Scenario"/></div>
      </subsection>
      <subsection name="アクションクラス">
        <p>アクションクラスは次のような処理を担当します。</p>
        <ul>
          <li>入力値の検証</li>
          <li>トランザクションの制御</li>
          <li>ビューへ転送するのデータの作成</li>
          <li>エラーメッセージ処理</li>
        </ul>
          <p>
トランザクション制御には、 <strong>宣言的トランザクション制御</strong> を採用しているため、プログラマがトラ
ンザクションに関するコードを書くことはほとんどありません。トランザクション制御の範囲は
<a href="http://static.springframework.org/spring-webflow/docs/1.0.x/api/org/springframework/webflow/execution/Action.html"><code>Action</code></a>
インターフェースの <code>execute</code> メソッドの開始から終わりまでです。アクションクラスのアクションメ
ソッドが例外を放った時点でロールバックを実行します。
          </p>
        <p>
United Front 2 では入力フォーム処理用のアクションクラス
<a href="apidocs/org/unitedfront2/web/controller/FormAction.html"><code>org.unitedfront2.web.controller.FormAction</code></a>
を提供しています。このクラスは Spring オリジナルの <a href="http://static.springframework.org/spring-webflow/docs/1.0.x/api/org/springframework/webflow/action/FormAction.html"><code>org.springframework.webflow.action.FormAction</code></a>
を継承しており、さらに以下の機能を加えています。
        </p>
        <ul>
          <li>ドメインファクトリを使ったフォームオブジェクトの生成</li>
          <li>設定した検証クラスをビューへ転送</li>
          <li>メール送信フレームワーク</li>
        </ul>
        <p>
United Front 2 におけるフォーム処理は通常 United Front 2 の <code>FormAction</code> を継
承して実装します。
        </p>
        <div class="info">
          <h5>Note: Web MVC フレームワーク</h5>
          <p>
Spring MVC は <a href="http://struts.apache.org/">Struts</a> (1.x) に代表される従来
の Web MVC フレームワークからいくつかの改良点が加えられています。その改良点の一つに、クライアントからのリク
エストを直接 JavaBean オブジェクトにバインドする仕組みが挙げられます。この機能を利用すれば、United
Front 2 のドメインオブジェクトをビュー層からドメイン層まで一貫して利用できます。また、Spring Web Flow を
採用する利点には次のようなものがあります。
          </p>
          <ul>
            <li>セッション管理をフレームワークに任せることができる</li>
            <li>一つの URL で一連の画面遷移を実現できる</li>
            <li>画面遷移を再利用できる</li>
            <li>Spring MVC の機能を利用できる（タグライブラリなど）</li>
          </ul>
        </div>
        <div>
          <h4>主要アクションメソッド</h4>
          <p>
<a href="http://static.springframework.org/spring-webflow/docs/1.0.x/api/org/springframework/webflow/action/MultiAction.html"><code>MultiAction</code></a>
が持つべき代表的なアクションメソッドを次に示します。アクションメソッドについては Spring Web Flow のドキュメ
ント <a href="http://static.springframework.org/spring-webflow/docs/1.0.x/reference/flow-definition.html#actionStateXml-multiActionMethod">ActionState XML - multi action</a>
を参照ください。
          </p>
          <div class="smaller">
            <table>
              <tr>
                <th>メソッド名</th>
                <th>説明</th>
              </tr>
              <tr>
                <td><code>init</code></td>
                <td>フローの初期処理を行います。</td>
              </tr>
              <tr>
                <td><code>setupForm</code></td>
                <td>フォーム画面表示前の処理を行います。例えば、フォーム画面に表示するデータをリクエストスコープに設定します。</td>
              </tr>
              <tr>
                <td><code>bindAndValidate</code></td>
                <td>クライアントリクエストからドメインオブジェクトを作成（バインド）し、ドメインオブジェクトの検証を行います。実際のバインドのロジックおよび検証ロジックは、それぞれ <code>doBind</code> メソッド、 <code>doValidator</code> メソッドに記述します。</td>
              </tr>
              <tr>
                <td><code>view</code></td>
                <td>情報を画面に表示します。</td>
              </tr>
              <tr>
                <td><code>sendMail</code></td>
                <td>メールを送信します。実際の送信ロジックは <code>doSendMail</code> メソッドに記述します。</td>
              </tr>
              <tr>
                <td><code>finish</code></td>
                <td>フローの終了処理を行います。</td>
              </tr>
            </table>
          </div>
        </div>
        <div>
          <h4>サンプルコード</h4>
          <p>
アクションクラスのサンプル <a
href="apidocs/org/unitedfront2/web/controller/account/MailAddrChangeAction.html">
<code>MailAddrChangeAction</code></a> を示します。<code>initAction</code> メソッドでは、
ドメインモデルの指定と e メール送信用テンプレート MailAddrChange-mail を設定しています。メールテンプ
レートについてはビュー層で解説しています。完全なコードは <a href="xref/org/unitedfront2/web/controller/account/MailAddrChangeAction.html"><code>MailAddrChangeAction</code> のソースコード</a>
を参照してください。
          </p>
<pre name="code" class="java">
// アノテーションベースの Spring Bean 定義。
// Bean 名は ${機能名}.${先頭が小文字のクラス名}
@Repository(value = "account.mailAddrChangeAction")
public class MailAddrChangeAction extends FormAction {

    @Autowired
    private AccountTable accountTable;

    @Override
    protected void initAction() {
        super.initAction();
        setFormObjectClass(Account.class);
        setMailTemplateName("MailAddrChange-mail");
    }

    /** メールアドレスの変更とパスワードの再発行 */
    public Event changeMailAddrAndReissuePassword(RequestContext context)
        throws MailAddrUsedByOtherException {

        int id = WebUtils.getAccount(context).getId();
        String newMailAddr = ((Account) getFormObject(context)).getMailAddr();
        String newPassword = Account.createRandomPassword(4, 8);

        Account newAccount = accountTable.get(id);
        newAccount.setMailAddr(newMailAddr);
        newAccount.setPassword(newPassword);
        newAccount.encrypt();
        try {
            newAccount.store();
        } catch (MailAddrUsedByOtherException e) {
            // メールアドレスが登録済みであるため、エラー処理
            // エラーメッセージを設定した後、例外をそのまま投げています。
            // 例外発生後の動作はフロー定義ファイル側で定義されます。
            logger.warn(e.getMessage());
            Errors errors = getBindingErrors(context, newAccount);
            errors.rejectValue("mailAddr",
                "account.validation.mailAddrUserdByOther",
                new Object[] {e.getMailAddr()}, e.getMessage());
            throw e;
        }

        // ビューへ転送するデータを設定
        context.getRequestScope().put("mailAddrAndPassword",
                new MailAddrAndPassword(newAccount.getMailAddr(), newPassword));

        return success();
    }

    // 検証クラスをインジェクション
    @Override
    @Resource(name = "account.mailAddrFormValidator")
    public void setValidator(Validator validator) {
        super.setValidator(validator);
    }
}
</pre>
          <div class="warning">
            <h5>Warning</h5>
            <p>
メールアドレスが既に使用されていた際に、<code>error()</code> メソッドではなく例外を発生させてメソッドを
終了している点に注意してください。これにより、トランザクションをロールバックしています。
<code>error()</code>　メソッドを使用した場合、ロールバックは実行されません。
            </p>
          </div>
          <div class="warning">
            <h5>Warning: 必要に応じて <code>initBinder</code> をオーバーライドする</h5>
            <p>
必要に応じて <code>initBinder</code> メソッドをオーバーライドし、クライアントからのリクエストを制限てくだ
さい。Spring のデフォルトの設定では、クライアントから送信された全てのプロパティをドメインオブジェクトに設定しよ
うと試みます。これは場合によってはセキュリティ上大変危険です。予期しない値がドメインオブジェクトのプロパティに設
定されないようにするためには、<code>FormAction</code> の <code>initBinder</code> メソッドを
オーバーライドし、<a href="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/validation/DataBinder.html"><code>DataBinder</code></a>
に許可するプロパティを設定します。
            </p>
<pre name="code" class="java">
@Override
protected void initBinder(RequestContext context, DataBinder binder) {
    super.initBinder(context, binder);
    binder.setAllowedFields(new String[] {"mailAddr"});
}
</pre>
          </div>
        </div>
      </subsection>
      <subsection name="入力値検証クラス">
        <p>
画面入力項目の検証クラスはドメイン層の検証クラスを用いて実装します。画面入力項目の検証クラスは <a
href="apidocs/org/unitedfront2/validation/SpringValidator.html"><code>
SpringValidator</code></a> インターフェースを実装する必要があります。実装は <a
href="apidocs/org/unitedfront2/validation/SpringValidatorSupport.html">
<code>SpringValidatorSupport</code></a> を使って簡素化できます。
        </p>
        <div>
          <h4>静的構造図</h4>
          <p>
<code>SpringValidator</code> は United Front 2 のフォームアクション <code>FormAction
</code> で使われています。<code>FormAction</code>　は <code>SpringValidator</code> から
オリジナルの検証クラスを取り出し、それをビューへ転送しています。
          </p>
          <div><img src="images/formValidator.png" alt="入力値検証クラス"/></div>
        </div>
        <div>
          <h4>サンプルソース</h4>
          <p>
入力値検証クラスのサンプル <a href="apidocs/org/unitedfront2/web/controller/account/MailAddrFormValidator.html"><code>MailAddrFormValidator</code></a>
を示します。<code>MailAddrFormValidator</code> はアカウントのメールアドレスの値の検証を行います。
完全なソースは <a href="xref/org/unitedfront2/web/controller/account/MailAddrFormValidator.html"><code>MailAddrFormValidator</code> のソースコード</a> を参照してください。
          </p>
<pre name="code" class="java">
@Repository(value = "account.mailAddrFormValidator")
public class MailAddrFormValidator
    extends SpringValidatorSupport&lt;AccountValidator, Account&gt; {

    @Override
    protected void doValidate(Account account, Errors errors) {
        try {
            getOriginalValidator().validateMailAddr(account);
        } catch (ValidationException e) {
            rejectValue("mailAddr", e, errors);
        }
    }

    @Override
    @Autowired
    public void setOriginalValidator(AccountValidator originalValidator) {
        super.setOriginalValidator(originalValidator);
    }
}
</pre>
        </div>
      </subsection>
      <subsection name="Flow 定義">
        <p>
画面遷移を含む処理の流れを Flow 定義ファイルに記述します。主要な Flow ID には次のようなものがあります。
        </p>
        <div class="smaller">
          <table>
            <tr>
              <th>ID</th>
              <th>説明</th>
            </tr>
            <tr>
              <td><code>init</code></td>
              <td>フローの初期処理実行状態に付与する ID です。通常 <code>action-state</code> タグに付与されます。通常アクションメソッド <code>init</code> を利用します。</td>
            </tr>
            <tr>
              <td><code>form</code></td>
              <td>フォーム処理実行状態に付与する ID です。通常 <code>action-state</code> タグに付与されます。通常アクションメソッド <code>setupForm</code> と <code>bindAndValidate</code> を利用します。</td>
            </tr>
            <tr>
              <td><code>mailSend</code></td>
              <td>メール送信処理実行状態に付与する ID です。通常 <code>action-state</code> タグに付与されます。通常アクションメソッド <code>sendMail</code> を利用します。</td>
            </tr>
            <tr>
              <td><code>finish</code></td>
              <td>フローの終了処理実行状態に付与する ID です。通常 <code>end-state</code> タグに付与されます。</td>
            </tr>
          </table>
        </div>
        <div>
          <h4>サンプルコード</h4>
          <p>
メールアドレス変更フォームから完了までの流れをフロー定義 <a
href="http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi/trunk/src/main/webapp/WEB-INF/flows/account/mailAddrChange-flow.xml?root=unitedfront2&amp;view=markup">mailAddrChange-flow.xml</a>
に記述しています。実際に認証を行っているのは認証サブフロー <a
href="http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi/trunk/src/main/webapp/WEB-INF/flows/account/authentication-sub-flow.xml?root=unitedfront2&amp;view=markup">authentication-sub-flow.xml</a>
です。メールアドレスの変更とパスワードの再発行を行うアクションステート
<code>changeMailAddrAndReissuePassword</code> では、メールアドレスが既に他者に使われてしまっ
ている場合に生じる <code>MailAddrUsedByOtherException</code> をキャッチすると、再度フォームス
テート <code>form</code> へ遷移します。次のサンプルは説明のため実際のコードから若干変更しています。
          </p>
<pre name="code" class="xml">
&lt;start-state idref="form"/&gt;

&lt;!-- メールアドレス変更フォーム --&gt;
&lt;view-state id="form" view="account.MailAddrChangeForm"&gt;
  &lt;render-actions&gt;
    &lt;action bean="account.mailAddrChangeAction" method="setupForm"/&gt;
  &lt;/render-actions&gt;
  &lt;transition on="submit" to="authenticate"&gt;
    &lt;action bean="account.mailAddrChangeAction" method="bindAndValidate"/&gt;
  &lt;/transition&gt;
&lt;/view-state&gt;

&lt;!-- 認証サブフローへ --&gt;
&lt;subflow-state id="authenticate" flow="account/authentication-sub-flow"&gt;
  &lt;transition on="authenticated" to="change"/&gt;
&lt;/subflow-state&gt;

&lt;!-- メールアドレス変更処理 --&gt;
&lt;action-state id="change"&gt;
  &lt;action bean="account.mailAddrChangeAction" method="changeMailAddrAndReissuePassword"/&gt;
  &lt;transition on="success" to="mailSend"/&gt;
  &lt;transition on-exception="org.unitedfront2.domain.MailAddrUsedByOtherException" to="form"/&gt;
&lt;/action-state&gt;

&lt;!-- e メールの送信 --&gt;
&lt;action-state id="mailSend"&gt;
  &lt;action bean="account.mailAddrChangeAction" method="sendMail"/&gt;
  &lt;transition on="success" to="finish"/&gt;
&lt;/action-state&gt;

&lt;!-- メールアドレス変更完了画面 --&gt;
&lt;end-state id="finish" view="account.MailAddrChangeSuccess"/&gt;
</pre>
          <p>
この Web Flow を <a href="http://springide.org/blog/">Spring IDE</a> を使って図示すると
次のようになります。
          </p>
          <div><img src="images/mailAddrChange-flow.png" alt="メールアドレス変更の画面遷移"/></div>
        </div>
      </subsection>
    </section>
    <section name="URL">
      <p>
URL は WEB-INF/flows フォルダの階層とフロー定義ファイル名で決まります。<br/>
WEB-INF/flows/<strong>account</strong>/<strong>mailAddrChange</strong>-flow.xml
に配置されているメールアドレス変更画面遷移は次の URL になります。
      </p>
<source>
http://HOST_NAME/unitedfront2/<strong>account</strong>/<strong>mailAddrChange</strong>.html
</source>
      <p>
例外として、*-sub-flow.xml という名前のフロー定義ファイルはサブフローとみなされ、URL から直接アクセスす
ることはできないようになっています。
      </p>
      <div class="info">
        <h5>Note: URL の命名</h5>
        <p>
URL は mailAddrChange.html とすべきでしょうか？それとも changeMailAddr.html とすべきでしょうか
？前者は単語、後者は動詞を表現しているように思えます。URL - Uniform <strong>Resource</strong>
Locator - は「リソースを指すもの」という考えから、United Front 2 では前者を採用しました。もしこの URL
がメールアドレスに関して包括的に扱うページなら、単に mailAddr.html としても良いかもしれません。
        </p>
      </div>
      <div class="info">
        <h5>Note: URL 生成の実装</h5>
        <p>
URL の仕組みは United Front 2 の独自クラス <a href="apidocs/org/unitedfront2/web/flow/HierarchyXmlFlowRegistryFactoryBean.html"><code>HierarchyXmlFlowRegistryFactoryBean</code></a>
と <a href="apidocs/org/unitedfront2/web/flow/UriFlowExecutorArgumentHandler.html"><code>UriFlowExecutorArgumentHandler</code></a>
を使って実現しています。
        </p>
      </div>
      <p>
資源への識別子はパラメータではなく URL 本文に埋め込んでいます。ここでいう資源とは、<a href="apidocs/org/unitedfront2/domain/accesscontrol/Resource.html"><code>Resource</code></a>
インターフェースを実装したドメインオブジェクトのことです。例えば、プロフィールへの URL はパラメータを用いて通常①
のように表現できますが、United Front 2 では基本的に②のようにパラメータを埋め込んだ URL を使うようにし
ています。
      </p>
<source>
① http://HOST_NAME/unitedfront2/profile/view.html?userCode=${userCode}
</source>
<source>
② http://HOST_NAME/unitedfront2/profile/${userCode}/index.html
</source>
      <p>
これによって、各資源へクエリなしでアクセスできるようになります。この実装は
<a href="http://tuckey.org/urlrewrite/">UrlRewriteFilter</a> を使っています。設定ファイ
ル
<a href="http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi/trunk/src/main/webapp/WEB-INF/urlrewrite.xml?root=unitedfront2&amp;view=markup">urlrewrite.xml</a>
に次のように記述するだけで簡単に実装できます。
      </p>
<pre name="code" class="xml">
&lt;rule&gt;
  &lt;from&gt;profile/([a-zA-Z0-9]+)/index\.html&lt;/from&gt;
  &lt;to&gt;profile/view.html?userCode=$1&lt;/to&gt;
&lt;/rule&gt;
</pre>
        <p>
なお、ディレクトリを直接参照した際には index.html ファイルへリダイレクトします。
        </p>
      <div class="info">
        <h5>Note</h5>
        <p>
このルールは、ブラウザのアドレスバーに表示される - つまりユーザが認識できる - URL にのみ適用しています。
例えば、アクセスした後、他の URL にリダイレクトするような一時的に使われるだけの URL にはこのルールを適用し
ていません。
        </p>
      </div>
    </section>
    <section name="タイトル">
      <p>
HTML の <code>TITLE</code> タグは、<a
href="apidocs/org/unitedfront2/web/handler/TitleInterceptor.html"><code>TitleInterceptor</code></a>
によってビュー名 - ビュー層の項で説明する Tiles 定義で属性 <code>name</code> に設定される値 - と一
致するメッセージコードのメッセージが選択されます。ただしこれはデフォルトの挙動で、コントローラ内でタイトルを変更
することも可能です。
      </p>
<pre name="code" class="java">
RequestContext context..
context.getRequestScope().put(
        TitleInterceptor.TITLE_CODE_PARAM_NAME, "message.code");
context.getRequestScope().put(
        TitleInterceptor.TITLE_ARGS_PARAM_NAME, new Object[] {"argument"});
</pre>
    </section>
    <section id="security" name="セキュリティ">
      <p>
システムロールのアクセス制御を <a href="http://static.springframework.org/spring-security/site/index.html">Spring Security</a>
を使って実装しています。システムロールとは、アカウントの認証や管理などのシステム運用上必要となる権限のことで
す。細かな承認処理に対するアクセス制御は各アクションクラスで実装します。システムロールには次の３種類が存在
します。
      </p>
      <div class="smaller">
        <table>
          <tr>
            <th>ロール名</th>
            <th>説明</th>
          </tr>
          <tr>
            <td><code>USER_ROLE</code></td>
            <td>アカウントを保持する一般ユーザ。</td>
          </tr>
          <tr>
            <td><code>ADMIN_ROLE</code></td>
            <td>システム管理者。</td>
          </tr>
          <tr>
            <td><code>ROLE_ANONYMOUS</code></td>
            <td>アカウントを持っていないか、持っていてもログインしていないユーザ。</td>
          </tr>
        </table>
      </div>
      <p>
このアクセス制御では、ユーザからのアクセスを URL レベルで制御できます。デフォルトの設定では、全ての HTML
ファイルは <code>ROLE_USER</code> からのみのアクセスを許可しています。必要に応じて設定ファイル <a href="http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi/trunk/src/main/webapp/WEB-INF/applicationContext-security.xml?root=unitedfront2&amp;view=markup">applicationContext-security.xml</a>
に定義されている <code>filterInvocationInterceptor</code> Bean のプロパティを編集します。次
の例では、URL '/informationUpdate.html' に対するアクセスをシステム管理者のみに制限しています。
      </p>
<pre name="code" class="xml">
&lt;bean id="filterInvocationInterceptor"
    class="org.springframework.security.intercept.web.FilterSecurityInterceptor"&gt;
  &lt;property name="authenticationManager" ref="authenticationManager"/&gt;
  &lt;property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/&gt;
  &lt;property name="objectDefinitionSource"&gt;
    &lt;security:filter-invocation-definition-source&gt;

      &lt;!-- ... --&gt;

      &lt;security:intercept-url pattern="/informationUpdate.html" access="ROLE_ADMIN"/&gt;

      &lt;!-- ... --&gt;

      &lt;security:intercept-url pattern="/**" access="ROLE_USER"/&gt;
    &lt;/security:filter-invocation-definition-source&gt;
  &lt;/property&gt;
&lt;/bean&gt;
</pre>
      <div class="info">
        <h5>Note: 匿名ユーザからの不正アクセス</h5>
        <p>
この設定では、匿名ユーザによる不正な HTML ファイルのアクセスは「アクセス拒否」となります。存在しない HTML
ファイルにアクセスした際も「アクセス拒否」扱いとなります。このとき、「アクセス拒否」ページではなく、トップページへ
遷移しますが、これは Spring Security のデフォルトの動作になります。
        </p>
      </div>
    </section>
    <section name="エラーページ">
      <p>
「Page Not Found」や「Internal Server Error」といったページに遷移させたい場合、アクションクラスで指
定された例外を発生させることで簡単に実現できます。例外の対応表を次に示します。
      </p>
      <div class="smaller">
        <table>
          <tr>
            <th>エラー内容</th>
            <th>エラーコード</th>
            <th>例外</th>
          </tr>
          <tr>
            <td>リクエストが不正</td>
            <td>400</td>
            <td>
              <a href="apidocs/org/unitedfront2/web/BadRequestException.html"><code>org.unitedfront2.web.BadRequestException</code></a>,
              <a href="apidocs/org/unitedfront2/web/flow/BadRequestException.html"><code>org.unitedfront2.web.flow.BadRequestException</code></a>,
              <a href="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/web/bind/ServletRequestBindingException.html"><code>ServletRequestBindingException</code></a>,
              <a href="http://static.springframework.org/spring-webflow/docs/1.0.x/api-binding/org/springframework/binding/convert/ConversionException.html"><code>ConversionException</code></a>
            </td>
          </tr>
          <tr>
            <td>アクセス拒否</td>
            <td>403</td>
            <td>
              <a href="apidocs/org/unitedfront2/web/AccessDeniedException.html"><code>org.unitedfront2.web.AccessDeniedException</code></a>,
              <a href="apidocs/org/unitedfront2/web/flow/AccessDeniedException.html"><code>org.unitedfront2.web.flow.AccessDeniedException</code></a>
            </td>
          </tr>
          <tr>
            <td>ページが見つからない</td>
            <td>404</td>
            <td>
              <a href="apidocs/org/unitedfront2/web/PageNotFoundException.html"><code>org.unitedfront2.web.PageNotFoundException</code></a>,
              <a href="apidocs/org/unitedfront2/web/flow/PageNotFoundException.html"><code>org.unitedfront2.web.flow.PageNotFoundException</code></a>,
              <a href="http://static.springframework.org/spring-webflow/docs/1.0.x/api/org/springframework/webflow/definition/registry/NoSuchFlowDefinitionException.html"><code>NoSuchFlowDefinitionException</code></a>
            </td>
          </tr>
          <tr>
            <td>内部エラー</td>
            <td>500</td>
            <td>他の例外</td>
          </tr>
        </table>
      </div>
      <p>
United Front 2 が提供する例外クラスは <a href="apidocs/org/unitedfront2/web/flow/package-summary.html"><code>org.unitedfront2.web.flow</code></a>
および <a href="apidocs/org/unitedfront2/web/package-summary.html"><code>org.unitedfront2.web</code></a>
の二つのパッケージに存在します。アクションクラスで例外を発生する際は前者を、それ以外は後者のパッケージを利
用します。アクションクラスにおける例外処理のサンプルコードを次に示します。
      </p>
<pre name="code" class="java">
@Override
public Event doExecute(RequestContext context) throws PageNotFoundException {
    String code = context.getRequestParameters().get(codeParamName);
    String code = context.getRequestParameters().get("code");
    Blog blog = blogTable.findByCode(code);
    if (blog == null) {
        String message = "The blog [Code='" + code + "'] not found.";
        logger.warn(message);
        throw new PageNotFoundException(context, this, message);
    }

    // ...
}
</pre>
    </section>
    <section name="Tiles">
      <p>
<a href="http://tiles.apache.org/">Apache Tiles 2</a> の <a
href="http://tiles.apache.org/tutorial/advanced/preparer.html">View
Preparers</a> 機能を使って、画面の一部に小さな Web コントローラを設けることができます。
      </p>
      <subsection name="サンプルコード">
        <p>
公開中のプロフィールを、プロフィールウィジェットに渡す <a href="apidocs/org/unitedfront2/web/controller/profile/PublicProfileWidgetPreparer.html"><code>PublicProfileWidgetPreparer</code></a>
を示します。完全なコードは <a href="xref/org/unitedfront2/web/controller/profile/PublicProfileWidgetPreparer.html"><code>PublicProfileWidgetPreparer</code> のソースコード</a>
を参照ください。実際のコードでは、キャッシュを使ってデータアクセスを効率化しています。
        </p>
<pre name="code" class="java">
@Repository(value = "profile.publicProfileWidgetPreparer")
public class PublicProfileWidgetPreparer implements ViewPreparer {

    /** プロフィールテーブル */
    @Autowired
    private ProfileTable profileTable;

    @Override
    public void execute(TilesRequestContext tilesContext,
            AttributeContext attributeContext) throws PreparerException {
        attributeContext.putAttribute("users",
            new Attribute(profileTable.getPublicProfileOwners()));
    }
}
</pre>
      </subsection>
    </section>
    <section name="RSS">
      <p>
RSS の実装には <a href="https://rome.dev.java.net/">Rome</a> を利用しています。RSS のコン
トローラは Spring によって管理されますが、Web Flow ではなく、Spring MVC のコントローラとして実装しま
す。
      </p>
      <p>
サンプルコードとして、ブログの RSS 用コントローラ <a href="apidocs/org/unitedfront2/web/controller/blog/RssController.html"><code>RssController</code></a>
の一部を紹介します。このコントローラでは、取得したブログドメインオブジェクトからフィードを生成し、ビューへ転送して
います。フィードタイプやエンコードはビュー側で設定されます。また、<code>setLink</code> に設定している
URL はプロトコル、ホスト名、コンテキスト名が設定されていませんが、これらもビュー側で正しく設定されるためここで
は設定不要です。ビューは RSS 専用の <a href="apidocs/org/unitedfront2/web/view/RssView.html"><code>RssView</code></a>
です。<code>RssController</code> の完全なコードは  <a href="xref/org/unitedfront2/web/controller/blog/RssController.html"><code>RssController</code> のソースコード</a>
を参照してください。
      </p>
<pre name="code" class="java">
@Repository(value = "blog.rssController")
public class RssController extends AbstractController {

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        Blog blog = getBlog(request);
        SyndFeed feed = toFeed(blog, WebUtils.getLocale(request));
        ModelAndView mav = new ModelAndView(new RssView());
        mav.addObject(RssView.FEED_PARAM_NAME, feed);
        return mav;
    }

    private Blog getBlog(HttpServletRequest request) {
        // ...
    }

    private SyndFeed toFeed(Blog blog, Locale locale) {
        SyndFeed feed = new SyndFeedImpl();

        // 概要
        feed.setTitle(blog.getOverview().getSubject(locale));
        feed.setLink("/blog/" + blog.getCode() + "/index.html");
        feed.setDescription(blog.getOverview().getBody(locale));
        feed.setAuthor(HtmlUtils.htmlEscape(blog.getOwner().getName()));

        // 記事
        List&lt;SyndEntry&gt; entries
            = new ArrayList&lt;SyndEntry&gt;(blog.getEntries().size());
        for (BlogEntry be : blog.getEntries()) {
            SyndEntry entry = new SyndEntryImpl();
            entry.setTitle(be.getEntry().getSubject(locale));
            entry.setLink("/blog/" + blog.getCode() + "/entry-"
                    + be.getCode() + ".html");
            SyndContent description = new SyndContentImpl();
            description.setType("text/html");
            description.setValue(be.getEntry().getBody(locale));
            entry.setDescription(description);
            entry.setPublishedDate(be.getEntry().getRegistrationDate());
            entry.setUpdatedDate(be.getEntry().getLastUpdateDate());
            entries.add(entry);
        }
        feed.setEntries(entries);
        return feed;
    }
}
</pre>
      <p>
RSS を保持するページでは、RSS への参照を <code>HEAD</code> タグ内の <code>LINK</code> タグで
設定する必要があります。これには、対象ページのコントローラで RSS への参照を保持する <code>_feedUrl</code>
変数を定義します。
      </p>
<pre name="code" class="java">
@Repository(value = "blog.viewAction")
public class ViewAction extends AbstractAction {

    @Override
    protected Event doExecute(RequestContext context) {

        // ...

        context.getRequestScope().put("_feedUrl", "/blog/" + blog.getCode()
            + "/index.xml");
        return success();
    }
}
</pre>
      <p>
最後に、<a href="http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi/trunk/src/main/webapp/WEB-INF/applicationContext-servlet.xml?root=unitedfront2&amp;view=markup">applicationContext-servlet.xml</a>
にコントローラと URL をマッピングします。
      </p>
<pre name="code" class="xml">
&lt;bean id="urlMapping"
    class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt;

  &lt;!-- ... --&gt;

  &lt;property name="mappings"&gt;
    &lt;props&gt;
      &lt;prop key="/**/*.html"&gt;flowController&lt;/prop&gt;
      &lt;prop key="/blog/view.xml"&gt;blog.rssController&lt;/prop&gt;
    &lt;/props&gt;
  &lt;/property&gt;
&lt;/bean&gt;
</pre>

<script type="text/javascript" src="js/dp.SyntaxHighlighter/Scripts/shCore.js"></script>
<script type="text/javascript" src="js/dp.SyntaxHighlighter/Scripts/shBrushJava.js"></script>
<script type="text/javascript" src="js/dp.SyntaxHighlighter/Scripts/shBrushXml.js"></script>
<script type="text/javascript">
dp.SyntaxHighlighter.ClipboardSwf = 'js/dp.SyntaxHighlighter/Scripts/clipboard.swf';
dp.SyntaxHighlighter.HighlightAll('code');
</script>

<script type="text/javascript">
var ID='100354378-controller';
var AD=1;
var FRAME=0;
</script>
<script src="http://j1.ax.xrea.com/l.j?id=100354378" type="text/javascript"></script>
<noscript>
<a href="http://w1.ax.xrea.com/c.f?id=100354378" target="_blank"><img src="http://w1.ax.xrea.com/l.f?id=100354378&amp;url=X" alt="AX" border="0"/></a>
</noscript>

    </section>
  </body>
</document>
