広告

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2010年02月07日

    Java総合講座 - 初心者から達人へのパスポート
                  vol.190

                                セルゲイ・ランダウ
 バックナンバー: http://www.flsi.co.jp/Java_text/
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


-------------------------------------------------------
・現在、このメールマガジンは以下の2部構成になっています。
[1] 当初からのコース:毎週日曜の夜に発行
   これは現在、中級レベルになっています。
[2] 2009年11月開講コース:毎週水曜の夜に発行
   これは現在、初心者向けのレベルになっています。
・このメールマガジンは、画面を最大化して見てください。
小さな画面で見ていると、不適切な位置で行が切れてしまう
など、問題を起すことがあります。
・このメールマガジンに掲載されているソース・コード及び
文章は特に断らない限り、すべて筆者が著作権を所有してい
ます。また、これらのソース・コードは学習用のためだけに
提供しているものです。
-------------------------------------------------------


========================================================
◆ 01.Strutsのアプリケーション開発
========================================================


さて、前回のCategoryDbManagerクラスの作成時に使ったReflectionToStringMaker
にちょっと誤りがあることに気がつきましたので修正したいのですが、作業上の
煩わしさを避けるためにValueLogStringMakerというクラス名で新しく作り直す
ことにします。(実際の現場で使用するプログラムと違って、ろくにテストもして
いないので、このようにあとで誤りに気づいたりします。)

(1) Eclipseのプロジェクト・エクスプローラー内のStrutsShop(もしくは、さらに
その配下の「Javaリソース: src」)を右クリックし、「新規」→「パッケージ」
を選択します。

(2) 「名前」欄に

jp.co.flsi.lecture.reflect

と入力し、「完了」ボタンをクリックします。

(3) 続いて、プロジェクト・エクスプローラー内のStrutsShop配下の
「Javaリソース: src」配下のjp.co.flsi.lecture.reflectを右クリックし、
「新規」→「クラス」を選択します。

(4) 「名前」欄に

ValueLogStringMaker

と入力し、「完了」ボタンをクリックします。

(5) ValueLogStringMaker.javaのエディターが開いたら、下記のように
編集しましょう。

--------------------------------------------------------
package jp.co.flsi.lecture.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;

public class ValueLogStringMaker {
   StringBuffer buffer = null;

   public String getValues(String variableName, Object object) {
      buffer = new StringBuffer();
      buffer.append(variableName + " = [\n");
      appendObject(variableName, object);
      buffer.append("]");
      return buffer.toString();
   }

   private void appendFields(Object object) {
      Class clazz = object.getClass();
      buffer.append(clazz.getName());
      buffer.append("@" + Integer.toHexString(object.hashCode()) + "[\n");
      Field[] fieldList = clazz.getDeclaredFields();
      for (Field field : fieldList) {
         appendProperty(field.getName(), field.getType().getName(), object);
      }
      buffer.append("]");
   }

   private void appendProperty(String fieldName, String fieldType, Object object) {
      String getterMethodName = null;
      // publicなgetメソッドを持つフィールド(プロパティー)のみをアペンドする。

      // ただし、boolean型のgetメソッドはisで始まるものとする。
      if (fieldType.equals("boolean")) {
         getterMethodName = "is" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
      }
      else {
         getterMethodName = "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
      }
      Method method = null;
      try {
         method = object.getClass().getMethod(getterMethodName, new Class[0]);
      } catch (SecurityException e) {
         e.printStackTrace();
      } catch (NoSuchMethodException e) {
         // getメソッドのないものは無視する。
         return;
      }
      Object result = null;
      try {
         result = method.invoke(object, new Object[0]);
      } catch (IllegalArgumentException e) {
         e.printStackTrace();
      } catch (IllegalAccessException e) {
         e.printStackTrace();
      } catch (InvocationTargetException e) {
         e.printStackTrace();
      }
      buffer.append("   " + fieldName + " = ");
      appendObject(fieldName, result);
   }

   private void appendObject(String fieldName, Object value) {
      if (value == null) {
         buffer.append("null");
      }
      else if (value instanceof Collection) {
         append(fieldName, (Collection) value);
      } else if (value instanceof Map) {
         append(fieldName, (Map) value);
      } else if (value instanceof long[]) {
         append(fieldName, (long[]) value);
      } else if (value instanceof int[]) {
         append(fieldName, (int[]) value);
      } else if (value instanceof short[]) {
         append(fieldName, (short[]) value);
      } else if (value instanceof byte[]) {
         append(fieldName, (byte[]) value);
      } else if (value instanceof char[]) {
         append(fieldName, (char[]) value);
      } else if (value instanceof double[]) {
         append(fieldName, (double[]) value);
      } else if (value instanceof float[]) {
         append(fieldName, (float[]) value);
      } else if (value instanceof boolean[]) {
         append(fieldName, (boolean[]) value);
      } else if (value.getClass().isArray()) {
         append(fieldName, (Object[]) value);
      } else {
         append(fieldName, value);
      }
      buffer.append("\n");
   }

   private void append(String fieldName, Collection value) {
      Object[] array = value.toArray();
      buffer.append("{\n");
      for (Object element : array) {
         buffer.append("   ");
         appendObject(fieldName, element);
      }
      buffer.append("}");
   }

   private void append(String fieldName, Map value) {
      Collection col = value.values();
      Object[] array = col.toArray();
      buffer.append("{\n");
      for (Object element : array) {
         buffer.append("   ");
         appendObject(fieldName, element);
      }
      buffer.append("}");
   }

   private void append(String fieldName, long[] value) {
      buffer.append("{\n");
      for (long element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, int[] value) {
      buffer.append("{\n");
      for (int element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, short[] value) {
      buffer.append("{\n");
      for (short element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, byte[] value) {
      buffer.append("{\n");
      for (byte element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, char[] value) {
      buffer.append("{\n");
      for (char element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, double[] value) {
      buffer.append("{\n");
      for (double element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, float[] value) {
      buffer.append("{\n");
      for (float element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, boolean[] value) {
      buffer.append("{\n");
      for (boolean element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, Object[] value) {
      buffer.append("{\n");
      for (Object element : value) {
         buffer.append("   ");
         appendObject(fieldName, element);
      }
      buffer.append("}");
   }

   private void append(String fieldName, Object value) {
      if ((value instanceof String) ||
            (value instanceof Long) ||
            (value instanceof Integer) ||
            (value instanceof Short) ||
            (value instanceof Byte) ||
            (value instanceof Character) ||
            (value instanceof Double) ||
            (value instanceof Float) ||
            (value instanceof Boolean)) {
         buffer.append(value);
      } else {
         appendFields(value);
      }
   }

}
--------------------------------------------------------

ReflectionToStringMakerとどこが違うのか、わかりますね。
どこをどう修正したのか、各自が考えて下さい。
(ヒント:最初に呼び出すprivateメソッドを間違えていました。)



では、ついでにこのValueLogStringMakerクラスを他のアプリケーションでも
使えるようにJARファイルにしておきましょう。(ただし、今回のアプリケー
ションではこのJARファイルは使用しません。)

(1) プロジェクト・エクスプローラー内のStrutsShop配下の
「Javaリソース: src」配下のjp.co.flsi.lecture.reflect配下の
ValueLogStringMaker.javaを右クリックし、「エクスポート」を
選択します。

(2) 「エクスポート」ウインドウにおいて、「Java」配下の「JARファイル」を
選択し、「次へ」ボタンをクリックします。

(3) 「JARファイル」欄に

C:\JavaWorkSpace\reflectstringmaker.jar

と入力し、「完了」ボタンをクリックしましょう。

(4) 「JARエクスポートが警告とともに完了しました。追加情報については詳細を・・・」
というメッセージが出ますが、これは以前お話したようにコンパイルの時点で警告が
出ているためです。この警告は以前お話した通り無視していいので、気にせずに
「OK」ボタンをクリックします。


それでは、ReflectionToStringMakerの代わりにValueLogStringMakerクラスを使用
するように、CategoryDbManagerクラスを修正しましょう。

CategoryDbManager.javaを下記のように書き換えて下さい。

--------------------------------------------------------
package jp.co.flsi.lecture.struts.db;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Vector;
import jp.co.flsi.lecture.reflect.ValueLogStringMaker;

import org.apache.log4j.Logger;

public class CategoryDbManager extends DbManager {
   private static final String selectNameSql = "SELECT * FROM CATEGORY WHERE NAME LIKE ?";
   private static Logger logger = Logger.getLogger(CategoryDbManager.class);

   public Vector<Category> getDataByName(String name) throws StruShopDbException {
      logger.info("Start ...............");
      ValueLogStringMaker stringMaker = new ValueLogStringMaker();
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("name", name));
      logger.info(">>>>>");
      Vector<Category> categoryList = new Vector<Category>();
      try {
         PreparedStatement selectPs = null;
         ResultSet rs;
         if (name == null) {
            name = "";
         }
         selectPs = conn.prepareStatement(selectNameSql);
         selectPs.setString(1, "%"+ name + "%");
         rs = selectPs.executeQuery();
         while (rs.next()) {
            Category category = new Category();
            category.setNum(rs.getString("NUM"));
            category.setName(rs.getString("NAME"));
            categoryList.add(category);
         }
         selectPs.close();
      }
      catch (SQLException e) {
         logger.error(e, e);
         throw new StruShopDbException("Error: getDataByName() failed!", e);
      }
      catch (Throwable e) {
         logger.error(e, e);
      }
      finally {
         logger.info("End ...............");
      }
      logger.info("Method return: <<<<<" + stringMaker.getValues("categoryList", categoryList));
      logger.info(">>>>>");
      return categoryList;
   }

}
--------------------------------------------------------

どこを修正したのか、わかりますね。



それから、vol.187でStrutsShopプロジェクトのクラスパスに登録していた
reflectstringmaker.jarは不要になるので除去しましょう。

(1) プロジェクト・エクスプローラー内のStrutsShop(プロジェクト)を
右クリックし、「ビルド・パス」→「ビルド・パスの構成」を選択します。

(2) 「StrutsShopのプロパティー」ウインドウの右側の「ライブラリー」タブをクリック
し、「ビルド・パス上のJARおよびクラス・フォルダー」欄の中の

reflectstringmaker.jar - C:\JavaWorkSpace

を選択し、「除去」ボタンをクリックします。

(3) 「OK」ボタンをクリックします。



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


続いて、商品のテーブル(ITEM)にマッピングするエンティティーのクラス
として、Itemというクラスを作成しましょう。

(1) プロジェクト・エクスプローラー内でjp.co.flsi.lecture.struts.dbを右クリック
し、「新規」→「クラス」を選択します。

(2) 「名前」欄に

Item

と入力し、「完了」ボタンをクリックします。

(3) Item.javaのエディターが開いたら、下記のように編集しましょう。

--------------------------------------------------------
package jp.co.flsi.lecture.struts.db;

public class Item {
   private String num;
   private String name;
   private int price;
   private String image;
   private String catNum;
   private String catName;
   private int quantity;

   public void setNum(String num) {
      this.num = num;
   }
   public String getNum() {
      return num;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getName() {
      return name;
   }
   public void setPrice(int price) {
      this.price = price;
   }
   public int getPrice() {
      return price;
   }
   public void setImage(String image) {
      this.image = image;
   }
   public String getImage() {
      return image;
   }
   public void setCatNum(String catNum) {
      this.catNum = catNum;
   }
   public String getCatNum() {
      return catNum;
   }
   public void setCatName(String catName) {
      this.catName = catName;
   }
   public String getCatName() {
      return catName;
   }
   public void setQuantity(int quantity) {
      this.quantity = quantity;
   }
   public int getQuantity() {
      return quantity;
   }

}
--------------------------------------------------------

(いちいち断っていませんが、こういったフィールドとsetterメソッド、getter
メソッドだけから構成されるようなクラスの場合、フィールドだけ自分でコーディ
ングしておけば、メソッドはリファクタリングの機能(「リファクタリング」→
「フィールドのカプセル化」)で自動生成できますので、上のクラスの作成には
たいして手間はかかりませんね。
さらに、後の上級コースでは、これらのコーディングを自動化するテクニックもお話
いたします。)

なお、このクラスはITEMテーブルのカラムに対応したフィールドだけでなく、CATEGORY
テーブルのカラムに対応したフィールドも含んでいることに注意して下さい。

これは、商品のカテゴリーの名前を調べるのにいちいちCategoryオブジェクトに
問い合わせなければならないのでは、効率が悪いからです。



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


続いて、商品のテーブル(ITEM)へアクセスを行うためのクラス
を作成しましょう。

(1) プロジェクト・エクスプローラー内でjp.co.flsi.lecture.struts.dbを右クリック
し、「新規」→「クラス」を選択します。

(2) 「名前」欄に

ItemDbManager

と入力し、「完了」ボタンをクリックします。

(3) ItemDbManager.javaのエディターが開いたら、下記のように編集しましょう。

--------------------------------------------------------
package jp.co.flsi.lecture.struts.db;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Vector;
import jp.co.flsi.lecture.reflect.ValueLogStringMaker;
import org.apache.log4j.Logger;

public class ItemDbManager extends DbManager {
   private static final String selectItemNameAndCatNumSql =
      "SELECT I.NUM I_NUM, I.NAME I_NAME, PRICE, IMAGE, C_NUM, C.NAME C_NAME, QUANTITY FROM ITEM I, CATEGORY C "
      + "WHERE I.C_NUM = C.NUM AND I.NAME LIKE ? AND C_NUM = ?";
   private static final String selectItemNameAndCatNameSql =
      "SELECT I.NUM I_NUM, I.NAME I_NAME, PRICE, IMAGE, C_NUM, C.NAME C_NAME, QUANTITY FROM ITEM I, CATEGORY C "
      + "WHERE I.C_NUM = C.NUM AND I.NAME LIKE ? AND C.NAME LIKE ?";
   private static Logger logger = Logger.getLogger(ItemDbManager.class);

   public Vector<Item> getDataByItemNameAndCatNum(String itemName, String categoryNum) throws StruShopDbException {
      logger.info("Start ...............");
      ValueLogStringMaker stringMaker = new ValueLogStringMaker();
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("itemName", itemName));
      logger.info(">>>>>");
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("categoryNum", categoryNum));
      logger.info(">>>>>");
      Vector<Item> itemList = new Vector<Item>();
      try {
         PreparedStatement selectPs = null;
         ResultSet rs;
         if (itemName == null) {
            itemName = "";
         }
         if (categoryNum == null) {
            categoryNum = "";
         }
         selectPs = conn.prepareStatement(selectItemNameAndCatNumSql);
         selectPs.setString(1, "%"+ itemName + "%");
         selectPs.setString(2, categoryNum);
         rs = selectPs.executeQuery();
         while (rs.next()) {
            Item item = new Item();
            item.setNum(rs.getString("I_NUM"));
            item.setName(rs.getString("I_NAME"));
            item.setPrice(rs.getInt("PRICE"));
            item.setImage(rs.getString("IMAGE"));
            item.setCatNum(rs.getString("C_NUM"));
            item.setCatName(rs.getString("C_NAME"));
            item.setQuantity(rs.getInt("QUANTITY"));
            itemList.add(item);
         }
         selectPs.close();
      }
      catch (SQLException e) {
         logger.error(e, e);
         throw new StruShopDbException("Error: getDataByItemNameAndCatNum() failed!", e);
      }
      catch (Throwable e) {
         logger.error(e, e);
      }
      finally {
         logger.info("End ...............");
      }
      logger.info("Method return: <<<<<" + stringMaker.getValues("itemList", itemList));
      logger.info(">>>>>");
      return itemList;
   }

   public Vector<Item> getDataByItemNameAndCatName(String itemName, String categoryName) throws StruShopDbException {
      logger.info("Start ...............");
      ValueLogStringMaker stringMaker = new ValueLogStringMaker();
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("itemName", itemName));
      logger.info(">>>>>");
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("categoryName", categoryName));
      logger.info(">>>>>");
      Vector<Item> itemList = new Vector<Item>();
      try {
         PreparedStatement selectPs = null;
         ResultSet rs;
         if (itemName == null) {
            itemName = "";
         }
         if (categoryName == null) {
            categoryName = "";
         }
         selectPs = conn.prepareStatement(selectItemNameAndCatNameSql);
         selectPs.setString(1, "%"+ itemName + "%");
         selectPs.setString(2, "%"+ categoryName + "%");
         rs = selectPs.executeQuery();
         while (rs.next()) {
            Item item = new Item();
            item.setNum(rs.getString("I_NUM"));
            item.setName(rs.getString("I_NAME"));
            item.setPrice(rs.getInt("PRICE"));
            item.setImage(rs.getString("IMAGE"));
            item.setCatNum(rs.getString("C_NUM"));
            item.setCatName(rs.getString("C_NAME"));
            item.setQuantity(rs.getInt("QUANTITY"));
            itemList.add(item);
         }
         selectPs.close();
      }
      catch (SQLException e) {
         logger.error(e, e);
         throw new StruShopDbException("Error: getDataByItemNameAndCatName() failed!", e);
      }
      catch (Throwable e) {
         logger.error(e, e);
      }
      finally {
         logger.info("End ...............");
      }
      logger.info("Method return: <<<<<" + stringMaker.getValues("itemList", itemList));
      logger.info(">>>>>");
      return itemList;
   }

}
--------------------------------------------------------

このクラスでは、Itemオブジェクトにカテゴリーの名前まで一緒に設定して
いることに注意して下さい。

そのために、ITEMテーブルから商品の情報を取り出すときに、同時にCATEGORYテーブル
からカテゴリーの名前を取得できるようなSQL文を組んでありますね。



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


では、ここで再度struts-config.xmlのエディターに戻って下さい。
そのフロー・エディターを開いて(下のほうにある「フロー」タブをクリックすると開く)
下さい。

/itemlistのアイコンに警告のマーク(ビックリ・マークのはいった橙色の三角形
のマーク)が付いていましたね。

(1) この/itemlistのアイコンをダブル・クリックして下さい。

(2) 「Struts Action」ウインドウが開きますので、「完了」ボタンをクリックして
下さい。

すると、ItemListAction.javaのエディターが開きますね。
これは後で編集しますので、そのままにしておいて下さい。



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


さて、WebページのFORMに入力されたデータは、StrutsではActionFormを
通じて取得できるのでしたね。

ItemListActionを編集する際には、このActionFormにアクセスすることに
なりますので、ActionFormのサブクラスを用意しておく必要があります。

というわけで、itemSelect.jspのWebページの「キーワード」欄や「カテゴリー」欄
に入力されたデータを取得するためのActionFormのサブクラスを、ItemSelectFormという
名前で作成することにします。


まずは、ItemSelectFormをstruts-config.xmlに登録しておきましょう。
struts-config.xmlのソース・エディターを開いて(下のほうにある「ソース」タブを
クリックすると開く)、下記のようにItemSelectFormに関する記述を挿入して下さい。
(ItemSelectFormの編集後の全ソース・コードを提示しておきます。)

--------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
  <data-sources>
  </data-sources>
  <form-beans>
    <form-bean name="itemSelectForm" type="jp.co.flsi.lecture.struts.ItemSelectForm" />
  </form-beans>
  <global-exceptions>
  </global-exceptions>
  <global-forwards>
  </global-forwards>
  <action-mappings>
    <action path="/itemlist" type="jp.co.flsi.lecture.struts.ItemListAction"
     name="itemSelectForm" scope="request" input="/itemSelect.jsp">
      <forward name="success" path="/itemList.jsp"/>
    </action>
    <action path="/cart" type="jp.co.flsi.lecture.struts.CartAction"
     input="/itemList.jsp">
      <forward name="success" path="/cart.jsp"/>
    </action>
    <action path="/orderprocess" type="jp.co.flsi.lecture.struts.OrderProcessAction"
     input="/cart.jsp">
      <forward name="success" path="/order.jsp"/>
    </action>
    <action path="/confirmorder" type="jp.co.flsi.lecture.struts.ConfirmOrderAction"
     input="/order.jsp">
      <forward name="success" path="/confirmOrder.jsp"/>
    </action>
    <action path="/completeorder" type="jp.co.flsi.lecture.struts.CompleteOrderAction"
     input="/confirmOrder.jsp">
      <forward name="success" path="/completeOrder.jsp"/>
    </action>
  </action-mappings>
  <controller processorClass="org.apache.struts.tiles.TilesRequestProcessor"/>
  <message-resources parameter="MessageResources"/>
  <plug-in className="org.apache.struts.tiles.TilesPlugin">
    <set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml"/>
    <set-property property="moduleAware" value="true"/>
  </plug-in>
  <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
    <set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
  </plug-in>
</struts-config>
--------------------------------------------------------



続いて、ItemSelectFormクラスを下記のように作成しましょう。

(1) プロジェクト・エクスプローラー内でjp.co.flsi.lecture.strutsを右クリック
し、「新規」→「その他」を選択します。

(2) 「新規」ウインドウにおいて「Amateras」配下の「Struts」配下の
「Struts ActionForm」を選択し、「次へ」ボタンをクリックします。

(3) 「名前」欄に

ItemSelectForm

と入力し、「完了」ボタンをクリックします。

(4) ItemSelectForm.javaのエディターが開いたら、下記のように編集しましょう。

--------------------------------------------------------
package jp.co.flsi.lecture.struts;

import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;

public class ItemSelectForm extends ActionForm {
   private static Logger logger = Logger.getLogger(ItemSelectForm.class);
   private String keyword = null;
   private String category = null;

   public void reset(ActionMapping mapping, HttpServletRequest request) {
      logger.info("Start ...............");
      try {
         request.setCharacterEncoding("UTF-8");
      } catch (UnsupportedEncodingException e) {
         logger.error(e, e);
      }
      finally {
         logger.info("End ...............");
      }
   }

   public void setKeyword(String keyword) {
      this.keyword = keyword;
   }
   public String getKeyword() {
      return keyword;
   }
   public void setCategory(String category) {
      this.category = category;
   }
   public String getCategory() {
      return category;
   }

}
--------------------------------------------------------

ここで、reset()メソッドの中で

request.setCharacterEncoding("UTF-8");

を実行していることに注意して下さい。

itemSelect.jspでは、

charset=UTF-8

を指定していましたから、JavaのプログラムがitemSelect.jspのWebページから
データを受け取るときにも同じエンコーディングを指定しておく必要があります。
つまり、

request.setCharacterEncoding("UTF-8");

を実行しておく必要があるわけです(何を言っているのか分からない人は、
vol.100やvol.087を復習のこと)が、これはStrutsでは上記のようにActionForm
のreset()メソッドの中で実行しておく必要があります。

Webページにに入力されたデータを最初に受け取るのはActionFormオブジェクト
なので、ActionFormの中でsetCharacterEncoding()メソッドを実行しておく
必要があるのです。

Actionクラス(ここではItemListAction)の中でsetCharacterEncoding()メソッド
を実行しても手遅れで、その時点で受け取るActionFormオブジェクトの中では既に
文字化けを起してしまっているという事態になってしまいます。

このActionFormのreset()メソッドは、ActionFormがインスタンス化された直後に
実行されるので、その時点で正しくエンコーディングを設定しておけば、Webページ
に入力されたデータがActionFormオブジェクトに渡されるときに正しく文字が読み
込まれることになるのです。



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


さて、先ほど、ItemListAction.javaのエディターを開いていましたね。
これを下記のように編集しましょう。

--------------------------------------------------------
package jp.co.flsi.lecture.struts;

import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jp.co.flsi.lecture.reflect.ValueLogStringMaker;
import jp.co.flsi.lecture.struts.db.Item;
import jp.co.flsi.lecture.struts.db.ItemDbManager;
import jp.co.flsi.lecture.struts.db.StruShopDbException;
import org.apache.log4j.Logger;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

public class ItemListAction extends Action {
   private static Logger logger = Logger.getLogger(ItemListAction.class);

   public ActionForward execute(ActionMapping mapping, ActionForm form,
         HttpServletRequest request, HttpServletResponse response) {
      logger.info("Start ...............");
      ValueLogStringMaker stringMaker = new ValueLogStringMaker();
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("mapping", mapping));
      logger.info(">>>>>");
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("form", form));
      logger.info(">>>>>");
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("request", request));
      logger.info(">>>>>");
      logger.info("Method parameter: <<<<<" + stringMaker.getValues("response", response));
      logger.info(">>>>>");
      ItemSelectForm itemSelectForm = (ItemSelectForm) form;
      ItemDbManager itemDbManager = new ItemDbManager();
      try {
         itemDbManager.connect();
         Vector<Item> itemList = null;
         itemList = itemDbManager.getDataByItemNameAndCatName(itemSelectForm.getKeyword(), itemSelectForm.getCategory());
         request.setAttribute("itemList", itemList);
      } catch (StruShopDbException e) {
         logger.error(e, e);
      }
      catch (Throwable e) {
         logger.error(e, e);
      }
      finally {
         try {
            itemDbManager.disconnect();
         }
         catch (Exception e) {
            logger.info("Disconnect failed or there is no connection.");
         }
         logger.info("End ...............");
      }
      logger.info("Method return: <<<<<" + stringMaker.getValues("mapping", mapping));
      logger.info(">>>>>");
      return mapping.findForward("success");
   }

}
--------------------------------------------------------



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


(次回に続く)


では、今日はここまでにします。



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      http://www.flsi.co.jp/Java_text/
★このメールマガジンは
     「まぐまぐ(http://www.mag2.com)」
 を利用して発行しています。
★バックナンバーは
      http://www.flsi.co.jp/Java_text/
 にあります。
★このメールマガジンの登録/解除は下記Webページでできます。
      http://www.mag2.com/m/0000193915.html
★このメールマガジンへの質問は下記Webページにて受け付けて
 います。わからない所がありましたら、どしどしと質問をお寄
 せください。
      http://www.flsi.co.jp/Java_text/
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Copyright (C) 2010 Future Lifestyle Inc. 不許無断複製