■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2009年10月18日

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

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


-------------------------------------------------------
・このメールマガジンは、画面を最大化して見てください。
小さな画面で見ていると、不適切な位置で行が切れてしまう
など、問題を起すことがあります。
・このメールマガジンに掲載されているソース・コード及び
文章は特に断らない限り、すべて筆者が著作権を所有してい
ます。また、これらのソース・コードは学習用のためだけに
提供しているものです。
-------------------------------------------------------


========================================================
◆ 01.SOAPのアプリケーション(Webサービス)
========================================================


では、生成されたスタブを使って、Webサービスを呼び出すWebアプリケーション
をこれから作っていきましょう。

このWebアプリケーションの処理の流れは、次のようなものとします。

(1) Webブラウザーに旅行検索のURLを入力することにより、旅行検索のため
のWebページ(travel.html)が開く。

(2) 必要な項目を指定し、送信ボタンをクリックすることにより、サーブレット
(TravelSearchServlet.java)が起動される。

(3) サーブレットはホテルの検索のために、ホテルのクラス(HotelBean.java)
を呼び出し、JSP(travellist.jsp)を起動する。

このときHotelBean.javaは、H社のホテルを検索(H社のWebサービスを呼び出す)
し、その結果のリストをtravellist.jspに渡す。

(4) JSP(travellist.jsp)はWebブラウザー上でWebページを表示し、
予約の要求を待つ。

(5) Webページで予約の要求(予約ボタンをクリック)を行うと、サーブレット
(HotelServlet.java)が起動される。

(6) サーブレットはホテルの予約のために、ホテルのクラス(HotelBean.java)
を呼び出し、JSP(reserveresult.jsp)を起動する。

このときHotelBean.javaは、H社のホテルの予約をし(H社のWebサービス
を呼び出す)、その結果のリストをreserveresult.jspに渡す。


開発の手順等はvol.077以降に行ったWebアプリケーション開発とほとんど
同様になりますので、詳しい説明は省いていきます。



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


なお、今回のWebアプリケーションでは、Log4jを使ってエラーのログなどを出力
できるようにしておきましょう。

本来ならば

http://logging.apache.org/log4j/1.2/download.html

などからLog4jをダウンロードしてインストールすべきですが、既にインストール
済みのAxisの中にLog4jのJARファイル(log4j-1.2.8.jar)が含まれているので、
ここではそれを利用しましょう。同時に、現在開発中のWebアプリケーションからも
AxisのJARファイルにアクセスできるようにする必要がある(Webサービスのスタブ
を使用しているため)ので、AxisのJARファイルをまるごとコピーして利用すること
にします。

というわけで、

C:\Tomcat6.0\webapps\axis\WEB-INF\lib

にあるAxisのJARファイル、すなわち

axis-ant.jar
axis.jar
commons-discovery-0.2.jar
commons-logging-1.0.4.jar
jaxrpc.jar
log4j-1.2.8.jar
saaj.jar
wsdl4j-1.5.1.jar

をごっそりと

C:\JavaWorks\JStudyRshaSoapClient\WEB-INF\lib

にコピーして下さい。
(ここでは、TomcatのフォルダーではなくEclipseのワークスペース内の
フォルダーにコピーしていますが、間違いではありません。
あとでEclipseからWARファイルを生成してTomcatにデプロイしますので、
結局はTomcatのほうに入ることになります。
なお、もし当Webアプリケーションだけでなく、すべてのTomcatのアプリ
ケーションからJARファイルにアクセスできるようにしたい場合は、上の
WEB-INF\libではなく、C:\Tomcat6.0\libにコピーする必要があります。)



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


では、まず最初に、HTMLファイル(travel.html)の作成から行っていきましょう。
下記のように作業を行って下さい。

(1) Eclipseのパッケージ・エクスプローラーの中のJStudyRshaSoapClientを
右クリックし、「新規」→「ファイル」を選択します。

(2) 「名前」に
travel.html
を入力し、「終了」ボタンをクリックします。

(3) パッケージ・エクスプローラーの中にできたtravel.htmlを右クリックし、
「アプリケーションから開く」→「テキスト・エディター」を選択し、
下記のようなソース・コードに編集します。

--------------------------------------------------------
<HTML>
<HEAD>
<TITLE>旅行検索のページ</TITLE>
</HEAD>
<BODY bgcolor="#77ffff" text="#fa5a00">
<H1>旅行(交通機関とホテル)検索</H1>
<FORM action="http://localhost:8080/JStudyRshaSoapClient/servlet/travelsearch" method="POST">
<BR>
出発地:
<BR>
<SELECT NAME="departurePlace">
<OPTION selected>東京</OPTION>
</SELECT>
<BR>
<BR>
行き先:
<BR>
<SELECT NAME="destination">
<OPTION selected>熱海</OPTION>
<OPTION>箱根</OPTION>
</SELECT>
<BR>
<BR>
旅行開始年月日:
<BR>
<SELECT NAME="startYYYY">
<OPTION selected>2010</OPTION>
<OPTION>2011</OPTION>
<OPTION>2012</OPTION>
</SELECT>

<SELECT NAME="startMM">
<OPTION selected>1</OPTION>
<OPTION>2</OPTION>
<OPTION>3</OPTION>
<OPTION>4</OPTION>
<OPTION>5</OPTION>
<OPTION>6</OPTION>
<OPTION>7</OPTION>
<OPTION>8</OPTION>
<OPTION>9</OPTION>
<OPTION>10</OPTION>
<OPTION>11</OPTION>
<OPTION>12</OPTION>
</SELECT>

<SELECT NAME="startDD">
<OPTION selected>1</OPTION>
<OPTION>2</OPTION>
<OPTION>3</OPTION>
<OPTION>4</OPTION>
<OPTION>5</OPTION>
<OPTION>6</OPTION>
<OPTION>7</OPTION>
<OPTION>8</OPTION>
<OPTION>9</OPTION>
<OPTION>10</OPTION>
<OPTION>11</OPTION>
<OPTION>12</OPTION>
<OPTION>13</OPTION>
<OPTION>14</OPTION>
<OPTION>15</OPTION>
<OPTION>16</OPTION>
<OPTION>17</OPTION>
<OPTION>18</OPTION>
<OPTION>19</OPTION>
<OPTION>20</OPTION>
<OPTION>21</OPTION>
<OPTION>22</OPTION>
<OPTION>23</OPTION>
<OPTION>24</OPTION>
<OPTION>25</OPTION>
<OPTION>26</OPTION>
<OPTION>27</OPTION>
<OPTION>28</OPTION>
<OPTION>29</OPTION>
<OPTION>30</OPTION>
<OPTION>31</OPTION>
</SELECT>

<BR>
<BR>
旅行日数:
<BR>
<SELECT NAME="days">
<OPTION selected>1</OPTION>
<OPTION>2</OPTION>
<OPTION>3</OPTION>
<OPTION>4</OPTION>
<OPTION>5</OPTION>
<OPTION>6</OPTION>
<OPTION>7</OPTION>
<OPTION>8</OPTION>
<OPTION>9</OPTION>
<OPTION>10</OPTION>
<OPTION>11</OPTION>
<OPTION>12</OPTION>
<OPTION>13</OPTION>
<OPTION>14</OPTION>
<OPTION>15</OPTION>
<OPTION>16</OPTION>
<OPTION>17</OPTION>
<OPTION>18</OPTION>
<OPTION>19</OPTION>
<OPTION>20</OPTION>
<OPTION>21</OPTION>
<OPTION>22</OPTION>
<OPTION>23</OPTION>
<OPTION>24</OPTION>
<OPTION>25</OPTION>
<OPTION>26</OPTION>
<OPTION>27</OPTION>
<OPTION>28</OPTION>
<OPTION>29</OPTION>
<OPTION>30</OPTION>
</SELECT>
<BR>
<BR>
旅行者人数:
<BR>
<SELECT NAME="numOfTravelers">
<OPTION selected>1</OPTION>
<OPTION>2</OPTION>
<OPTION>3</OPTION>
<OPTION>4</OPTION>
<OPTION>5</OPTION>
</SELECT>
<BR>
<BR>
<INPUT TYPE="submit" NAME="submit" VALUE="送信">
</FORM>
</BODY>
</HTML>
--------------------------------------------------------

上に新しく出てきた<SELECT>というタグは、選択肢のリストを表示するプルダウン・
メニューを作るためのもので、その選択肢の一つ一つはその下に並んでいる<OPTION>
というタグによって指定します。例えば、

<SELECT NAME="startYYYY">
<OPTION selected>2010</OPTION>
<OPTION>2011</OPTION>
<OPTION>2012</OPTION>
</SELECT>

という指定では、プルダウン・メニューで2010と2011と2012が選択項目として表示
されることになります。このうち<OPTION selected>というふうに<OPTION>タグに
selected属性が指定されているものは、デフォルトで選択状態になる項目を指示す
ることになります。

また、<SELECT>タグのNAME属性に指定した値は、vol.075で説明した<INPUT>タグの
場合と同様にパラメーターの名前としてサーブレットに渡されることになります。
また、<OPTION>タグで指定した選択項目のうち、実際にWebブラウザー上で選択
されたものは、パラメーターの値としてサーブレットに渡されることになります。
例えば、上記のstartYYYYというパラメーターの場合は、デフォルトでは2010が
選択状態になりますから、Webブラウザー上で選択状態を変えない限り2010が
startYYYYというパラメーターの値としてサーブレットに渡されることになります。

なお、上記のHTMLでは、すべての入力項目をプルダウン・メニュー式にしていま
すが、このようなやり方をすれば、入力できる値を制限できますし、ユーザーが
入力間違いを犯す(例えば半角で入力すべき数値を全角で入力してしまうなど)
ことを防ぐことができ、入力しやすくなるという点でも望ましい方法です。



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


続いて、あとで作成するクラスが参照するプロパティー値を、プロパティー・ファイル
から読み取るためのクラスを作成しましょう。

Eclipseを起動して、以下のような作業を行って下さい。

(1) Eclipseのパッケージ・エクスプローラーの中のJStudyRshaSoapClientの中の
WEB-INF/srcを右クリックし、「新規」→「パッケージ」を選択します。

(2) 「名前」に
jp.co.flsi.lecture.webapp.utility
を入力し、「終了」ボタンをクリックします。

(3) パッケージ・エクスプローラーの中にできた
jp.co.flsi.lecture.webapp.utilityを右クリックし、
「新規」→「クラス」を選択します。

(4) 「名前」に
TravelServiceProperties
と入力し、「終了」ボタンをクリックします。

(5) TravelServicePropertiesのエディターが開いたら、下記のようなソース・
コードに編集します。

--------------------------------------------------------
package jp.co.flsi.lecture.webapp.utility;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.log4j.Logger;

public class TravelServiceProperties extends Properties {

   private static TravelServiceProperties instance = null;
   private static Logger logger = Logger.getLogger(TravelServiceProperties.class);

   private TravelServiceProperties() {
      InputStream inputStream = getClass().getResourceAsStream("/travelservice.properties");
      if(inputStream != null) {
         try {
            super.load(inputStream);
         } catch (IOException e1) {
            logger.error(e1);
         }
      }
      logger.info("インスタンスを生成しました。 ...............");
   }

   public static TravelServiceProperties getInstance() {
      if (instance != null) {
         logger.info("インスタンスは既に存在します。 ...............");
      }
      else {
         logger.info("インスタンスが存在しないので生成します。 ...............");
         instance = new TravelServiceProperties();
      }
      return instance;
   }
}
--------------------------------------------------------

もうお分かりだと思いますが、これはvol.145で作成したRunModePropertiesと
同様のものですね(実際にそのソースをコピーしてから編集し直したものです)。
したがって説明は省略します。このソース・コードの意味が分からない人は、
vol.145を復習して下さい。



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


続いて、H社のWebサービスを呼び出すクラス(HotelBean.java)を作成しま
しょう。

Eclipseを起動して、以下のような作業を行って下さい。

(1) Eclipseのパッケージ・エクスプローラーの中のJStudyRshaSoapClientの中の
WEB-INF/srcを右クリックし、「新規」→「パッケージ」を選択し
ます。

(2) 「名前」に
jp.co.flsi.lecture.webapp.bean
を入力し、「終了」ボタンをクリックします。

(3) パッケージ・エクスプローラーの中にできた
jp.co.flsi.lecture.webapp.beanを右クリックし、
「新規」→「クラス」を選択します。

(4) 「名前」に
HotelBean
と入力し、「終了」ボタンをクリックします。

(5) HotelBeanのエディターが開いたら、下記のようなソース・コード
に編集します。

--------------------------------------------------------
package jp.co.flsi.lecture.webapp.bean;

import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import javax.xml.rpc.ServiceException;

import org.apache.log4j.Logger;

import jp.co.flsi.lecture.webapp.utility.TravelServiceProperties;
import jp.co.flsi.lecture.webservice.hotel.Hotel;
import jp.co.flsi.lecture.webservice.hotel.HotelService;
import jp.co.flsi.lecture.webservice.hotel.HotelServiceLocator;
import jp.co.flsi.lecture.webservice.hotel.RoomInfo;
import jp.co.flsi.lecture.webservice.hotel.RoomReserveInfo;
import jp.co.flsi.lecture.webservice.hotel.StayInfoInput;

public class HotelBean {

   private static Logger logger = Logger.getLogger(HotelBean.class);

   private RoomInfo[] roomInfos;
  
   public void setRoomInfos(RoomInfo[] roomInfos) {
      this.roomInfos = roomInfos;
   }

   public RoomInfo[] getRoomInfos() {
      return roomInfos;
   }

   public void findHotels(String startDate, int numOfNights, int numOfLodgers) throws RemoteException, ServiceException {
      HotelService locator = new HotelServiceLocator();

      Hotel hotel = null;
      TravelServiceProperties properties = TravelServiceProperties.getInstance();
      String url = properties.getProperty("WebService.URL");
      try {
         hotel = locator.getHotel(new URL(url));
      } catch (MalformedURLException e) {
         logger.error(e, e);
      }
      StayInfoInput stayInfo = new StayInfoInput();
      stayInfo.setStartDate(startDate);
      stayInfo.setNumOfLodgers(numOfLodgers);
      stayInfo.setNumOfNights(numOfNights);
      stayInfo.setMinRatePerNight(-1);
      stayInfo.setMaxRatePerNight(-1);
      setRoomInfos(hotel.findRooms(stayInfo));
   }

   public boolean reserveHotel(int roomNum, String startDate, int numOfNights, int numOfLodgers,
                               String name, String address, String telNo) throws RemoteException, ServiceException {
      HotelService locator = new HotelServiceLocator();

      Hotel hotel = null;
      TravelServiceProperties properties = TravelServiceProperties.getInstance();
      String url = properties.getProperty("WebService.URL");
      try {
         hotel = locator.getHotel(new URL(url));
      } catch (MalformedURLException e) {
         logger.error(e, e);
      }

      RoomReserveInfo roomReserve = new RoomReserveInfo();
      roomReserve.setAddress(address);
      roomReserve.setName(name);
      roomReserve.setNumOfLodgers(numOfLodgers);
      roomReserve.setNumOfNights(numOfNights);
      roomReserve.setRoomNum(roomNum);
      roomReserve.setStartDate(startDate);
      roomReserve.setTelNo(telNo);
      if (hotel.reserveRoom(roomReserve)) {
         return true;
      }
      else {
         return false;
      }
   }
}
--------------------------------------------------------

このソース・コードのうち、

      stayInfo.setMinRatePerNight(-1);
      stayInfo.setMaxRatePerNight(-1);

という行は、アプリケーションを簡単にするために(検索条件としての)
最低料金と最高料金の指定を省略したものです。(vol.148で説明したよう
にこれらに負の値(ここでは-1)を指定すると省略したことを意味します。
なお、こういったWebサービスの仕様は、H社が利用者にWSDLと一緒に説明
の文書を提供しておくべきものです。)

残りのコードは説明しなくても理解できますね。

なお、このソース・コードでは、先ほど作成したTravelServicePropertiesを使って、
WebサービスのURLを、プロパティー・ファイルの"WebService.URL"というプロパティー
の値から読み出していますね。
したがって、プロパティー・ファイル(travelservice.properties)を作成しておく
必要があります。
C:\JavaWorks\JStudyRshaSoapClient\WEB-INF\classesフォルダーの配下に、
下記のような内容のtravelservice.propertiesを作成して下さい。

--------------------------------------------------------
WebService.URL=http://192.168.0.5:8080/axis/services/Hotel
--------------------------------------------------------

ただし、上記の192.168.0.5の部分は筆者の環境におけるLinux(CentOS)のPC
のIPアドレスですから、この部分は読者の環境に合わせて書き換えて下さい。


また、同じフォルダー配下にLog4jのプロパティー・ファイル(log4j.properties)
も下記の内容で作成しておきましょう。

--------------------------------------------------------
log4j.rootLogger=INFO, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=*%-5p [%d] %c.%M: %m%n
--------------------------------------------------------



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



(次回に続く)


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



======================================================
◆ 02.演習問題
======================================================

上のHotelBeanのソース・コードでは、findHotels()メソッドと
reserveHotel()メソッドの先頭の何行かのコードが重複してい
ますね。
これを重複しないように、もう少しすっきりしたソース・コード
に修正してみて下さい。
[ヒント:重複した部分を別のメソッドに切り出す。]



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      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) 2009 Future Lifestyle Inc. 不許無断複製