GAE/JでYUI2.7.0+Struts1.3をつかってCSVファイルを取得してDataTableで表示する

Google App Engine/Java(GAE/J)の認証が一息ついたところで、以下の仕様で、カスタムログインを作り始めてみようかと思う。

  • userデータ Email,日本語名(任意),住所(任意),role をData Storeに持たせる。
  • GAE/Jでの認証後に、Data Storeに存在チェックをして、存在しなければログイン画面に戻す。
  • 存在した場合には、DataStoreの情報をSessionに持たせる。


この程度のことができれば、応用して大抵のことはできると思う。


その第1歩として、CSVファイルにuserデータを持たせてStrutsで取得する。それを確認するために、YUIのDataTableにそれを表示する。これができれば、次にData Storeから情報を取得する、という手順で拡張していくつもり。

サンプル

CSVファイルには、以下のデータを入れることにする(war/data/users.csv)。左から

  • Emailアドレス
  • 日本語ユーザー名
  • 住所
  • 役割(ロール)

となっている。

tetsuya.odaka@gmail.com,小高,東京都,admin
dummy@dummy.com,山田,北海道,user


上の内容を以下の画面で確認する。


以下の作業は、GAE/JプラグインのインストールされたGanymede(Eclipse3.4)でおこなった。Galileo(Eclipse3.5)で少し再トライしてみたが、「大量にメモリを消費して、Perm Genエラー(Out of Memory)」でハングアップする。調査が必要なので、Ganymedeに戻してしまった。

プロジェクトの作成

以前のログ「GAE/JでYUI2.7.0+Struts1.3をつかってAjaxでテキストを取得する」からプロジェクトをコピーする。もしくは、新規にWeb applicationプロジェクトを作成して、Struts1.3のjarをwar/WEB-IINF/lib化にコピーする。

Actionクラスの作成

war/data/users.csvを読み込んで、クライアントにレスポンスするActionクラス(UserForwardAction.java)を作成する。

UserForwardAction.java

package test;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.BaseAction;

public class UserForwardAction extends BaseAction {

    @Override
    public ActionForward execute(
                ActionMapping mapping, 
                ActionForm form,
                HttpServletRequest req, 
                HttpServletResponse res) 
            throws IOException
    {
        // サーブレットコンテキストの取得
        ServletContext sc = this.getServlet().getServletContext();

        String path = sc.getRealPath("/data/users.csv");
        
        String tmpStr;
        StringBuffer sb = new StringBuffer();
        byte[] bStr;

        try {
            FileInputStream fi;
            fi = new FileInputStream(path);
            InputStreamReader is = new InputStreamReader(fi, "UTF8");
            BufferedReader br = new BufferedReader(is);
            
            while ((tmpStr = br.readLine()) != null) {
                sb.append("\n");
                sb.append(tmpStr);
            }
            bStr = sb.toString().getBytes("UTF-8");

            br.close();
            is.close();
            fi.close();

            res.setContentType("text/html; charset=UTF-8"); 
            ServletOutputStream outputStream;
            outputStream = res.getOutputStream();
            outputStream.write(bStr);
            outputStream.flush();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }

        return null;
    }
}

struts-configの作成

war/WEB-INF/struts-config.xmlは以下のようにした。

<?xml version="1.0" encoding="utf-8" ?>
<!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at
   
         http://www.apache.org/licenses/LICENSE-2.0
   
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
          "http://struts.apache.org/dtds/struts-config_1_3.dtd">

<struts-config>


<!-- ================================================ Form Bean Definitions -->

    <form-beans>
        <form-bean
		name="dummyForm"
		type="org.apache.struts.action.DynaActionForm" >
	</form-bean>
	
    </form-beans>


<!-- ========================================= Global Exception Definitions -->


<!-- =========================================== Global Forward Definitions -->

    <global-forwards>
        <!-- Default forward to "Welcome" action -->
        <!-- Demonstrates using index.jsp to forward -->
        <forward
            name="welcome"
            path="/index.hml"/>
    </global-forwards>


<!-- =========================================== Action Mapping Definitions -->

    <action-mappings>
	<action path="/forwardText"
			type="test.UserForwardAction"
			name="dummyForm"
			scope="request">
	</action>
    </action-mappings>


<!-- ======================================== Message Resources Definitions -->

    <message-resources parameter="MessageResources" />

</struts-config>

web.xmlの修正

war/WEB-INF/web.xmlは以下のようにした。

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

  <display-name>GAE/J Sample Application</display-name>
    
  <!-- Standard Action Servlet Configuration -->
  <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
      <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <!-- Standard Action Servlet Mapping -->
  <servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

  <!-- The Usual Welcome File List -->
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>

</web-app>

index.xmlの作成

web.xmlでwelcome-fileに指定したindex.htmlで、上記の画面を作成する。
以前のログ「YUI2.7.0のEditable Table(編集可能な表)でCSV形式のデータを更新・削除する」を表示だけするように書き直した。

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Ajax+Strutsのサンプル</title>
<link rel="shortcut icon" href="../images/egp-favicon.ico" >

<style type="text/css"> 
body {
	margin: 2px;
	padding: 3px;
}
</style> 
 
<link rel="stylesheet" type="text/css" href="./scripts/lib/yui/build/fonts/fonts-min.css" /> 
<link rel="stylesheet" type="text/css" href="./scripts/lib/yui/build/paginator/assets/skins/sam/paginator.css" /> 
<link rel="stylesheet" type="text/css" href="./scripts/lib/yui/build/datatable/assets/skins/sam/datatable.css" /> 
<script type="text/javascript" src="./scripts/lib/yui/build/utilities/utilities.js"></script> 
<script type="text/javascript" src="./scripts/lib/yui/build/paginator/paginator-min.js"></script> 
<script type="text/javascript" src="./scripts/lib/yui/build/datasource/datasource-min.js"></script> 
<script type="text/javascript" src="./scripts/lib/yui/build/datatable/datatable-min.js"></script> 

<script>
XHRDataTableSample = function() {
	var myDataSource;
	var myDataTable;
	
	return{
		init:function() {

			// DataTable用:列定義
    		var myColumnDefs = [
             	{	key:"email",
                 	label:"e-mail",
             		parser:"text",
                 	width:250,
                 	resizeable:true,
                 	sortable:true},
                {	key:"jname",
                    label:"名前",
             		parser:"text",
                    width:100,
                    resizeable:true,
                    sortable:true},
               	{	key:"addr",
                    label:"住所",
              		parser:"text",
                    width:100,
                    resizeable:true,
                    sortable:true},
               	{	key:"role",
                    label:"役割",
               		parser:"text",
                    width:100,
                    resizeable:true,
                    sortable:true}
    		];

 		   	// DataTable用:コンフィグ属性
    		var myConfigs = {
            sortedBy:{key:"email",dir:YAHOO.widget.DataTable.CLASS_ASC},
            paginator: 
                new YAHOO.widget.Paginator({
                	rowsPerPage: 10,
                	template: YAHOO.widget.Paginator.TEMPLATE_ROWS_PER_PAGE,
                	rowsPerPageOptions: [10,25,50,100],
                	pageLinks: 5
            	}),
           	caption:"users",
			// 列のDrag and Drop
           	draggableColumns:true,
           	// 行の選択は1つだけ
           	selectionMode:"single"
    		};

    		// DataSourceのインスタンス化;struts actionを呼ぶ
        	myDataSource = new YAHOO.util.DataSource('/forwardText.do');
	        	myDataSource.responseType = YAHOO.util.DataSource.TYPE_TEXT;
    		myDataSource.responseSchema = {
   			// 行区切り
            	recordDelim: '\n',
            	// フィールド区切り
            	fieldDelim: ',',
        		fields: ['email','jname','addr','role']
    		};

        	// DataTableのインスタンス化
	        myDataTable = new YAHOO.widget.DataTable("output", 
	    	    myColumnDefs, myDataSource, myConfigs);

			/*
			* 行の選択補助。
			*/
			// クリックでハイライトするようにハンドラを設定
        	myDataTable.subscribe("rowClickEvent",
            	myDataTable.onEventSelectRow);
        	myDataTable.subscribe("rowMouseoverEvent", 
       			myDataTable.onEventHighlightRow);
        	myDataTable.subscribe("rowMouseoutEvent", 
       			myDataTable.onEventUnhighlightRow);

		}, // initの終わり
	   	oDS: myDataSource,
   		oDT: myDataTable
	};
}();


//DOMが完全にloadされたら、サンプルを初期化する。
YAHOO.util.Event.onDOMReady(
	//DomReadyイベントで発火するハンドラ
	XHRDataTableSample.init,
	//ハンドラに渡すオブジェクト(関数)
	XHRDataTableSample,
	//ハンドラは、上記のオブジェクトのスコープをもつ。   
	true
);

</script>
</head> 
 
<body class="yui-skin-sam"> 

<h2>YUI2.7 ConnectionManager,DataTable + Struts1.3</h2>

GAE/Jサーバーにあるcsvファイルを、struts経由で取得します。
<br>
<br>

<div id="output">
</div>

</body>
</html>

テストとデプロイ

ローカルサーバーでテストした後に、GAE/Jにデプロイする。
最終テストは必ずGAE/Jサーバーで行った方がよい。ローカルサーバーとGAE/Jでは(共にGoogleが提供するものとはいえ)、違いが存在する。このサンプルのように、日本語を扱う場合には、開発環境が日本語環境のためにテストで発見されない不具合が、GAE/Jで発生する可能性がある