2011年3月21日月曜日

CSVファイルをExcelファイルに変換するツール

CSVファイルをExcelに読み込むと0詰めした数値や日付が異なる書式になってしまうという問題があります。『外部データの取り込み』機能を使用することによりCSVやタブ区切りテキスト等をそのまま読み込むこともできますが、手順がややこしいのでCSVからXLSに変換するプログラムで作ってみました。

なお、CSVファイルの形式はソフトによって微妙に仕様が異なるものの、RFC 4180で標準的な仕様がまとめられています。


■ソースについて■

Visual Studio 2008(C#)で開発しています。
zlib/libpng Licenceで配布します。

■ソースの説明■

Excelを操作するために、COMオブジェクトへの参照設定を追加する必要があります。
Excelのバージョンによって表記が異なりますが、ここでは『Microsoft Excel 11.0 Object Library』を追加しています。


usingで以下のパッケージの使用を宣言します。InteropServicesにあるMarshalクラスはCOMオブジェクトを操作するのに使用します。
using System.Runtime.InteropServices;

using Microsoft.Office.Interop.Excel;
Excelを操作するにはApplicationクラスのインスタンスを作成します。
エラー時にもメッセージを表示しないように、DisplayAlertsにはfalseを指定しておきます。
ExcelObj = new Application();
ExcelObj.DisplayAlerts = false;
 この後、ワークブック、シート、セル、レンジの順にオブジェクトを取得します。
取得したオブジェクトは不要になったらReleaseComObjectで開放します。
開放を忘れるとExcelのプロセスが終了しません。
Workbooks workbooksObj = ExcelObj.Workbooks;
Marshal.ReleaseComObject(workbooksObj);
レンジオブジェクトのValue2プロパティを使用しセルに任意の値を設定します。
cellObj = (Range)rangeObj[row + 1, col + 1];
cellObj.Value2 = value;
最後に、SaveAsでファイルに保存します。
このとき、Excelのバージョンによってフォーマットの定数が異なるので注意が必要です。
BookObj.SaveAs(filePath, fileFormat, null, null, null, null, XlSaveAsAccessMode.xlExclusive, null, null, null, null, null);

■ダウンロード■
 
プログラム:
http://tecproglab.googlecode.com/files/csv2xls.zip
 
実行ファイル:
http://tecproglab.googlecode.com/files/csv2xls.exe.zip
 
SVN:
http://tecproglab.googlecode.com/svn/trunk/vcs/csv2xls

2011年1月31日月曜日

VB.netで常駐プログラム

VB.netで常駐プログラムを作ろうと思い立ったので実現方法を調べてみました。

サンプルソースコード


■ウィンドウの非表示■

標準ではフォームが表示されてしまうので、ShownイベントでVisibleにFalseを設定し、常に非表示にします。
Private Sub Form_Shown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown

    Me.Visible = False

End Sub
 また、ShowInTaskbarプロパティにFalseを設定し、タスクバーに表示されないようにします。


■タスクトレイにアイコンを表示■

タスクトレイ(タスクバーの右端に並ぶアイコンのことです)にアイコンを表示する方法ですが、NotifyIconクラスを使用します。
使い方は簡単で、ツールボックスからフォームにNotifyIconを貼り付けるだけです。アイコンや表示するテキストはプロパティから変更できます。

NotifyIconのイベントではアイコンをクリックした場合のマウスイベントを拾えます。また、ContextMenuStripプロパティを使用すれば、右クリック時に表示するメニューを設定できます。サンプルでは終了のメニューを表示しています。

■デスクトップにウィンドウを張り付ける■

Win32APIをいくつか使用するとデスクトップに張り付いたウィンドウを表示できます。

以下のWin32APIを定義します。
Public Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Integer) As Integer

Public Declare Function FindWindow Lib "USER32.DLL" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
Public Declare Function SetParent Lib "USER32.DLL" (ByVal hWndChild As Integer, ByVal hWndNewParent As Integer) As Integer
ウィンドウタイトルより”Program Manager”を検索し、親ウィンドウに設定します。
また、デスクトップ上のアイコンに隠れないように最前面に表示します。
Protected Sub SetFormPosDesktop(ByVal targetForm As Form)

    Dim hProgramManagerHandle As Integer
    hProgramManagerHandle = FindWindow(vbNullString, "Program Manager")
    Call SetParent(targetForm.Handle.ToInt32, hProgramManagerHandle)
    Call SetForegroundWindow(targetForm.Handle.ToInt32)
End Sub

試しにカレンダーのサンプルを作成してみました。
実行した画面はこんな具合です。
画像だとわかりにくいかもしれませんが、ウィンドウをアクティブにしてもデスクトップに張り付いています。


ソースコードとサンプルプログラムはこちら↓からダウンロードできます。
http://tecproglab.googlecode.com/files/Calendar.zip
開発環境:Windows 7, VS2005Pro

2010年11月1日月曜日

2010年秋 情報処理技術者試験 ITストラテジスト解答例

昨日受けてきたITストラテジストの自己解答です。
解答範囲は午後1のみです。午前の解答はJITECが公開しています。

■■問1■■


設問1

(1)安全在庫の基準値を適正にし欠品を減少できる。
  >>商品の補充が間に合わず…、在庫情報を即時に参照できる…とあるため。

(2)化粧品を製造ロット番号の順に出荷できる。
  >>古いロットの商品が出荷されることのないように、
  出荷管理は製造ロット番号と出荷日付によって行い…とあるため。

設問2

(1)一定の納品時刻に配送が可能なため。
  >>納品時刻を一定にしてほしい、希望納品時刻どおりの配送が可能とあるため。

(2)納期遵守率
  >>納品時刻を一定にしてほしい、とあるため。

設問3

(1)製品を小売業者へ出荷した際の数量と製造ロット番号をメーカーに提供する。
  >>トレーサビリティ強化の要望を持っている、とあるため。

(2)受注時に在庫をオンラインで確認し欠品の場合は直ちに顧客に連絡する。
  >>注文時に欠品が…連絡してほしい、とあるため。



■■問2■■

設問1

(1)生産計画責任者の余分に在庫を持つという意見は在庫数量を減らす経営方針に反する。
  >>在庫数の削減によるコスト削減、とあるため。

(2)大手の顧客とは長期契約を結んでいるので既存製品の生産終了によるリスクは低い。
  >>大手の顧客とは、長期契約を結び、とあるため。

設問2

(1)3ヶ月先までの完成品の出荷予定日と出荷数量
  >>完成品の現在庫数及び…3か月分の生産計画を作成する、とあるため。

(2)エンジン本体と付属機器のセットの、組み合わせと付属機器の必要な数量
  >>エンジン本体と付属機器をセットにして…とあるため。


設問3
 工場内の入出庫管理システムのデータを取り込み生産計画を反映する機能。
  >>入出庫管理システムをインストールした独立型のPCを…とあるため。


■■問3■■

設問1
(1)給与計算処理業務と連携したサービスが提供できる。
  >>給与計算処理業務を受託するなど…とあるため。

(2)親会社を通じて、地域の法人の会でサービスの紹介やデモンストレーションを行う。
  >>親会社は…地域の法人の会の会長に…とあるため。

設問2
(1)削減の見込める事務コストより安い料金であること。
  >>新たに費用負担が増加するような…とあるため。

(2)利用する顧客の数と社員数
  >>従業員1名あたりの月額料金を基準として…とあるため。

設問3
(1)勤怠の打刻漏れをチェックし携帯電話にメールで通知する機能。
  >>出退勤時刻を記載し忘れたまま…とあるため。

(2)携帯電話による安否確認の機能。
  >>各社員の携帯電話を使って安否確認が…とあるため。

■■問4■■

設問1
(1)
 (a)
  ①経済的な電力売買を設定できる機能。
   >>時間帯によって電力の売買単価が異なる…とあるため。
  ②外出先から家庭電化製品の管理を行う機能。
   >>外出先から、自宅の家庭用電化製品の…とあるため。

 (b)
  ①通信手順の更新が行えること。
   >>通信手順は、標準化されても…とあるため。
  ②新旧の通信手順に対応できること。
   >>古い通信手順の家庭用電化製品とも通信しなくては…とあるため。

(2)
 ①電力売買を行うスケジュールの情報
  >>時間帯によって電力の売買単価が異なる…とあるため。
 ②監視・管理する家庭用電化製品の情報
  >>外出先から、自宅の家庭用電化製品の…とあるため。

設問2

(1)多発する停電に対応できる必要がある。
  >>電力供給の信頼性が日本に比べて低く…とあるため。
(2)標準規格や特許への対応が必要である。
  >>通信手順の標準規格化に…、スマートグリッドに関連する特許取得を…とあるため。

設問3
 自社開発より短期間で、F社の製品に適した仕様の製品を独占して調達できる。
  >>太陽光システムに適した仕様が必要、自社開発及び製造を行うには…膨大な時間
    とあるため。


■■総評■■
 問1と問4が比較的解答しやすい問題かと思います。
 問4は解答が多い分、点数が稼ぎやすかったのではないでしょうか。

 問2は大まかな答えは分かるものの確実な正解が導きにくい問題で、
 問3は閃き次第で点数が大幅に変わりそうな運要素が強い問題だと思います。

 ちなみに自分は問1と問2を選択しました。

2010年8月30日月曜日

Zend Frameworkで掲示板を作ってみる

今回はZend FrameworkとSmartyを活用し掲示板のサンプルを作成してみます。
ただし、細かい部分までは解説しきれないので要点を絞って説明します。
また、デザインやエラーチェックは考慮しないものとします。


使用する環境は以下となります。
Windows XP
WAMP Server 2.0(PHP 5.3, MySQL 5.1)
ZendFramework 1.10.6
Smarty 2.6.26

作成したソースコードはこちらからダウンロードできます。

***フレームワークの設定***

まず、ZendFrameworkとSmartyをダウンロードし展開します。
コマンドプロンプトを開き、ZendFrameworkのbinフォルダにパスを通します。

>set path=C:\wamp\bin\php\php5.3.0;c:\ZendFramework-1.10.6-minimal\bin;%path%

ZendFrameworkのzf.cmdを実行しプロジェクトを作成します。
ここではプロジェクト名をzbbsとします。

>zf create project zbbs

zbbsフォルダの中にapplicationやpublicといったフォルダが作成されれば成功です。

ライブラリのパスを設定します。
php.iniを修正する方法もありますが、手っ取り早くpublic\index.phpを修正することにします。

set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
realpath(APPLICATION_PATH . '/../../library'), //<<この行を追加します。
get_include_path(),
)));

あとはzbbsと同じ階層にlibraryのフォルダを作成し、ZendFrameworkとSmartyのライブラリをコピーします。
フォルダ構成は以下のようになります。

www/
 zbbs/
  application/
  library/
  public/
   index.php
 library/
  Zend/
  Smarty/

application\configs\application.iniに文字エンコードの設定を追加します。
phpSettings.mbstring.http_output = "UTF-8"

zbbsフォルダ直下にindex.phpと.htaccessファイルを作成します。

index.phpファイルではpublicフォルダのindex.phpを読み込むようにします。
require_once dirname(__FILE__) . "/public/index.php";

.htaccessファイルでは以下の設定を行います。

ZendFrameworkの開発用の設定を有効にします。(本番環境ではこの設定を削除します。)
SetEnv APPLICATION_ENV "development"

サーバの基準となるURLを設定します。
今回はhttp://localhost/zbbs/でアクセスできる位置に配置するため、RewriteBaseを/zbbsに設定します。
他の場所に置く場合はそのURLに合わせてRewriteBaseを変更します。
RewriteEngine on
RewriteBase /zbbs

全てのリクエストをindex.phpに受け渡すように設定します。
RewriteRule .* index.php


ログの保存やSmartyのため、tempフォルダを作成します。
(Linuxの場合は書き込み権限を与えます)

ここまで設定が終わったらWAMPの設定でApacheのエイリアスを追加し、ブラウザでアクセスします。
http://localhost/zbbs/

青い背景のZendFrameworkの画面が表示されれば成功です。


***コントローラーと画面の作成***

再びコマンドラインを開き、zbbsフォルダの中に移動します。
zf.cmdで、今度はコントローラ・アクション・ビューを作成します。
(ざっくり説明するとコントローラは画面の制御処理、アクションはコントローラ中の画面ごとの処理、ビューが画面に当たります)

まずはコントローラを作成します。
>zf create controller edit

application\controllers\EditController.phpが作成されれば成功です。
コントローラを作成すると、デフォルトのアクションとビューが作成されます。
アクションはEditController.phpの中にあるindexAction関数です。
ビューはapplication\views\scripts\edit\index.phtmlファイルです。

application\views\scripts\edit\index.phtmlファイルを以下のように修正します。
<form method="post" action="{$SMARTY_BASE_URL}/edit/confirm">
<table>
<tr>
<th>タイトル</th>
<td><input type="text" name="topic_title" style="width: 20em" value="{$topic_title}"/></td>
</tr>
<tr>
<th>内容</th>
<td><textarea cols="40" rows="10" name="topic_note"/>{$topic_note}</textarea></td>
</tr>
<tr>
<td align="right" colspan="2"><input type="submit" name="post" value="確認"/></td>
</tr>
</table>
</form>

以下のURLにアクセスして画面が表示されるか確認してください。index.phtmlを修正してリロードすれば表示が変わるはずです。
http://localhost/zbbs/edit


このままでも開発は可能ですが、画面のテンプレート機能がないと開発効率が悪いのでSmartyを組み込みます。
Smartyの組み込みの詳細は前回説明したので省略します。
libraryフォルダにZbbs/ViewSmarty.phpファイルを保存します。
また、Bootstrap.phpを修正します。

$view = new Zbbs_ViewSmarty(APPLICATION_PATH . '/views/scripts',
array('compile_dir' => $smartyTempPath)
);


$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
$viewRenderer->setView($view);

再度以下のURLにアクセスして画面が表示されるか確認してください。
http://localhost/zbbs/edit


続けてアクションを作成します。
コマンドプロンプトで以下のコマンドを実行します。
>zf create action confirm edit

最後の引数(edit)がコントローラの名前で、その前の引数(confirm)がアクションの名前です。
アクションを作成するとそれに対応したビューも作成されます。
EditController.phpにconfirmAction関数が追加されていること、
また、application\views\scripts\edit\confirm.phtmlファイルが作成されていることを確認してください。

同様に、regist、resultの2つのアクションを作成します。
アクションには以下のようなURLでアクセスできます。
http://localhost/zbbs/edit/confirm
http://localhost/zbbs/edit/result

URLは/zbbs/(コントローラー名)/(アクション名)のようになります。
省略するとindexがデフォルトとなるため、/zbbsは/zbbs/index/indexと同じ画面が表示されます。


***データベースへの保存、検索***

あらかじめ掲示板用のデータベースを構築します。
WAMPのphpMyAdminでzbbsデータベースとユーザーを作成してください。

topic_itemテーブルを作成します。
CREATE TABLE IF NOT EXISTS `topic_item` (
`topic_id` int(11) NOT NULL,
`topic_title` varchar(100) NOT NULL,
`topic_note` varchar(1000) DEFAULT NULL,
PRIMARY KEY (`topic_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;



データベースにアクセスするためapplication.iniに以下の設定を追加します。

database.adapter="PDO_MYSQL"
database.params.host="localhost"
database.params.dbname="zbbs"
database.params.username="zbbs"
database.params.password="zbbs"

Bootstrap.phpに以下の処理を追加します。
設定ファイルからデータベースへの接続クラスを作成し、Zend_Registryに格納します。
(Zend_RegistryはZendFramework用のグローバル変数といったもので、どのスクリプトからも格納してあるオブジェクトを取得できます。)

$config = new Zend_Config($this->getOptions());
Zend_Registry::set("config", $config);


$database = Zend_Db::factory($config->database);
Zend_Registry::set("database", $database);

データベースへ保存する処理をregistAction関数に記述します。
今回はエラー処理を無視して必要最低限のコードを記述します。

//データベースへの接続を取得します。
$database = Zend_Registry::get("database");

//次のIDを取得します。
$rows = $database->query('SELECT MAX(topic_id) + 1 next_id FROM topic_item')->fetchAll();
$topic_id = $rows[0]['next_id'];
if($topic_id === null)
{
$topic_id = 1;
}

//データベースに保存する値を設定します。
$dataset = array(
'topic_id' => $topic_id,
'topic_title' => $this->_getParam("topic_title"),
'topic_note' => $this->_getParam("topic_note"),
);

//Insertを実行します。SQL文はZendFrameworkが自動生成します。
$database->insert('topic_item', $dataset);

//最後にtopic_idを設定してからresult画面を表示します。
$this->_setParam('topic_id', $topic_id);
$this->_forward('result');


保存した内容をデータベースから取得する処理をresultAction関数に記述します。

//topic_idを取得します。
$topic_id = (int)$this->_getParam("topic_id");
//データを検索します。
$rows = $database->query('SELECT * FROM topic_item WHERE topic_id = ' . $topic_id)->fetchAll();
//ビューにデータを設定します。
$this->view->assign($rows[0]);


http://localhost/zbbs/editから入力を行い、topic_itemテーブルへ保存ができれば成功です。



最後に、データベースに保存した内容をトップ画面に表示するようにします。

//データを全件取得し、ビューに渡します。
$rows = $database->query('SELECT * FROM topic_item ORDER BY topic_id DESC')->fetchAll();
$this->view->assign("rows", $rows);


application\views\scripts\index\index.phtmlを以下のように修正します。
{foreach}タグについてはSmartyのドキュメントを参考にしてください。
<form>
<table border="0" cellspacing="0" width="400">
{foreach from=$rows|smarty:nodefaults item=item name=loop}
<tr>
<th align="left" width="400">
{$item.topic_title}
</th>
</tr>
<tr>
<td>
<textarea cols="40" style="border-style: dotted; border-color: silver;" readonly="1" rows="3" name="topic_note"/>{$item.topic_note}</textarea>
</td>
</tr>
{/foreach}
</table>
</form>

以上で、簡単ではありますが投稿と一覧表示を行う簡易掲示板が完成です。


作成したソースコードはこちらからダウンロードできます。

2010年8月4日水曜日

SmartyをZend Frameworkの標準のViewに設定する

今回はPHPフレームワークのZend FrameworkとSmartyについての解説です。

Zend FrameworkはPHPの汎用的なWebアプリケーションフレームワークです。
様々な機能が標準で組み込まれていますが、JSPのようなテンプレート機能がありません。

そこで、PHPで比較的普及しているテンプレートライブラリのSmartyを組み込むことにより、
Struts+JSPに近い感覚で開発できるようにしてみます。


まずZend Framework(1.10.6)をダウンロードしプロジェクトを作成します。
(Zend Frameworkの設定については省略します)

同様にSmartyをダウンロードし展開します。ここではVer 2.6.26を使用します。
ディレクトリ構成は以下のようにします。
/zbbs
    /application
        /configs/
        /controllers/
        /views/scripts/index/index.php
        /ViewSmarty.class.php
    /library
        /Zend
        /Smarty
    /public
    /temp/templates_c

application、library、publicディレクトリはzfコマンドが標準で作成します。
temp/templates_cディレクトリはSmartyが使用するので、あらかじめ作成し書き込み権限を与えます。
library/Zendとlibrary/SmartyにはそれぞれZend FrameworkとSmartyを展開して配置します。
(別の場所にinclude_pathが設定してある場合はそれでも問題ありません)
ViewSmarty.class.phpはここからダウンロードしてください。

application/Bootstrap.phpを以下のように修正します。

public function run()
{
    ini_set('mbstring.http_output','UTF-8');
    $this->_initSmarty();
    return parent::run();
}

protected function _initSmarty()
{
    require_once('Smarty/Smarty.class.php');
    require_once(dirname(__FILE__) . '/ViewSmarty.class.php');

    $compile_dir = APPLICATION_PATH . '/../temp/templates_c';

    $view = new ViewSmarty(
         APPLICATION_PATH . '/views/scripts',
         array(
            'compile_dir' => $compile_dir,
            'default_modifiers' => 'escape'
        )
    );

    $request = new Zend_Controller_Request_Http();
    $view->assign($request->getParams());

    $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
    $viewRenderer->setView($view)
        ->setViewBasePathSpec($view->getEngine()->template_dir)
        ->setViewScriptPathSpec(':controller/:action.:suffix')
        ->setViewScriptPathNoControllerSpec(':action.:suffix')
        ->setViewSuffix('phtml');
}


設定内容について簡単に説明しますと、最初のrequire_onceでSmartyのクラスと
独自のZendFramework用のViewクラス(ViewSmarty)を読み込みます。
ViewSmartyの内容についてはここでは省略します。)

ViewSmartyの初期化でコンパイル用のテンポラリディレクトリと標準でエスケープを行うdefault_modifiers=escapeを設定します。

$view->assign()でフォームから送信されたパラメータをあらかじめSmartyに設定しておきます。

最後に$viewRenderer->setView()でViewSmartyをZendFrameworkに設定し完了です。


動作確認のため、application/views/scripts/index/index.phtmlを修正し、フォームから送信されたパラメータが表示されるか試します。

index.phtmlは以下のようにします。

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
</head>
<body>
<form method="post">
<input name="message" value="{$message}" />
<input type="submit" value="OK" />
</form>
</body>
</html>


日本語やダブルクォーテーションを含むテキストを送信しても問題なく表示されれば成功です。

2010年3月6日土曜日

iBatisの組み込み

データベースアクセスのフレームワークであるiBatis(Ver 2)をプロジェクトに組み込み
データの取得を行ってみます。

サンプルはこちらからダウンロードできます。

※BLOGの都合上、文中のタグ用の括弧はすべて全角文字にしてあります。

組み込み

まず、以下のページからiBatisをダウンロードします。
Ver3のベータ版が出ているようですが、ここではVer2のibatis-2.3.4.726.zipをダウンロードします。
http://ibatis.apache.org/java.cgi

ダウンロードしたファイルを展開し、ibatis-2.3.4.726.jarをWebContext/libフォルダにコピーします。

次に、xmlフォルダ(またはsrcフォルダ)にSqlMapConfig.xmlを作成します。
SqlMapConfig.xmlにはDB接続の情報や使用する追加で読み込むSqlMap.xmlファイルのパスを指定します。

ここでは、外部のJDBCドライバが不要なODBC経由でデータベースに接続します。
ODBC経由でのDB接続の設定は以下のようになります。(一部抜粋)
<property name="JDBC.Driver" value="sun.jdbc.odbc.JdbcOdbcDriver" />
<property name="JDBC.ConnectionURL" value="jdbc:odbc:struts2_sample" />
<property name="JDBC.Username" value="struts2_sample" />
<property name="JDBC.Password" value="struts2_sample" />

ODBCデータソースアドミニストレータでデータソース「struts2_sample」を追加します。

なお、MySQLの場合の設定は以下のようになります。(一部抜粋)
<property name="JDBC.Driver" value="com.mysql.jdbc.Driver" />
<property name="JDBC.ConnectionURL" value="jdbc:mysql://localhost/struts2_sample" />
<property name="JDBC.Username" value="struts2_sample" />
<property name="JDBC.Password" value="struts2_sample" />

データの準備

以下のSQL文をデータベースアクセスクライアント等で実行し、
あらかじめテーブルの作成とデータの追加を行います。
なお、ここで使用しているSQL文はMySQL用のものです。

create table sample_user_tables(user_name varchar(100), mail_address varchar(200), login_count integer, primary key(user_name));

INSERT INTO sample_user_tables
(
user_name,
mail_address,
login_count
)
VALUES
(
'hoge',
'hoge@example.com',
'3'
)
;

INSERT INTO sample_user_tables
(
user_name,
mail_address,
login_count
)
VALUES
(
'piyo',
'piyo@example.com',
'10'
)
;

iBatisの初期化

iBatisを使用するにはSqlMapClientクラスを作成する必要があります。
SqlMapClientクラスは一度作成したら使い回しができるので、
ここではシングルトンのクラスSqlMapClientHolderを作成し初回だけ初期化を行うようにします。

public class SqlMapClientHolder {
 public static final String RESOURCE_PATH = "SqlMapConfig.xml";
 private static SqlMapClient sqlMapClient;
 static {
  try {
   Reader reader = Resources.getResourceAsReader(RESOURCE_PATH);
   sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);
  } catch (IOException ioe) {
   throw new RuntimeException("SqlMapConfig.xml load failed.", ioe);
  }
 }

 public static SqlMapClient getInstance() {
  return sqlMapClient;
 }
}

DAOの作成

データベースにアクセスするデータアクセスクラス(DAO)を作成します。
まず、SQL文を記述した設定ファイルをXML(SqlMap.xml)で作成します。
ファイル名は自由に設定できますが、xmlフォルダ(またはsrcフォルダ)といった
コンパイル対象のフォルダにおく必要があります。
作成したファイルのパスはSqlMapConfig.xmlにsqlMapタグで指定します。
<sqlMap resource="sqlmap/SqlMap-SampleQuery.xml" />

SqlMap-SampleQuery.xmlの内容は以下のようになります。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap      
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"      
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap>
 <resultMap id="SampleQueryDto"
  class="com.googlecode.tecproglab.struts2_sample.dto.SampleQueryDto">
  <result property="userName" column="user_name" />
  <result property="mailAddress" column="mail_address" />
  <result property="loginCount" column="login_count" />
 </resultMap>
 <select id="queryAll" resultMap="SampleQueryDto">
  SELECT
  user_name,
  mail_address,
  login_count
  FROM
  sample_user_tables
  ORDER BY
  user_name
    </select>
</sqlMap>

selectタグにはSQL文(ここではSELECT文)を記述します。
また、SampleQueryDtoに取得したデータを保存するDTOクラスを指定します。

resultMapタグにはDTOクラスのクラス名を指定します。
resultタグにはDTOクラスの要素とSQLで取得した列名の組み合わせを指定します。

データを保存するDTOクラスを作成します。
DTOのメンバー変数(userName)はresultMapタグの指定と厳密に一致させます。

//一部抜粋
public class SampleQueryDto {
 private String userName;

 public String getUserName() {
  return userName;
 }

 public void setUserName(String userName) {
  this.userName = userName;
 }
 //以下省略
}

実際の処理を行うDAOを作成します。
といっても、SqlMapClientを取得してiBatisを呼び出すだけです。
queryForListの引数にはselectタグに記述した名前を指定します。
SQLを実行した結果としてDTOのリストが返ります。

public class SampleQueryDao {
 public List<SampleQueryDto> queryAll() {
  SqlMapClient sqlMapClient = SqlMapClientHolder.getInstance();

  try {
   List<SampleQueryDto> list = (List<SampleQueryDto>) sqlMapClient
     .queryForList("queryAll");
   return list;
  } catch (SQLException se) {
   throw new RuntimeException(se);
  }
 }

}

動作確認

iBatisはWebサーバが不要のため、以下のようなテストコードで動作確認が行えます。
Eclipse上から実行するには以下のように行います。
1.main関数を記述したクラスをプロジェクトエクスプローラーから右クリックします。
2.コンテキストメニューのRun As>Java Applicationをクリックします。

public static void main(String[] args) {
 SampleQueryDao dao = new SampleQueryDao();
 List<SampleQueryDto> list = dao.queryAll();

 for (SampleQueryDto dto : list) {
  System.out.println(dto);
 }
}

2010年2月7日日曜日

アプリケーションのWindows7移行について

先日MS主催のセミナー『Windows7&Windows Server 2008 R2対応アプリケーションへの移行のための開発ポイント』に参加しました。
広範囲にわたる内容でしたが、気になった箇所と要点をざっとまとめてみました。


■Windows7への対応方法


Windows7はWindows Vistaがベースであり、完全互換を目標として開発されている。
Vistaでの検証済みアプリケーションは概ねWindows7でも動作する。
Windows7への対応はVistaへの対応方法とほぼ同じ。

*Windows7の強化ポイント
先進的なユーザーエクスペリエンス、総合検索など。
ビルトインアカウントのAdministratorは既定で無効。

*互換モード

OSが互換機能を提供。
ただし、.netやJavaのアプリケーションは適用外。

*Windows XPモード
Windows 7 Pro以上で利用可能。
Virtual PCを利用し仮想Windows XPで動作するアプリケーションのウィンドウだけをWindows7上に表示する。

*開発環境
Visual Studio 2008 SP1
Windows7 SDK
Windows Server 2008 R2 SDK
.net Framework 3.5 SP1
VB6ランタイムも含まれている

*Windows7のバージョン
Windows7のバージョンはメジャーバージョン=6、マイナーバージョン=1。
Vistaはメジャーバージョン=6、マイナーバージョン=0。

.netではEnvironment.OSVersionを使用して取得。

*フォルダ構成の変更(Vistaから)
Document and Settings, All Users, My Documents, Application Dataといったフォルダのパスが変更されている。
フォルダのパスは.netではSystem.Environment.GetFolderPathメソッドで取得する。

*フォルダーの接合点
旧来のパス(Document and Settingsなど)に書き込みを行うと、別のフォルダーへリダイレクトして書き込む。
読み込みは行われない。

*ユーザーアカウント制御(UAC)

管理者でも普段は標準ユーザーのトークン(=特権)しか持たず、必要に応じて
フルトークン(=管理者権限)を利用可能にする。
ただし、ビルトインのAdministrator(既定では無効)は常にフルトークンで動作

権限昇格が必要な場合はUACダイアログを必要に応じて表示する。
アプリケーションの発行元によってダイアログの帯の色が変わる。

Windows7ではUACの表示タイミングが4段階に変更。
UACダイアログの表示が最低限に改良。
インストール時も一度だけ表示される。

*シールドアイコン
権限昇格が必要な場合にボタンに表示(手動)。また、アプリケーションのアイコンに表示(自動)。

*権限昇格の方法
コンテキストメニューから管理者として実行する。
ファイルのプロパティで指定。
アプリケーションマニュフェストで指定・

*アプリケーションマニフェスト
実行ファイルの実行権限をアプリケーションマニュフェストに記述する。
管理者権限が必要な場合、アプリケーション起動時にUACダイアログが表示される。

ファイル名は「実行ファイル名.exe.mnifest」とし、実行ファイルと同じフォルダに配置するか実行ファイルに埋め込む。

Windows7からマニュフェストにCompatibilityセクションが追加され、
アプリケーションの対応OSが指定可能に。
指定がないとVista互換モードで動作する。

マニュフェストがない場合、ファイル名にsetup, installなどが含まれるとインストーラとして検知され
権限昇格ダイアログが表示される。

*インストーラの注意
ユーザー毎の設定はインストーラでは行わない。
アプリケーションの初回起動時に行う。
Windows Installerの使用を推奨。

管理者権限が必要な場合、別プログラムもしくはCOMオブジェクトとして分離する。
もしくはタスクやサービスを利用する。

*ファイルとレジストリの仮想化
権限のない特定のフォルダーやレジストリに書き込みを行った場合に
ユーザー別のフォルダ・レジストリに書き込むことにより互換性を保つ。
次回読み込む場合はユーザー別のフォルダ・レジストリから読み込む。

フォルダ:Program Files, レジストリ:HKLM\Softwareなどが対象
対象は32ビットの対話型アプリケーションで管理者権限で実行されていない場合。

*整合性レベル(IL)
高中低の3段階にレベルを分け、保護を行う。
たとえば、%WinDir%などは高ILの領域であり、
高ILのプロセスからは高ILの領域にアクセスできるが
中・低のプロセスからは高ILの領域にはアクセスできない。
このように、下位のILからの上位のILへのアクセスは禁止される。

*ユーザーインターフェース特権の分離(UIPI)
上位権限のプロセスを、デスクトップ上の下位権限のプロセスからの
ウィンドウメッセージなどによる攻撃から保護する。
スレッドフック、PostMessage、ハンドルによるアクセス、DLLの注入など

*Internet Explorerの保護モード
保護モードをオンにすると、IEのプロセスは下位ILで動作する。
上位ILのプロセスや保護されたフォルダへはアクセスできない。

*セッション0の分離
Windows XPでは最初にログインしたユーザーとサービスが同じセッションとなっていたが、
VistaとWindows7では完全に分離される。
システムプロセスとサービスはセッション0で、ユーザーはセッション1以降を使用する。
このため、サービスからウィンドウを表示することができない。

*Windowsリソース保護
保護されたファイル・レジストリの更新が行われた場合、アクセスエラーを表示しない
(関数の戻り値は成功を返す)がリソースの変更はできない。
条件:インストーラの実行権限がマニュフェストで定義されておらず、
管理者権限で動作している場合。(ファイル名にsetupが含まれる場合など)

*Unicode対応
Shift-JISに含まれない文字が存在しうる。
JIS2004のサポートにより、サロゲートペア文字(1文字が32ビット)が含まれるようになった。
1文字16ビットを仮定してはいけない。

*LCIDの指定
標準のソート方法がユーザーごとに変更できるため、
必要な場合はロケールID(LCID)を明示的に指定する。

*フォント
Windows7対応フォントは言語属性を持ち、
フォントの選択ダイアログでは文字入力の言語と一致したフォントのみが表示される。

*高DPIへの対応
Windows7では高解像度(高DPI)がユーザー別に設定可能に。
従来のアプリケーションはDPI仮想化により拡大表示できる。

■64ビットへの対応

Windows7は32ビットと64ビットに対応
Windows Server 2008 R2 は64ビット専用

*64ビットのメリット
広大なメモリ空間とアドレス空間。
レジスターの効率的利用など

*WOW64
Windows on Windows 64
Win32 x86アプリをそのまま動作させることができる。
レジストリ・システムファイル・環境変数を32ビットと64ビットで分離し共存

システムファイルは%windir%\syswow64にリダイレクトされる

32ビットアプリケーションがレジストリにアクセスする場合、WOW6432Nodeにリダイレクトされる。
例:HKLM\Software → HKLM\Software\WOW6432Node

*WOW64の制限
同一プロセスで32ビットと64ビットの混在はできない。
たとえば、32ビットプロセスは64ビットのDLLをロードできない。
混在させるにはアウトプロセスCOMやRPC、共有メモリなどを使用する

*開発環境
VS2008は32ビットアプリケーションの開発とリモートデバッグをサポート。
32ビット版・64ビット版・任意(Any CPU)の作成をサポート。

.net Frameworkの64ビット版には32ビットと64ビットの両方が含まれる。
(.net Framework2.0以降は64ビット対応)

*VB6で作成したプリケーション
32ビットで動作させるならそのまま動作可能。
64ビットで移行させる場合は.net Frameworkへ移行が必要。

*移植に関する注意
P/Invoke, COMを使用する場合、ポインターのサイズを使用している場合は修正が必要。
StructLayout属性などにより構造体のアライメントを変更している場合は確認が必要。

■Windows2008 R2 への対応


Windows 7と同一カーネルを使用しており、Windows7 +αで対応可能。
新機能にはHyper-V 2.0、IIS7.5などがある。

*仮想化
Hyper-V2.0とリモートデスクトップ仮想化に対応。
プログラム・セッションごとのIPアドレスの仮想化に対応。

*IIS 7.5
アプリケーションプールごとに32ビット・64ビットを選択可能。
Server Core上でのASP.NETをサポート。
FTP/WebDAVの統合。
PowerShellによる管理に対応。

*注意点
既定でインストールされない機能が多い。
IISのビルトインアカウント名が変更に。
IIS5 互換モードは廃止。
クエリー文字列長さの制限が2048バイトに。
実行するアカウント名がアプリケーションプール名に。(従来のNetworkServiceへの変更も可能。)

*サーバコア
.net Frameworkをサポート。
WOW64 32ビットアプリケーションをサポート。(既定ではインストールされない)
ただし、サーバコアでの.net Frameworkは画面表示などの機能を除いたサブセット版。

*Power Shellの強化
新しいAPIとコマンドレットに対応。
リモートおよびバックグラウンドジョブに対応。
スクリプトのデバッグ。
国際化対応など。