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の再起動が必要。

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