2008年4月25日金曜日

Javaでのデータベース接続(Tomcat版)について


まずJDBC接続とJNDI接続の2つがあります。

1. JDBCはDriverMangerを使うため、コードの中に直接データベース情報を書き込まないといけないので可搬性が低くなります。現在ではJNDIのDataSourceを使うのが主流になります。


どちらもgetConnection()メソッドでConnection型の接続オブジェクトを取得します。



今回は両方を試してするのでJNDI、JDBCのインターフェイスを用意したいと思います。



ConnectionProvider.java

=======================================================================================================================

package database;



import java.sql.Connection;
import java.sql.SQLException;

public interface ConnectionProvider {

public Connection getConnection() throws SQLException;

}

=======================================================================================================================
次にまずはJDBCクラスを作成します。ConnectionProviderインターフェイルを実装します。

JDBCProvider.java
=======================================================================================================================

package database;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class JDBCProvider implements ConnectionProvider { //ConnectionProviderを実装
/**
* JDBC Driver Name
*/

private String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; //ここに直接ドライバー名を記述。今回はSQLServer2005のドライバを使用した場合
**
* JDBC Connection url
*/

private String connectionURL = "jdbc:sqlserver://IDIOM-TEST-AP2:1433;DatabaseName=SampleDataBase;User=sa;Password=P@ssw0rd;";
//ここにデータベースにアクセスする為の情報を記述、データベース名、ユーザー名、パスワードを入力

public Connection getConnection() throws SQLException {

try {
Class.forName(driverName).newInstance();

} catch (InstantiationException e) {

throw new SQLException("Get Database Connection Error");
} catch (IllegalAccessException e) {

throw new SQLException("Get Database Connection Error");
} catch (ClassNotFoundException e) {

throw new SQLException("Get Database Connection Error");

}

return DriverManager.getConnection(connectionURL);
//DriverManagerのgetConnectionメソッドで接続オブジェクトを返します。

}

}
=======================================================================================================================
次にConnectionオブジェクトを作成するためのクラスを作成します。外部からConnectionオブジェクトを作成する際には、すべてこのクラスを使うことになります。
ConnectionManager.java
=======================================================================================================================
package database;
import java.sql.Statement;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import exception.SchemaException;

public class ConnectionManager {

private static ConnectionProvider connectionProvider = new JDBCProvider();
//private static ConnectionProvider connectionProvider = new JNDIProvider();
//(1)ConnectionオブジェクトをJDBCクラスから作成するのであれば、JNDIをコメントアウトしておきます。
protected static boolean supportsTransactions = true;


/**
* Get general dataBase connection
*
* @return
* @throws PersonManagerException
*/

public static Connection getConnection() throws SchemaException {
Connection con;
try {
con = connectionProvider.getConnection();
    //connectionProviderは(1)で有効になっているどちらかのgetConnectionメソッドを実行し、Connectionオブジェクトを返す。こういった時のため、最初にConnectionProviderインターフェイスを作成し、両方getConnectionメソッドを実装するようにした(別にインターフェイスにしなくとも、両方に同じ名前のメソッドを作れば良いのだが、この場合はあえてそうしてみた。)

con.setAutoCommit(false);

} catch (SQLException ex) {

throw new SchemaException(

"When getting general dataBase connection, exception is happened : ", ex);

}

if (con == null) {

throw new SchemaException("Get general dataBase connection error");
}

return con;
}



/**
* Get transaction dataBase connection
*
* @return
* @throws PersonManagerException
*/

public static Connection getTransactionConnection() throws SchemaException {

Connection con = getConnection();

if (supportsTransactions) {

try {

con.setAutoCommit(false);

} catch (SQLException ex) {

throw new SchemaException(

"When getting transaction dataBase connection, exception is happened : ", ex);

}

}

return con;

}



/**
* Close dataBase connection
*
* @param rs
*/

public static void closeResult(ResultSet rs) {

if (rs == null)
return;

try {

rs.close();

} catch (SQLException e) {

System.err.println("Close dataBase connection error");

}

}

/**
* Close statement
*
* @param stat
*/

public static void closeStatement(Statement stat) {

if (stat == null)
return;

try {

stat.close();

} catch (SQLException e) {

System.err.println("Close statement error");

}

}


/**
* Close preparedStatement
*/

public static void closePreparedStatement(PreparedStatement preStat) {

if (preStat == null)

return;

try {

preStat.close();

} catch (SQLException e) {

System.err.println("Close preparedStatement error");

}

}



/**
* Close dataBase connection
*
* @param con
*/

public static void closeConnection(Connection con) {

if (con == null)
return;

try {

con.close();

} catch (SQLException e) {

System.err.println("Close dataBase connection error");

}

}



/**
* Close transaction dataBase connection
*
* @param con
* @param abortTransaction
*/

public static void closeTransactionConnection(Connection con,

boolean abortTransaction) {

if (con == null)

return;

if (supportsTransactions) {

try {

if (abortTransaction) {

con.commit();

} else {

con.rollback();

}

con.close();

} catch (SQLException e) {

System.err.println("Close transaction dataBase connection error");

}

}



}


public static ConnectionProvider getConnectionProvider() {

return connectionProvider;

}

}

=======================================================================================================================

ここまでできたらJDBC経由でデータベースにアクセス可能になる。

では簡単にアクセスするためのコードを書いてみる。長いコードだがデータベース関連のところのみ赤く表示し、説明します。

SampleDataBaseConnection.java

=======================================================================================================================

package database.dao;

import java.sql.*;
import java.util.ArrayList;
import database.ConnectionManager;
public ArrayList selectWords(String mstId, String timestamp, String history) throws SchemaException {
Connection con = null; con = ConnectionManager.getConnection();
     //データベースに接続するためのConnectionオブジェクトを取得する ArrayList words = new ArrayList(); ResultSet rs = null; //データベースから戻ってきた結果を入れるためのオブジェクトを作成する PreparedStatement stmt = null; //SQL文を発行するためのオブジェクトを作成する String sql = ""; //SQL文を入れるオブジェクトを作成する try { sql = "SELECT * FROM WORD WHERE ID IN ("; sql += "SELECT MAX(ID) FROM WORD "; if (timestamp == null) { sql += "WHERE MST_ID = ? AND (INSERTED_AT IS NULL) "; } else { sql += "WHERE MST_ID = ? AND (INSERTED_AT <= ? OR INSERTED_AT IS NULL) "; } sql += "GROUP BY MST_ID, LANG_ID )";
stmt = con.prepareStatement(sql);

//SQLを発行するためのPreparedStatementオブジェクトにSQL文がセットされた。

stmt.setInt(1, Integer.parseInt(mstId));

if (timestamp != null) {

stmt.setString(2, timestamp);

}


//SQL文の中のパラメータに値をセットする。SQL文にある?マークの順番を指定し、データ型に応じてsetメソッドを変える(例: Integer型であればsetIntメソッドを使用するなど)

rs = stmt.executeQuery();

//ここで初めてデータベースにクエリが発行される。結果はResultSetオブジェクトに入る。

while (rs.next()) {

words.add(fillWordEntity(rs));

}


//rsにはSQLの一行が入り、最後まで行くとwhileのループを抜ける。rsの左から一列目の値を取得したければ、rs.getInt(1)などと指定できる。一列目がString型ならrs.getString(1)となる。直接フィールド名を指定して取得も可能である(例: rs.getInt("MST_ID"))など

} catch (SQLException e) {

throw new SchemaException("[" + e.toString() + "]");

} finally {

ConnectionManager.closeResult(rs);

//終わったらまずはResultSetオブジェクトを開放します。

ConnectionManager.closeStatement(stmt);

//次にPreparedStatementオブジェクトを開放します。

ConnectionManager.closeConnection(con);

//最後にConnectionオブジェクトを開放します。これを開放しないとTomcatのConnectionの数には限りがあるので、その数に達した時にConnection Poolingというエラーになってしまいます。

}



return words;



=======================================================================================================================

以上がJDBC経由のやり方です。次にJNDI経由でデータベース接続を行うにはJNDI用のクラスを作成します。

JNDIとはある名前を送ると、その名前にあった値を返してくれるものです。



JNDIProvider.java

=======================================================================================================================

package database;



import java.sql.Connection;

import java.sql.SQLException;



import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import javax.sql.DataSource;





public class JNDIProvider implements ConnectionProvider { //ConnectionProviderを実装



private String jndiName = "java:comp/env/jdbc/SchemaDB";

//"java:comp/env/"はJNDIを表す固定の文字列で"jdbc/SchemaDB"が下記にあるweb.xmlに登録した文字列。

public Connection getConnection() throws SQLException {



Context context = null;

DataSource dataSource = null;

//データソース(DataSource)とはプログラムとデータベースへの接続との間のインターフェースで、データベースへの接続を取得するために使用されます。

try {

context = new InitialContext();

//InitialContextオブジェクトはネーミング操作を実行するための開始コンテキスト

dataSource = (DataSource)context.lookup(jndiName);

} catch (NamingException e) {

throw new SQLException("JNDI Naming Exception : " + e.toString());

}

Connection conn = null;

if (dataSource != null) {

conn = dataSource.getConnection();

//DataSourceのgetConnectionメソッドで接続オブジェクトを返します。

}

return conn;



}



}



=======================================================================================================================



JNDI接続を行うにはこのクラスの他、Tomcatのweb.xmlとServer.xmlを編集する必要があります。

まずはweb.xmlに以下の文字列を追加します。これで"jdbc/SchemaDB"というJNDI名を登録します。



web.xml

======================================================================================================================= <resource-ref>

<description>SchemaDB</description>

<res-ref-name>jdbc/SchemaDB</res-ref-name>

<res-type>javax.sql.DataSource</res-type>

<res-auth>Container</res-auth>

</resource-ref>



=======================================================================================================================

次にserver.xmlにDataSourceの情報を登録します。以下の文字列をTomcatのserver.xmlに追加します。



server.xml

======================================================================================================================= <GlobalNamingResources>

<!-- Used by Manager webapp -->

<Resource name="UserDatabase" auth="Container"

type="org.apache.catalina.UserDatabase"

description="User database that can be updated and saved"

factory="org.apache.catalina.users.MemoryUserDatabaseFactory"

pathname="conf/tomcat-users.xml" />



<Resource name="jdbc/SchemaDB" auth="Container" type="javax.sql.DataSource"

driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"

url="jdbc:sqlserver://ServerName:1433;DatabaseName=HDatabaseNameonbanSQL"

username="sa" password="WSisgreat1"

maxActive="10" maxIdle="10" maxWait="10000"/>

//この10がConnectionPoolの数。仮にConnectionを開放しないと10回データベースアクセスした時点でエラーになってしまう



</GlobalNamingResources>





=======================================================================================================================

これでJNDIの設定が完了です。server.xmlにデータベースへの接続情報を書くことでいちいちデータベースが変る度にビルドする必要がないです。



最後にJNDI接続を利用したい場合はConnectionManagerクラスの

//private static ConnectionProvider connectionProvider = new JDBCProvider();

private static ConnectionProvider connectionProvider = new JNDIProvider();



とし、JDBCを無効にさせます。同じようにSampleDataBaseConnection.javaを実行すればJNDI経由で実行されます。

2008年4月16日水曜日

Excelで最大の行数・列数を求める


==============================================================

Function EffectiveRow() As Long
' 行の最大数を求める A列固定
' Excelの最大行数(65536)から上方向(xlUp)に空白でないセルを探す

EffectiveRow = Range("A65536").End(xlUp).Row
End Function

==============================================================

Function EffectiveColumn() As Long
' 列の最大数を求める 1行目固定
' Excelの最大列数(256)から左方向(xlToLeft)に空白でないセルを探す
EffectiveColumn = Cells(1, 256).End(xlToLeft).Column
End Function
==============================================================


2008年3月6日木曜日

JSP - Pageディレクティブ MIMEタイプ

MIMEタイプとは、送信するデータの含まれているデータの種類(テキスト、画像、オーディオなど)を指定するためのものです。データを受け取るクライアントはこのMIMEタイプを見てどのように表示させればよいか判断するので、適切に指定する必要があります。










HTMLtext/html
PLAINテキストtext/plain
CSStext/css
JPEG画像image/jpeg
GIF画像image/gif
Excel形式のデータapplication/vnd.ms-excel
PowerPoint形式のデータapplication/vnd.ms-powerpoint
その他のデータapplication/octec-stream


例:
<%@ page contentType="text/html; charset=UTF-8"%>








Javaでfor eachループを使用する


for-eachと組み合わせて使用することができるコレクションクラスは、java.lang.Iterableインターフェイスを実装しているコレクションクラスに対して使用することができます。

Iteratableインターフェイスを実装しているクラスは以下のとおりです:








ArrayBlockingQueueArrayListAttributeList
BeanContextServicesSupportBeanContextSupportConcurrentLinkedQueue
CopyOnWriteArrayListCopyOnWriteArraySetDelayQueue
EnumSetHashSetJobStateReasons
LinkedHashSetLinkedListPriorityBlockingQueue
PriorityQueueRoleListRoleUnresolvedList
StackSynchronousQueueTreeSet
VectorLinkedBlockingQueue



構文:

for (データ型 ループ内で使用する変数名 : 集合を保持する参照変数名){
    //  繰り返して実行したい処理




例:

ArrayList list = new ArrayList();
list.add("スペード");


for (String value : list){

System.out.println(value);

}

2008年2月12日火曜日

VMWare WorkStationでドメインを構築する

VMWareでドメインの設定をするには以下の手順で行います。

VMWareでチームを作成する


1. [ファイル]→[新規]→[チーム]を選択。
2. チーム名を入れ、そのチームに仮想マシンを追加する。既存のイメージを追加すること可能だし、新規のイメージを作り、それを追加することもできる。
3. チームにLAN セグメントを一つ追加する。
4. 以下のような設定になる。






今回の場合、3台のマシンをドメインに入れました。



ActiveDirectoryサーバーの構築



1. 追加した3つのイメージのどれか(WindowsServer2003)を開き、[スタート]→[管理ツール]→[サーバーの構成ウィザード]を開きます。

2. ドメインコントローラ (ActiveDirectory)を線楽し、[次へ]をクリックします。

7. ActiveDirectoryのインストールウィザードが立ち上がるので「新しいドメインのドメインコントローラ」を選択し、[次へ]をクリックします。

3. 「新しいフォレストのドメイン」を選択し、[次へ]をクリックします。

4. 適当なDNS名を入れます。例)testdomain.co.jp

5. NetBIOS名もそのままで[次へ]をクリックします。

6. ログを適当な場所に保存します(デフォルトのままでもオッケーです)。

7. DNS登録の診断で失敗の画面が出ますがそのまま無視して[次へ]で進みます。このエラーはDNSサーバを設定していないために起こるものですがこのまま続行すれば最終的にはDNSサーバの設定もできます。
8. 「Windows2000またはWindows Server2003 OSとのみ互換性があるアクセス許可」を選択し、[次へ]をクリックします。

9. パスワードを入力します。

10. これでActiveDirectoryの設定は完了です。



ネットワークの設定をする



1. ActiveDirectoryサーバーになっているサーバのIPを固定で割り振ります。ここではActiveDirectoryサーバのIPを192.168.0.100とします。


2. 次に他のVMWareチームに追加したマシンを選び、上記と同じように設定します。違うのはIPアドレスのみです。例えば二台目のマシンは192.168.0.101、三台目は192.168.0.102などと設定します。デフォルトゲートウェイ、優先DNSサーバーは192.168.0.100のままです。

3. すべてのマシンのネットワーク設定が終わったらPingで確認してみます。ADサーバ以外のマシンからPing 192.168.0.100と打ってみてレスポンスが返ってくるか確かめてみます。もし返ってこない場合にはファイアウォールが原因の場合があります。ファイアウォールの設定を無効にして再度試してください。

4. Pingの応答があればあとはドメインに各マシンを追加するのみです。ドメインへの追加はマイコンピュータのプロパティから行ってください。

2008年2月8日金曜日

HOSTSファイルでIPアドレスとホスト名を紐付ける

HOSTSファイルとは、TCP/IPプロトコルで通信を行なう場合に、通信を可能にするための名前解決のファイルです。
ファイルは以下にあります。

C:\WINDOWS\system32\drivers\etc\hosts
これをテキストエディタで開き、「127.0.0.1 localhost」の下に紐付けたいIPアドレスとホスト名を入れます。IPアドレスとホスト名の間にはタブを入れます。

例:
127.0.0.1 localhost
172.16.16.26 hostname


上記を設定することでローカルマシンから http://172.16.16.26/ と打っても、http://hostname/ と打っても同じになります。

2008年2月7日木曜日

プロセスのログを記録する。

最近Tomcatが急に落ちるといった現象がある。急に落ちるのでTomcatのログには残らない。ワトソンのログにもイベントビューアにも記録されない。困った。。。。そこでプロセスのログをカスタマイズすることにした。方法は以下の通りです。

1. コンピュータの管理 -> パフォーマンスログと警告 -> カウンタログ で「新しいログの設定」を選択。

2. 「新しいログの設定」画面で適当に名前を入力。

3. 以下のような画面が出るので[カウンタの追加]をクリック



















4. 例えば今回はJVMのプロセスのログを取りたいとしたら以下のようにパフォーマンスオブジェクトで「Process」を選択し、Javaのインスタンスを選択する。そして記録したいカウンタをそれぞれ選択し、[追加]していく。
















5. 追加し終えたら[閉じる]を押し、次に[ログファイル]タブを開く。ログファイルを種類を選び、[構成]ボタンをクリックする。ここでログファイルの保存先とサイズの指定ができるので設定する。


6. 次に[スケジュール]タブを開き設定する。私の場合は手動設定にし、5で設定したログファイルのサイズがいっぱいになったときは新しいログファイルを開始するといった設定にした。



これで設定完了です。ログファイルを開くと[全般]タブで指定した間隔ごとのログが記録されているのが分ります。
こんな感じに↓
==================================================================
(PDH-CSV 4.0) ()(-540)    % Processor   TimePage File Bytes Peak  Thread Count
02/07/2008 17:52:21.009   0 3.22E+08            52
02/07/2008 17:52:36.009 0 3.22E+08 52
==================================================================

2008年2月5日火曜日

Java-Com Bridgeを使う(PowerPoint編)

例えば以下のようなSubプロシージャがある

===========================================================
Private Sub RemoveTextInShape(thisShape As Shape)
If thisShape.HasTextFrame = msoTrue Then
thisShape.TextFrame.TextRange.Text = RemoveInText(InjectCharacters(thisShape.TextFrame.TextRange.Text))
End If

If thisShape.HasTable = msoTrue Then
Dim thisRows As Rows
Set thisRows = thisShape.Table.Rows
Dim thisRow As Row
For Each thisRow In thisRows
Dim thisCells As CellRange
Set thisCells = thisRow.Cells
Dim thisCell As Cell
For Each thisCell In thisCells
RemoveTextInShape thisCell.Shape
Next
Next
End If
End Sub

===========================================================

これをJava-Com Bridgeを使用してJava流に書き直すと以下のようになる

===========================================================

public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String openUrl = "C:\\java_test\\sample.ppt";

oPPT = new ActiveXComponent("PowerPoint.Application");

try{

oPPT.setProperty("Visible", new Variant(true));
Object oPresentations = oPPT.getProperty("Presentations").toDispatch();
Object oPresentation = Dispatch.call(oPresentations, "Open", openUrl).toDispatch();
Object oActivePresentation = oPPT.getProperty("ActivePresentation").toDispatch();
Object oSlides = oPPT.call(oActivePresentation, "Slides").toDispatch();
int totalSlides = oPPT.call(oSlides, "Count").toInt();

//Slideの配列を作成する
ArrayList<Object> thisSlides = new ArrayList<Object>();
for (int i = 1; i < totalSlides + 1; i++){

Object slideObj = oPPT.call(oActivePresentation, "Slides", new Variant(i)).toDispatch();
thisSlides.add(slideObj);
}

System.out.println("スライドの総数は " + thisSlides.size());
for(int i = 0; i < thisSlides.size(); i++){

System.out.println("Slide ID: " + oPPT.call(thisSlides.get(i), "SlideID").toInt());
Object oShape = oPPT.call(thisSlides.get(i), "Shapes").toDispatch();
int totalShapes = oPPT.call(oShape, "Count").toInt();
//System.out.println("totalShapesは " + totalShapes);

//個々のshapeに対して実行する。
for (int n = 1; n < totalShapes + 1; n++){
Object shapeObj = oPPT.call(thisSlides.get(i), "Shapes", new Variant(n)).toDispatch();
removeTextInshape(shapeObj);
}

}
Dispatch.call(oPresentation, "Save");

} catch (ComFailException e){
System.err.println(e.getMessage() + e.getHResult());
} finally {
Dispatch.call(oPPT, "Quit");
ComThread.Release();
}

}

private static ActiveXComponent oPPT;

===========================================================

要は Object slideObj = oPPT.call(oActivePresentation, "Slides", new Variant(i)).toDispatch(); をスライドの数だけループし、いちいちSlides配列を作成する必要がある。とっても面倒くさい。。

XSLでクォーテーション内に文字を入れたい時

例えばXMLで以下のような記述があったとします。
<link>
<url path="http://www.google.co.jp" name="Googleのホーム"></url>
<url path="http://www.yahoo.co.jp" name="Yahooのホーム"></url>
</link>

これにXSLを当てて動的に以下のようにしたい時
<a href="http://www.google.co.jp">Googleのホーム</a>
<a href="http://www.yahoo.co.jp">Yahooのホーム</a>

普通にやると以下のように書きます。
<xsl:template match="url">
 <a href="<xsl:value-of select="@path" />">="<xsl:value-of select="@name" /></a>
</xsl:template>

しかし、、、これでブラウズすると「文字 '< ' は、属性値内に使用できません。」とエラーになってしまいます。どうするか。。。で最終的のこんな具合に

<xsl:template match="link/url">
 <a>
<xsl:attribute name="href"><xsl:value-of select="@path" /></xsl:attribute>
<xsl:value-of select="@name" />
</a>
</xsl:template>

<xsl:attribute name>を使うと属性が作成できるようです。

2008年2月4日月曜日

PowerPointマクロで全角半角置換

Option Explicit

Function IsKatakana(strTarget As String) As Boolean
Dim strPattern
strPattern = "[ア-ンア-ン]" ' カタカナ範囲チェック用
Dim reg As Object
Set reg = CreateObject("VBScript.RegExp") ' 正規表現コンポーネントを利用
reg.Pattern = strPattern
IsKatakana = reg.Test(strTarget)
Set reg = Nothing
End Function

Sub ChangeKanaText2()
' スライドを取得
Dim sld As slide
For Each sld In ActiveWindow.Parent.Slides
' スライド内のシェイプオブジェクト(テキストボックス等)を取得
Dim shp
For Each shp In sld.Shapes
' シェイプが TextFrame を持つ場合のみ後続の処理を実行
If shp.HasTextFrame Then
' シェイプ(テキストボックス等)の単語を取得
Dim word
For Each word In shp.TextFrame.TextRange.Words
' 文字列の置換
If IsKatakana(word.Text) = True Then
' カタカナの場合は全角に変換
word.Text = StrConv(word.Text, vbWide)
Else
' それ以外は半角に変換
word.Text = StrConv(word.Text, vbNarrow)
End If
Next
End If
' シェイプが 表 を持つ場合(追加)
Dim myRow As Row
Dim myCell As Cell
If shp.HasTable Then
For Each myRow In shp.Table.Rows
For Each myCell In myRow.Cells
For Each word In myCell.Shape.TextFrame.TextRange.Words
If IsKatakana(word.Text) = True Then
word.Text = StrConv(word.Text, vbWide)
Else
word.Text = StrConv(word.Text, vbNarrow)
End If
Next
Next
Next
End If
Next
Next
End Sub

Javaで半角を全角に置換するメソッド

//以下ソース-----------------------------------------------


public class HankakuToZenkaku {

/** 全角英数字 */
private static String sZen = "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";

/** 半角英数字 */
private static String sHan = "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

/**
* 半角英数字->全角英数字に置換する。
* 原理は、置換対象文字列 sSrc から1文字づつ取り出して
* sHan に該当する文字があったら、その文字が何文字目にあるか取得して、sZen から同じ文字目から文字を
* 取ると、全角にすり返るという方法。
* 例)
* sSrc = "ab1";
* 1番目の文字 "a" は、sHanの36文字目なので、sZenの36文字目は、"a"で、置換
* 2番目の文字 "b" は、sHanの37文字目なので、sZenの37文字目は、"b"で、置換
* 3番目の文字 "1" は、sHanの1文字目なので、sZenの1文字目は、"1"で、置換
* @param args
*/
public static void main(String[] args) {

String sSrc = "aABBあ漢字-zYあ"; //変換対象文字

//対象文字数分ループ
for (int iLoop = 0; iLoop < sSrc.length(); iLoop++) {

//1.対象文字列よりiLoop番目の文字取得
//2.文字型を文字型に変換
//3.sHan(半角文字)の何番目に該当するか取得->iPosに格納
int iPos = sHan.indexOf(String.valueOf(sSrc.charAt(iLoop)));

//sHan(半角文字)に該当する文字があった場合
if(iPos > -1) {

//sSrc = sSrcの0~iLoop番目の文字列を取得
// + sZen(全角文字)からiPos番目の文字を1つ取得
// + sSrcのiLoop番目+1より後ろの文字列を取得
sSrc = sSrc.substring(0,iLoop) + sZen.charAt(iPos) + sSrc.substring(iLoop+1);
}
}

//変換後出力
System.out.println(sSrc);
}
}

2008年1月30日水曜日

Tomcat5.5でアクセスログを作成する

Tomcatでアクセスログを作成するにはServer.xmlかコンテキスト名.xmlに以下を記述するだけで良いです。

directory="logs/AccessLog"
prefix="tomcat_accs_"
suffix=".log" />

それぞれの属性についてはhttp://www.javaroad.jp/opensource/js_tomcat6.htmを参照してください。

Server.xml(CATALINA_HOME\conf)はTomcatにあるすべてのWEbアプリケーションにアクセスしたログを記録します。記述する際にはタグの間に上記のタグを追加するだけです。
それに対してコンテキスト名.xml(CATALINA_HOME\conf\Catalina\localhost)は特定のWebアプリケーションに対するログのみを記録するのに使用します。通常、コンテキスト名とWebアプリケーション名(XXXX.warなどのXXXX)は同じになっています。
記述する際にはタグの間に上記のタグを追加します。

2008年1月23日水曜日

IE7でJavascriptを実行しようとするとエラーになる問題

IE7でJavascriptを含んだHTMLを実行しようとすると以下のエラーになった。

「文字が正しくありません」
「オブジェクトを指定してください」

色々調べてみるとMSのサポートサイトを参照しろとあった。
http://support.microsoft.com/kb/934366/ja

しかしなぜか直らない。
どうもエンコーディングの問題らしいのだが。
結局以下のようにして問題は解決しました。
HTMLとあるがこれは元々はXMLにXSLをあてて作成したものなのです。その際にエンコーディングの設定をしてhtmlに出力するという記述を加えたところみごとに成功!

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="utf-8" method="html" indent="yes" />

もちろん、XSL、JSともにUTF-8で保存してあります。

前にもJavascriptがIE7で実行できないという問題があったが、この時はJSファイルをUTF-8保存したら実行できるようになった。どうもIE7はエンコーディングに対して注意を払う必要があるらしい。

2008年1月22日火曜日

Java-Com Bridgeを使う

以下のようなVBScriptがあります。

===========================================================
'日本語から英語への翻訳の場合に、全角の英数字、記号を半角に変換するスクリプトです
Dim objWord
Set objWord = CreateObject("Word.Application")
'objWord.Visible = TrueobjWord.Documents.Open(WScript.Arguments.Item(0))
' 検索条件の指定 objWord.Selection.Find.ClearFormatting
objWord.Selection.Find.Text = "[0-9A-Za-z!-?「」[] .,]"
objWord.Selection.Find.Forward = True
objWord.Selection.Find.Wrap = 1
objWord.Selection.Find.Format = False
objWord.Selection.Find.MatchCase = False
objWord.Selection.Find.MatchWholeWord = False
objWord.Selection.Find.MatchByte = False
objWord.Selection.Find.MatchAllWordForms = False
objWord.Selection.Find.MatchSoundsLike = False
objWord.Selection.Find.MatchFuzzy = False
objWord.Selection.Find.MatchWildcards = True

Do While objWord.Selection.Find.Execute
objWord.Selection.Range.CharacterWidth = 6
objWord.Selection.MoveRight
Loop

objWord.Selection.WholeStory
objWord.Selection.Font.Name = "MS Pゴシック"
objWord.ActiveDocument.Save
objWord.Documents.Close
objWord.Quitset objWord = nothing

===========================================================

これをJacob.jar(http://www.land-of-kain.de/docs/jacob/)を使用してJavaで実行しようとすると以下のようになります。

===============================================================
import com.jacob.com.*;
import com.jacob.activeX.*;

中略

String openUrl = "D:\Test\sample.doc";

ActiveXComponent oWord = new ActiveXComponent("Word.Application");

try{
Object oDocuments = oWord.getProperty("Documents").toDispatch();
Object oDocument = Dispatch.call(oDocuments, "Open", openUrl).toDispatch();
Object oSelection = oWord.getProperty("Selection").toDispatch();

//ここから半角処理
Object oFind = oWord.call(oSelection, "Find").toDispatch();
Dispatch.call(oFind, "ClearFormatting");
Dispatch.put(oFind, "Text", "[0-9A-Za-z!-?「」[] .,]");
Dispatch.put(oFind, "Forward", true);
Dispatch.put(oFind, "Wrap", 1);
Dispatch.put(oFind, "Format", false);
Dispatch.put(oFind, "MatchCase", false);
Dispatch.put(oFind, "MatchWholeWord", false);
Dispatch.put(oFind, "MatchByte", false);
Dispatch.put(oFind, "MatchAllWordForms", false);
Dispatch.put(oFind, "MatchSoundsLike", false);
Dispatch.put(oFind, "MatchFuzzy", false);
Dispatch.put(oFind, "MatchWildcards", true);

while (Dispatch.call(oFind, "Execute").toBoolean()){
Dispatch oRange = Dispatch.call(oSelection, "Range").toDispatch();
Dispatch.put(oRange, "CharacterWidth", 6);
Dispatch.call(oSelection, "MOveRight");
}

Object oWholeStory = oWord.call(oSelection, "WholeStory");
Object oFont = Dispatch.get(oSelection, "Font").toDispatch();
Dispatch.put(oFont, "Name", "MS Pゴシック");
Object oActiveDocument = oWord.getProperty("ActiveDocument").toDispatch();
Dispatch.call(oActiveDocument, "Save");

} catch (ComFailException e){
System.err.println(e.getMessage() + e.getHResult());
} finally {
Dispatch.call(oWord, "Quit");
ComThread.Release();
}

使い方
MS Wordを操作するのであれば以下の2行は必ず必要です。

ActiveXComponent oWord = new ActiveXComponent("Word.Application");
Object oDocuments = oWord.getProperty("Documents").toDispatch();

次に例えばVBでobjWord.Selection.Range.CharacterWidth = 6 とある記述をJavaで書くには、まずRangeオブジェクトを作成、そこからCharacterWidthプロパティに6を入れるといった記述をする。
RangeはSelectionオブジェクトのメソッドなのでまずはSelectionオブジェクトを作成する。
Selectionオブジェクトの上はMS WordのActiveXComponentなので既にで作成されている。

ということで手順は
1. でSelectionオブジェクトの作成をする。
2. でRangeオブジェクトを作成する。
3. でCharacterWidthプロパティに値をセットする。

となる。
メソッドやプロパティに値をセットする時は必ずそれを実行するためのオブジェクトを作成する必要があります。

メソッドの実行方法
Dispatch.call(オブジェクト名, メソッド名);

プロパティの設定方法;
Dispatch.put(オブジェクト名, プロパティ名,プロパティ 値);

2008年1月15日火曜日

ASP.NETのWEB Serviceを公開する。

ASP.NETの作成手順

1. Visual Studio2005の[File] →[New Web Site]で「ASP .Net Web Service」を選択する。
2. service.vbにコードを書く
3. service.asmxを開き、2で記述したclass名をこのファイルにも記述する。
4. [Build] → [Buid Web Site]でコンパイルする。
5. コンパイルしてできあがったファイルをIISのディレクトリにコピーする。コピーしたファイルは以下のものです:

Service.asmx
web.config
App_Code\Service.vb

これをIISの既定のWebサイトの直下にコピー

IISがASP.NETを実行できるようにする

1. コマンドプロンプトで以下を実行する。
  C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -i
  * バージョンは環境によって異なる。このバージョンを調べるにはIISマネージャを開き、「既定のWebサイト」のプロパティを開き、ASP.NETタブを開き、バージョンが何になっているかを確認する。
2. IISマネージャを開き、Webサービス拡張を開く。
3.ASP.NET v2.0.50727 を「許可」にする。
4. サーバーから「http://localhost/service.asmx実行し、開けるかどうかを確認する。
5. 開けたら今度は外部からの接続を試してみる

2008年1月14日月曜日

Googleアカウントとの紐付け

https://www.google.com/accounts/AddNonGmailAlternate
で追加のメール アドレスを Google アカウントに関連付けることができます。

はじめてのブログ


自分はブログというか日記というものを今まで書いたことがない。なぜこの歳になって書こうかと思ったかというと最近物忘れがひどいのです。なのでStop the 物忘れということでブログのタイトルもForget me notとしました。
あまり面白いことも書くつもりもありませんが何か役に立つことも書くかもしれません。

自己紹介

最近気胸になりました。でタバコやめました。