2011年11月30日水曜日

[Linux][MySQL][CentOS][バイナリ形式][インストール]LinuxへのMySQLのインストール

Linux(CentOS 6.0)にMySQLのバイナリバージョン(コンパイル済みバージョン)をインストールする方法は、次の通り。

1. googleなどの検索エンジンで "MySQL Linux ダウンロード" などのキーワードを打ち込み、資材をダウンロードする。

2. Linux向けのバイナリバージョン(.tar.gz形式のもの)をダウンロードする。

3. インストールするLinuxマシンにrootでログインする。

4. /usr/local直下にダウンロードした.tar.gz形式の資材をコピーする。
    ※ /usr/localディレクトリは全ユーザ共通のアプリケーションをインストールする場合に使用するディレクトリ。

5. /usr/localで、次のコマンドを打ち込む。

    groupadd mysql
    useradd -r -g mysql mysql
    cd /usr/local
    tar zxvf /tmp/mysql-5.1.60-linux-i686-glibc23.tar.gz
    ln -s /usr/local/mysql-5.1.60-linux-i686-glibc23 mysql
    cd mysql
    chown -R mysql .
    chgrp -R mysql .
    scripts/mysql_install_db --user=mysql
    chown -R root .
    chown -R mysql data
    groupadd mysql
    useradd -r -g mysql mysql
    cd /usr/local
    tar zxvf /tmp/mysql-5.1.60-linux-i686-glibc23.tar.gz
    ln -s /usr/local/mysql-5.1.60-linux-i686-glibc23 mysql
    cd mysql
    chown -R mysql .
    chgrp -R mysql .
    scripts/mysql_install_db --user=mysql
    chown -R root .
    chown -R mysql data
    cp support-files/my-medium.cnf /etc/my.cnf
    cp support-files/mysql.server /etc/init.d/mysql.server

    ※ このコマンドは、INSTALL_BINARYというファイルに記載されている。
        (ダウンロードした資材を解凍すると生成されるディレクトリの直下にある)
        ネット上のバイナリインストール記事を見ても、うまくインストールできないことがある。
        (バージョンによって、若干手順が異なる)
        そのため、初期のインストールは.tar.gzに含まれているコマンドを打つ方が確実である。

    ※ 最後の2つのコマンドでは、デフォルトの設定ファイルをコピーし、Linux起動時に
        MySQLが自動で起動するよう設定している。

6. 設定ファイルに文字コードの設定、トランザクションの設定を追記する。

    /etc/my.cnfに、次の設定を追加。

    [mysqld]
    (中略)
    default-character-set=sjis
    innodb_data_home_dir = /usr/local/mysql/data
    innodb_data_file_path = ibdata1:10M:autoextend
    innodb_log_group_home_dir = /usr/local/mysql/data

    [mysqldump]
    (中略)
    default-character-set=sjis

    ※ 文字コードはきちんと指定しないと誤動作を招きやすいため、必ず指定する。

    ※ InnoDBを有効化しないとトランザクションが使えず、ロールバックができない。
        Linuxの場合は、CREATE TABLE時にInnoDBを使うことを明示的に宣言しないと、
        トランザクションが有効にならない。(Windowsの場合は明示なしでも可)

7. MySQLのrootアカウントのパスワードを変更する

    mysql> SET PASSWORD FOR root@localhost=password('[変更後のパスワード]');

    ※ デフォルトでMySQLのrootパスワードなしとなる。
        アプリケーションを作成する上で、まれにrootのパスワードがないとできなくな
        る操作があるため、パスワード設定が必要な場合は、rootで一度MySQLにログイン
        して、このコマンドを打つこと。

    ※ MySQLにログインする場合は、次のコマンドを実行する。

        /usr/local/mysql/bin/mysql -uroot

8. マシンを再起動し、次のコマンドを打ってMySQLの起動を確認できれば成功。

    ps -eaf | grep mysql

    ※ mysqlのデーモンが起動していることが確認できればOK。

2011年11月18日金曜日

[Spring][Form][Controller]フォームクラスとコントローラクラスの記述

コントローラクラスは@Controllerというアノテーションを付与することで、Springフレームワークに自動認識させることができる。(ただし名前によるコントローラ認識の設定ファイル記述は必要)

@Controller
public class SampleController {

画面入力項目を集めたフォームクラスを定義し、コントローラクラスに設定するための記述方法は、次の通り。

    @ModelAttribute
    public SampleForm setSampleForm() {
        return new SampleForm();
    }

コントローラクラス内でModelAttributeアノテーションを使い、フォームクラスをnewするsetterメソッドを作ることで、サブミット時に画面入力項目のデータがフォームクラスに設定されるようになる。

HTTPプロトコルのGETに対応するハンドラメソッドを作りたい場合は、次のように記述する。

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView toInitialPage() {

戻り値はStringでもよく、その場合はビューのリソース位置をreturnする。

    @RequestMapping(method = RequestMethod.GET)
    public String index() {
        return "/index/index";
    }

このように記述した場合/WEB-INF/jsp/index/index.jspを指す。(ただしリソースパスはweb.xml等で設定したものによって変わる)
DTOなど、画面表示項目がある場合は、それをModelAndViewクラスに設定してreturnする。

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView index() {

        // 画面表示項目の取得

        // 画面出力内容を設定する
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("sampleDto", sampleDto);

        // 画面遷移を行う
        return modelAndView;
    }

sampleDtoというDTOクラスには、画面表示用の項目を設定してあるものとする。
上記のように記述した場合、JSPのEL式で${sampleDto}と記述すればアクセスできる。
${sampleDto.id}など、DTOクラスのメンバにもアクセス可能である。(この辺りは通常のEL式の使い方と同じ)

フォームクラスを定義し、サブミット時にフォームクラスのデータを引数として取得したい場合は、次のように記述する。

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView onSubmit(SampleForm sampleForm, BindingResult bindingResult) {

HttpSessionの情報を受け取りたい場合は、次のように記述する。

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView onSubmit(HttpSession session) {

引数・戻り値に応じてSpringフレームワークが自動で設定・取得を行ってくれる。

[Spring][hibernate][設定]xxx-servlet.xmlの記述(後半)

Springアプリケーションのビュー(URL指定の解釈)は、次のように設定する。

  <!-- ViewResolver -->
  <bean id="internalResourceViewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass">
      <value>org.springframework.web.servlet.view.JstlView</value>
    </property>
    <property name="prefix">
      <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
      <value>.jsp</value>
    </property>
  </bean>

"/WEB-INF/jsp/[任意の文字列].jsp" という名前をビューの名前として認識する。
http://localhost:8080/sample/sample.html
上記設定でURLを(↑)このように指定した場合、/WEB-INF/jsp/sample.jspが該当するビューであると認識する。

サーブレットの設定ファイルには、例外処理についても規定できる。

  <!-- ExceptionHandler -->
  <bean id="exceptionHandler"
        class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
      <value>
        java.lang.Exception=exception
      </value>
    </property>
  </bean>

このように設定した場合、コントローラクラスでjava.lang.Exception例外が発生した場合、/WEB-INF/jsp/exception.jspに遷移する。
exception.jspには「システムエラーが発生しました」等の表示を行う。(もしくはアプリケーションによっては、そのまま別のページにリダイレクトする。この辺りはエラー処理の取り決めによる)

前半部でインジェクションのためのコンポーネントスキャン設定で、特定のパッケージ配下にある全てのクラスを自動でインジェクションしたが、個々のクラスでインジェクション設定を記述することもできる。
例えば、SampleDaoインターフェースにSampleDaoImplクラスをインジェクションし、プロパティとしてdataSourceを持たせる場合は、次のように記述する。

  <bean id="sampleDao" class="sample.dao.SampleDaoImpl">
    <property name="dataSource">
      <ref bean="dataSource" />
    </property>
  </bean>

Spring version3以降を使用する場合は、コンポーネントスキャンにより書かなければならない設定を大幅に減らすことができる。
コンポーネントスキャンで読ませたクラスを@Autowiredで設定する方法が推奨される。

[Spring][hibernate][設定]xxx-servlet.xmlの記述(前半)

web.xmlにDispatcherServletの設定を記述すると、applicationContext.xmlの次に "[サーブレット名]-servlet.xml" という名前の設定ファイルをSpringが自動的に探して、設定を読み込む。

設定ファイルの読み込み順序は、次の通り。
web.xml → applicationContext.xml -> [サーブレット名]-servlet.xml

サーブレット設定のファイルでは、定義したbean間の依存関係等を記述する。
冒頭部のエンコード設定等は他の設定ファイルと同じく、Springに付属しているサンプル等からコピーする。
(この記述は、Spring3.0.2(Java1.6、Tomcat6.0)を動かしたときの設定)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-3.0.xsd
  http://www.springframework.org/schema/aop
  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

コントローラを名前によって自動で識別させる場合は、次のように記述する。

  <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />

このように記述すると例えばURLに
http://localhost:8080/sample/index.html
と指定した場合、SpringフレームワークがIndexControllerというクラスを自動で探す。
LoginFormControllerのように、2つ以上の単語が複合する名前の場合、全て小文字で表記する。
http://localhost:8080/sample/loginform.html
(↑)こうURL指定すると、SpringフレームワークがLoginFormControllerというクラスを自動で探す。

DIを自動で行わせるためにDI対象のクラスを自動スキャンする設定は、次の通り。

  <context:component-scan base-package="sample.dao.impl" />

DAOインターフェイスに対応するDAO実装クラスが "sample.dao.impl" パッケージにあるとき、上記のように記述することで、同パッケージ配下の全てのクラスをDI対象として読み込む。
ただしDIに使いたいクラスの宣言部に@Componentアノテーションを付けておく必要がある。

@Complnent
public class SampleUserDaoImpl implements SampleUserDao {

DI対象として読み込まれたクラスを使いたい場合は、@Autowiredアノテーションを付けて宣言する。
例えばSampleUserDaoというインタフェースをDIで使いたい場合は、このインターフェースを使いたいクラスで次のように記述する。

@Autowired
private SampleUserDao sampleUserDao;

先にコンポーネントスキャンで、sample.dao.implパッケージ配下を読ませているので、同パッケージ配下にある実装クラスがインジェクションされる。
DAOクラスをインターフェースとしているのは、実装のDI設定を柔軟に変更できるようにするため。
例えばテストのために固定データをreturnするだけのモックをDIさせたい場合は、コンポーネントスキャンでモックのパッケージを指定する。(SampleUserDaoインターフェースの実装がモックに差し替わる)

この他、ビューや例外処理の記述もあるが、長くなりすぎるため別の記事とする。

2011年11月17日木曜日

[Spring][hibernate][applicationContext.xml][設定ファイル]Springの設定ファイル記述について

"web.xml" と同様、WEB-INF直下に "applicationContext.xml" という名前で設定ファイルを置く。
web.xml内にリスナの設定が書かれていれば、applicationContext.xmlというファイルをSpringフレームワークが自動的に探して設定を読む。

このファイルには、データソース(DB設定)等のbean設定を記述する。
ここでbeanとして定義されたものをDIで使うことができる。ファイルの冒頭では、次のように記述する。
(この記述は、Spring3.0.2(Java1.6、Tomcat6.0)を動かしたときの設定)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-3.0.xsd
  http://www.springframework.org/schema/aop
  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

エンコーディングはUTF-8としている。
web.xmlのエンコーディングをShift_JISにしていても、ここはUTF-8と書いて問題ない。(動作する)
データベースがShift_JISでWebアプリはUTF-8など、開発条件・制約は様々あるので臨機応変に設定を変更する。

hibernateの設定をhibernate.cfg.xmlから読み込む場合は、次のように記述する。

  <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="configLocation">
      <value>/WEB-INF/src/hibernate.cfg.xml</value>
    </property>
  </bean>

O/Rマッピングのフレームワークとしてhibernateを単体で使う場合、hibernate.cfg.xmlをクラスパス上に置くことでhibernateは自動的にこの名前の設定ファイルを読みに行くが、Springと組み合わせて使う場合はこのように記述する。
hibernate.cfg.xmlを使わず、applicationContext.xmlに設定を書く方法もあるが、こちらはSpring独自の文法でhibernate設定を書き直さねばならない。hibernate単体の資産がある場合は、上記の書き方が推奨される。

applicationContext.xmlにsessionFactoryを定義しておくことで、DIによりどのソースコードでもSessionFactoryを取得できるようになる。SessionFactoryでopenSessionを行えば、トランザクション制御も可能になる。
Spring3以降は、SessionFactoryを使うべき位置にDIで挿入することが推奨されている。

Spring固有の設定としては、メッセージリソースの設定がある

  <!-- MessageSource -->
  <bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames">
      <list>
        <value>messages</value>
      </list>
    </property>
  </bean>

このように記述しておくことでmessages.propertiesファイルにあるプロパティを使うことができる。
エラーメッセージ等を key=value の形式で記述しておき、keyでプロパティからvalueを取得できる。

最後に</beans>タグで設定を閉じて完了。

[Spring][web.xml][設定ファイル]Springの設定ファイル記述について

Springフレームワークに必要となる設定ファイルはいくつかあるが、まずは "web.xml" の設定を行う。
他の全ての設定ファイルを作る前に、このファイルを作成する。
(設定ファイルは上位→下位の順に作成していくと分かりやすい)

web.xmlはフレームワークを使わないサーブレットプログラムと同様、クラスパス上に置く。(WEB-INF/web.xmlなど)
Tomcat等のAPサーバが持っているweb.xmlにない、アプリケーション独自の設定を追加するために必要である。
Springフレームワークを使うときは、最初にXMLのバージョンとエンコードを設定する。

<?xml version="1.0" encoding="Shift_JIS"?>

昨今のプロジェクトでは、UTF-8が増えているがここではShift_JISで解説する。
(ただし設定ファイルごとにエンコードは変えてもいいので、別のファイルはUTF-8で作成する。後述)

次に、web-appタグを記述する。
次の記述は、Spring3.0.2(Java1.6、Tomcat6.0)を動かしたときの設定。

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

JSP中で使えるEL式等が異なるため、この設定は重要。
(例えばこの設定だと、Java1.5、Tomcat5.5で動かない)
ネットを調べて探し当てるのは時間と労力の無駄遣いなので、ダウンロードしたSpringフレームワークに付属しているサンプルの設定ファイルをコピーすること。
そうでなければ既存の動いている信頼性のあるサンプル(書籍のおまけでも何でも)からコピーする。

日本語対応させるためには、次の設定を記述する。

  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>Shift_JIS</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>

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

ここでは日本語コードをShift_JISとしている。
encodingの箇所を変更すれば、日本語コードを変更できる。

Springの設定ファイルを読み込ませるためのリスナ設定は、次の通り。

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

Springフレームワーク使う宣言のようなもので、こう記述するとSpringの設定ファイルとして "/WEB-INF/applicationContext.xml" を読むようになる。
applicationContext.xmlというファイル名はデフォルトで、通常はこの名前を用いる。

サーブレットの設定は、次の通り。

  <servlet>
    <servlet-name>[プロジェクト名]</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>[プロジェクト名]</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>

[プロジェクト名]の箇所はeclipseのプロジェクト名を記述する、で構わない。(後で変更してもよい)
Tomcat等のAPサーバを起動後、"http://localhost:8080/[プロジェクト名]/index.html"といったアクセスとなる。
servlet-mappingは"index.html"の部分のことを示す。
ブラウザのURLに"http://localhost:8080/[プロジェクト名]/index.html"と入力してEnterを押した場合、index.htmlに対応するコントローラをSpringフレームワークが探すこととなる。
ちなみにこう書いた場合"index.jsp"を指すが、それは別の設定ファイルでprefixとsuffixを操作しなくてはならない。(後述)

ここまでの設定を順番に記述し、</webapp>タグで閉じればweb.xmlの記述は完了。

2011年11月11日金曜日

[hibernate][select][join]多対一の関係にあるテーブルで結合を行う

多対一の関係にあるテーブルのデータも読み込むためには、HQL内でjoinを呼び出す。
(joinをHQLに書かなくても読み込むことができるが、バックグラウンドで発行されるSQLは複数になる)

例えば「サンプルサービスユーザ」に「都道府県」の情報が付随しているとする。
ユーザが住んでいる都道府県がデータベースに格納される仕様だとすると、ユーザの分だけ都道府県の情報が登録される。
「サンプルサービスユーザ」と「都道府県」は、多対一の関係になる。

このときエンティティのコードは、次のようになる。(setter/getter省略)

    /** 都道府県 */
    @Entity(name = "PREF")
    public class Pref {

        /** 都道府県ID */
        @Id
        @GeneratedValue
        @Column(name = "PREF_ID")
        private Integer prefId;

        /** バージョン(楽観ロック用) */
        @Version
        @Column(name = "VERSION")
        private Integer version;

        /** 都道府県名 */
        @Column(name = "PREF_NAME")
        private String prefName;
    }

    /** サンプルサービスユーザ */
    @Entity(name = "SAMPLE_SERVICE_USER")
    public class SampleServiceUser {

        /** ユーザID */
        @Id
        @GeneratedValue
        @Column(name = "SAMPLE_SERVICE_USER_ID")
        private Integer sampleServiceUserId;

        /** バージョン(楽観ロック用) */
        @Version
        @Column(name = "VERSION")
        private Integer version;

        /** メールアドレス */
        @Column(name = "MAIL")
        private String mail;

        /** パスワード */
        @Column(name = "PASSWORD")
        private String password;

        /** ニックネーム */
        @Column(name = "NICKNAME")
        private String nickname;

        /** 都道府県 */
        @ManyToOne
        @JoinColumn(name = "PREF_ID")
        private Pref pref;
    }

@ManyToOneアノテーションにより、都道府県テーブルとの多対一の関係を明示する。
@JoinColumnアノテーションにより、外部キーを指定する。
HQLは、次の通り。(セッション取得までは省略)

    // 登録ユーザIDによる検索を行う
    List list = session.createQuery(
            "from SAMPLE_SERVICE_USER u" + " inner join u.pref p").list();

このように記述することで、バックグラウンドではINNER JOINのSQLが発行される。
このクエリでSAMPLE_SERVICE_USERエンティティを読み込むと、prefの中に都道府県の情報も入っている。

[hibernate][select]可変パラメータを含むHQLの発行

可変パラメータを含む検索を行いたい場合は、次のように記述する。
例えば「メールアドレスが一致しているユーザの情報を取得する」という場合、メールアドレスが可変パラメータとなる。
下記はサンプルコード。

// コンフィギュレーションを作成する
Configuration config = new Configuration().configure();

// セッションファクトリーを作成する
SessionFactory sessionFactory = config.buildSessionFactory();

// セッションを取得する
Session session = sessionFactory.openSession();

// メールアドレスによる検索を行う
List list = session.createQuery(
        "from SAMPLE_SERVICE_USER u" + " where u.mail = :mail")
        .setParameter("mail", "test@test.co.jp").list();

検索結果をエンティティのリストとして取得する場合、createQueryにselectは書かなくてよい。
fromの次は、@Entityアノテーションのname属性で指定した名前(データベースのテーブル名)を指定する。
SAMPLE_SERVICE_USERをuという別名にし、同テーブルの属性mailでwhereを記述している。

whereの箇所で出ている":mail"の部分が可変パラメータとなる。
setParameterの第1引数に"mail"と書くと、":mail"の箇所が"test@test.co.jp"に置き換わる。

クエリの戻り値はObjectの配列となっているため、整形が必要。

// 結果を整理し、適切な形で呼び出し側に戻す
List<SampleServiceUser> sampleServiceUserList = new ArrayList<SampleServiceUser>();
for (int i = 0; i < list.size(); i++) {
    Object[] item = (Object[]) list.get(i);
    for (int j = 0; j < item.length; j++) {
        if (item[j].getClass() == SampleServiceUser.class) {
            sampleServiceUserList.add((SampleServiceUser) item[j]);
        }
    }
}

サンプルを動作確認が取れれば成功。

[hibernate][insert][update]データの新規追加もしくはアップデート

hibernateを使ってデータベースにデータを新規追加する、もしくは既存のデータを更新するサンプルは、次の通り。

    // コンフィギュレーションを作成する
    Configuration config = new Configuration().configure();

    // セッションファクトリーを作成する
    SessionFactory sessionFactory = config.buildSessionFactory();

    // セッションを取得する
    Session session = sessionFactory.openSession();

    // データを新規追加する
    SampleServiceUser sampleServiceUser = new SampleServiceUser();
    sampleServiceUser.setMail("test@test.co.jp");
    sampleServiceUser.setPassword("test");
    sampleServiceUser.setNickname("テスト");
    Integer id = (Integer) session.save(sampleServiceUser);

データの更新を行う場合は、Sessionクラスのupdateメソッドを使う。
(引数はsaveと同じ)

[hibernate][環境構築]サンプルプログラムの作成

別掲の[hibernateの環境構築]ができている状態で、次の手順を実行する。

1. エンティティクラスのソースファイルを作成する。

    @Entity(name = "SAMPLE_SERVICE_USER")
    public class SampleServiceUser {

        /**
         * ユーザID
         */
        @Id
        @GeneratedValue
        @Column(name = "SAMPLE_SERVICE_USER_ID")
        private Integer sampleServiceUserId;

        public Integer getSampleServiceUserId() {
            return sampleServiceId;
        }

        public void setSampleServiceUserId(Integer sampleServiceUserId) {
            this.sampleServiceUserId = sampleServiceUserId;
        }

        /**
         * バージョン(楽観ロック用)
         */
        @Version
        @Column(name = "VERSION")
        private Integer version;

        public Integer getVersion() {
            return version;
        }

        public void setVersion(Integer version) {
            this.version = version;
        }

        /**
         * メールアドレス
         */
        @Column(name = "MAIL")
        private String mail;

        public String getMail() {
            return mail;
        }

        public void setMail(String mail) {
            this.mail = mail;
        }

        /**
         * パスワード
         */
        @Column(name = "PASSWORD")
        private String password;

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        /**
         * ニックネーム
         */
        @Column(name = "NICKNAME")
        private String nickname;

        public String getNickame() {
            return nickame;
        }

        public void setNickname(String nickname) {
            this.nickname = nickname;
        }
    }

    上記はサンプル。
    @Entityアノテーションにより、クラスがエンティティであることを明示する。
    エンティティクラスに対応するテーブル名は、name属性で指定する。
    @Idアノテーションは、主キー(hibernateの場合はサロゲートキー推奨)に付与する。
    @GeneratedValueアノテーションは、IDを自動生成する場合に付与する。
    @Columnアノテーションにより、データベースのカラムに対応していること明示する。
    name属性には、データベース側のカラム名を記述する。
    @Versionアノテーションは、hibernateのバージョン番号による楽観ロックを使う場合に付与する。
    hibernateはデータベースに変更があるとversionを自動でインクリメントする。
    変更前後でversionの値が違う場合は、別のユーザによる変更があったものと見なし、エラーとする。(ロールバック)

2. 次のサンプルコードを動作させ、データが取得できることを確認する。

    サンプルコードを記述する前に、設定がなされていることを確認する。
    hibernate.cfg.xmlにエンティティクラスを読み込む設定を記述しておく必要がある。

    <mapping class="entity.SampleServiceUser" />

    また、データベースに何らかのデータを登録しておく必要がある。(動作確認のため)
    Javaのコードは、次の通り。

    // コンフィギュレーションを作成する
    Configuration config = new Configuration().configure();

    // セッションファクトリーを作成する
    SessionFactory sessionFactory = config.buildSessionFactory();

    // セッションを取得する
    Session session = sessionFactory.openSession();

    // ID=1のデータを取得する
    SampleServiceUser sampleServiceUser = (SampleServiceUser) session.get(
            SampleServiceUser.class, 1);

    SampleServiceUserが取得できていれば、hibernateが正常動作している。

[hibernate][環境構築]hibernateの環境構築

1. googleで"hibernate ダウンロード"と検索し、SourceForgeからhibernateをダウンロードする。

2. ダウンロードしたファイルを解凍し、libフォルダにあるjarをビルドパスに追加する。
    ※ hibernate3の場合は、解凍した直下のディレクトリにhibernate3.jarがあるので注意を要する。
    ※ 最小限の構成ならば、lib配下のrequiredディレクトリにあるjarのみでも動く。
        ただしjasperのjarなど、required以外のディレクトリにあるものも必要になるケースが多い。
        全部のjarをビルドパスに追加するのが無難。

3. hibernate.cfg.xmlを作成し、次のように内容を記述する。

    <!DOCTYPE hibernate-configuration PUBLIC
      "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
      "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

    <hibernate-configuration>
      <session-factory name="sessionFactory">
        <property name="show_sql">true</property>
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/[データベース名]</property>
        <property name="hibernate.connection.username">[データベースユーザ名]</property>
        <property name="hibernate.connection.password">[パスワード]</property>
        <mapping class="entity.SampleEntity" />
      </session-factory>
    </hibernate-configuration>

    上記は、MySQL5.x系の最小設定。
    <mapping class>タグで、O/Rマッピングしたいエンティティクラスを指定する。
    パッケージまで書く必要があるので注意を要する。

4. 作成したhibernate.cfg.xmlをクラスパスの通っているディレクトリに置く。

    コマンドラインで実行しているなら、クラスパスは-cpオプションで指定する。
    Eclipseを使っている場合は、プロジェクト直下のディレクトリにある.classpathファイルを見る。

    <classpathentry kind="src" path="WEB-INF/src"/>

    このように記述されていた場合は、プロジェクト配下のWEB-INF/srcディレクトリに設定ファイルを置く。
    実行時にクラスパスをサーチする場合、サブディレクトリまでは見ないので必ず該当ディレクトリの直下に配置すること。

5. ソースファイル上で次のコードを記述し、SessionFactoryが作成されることを確認する。

    // コンフィギュレーションを作成する
    Configuration config = new Configuration().configure();

    // セッションファクトリーを作成する
    SessionFactory sessionFactory = config.buildSessionFactory();

    // セッションを取得する
    Session session = sessionFactory.openSession();

    ※ 確認はデバッグ実行で実施し、例外が発生しなければOKと判断する。
        (設定ファイル読み込み確認まで、まだクエリは出せない状態)

2011年11月7日月曜日

[Seasar2][ドメイン駆動][ビジネスルール]ビジネスルールの外部化について

ドメイン駆動では、全ての業務ロジックをドメイン層に記述する。
従ってチェック等の処理もドメインもしくはリポジトリのクラスに記述するのが原則である。
このビジネスルールは業務をアプリケーションにしていく上で、最も変わりやすいものである。
この部分のロジックだけを外部化することにより、プログラムの柔軟性を高められる。

例えばプロジェクトがユースケース駆動を採用している場合、全ての業務チェックはユースケースに記述されることとなる。
ユースケースはシステムの機能を列挙したものであるから、そこに書かれている業務チェックは、全て機能ごとの業務チェックということになる。
オブジェクト指向プログラミングにおいては、「クラスを機能単位に分割してはいけない。モノ単位に分割する」という原則があるため、業務チェックをそのままクラスに実装しようとすると、重複するチェックが多数出てくる上、機能単位にまとめることもできないため、無理やり変な基本クラスを作って共通業務チェックを差し込むことになりかねない。

そのようなケースでは、機能ごとの業務チェックをクラスとし、複数の業務チェックで共通して行われるチェックは基本クラスとすべきである。
複数のクラスが相互作用した結果、特定の機能を実現されることから、こうしたチェックはどこかのクラスで呼び出されることとなる。業務チェックのクラスを必要なときだけnewして、チェックしたいインスタンスを渡し、エラーがあったら例外をスローする、などの共通処理を形成しやすい。

このような業務チェックは、ドメイン層(ドメインもしくはリポジトリ)と双方向関連のクラスとして定義すべきである。
例えば、次のようなビジネスルールがあったとする。

「ユーザはメールアドレスをユーザIDとしてサイトにユーザ登録する。よって、重複したメールアドレスを登録しようとした場合は、エラーとしなくてはならない」

このビジネスルールは、ユーザ登録時の業務チェックであることから、UserRegistrationBusinessRuleといったクラスを作成し、業務チェックのメソッドを作成する。

public class UserRegistrationBusinessRule {

    private UserRepository userRepository;

    public UserRegistrationBusinessRule(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void doCheck(String mail) throws BusinessRuleViolationException {

        UserDomain userDomain = userRepository.findByMail(mail);
        if (userDomain != null) {
            throw new BusinessRuleViolationException();
        }
    }
}

メールアドレスをキーとしてリポジトリに問い合わせを行い、データが見つかった場合はビジネスルール違反例外(ユーザが定義した独自例外)としている。
このビジネスルールクラスによるチェックを行う箇所では、次のようにコードを記述する。

new UserRegistrationBusinessRule(userRepository).doCheck();

複数のビジネスルールに共通するチェックを抽出したら、基本クラスを作成することで重複処理の記述を回避できる。
staticメソッドでも問題ないが、デコレータやストラテジといったデザインパターンを使う場合は、staticにすると却って不利になるのでここではインスタンス化している。

全ての業務ロジックをリポジトリ・ドメインのクラスに記述すると、コードが長大になってしまうことがある。
そのように業務チェックが複雑化するロジックでは、重複したチェックも出やすい。
本来はドメイン層のクラスそのものに業務チェックを記述すべきであるが、場合によっては外部化を検討した方が分かりやすくなる。

[Seasar2][SAStruts][アノテーション]executeアノテーション(input等)について

@Execute(input = "index.jsp")と記述した場合、「エラーが起きたらinput.jspに遷移する」という意味になる。
@Executeアノテーションでは、デフォルトでvalidator = trueとなるため、バリデーションの結果がNGだった場合に、遷移先を指定しておく必要がある。
遷移先のページで<html:errors/>と記述しておくと、バリデーションのエラーメッセージを出力できる。
このとき表示されるエラーメッセージは、application_ja.propertiesファイルに記述しておくことで変えることが可能である。
(googleで@Executeアノテーションを調べると出てくる)

フォームクラスで必須入力項目に@Requiredを付けることで、入力がない場合にエラーにすることができる。
@Required(target = "onClickGo")のように指定することで、onClickGoメソッドが呼ばれた場合だけ必須入力項目と扱う、ということもできる。
桁数チェック等の他のバリデーションについてもアノテーションで対応可能である。
まとめると、次の通り。

1. フォームクラスに画面入力項目を定義する。
2. 入力必須項目には@Requiredなどのアノテーションを付けることで、バリデーションが可能となる。
3. アクションクラスのメソッドで@Execute(validator = false)を指定しなければバリデーションが有効となる。
4. バリデーションが有効な場合、@Execute(input = "xxx.jsp")で指定したjspが、エラー時に飛ぶJSPとなる。
5. JSPファイル内に<html:errors/>と記述しておくと、エラーを表示できる。
6. エラーメッセージはapplication_ja.propertiesを変更したり、追加したりすると変えられる。

[Seasar2][SAStruts][アノテーション]executeアノテーションについて

SAStrutsではURLにプロジェクト名だけ指定した場合、IndexActionクラスが呼び出される。
例えばプロジェクト名がtestproject、Tomcatによるデバッグ環境で、

http://localhost:8080/testproject/

と入力した場合、IndexActionクラスのindexメソッドが呼び出される。
また、アクションクラスを追加した場合、indexメソッドによりそのアクションクラスが所属するパッケージのindex.jspを呼び出すことができるようになる。

例えばSougouMenuActionというアクションクラスを追加し、

http://localhost:8080/sougouMenu/

と入力した場合、SougouMenuActionクラスのindexメソッドが呼び出される。
ここでreturn "index.jsp";と記述すれば、sougouMenuパッケージ配下のindex.jspが呼び出される。

HTML名を指定せずにアプリを実行した場合、アクションクラスのindexメソッドが自動で呼び出されるようにするためには、indexメソッドに@Executeアノテーションを付与する必要がある。(@Executeが付いているメソッドをフレームワークが探すため)
アノテーションのよる、バリデーションを行わない場合は@Execute(validator = false)とする。
新しく追加したアクションの場合、JSPには何も画面入力項目がない状態なので、最初は@Execute(validator = false)して初期の動作確認をした方がよい。

画面を全部作ってアクションのメソッドを定義してもよいが、トラブルがあったときに時間を取られやすい。
インクリメンタルな開発を行うことで開発効率を上げる手法が推奨される。

[Seasar2][S2JDBC][MySQL]S2JDBCとMySQLの連携

Seasar2はデフォルトでH2というデータベースを持っており、そのままだとH2でS2JDBCのサンプルを動かすこととなる。
S2JDBCで他のDB(この例ではMySQL)と連携したい場合は、次の設定ファイルを書き換える。

1. src/main/resources/jdbc.dicon

    H2の設定をHTMLコメント(<!-- -->)で囲んで無効化し、代わりにMySQLのHTMLコメントを外して有効化する。
    MySQLの設定で変更する必要があるのは、次の箇所。

    (1) URL
        "jdbc:mysql://[位置]:[ポート番号]/[データベース名]"
        位置はIPアドレスもしくは名前解決されているマシン名を指定する。

    (2) user
        データベースのユーザ名。

    (3) password
        データベースユーザのパスワード。

2. src/main/resources/s2jdbc.dicon

    H2の設定をHTMLコメント(<!-- -->)で囲んで無効化し、代わりにMySQLのHTMLコメントを外して有効化する。
    動作確認は、次のようにして行う。

    (1) データベーステーブルの構成と同じエンティティクラスを作成する。
        主キーは@Id、自動採番なら@GeneratedValueアノテーションを忘れずに付ける。
        楽観ロックのためのバージョン番号属性は@Versionアノテーションを忘れずに付ける。

    (2) S2AbstractService<[エンティティ名]>をextendsしたクラスを作成する。(DAOの実装クラス)

    (3) アクションクラスで上記(2)のDAOクラスをインジェクションする。
        (@Resourceアノテーションを付けて、private属性としてクラス内に宣言する)
        デバッグ実行して、実際にDAO実装クラスがインジェクションされていれば成功。

    (4) 上記(2)で作成したDAO実装クラスに、S2JDBCを動作させる次のようなコードを記述し、動作を確認する。

        public [エンティティクラス] get(Integer id) {

            return select().id(id).getSingleResult();
        }

        データが正しく取得できていれば成功。

2011年11月4日金曜日

[Seasar2][ドメイン駆動]ドメイン駆動の各階層について

次のような階層構造とする。

プレゼンテーション層(Seasar2のアクションクラス)

サービス層(独自に定義、DI設定も追加が必要)

ドメイン層(ドメイン・リポジトリ、独自に定義、DI設定も追加が必要)

データアクセス層(DAO・エンティティ)

上位の階層は1つ下の階層にあるクラスのみを呼び出せる。
2つ以上下の階層にあるクラスを直接呼び出してはいけない。

また、サービスとDAOはインターフェースとする。
(DI設定により、実装を差し替えられるようにするため。主にテストで必要となる)

リポジトリは、必ずドメイン生成とドメイン取得をメソッドとして用意する。
ドメインにDAOをインジェクションする場合、newはできないのでコピーメソッドを用意する。

public class Domain {

    /**
     * DI内容のコピー
     *
     * @return DIの内容をコピーしたドメインのインスタンス
     */
    public Object copyDi() {

        //
        // DIではnewするごとにインジェクションはできず、DIコンテナの
        // getメソッドを使うと、シングルトンやリクエスト、セッション
        // ごとのインスタンスしか戻すことができない。
        // よって、不特定多数のドメインを生成する場合は、インジェクション
        // 設定をクローンメソッドによりコピーする必要がある。
        // (そうしないと、シングルトンの内容を別のクラスで書き換える
        // といったバグの温床になる)
        //

        try {
            // クラスの新しいインスタンスを生成する
            Object obj = this.getClass().newInstance();

            // メソッド配列を取得する
            Method[] methods = this.getClass().getMethods();

            // getterメソッドのマップを作成するまでループ
            Map<String, Method> getterMap = new HashMap<String, Method>();
            for (int i = 0; i < methods.length; i++) {

                // メソッド名がDaoかRepositoryのgetterの場合はマップに記録
                if (methods[i].getName().indexOf("get") == 0) {
                    if (methods[i].getName().contains("Dao")
                            || methods[i].getName().contains("Repository")) {
                        String targetName = methods[i].getName().substring(3);
                        getterMap.put(targetName, methods[i]);
                    }
                }
            }

            // setterを使い、新しいインスタンスに設定を行うループ
            for (int i = 0; i < methods.length; i++) {

                // DaoかRepositoryのsetterの場合は、設定を行う
                if (methods[i].getName().indexOf("set") == 0) {
                    if (methods[i].getName().contains("Dao")
                            || methods[i].getName().contains("Repository")) {
                        String targetName = methods[i].getName().substring(3);
                        methods[i].invoke(obj, getterMap.get(targetName)
                                .invoke(this));
                    }
                }
            }

            // 生成したクローンを呼び出し側に戻す
            return obj;

        } catch (Exception e) {

            // 何らかのエラーが起きた場合はnullを戻す
            return null;
        }
    }
}

コード中にも理由が書かれているが、ドメインはデータベース行数分だけ生成されるため、DIのインスタンス生成タイミングと一致しない。

1. リポジトリがドメインをDIする。(シングルトンで用意されているDaoがドメインにDIされる)
2. リポジトリでドメイン生成・ドメイン取得する場合は、上記1.のDIをコピーする。

Seasar2におけるドメイン・リポジトリのDI設定例は、次の通り。

  <component class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
    <initMethod name="addClassPattern">
      <arg>"rootpackage.domain"</arg>
      <arg>".*Repository"</arg>
    </initMethod>
  </component>

  <component class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
    <initMethod name="addClassPattern">
      <arg>"rootpackage.domain"</arg>
      <arg>".*Domain"</arg>
    </initMethod>
  </component>

FileSystemComponentAutoRegisterは、プロジェクト内のファイルから探す。
JARにまとめたクラスからDIさせる場合は、JarComponentAutoRegisterを使う。

[Seasar2][S2JDBC]DAO実装クラスの記述

S2JDBCをO/Rマッパーとして使う場合、DAO実装クラスの記述上の注意点は、次の通り。
なお、DAOはインターフェースとして定義するものとする。

1. S2AbstractService<エンティティクラス名>をextendsで拡張すると使いやすい。

    ※ 必須ではないがエンティティを固定できるため、コード記述が楽になる。

2. エンティティで@ManyToOneアノテーションを使っている場合、innerJoinにより関連テーブルのデータも取得できる。

    ※ 直前の記事に記載されている例を参照のこと。

3. 主キーによる検索は、次のように記述する。

    public User get(Integer userId) {

        return select().id(userId).getSingleResult();
    }

    ※ 上記1.のS2AbstractServiceを拡張した場合、この記述が使える。

4. 可変の引数を使う場合は、次のように記述する。

    public List<User> findByUserId(Integer userId) {

        return select().where("userId = ?", userId).getResultList();
    }

    WHERE句に相当するwhereメソッド等では、可変引数仕様となっている。
    複数の条件がある場合は、?と引数の数を増やしていく。

[Seasar2][S2JDBC]エンティティクラスの記述

S2JDBCをO/Rマッパーとして使う場合、エンティティクラス定義上の注意点は、次の通り。

1. entityパッケージ配下にクラスを作成する。

2. エンティティクラスに@Entityアノテーションを付ける。

3. 主キーには@Idアノテーションを付ける。
    また、主キーがサロゲートキーであり、IDを自動生成する場合は@GeneratedValueアノテーションを付ける。

4. 楽観ロックのためのバージョン属性には@Versionアノテーションを付ける。

5. 外部キーで他のテーブルとリンクしている場合、外部キーの他にリンクしているテーブルクラスも定義する。
    例えば、userId(テーブルの属性名USER_IDに対応する)によってUserテーブルとリンクしているとする。
    この場合は、次のように記述する。

    public Integer userId;

    @ManyToOne
    @JoinColumn(name = "USER_ID")
    public User user;

    S2JDBCのJavaコード上でinnerJoin()と書くと、userIdをキーとしてUserテーブルの内容も格納される。

6. S2JDBC上のコードで上記5.のUserを読ませるコード例は、次の通り。

    return select().id(sampleId).innerJoin("user").getSingleResult();

    SAMPLE_IDを主キー(サロゲートキー)とするSAMPLEテーブルがあり、このテーブルが外部キーUSER_IDとした場合の例。
    このように記述すれば、Userエンティティ内の全てのデータも読み込める。

[Seasar2][SAStruts]コンポーネントスキャンによるDIの方法

Seasar2のDIはapp.diconに記述されているので、DIについての設定を追加する場合は、app.diconを変更する。
通常は、次のようにユーザ定義のみを集めた独自のdiconファイルを新規作成し、app.diconからそのファイルをインクルードする。

  <include path="user.dicon"/>

特定のパッケージ配下にあるクラス全てをDIコンポーネントとして識別させるための設定は、次の通り。

  <component class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
    <initMethod name="addClassPattern">
      <arg>"rootpackage.dao"</arg>
      <arg>".*DaoImpl"</arg>
    </initMethod>
  </component>

このように記述すると、「rootpackage.dao配下にある ".*DaoImpl" という名前のクラスをコンポーネントとして認識する」という意味になる。
例えばrootpackage.daoにTestDaoImplというクラスがあった場合、この設定でコンポーネントとして認識される。

コンポーネントとして認識されているクラスは、@Resource(@Bindingでも可)アノテーションでDIできる。

    @Resource
    private TestDao testDao;

このように記述することで、TestDaoImplが自動でインジェクションされる。
(newしなくても、最初からクラスに生成済みのインスタンスが入っている)

上記設定は、ファイルシステムにソースファイルがある場合の設定である。
JARファイル内のクラスを探す場合は、JarComponentAutoRegisterを用いる。

[Seasar2][SAStruts]セッション情報へのアクセス

SAStrutsでは、次のように記述することでセッション情報にアクセスできる。

    @Resource
    private Map<String, Object> sessionScope;

これはSeasar2が暗黙のオブジェクトとして、このsessionScopeを定義しているからである。
アクションクラスで@Resourceを付けて上記の名前の通り宣言すると、セッション情報にアクセスできる。

セッション情報への設定、セッション情報の取得コードは、次の通り。

    sessionScope.put("userId", userId);
    (Integer) sessionScope.get("userId");

[Seasar2][SAStruts]リダイレクトによる遷移

Seasar2では、アクションに対応するJSPはパッケージごとに管理される。
例えば、トップページに5画面の遷移があるとすると、topPageといったパッケージに5つのJSPファイルを記述することとなる。
別途ログイン処理に3画面の遷移があるとすると、loginといったパッケージに3つのJSPファイルが生成される。

ログイン認証が終わったのでトップ画面に遷移したいという場合、リダイレクトは次のように記述する。

    @Execute(input = "login.jsp", redirect = true)
    public String onClickLogin() {

        // 認証処理

        return "/topPage/";
    }

@Executeアノテーションのredirectをtrueにすると、リダイレクトとなる。
URL指定については、サンプルを参照のこと。
この例の場合、トップページパッケージ配下を指定している。(topPageのindex.jspが選択される)

[Seasar2][SAStruts]サブミットに対応するハンドラの記述

JSPでボタンを押した場合などにサブミットさせる場合、SAStruts側は次のように記述する。

1. JSPでサブミットの定義を行う。

    <s:form>
        メールアドレス<html:text property="mail"/>
        <input type="submit" name="onClickCreate" value="ユーザ登録"/>
    </s:form>

2. JSPに対応するアクションクラスを開く。

3. onClickCreate(JSP中で指定した名前)メソッドをアクションクラスに追加する。

    @Execute(input = "xxx.jsp")
    public String onClickCreate() {
        return "yyy.jsp";
    }

4. 上記3.でも出ているが、処理を行った後にreturnで遷移先のJSP名を指定する。

5. 実際に動かしてみて、画面遷移がうまくいくことを確認する。

[Seasar2][SAStruts][Dolteng]フォームクラスの作成

画面入力はXxxFormというクラスにまとめることができる。
手順は、次の通り。

1. Doltengプロジェクトで画面に対応するアクションクラスを開く。

2. returnで遷移するJSPファイル名にカーソルを置いて、Ctrl+8を押す。

3. 表示されるJSPで<form>タグを次のように使い、フォームを記述する。

    <s:form>
        メールアドレス<html:text property="mail"/>
        <input type="submit" name="onClickCreate" value="ユーザ登録"/>
    </s:form>

4. Doltengプロジェクトのsrc/main/java配下のformパッケージで右クリック。

5. 表示される右クリックメニューから[新規]-[クラス]を選択する。

6. アクションクラス名のActionの部分をFormに変えたクラスを作成する。

7. 生成したクラスに、画面入力項目を追加する。(publicでよい)

    ※ 上記例の場合は、public String mail;を作成したフォームクラスに追加。

8. アクションクラスの属性として、formを記述する。

    @ActionForm
    @Resource
    private XxxForm xxxForm;

    @ActionFormアノテーションにより、フォームクラスであることを明示する。
    @Resourceアノテーションにより、DIが実施される。

9. デバッグ実行等により、JSPのフォームで入力したデータがフォームクラスに格納されていることを確認する。

[Seasar2][SAStruts][Dolteng]アクションクラス作成とJSPの自動生成

1. パッケージエクスプローラで、次の位置にあるactionパッケージを右クリック。

    Doltengプロジェクトのsrc/main/java配下

2. 右クリックで出てきたメニューから[新規]-[クラス]を選択。

3. クラス名をXxxAction(Xxxの部分は任意)とし、[完了]をクリック。

4. 次のコードを追加する。

    @Execute(validator = false)
    public String index() {
        return "index.jsp";
    }

5. return "index.jsp";の "index.jsp" 上にカーソルを置いてCtrl+8を押す。

6. JSPを自動生成するか聞いてくるので、そのまま自動生成する。

7. Tomcatを起動し、次のURLでアクセスできたら成功。

    http://localhost:8080/[プロジェクト名]/xxx/

    ※ xxxの箇所はXxxActionのXxxの先頭1文字を小文字にした名前。

    ※ JSPが表示されたら、HTMLの内容を変えて反映されることもテストして確かめる。

[Seasar2][SAStruts][S2JDBC][Dolteng]Doltengプロジェクトの自動生成

Doltengを使い、Seasar2でSAStruts+S2JDBCのプロジェクトを作成する手順は、次の通り。

1. メニューから[ファイル]-[新規]-[プロジェクト]の順に選択。

2. 表示される一覧から[Dolteng]-[Doltengプロジェクト]を選択し、[次へ]をクリック。

3. 表示される画面で[プロジェクト名]と[ルートパッケージ名]を入力、[プレゼンテーション]を[SAStruts]に、[永続化]を[S2JDBC]として[完了]をクリック。

以上の手順で、DoltengによるSAStruts+S2JDBCのプロジェクトが自動生成される。
この自動生成の利点は、次の通り。

    ・パッケージ構成の構築等、複雑な手作業をしなくて済む。
    ・ソースファイルを追加していくだけで、SAStruts+S2JDBCが動く。
    ・SAStruts+S2JDBCの設定ファイルが最初から全て書かれている。

[Seasar2][SAStruts][S2JDBC][Dolteng]Doltengのインストール

SAStrutsなどで使えるコード自動生成ツールのインストール方法は、次の通り。

eclipseのメニューから[ヘルプ]-[ソフトウェア更新]を選択、[使用可能なソフトウェア]タグから[サイトの追加]を選ぶ。
(eclipseのバージョンによって、多少インターフェイスが異なることあり)

http://eclipse.seasar.org/updates/3.3/

と入力し、Doltengを選んで[インストール]をクリックする。
eclipseの再起動が必要。

2011年11月2日水曜日

[Seasar2][SAStruts][環境構築]SAStruts+S2JDBCの環境構築(設定編)

前述インストール編の1.~3.の手順に続いて、下記設定を行う。

4. 文字化けの防止

    Pleiadesで使うTomcatの配下、confディレクトリ内のserver.xmlを編集する。   

    (1) Connectorタグ内に、次の属性を追加   
        useBodyEncodingForURI="true"
        URIEncoding="UTF-8"

        以下、設定サンプル。

5. HotDeployの有効化

    Pleiadesで使うTomcatの配下、confディレクトリ内のcontext.xmlを編集する。
    <Manager>タグのコメントを解除して有効化する。

    ※ server.xmlではないので注意!

6. WebアプリケーションをTomcatで認識できるようにする

    Pleiadesで使うTomcatの配下、conf\Catalina\localhostにsa-struts-tutorial.xmlを追加し、内容を次のように記述する。

    <Context path="/sa-struts-tutorial"
             reloadable="true"
             docBase="[sa-struts-tutorialを置いているパス]\sa-struts-tutorial\src\main\webapp"
             workDir="[sa-struts-tutorialを置いているパス]\sa-struts-tutorial\src\main\webapp\work" />

7. 動作確認
    eclipse上からTomcatを起動し、ブラウザから下記URLを入力してページが表示されれば成功。
    ここでTomcatのエラーが出る場合は、上記2.でコンパイルエラーが起きているか上記6.で設定ファイルの記述に失敗している。

    http://localhost:8080/sa-struts-tutorial/

[Seasar2][SAStruts][環境構築]SAStruts+S2JDBCの環境構築(インストール編)

1. eclipseのインストール   

    googleでキーワード "eclipse 日本語化 ダウンロード" で検索。
    sourceforgeのPleiades(=eclipseを含むall in one環境)ダウンロードサイトにアクセスする。
    バージョンは常に新しくなるので、任意のものを選択する。

2. Seasar2プロジェクトからSAStrutsのチュートリアルをダウンロード

    http://sastruts.seasar.org/download.html

    チュートリアルがあるのでダウンロードする。
    Seasar2フレームワークそのものはeclipseの設定でダウンロードするため、ここではダウンロード不要。
    上記URLは将来的に変わりうる。その場合はgoogleでキーワード "SAStruts チュートリアル" などで検索すること。

    eclipse(Pleiades)の[ファイル]-[インポート]で既存プロジェクトとしてインポートする。
    (チュートリアル自体は圧縮ファイルなので、解凍してからインポートする)

    「TOMCAT_HOMEがない」というコンパイルエラーが出る場合は、チュートリアルプロジェクトを右クリックし、出てくるメニューから[ビルドパス]-[ビルドパスの構成]を選択する。
    出てくる画面で[ライブラリー]タグを選択、[変数の追加]を押下、[変数の構成]を押下、[新規]を押下し、TOMCAT_HOMEをPleiadesに含まれるいずれかのTomcatホームディレクトリにする。(<例>C:\Pleoades\Tomcat5.5)

    なお、Pleiadesには最初からTomcatが数バージョン入っており、デフォルトで選択されているバージョンは、eclipseの[ウインドウ]-[設定]メニューから参照できる。
    ここで選択されているTomcatを指定しないと、動作確認がうまくいかないので注意を要する。

3. SAStruts Pluginのインストール   

    eclipseのメニューから[ヘルプ]-[ソフトウェア更新]を選択、[使用可能なソフトウェア]タグから[サイトの追加]を選ぶ。
    (eclipseのバージョンによって、多少インターフェイスが異なることあり)

    http://eclipse.seasar.org/updates/3.3/

    と入力し、SAStrutsPluginを選んで[インストール]をクリックする。
    eclipseの再起動が必要。

以上で必要なツール類の準備は完了となる。
動作させるためには、一部設定変更等が必要となる。(別途、記事として掲載)

2011年10月19日水曜日

[Servlet][JSP][Webアプリケーション]エンティティクラスについて

Webアプリケーションを作成する場合、データベースのテーブルに対応するエンティティクラスを作るのが一般的である。
エンティティクラスは、データベーステーブルの各属性のsetter/getterを持つクラスである。
データベーステーブルのレコード1件分を格納するために用いる。

例えば次のようなデータベーステーブルがあったとする。

CREATE TABLE SAMPLE(
    SAMPLE_ID INT AUTO_INCREMENT,
    SAMPLE_STRING VARCHAR(256),
    PRIMARY KEY(SAMPLE_ID)
    );

このテーブルに対応するエンティティクラスは、次のようになる。

public class Sample implements Entity {

    private Integer sampleId;
    public Integer getSampleId() {
        return sampleId;
    }
    public void setSampleId(Integer sampleId) {
        this.sampleId = sampleId;
    }

    private String sampleString;
    public String getSampleString() {
        return sampleString;
    }
    public void setSampleString(String sampleString) {
        this.sampleString = sampleString;
    }
}

データベースの型を見ると、SAMPLE_IDがINT、SAMPLE_STRINGがVARCHARとなっている。
Javaの場合、IntegerとStringが対応するクラスとなるため、エンティティはIntegerとStringで作る。
(ただし桁数が多い場合など、個別に対応する型を考慮する必要が出てくる場合もある)

記述は必ずキャメル記法とする。(最初の1単語は全て小文字、次の単語以降は先頭1文字のみ大文字)
これはJSPでEL式を使う場合に、重要となる命名規則である。
規則通りに書いておかないと、EL式で変数を認識できなくなる。

DAOクラスでSELECTを実行する場合、取得したデータはエンティティクラスに格納する。
これによりDBから取得したデータをどこに格納するのかが明確となり、コードのメンテナンス性が上がる。

サンプルでEntityというインターフェースをimplementsしているが、これは別途記述するロウマッパーなどの仕組みを使う際に必要となる。
当該クラスがEntityであることを示すためのマーカーインタフェースが必要な場合は、空のインターフェースを作成して、エンティティクラスでimplementsの記述を行う。

[Servlet][JSP][DAO]JDBCについて(可変引数のあるSELECT)

可変要素のあるSELECTを実行するサンプルは、次の通り。

// 可変要素のあるSELECTの実行
public void executePreparedSelect(int searchId) throws ClassNotFoundException,
        SQLException {

    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
        // JDBCドライバをクラス名で探し、初期化を行う
        Class.forName("com.mysql.jdbc.Driver");

        // コネクションを取得する
        conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/SAMPLE", "sampleuser",
                "samplepassword");

        // プリペアドステートメントを作成する
        String sql = "SELECT ID, STR FROM SAMPLE_TABLE WHERE ID = ?";
        ps = conn.prepareStatement(sql);
        ps.setInt(1, searchId);

        // SQLを実行し、リザルトセットを得る
        rs = ps.executeQuery();

        // テーブルにintのID、varcharの文字列がある場合、次のように取得できる
        while (rs.next()) {
            Integer id = rs.getInt(1);
            String str = rs.getString(2);
            System.out.println("ID : " + id);
            System.out.println("STR : " + str);
        }

    } finally {

        // 後始末をする
        if (conn != null) {
            conn.close();
        }
        if (ps != null) {
            ps.close();
        }
        if (rs != null) {
            rs.close();
        }
    }
}

SELECTの可変要素とは、次のSQLの?の部分のことを指す。

"SELECT ID, STR FROM SAMPLE_TABLE WHERE ID = ?"

Javaプログラム(例えば画面入力項目)を?の箇所に当てはめてSQLを実行する場合、本サンプルのようなプログラム記述となる。
1番目の?に引数のsearchIdを設定しているコードは、次の箇所である。

ps.setInt(1, searchId);

文字列を設定する場合はsetStringとなる。
?が2つ以上になる場合は、1、2、3とsetXXXの第1引数を増やしていく。

[Servlet][JSP][DAO]JDBCについて(可変引数のないSELECT)

DAOクラスでJDBCによるアクセスを行う場合は、まずJDBCドライバをクラスパスに配置する。
MySQLならばWebサイトに行ってjarをダウンロードしてくると、JDBCを使えるようになる。

eclipseで開発しているなら、WEB-INF/lib配下にJDBCのjarを置き、ビルドパスに追加する。
DBにアクセスするコードは、次のようになる。

// SELECTの実行
public void executeSelect() throws ClassNotFoundException, SQLException {

    Connection conn = null;
    Statement s = null;
    ResultSet rs = null;
    try {
        // JDBCドライバをクラス名で探し、初期化を行う
        Class.forName("com.mysql.jdbc.Driver");

        // コネクションを取得する
        conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/SAMPLE",
                "sampleuser", "samplepassword");

        // ステートメントを作成する
        s = conn.createStatement();

        // SQLを実行し、リザルトセットを得る
        rs = s.executeQuery("SELECT * FROM SAMPLE_TABLE");

        // テーブルにintのID、varcharの文字列がある場合、次のように取得できる
        while (rs.next()) {
            Integer id = rs.getInt(1);
            String str = rs.getString(2);
            System.out.println("ID : " + id);
            System.out.println("STR : " + str);
        }

    } finally {

        // 後始末をする
        if (conn != null) {
            conn.close();
        }
        if (s != null) {
            s.close();
        }
        if (rs != null) {
            rs.close();
        }
    }
}

[Servlet][JSP][DAO][Seasar2]DAOクラスについて

サーブレットやフレームワークを使った開発でDAOパターンを採用する場合、DAOは必ずインターフェースとする。
これはモックへの差し替えを行うためである。
DIと組み合わせることによって、設定ファイルのみでモックによるテストを行ったり、本物の実装を動かせるようにする。

<<interface>>XxxDao


XxxDaoImpl

(↑)実装は上記のようなクラス構成となる。
モックを使う場合は、XxxDaoImplクラスのモックを別パッケージに用意し、DI設定を変える。
例えばSeasar2で、通常のDAO設定が次のようなものだとする。

  <component class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
    <initMethod name="addClassPattern">
      <arg>"jp.co.sample.dao"</arg>
      <arg>".*DaoImpl"</arg>
    </initMethod>
  </component>

モックの場合は、次のように設定が変わる。(パッケージが"jp.co.sample.dao"から"jp.co.sample.dao.mock"になっている)

  <component class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
    <initMethod name="addClassPattern">
      <arg>"jp.co.sample.dao.mock"</arg>
      <arg>".*DaoImpl"</arg>
    </initMethod>
  </component>

ドメイン駆動などにおけるサービスも同様で、サービスは必ずインターフェースとする。

[MySQL][CSV][読み込み]CSVファイルのデータをテーブルに格納する

MySQLに用意されている次のSQLコマンドで、CSVファイルを読み込むことができる。

LOAD DATA INFILE '[CSVファイルの絶対パス]'
 INTO TABLE [テーブル名]
 FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\r\n';

CSVファイルに記述されているデータがテーブルにロードされる。
バッチファイルやシェルファイルにして、自動化すると効率的。

[MySQL][コマンドライン]コマンドラインからMySQLにクエリを発行する

最初にSQLファイルを作る。(テキストファイル、拡張子は".sql")
SQLファイル内には複数のクエリを記述できる。
下記はサンプル。(SAMPLEというデータベースに、SAMPLE_TABLEというテーブルを追加)

CREATE DATABASE SAMPLE;
SHOW DATABASES;
USE SAMPLE;
CREATE TABLE SAMPLE(
    SAMPLE_ID INT AUTO_INCREMENT,
    SAMPLE_STRING VARCHAR(256),
    PRIMARY KEY(SAMPLE_ID)
    );
SHOW TABLES;

(以上、サンプル)

次にバッチファイルを作成する。
下記はサンプル。(sample.sqlというファイルに書かれたSQLを実行)

@echo off
set MYSQL_DIR="C:\Program Files\MySQL\bin"
set TEST_USER=testuser
set TEST_PASSWORD=password
set SQL_FILE=sample.sql
%MYSQL_DIR%\mysql -u%TEST_USER% -p%TEST_PASSWORD% < %SQL_FILE%
pause

(以上、サンプル)

バッチファイルを実行すると、SQLファイルの中に書かれたSQLが実行される。
なお、バッチファイルで発行するコマンドを次のように変えると、対話モードとなる。
対話モードで直接SQLを発行する場合は、こちらを利用する。

[MySQLのインストールディレクトリ]\bin\mysql -u[ユーザ名] -p

[バッチファイル][変数の外部ファイル化]

WindowsのバッチファイルはUNIX系のシェルに比べて機能が弱く、文法も独自で使い勝手が悪い。
しかし開発等でWindowsでバッチファイルを作って効率化しなければならない局面は多い。
バッチファイルで問題となるのが絶対パスの指定等が必要な場合である。

パス指定は開発者の環境によって変わりうるため、必然的に可変部分を外部ファイルとして切り出したいニーズが出てくる。
可変となる設定部分を外部ファイル化してバッチファイルで読むサンプルは、次の通り。

まず最初に、可変の設定値を集めたテキストファイルを作成する。(例えばsetup.txt)
設定値は "[設定値の名前]=[設定値]" の形式で記述する規則とする。
以下、設定サンプル。

USER_NAME=user
PASSWORD=password

次に作成した設定値のファイルをバッチから読み込むコードを記述する。
バッチファイルを作成し、次のように記述して設定値が読めることを確認する。

@echo off
for /f "tokens=1,2 delims==" %%a in ('findstr USER_NAME setup.txt') do set USER_NAME=%%b
for /f "tokens=1,2 delims==" %%a in ('findstr PASSWORD setup.txt') do set PASSWORD=%%b
echo %USER_NAME%
echo %PASSWORD%
pause

設定ファイル内の設定を読む場合などに重宝するのはforを使った繰り返し処理である。
(下記箇所が、設定を読み込んでいる記述)

for /f "tokens=1,2 delims==" %%a in ('findstr USER_NAME setup.txt') do set USER_NAME=%%b

for /f [解析文字列]
と記述することで、解析文字列内で指定した方法でトークンを切り出すことができるようになる。
"tokens=1,2 delims==" と書いた場合、文字列中にトークンが2つあり、"=" で区切られていると解釈される。
"USER_NAME=user" という設定が書いてあった場合は、トークン1がUSER_NAME、トークン2がuserと解釈される。

%%aはループ内変数を示し、"token=1,2" と書いてあった場合はトークン1(USER_NAME)を示す。
%%bはトークン2(user)を示す。

in ()の括弧内にシングルクオートで囲んだ文字列を指定した場合、コマンドを実行した結果を示す。
in ('findstr USER_NAME setup.txt') とあった場合は、setup.txtというファイル内にUSER_NAMEという文字列があるかfindstrコマンドで探した結果が入る。
上記例でsetup.txtには "USER_NAME" という文字列を含む "USER_NAME=user" という行データが入る。

do以下は、forループで実行されるコマンドを記述する。
set USER_NAME=%%bでUSER_NAMEというバッチ変数にuserという文字列を代入している。
これにより、ファイルから読み込んだ値をバッチファイル内の変数としている。

[Servlet][JSP]サーブレット最小アプリケーションの作成

eclipseは日本語All in one環境であるPleiadesがインストールされているものとする。

1. [ファイル]-[新規]-[プロジェクト]を選ぶ。
2. [Tomcatプロジェクト]を選択し[次へ]をクリックする。
3. プロジェクト名を入力し、[完了]をクリックする。(※1)
4. [WEB-INF]ディレクトリ直下に、web.xmlを作成する。
5. eclipse上からTomcatを起動する。
6. ブラウザでhttp://localhost:8080/[プロジェクト名]/index.htmlにアクセスする。(※2)

※1 プロジェクト名は英小文字のみをハイフンで接続するのが通例。
※2 index.htmlを作成している場合の例。web.xmlの設定による。

XMLの記述内容サンプルは、次の通り。

<web-app 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"
version="2.4">

  <servlet>
    <servlet-name>Index</servlet-name>
    <servlet-class>servlet.IndexServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Index</servlet-name>
    <url-pattern>/index.html</url-pattern>
  </servlet-mapping>

  <servlet>
    <servlet-name>Top</servlet-name>
    <servlet-class>servlet.TopServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Top</servlet-name>
    <url-pattern>/top.html</url-pattern>
  </servlet-mapping>

</web-app>

(以上、サンプル)

<web-app>タグにあるごちゃごちゃした記述は、JSPのEL式を使うために必須。(xmlns等)
EL式がないとJSP上にJavaのコードを書くことになるので、おまじないだと思って書くこと。

<servlet>タグ内の<servlet-name>タグは、サーブレットに付ける名前で任意。
プログラム上の名称と合わせたりする必要はない。
<servlet-mapping>との関連付けのために必要。
<servlet-mapping>内の<servlet-name>と同じものを書くこと。

<servlet>タグ内の<servlet-class>は、実際に動かすサーブレットプログラムクラスの完全修飾名を記述する。
"servlet.IndexServlet" と書いたら、プロジェクト配下のservletパッケージにあるIndexServletクラスを指す。
本格的なWebアプリならパッケージ名は "jp.co.xxx.sys.servlet.XxxClass" のように長くなるはずである。

<servlet-mapping>タグ内の<servlet-name>タグは、<servlet>タグと同じものを記述する。
<servlet-mapping>タグ内の<url-pattern>タグは、ブラウザで入力するURLを指定する。
"/index.html"と書いたら、"http://localhost:8080/[プロジェクト名]/index.html" と書くことで、対応するサーブレットが動く。
外部の人から見て、あたかもhtmlを読んでいるかのように見せることができる。

【重要!】Tomcatを起動しても、サーブレットが動かない場合
TOMCAT_HOME配下の設定ファイルにコンテキスト設定がないことが考えられる。
TOMCAT_HOMEはTomcatのインストールディレクトリを指す。
"TOMCAT_HOME/conf/Catalina/localhost" ディレクトリ配下にコンテキスト設定を記述した[プロジェクト名].xmlファイルを置くか、"TOMCAT_HOME/conf/server.xml" にコンテキスト設定を追加することで、アプリケーションが動作するようになる。

後者のserver.xml直接編集はTomcatの設定を変えることになるので、最近は前者がほとんどである。
eclipseの[ウインドウ]-[設定]を選んで、[Tomcat]-[コンテキスト宣言モード]を見るとどちらを使っているか分かる。
後者のXMLファイルに記述する設定内容は、次の通り。

<Context path="/web-app-sample"
         reloadable="true"
         docBase="C:\eclipse\workspace\web-app-sample"
         workDir="C:\eclipse\workspace\web-app-sample\work" />

docBaseで指定したディレクトリ配下のWEB-INFディレクトリを、サーブレットのディレクトリとしてTomcatが認識する。
上記設定サンプルでいうと、docBaseで指定したディレクトリ配下にservletというパッケージがあり、その中にIndexServletクラスがあれば、"http://localhost:8080/web-app-sample/index.html" と記述することでアクセスできるようになる。
この他、「TOMCAT_HOMEがない」というエラーが出る場合は、プロジェクトの右クリックメニューから[ビルドパスの構成]を選択して、TOMCAT_HOMEのディレクトリ設定を行う必要もある。

サーブレットはサンプルを動かすまでが大変。
eclipseとTomcatがあれば動くはずなので、設定をよく見直してまずは動かそう。
サーブレットプログラムは、動作確認だけなら次のコードで十分。

public class IndexServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public void doGet(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, IOException {

        RequestDispatcher rd = req.getRequestDispatcher("/jsp/index.jsp");
        rd.forward(req, res);
    }
}

JSPファイルはeclipseのプロジェクト直下にjspフォルダを作ってそこに置いておく。
(場所を変えても問題ない)
JSPの内容は、次の通り。(ここではUTF-8を使用している)

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

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>web-app-sample</title>
</head>
<body>
<h1>Hello world!</h1>
</body>
</html>

[Java][コマンドライン]Javaプログラムコマンドライン起動

eclipseの便利さに慣れてしまうと、コマンドラインでJavaプログラムをコンパイルすることはないが、現場レベルでは往々にしてコマンドライン起動がありうる。

例えばサーバ上でJavaプログラムを動かしている場合、サーバ機には開発ツール等の余計なものは入っていないはずだ。
サーバ運用に必要な最小限の構成を組み、セキュリティアップデートなども記録して行っているはずである。
開発用サーバならまだしも、本番機にはまずeclipseは入っていない。

こうしたときに、サーバにアップデートした検証用プログラムや新しいプログラムを起動するためには、コマンドライン起動ができなくてはならない。
そのようなケースのために、手順を記述する。

例えばプロジェクトルートSampleProject、パッケージ名sample、クラスファイル名SampleProgram.classという構成でプログラムを動かす場合を考えてみる。
ディレクトリ構成は、下記を想定する。

[dir]SampleProject
  [dir]bin
    [dir]sample
      SampleProgram.class
  [dir]src
    [dir]sample
      SampleProgram.java

ディレクトリには[dir]と記述している。
eclipseでプログラムを作った場合、通常は上記の構成となるだろう。
起動のためには、SampleProjectディレクトリで次のコマンドを打つ。

java -classpath .:./bin sample.SampleProgram

クラスパスオプション("-classpath [クラスパス]")には".:./bin"を指定している。
ドット(.)はカレントディレクトリ、./binはカレントディレクトリ配下のbinディレクトリを示している。
複数のディレクトリをつなぐ場合は、コロン(:)を用いる。(Linuxの場合、Windowsならセミコロン(;))
つまり「クラスパスとしてカレントディレクトリ及びbinディレクトリを指定する」という意味になる。
(複数ディレクトリ指定のためにカレントディレクトリも入れたが、本当は./binだけでよい)

続く"sample.SampleProgam"は「sampleパッケージのSampleProgram.class」を意味している。
Javaではプログラムをひとまとまりとするためにパッケージを用いる。
パッケージ名のディレクトリ配下に、そのパッケージに含めるクラスファイルを格納する。
コマンドライン起動の場合は、クラスパスでbinディレクトリを指定したら、その配下にあるクラスファイルの名前を".class"抜きで記述する。

ちなみに、"sample.SampleProgram"を"SampleProgram"とだけ書くのはNG。
プログラムは起動しない。
[パッケージ名].[クラスファイル名(".class"を抜いた名称)]
という記述が決まりとなっている。(完全修飾名)

次に、コンパイルコマンドについて記述する。
eclipseを使っている場合、サーバとJavaのバージョンが合っていればWindowsで作ったクラスファイルをLinuxで起動しても問題なく動く。
通常はコンパイルすることはないだろう。
だが、修正したファイルをすぐに試したい場合など、手動コンパイルの出番がないわけではない。

少々長いが、下記のようにコマンドを打つことで、手動コンパイルができる。
コマンドを実行するディレクトリは、先ほどと同じくSampleProjectディレクトリである。

javac -sourcepath ./src/sample -classpath ./bin -d ./bin ./src/sample/SampleProgram.java

"-sourcepath [ソースパス]"でソースファイルがあるパス名を指定する。
"-classpath [クラスパス名]"でクラスパスを指定するのは、実行コマンドと同じである。
"-d [出力先ディレクトリ]"はクラスファイルの出力先ディレクトリを示す。

クラスパス、出力先ディレクトリともに、パッケージディレクトリまでは指定してはいけない。
sampleパッケージだからbin/sample配下にクラスファイルを出力しようとして、下記のように書くのはNG。

-d ./bin/sample

(↑)こう書くと、bin/sample/sample/SampleProgram.classが出来てしまう。
(sampleの下にsampleが出てくる)
Javaコンパイラはpackage宣言を参照して、自動的にパッケージディレクトリを作るため、"./bin"までの指定が正しい。
なお、依存関係にあるクラスは依存先を最初にコンパイルし、クラスパスを通しておかないと、依存元のコンパイルでエラーとなるので注意が必要である。

上記のコマンドライン起動がうまくいったら、シェルスクリプトやバッチファイルにコマンドを記述し、次回以降は面倒なコマンドをフルに打たなくても起動できるようにするのがオススメである。

[Subversion][Tomcat]SubversionでTomcatプロジェクトを扱う際の注意点

Windows上で管理者がSubversionにTomcatプロジェクトをインポートし、開発者がチェックアウトすると、コンパイルエラーとなる現象が発生したので、その原因と対処について記述する。

原因はチェックアウト時にTOMCAT_HOMEを認識しないためである。
(環境変数にCATALINA_HOMEやTOMCAT_HOMEを定義していれば出ないかも?)
Tomcatプロジェクトではeclipseがサーバサイドプログラムのための各種設定を行ってくれる。
TOMCAT_HOME/common/libなどへパスを通しておかないと、サーブレット等が使えないため、こうしたディレクトリへのパスもeclipseで自動的に定義される。

ただしSubversionで単純にプロジェクトをチェックアウトしただけだとTOMCAT_HOMEが認識されないため、管理者側ではきちんとコンパイルが通っているコードでもコンパイルが通らなくなってしまう。

この問題を解消するには、プロジェクトを右クリックして出てくるビルドパスの構成で、TOMCAT_HOME配下のディレクトリへの参照をきちんと設定しれやればよい。
(TOMCAT_HOME/common/libなどへの参照が空になっているので、編集ボタンを押してTomcatのインストールディレクトリ配下の該当ディレクトリを指定する)

[eclipse][環境変数]eclipseを使う場合の環境変数設定について

eclipse、特にpleiadesを使った場合、環境変数の設定は必要ない。
Java入門サイトを見ると、Windowsの場合、よく環境変数のPATH変数にJAVA_HOMEやJAVA_HOME/binへの参照を追加する、という記述が見られる。

かつてMS-DOS時代ならば、configでこうしたパス設定を行うことは珍しくなかったかも知れない。
しかし、シェル変数による環境変数設定が一般的なLinuxでも、むやみに環境変数を書き換えることは推奨されていない。
少なくとも、特定ユーザのログインシェル(.profileや.bashXXなど)を変更し、他のユーザに影響を与えないことが基本である。

Windowsの場合、環境変数はそこまで柔軟なものではなく、下手に書き換えるとPCが正しく立ち上がらなくなったりする。
できれば環境変数設定を操作してはいけないのである。
(その点Linuxならばシェルスクリプトに、当該スクリプト内だけのシェル変数を定義できるので、シェルごとにパス設定が簡単にできる。色々な意味で、WindowsとLinuxの作法は違うのである)

eclipseはそうした点のかなりの部分を解消してくれる。
日本語環境であるpleiadesを使った場合、[ウインドウ]-[設定]で表示されるダイアログから[Java]-[コンパイラー]の順に選んでいくと、最初からpleiadesに入っている複数バージョンのコンパイラを選ぶことができる。

重要なのは1.4から1.5への移行だろう。
1.5以降はVector<String>といったコンテナの型指定が必須となっており、こう書かないと警告になる。
ところが1.4だとGenerics(型指定等を含む新しい文法)がまだ含まれていないため、Vector<String>と書くとコンパイルエラーになってしまう。

1.4ではJUnit4が使えないという点も不利である。
JUnit4はそれまでのJUnitよりも更に簡単な記述で、自動テストができるようになっている。
メソッド名に制約があったり、テストの実行順序などを細かく記述しないとテストスイートが動かなかったJUnit3と比べると便利であり、一度慣れてしまうとなかなか戻れない。

こうしたコンパイラのバージョンはeclipse上で変えられるため、環境変数の設定は必要ない。
同様にTOMCAT_HOMEやMySQLのディレクトリ設定も必要ない。
TOMCATはTOMCATプロジェクトを作った場合、pleiades(eclipse)がTOMCAT_HOME以下WEB-INFまでのパス設定をプロジェクトの設定ファイルで作ってくれる。

MySQLは多少面倒でもバッチファイルにフルパス名でコマンドを記述するか、インストーラでインストールした場合に付属するツールを使えば、パスが通っていなくても動作させることができる。

初心者のときに随分色々と環境変数を追加して「アナログなことをするんだなぁ」と思っていたのは少し前の話。
洗練された統合環境には、必ず洗練されたパス解決の仕組みが備わっているのだ、と思う。
最近になってようやくそのことを理解し、JAVA_HOMEなどの余計な環境変数設定を全て削除して、環境変数をきれいな状態に戻すことができた。

[Subversion][Subclipse][チェックアウト]Subclipseによるチェックアウト手順

eclipse上から、Subversionで管理しているファイルをチェックアウトする手順について記述する。
この手順を実行する際の前提事項は以下の通り。
・svnserve.exeが起動していること
・レポジトリにマスタファイルがインポートされていること

Subclipseを使ったチェックアウト手順は以下の通り。

(1) eclipseを起動する。
Pleiadesを使っている場合、SVNプラグインは最初から入っているので、特別なインストール手順は必要ない。
eclipseを起動するだけでSubclipseが使える状態になっている。

(2) SVNパースペクティブを開く。
メニューから[ウインドウ]-[パースペクティブを開く]-[その他]を選択し、ダイアログから[SVNレポジトリー・エクスプローラ]を選択して[OK]ボタンを押下する。

(3) SVNレポジトリー・エクスプローラのウインドウで右クリックから[新規]-[レポジトリー・ロケーション]を選択する。

(4) URLに"svn://localhost"と入力し、[完了]ボタンを押下する。

(5) SVNレポジトリー・エクスプローラにインポート済みのプロジェクトが表示されれば成功。

本サイトの記事で前述したインポート手順を実行している場合、続けて上記手順を実行できる。
(前の記事を参照のこと)
余談だが、インポート手順について気を付けたい点について記述する。
インポート手順を間違えると変なバージョンが付いたり、ゴミファイルが残ったりする危険がある。
よって、前述したインポート手順が成功したなら、実行したコマンドをバッチファイルにまとめておき、必ず成功する手順を固めておくことが望ましい。(それまでに作ったものは一度全部消して、バッチファイルから再構成するときれいに仕上がる)

バージョン管理ではこうした初期設定の面倒をきちんとクリアしておくことで、管理体制の見通しがよくなる。
最初がうまくいけば、後は追加や更新の手順を整備するだけとなる。
(これもできればバッチ処理や手順をまとめる。こうすることでマスタ管理の混乱を未然に防げる)

[Subversion][Subclipse][インポート]Subclipseによるインポート手順

Subversionで作成したレポジトリに、eclipseからアクセスする方法について覚書を記述する。
eclipse上からSubversionにアクセスするためには、以下の手順で操作を行う。
(ここではSubversionをc:\svnにインストールしたものとして記述を行う)

1. c:\svn\bin\svnadmin.exeを使って、レポジトリを作成しておく。
例えばWindowsでSubversionを"c:\svn"にインストールし、"c:\svn\repos"にレポジトリを作る場合、以下のコマンドを打つ。
cd c:\svn\bin
svnadmin create c:\svn\repos

2. レポジトリのconf/svnserve.confの設定を行う。
デフォルトで用意される設定ファイルのコメントを外していく。(行頭の"# "を取る)
コメントを外して有効にする設定は、以下の通り。

anon-access = read
auth-access = write
password-db = passwd
realm = My First Repository

(ファイルはc:\svn\repos\conf\svnserve.conf)

3. レポジトリのconf/passwdを編集し、ユーザ・パスワードを設定する。
同ファイルに"[ユーザ名] = [パスワード]"の形式で記述。
例えばユーザ名"user1"、パスワード"password1"のユーザを作る場合、次の行をファイルに追加する。

user1 = password1

(ファイルはc:\svn\repos\conf\passwd)

4. コマンドラインから以下のコマンドを入力し、svnserve.exeを起動する。
eclipseからレポジトリにアクセスするためには、レポジトリを監視している常駐プロセスにTCP/IPで接続できなくてはならない。
(Subclipseでは裏でTCP/IP接続を行っている)

cd c:\svn\bin
svnserve -d -r c:\svn\repos

-dオプションは"svnserve.exeをデーモンモードで起動する"という意味であり、これによってsvnserve.exeがTCP/IP接続を受けられる状態になる。
-rオプションはレポジトリのルートを示すものでレポジトリのディレクトリを指定する。(この場合c:\svn\reposとなる)

5. eclipseを起動し、レポジトリにプロジェクトを追加する。
例えばTargetというJavaプロジェクトがeclipseに存在し、そのプロジェクトをレポジトリに追加したい場合、以下の操作を行う。

(1) Targetプロジェクトを右クリックして出るメニューから[チーム]-[プロジェクトの共用]を選択する。
(2) SVNを選択し、[次へ]をクリックする。
(3) レポジトリのロケーション(URL)に"svn://localhost"と入力する。
(4) ユーザ名とパスワードに上記3.で設定したデータを入力する。
(5) URLの横にある参照ボタンを押し、エラー表示が出ないことを確認する。
(6) 上記(5)が確認できたら[完了]ボタンを押す。
(7) 続く画面では[全て選択]、[OK]を押下する。(プロジェクトのファイル全てを管理対象として追加できる)
(8) eclipseのメニューから[ウインドウ]-[パースペクティブを開く]-[その他]を選択する。
(9) [SVNレポジトリ・エクスプローラ]を開き、Targetがインポートされていれば成功。

なお、テストした環境では1回目の接続でエラーになった。
その場合は手順をもう一度繰り返せば成功する。
(何度か繰り返したが現象変わらず。2つ目以降のプロジェクト登録は成功するので1度目だけ)

[Subversion][Subclipse][使い方]Subclipse概要調査

Subversionで作成したレポジトリにeclipseからアクセスするツールについて、調査内容をまとめる。
eclipseからSubversionに接続するためのツールは複数があるが、Subclipseの使い方について調査した。
Pleiadesというeclipse環境をインストールしていれば、SubclipseというSubversionアクセスツールが最初から入っている。

Pleiadesはアマテラスプロジェクトで公開している日本語eclipse環境のことで、SubclipseやStruts、Tomcatなど、eclipseでよく使うツールが最初から全部入っている。
通常はeclipseにプラグインを次々に付け足していかなければならないが、これは英語サイトなどで説明を読みながら自力で行う必要があり、初心者にはハードルが高い。
Pleiadesはオススメのeclipse開発環境である。

以下、Subversionで使う概念について、簡単に記述する。
レポジトリとはバージョン管理対象となるファイルを格納する場所のこと。
レポジトリにはマスタファイルを登録(インポート)する。
各開発者はレポジトリからマスタファイルを取得(チェックアウト)する。
開発者がマスタファイルを更新した場合、更新の登録(コミット)を行う。
他の開発者が再度チェックアウトを行うと、コミットした内容が適用された最新ファイルが取得できる。

Subclipseでは、svnのレポジトリにeclipseからアクセスし、マスタファイルをインポートすることができる。
また、インポートしたマスタファイルをeclipse上からチェックアウトすることができる。
よって、開発環境管理者はマスタファイルをインポートし、各開発者はそのマスタファイルをチェックアウトして編集作業を行うという手順を、eclipse上からできることになる。
この次以降の記事では、実際の手順について記述する。

[Javadoc][生成]Javadoc生成

eclipse上からJavadocを生成する手順。
Javadocは/** ~ */までのコメント内に特定のシグネチャ(@で始まるキーワード)を埋め込むことによって、従来でいう関数仕様書のようなものを自動で生成するツール。

出来上がったJavadocはHTMLとなっており、見やすい上に詳細な記述ができるレイアウトである。おそらくこれを自分で1から作ったら何日もかかる。こうした自動生成により、ドキュメント作成にかける時間を短縮し、プロジェクトの効率化を図ることができる。
生成手順は下記の通り。

ソースファイル上のメソッド名をクリックし、行が選択された状態になったら右クリック。
メニューから[ソース]-[要素コメントの生成]でJavadoc形式のコメントを作成できる。

生成した要素コメントがJavadocにどう反映されるかは、次の操作でビューを表示することによって確認できる。
パッケージエクスプローラ上でソースファイルを選択する。
[ウインドウ]メニューから[ビューの表示]-[Javadoc]を選択すると、当該ソースファイルのJavaDocが見れる。

また、最終的にプロジェクトが完成した場合、次の手順によりプロジェクト全体のJavadocを生成することができる。
パッケージエクスプローラ上でプロジェクトを選択する。
[プロジェクト]メニューから[Javadocの生成]を選択すると、Javadocのドキュメントが生成される。

[Javadocの生成]は、プロジェクトが完成した時点で行うのが妥当。
途中でメソッドを追加すると、生成されたドキュメントがエラーとなり、パッケージエクスプローラ上で×印が付く。

生成されたドキュメントはプロジェクト配下のdocディレクトリに格納される。
これを全て削除してもう一度手順を実行すると、最新のソースファイルからJavadocが再度生成される。
docディレクトリのindex.htmlを見ると、プロジェクト全体のJavadocを概観できる。

[JUnit][動作確認]JUnit4動作確認テスト

eclipseを起動し、Javaプロジェクトを作成する。
ここでは動作確認のためのプロジェクト名をTarget、テスト対象のクラスをTargetClassとした。
なお、TargetClassはmodelパッケージの配下とした。(パッケージは作らなくてもよい、便宜上のもの)

テスト用のプロジェクトを、Javaプロジェクトとして作成する。
ここではプロジェクト名をTargetTestとした。
TargetTestプロジェクトにmodel.junit.testパッケージを追加し、その配下にTargetClassTestクラスを追加する。
(ここでもパッケージは作らなくてもよい、便宜上のもの)

パッケージエクスプローラ上でTargetTestプロジェクトを右クリックするとメニューが出る。
ここで出るメニューから、[ビルドパス]-[ビルドパスの構成]を選択する。

[ライブラリ]タグを選択し、[ライブラリの追加]ボタンを押下する。
JUnitを選択し[次へ]。
次の画面では[JUnit4]を選択する。

同じく[ビルドパスの構成]を選んで出てくる画面で、[プロジェクト]タグを選択し、[追加]ボタンを押下する。
[Target]にチェックを入れ、[OK]ボタンを押下する。(このTargetは先に作ったプロジェクトのこと)

TargetClassのソースファイルを開き、以下のメソッドを追加。

public void exec(String[] args) {

  // ひとまず中身は空でよい
}

TargetClassTestクラスのソースファイルを開き、次のimportステートメントを追加。

import static org.junit.Assert.*;
import org.junit.Test;
import model.TargetClass;

さらに、次のテストメソッドを追加。

@Test
public void testExec() {

  try {
    TargetClass tc = new TargetClass();
    tc.exec(null);
  }

  catch (Exception e) {
    fail();
  }
}

パッケージエクスプローラ上でTargetClassTestを右クリックするとメニューが出る。
このメニューから[実行]-[JUnitテスト]を実行し、1/1成功の表示が出れば動作確認完了。
ひとまずこれで、JUnitを動作させる環境が整ったことになる。

迅速なテストを行うため、JUnitのテストはオブジェクト指向分析でいうところのモデル部分のみを対象とすることが望ましい。
たとえば作成したモデル部分のロジックが、リッチクライアントアプリケーション上から使われても、Webアプリケーションから使われても、結果は同じはずである。(モデルとしての動作は、ビューに影響を受けない)

自動テスト対象はモデル部分に限定する、というのが私の個人的な意見である。
ツールが発達してWebアプリなども自動でテストできるようだが、原則は「不変」であるはずのモデルのロジックのみとしたいところ。
標準出力へのprintといった動作も原則NG。
代わりにlog4jなどを使ったロギングで動作状況を把握する、というJUnit以外のトレース手段も本番環境としては用意すべきだと思う。

とはいえ、これは頭が固い人間の意見で、却って効率を落とすことがあるかもしれない。
プロジェクトごとに最善の方法を探っていくべきである。

[Subversion][インストール]Subversion 1.6.1 インストール

eclipseからも使えるバージョン管理ソフトとして、Subversionを試すことに決め、インストールを行った。
SubversionはCVSのいいところを残して進化させたツールであるとのこと。
WinCVSを使った開発を最近になってもやってきた経緯があるので、技術の流れが早いことを痛感する。

インストールは"Subversion インストール"で出てくるサイトからリンクをたどれば、意外とすぐいける。
インストールの紹介サイトではWindows版ならインストーラ提供、となっているが、実際にはzipだった点が予想外。
ただこれはJava関係ならよくある話で、要はインストールするまでもなく、zipを解凍して適当なディレクトリに置けば、そこがインストールディレクトリになる、というものである。

zipを解凍して、コマンドラインからレポジトリを作成する。
([インストールディレクトリ]\binにパスを通しておく)
コマンドは、以下の通り。
svnadmin create [レポジトリのディレクトリを指定]
コマンドラインで出るメッセージが「成功」を意味する英語ならOK!
指定したディレクトリに、Subversionが管理に使う様々なディレクトリやファイルが自動生成されているはずである。

次にJava開発プロジェクトなど、管理対象をレポジトリにインポートする。
コマンドは、以下の通り。
svn import [管理対象に加えたいディレクトリのパス] [レポジトリのURL] -m ""

レポジトリがc:\sub_version\manage\repositoryディレクトリであり、管理対象の開発プロジェクトがc:\java\projectであるとする。
レポジトリを作成するコマンドは、
snvadmin create c:\sub_version\manage\repository
レポジトリに管理対象のプロジェクトを追加するコマンドは、
svn import c:\java\project file:///c:/sub_version/manage\repository -m ""
となる。

ここで注意すべきは"file:///c:/sub_version/manage/repository"で、ここを書き間違えやすい。
この表記はブラウザからローカル(自分のPC)のファイルを見るときに指定する方法と同じであり、このように書くことで
c:\sub_version\manage\repository
(↑)このディレクトリを指定したのと同じ意味になる。
ディレクトリの区切りもここだけは"\"ではなく"/"でなければならない。

ブラウザで"file:///c:/~"と入力すれば、実際にローカルPCのディレクトリが見えるはず。
納得いかない場合は、試してみると理解が早い。
ちなみに、自分のPCではなくネットワーク上にあるファイルをレポジトリに登録する場合は、"http://~"に変わる。
ブラウザと同じ指定方法で、管理対象のファイルを指定できるようになっている。

ここまでで、バージョン管理を行うレポジトリ(格納庫)にプロジェクトが登録されたことになる。
後は各開発者が、自分の開発用ディレクトリを作り、レポジトリからプロジェクト全体のソースファイルを取得する。
これをチェックアウトと呼ぶ。
自分の開発用ディレクトリで、以下のコマンドを打つ。
svn checkout file:///c:/sub_version/manage/repository

(↑)こうすると、レポジトリで管理しているプロジェクトの全ファイルが自分の開発用ディレクトリにコピーされる。
ここで何らかのファイルを修正した場合、コミットを実行すればそれがレポジトリに登録され、新しいマスタとなる。
コミットした後に、自分の開発用ディレクトリの中身を全部消して、もう1回チェックアウトを実行すれば、自分がコミットしたファイルも含めた最新版が取得できるはずだ。

チェックアウトやコミットをコマンドラインでやっていくのは面倒であるため、eclipseにプラグインを入れてGUIから操作できるようにすることが多い。
それについては、改めて記述する。
以上、確認が取れたところまで記述。

[Java][開発][セキュリティ]Java開発関連セキュリティ

Javaの各種開発ツールを使う上で気を付けたいのがセキュリティの問題。
開発用のTomcatしかり、正式なWebサーバとするためにApacheを採用する場合にもいえることだが、ポートが開くためにセキュリティ上の問題が生じる。

いわゆるBOF攻撃は、特定のIPアドレスに対し、特定のデータを送信するだけで、コンピュータの制御権を取られてしまう。(サービスがセグメンテーションバイオレーションで異常終了するだけのこともあり)
ポートが開いていれば、自動的に攻撃の対象となる。

一番良いのはスタンドアロンによる開発。
Webと接続していない環境のローカルマシンでTomcatなどのサーバを立ち上げ、開発を行うのがよい。
少なくともネットに対してポートを開いてはいけない。

しかしこの制約はわざわざ開発用にPCを1台スタンドアロンにする余裕がない人には向かない方法だ。
次善の策としては、Acronisといったハードディスクの内容をすべてバックアップできるツールを使い、いざとなったら5分程度で以前の環境に復旧できるようにすることだ。

もうかなり以前から、ハードディスクに個人情報を一切置かないようにしている。
一瞬「無理」と思われるが、やってみると意外にいける。
インストール時に入力する名前は適当な偽名、組織名等は入力せず。
最重要なメールは携帯で受けられるようにする、といった工夫が必要ではあるが・・・

万一ワーム等で情報が流出すると、絶対に消せなくなってしまう。
いつまでも、どこかで誰かがその流出データを見る可能性を消せなくなる。
それは時として致命的なことだ。
特に社会人として長く職に在り、責任が重くなってくればくるほどそうである。

学生時代には自分の住所や電話番号が分かったところで、どうなるものでもないと考えていたが、今では個人情報を入力しなくてはならないサイトも、かなり考えてから登録の有無を決定している。

[eclipse][Pleiades][Tomcatプロジェクト]Eclipse 3.4 Ganymede Pleiades Tomcat プロジェクト作成

プレアデス(Pleiades)にTomcatとTomcatプラグインが最初から入っており、eclipseのメニュー上からもTomcatプロジェクトをいきなり作成できる状態だった。

eclipseからTomcatを起動してコンソールの表示を確認。
Pleiadesに3バージョンも入っているTomcatのうち、Tomcat 5.5.27 を動かしていることが判明。
早速Tomcatプロジェクトを作成して、JSPとサーブレットを動かしてみる。

すると、JSPはすんなり動いたのにサーブレットは動かない。
パス設定の問題かと思い、CATALINA_HOMEの設定をしてみたが動かず。

となると、JSPは動くのにサーブレットが動かない理由は、invokerの設定かと考え、%CATALINA_HOME%/conf/web.xmlを編集。
コメントとなっていたinvokerの設定を有効にすると、サーブレットも動くようになった。(ファイルを"invoker"で検索し、コメントになっている部分のコメントを解除する)

そういえばinvokerはセキュリティ上の問題から、使用が推奨されないのだったか。
web.xmlを手書きで編集しないとダメだった点は痛いが、原因が分かったのでひと安心。
手書きサーブレットは、web.xmlも手書きで登録するか、invokerを使わないとダメなようだ。

サーブレットはStrutsなどを使う場合、ActionServlet(自動で動くサーブレット)となり不要になるため、invokerの設定は再度コメントにしておくこととした。
パス設定も不要なので、CATALINA_HOMEは削除。

[eclipse][Pleiades][インストール]Eclipse 3.4 Ganymede Pleiades All in Oneインストール

検索で"eclipse 日本語化"で出てくるリンクをたどればすぐにたどりつく。
インストールは圧縮ファイルを展開するだけ。
ただし、パス名が長くなりすぎるとエラーになるため、なるべくインストールするドライブのルートに近いディレクトリで展開する必要がある。

展開後は1GB近くになる大容量だが、何とTomcatまで中に入っている。
eclipse.exeをダブルクリックすると、最初から全て日本語表示。
すばらしい!
まさしく開発者のためにあるような環境だ。
アマテラスプロジェクトおそるべしである。

念のため、Javaプロジェクトを作成して、System.out.printlnで"Hello world"系の出力を出すだけのプログラムを作成してみた。
問題なく動く。
あとはTomcatプロジェクトだが、これもTomcatプラグインをインストールしなくても、最初から入っている模様。

Tomcatプロジェクトについて後で試すこととし、とりあえずインストール成功とみなす。
Tomcatプロジェクトが動かなかったら別途考える。
十分に枯れてそうな完成度なので大丈夫だと思うが・・・

この分だと、Strutsも入ってる?
最初にこれをインストールすればよかった、って感じの万能環境だった。
とりあえずこれまでにインストールしたものと、PATH設定とかでのバッティングもないので、今後はこの環境を使っていく。
(英語版の環境も、英語版でないとできないものがあってはいけないので、念のため残しておく)

[SWT][インストール]SWT 3.5M6 インストール

記述を忘れていたが、ここまでに記載した内容はいずれもWindows環境にJava開発関連のソフトをインストールする手順である。
Linuxの場合、eclipseやTomcat、MySQLなど一部のツールについては、OSのインストールと同時に入ることもある上、環境設定のやり方が違うので注意が必要。

SWTはJavaのウインドウプログラムサンプルを作るためにダウンロードしてきた。
eclipseのFileメニューからImportを選び、アーカイブファイルのインポートを選択、ダウンロードしてきたzipファイル内にあるアーカイブを指定すると、SWTを使ったGUIプログラムが作れるようになる。

eclipseで簡単なウインドウプログラムを作成し、プログラムが動いたことが確認できた。
インストール成功。

[MySQL][インストール]MySQL 5.1.33 インストール

Javaからアクセスするデータベースとして、MySQLを選択。
"MySQL ダウンロード"などのキーワードで検索し、Windows用のインストーラをダウンロードする。

インストーラから普通にインストールできる。
カスタムを選択しても、英語の内容をよく読めば問題なくインストールできると思う。(実際、カスタムにした)

標準で付いてくるコンソールプログラムでパスワードを入力するとログインできる。
デフォルトではtestというデータベースディレクトリが用意されている。
use test
(↑)このコマンドを打ってtestデータベースを選択したら、適当にテーブルを作成し、
select * from XXX_TBL
などと打ち込んで、データが取得できればインストール完了。

[Tomcat][インストール]Tomcat 5.5.27 インストール

TomcatはサーブレットやJSPといった、サーバサイドのJavaアプリケーションを開発するために必要となる。
いわゆるWebサーバである。

TomcatはWebサーバとしての機能が弱く、セキュリティにも問題があるので、実際のWebアプリケーションではほとんど採用されないが、イ ンストールしてeclipseにTomcatプラグインを付ければ、開発マシンですぐにデバッグできる環境が整うとあって、開発にはよく利用される。

検索で"Tomcat ダウンロード"などのキーワードを指定し、インストーラをダウンロードする。
eclipseと同じく、インストールパス名に半角スペースやドットが入るといけないので、ドライブ直下のディレクトリを指定してインストール。(デフォルトだと半角スペース入りの"Program Files"配下などにいってしまうため、この点は注意する必要がある)

インストールが完了したら、標準で付いているモニタプログラムかシステム管理 - サービスからapache tomcatサービスを起動する。
ブラウザを開き、
http://localhost:8080/
と入力して、tomcatのページが表示されればインストール完了。

なお、Vistaでは標準添付のモニタプログラムでアクセス拒否エラーが出てしまう。
なので面倒だったが、システム管理 - サービスから起動してテストを行った。

[JDK][インストール]JDK 1.6.0_13 インストール

JDKのバージョンは1.6.0_13。
JDKはJava Development Kitの略称。
ダウンロードしたファイルをダブルクリックするとインストーラが起動する。

問題はダウンロードにあり。
"jdk ダウンロード"などで検索し、リンクをたどっていかないと場所が分からない。
サンマイクロシステムズは経営危機にあるというが、管理がずさんになってきている?

ともかく、素人にはリンクをたどってたどりつくのが難しい位置にあると思う。
少なくともページを見てすぐにたどりつけるようにはなっていない。
(JREなら簡単に入手できるが・・・)

インストール後、環境変数にJAVA_HOMEを追加し、jdkをインストールしたディレクトリを設定する。
さらに環境変数PATHに%JAVA_HOME%\binを追加すると、コマンドプロンプトでJavaソースファイルがコンパイルできるようになる。

サーブレットやJSP、その他のJavaプログラムを手書きすることはもちろん可能である。
よって、JDKのみでも開発を行っていくことは不可能ではない。
しかしこのままでは余りに環境が貧弱なため、通常は統合開発環境であるeclipseをインストールし、Java開発を支援するいくつかのプラグインを追加して使うことになる。

[eclipse][インストール]eclipse 3.4.2 インストール

eclipseのバージョンは3.4.2。
ganymedeと呼ばれる版。

サイトからダウンロードしてきたzipファイルを解凍すると、eclipseのexeも含めたインストールディレクトリが形成される。

インストールパスに半角スペースやドットがあると、開発時に問題を起こしていたらしいので、慣習的に空いているドライブの直下に置くことが多いようだ。
最も多いのが当然ながらCドライブ直下。
念のため、ドライブ直下のパスにインストールすることに。

解凍したファイルをコピーするのみとなっており、一般的なインストーラを使った手順ではない。
別途JDK(Java Development Kit)をインストールしており、環境変数にJAVA_HOMEが設定されていること、PATHに%JAVA_HOME%\binが追加されていることが起動の条件。

exeをダブルクリックして、無事に起動すれば成功。
メニューからJavaプロジェクトを作成し、System.out.printlnで"Hello world!"でも出力すれば、動作確認も完璧。
ひとまずJava開発のプラットフォームを手に入れたことになる。