2.5.4. Strutsのサンプル

2.5.4.1. 実行手順

  1. サンプルプロジェクト struts-sample.zip をインポートします。
  2. 右クリック > サーバで実行 を選択します。
  3. http://Webサーバ名(ドメイン省略不可):ポート番号/struts-sample/ にアクセスします。

2.5.4.2. StrutsによるWebアプリケーション

フレームワーク

フレームワークは、Webアプリケーションを作成する上で必要となる共通的な機能や構造を提供します。 アプリケーションの共通的なメイン部分が提供されており、開発者はアプリケーション固有のロジックをフレームワークに組み込むことで、Webアプリケーションを作成することができます。


図2.5.4.2-1

フレームワークは、Web アプリケーションの画面制御や、エラーのハンドリングをしてくれるため、Webアプリケーションの開発工数を削減できます。 また、フレームワークに沿って、開発したアプリケーションは再利用性が高まります。

「MVCモデル2」Web アプリケーションのスケルトンです。 MVCモデル2とは下記のMVCとモデル2の考え方を組み合わせた物として提案されています。


図2.5.4.2-2

Struts 2の仕組み

Struts 2は定義ファイル(struts.xml)を設定することで、リクエストによる処理の振り分け、画面遷移の制御等を行います。

Struts 2には以下の主要機能があります。
※ Modelに当たる処理はStrutsより制御できるようにStrutsの用意した特定クラスを継承する必要があります。 継承するクラスはアプリケーションクラスを作成するためのActionSupportクラス等があります。

2.5.4.3. StrutsによるWebアプリケーションの開発

開発の流れ
サンプルWebアプリケーション

Strutsを使用したサンプルアプリケーション(struts-sample)の開発手順を記述します。

1. シナリオ作成

Strutsを用いたサンプルWebアプリケーションを作成します。

サンプルの処理概要は

2. 処理概要をMVCに当てはめる


図2.5.4.3-1

※ MVCのC(Controller)に当たる処理は定義ファイルを元にStrutsが行います。 ※ 表示データ編集処理は同一のものです。

サンプルの処理概要を3つの処理(A,B,C)に分けてMVCモデルに当てはめていきます。

ログオン処理(A)

注文データ入力処理(B)

注文データDB登録処理(C)

3. 各処理部品の概要

MVCに当てはめた各部品を作成していきます。

サンプルWebアプリケーションのファイル構成は次のようになります。

/struts-sample
|-- logon.jsp ログオン画面
|-- order.jsp 発注画面
|-- orderlist.jsp 発注一覧表示画面
|-- entryEnd.jsp 発注完了画面
|-- entryResult.jsp 発注結果表示画面
|-- index.html 初期表示画面(ログオン画面を呼び出します)
|-- /WEB-INF
|-- web.xml WebAPの定義ファイル
|-- nec-web.xml WebOTX固有WebAPの定義ファイル
|-- /lib
|-- /struts2-core-*.jar Struts本体
|-- *.jar 他の必要ライブラリ
|--/classes
|--/struts.xml Strutsの定義ファイル
|--/jp/co/nec/WebOTX/StrutsSample
|-- DBOrderData.class 発注データDB登録処理
|-- EditShowData.class 表示データ編集処理
|-- LogonAction.class ログオンAction
|-- OrderAction.class 発注Action
|-- ShowAction.class データ表示Action
|-- ApplicationResources.properties 文字列リソースファイル(英語)
|-- ApplicationResources_ja.properties 文字列リソースファイル(日本語)
|-- /dbmng
|-- index.html DBのテーブル作成/データ設定/削除/表示処理へのリンク
|-- dbenvset.jsp DB接続を設定する。
|-- dbtbladd.jsp DBにサンプルで使用するテーブルを作成する。
|-- dbtbldel.jsp 作成したテーブルを削除する。
|-- dbtblset.jsp 作成したテーブルに初期データを設定する。
|-- dbtblview.jsp DBより在庫データ、発注データを表示する。

サンプルWebアプリケーションの処理概要図は以下の通りです。


図2.5.4.3-2

画面の作成
1. 初期表示画面


図2.5.4.3-3

1) StrutsSampleの初期表示画面です。

2) 「ログオン画面へ」を選択するとログオン画面に遷移します。

2. ログオン画面


図2.5.4.3-4

1) サンプル実行時に起動される画面で、ユーザ名、パスワードを入力します。

表2.5.4.3-1
ユーザ名 パスワード
User_1 Pass_1
User_2 Pass_2

2) 「発注開始」ボタンをクリックすると、ログオンAction(LogonAction.class)にリクエストを送信します。

3) 「発注中止」ボタンをクリックすると、発注処理終了画面(entryEnd.jsp)に遷移し発注処理を中断します。

4) 使用しているStrutsの機能

<s:actionerror>タグを使用しエラーメッセージを表示した場合の画面を次に示します。


図2.5.4.3-5

ログオン画面(logon.jsp)のソースファイルを次に表示します。

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<html>
<head>
<title><s:text name="logon.wtitle" /></title>
</head>
<body bgcolor="#B0FFB0">
    <s:actionerror cssStyle="color: red" />
    <br>
    <br>
    <DIV
        style="background-color: #363562; width: 90%; border-style: outset"
        align=center>
        <FONT size=42 color=white face="arial"><s:text
                name="system.title" /></FONT>
    </DIV>
    <s:form name="form1" action="logon" validate="false" method="POST">
        <center>
            <div align="center">
                <table style="width: 450;">
                    <tr>
                        <td COLSPAN="2" align="left"><strong><s:text
                                    name="word.user" /></strong>/<strong><s:text name="word.pass" /></strong>
                            <s:text name="logon.message1" /></td>
                    </tr>
                    <s:textfield tabindex="1" label="%{getText('word.user')}"
                        name="username"></s:textfield>
                    <s:textfield tabindex="2" label="%{getText('word.pass')}"
                        name="password"></s:textfield>
                    <tr>
                        <td style="text-align: left;" COLSPAN="2" valign="top" nowrap><s:submit
                                value="%{getText('logon.button1')}" /></td>
                    </tr>
                </table>
            </div>
        </center>
    </s:form>
    <s:form name="form2" action="entryEnd.jsp" method="POST">
        <div align="right">
            <s:submit align="right" value="%{getText('logon.button2')}" />
        </div>
    </s:form>

    <hr>
</body>
</html>
3. 発注画面


図2.5.4.3-6

1) ログオンAction(LogonAction.class)で生成されたログオン情報、表示データを元に画面を表示します。

2) 「Next/Before Page」ボタンをクリックすると、次/前ページの表示をデータ表示Action(ShowAction.class)にリクエストします。

3) 注文数に値が入力された場合、注文数(注文データ)の保存をデータ表示Action(ShowAction.class)にリクエストします。

4) 「注文状況一覧」ボタンをクリックすると、注文データ一覧の表示をデータ表示Action(ShowAction.class)にリクエストします。

5) 「発注を行います」ボタンをクリックすると、発注のリクエストを発注Action処理(OrderAction.class)に送信します。

6) 「発注中止ボタン」をクリックすると、発注処理終了画面(entryEnd.jsp)に遷移し発注処理を中断します。

7) 使用しているStrutsの機能

発注画面(order.jsp)のソースファイルを次に表示します。

<%@ page import="java.util.Hashtable"
    contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<html>
<head>
<title><s:text name="order.wtitle" /></title>
<SCRIPT type="text/javascript">
    function fncchange(f) {
        f.submit();
    }
</SCRIPT>
</head>
<body bgcolor="#B0FFB0">
    <s:actionerror cssStyle="color: red" />
    <br>
    <br>
    <div
        style="background-color: #363562; width: 90%; border-style: outset"
        align=center>
        <font size=42 color=white face="arial"><s:text
                name="system.title" /></font>
    </div>
    <br>
    <%
        boolean errChk = false;
        String _shop = null;
        String _clerk = null;
        String _orderno = null;

        String[] logonInfo = (String[]) pageContext.getAttribute(
                "AttrLogOnInfo", PageContext.SESSION_SCOPE);
        if (logonInfo == null) {
            errChk = true;
        } else {
            _shop = logonInfo[0];
            _clerk = logonInfo[1];
            _orderno = logonInfo[2];
        }
        String[] _showproduct = (String[]) pageContext.getAttribute(
                "AttrShowProduct", PageContext.SESSION_SCOPE);
        String[] _showprodname = (String[]) pageContext.getAttribute(
                "AttrShowProdName", PageContext.SESSION_SCOPE);
        Long[] _showprice = (Long[]) pageContext.getAttribute(
                "AttrShowPrice", PageContext.SESSION_SCOPE);
        Long[] _showstoks = (Long[]) pageContext.getAttribute(
                "AttrShowStoks", PageContext.SESSION_SCOPE);
        Hashtable<String, Integer> _orderdata = (Hashtable<String, Integer>) pageContext
                .getAttribute("AttrOrderData", PageContext.SESSION_SCOPE);
        if (_showproduct == null || _showprodname == null
                || _showprice == null || _showstoks == null
                || _orderdata == null) {
            errChk = true;
        }
    %>
    <s:if test="%{#request.errChk}">
        <div align="center">
            <s:text name="error.system.paramerr" />
        </div>
    </s:if>
    <s:else>
        <div align="center">
            <table style="width: 678px; border: 0px;">
                <tr>
                    <td width="10%" nowrap><small><strong><s:text
                                    name="word.orderno" /></strong></small></td>
                    <td width="90%"><small><strong>:</strong><%=_orderno%></small></td>
                </tr>
                <tr>
                    <td width="10%" nowrap><small><strong><s:text
                                    name="word.branch" /></strong></small></td>
                    <td width="90%"><small><strong>:</strong><%=_shop%></small></td>
                </tr>
                <tr>
                    <td width="10%" nowrap><small><strong><s:text
                                    name="word.charge" /></strong></small></td>
                    <td width="90%"><small><strong>:</strong><%=_clerk%></small></td>
                </tr>
            </table>
            <br>
            <table style="width: 678px; border: 0px;">
                <tr>
                    <s:form name="orderform1" method="POST" action="show"
                        theme="simple">
                        <td width="70%" nowrap><input type="submit"
                            value="&lt;&lt; Before Page"> <s:hidden name="reqKind"
                                value="BEFOR"></s:hidden></td>
                    </s:form>
                    <s:form name="orderform2" method="POST" action="show"
                        theme="simple">
                        <td width="30%" nowrap><input type="submit"
                            value="Next Page    &gt;&gt;"> <s:hidden name="reqKind"
                                value="NEXT"></s:hidden></td>
                    </s:form>
                </tr>
                <tr>
                    <td COLSPAN="2" width="670">
                        <table style="width: 100%; border: 0px;">
                            <tr>
                                <th nowrap width="20%" bgcolor="#FF8F20"><s:text
                                        name="word.product" /></th>
                                <th nowrap width="20%" bgcolor="#FF8F20"><s:text
                                        name="word.prdname" /></th>
                                <th nowrap width="15%" bgcolor="#FF8F20"><s:text
                                        name="word.price" /></th>
                                <th nowrap width="10%" bgcolor="#FF8F20"><s:text
                                        name="word.stoks" /></th>
                                <th nowrap width="10%" bgcolor="#FF8F20"><s:text
                                        name="word.ordernum" /></th>
                                <th nowrap width="15%" bgcolor="#FF8F20"><s:text
                                        name="word.subtotal" /></th>
                            </tr>
                            <s:iterator value="%{#session.AttrShowProduct}" var="objValue"
                                status="cnt">
                                <s:set var="prdid" value="objValue" scope="request"></s:set>
                                <s:if test="%{#session.AttrOrderData[#request.prdid]==null}">
                                    <s:set var="ordernum" value="0" scope="request"></s:set>
                                </s:if>
                                <s:else>
                                    <s:set var="ordernum"
                                        value="%{#session.AttrOrderData[#request.prdid]}"
                                        scope="request"></s:set>
                                </s:else>
                                <s:set var="price" value="#session.AttrShowPrice[#cnt.index]"></s:set>
                                <tr>
                                    <td nowrap width="20%" bgcolor="#FFE9D2" align="center"><s:property
                                            value="%{#request.prdid}" /></td>
                                    <td nowrap width="20%" bgcolor="#FFE9D2"><s:property
                                            value="%{#session.AttrShowProdName[#cnt.index]}" /></td>
                                    <td nowrap width="15%" bgcolor="#FFE9D2" align="right"><s:property
                                            value="%{#request.price}" /></td>
                                    <td nowrap width="10%" bgcolor="#FFE9D2" align="right"><s:property
                                            value="%{#session.AttrShowStoks[#cnt.index]}" /></td>
                                    <s:form name="orderform3" method="POST" action="show"
                                        theme="simple">
                                        <td nowrap width="10%" bgcolor="#FFE9D2">
                                            <div align="center">
                                                <s:textfield name="reqValue2" SIZE="3" align="right"
                                                    value="%{#request.ordernum}"
                                                    onChange="fncchange(this.form)"></s:textfield>
                                            </div>
                                        </td>
                                        <td nowrap width="15%" bgcolor="#FFE9D2" align="right"><s:property
                                                value="%{#request.ordernum * #request.price}" /></td>
                                        <td nowrap width="0%"><s:hidden name="reqKind"
                                                value="SETORDER"></s:hidden></td>
                                        <td nowrap width="0%"><s:hidden name="reqValue1"
                                                value="%{#request.prdid}"></s:hidden></td>
                                    </s:form>
                                </tr>
                            </s:iterator>
                        </table>
                    </td>
                </tr>
                <tr height="16">
                    <td></td>
                </tr>
                <tr>
                    <td COLSPAN="2">
                        <table style="width: 100%; border: 0px; height: 16px;">
                            <tr>
                                <td nowrap width="25%"><s:form name="orderform4"
                                        method="POST" action="order">
                                        <s:submit value="%{getText('order.button1')}" />
                                    </s:form></td>
                                <td nowrap width="75%" align="left"><s:form
                                        name="orderform5" method="POST" action="show">
                                        <s:submit value="%{getText('order.button2')}" />
                                        <s:hidden name="reqKind" value="ORDERLIST"></s:hidden>
                                    </s:form></td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </div>
    </s:else>
    <s:form name="form2" action="entryEnd.jsp" method="POST">
        <div align="right">
            <s:submit align="right" value="%{getText('logon.button2')}" />
        </div>
    </s:form>
    <hr align="center">
</body>
</html>
4. 発注一覧表示画面


図2.5.4.3-7

1) データ表示Action(ShowAction.class)で生成された一覧データを元に画面を表示します。

2) 「戻る」ボタンクリックでデータ表示Action(ShowAction.class)に発注画面表示をリクエストします。

3) 使用しているStruts機能

発注一覧表示画面(orderlist.jsp)のソースを次に表示します。

<%@ page import="java.util.Hashtable"
    contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<html>
<head>
<title><s:text name="order.wtitle" /></title>
<SCRIPT type="text/javascript">
    function fncchange(f) {
        f.submit();
    }
</SCRIPT>
</head>
<body bgcolor="#B0FFB0">
    <s:actionerror cssStyle="color: red" />
    <br>
    <br>
    <DIV
        style="background-color: #363562; width: 90%; border-style: outset"
        align=center>
        <font size=42 color=white face="arial"><s:text
                name="system.title" /></font>
    </DIV>
    <br>

    <%
        boolean errChk = false;
        String _shop = null;
        String _clerk = null;
        String _orderno = null;

        String[] logonInfo = (String[]) pageContext.getAttribute(
                "AttrLogOnInfo", PageContext.SESSION_SCOPE);
        if (logonInfo == null) {
            errChk = true;
        } else {
            _shop = logonInfo[0];
            _clerk = logonInfo[1];
            _orderno = logonInfo[2];
        }
        String[] _showproduct = (String[]) pageContext.getAttribute(
                "AttrShowProduct", PageContext.SESSION_SCOPE);
        String[] _showprodname = (String[]) pageContext.getAttribute(
                "AttrShowProdName", PageContext.SESSION_SCOPE);
        Long[] _showprice = (Long[]) pageContext.getAttribute(
                "AttrShowPrice", PageContext.SESSION_SCOPE);
        Long[] _showstoks = (Long[]) pageContext.getAttribute(
                "AttrShowStoks", PageContext.SESSION_SCOPE);
        Hashtable<String, Integer> _orderdata = (Hashtable<String, Integer>) pageContext
                .getAttribute("AttrOrderData", PageContext.SESSION_SCOPE);
        if (_showproduct == null || _showprodname == null
                || _showprice == null || _showstoks == null
                || _orderdata == null) {
            errChk = true;
        }
    %>
    <s:if test="%{#request.errChk}">
        <div align="center">
            <s:text name="error.system.paramerr" />
        </div>
        <s:form name="form1" action="entryEnd.jsp" method="POST">
            <div align="right">
                <input type="submit" value="%{getText('logon.button2')}" />
            </div>
        </s:form>
    </s:if>
    <s:else>
        <div align="center">
            <div align="center">
                <table style="border: 0px; width: 678px;">
                    <tr>
                        <td width="10%" nowrap><small><strong><s:text
                                        name="word.orderno" /></strong></small></td>
                        <td width="90%"><small><strong>:</strong><%=_orderno%></small></td>
                    </tr>
                    <tr>
                        <td width="10%" nowrap><small><strong><s:text
                                        name="word.branch" /></strong></small></td>
                        <td width="90%"><small><strong>:</strong><%=_shop%></small></td>
                    </tr>
                    <tr>
                        <td width="10%" nowrap><small><strong><s:text
                                        name="word.charge" /></strong></small></td>
                        <td width="90%"><small><strong>:</strong><%=_clerk%></small></td>
                    </tr>
                </table>
                <br>
                <table style="border: 0px; width: 678px;">
                    <tr>
                        <td COLSPAN="2" width="670">
                            <table style="border: 0px; width: 100%;">
                                <tr>
                                    <th nowrap width="20%" bgcolor="#FF8F20"><s:text
                                            name="word.product" /></th>
                                    <th nowrap width="20%" bgcolor="#FF8F20"><s:text
                                            name="word.prdname" /></th>
                                    <th nowrap width="15%" bgcolor="#FF8F20"><s:text
                                            name="word.price" /></th>
                                    <th nowrap width="10%" bgcolor="#FF8F20"><s:text
                                            name="word.stoks" /></th>
                                    <th nowrap width="10%" bgcolor="#FF8F20"><s:text
                                            name="word.ordernum" /></th>
                                    <th nowrap width="15%" bgcolor="#FF8F20"><s:text
                                            name="word.subtotal" /></th>
                                </tr>
                                <s:iterator value="%{#session.AttrShowProduct}" var="objValue"
                                    status="cnt">
                                    <s:set var="prdid" value="objValue" scope="request"></s:set>
                                    <s:if test="%{#session.AttrOrderData[#request.prdid]==null}">
                                        <s:set var="ordernum" value="0" scope="request"></s:set>
                                    </s:if>
                                    <s:else>
                                        <s:set var="ordernum"
                                            value="%{#session.AttrOrderData[#request.prdid]}"
                                            scope="request"></s:set>
                                    </s:else>
                                    <s:set var="price" value="#session.AttrShowPrice[#cnt.index]"></s:set>
                                    <tr>
                                        <td nowrap width="20%" bgcolor="#FFE9D2" align="center"><s:property
                                                value="%{#request.prdid}" /></td>
                                        <td nowrap width="20%" bgcolor="#FFE9D2"><s:property
                                                value="%{#session.AttrShowProdName[#cnt.index]}" /></td>
                                        <td nowrap width="15%" bgcolor="#FFE9D2" align="right"><s:property
                                                value="%{#request.price}" /></td>
                                        <td nowrap width="10%" bgcolor="#FFE9D2" align="right"><s:property
                                                value="%{#session.AttrShowStoks[#cnt.index]}" /></td>
                                        <td nowrap width="10%" bgcolor="#FFE9D2" align="right"><s:property
                                                value="%{#request.ordernum}" /></td>
                                        <td nowrap width="15%" bgcolor="#FFE9D2" align="right"><s:property
                                                value="%{#request.ordernum * #request.price}" /></td>
                                    </tr>
                                </s:iterator>
                            </table>
                        </td>
                    </tr>
                    <tr height="16">
                        <td></td>
                    </tr>
                    <tr>
                        <td COLSPAN="2">
                            <table style="border: 0px; width: 100%; height: 16px;">
                                <tr>
                                    <td nowrap width="75%" height="16" align="center"><s:form
                                            name="form13" action="show" method="POST">
                                            <s:submit value="%{getText('orderlist.button1')}" />
                                            <s:hidden name="reqKind" value="RESHOW"></s:hidden>
                                        </s:form></td>
                                </tr>
                            </table>
                        </td>
                    </tr>
                </table>
            </div>
        </div>
    </s:else>
    <br>
    <hr align="center">
</body>
</html>
5. 発注結果表示画面


図2.5.4.3-8

1) 発注に失敗したデータの一覧を表示します。

2) 「Order Page」ボタンをクリックするとデータ表示Action(ShowDataAction.class)に発注画面表示をリクエストし、処理を継続します。

3) 「EntryEnd Page」ボタンをクリックすると発注完了画面(entryEnd.jsp)に遷移します。

4) 使用しているStrutsの機能

発注結果表示画面(entryResult.jsp)のソースを次に表示します。

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ page import="java.util.*"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<html>
<head>
<title><s:text name="end.wtitle" /></title>
</head>
<body bgcolor="#B0FFB0">

    <DIV
        style="background-color: #363562; width: 90%; border-style: outset"
        align=center>
        <FONT size=42 color=white face="arial"><s:text
                name="system.title" /></FONT>
    </DIV>
    <br>
    <s:actionerror cssStyle="color: red" />

    <div style="">
        <table style="width: 678; border: 0px;">
            <tr>
                <td width="25%" height="18"></td>
                <td width="75%" height="18" align="right"></td>
            </tr>

            <tr>
                <td width="20%"></td>
                <td valign="top" width="80%" nowrap>
                    <table style="width: 100%; border: 0px; height: 16px;">
                        <tr>
                            <td nowrap width="35%" height="16"><s:form name="form1"
                                    method="POST" action="order.jsp" theme="simple">
                                    <s:submit value="Order Page" />
                                </s:form></td>
                            <td nowrap width="65%" height="16"><s:form name="form2"
                                    method="POST" action="entryEnd.jsp" theme="simple">
                                    <s:submit value="Entry End Page" />
                                </s:form></td>
                        </tr>
                    </table>
                </td>
            </tr>
        </table>
    </div>
    <hr>
</body>
</html>
6. 発注完了画面


図2.5.4.3-9

1) 発注処理に使用した一時データ(ログオン情報、注文データ等)を削除します。

2) 「LogOn Page」ボタンをクリックするとログオン画面(logon.jsp)に遷移します

3) 「Index Page」ボタンをクリックすると初期表示画面(index.html)に遷移します

4) 使用しているStrutsの機能

発注完了画面(entryEnd.jsp)のソースを次に表示します。

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<html>
<head>
<title><s:text name="end.wtitle" /></title>
</head>
<body bgcolor="#B0FFB0">
    <s:actionerror cssStyle="color: red" />
    <br>
    <br>
    <%
        // Attribute Info clear
        pageContext.removeAttribute("AttrLogOnInfo",
                PageContext.SESSION_SCOPE);
        pageContext.removeAttribute("AttrShowProduct",
                PageContext.SESSION_SCOPE);
        pageContext.removeAttribute("AttrShowProdName",
                PageContext.SESSION_SCOPE);
        pageContext.removeAttribute("AttrShowPrice",
                PageContext.SESSION_SCOPE);
        pageContext.removeAttribute("AttrShowStoks",
                PageContext.SESSION_SCOPE);
        pageContext.removeAttribute("AttrOrderData",
                PageContext.SESSION_SCOPE);
        pageContext.removeAttribute("AttrTotalRec",
                PageContext.SESSION_SCOPE);
        pageContext.removeAttribute("AttrNowPage",
                PageContext.SESSION_SCOPE);
    %>

    <DIV
        style="background-color: #363562; width: 90%; border-style: outset"
        align=center>
        <FONT size=42 color=white face="arial"><s:text
                name="system.title" /></FONT>
    </DIV>
    <br>
    <table style="width: 450; border: 0px; height: 184px;">
        <tr>
            <td width="20%" height="18"></td>
            <td width="80%" height="18" align="right"></td>
        </tr>

        <tr>
            <td></td>
            <td><s:text name="end.message1" /></td>
        </tr>

        <tr>
            <td width="20%"></td>
            <td valign="top" width="80%" nowrap>
                <table style="width: 100%; border: 0px; height: 16px;">
                    <tr>
                        <td nowrap width="35%" height="16"><s:form name="form1"
                                method="POST" action="logon.jsp" theme="simple">
                                <s:submit value="LogOn Page" />
                            </s:form></td>
                        <td nowrap width="65%" height="16"><s:form name="form2"
                                method="POST" action="index.html" theme="simple">
                                <s:submit value="Index Page" />
                            </s:form></td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>
    <hr>
</body>
</html>
アプリケーションクラスの作成

StrutsのServletで受信したリクエストの振り分け先としてActionSupportクラスを継承したアプリケーションクラスを作成します。

1. ログオンAction

1) ログオン画面で指定されたログオン情報を元に発注番号を生成、保存します。

2) 表示データ編集処理(EditShowData.class)にて発注画面(order.jsp)で表示するデータを生成します

3) 使用しているStrutsの機能

ログオンAction(LogonAction.class)のソースを次に表示します。

package jp.co.nec.WebOTX.StrutsSample;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.util.ServletContextAware;

import com.opensymphony.xwork2.ActionSupport;

public final class LogonAction extends ActionSupport implements SessionAware,
        ServletContextAware {

    private static final long serialVersionUID = 3268815902663739056L;

    // ----------------------------------------------------- Instance Variables
    private String username;
    private String password;
    private Map<String, Object> session;
    private ServletContext servletContext;

    // --------------------------------------------------------- Public Methods
    public String execute() throws Exception {

        String user = username;
        String pass = password;

        boolean inputerr = false;
        if ((username == null) || (username.length() < 1)) {
            addActionError(this.getText("error.username.required"));
            inputerr = true;
        }
        if ((password == null) || (password.length() < 1)) {
            addActionError(this.getText("error.password.required"));
            inputerr = true;
        }
        if (inputerr) {
            return "input";
        }

        String[] dbInfo = null; // DB接続情報
        String dbDriver = null; // JDBCドライバ名
        String dbUrl = null; // DBへのURL
        String dbUserid = null; // ユーザ名
        String dbPasswd = null; // パスワード

        dbInfo = (String[]) session.get("AttrDBInfo");
        if (dbInfo == null) {
            dbInfo = new String[4];

            dbInfo[0] = dbDriver = servletContext.getInitParameter("dbDriver");
            dbInfo[1] = dbUrl = servletContext.getInitParameter("dbURL");
            dbInfo[2] = dbUserid = servletContext.getInitParameter("dbUserId");
            dbInfo[3] = dbPasswd = servletContext
                    .getInitParameter("dbPassword");

            session.put("AttrDBInfo", dbInfo);
        } else {
            dbDriver = dbInfo[0];
            dbUrl = dbInfo[1];
            dbUserid = dbInfo[2];
            dbPasswd = dbInfo[3];
        }

        Connection conn = null;
        Statement stmt = null;
        ResultSet rset = null;

        // 在庫テーブルのコネクション生成
        try {
            Class.forName(dbDriver);
            conn = DriverManager.getConnection(dbUrl, dbUserid, dbPasswd);
            stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
        } catch (Exception e) { // SQLException / ClassNotFoundException /
                                // Exception
            try { // DB Objectクローズ
                if (stmt != null) {
                    stmt.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException se) {
            }
            throw new ServletException(e.toString());
        }

        Vector<String[]> UserInfo = new Vector<String[]>();
        try {
            String sqlStr = "SELECT * FROM WEBCONT_USERINFO";
            rset = stmt.executeQuery(sqlStr);
            for (; rset.next() == true;) {
                String userinfo[] = new String[3];
                userinfo[0] = rset.getString(1).trim();
                userinfo[1] = rset.getString(2).trim();
                userinfo[2] = rset.getString(3).trim();
                UserInfo.add(userinfo);
            }
            rset.close();
        } catch (Exception e) { // SQLException
            throw new ServletException(e.toString());
        }

        boolean boo = false;
        String logoninfo[] = new String[3];
        for (int cnt = 0; cnt < UserInfo.size(); cnt++) {
            String userinfo[] = (String[]) UserInfo.get(cnt);
            if (userinfo[0].equals(user) && userinfo[1].equals(pass)) {
                logoninfo[0] = userinfo[2];
                logoninfo[1] = userinfo[0];
                Timestamp times = new Timestamp(System.currentTimeMillis());
                DateFormat fmt = new SimpleDateFormat("yyyyMMddHHmmss");
                logoninfo[2] = userinfo[2] + "-" + userinfo[0] + "-"
                        + fmt.format(times);
                boo = true;
                session.put("AttrLogOnInfo", logoninfo);
            }
        }

        if (!boo) {
            addActionError(this.getText("error.logon.dberr",
                    new String[] { "logon error(user or pass)" }));
            return "input";
        }

        session.put("AttrOrderData", new Hashtable<String, Integer>());

        try {
            EditShowData edShowData = new EditShowData(servletContext, session);
            session.put("AttrNowPage", new Integer(1));
            edShowData.getShowData(session);
        } catch (IOException ie) {
            addActionError(getText("error.logon.dberr",
                    new String[] { ie.toString() }));
            return "input";
        }

        // Forward control to the specified success URI
        return "success";
    }

    /**
     * @return the username
     */
    public String getUsername() {
        return username;
    }

    /**
     * @param username
     *            the username to set
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }

    /**
     * @param password
     *            the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public void setSession(Map<String, Object> session) {
        this.session = session;
    }

    @Override
    public void setServletContext(ServletContext sc) {
        this.servletContext = sc;
    }
}
2. データ表示Action

1) 発注画面表示が要求された場合、表示ページ数を元に表示データ編集処理(EditShowData.class)にて表示データを生成します

2) 次/前ページの表示を要求された場合、表示ページ数を更新して表示データ編集処理(EditShowData.class)にて発注画面(order.jsp)表示データを生成します

3) 注文数が入力された場合、注文数を製品コードをキーに注文データとして保存します。また注文数に0が設定された場合、該当するデータを削除します

4) 注文状況一覧が入力された場合、表示データ編集処理(EditShowData.class)にて注文データを元に表示する一覧データを生成します

5) 使用しているStrutsの機能

データ表示Action(ShowDataAction.class)のソースを次に表示します。

package jp.co.nec.WebOTX.StrutsSample;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;

import javax.servlet.ServletContext;

import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.util.ServletContextAware;

import com.opensymphony.xwork2.ActionSupport;

public final class ShowAction extends ActionSupport implements SessionAware,
        ServletContextAware {

    private static final long serialVersionUID = -4254213027924588177L;

    // ----------------------------------------------------- Instance Variables
    private Map<String, Object> session;
    private ServletContext servletContext;
    private String reqKind;
    private String reqValue1;
    private String reqValue2;

    // --------------------------------------------------------- Public Methods
    public String execute() throws Exception {

        if (reqKind.equals("SETORDER")) {
            Integer objInteger = null;

            if (reqValue1 == null || reqValue2 == null) {
                addActionError(getText("error.show.paramerr", new String[] {
                        reqValue1, reqValue2 }));
                return "input";
            }

            try {
                objInteger = new Integer(reqValue2);
            } catch (Exception e) {
                addActionError(getText("error.show.paramerr",
                        new String[] { reqValue2 }));
                return "input";
            }

            Hashtable<String, Integer> orderData = (Hashtable<String, Integer>) session
                    .get("AttrOrderData");
            if (orderData == null) {
                orderData = new Hashtable<String, Integer>();
            }

            if (objInteger.intValue() == 0) {
                orderData.remove(reqValue1);
            } else {
                orderData.put(reqValue1, objInteger);
            }
            session.put("AttrOrderData", orderData);
        } else if (reqKind.equals("NEXT")) {
            Integer nowPage = (Integer) session.get("AttrNowPage");
            Long totalRec = (Long) session.get("AttrTotalRec");
            int nowRec = ((nowPage.intValue() - 1) * 5) + 1;
            if ((nowRec + 5) <= totalRec.intValue()) {
                // 次のページに表示するデータ有
                nowPage = new Integer(nowPage.intValue() + 1);
                // 表示ページ数更新
                session.put("AttrNowPage", nowPage);
            }

            try {
                EditShowData edShowData = new EditShowData(servletContext,
                        session);
                edShowData.getShowData(session);
            } catch (IOException ie) {
                addActionError(getText("error.show.dberr",
                        new String[] { ie.toString() }));
                return "input";
            }
        } else if (reqKind.equals("BEFOR")) {
            Integer objInteger = (Integer) session.get("AttrNowPage");
            int nowPage = objInteger.intValue();
            if ((nowPage - 1) >= 1) {
                // 戻るページ有
                nowPage = nowPage - 1;
                // 表示ページ数更新
                session.put("AttrNowPage", new Integer(nowPage));
            }

            try {
                EditShowData edShowData = new EditShowData(servletContext,
                        session);
                edShowData.getShowData(session);
            } catch (IOException ie) {
                addActionError(getText("error.show.dberr",
                        new String[] { ie.toString() }));
                return "input";
            }
        } else if (reqKind.equals("ORDERLIST")) {
            try {
                EditShowData edShowData = new EditShowData(servletContext,
                        session);
                edShowData.getListData(session);
            } catch (IOException ie) {
                addActionError(getText("error.show.dberr",
                        new String[] { ie.toString() }));
                return "input";
            }

            // 一覧表示画面へ
            return "orderlist";
        } else if (reqKind.equals("RESHOW")) {
            try {
                EditShowData edShowData = new EditShowData(servletContext,
                        session);
                edShowData.getShowData(session);
            } catch (IOException ie) {
                addActionError(getText("error.show.dberr",
                        new String[] { ie.toString() }));
                return "input";
            }
        } else {
            addActionError(getText("error.show.kinderr",
                    new String[] { reqKind }));
            return "input";
        }

        // Forward control to the specified success URI
        return "success";
    }

    @Override
    public void setSession(Map<String, Object> session) {
        this.session = session;
    }

    @Override
    public void setServletContext(ServletContext sc) {
        this.servletContext = sc;
    }

    /**
     * @param reqKind
     *            the reqKind to set
     */
    public void setReqKind(String reqKind) {
        this.reqKind = reqKind;
    }

    /**
     * @param reqValue1
     *            the reqValue1 to set
     */
    public void setReqValue1(String reqValue1) {
        this.reqValue1 = reqValue1;
    }

    /**
     * @param reqValue2
     *            the reqValue2 to set
     */
    public void setReqValue2(String reqValue2) {
        this.reqValue2 = reqValue2;
    }
}
3. 発注処理Action

1) 注文データを発注データDB登録処理(DBOrderData.class)にてデータベースに登録します。

2) 発注処理が正常に終了した場合表示する画面を発注終了画面(entryEnd.jsp)に遷移します。 正常に終了しないデータがあった場合ActionErrorオブジェクトにエラーになった商品データ一覧を作成し、発注結果表示画面(entryResult.jsp)に遷移します。

3) 使用しているStrutsの機能

発注処理Action(OrderAction.class)のソースを次に表示します。

package jp.co.nec.WebOTX.StrutsSample;

import java.util.Enumeration;
import java.util.Map;

import javax.servlet.ServletContext;

import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.util.ServletContextAware;

import com.opensymphony.xwork2.ActionSupport;

public final class OrderAction extends ActionSupport implements SessionAware,
        ServletContextAware {

    private static final long serialVersionUID = -6234434700793404880L;

    // ----------------------------------------------------- Instance Variables
    private Map<String, Object> session;
    private ServletContext servletContext;

    // --------------------------------------------------------- Public Methods
    public String execute() throws Exception {

        try {
            DBOrderData dbOrder = new DBOrderData(servletContext, session);
            dbOrder.errorData.clear();
            dbOrder.entryData(session);

            if (dbOrder.errorData.size() > 0) {
                session.put("AttrOrderData", dbOrder.errorData);
                Enumeration<String> enumeration = dbOrder.errorData.keys();
                for (; enumeration.hasMoreElements();) {
                    String keyname = enumeration.nextElement();
                    Integer ordernum = dbOrder.errorData.get(keyname);

                    addActionError(getText("error.order.orderNum",
                            new String[] { keyname, String.valueOf(ordernum) }));
                }
                return "result";
            }
        } catch (Exception e) {
            addActionError(getText("error.order.dberr",
                    new String[] { e.toString() }));
            return "end";
        }

        // Forward control to the specified success URI
        return "end";
    }

    @Override
    public void setSession(Map<String, Object> session) {
        this.session = session;
    }

    @Override
    public void setServletContext(ServletContext sc) {
        this.servletContext = sc;
    }
}
ビジネスロジックの作成
1. 表示データ編集処理

1) 呼び出し元で指定されたページ数を元に発注画面(order.jsp)に表示するデータを生成、保存します。

2) 注文データを元に注文状況一覧画面(orderlist.jsp)に表示するデータ一覧を生成、保存します。

表示データ編集処理(EditShowData.class)のソースを次に表示します。

package jp.co.nec.WebOTX.StrutsSample;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Map;

import javax.servlet.ServletContext;

public final class EditShowData {

    // ----------------------------------------------------- Instance Variables
    String[] dbInfo = null; // DB接続情報
    String dbDriver = null; // JDBCドライバ名
    String dbUrl = null; // DBへのURL
    String dbUserid = null; // ユーザ名
    String dbPasswd = null; // パスワード

    public EditShowData(ServletContext servcon, Map<String, Object> session)
            throws IOException {

        initDBInfo(servcon, session);
    }

    // --------------------------------------------------------- Public Methods
    public void initDBInfo(ServletContext servcon, Map<String, Object> session)
            throws IOException {

        Connection conn = null;
        Statement stmt = null;
        ResultSet rset = null;

        // DB情報の取得
        dbInfo = (String[]) session.get("AttrDBInfo");
        if (dbInfo == null) {
            dbInfo = new String[4];

            dbInfo[0] = dbDriver = servcon.getInitParameter("dbDriver");
            dbInfo[1] = dbUrl = servcon.getInitParameter("dbURL");
            dbInfo[2] = dbUserid = servcon.getInitParameter("dbUserId");
            dbInfo[3] = dbPasswd = servcon.getInitParameter("dbPassword");
            session.put("AttrDBInfo", dbInfo);
        } else {
            dbDriver = dbInfo[0];
            dbUrl = dbInfo[1];
            dbUserid = dbInfo[2];
            dbPasswd = dbInfo[3];
        }

        Long totalRec = (Long) session.get("AttrTotalRec");
        if (totalRec != null) {
            return;
        }

        // 在庫テーブルのコネクション生成
        try {
            Class.forName(dbDriver);
            conn = DriverManager.getConnection(dbUrl, dbUserid, dbPasswd);
            stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
        } catch (Exception e) { // SQLException / ClassNotFound / Exception
            try { // DB Objectクローズ
                if (stmt != null) {
                    stmt.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException se) {
            }
            throw new IOException(e.toString());
        }

        try {
            // 在庫テーブルのレコード数抽出
            rset = stmt.executeQuery("SELECT COUNT(*) from WEBCONT_WAREHOUSE");
            rset.next();
            long recNum = rset.getLong(1);
            session.put("AttrTotalRec", new Long(recNum));
        } catch (SQLException e) {
            throw new IOException(e.toString());
        } finally {
            try {
                // DB Objectクローズ
                rset.close();
                stmt.close();
                conn.close();
            } catch (SQLException se) {
            }
        }
    }

    public void getShowData(Map<String, Object> session) throws IOException {

        Connection conn = null;
        Statement stmt = null;
        ResultSet rset = null;

        // 在庫テーブルのコネクション生成
        try {
            Class.forName(dbDriver);
            conn = DriverManager.getConnection(dbUrl, dbUserid, dbPasswd);
            stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
        } catch (Exception e) { // SQLException / ClassNotFound / Exception
            try { // DB Objectクローズ
                if (stmt != null) {
                    stmt.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException se) {
            }
            throw new IOException(e.toString());
        }

        Integer nowPage = null; // 現在表示ページ
        int startRec = 0; // 表示開始レコード

        // 表示開始レコード算出
        nowPage = (Integer) session.get("AttrNowPage");
        if (nowPage == null) {
            nowPage = new Integer(1);
        }
        startRec = 1 + ((nowPage.intValue() - 1) * 5);

        String rset_c1 = null; // 製品CD
        String rset_c2 = null; // 製品名
        long rset_c3 = 0; // 単価
        long rset_c4 = 0; // 在庫数
        int cnt = 0; // カウンタ

        String[] product = new String[5];
        String[] prodname = new String[5];
        Long[] price = new Long[5];
        Long[] stoks = new Long[5];

        try {
            // 在庫テーブルの抽出
            rset = stmt.executeQuery("SELECT * from WEBCONT_WAREHOUSE");
            // 開始レコードの設定
            if (startRec == 1) {
                rset.beforeFirst();
            } else {
                rset.absolute(startRec - 1);
            }

            // 表示データクリア
            session.remove("AttrShowProduct");
            session.remove("AttrShowProdName");
            session.remove("AttrShowPrice");
            session.remove("AttrShowStoks");

            for (cnt = 0; cnt < 5 && (rset.next() == true); cnt++) {

                // 在庫データの取得
                rset_c1 = rset.getString(1);
                rset_c1 = rset_c1.trim();
                rset_c2 = rset.getString(2);
                rset_c2 = rset_c2.trim();
                rset_c3 = rset.getLong(3);
                rset_c4 = rset.getLong(4);

                // 在庫データの設定
                product[cnt] = rset_c1;
                prodname[cnt] = rset_c2;
                price[cnt] = new Long(rset_c3);
                stoks[cnt] = new Long(rset_c4);
            }

            session.put("AttrShowProduct", product);
            session.put("AttrShowProdName", prodname);
            session.put("AttrShowPrice", price);
            session.put("AttrShowStoks", stoks);
        } catch (SQLException e) {
            throw new IOException(e.toString());
        } finally {
            try {
                // DB Objectクローズ
                rset.close();
                stmt.close();
                conn.close();
            } catch (SQLException se) {
            }
        }
        return;
    }

    public void getListData(Map<String, Object> session) throws IOException {

        Connection conn = null;
        Statement stmt = null;
        ResultSet rset = null;

        // 在庫テーブルのコネクション生成
        try {
            Class.forName(dbDriver);
            conn = DriverManager.getConnection(dbUrl, dbUserid, dbPasswd);
            stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
        } catch (Exception e) { // SQLException / ClassNotFound / Exception
            try { // DB Objectクローズ
                if (stmt != null) {
                    stmt.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException se) {
            }

            throw new IOException(e.toString());
        }

        @SuppressWarnings("unchecked")
        Hashtable<String, Integer> orderData = (Hashtable<String, Integer>) session
                .get("AttrOrderData");
        int orderNum = orderData.size();

        // 現在表示データ保存
        String[] rbkProduct = (String[]) session.get("AttrShowProduct");
        String[] rbkProdName = (String[]) session.get("AttrShowProdName");
        Long[] rbkPrice = (Long[]) session.get("AttrShowPrice");
        Long[] rbkStoks = (Long[]) session.get("AttrShowStoks");

        // 表示データクリア
        session.remove("AttrShowProduct");
        session.remove("AttrShowProdName");
        session.remove("AttrShowPrice");
        session.remove("AttrShowStoks");

        Enumeration<String> enumeration = orderData.keys();
        String[] sortprod = new String[orderNum];
        String[] product = new String[orderNum];
        String[] prodname = new String[orderNum];
        Long[] price = new Long[orderNum];
        Long[] stoks = new Long[orderNum];
        int cnt = 0; // カウンタ
        String sqlStr = null;
        String rset_c1 = null; // 製品CD
        String rset_c2 = null; // 製品名
        long rset_c3 = 0; // 単価
        long rset_c4 = 0; // 在庫数
        int orderCnt = 0;

        try {
            for (cnt = 0; cnt < orderNum; cnt++) {
                sortprod[cnt] =enumeration.nextElement();
            }
            Arrays.sort(sortprod);
            for (cnt = 0; cnt < orderNum; cnt++) {
                rset_c1 = sortprod[cnt];
                sqlStr = "SELECT * FROM WEBCONT_WAREHOUSE WHERE PRODUCT_ID LIKE '"
                        + rset_c1 + "'";
                rset = stmt.executeQuery(sqlStr);
                if (!rset.first()) {
                    continue;
                }
                // 在庫データの取得
                rset_c1 = rset_c1.trim();
                rset_c2 = rset.getString(2);
                rset_c2 = rset_c2.trim();
                rset_c3 = rset.getLong(3);
                rset_c4 = rset.getLong(4);
                // 在庫データの設定
                product[orderCnt] = rset_c1;
                prodname[orderCnt] = rset_c2;
                price[orderCnt] = new Long(rset_c3);
                stoks[orderCnt] = new Long(rset_c4);
                orderCnt++;
            }

            // 表示データの更新
            session.put("AttrShowProduct", product);
            session.put("AttrShowProdName", prodname);
            session.put("AttrShowPrice", price);
            session.put("AttrShowStoks", stoks);

            // DB Objectクローズ
            if (rset != null)
                rset.close();
        } catch (SQLException e) {
            // 現在表示データの復帰
            session.put("AttrShowProduct", rbkProduct);
            session.put("AttrShowProdName", rbkProdName);
            session.put("AttrShowPrice", rbkPrice);
            session.put("AttrShowStoks", rbkStoks);
            throw new IOException(e.getMessage());
        } finally {
            try { // DB Objectクローズ
                stmt.close();
                conn.close();
            } catch (SQLException se) {
            }
        }
        return;
    }
}
2. 発注データDB登録処理

1) 注文データを元に発注済データの登録と在庫管理テーブルの更新を行います。

在庫データ − 注文データ ⇒更新⇒ 在庫データ
注文データ ⇒追加⇒ 発注済データ

発注データDB登録処理(DBOrderData.class)のソースを次に表示します。

package jp.co.nec.WebOTX.StrutsSample;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Map;

import javax.servlet.ServletContext;

public final class DBOrderData {

    // ----------------------------------------------------- Instance Variables
    String[] dbInfo = null; // DB接続情報
    String dbDriver = null; // JDBCドライバ名
    String dbUrl = null; // DBへのURL
    String dbUserid = null; // ユーザ名
    String dbPasswd = null; // パスワード
    Hashtable<String, Integer> errorData = new Hashtable<String, Integer>();

    public DBOrderData(ServletContext servcon, Map<String, Object> session)
            throws IOException {

        initDBInfo(servcon, session);
    }

    // --------------------------------------------------------- Public Methods
    public void initDBInfo(ServletContext servcon, Map<String, Object> session)
            throws IOException {

        // DB情報の取得
        dbInfo = (String[]) session.get("AttrDBInfo");
        if (dbInfo == null) {
            dbInfo = new String[4];

            dbInfo[0] = dbDriver = servcon.getInitParameter("dbDriver");
            dbInfo[1] = dbUrl = servcon.getInitParameter("dbURL");
            dbInfo[2] = dbUserid = servcon.getInitParameter("dbUserId");
            dbInfo[3] = dbPasswd = servcon.getInitParameter("dbPassword");
            session.put("AttrDBInfo", dbInfo);
        } else {
            dbDriver = dbInfo[0];
            dbUrl = dbInfo[1];
            dbUserid = dbInfo[2];
            dbPasswd = dbInfo[3];
        }
    }

    public void entryData(Map<String, Object> session) throws IOException {

        Connection conn = null;
        Statement stmt = null;
        ResultSet rset = null;
        PreparedStatement od_stmt = null;
        // 在庫テーブルのコネクション生成
        try {
            Class.forName(dbDriver);
            conn = DriverManager.getConnection(dbUrl, dbUserid, dbPasswd);
            stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
        } catch (Exception e) { // SQLException / ClassNotFound / Exception
            try {
                // DB Objectクローズ
                if (stmt != null) {
                    stmt.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException se) {
            }
            throw new IOException(e.toString());
        }

        @SuppressWarnings("unchecked")
        Hashtable<String, Integer> orderData = (Hashtable<String, Integer>) session
                .get("AttrOrderData");
        if (orderData == null) {
            return;
        }

        String rset_c1 = null; // 製品CD
        String rset_c2 = null; // 製品名
        long rset_c3 = 0; // 単価
        long rset_c4 = 0; // 在庫数
        long sub_total = 0; // 小計
        Timestamp nowtim = null; // 日時刻
        Integer orderNum = null; // 注文数
        String sqlStr = null; // 実行SQL文

        String[] logonInfo = (String[]) session.get("AttrLogOnInfo");
        if (logonInfo == null) {
            throw new IOException("not found logon data");
        }

        Enumeration<String> enumeration = orderData.keys();

        try {
            for (; enumeration.hasMoreElements();) {
                rset_c1 = enumeration.nextElement();
                // 在庫データより該当データを抽出
                sqlStr = "SELECT * FROM WEBCONT_WAREHOUSE WHERE PRODUCT_ID LIKE '"
                        + rset_c1 + "'";

                // 自動コミットを解除
                conn.setAutoCommit(false);

                // 在庫テーブルの抽出
                rset = stmt.executeQuery(sqlStr);
                rset.beforeFirst();

                if (rset.next() != true) {
                    // 自動コミットを復活
                    conn.setAutoCommit(true);
                    continue;
                }

                // 発注データ有無チェック
                if (orderData.get(rset_c1) == null) {
                    // 自動コミットを復活
                    conn.setAutoCommit(true);
                    continue;
                }

                rset_c2 = rset.getString(2);
                rset_c2 = rset_c2.trim();
                rset_c3 = rset.getLong(3);
                rset_c4 = rset.getLong(4);

                orderNum = orderData.get(rset_c1);
                rset_c4 = rset_c4 - orderNum.longValue();
                if (rset_c4 < 0) {
                    errorData.put(rset_c1, orderNum);

                    // 自動コミットを復活
                    conn.setAutoCommit(true);
                    continue;
                }

                // 検索結果クローズ
                rset.close();

                // 在庫テーブルの在庫数更新
                sqlStr = "UPDATE WEBCONT_WAREHOUSE SET STOCK_NUM=? WHERE PRODUCT_ID=?";
                od_stmt = conn.prepareStatement(sqlStr);
                od_stmt.setInt(1, new Long(rset_c4).intValue());
                od_stmt.setString(2, rset_c1);
                od_stmt.execute();
                od_stmt.close();

                // 発注済みデータの登録
                sqlStr = "INSERT INTO WEBCONT_ORDER(ORDER_SHOP,"
                        + "ORDER_CLERK," + "ORDER_NO," + "ORDER_DATE,"
                        + "PRODUCT_ID," + "PRODUCT_NAME," + "UNIT_PRICE,"
                        + "ORDER_NUM,SUB_TOTAL)"
                        + " values (?,?,?,?,?,?,?,?,?)";
                // INSERT (注文店/注文者/注文番号/注文日付/製品CD/製品名/単価/注文数/小計)
                od_stmt = conn.prepareStatement(sqlStr);

                sub_total = orderNum.longValue() * rset_c3; // 小計計算
                nowtim = new Timestamp(System.currentTimeMillis());
                od_stmt.setString(1, logonInfo[0]); // 発注店設定
                od_stmt.setString(2, logonInfo[1]); // 発注者設定
                od_stmt.setString(3, logonInfo[2]); // 発注番号設定
                od_stmt.setTimestamp(4, nowtim); // 注文日設定
                od_stmt.setString(5, rset_c1); // 製品CD設定
                od_stmt.setString(6, rset_c2); // 製品名設定
                od_stmt.setLong(7, rset_c3); // 単価設定
                od_stmt.setLong(8, orderNum.longValue()); // 注文数設定
                od_stmt.setLong(9, sub_total); // 小計設定
                // 設定実行
                od_stmt.execute();

                // ステートメントクローズ
                od_stmt.close();

                // コミットを行う
                conn.commit();

                // 自動コミットを復活
                conn.setAutoCommit(true);

                // 発注済みデータを発注データより削除
                orderData.remove(rset_c1);
            }
        } catch (Exception e) {
            try {
                conn.rollback();
            } catch (SQLException e2) {
                throw new IOException("DBOrder rollback NG");
            }
            throw new IOException(e.toString());
        } finally {
            try {
                // 自動コミットを復活
                conn.setAutoCommit(true);

                // DB Objectクローズ
                stmt.close();
                conn.close();
            } catch (SQLException se) {
            }
        }
        return;
    }
}
2.1. データベースへのアクセス

ユーザ情報、発注データを保存するためにデータベースを使用します。今回はDerbyとそのJDBCドライバを使用しデータの読み書きを行います。 JDBC ドライバのファイル(今回はderby.jar)をテスト用サーバのクラスパスに登録しておく必要があります。

try {
  Class.forName( "DBのドライバ名" ); // (1)
  Connection conn = DriverManager.getConnection("DBのURL","DBのユーザ名", "DBのパスワード" ); // (2)
  Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY); // (3)
} catch (SQLException e) {
:
(1)でJDBCドライバを読み込みます
(2)でコネクションを生成します。
(3)でステートメントを作成し、以後ステートメントに対してSQLを発行します。

サンプルで使用するDerbyのテーブル情報は以下の通り。

表2.5.4.3-2 在庫管理テーブル
製品ID 製品名 単価 在庫数
PRODUCT_ID PRODUCT_NAME UNIT_PRICE STOCK_NUM
char(16) char(32) integer integer
表2.5.4.3-3 発注済データテーブル
発注店 担当者 発注番号 発注日 製品ID 製品名 単価 注文数 小計
ORDER_SHOP ORDER_CLERK ORDER_NO ORDER_DATE PRODUCT_ID PRODUCT_NAME UNIT_PRICE ORDER_NUM SUB_TOTAL
char(32) char(32) char(64) date char(10) char(32) integer integer integer
表2.5.4.3-4 ユーザ情報テーブル
ユーザ名 パスワード 担当店
INFO_USER INFO_PASS INFO_SHOP
char(32) char(32) char(32)
定義ファイルの作成

Struts定義ファイル(struts.xml)を作成します。 HTTPからのリクエストを振り分ける、またレスポンスとして処理するファイルを決定するために、 struts.xmlファイルを設定する必要があります。

今回のサンプルWebアプリケーションの定義ファイルは次のようになります。

例) struts.xmlの設定例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd" >
<struts>
    <package name="struts-sample" extends="struts-default">
        <global-results>
            <result name="success">/order.jsp</result>
            <result name="end">/entryEnd.jsp</result>
        </global-results>
        <action name="logon" class="jp.co.nec.WebOTX.StrutsSample.LogonAction">
            <result name="input">/logon.jsp</result>
            <result name="success">/order.jsp</result>
        </action>
        <action name="show" class="jp.co.nec.WebOTX.StrutsSample.ShowAction">
            <result name="input">/order.jsp</result>
            <result name="success">/order.jsp</result>
            <result name="orderlist">/orderlist.jsp</result>
        </action>
        <action name="order" class="jp.co.nec.WebOTX.StrutsSample.OrderAction">
            <result name="input">/order.jsp</result>
            <result name="success">/order.jsp</result>
            <result name="result">/entryResult.jsp</result>
        </action>
    </package>
    <constant name="struts.custom.i18n.resources"
        value="jp.co.nec.WebOTX.StrutsSample.ApplicationResources"></constant>
</struts>

各要素について解説します。

<global-results> : ActionSupportクラスを継承したアプリケーションクラスの処理終了時、次に表示する画面を設定します。
<result> : アプリケーションクラス終了時に”success”を指定(name属性)すると発注画面(タグ値)に、”end”を指定(name属性)すると発注完了画面(タグ値)に、それぞれ遷移します。ただし<action>内に同名の<result>設定があった場合、そちらが優先されます。
<action> : リクエストを振り分ける情報を設定します。
<action> : リクエスト(URLがlogon.action、show.action、order.action)が来た場合、それぞれLogonAction.class、ShowAction.class、OrderAction.classに振り分ける(name属性、class属性)。
<result> : アプリケーションクラス終了時、遷移先の画面を指定する。(<global-results>と同様)

WebAPの定義ファイル(web.xml)ファイルを作成します。 ここではポイントとなるFilterのマッピングについて記述します。

web.xmlの設定

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <context-param>
        <param-name>dbURL</param-name>
        <param-value>jdbc:derby:C:\MyDB;create=true</param-value>
    </context-param>
    <context-param>
        <param-name>dbDriver</param-name>
        <param-value>org.apache.derby.jdbc.EmbeddedDriver</param-value>
    </context-param>
    <context-param>
        <param-name>dbUserId</param-name>
        <param-value/>
    </context-param>
    <context-param>
        <param-name>dbPassword</param-name>
        <param-value/>
    </context-param>
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
    </welcome-file-list>
</web-app>

<filter-mapping>の設定によりURLの最後が.actionでリクエストされた場合、全てStrutsのServletクラスが受信することになります。 Strutsは.actionの前の部分とStruts定義ファイル(struts.xml)を使用し、振り分け先のアプリケーションクラスを決定します。

warの配備

Webブラウザより運用管理コンソールを呼び出します。

http://localhost:5858/manager/

と入力してください。

ユーザ名、パスワードを要求された場合、admin/adminadmin を入力してください。 運用管理コンソールが表示されたら、画面左のツリーより「アプリケーション」を選択します。 アプリケーションの配備画面が表示されます。 「コンポーネントタイプ」から「Webコンポーネント」を選択し、「ファイル」に struts-sample.war を指定します。 「詳細項目の表示」をクリックし、詳細項目表示後、「コンポーネント名」に「struts-sample」を指定、「コンテキストルート」に「/struts-sample」を指定して配備を実行してください。

以上でWebアプリケーション「struts-sample」が配備されます。

Webアプリケーションの動作確認

ブラウザより http://localhost/struts-sample/ にアクセスします。

ログオン画面の表示確認

ログオン画面が表示されることを確認します。

ログオン失敗の確認

ログオンに失敗した場合の処理を確認します。
何も入力せずに発注開始を選択した場合
→ ログオン画面に戻り、エラーメッセージが画面上部に表示されていること
StrutsのTagを使用したエラーの表示
誤ったユーザ名/パスワードを入力した場合
→ ログオン画面に戻り、エラーメッセージが画面上部に表示されていること
StrutsのTagを使用したエラーの表示

ログオン成功の確認

ユーザ名(User_1)、パスワード(Pass_1)を入力し発注開始を選択
発注画面が表示されることを確認します。

発注画面表示の確認

発注画面が表示されることを確認します。

発注商品選択の確認

商品を選択し、注文数を入力します。小計が計算され表示されることを確認します。

発注データ一覧画面

発注データ一覧画面を表示し、注文した商品の一覧が表示されることを確認します。

発注処理の確認

発注処理を実行し、発注完了画面が表示されることを確認します。
DBに発注データが登録され、在庫データが更新されていることを確認します。(dbtblview.jspを使用)

発注処理で在庫データ不足により発注に失敗した商品があった場合、発注結果表示画面がが表示されることを確認します。

発注を継続する場合、発注画面が表示されることを確認します。
発注を中止した場合、発注完了画面が表示されることを確認します。

発注完了画面が表示されることを確認します。

発注完了画面は発注処理が正常に終了した場合、発注処理を途中で中断した場合に表示されます。
データソースの利用

DBへのコネクション生成は時間のかかる処理です。 このコネクションをあらかじめ生成して、データソースとしてJNDIに登録しておき、使用時に呼び出すことで、生成にかかる時間を短縮することができます。 プログラム中でコネクションを使用するときは、JNDIからコネクション(データソース)を取得(lookup)することで、コネクションを取得します。

2.5.4.4. 注意事項

サンプルを実行する前に、DBの設定が必要です。詳細は2.5.2.2. 各サンプルの初期設定 を参照してください。


「java.lang.NoClassDefFoundError」エラーの対応方法

「ログオン画面へ」のリンクをクリック時に「java.lang.NoClassDefFoundError」が発生する場合、以下の操作を行ってください。

「Expression parameters.templateDir is undefined」エラーの対応方法

「ログオン画面へ」のリンクをクリック時に下記のエラーが発生する場合、sever.pliocyに権限の追加を行ってください。

エラー現象
?ログオン画面には次のエラー情報が表示されます。
Expression parameters.templateDir is undefined on line 23, column 15 in template/xhtml/form.ftl.
?webotx_agent.logには次の情報が記録されています。
SECURITY - JACC Policy Provider:Failed Permission Check: context (" null ") , permission (" ("ognl.OgnlInvokePermission" "invoke.com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.setExcludeMethods") ") 
sever.policyへ権限の追加方法
{WebOTXインストールディレクトリ}/domains/{ドメイン名}/config/server.policyファイル(SecurityManager によるアクセス管理を定義するファイル)のgrant {...} に、次のポリシーを追加して、ドメインを再起動します。
permission ognl.OgnlInvokePermission "*";