javaの最近の情報

 Google App Engine for Java「実践」クラウドシステム構築

 

著者: 株式会社グルージェント

発行日: 2009年10月10日

発行者: 片山 巌

発行所: 株式会社技術評論社

310ページ

2,480円+税

 

 内容

Googleのスケーラビリティを案件で使い切る。活用の秘訣は、「制約」を正しく

理解すること。割り当てと制限、BigTableによるDB構築、課金のしくみ、

Google Apps、GDataとの連携、Memcache、Mail・・・API活用

 

ポイント

Window Azureサービスも開始され、クラウドサービスもビジネスだけではなく、個人的な

利用についても十分現実的なものになっていきている。Windows Azureも魅力的であるが

まだまだ情報も少なく、個人的に試してみるのは、まだ先かなぁと思う。

 

そんな中、やはり無料で使用でき、導入が容易、機能も豊富なサービスといえば、

Google App Engine for Javaでしょう。特にJava Webアプリケーションサーバの

実行環境が無料で利用できるというのは、Javaユーザにとっては、特にありがたい

でしょう(レンタルサーバでもJavaの実行環境が提供されるのは稀なので)

一定の使用量を超えると課金になるが、そこそこヘビーなアプリケーションでなければ、

制限を超えることはないと思う。ぜひ一度試してください。

 

本書では、こういった、サービスの基本的な内容、課金について、導入手順などはもちろん、

サービスの各機能の使用方法のポイントを、わかりやすく説明されているので、このサービス

の素晴らしさが実感できると思う。

 

とりあえず、触ってみたいという方は、Eclipse環境で導入可能なので以下参照してください。

http://pg2se.com/site/2009/07/google-app-engine-for-java.html

 

内容詳細

第1章 クラウド時代のシステムインテグレーション

1.1 クラウドコンピューティング

1.2 Google App Engine

1.3 Google App Engine for Java

 

第2章 制約

2.1 Quota(割り当て)とLimit(制限)

2.2 Java APIに対する制約

 

第3章 クラウド時代のシステムインテグレーション

3.1 GAEアカウントの作成とデプロイの準備

3.2 開発環境の構築

3.3 アプリケーションの作成とデプロイ

3.4 アプリケーションの設定

3.5 アプリケーションの管理

 

第4章 データストア

4.1 BigTable

4.2 JDOによるデータストアの操作

4.3 インデックス

4.4 トランザクション

4.5 JDO以外のデータストアAPI

4.6 データストア設計上の注意点

 

第5章 サービスAPI

5.1 Memcache API

5.2 URLフェッチ API

5.3 Images API

5.4 Mail API

 

第6章 テスト

6.1 ユニットテスト

6.2 ローカル環境でのテスト

6.3 実環境でのテスト

6.4 パフォーマンスの確認

 

第7章 GAEが提供するサービスとの連携

7.1 GAEが連携可能なGoogleアプリケーション

7.2 アカウント認証サービスとの設定

7.3 Google Calendarとの連携

7.4 GAE/Jアプリケーションを独自ドメインで運用

7.5 Secure Data Connector

 

第8章 追加リソースの購入

8.1 Billingの体系

8.2 Billingの設定

8.3 課金量の予測

 

2009年9月7日、オープンソース給与・勤怠システム「MosP」の

フレームワークとAPIが公開された。

MosPは、Mind Open Source Project の略で、「モスプ」と呼ぶ。

 

MosPはマインドが開発し公開しているJava Webアプリケーションであり、

Strutsと同様にMVCアーキテクチャをとる構造となっている。

 

画面サンプル

mosp0.jpg

mosp1.jpg

 

フレームワークの特徴

Action基本クラスは簡易ワンタイムパスワード機能や認証情報確認機能等を備えて

おり、データベースにアクセスするためのクラスとしてDaoとDtoクラスがある。

またjOpenDocumentを利用したOpenOffice.org帳票作成クラスと、Apachi POIを

利用したMicrosoft Excel帳票作成クラスがある。OpenOfficeまたはExeclで作成

したテンプレートに値を埋め込んで帳票を作成できる。

 

ドキュメントとして、アプリケーションの作成方法を記述した「MosPフレームワーク

手順書」と、APIのドキュメントが用意されている。 また、開発者向けにコミュニティ

MosP Developer's Communityを開設されており、情報を入手することができる。

 

標準機能(給与計算)
・SaaS基盤対応    ・賞与計算
・勤怠データ取込   ・個別賞与計算
・給与計算       ・賞与情報一覧
・個別給与計算    ・賞与明細出力
・給与情報一覧    ・賞与データ出力
・給与明細出力    ・社員賞与情報管理
・給与明細出力    ・賞与項目管理
・給与データ出力   ・MosP連携
・社員給与情報管理
・給与計算情報管理
・給与項目管理

標準機能(勤怠管理)

・SaaS基盤対応    ・個人情報登録
・出勤入力       ・MosP連携
・退社入力
・休暇入力
・有休管理
・確認変更
・承認機能
・帳票印刷
・スケジュール登録
・エクスポート
・基本情報登録

 

勿論、業務としてMospを採用するのは、それぞれの会社や、個人個人で、

意見は分かれるだろうが、オープンソースでどのように、給与システムや

勤怠管理システムが作られているかは技術者としては気になるところです。

 

 

Googleのインフラでウェブサービス(ウェブアプリケーション)が利用できる、

「Google App Engine for Java」が2009年4月に遂に公式発表された。

(最初の言語としてにPythonが2008年に公開されています)

 

スクリプト言語ではなく、JavaのWebコンテナ上でのバイトコードでの動作が

提供されるのは驚きです(もちろんセキュリティ上の制限はあるようです)

 

JSP、Servletはもちろん、JavaVMで動作することから、JRuby、Jython、Groovy、

Scala、Quercusなどを利用して、各種スクリプト言語も動作させることができそうです。

 

まずは、「Google App Engine for Java」を利用するまで進めてみたいと思います。

 

1.必要な環境

  Eclipse3.3、または、Eclipse3.4

  Google App Engine のアカウント

  ※インストール・取得方法は割愛します。

 

2.Eclipseへのプラグイン追加

    • [ヘルプ]-[ソフトウェア更新] メニューを開きます。
    • [使用可能なソフトウェア] タブを選択し、[サイトの追加] ボタンを押します。
    • [ロケーション] に、次の内容を入力し、[OK] ボタンを押します。
    • [Google Updates Site for Eclipse] が追加されるので、チェックボックス
      に、チェックを入れ、[インストール] ボタンをクリックします。
    • [次へ]で進み、ライセンス確認をすると、インストールが開始されます。
      ※インストール後、Eclipseを再起動をするようになります。
    • Eclipseのツールバーに、次のような、Google App Engine のツールが
      表示されていると準備完了です。
    • 20090705.jpg 

 

3.プロジェクトの作成

    • Google App Engine ツールの、左端のボタンをクリックすると、
      新規プロジェクト作成のウィザードが開始されます。
    • [Project Name] [package] を任意で指定して、[終了] ボタンを押します。
      ワークスペースに、[Project Name] で指定したプロジェクトが作成されま
      す。

 

4.プロジェクトの実行

    • ワークスペースの、プロジェクト名を右クリックして表示されるメニューの、
      [実行]-[3.Web Application] をクリックします。
    • ウィンドウが2つ起動されます。
      a)AppEngine server ...デバッグ実行用のサーバコンテナ
      b)デフォルトアプリケーションの画面(簡易ブラウザ)
    • デフォルトアプリケーションはGWTで実装されたAjaxのサンプルです。
      ->ボックスに入力し[Send]ボタンを押すとAjaxでメッセージが表示されます

※このデフォルトのソースを変更して、自分のアプリケーションを開発していきます。

※[デバッグ]メニューで実行すると、クライアント、サーバどちらもデバッグできます。

※簡易ブラウザでなく、同じURLをほかのブラウザに入力しても実行できます。
   ->コンパイルが必要です(ツールの真ん中のボタンをクリック)

 

5.アプリケーションの公開(デプロイ)

    • Google App Engine のアカウントを取得してログインします。
    • [Create an Application] ボタンを押します。
    • [Application Identifier] [Application Ttitle] を入力し、[Save] を押す。
      ->IDはGoogle Appspotのサブドメインなので世界でユニークな設定になります
    • 次に、Eclipseの設定です。ワークスペースのプロジェクトを右クリックし、
      [Google]-[App Engine Settings] メニューを開き、以下を入力します。
      [Application ID]-> 先に設定した[Application Identifier]を入力します。
      [Version]-> ユニークな番号を指定し、[OK]ボタンを押します。
    • デプロイを実行します。同じく[Google]メニューから、[Deploy to App Engine]
      を選択するか、ツールの右端のボタンを押します。
    • Google App Engineで登録した[Email]、と[Password]を入力し、[Deploy]
      ボタンを押すとデプロイが実行されます。
    • [コンソール] ウィンドウの最後に"Deployment completed successfully"
      と表示されればデプロイの完了です。

 

6.アプリケーションの実行

    • アプリケーションはインターネットを通じて、世界中に公開されます。
    • 公開されるアドレスは、http://[Application Identifier].appspot.com/ です。
      ->[Application Identifier] は、先に設定したIDです。
      ※ちなみに私の場合、http://appcontents.appspot.com/ で公開してます。
      ※GWTのUIを利用する際に日本語を設定すると文字化けしますので、
      ソースコード(リソース)の設定をUTF8にすると回避できます。


以上、Google App Engine for Java を利用する方法を書きました。

※とっても簡単にGoogleのインフラを利用したWebアプリケーションの開発ができる

ことが分かってもらえたかと思います。

 

JavaVMの環境が提供されているので、これを利用して、様々なサービスを

提供できる可能性が広がっています!!

 

<html:base>タグ

<html:base>タグは、Struts1で用意されていたタグライブラリである。

このタグは、HTMLの<base>タグを出力するためのタグです。

<base>タグは、<head>タグ内で記述し、<base href="[絶対パス]"> という書式になります。このタグは、HTMLファイルに相対パスで記述されたURIの基準となるURIを指定します。基準となるURIは、[絶対パス] 部分で指定された絶対パスです。

 

Struts1

このタグは、リクエスト時にフィルターの機能を用い、URL書き換えをおこなう場合に便利です。URL書き換えをした場合に、見かけ上のURLの階層が変わってしまったりすると、相対パスで記述しているリンクや、画像ファイルが正しくリンクされないようになってしまうからです。

この時に<html:base/>タグを記述していると、相対パスの基準となるURIが固定される(出力されるファイルの階層に固定される)ため、URL書き換えで見た目のURLの階層がいくら変化しても、各リソースのリンクには全く問題がなくなります。

 

Struts2

Struts2のタグライブラリには残念ながら、<html:base>に代わるものが存在しません。これは、画像やリンクなどの各リソースのURLの指定をするために、<s:url value="[リソース]"> タグを使うことで、<base> タグを指定する必要がなくなるためだからだろうと思いました。

しかしながら、各リソースのURLを動的に指定する必要がある場合、value属性に、<s:property> タグを入れ込んだりしての、URLの動的作成がうまくいきませんでした(もしかしたら、うまくやれば可能なのかもしれません...) さらに、フィルターによるURLの動的書き換えを組み合わせると、URLが2重になったりと先が見えなかったので、Struts1のように<base>タグを自前で出力させる方法を考えました。

 

<base>タグの出力

発想はいたって単純ですが、フィルターの処理中に、ベースとなるURLをrequestオブジェクトに保存しておき、viewの部分でそれを取り出し、<base>タグのhref属性に指定してあげるという方法です。

ポイントはベースとなるURLをどのように作成するところですが、以下のようにすることで簡単に求められそうです。

 

  //ベースURLの設定
  String url = req.getRequestURL().toString();
  int len = url.length() - req.getRequestURI().length();
  req.setAttribute("htmlbase",  url.substring(0, len) + req.getContextPath() + "/");

 

そして、viewでは以下のように呼び出すだけです。

   

    <%@taglib prefix="s" uri="/struts-tags" %>

    <head>

        <base href="<s:property value="#request.htmlbase"/>"/>

    </head>

 

以上で、Struts1の<html:base/>の処理と同様のことができるようになりました。

※他にもっと良い方法があるかもしれませんが、リソースのURLを動的に作成したり、フィルターにてリクエストのURLを書き換えてフォワードさせたりという処理を組み合わせると、思うような処理ができませんでした。

 

また、Struts2で、リクエストのURLを書き換え、フォワードしてアクションを実行させようとしてもできないトラブルの解決方法は以下を参照ください。

Struts2 RequestDispatcher の動作について

 

getRequestDispatcher foward

Strutsをはじめ、上記のようにリクエストのフォワーディングをおこなうことは少なくないのではないでしょうか?URLReWriteのような形で特定のURLパターンにマッチした場合にアドレスを変換したり、*.html のアドレスでアクセスされた場合に内部的には、*.jsp や、*.do などの動的な処理に転送したい場合などが考えられる。

また、サイトにアクセス制御がかけられている場合は、認証されていない場合にログイン画面に転送するなどにも利用される。

 

Struts2での問題

ここで今まで利用してきた Struts1では、上記のような処理を、通常、web.xml で設定された、フィルターの機能を利用しておこなっていた方も多いのでしょうか?これは非常に簡単なコーディングにてリクエストの転送を問題なくおこなえていました。

 

web.xml

  <filter>
    <filter-name>accessFilter</filter-name>
    <filter-class>com.pg2se.AccessFilter</filter-class>
  </filter>
 
  <filter-mapping>
    <filter-name>accessFilter</filter-name>
    <url-pattern>/security/*</url-pattern>
  </filter-mapping>

  <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

com.pg2se.accessFilter#doFilter

  if (checkLogin == false) {

    request.getRequestDispatcher("/login.do").forward(req, res);

  } else {

    chain.doFilter(req, res); 

  }

 

同様の処理を Struts2 に移植または実装しようとした際に、何も考えずコーディングした場合に、リクエストのフォワードがうまく動作しない現象が発生してしまうのではないでしょうか?

 

具体的には、

request.getRequestDispatcher("/login.action").forward(req, res);

 

と記述しても、

"/logon.action" is not available

 

となってしまいます。最初は原因はわからなくて戸惑うかも知れませんが、これは、Struts1 と Struts2 のアクションが起動される仕組みが変更されているからです。

 

web.xml

 <filter>
  <filter-name>AccessFilter</filter-name>
  <filter-class>com.pg2se..AccessFilter</filter-class>
 </filter>

 

 <filter>
  <filter-name>struts2</filter-name>
  <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
 </filter>

 

 <filter-mapping>
  <filter-name>AccessFilter</filter-name>
  <url-pattern>/security/*</url-pattern>
 </filter-mapping>
 

 <filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

 

Struts2 では、一般的に、上記のように記述しているのではないでしょうか?

この、Struts1 の記述と、Struts2 での記述の違いをみると、アクションの起動が、Struts1 では、servlet-mapping が利用されているのに対し、Struts2 は、filter-mappping を利用しているという点です。

 

AccessFilter の中で、Struts1と同じように、getRequestDispatcherで、foward をおこなっても、アクションは起動されないようになっている。なぜなら、Struts2 では、アクションはフィルターで動作するようになっおり、デフォルトでは、リクエスト時にはフィルターが呼び出されるが、foward時にはフィルターが呼び出されないようになっているからである。

 

これを回避するのは意外と簡単で、web.xml で設定できる。

設定の詳細はこちらのページで詳しく書かれています。

 

web.xml

 <filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*</url-pattern>
  <dispatcher>FORWARD</dispatcher>
  <dispatcher>REQUEST</dispatcher>
 </filter-mapping>

 

アクションの、filter-mapping にて、<dispatcher>要素を記述する。

記述できる値は、REQUEST、FORWARD、INCLUDE、ERROR である。

ここで、FORWARDを指定すれば、getRequestDispatcher#foward をおこなった際にも、

該当のフィルターが起動され目的の処理をおこなうことができるようになる。

 

 

はじめに

今回はStruts2を利用した、より実践的なアプリケーションの作成をおこなってみたいと思います。今回も前回と同様、ZeroConfigurationで開発をおこなっています。

Struts2の開発の準備がまだ整っていない場合は以下も参考にしてください。

 

このアプリケーションの解説の中では今後さらにしっかりとしたアプリケーションを開発していくにあたってのポイント、改良点なども記述していますので是非参考にしてください。

 

アプリケーションの概要

このアプリケーションは、シンプルな掲示板アプリケーションです。

複数の端末から共通の掲示板に情報を書き込み、その内容を共有するという単純なものです。情報には、投稿者の名前とメッセージ、そして投稿日時と投稿した端末のIPアドレスを自動で取得した内容が含まれます。

アプリケーションの仕様について簡単にまとめます

  • 掲示板のURLにアクセスすると現在の掲示板の情報が一覧表示されます。
  • "更新"ボタンを押すと、掲示板の情報が最新表示されます。
  • 掲示板の情報は、投稿日が新しいものから順に表示されます。
  • "名前"と"メッセージ"を任意に入力し、"投稿"ボタンを押すと、掲示板に情報が
    登録され、掲示板の内容が最新表示されます。
  • "名前"、"メッセージ"のいずれかが未入力の場合はエラーメッセージが表示され
    掲示板に情報は登録されません。

 

  • アプリケーション画面

simple_board.jpg 

 

ソースコード解説

シンプルな機能の掲示板ではありますが、アプリケーションとしてはMVCモデルを意識し、今後の拡張性も含めながら作成してみました。

 

  • モデル

BoardData .java

掲示板へ登録する情報を格納するデータを保持するクラスです。

データの保持以外の機能は特にありません。  

package com.pg2se.sample.model.board;

public class BoardData {

    private String postDate;
    private String name;
    private String message;
    private String remoteAddress;
   

 public String getPostDate() {
  return postDate;
 }
 public void setPostDate(String postDate) {
  this.postDate = postDate;
 }
 
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 
 public String getMessage() {
  return message;
 }
 public void setMessage(String message) {
  this.message = message;
 }
 
 public String getRemoteAddress() {
  return remoteAddress;
 }
 public void setRemoteAddress(String remoteAddress) {
  this.remoteAddress = remoteAddress;
 }

}

 

Board.java

複数の端末で共有する掲示板のオブジェクトと掲示板に情報を登録する機能を持ったクラスです。

package com.pg2se.sample.model.board;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Vector;

public class Board {

    private static List<BoardData> board = new Vector<BoardData>();
    private static SimpleDateFormat sdformat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    
    public static List<BoardData> addChatData(String name, String message, String remoteAddress){
     BoardData data = new BoardData();
     data.setName(name);
     data.setMessage(message);
     data.setRemoteAddress(remoteAddress);
     data.setPostDate(sdformat.format(new Date()));
     board.add(0, data);
     return board;
    }
    
    public static List<BoardData> getChatData(){
     return board;
    }

}

 

  • ビュー
  • board/board.jsp

    掲示板への情報の投稿と掲示板の情報の表示をおこないます。

     

    入力エラーの内容は<s:actionerror/>タグによって出力されます。

     

    "ValueStack"をコードで記述している部分ですが、board.jspをアドレスに指定されて呼び出された場合にアクションが呼び出されず掲示板の最新情報が取得できていないため無理やり取得しています。Struts1の場合は、フォームに関連付けられたformbeanが初期化されるため初期表示も可能だったんですが...。もっと良い方法あればいいんですが。

     

    また、"remoteAddress"をここで取得していますが詳細は後述します。

     

    ボタンは情報投稿用のボタンと、最新情報取得用の更新ボタンがありますが、method属性を指定して、呼び出すアクションクラスのメソッドを指定できます。

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <%@page import="com.pg2se.sample.model.board.Board"%>
    <%@page import="com.opensymphony.xwork2.util.ValueStack"%>
    <%@page import="org.apache.struts2.ServletActionContext"%><html>
    <%@taglib prefix="s" uri="/struts-tags" %>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>シンプル掲示板</title>
    </head>
    <body>
        <h1>シンプル掲示板</h1>
        <h2>struts2で作成するサンプルアプリケーション</h2><hr/>
       
        <s:form action="board.action" theme="simple">
          <input type="hidden" name="remoteAddress" value="<%= request.getRemoteAddr() %>"/>
          <s:text name="名前"/> <s:textfield name="name" size="10"/>
          <s:text name="メッセージ"/> <s:textfield name="message" size="60" value=""/>
          <s:submit value="投稿"/><s:submit value="更新" method="update"/>
        </s:form><hr/>
       
        <s:actionerror/>
       
        <table border="1">
     <%
      ValueStack stack = (ValueStack)request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
      if(stack!=null && stack.findValue("data")==null){
       stack.set("data", Board.getChatData());
      } 
     %>
        <s:iterator value="data" status="stat">
            <s:if test="#stat.first">
              <th>日時</th>
              <th>名前</th>
              <th>テキスト</th>
              <th>IPアドレス</th>
            </s:if>
            <tr>
              <td><s:property value="postDate"/></td>
              <td><s:property value="name"/></td>
              <td><s:property value="message"/></td>
              <td><s:property value="remoteAddress"/></td>
            </tr>
        </s:iterator>
        </table>
    </body>
    </html>

     

    • コントローラ

    BoardAction.java

    掲示板の情報の登録と最新表示をおこなうためのアクションです。

     

    メッセージの投稿用にはデフォルトのアクションexecuteメソッドを、最新情報取得用のアクションにはupdateを使用します。

     

    ActionSupportクラスを継承することで、validation(バリデーション:検証)やメッセージ・エラーメッセージを簡単に設定することができます。validateメソッドを実装するだけでよいのですが今回は使用しませんでした。理由は、validateメソッドはすべてのアクションに対して実行されてしまうため、今回バリデーションの必要がないupdateメソッドに適用されたくなかったためです。今回は自前のisValidメソッドで検証をおこなっています。※xmlファイルでバリデーションの定義をする場合は検証を除外するメソッドを設定できたりするようです。他にも方法はあるようなのですがわかりませんでした、

     

    "remoteAddress"についてはjspファイルから渡されるようにしています。本来はアクションクラスで、requestオブジェクトから取得したいのですがActionSupportクラスからは取得できないようです。取得するためには、ServletRequestAwareインターフェイスを実装する必要があります。そうすると実行時にHttpServletRequestオブジェクトが注入されるようです。

     

    今後の拡張として、掲示板の情報の編集・削除等のメンテナンスや掲示板の情報をデータベースへ保存し永続化するという点が考えられます。

    package com.pg2se.sample.action.board;

    import java.util.List;
    import com.opensymphony.xwork2.ActionSupport;
    import com.pg2se.sample.model.board.Board;
    import com.pg2se.sample.model.board.BoardData;

    public class BoardAction extends ActionSupport {

     private String name;
        private String message;
        private String remoteAddress;
        private List<BoardData> data;
     private static final long serialVersionUID = 1L;
       
     public String getName() {return name;}
     public void setName(String name) { this.name = name;}

     public String getMessage() {return message;}
     public void setMessage(String message) {this.message = message;}
     
        public String getRemoteAddress() {return remoteAddress;}
     public void setRemoteAddress(String remoteAddress) {this.remoteAddress = remoteAddress;}

     public List<BoardData> getData() {return data; }
     public void setData(List<BoardData> data) {this.data = data;}
     
     //execute
     public String execute() {

      if(isValid()){
      
          data = Board.addChatData(name, message, remoteAddress);
         
         } else {

          data = Board.getChatData();
         }
      
         return "success";
        }
     

     //update
     public String update() {
      
      data = Board.getChatData();
      
      return "success";
        }
     
     //validate
     public boolean isValid() {
      if(name == null || name.equals("")){
       addActionError("名前を入力してください");
      }
      if(message == null || message.equals("")){
       addActionError("メッセージを入力してください");
      }
      
      return !hasActionErrors();
     }
    }

    長いタイトルですが

    やりたいこととしては、サーバーサイドで表題の処理をおこない、

    ADOのレコードセットをクライアントに返したいということです。

    ADOのレコードセットのシリアライズ方法にXMLデータを利用します。

     

    ADODB.Recordset

    ADOは、Windows環境(ExcelやAccess等のVBA)で多く利用され、

    レコードセットのデータを簡単に加工したり、張り付けたりすることができるように

    なっています。また、ADOのレコードセットには標準でXMLへの入出力機能があり、

    簡単にシリアライズ・デシリアライズ化することができます。

     

    本題

    上記のXMLデータを用いて、直接ADO接続でDBMS(Oracle等)に接続する環境が

    クライアント側になくても、サーバサイドよりADOのレコードセットをシリアライズした

    XMLをクライアント側に返すことで、クライアント側で、ADOのレコードセットを自由に

    利用することができるようになるということです。

    一種のWebサービスとしての利用と言えます。

     

    COM

    それではなぜ、COM(Component Object Model)かというと、もちろん、COMを

    利用しなくても、Dom等を用いて、Javaの標準のライブラリでもADO仕様のXMLを

    生成することは可能なのですが、サーバーサイドでも同じADOの機能を用いた処理

    を行うことで手順がすっきりとし、生成されたXMLデータの互換性もほぼ問題は

    発生しないという点、パフォーマンス的にも有利ではないかという点でComを選択

    してみました。

    ※もちろんこの時点でサーバサイドもWindows環境に限定されてしまうことになり

    ますが、ADO以外にもComを利用した様々なWebサービスを提供できそうです。

     

    準備

    JavaでComの操作をするためのライブラリとしては、JCom(Java-COMブリッジ)

    利用しています。まず、まずComを呼び出すためのNativeのライブラリ、jcom.dll

    を、"java.library.path"上に配置します。jcom.dllは上記ライブラリに含まれます。

    また、"java.library.path"の確認は、

    System.getProperty("java.library.path")

    で確認するか、または、

    -Djava.library.path=

    で設定します。

    通常、SystemやSystem32がこれに含まれます。

    次に、jcom.jarをライブラリパスに設定し、これでjavaからCOMの操作をする

    準備の完了です。

     

    サンプル

    以下は、JCom経由でADOにてMSSQLServerに接続し、SQLを発行して

    レコードセットを取得します。取得したレコードセットは、Saveメソッドにて、

    ファイルに保存します(Saveメソッドの2つめの引数"1"がXML形式での保存を

    意味します。

      ReleaseManager rm = new ReleaseManager();
      
      try {
       //ADOConnectionの作成
       IDispatch con = new IDispatch(rm, "ADODB.Connection");
          
       //ConnectionStringの設定
       con.put("ConnectionString", "Provider=Sqloledb;Data Source=(local)\\SQLEXPRESS;Initial Catalog=dbname;Connect Timeout=15;user id=sa;password=");

       //データベースへ接続
       con.method("Open", null);
       
       //SQLの実行
       IDispatch rs = (IDispatch)con.get("Execute", new Object[] {"SELECT * FROM 商品マスタ"});
       
       //XML形式で出力
       rs.method("Save", new Object[] {"C:\\excel.xml", 1});
       
       //解放
       rs.method("Close", null); 
       con.method("Close", null);
      }
      
      catch(Exception e) {
       System.out.println(e.getMessage());
       e.printStackTrace();
      }

      finally {
       rm.release();
      }

     

    Java Servlet 3.0 Specification

    Public Review Ballotのフェーズを賛成多数で通過したが、

    ASF(Apache Software Foundation)は、反対票を投じている。

    しかし、ASFの反対票は技術的な問題ではなく、

    政治的な問題によるものだといわれている。

     

    Java Servlet 3.0 機能概要

    次期Servletとなる3.0でどういった機能が実現されるのかの概要で、

    特に興味深いトピックをまとめると次のとおりである。

     

    • Servlet 3.0 は、現在のServlet 2.5のアップデートバージョンであり、
      Java EE 6に取込まれる
    • Webフレームワークにプラガブル性や拡張性を提供する
    • 非同期処理のサポート登場
      (JDBC/Wev Service等リソース待ち機能。非同期レスポンス、非同期関連クラス導入)
    • 新しいアノテーションの導入によるEoDの推進
    • 単一のweb.xmlファイルから複数のファイルを含めるweb-fragment.xmlファイルの導入
    • HTTPServletRequestを拡張。ログインとログアウトのプログラマティックな処理を実現
    • Servletおよびフィルタを追加するメソッドの登場
      (ServletContext#addFilter, ServletContext#addServlet)

     

    機能詳細ピックアップ

    • プラグインの容易性(Pluggability)
      web.xmlのモジュール化(ファイルの分割)
      ServletContextにServletとFilterの宣言とマッピングを定義するメソッドが追加
    • 開発の容易性(Ease of development)
      Servletは、アノテーション@Servletにより定義可能。これにより大幅に記述量を
      減らす事ができる。また@GET、@PUTを指定する事で、任意のメソッドをhttpの
      GETやPUT時のメソッドに指定する事ができる
      FilterとFilterのマッピングについては、@ServletFilterと@FilterMappingの
      アノテーションで宣言する事が可能
      Context Listnerについても、@ServletContextListnerアノテーションで宣言可能
    • 非同期Servletのサポート(Async servlet support)
      非同期Servletは、Cometスタイルのアプリケーションや、非同期Webプロキシー、
      非同期Webサービスでの利用が想定されており、requestのsuspendや
      resumeを可能にする。ServletRequest、RequestListner、ServletResponseへ
      非同期メソッドの追加
    • セキュリティのエンハンス(Security enhancements)
      セキュリティとして、ログイン、ログアウトを可能にするため、loginとlogoutのメソッド
      を次のクラスに追加する。HttpServletRequest 、HttpServletRequestWrapper、
      HttpSession (logout only)
    • HttpOnlyCookieのサポート
      クライアントサイドスクリプティングからのcookieへのアクセスを防ぎ、また、
      クロスサイトスクリプティング攻撃を防ぐ
    • session tracking cookieの設定を可能
      session tracking cookieの設定を可能にし、多数のsession trackingの
      サポートも行う

     

     ドキュメント、API

    Servlet 3.0 の草案段階にあるAPIマニュアルと解説ドキュメントはJSR 315 から

    ダウンロードできるようになっている。

    Servlet 3.0 JSR315

     

    Zero Configuration

    それでは、Struts2での最初のアプリケーションを作成してみたいと思います。

    Struts2の特徴の一つに"Zero Configuration"があります。

    これは、Struts1で、xml地獄と呼ばれた、一連のアクションを実行するため、

    各コンポーネントを連携するために必要な設定を、xmlの設定ファイルで記述し、

    その設定ファイルが膨大になってしまいがちになる短所を改善するための機構

    です。

     

    Struts1で、JSP-ActionForm-Action-JSPの連携を全てstruts-config.xmlで設定

    していたものを、Struts2では、JSP-POJO-JSPの最小構成で、連携の設定を

    記述することなく動作させることができます。

     

    では具体例を見ていきましょう。

     

    Hello World!!

    例の如く、簡単なHello World!!アプリケーションを作成していきます。

    ポイントを絞って説明しますので不足点あればコメント欄で質問ください。

    (環境)

    eclipse3.4.1(tomcatPlugin)

    jdk1.6.0_02

    tomcat-6.0.14

    struts2.0.14

     

    20090118.jpg

    1. プロジェクトの作成
      "動的Webプロジェクト"を選択しプロジェクトを作成します。
      注)デフォルトの、classesディレクトリがWEB-INFの外にあり、そこに後述の
      struts.xmlを配置しても認識されなかったので、classesは、WEB-INFの下に
      設定してください。

      ライブラリを配置します。struts2のファイルの中から以下をlibに配置します。
      ・commons-logging-1.0.4.jar
      ・freemarker-2.3.8.jar
      ・ognl-2.6.11.jar
      ・struts2-codebehind-plugin-2.0.14.jar
      ・struts2-core-2.0.14.jar
      ・xwork-2.0.7.jar
      ※codebehindプラグインが、Zero Configurationのミソで、JSPが配置されている
      ディレクトリとアクション名より自動的にアクションクラス(POJOでも可)を探します。
      またアクションクラス名と戻り値にて自動的にJSPファイルを探します。

    2. Web.xml
      ポイントは、Struts1と同様、フィルターおよびパターンにてリクエストをStruts2で処理
      できるように設定を書いている点と、またまたZero Configurationの肝になる、
      actionPackagesというパラメータ設定です。ここにパッケージ名を記述しますが、
      指定したパッケージが、Webアプリケーションのトップディレクトリと同じ階層となり
      JSPとアクションの自動での紐づけの対象となります。
      例えば、/webapp/index.jsp の中で、"index.action"を呼び出すと、
      (actionPackages).IndexAction クラスの execute メソッドを実行しようとします。
      下の私の例では、com.pg2se.sample.action を指定していますので、
      com.pg2se.sample.action.IndexAction#executeメソッドが呼び出されます。
      ※何も設定していなければ"execute"メソッドが呼び出されます。

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app id="WebApp_ID" version="2.4" xmlns="
      http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
       
      <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
        <init-param>
          <param-name>actionPackages</param-name>
          <param-value>com.pg2se.sample.action</param-value>
        </init-param>
      </filter>
      <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>

      <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
      </web-app>


    3. Struts.xml
      Struts.xmlは、classesの直下に置くことで認識されます。冒頭で書いたように、
      WEB-INF以下に配置しないとうまく動作しませんでしたので適宜設定を変更
      してください。
      ※Zero Configurationで作成するため、記述は最低限の以下だけでOKです。

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE struts PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
          "
      http://struts.apache.org/dtds/struts-2.0.dtd">
      <struts>
          <constant name="struts.enable.DynamicMethodInvocation" value="true" />
          <constant name="struts.devMode" value="false" />
      </struts>


    4. index.jsp
      今回は、Webアプリケーションのトップディレクトリのindex.jspにアクセスし、ボタンを
      押すと、"Hello World!!"のメッセージが表示される簡単なアプリケーションにしています。
      ポイントは、Struts2のタグライブラリ(プレフィックス:s)の宣言をしている点と、
      Formのアクション設定に"index.action"を設定している点、プロパティ"message"を
      表示している点です。最初にJSPにアクセスした場合はプロパティは設定されていま
      せんのでボタンのみ表示されます。

      <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
      <%@ taglib prefix="s" uri="/struts-tags" %>
      <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "
      http://www.w3.org/TR/html4/loose.dtd">
      <html>
        <head>
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
          <title>Struts2</title>
        </head>
        <body>
          <s:form action="index.action" theme="simple">
            <s:property value="message"/><br/>
            <s:submit value="メッセージ"/>
          </s:form>
        </body>
      </html>


    5. IndexAction.java
      ここでのポイントは、パッケージの設定を、actionPackagesパラメータに
      合わせている点と、Actionの実行設定をしていない際のデフォルトで実行
      される、executeメソッドを実装している点と、ActionFormが無くなった
      代わりに、このクラスにプロパティを設定し、executeメソッドで、プロパティ
      に値をセットしている点、そしてクラスがPOJOである点です。
      ここまでの設定が正しければ、JSPよりボタンが押されると、execute
      メソッドが実行されるはずです。

      package com.pg2se.sample.action;

      public class IndexAction {
       
        private String message;

        public String getMessage() {
          return message;
        }

        public void setMessage(String message) {
          this.message = message;
        }
       
        public String execute() {
          message = "hello world!!";
          return "success";
        }

      }


    6. 最後に
      Actionが実行した最後に"success"を戻り値で返していますが、今回の場合、
      index-success.jspが優先で呼ばれるのですが、ファイルが存在しない場合は、
      次にindex.jspが呼ばれます。(結果的に再度呼び出し元のJSPが実行される
      ことになります)
      この際に、今度はActionでmessageプロパティが設定されていますので、その
      内容が、JSPの、

      <s:property value="message"/>

      の部分で表示されます。

      以上で、超簡単Struts2アプリが完成しました。

      次回は、より実践的にシンプルな掲示板アプリを作成して見たいと思います。

    最初に

    まずStruts2をインストールする前提条件ですが、

    Java SE(JDK)がインストールされていること、

    Tomcatがインストールされていることを前提としています。

    ※アプリケーションサーバについてはTomcatではなくても問題ないですが、

    その場合は適宜、Tomcatに関連する説明文は読み替えてください。

     

    Struts2について

    Struts2についての説明についてはこちらを参照してください。

    Struts2はフレームワークですので、それの単体では特に意味をなさないものですが、

    サンプルのアプリケーションが添付されているので、サンプルの動作確認と、

    実際に、Strtuts2のフレームワークを利用した最初のアプリケーションを

    作成して見たいと思います。

     

    ダウンロード

    Struts2のダウンロードはここから行います。

    2008年12月22日時点での最新版は、struts-2.0.14です。

    ここでは、Full Distribution である、struts-2.0.14-all.zip を

    上記リンクよりダウンロードして任意の場所に解凍しておきます。

     

    showcase - サンプルアプリケーション

    解凍した場所の/apps/struts2-showcase-2.0.14.warを短い名前に変更します。

     →showcase.war に変更

    変更したファイルを、Tomcatのアプリケーションを配備場所にコピーします。

     →TOMCAT_HOME/webapps/showcase.war

     

    以上でTomcatを起動すると、標準の設定では、

    http://localhost:8080/showcase/ でアクセスすると以下の画面が表示されるはずです。

    20081222_01.jpg

    以下のように様々なサンプルが公開されていますので、

    まずはサンプルを色々と触ってみて動作の確認をしてみてください。

    • Home
    • Ajax Theme for Struts Tags
    • Ajax Chat
    • Action Chaining
    • Config Browser
    • Conversion
    • CRUD
    • Execute & Wait
    • File Download
    • File Upload
    • Freemarker
    • Hangman
    • JavaServer Faces
    • Person Manager
    • Tags
    • Tiles
    • Token
    • Validation
    • Help 

     

    次回は実際に、Struts2のフレームワークを利用して、

    オリジナルのアプリケーションを作成してみます。