WicketでHTMLを別のディレクトリに配置する

前回の続き。

Wicket-jaのメーリングリストで最近話題になった内容。

WicketはデフォルトではPageクラスに対応するHTMLファイルはPageクラスと同じ階層にある必要がある。というかPageクラスと同じ階層を検索するようになっている。
特に問題はないけど、一般的にはWEB-INFの下に置いてあるのが普通だし、今回はHTML部分は自称デザイナーOが作ることになっているので、javaのパッケージ内をいじられるのはあまり好ましくない。というか彼も.javaやらのファイルがあるところで作業するのは嫌だろうと思う。

なのでHTMLファイルはWEB-INF以下に配置しようと思う。
まずはViewFileLocatorを作成する。
ViewFileLocator.java

public class ViewFileLocator extends ResourceStreamLocator{
   private String pagesPath;
   public ViewFileLocator(String pagesPath){
      this.pagesPath = pagesPath;
   }
   
   @Override
   public IResourceStream locate( Class<?> clazz, String path ){
      if( path.indexOf( pagesPath, 0 ) != -1 ){
         IResourceStream located = super.locate( clazz, path.substring(pagesPath.length() + 1));
         if( located != null ){
            return located;
         }
      }
      return super.locate( clazz, path );
   }
}

つぎにApplicationクラスのinitメソッド内に以下を追加

MyApplication.java

IResourceSettings resourceSettings = getResourceSettings();
resourceSettings.addResourceFolder( "WEB-INF/pages" );
resourceSettings.setResourceStreamLocator( new ViewFileLocator("taka/of/master/pages" ) );

以上で完了。
すると

taka.of.master.pages.HomePage.java

に対応するHTMLファイルは

WEB-INF/pages/HomePage.html

が使用される。

taka.of.master.pages.user.UserPage.java

WEB-INF/pages/user/UserPage.html

が使用される。

階層は保つ必要がありそうだけど、これでjavaソースフォルダ内からHTMLファイルがなくなった。


メーリングリスト、参考になりました。

以上。

Wicketでログアウトを実装する

前回の続き。
前回Wicket楽だね〜って事を書いたけど、昨日実際に例を見つけたから書いておこうと思う。

ログアウト機能をまだ実装してなかったから昨日実装した。

HomePage.classにこれだけ書いておしまい

this.add(new Link<Void>("logoutLink"){
     @Override
     public void onClick() {
          this.getSession().invalidate();
          this.getRequestCycle().setRedirect(true);
          this.setResponsePage(HomePage.class);
     }
});

あとはHTMLに

<a href="#" wicket:id="logoutLink">ログアウト</a>

ってかいておしまい。わずか9行!!
Wicketのすばらしさのほんの一例でした。

以上。

Wicketのすばらしいっぷり

前回の続き。

Wicketで画面周りを作り始めた。設計書を書いてるわけじゃないので頭の中に漠然とあるイメージでやってる。そうすると「あ、こういう画面いるじゃんか」とか「このあとはここに遷移したほうがいいな」とかがでてくる。
もしStrutsでやってたら、

  • 画面のモックを作ってHTMLの表示を確認する。
  • ActionFormを作る
  • Actionクラスを作る
  • struts-config.xmlに定義を追加する
  • validation.xmlに定義を追加する
  • tilsの定義を追加する

とか色々やって、定義は文字列で指定するもんだから間違ってたりとかして。。。
めんどくさいことになってたけど、今回はそうでもない気がする。

  • HTMLを作る
  • Pageクラスを作る

だけ。深く突っ込むとValidatorとかあるけど。やっぱこうしようとかがすごく楽です。

JSPでやってたようなことをPageクラス内でやるからコードは増えるけど、「あれ?このドロップダウンはどこから取ってきたやつをいれるんだっけ?」とか「何て名前でRequestにセットしたっけ?」とかいうのがなくて逆に楽な気がする。サブミットされた後の処理とかも同じページにあるからどういう値がどこにあって・・・。とかがわかりやすいし、匿名クラスってすごく便利だなと改めて実感した。

Wicketでできることが100あるとしたらまだ12くらいしか理解してないけど、Wicketすごく好きになった。ListViewとかすごく素敵。

このwebアプリを作っていく中で30くらいまで理解できたらいいなと思った。

以上。

設定ファイルを書く(SpringとIBatisとweb.xml)

前回は開発環境構築まで終わったのでいよいよ作っていこうと思う。

でも自動生成できるところはしていかないとめんどくさくてしょうがない。
まずビジネスロジックJUDEでクラス図を書いたのでjavaケルトンコードを出力。これでインターフェースと空の実装クラスが完成。パッケージもきちんと分けておけばそのとおりにフォルダが出力されるので、ワークスペースにどーんとブン投げればOK。

次にDAOまわり。今回はIBatisを使うのでAbatorっていうツールが使える。これは前にも使ったことがあって、すごく便利。O/Rマッパーを使用できない案件などで自作DAOを作るときとかも応用できそう。まぁやってることはそんなに難しくなくて、DBにアクセスしてテーブル定義からDAOとモデル、それからIBatis用のSqlMapファイルを生成してくれる。Springと連携する用の設定にすればSqlMapClientDaoSupportを継承したクラスを作ってくれる。
これもパッケージを指定できて、実行すればその階層にファイルが出来上がる。それをワークスペースにどーんとブン投げればOK。

で、設定ファイルを書く。つっても最初に書いてしまえば後はほとんど触らなくていいヤツだからさらっと書いてしまおう。

applicationContext.xml

<?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:context="http://www.springframework.org/schema/context"  
  xmlns:tx="http://www.springframework.org/schema/tx"  
  xmlns:aop="http://www.springframework.org/schema/aop"
  xsi:schemaLocation="    
    http://www.springframework.org/schema/beans    
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
    http://www.springframework.org/schema/tx     
    http://www.springframework.org/schema/tx/spring-tx-2.5.xsd    
    http://www.springframework.org/schema/context    
    http://www.springframework.org/schema/context/spring-context-2.5.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
    >

	<context:component-scan base-package="taka.of.master"/>
		
	<!-- DataSource -->
	<bean id="dataSource"
			class="org.apache.commons.dbcp.BasicDataSource"
			destroy-method="close">
		<property name="driverClassName" value="org.postgresql.Driver" />
		<property name="url" value="jdbc:postgresql://localhost:5432/appdb" />
		<property name="username" value="app" />
		<property name="password" value="app" />
	</bean>

	<!-- Transaction -->
	<tx:annotation-driven />
	
	<bean id="transactionManager"
			class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	
	<!-- SqlMap setup for iBATIS Database Layer -->
	<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation"><value>/WEB-INF/SqlMapConfig.xml</value></property>
		<property name="dataSource"><ref local="dataSource"/></property>
	</bean>
</beans>

まずはBean定義はアノテーションでやるので検索するパッケージを指定する。トランザクションアノテーション。それからIBatisの設定。今まではここにDAOの設定も書いていたんだけど今回はAbatorで

@Autowired
public UsersDao(SqlMapClient sqlmapClient) {
   super();
   this.setSqlMapClient(sqlmapClient);
}

こんな感じのコンストラクタができるように生成したので設定はいらなーい。
この設定ファイルは今後さわることはほとんどないだろう。AOPでログとかの設定するときには触るかな?でもbean定義をごりごり書かなくていいのでかなりすっきり。アノテーションってすばらしいね。

SqlMapConfig.xml

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

<sqlMapConfig>
    <settings useStatementNamespaces="true" />

    <!-- sqlMap settings -->
    <sqlMap resource="taka/of/master/dao/users_SqlMap.xml"/>
</sqlMapConfig>

IBatis用の設定ファイル。コレはテーブルが追加になったときは触るかな?でもそんなに頻繁にはないね。注意点はパッケージは/で区切る。コレくらい。

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>rumania-gorilla</display-name>
  <filter>
	<filter-name>wicket</filter-name>
	<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
	<init-param>
		<param-name>applicationClassName</param-name>
		<param-value>taka.of.master.web.core.MyApplication</param-value>
	</init-param>
	</filter>

	<filter-mapping>
		<filter-name>wicket</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	 <listener>  
           <listener-class>  
               org.springframework.web.context.ContextLoaderListener  
           </listener-class>  
     </listener>  
</web-app>

web.xmlはこれだけ。すごくシンプル。これももう触ることはないのかな?
wicketのアプリケーションクラスの設定とspringのリスナーの設定だけ。他はwicket内部でやるのでいらないっす。
ちなみにApplicationクラスのinitメソッド内で

this.addComponentInstantiationListener(new SpringComponentInjector(this));

って書くとWicketとSpringの連携は終了

これで設定も終了。strutsだと設定ファイルが大変なことになるけど今回はコレで終了。
さて。ごりごり作っていくかな。

以上。

eclipse+WTP+m2eclipseで開発環境を作る

前回の続き・・・。

さて、クラス図を一通り書き終わったので環境でも設定するか・・・。

開発環境

  • eclipse3.3
  • WTP
  • m2eclipse

今回はWTPMaven2でプロジェクトを作ろうと思う。

http://d.hatena.ne.jp/NAGASEYASUHiTO/20070703を参考にして設定。これでMavenプロジェクト&動的webプロジェクトができる。

そして今回のwebアプリで使用するライブラリをpom.xmlに記述していく。

<?xml version="1.0" encoding="UTF-8"?><project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>rumania-gorilla</groupId>
  <artifactId>rumania-gorilla</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <description></description>
  <dependencies>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.5.3</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>1.5.3</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring</artifactId>
      <version>2.5.5</version>
    </dependency>
    <dependency>
      <groupId>commons-beanutils</groupId>
      <artifactId>commons-beanutils</artifactId>
      <version>1.8.0</version>
    </dependency>
    <dependency>
      <groupId>commons-dbcp</groupId>
      <artifactId>commons-dbcp</artifactId>
      <version>1.2.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.wicket</groupId>
      <artifactId>wicket</artifactId>
      <version>1.4-m3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.wicket</groupId>
      <artifactId>wicket-auth-roles</artifactId>
      <version>1.4-m3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.wicket</groupId>
      <artifactId>wicket-datetime</artifactId>
      <version>1.4-m3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.wicket</groupId>
      <artifactId>wicket-extensions</artifactId>
      <version>1.4-m3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.wicket</groupId>
      <artifactId>wicket-spring</artifactId>
      <version>1.4-m3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.ibatis</groupId>
      <artifactId>ibatis-sqlmap</artifactId>
      <version>2.3.0</version>
    </dependency>
    <dependency>
      <groupId>postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>8.3-603.jdbc4</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
      <version>0.9.9</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>0.9.9</version>
    </dependency>
  </dependencies>
</project>

うわ・・。なげぇ・・。でも1回書いちゃえば楽だからね・・・。
保存するとm2eclipseが勝手に依存ライブラリを取得してくれる。

おし完了。コレで全部だよね?まぁ足りなかったらまたpom.xmlに追記すればOK。

さて・・。テーブル設計するか・・・。

以上。

※2009/08/26 追記
eclipse3.5+m2eclipseプラグインでやったらWebContentのままでいけた
上記のサイト通りsrc/main/webAppとかやらなくていいかも・・・・。

Wicket + Spring + IBatisでWEBアプリ

個人的に簡単なグループウェアのWEBアプリを作ることにした。
というのも地元の友人が結婚しだしたので、嫁さんとか含めてみんなでコミュニケーションとれるようにしたいね~ってことでつくることになった。

期間が1ヶ月(帰宅後と休日だけ)なので全部新しいものを使って勉強しながら作るのは無理っぽい。でもやるからには何か習得したいので、下記のような構成で行くことにした。

DIコンテナは違うやつ使ってみたかった(Guiceとか)けど時間がないので慣れたSpringで。
もちろん勉強中のWicketで行く。まだベータ?だけどジェネリクス対応の1.4で。
ホント簡単なものなので(つっても勉強用ではなく運用する予定)さくっと作ろうと思う。

予定している機能

  • 認証(openid対応で行こうと思う)
  • イベント(mixiとかのあんな感じのやつ)
  • 雑談(BBSにするかtwitterぽくするか考え中)
  • フォトギャラリー(タグをつけるか階層化するか。。どういう使い方するかだな)
  • メールでお知らせ(イベントとか雑談とかの更新のタイミングで。。。そうmixiとかのやつw)

とりあえず最初はこんなもんかな

その他の要件

  • 携帯電話対応(というか最初は携帯電話だけで)
  • なので簡単な認証がいい(はいはい端末UID?だっけ?で認証できるようにね。。。)

という感じ。

役割分担

今までもそうだったけど何か作るときはデザインは自称デザイナーの友人Oにお任せしてたので今回もそれで。。
今まではJSPいじってもらったりして色々問題が多かったけど今回はWicketだからどうでしょう?Wicketの実力が発揮できるかもしれん。。というわけでHTMLは友人Oの担当。それ以外は全部俺。

さっそくとりかかろう

設計書とか書かないっすよ?めんどいし。。でもいきなりソースゴリゴリは無理なのでとりあえずクラス図でもかくか~。モックができないと画面作っていけないのでとりあえずビジネスロジック層から着手。。


という感じで昨日作り始めたばかりだ。さぁ完成するだろうか!!

以上。

Apache WicketでWebアプリ

Apache Wicket 1.3がリリースされて、盛り上がってきた?Apache Wicketを試してみる。

とりあえずHello,Worldしてみる

準備するもの

環境を準備する

まずはいつものようにeclipseでwebアプリ用の設定をする。
そしていつものようにweb.xmlを編集する。

web.xmlの編集

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
	<display-name>wicket</display-name>
	<filter>
		<filter-name>wicket</filter-name>
		<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
		<init-param>
			<param-name>applicationClassName</param-name>
		<param-value>application.core.Application</param-value>
		</init-param>
	</filter>

	<filter-mapping>
		<filter-name>wicket</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>
WebApplicationを作成する。

名前のとおり、このwebアプリをあらわすクラスを作成する。

Application.java

package application.core;

import org.apache.wicket.protocol.http.WebApplication;
import application.pages.SamplePage;

public class Application extends WebApplication{

	@Override
	@SuppressWarnings("unchecked")
	public Class getHomePage() {
		return SamplePage.class;
	}
	
	@Override
    protected void init() {
        super.init();
        this.getRequestCycleSettings().setResponseRequestEncoding( "UTF-8");
        this.getMarkupSettings().setDefaultMarkupEncoding("UTF-8");
    }

}

上のようにorg.apache.wicket.protocol.http.WebApplicationのサブクラスを作成する。
このクラスは抽象クラスで必ず実装しなければならないクラスはgetHomePage()メソッドだけ。このメソッドは名前のとおり、ホームページを返すメソッド。ここでは後で作成するSampleHomePageクラスのClassオブジェクトを返す。
これでコンテキストルートのパスにアクセスがあった場合にこのページが表示される。
1.3ではジェネリクス対応していないため警告が出るので@SuppressWarnings("unchecked")をつける(1.4からは対応するらしい。。。色々議論が展開されているらしいが。。)

init()メソッドは文字コードの指定をする。Wicketではここで指定する以外にない?のかな?何かコンストラクタで設定したりしてもこの時点ではクラスがまだ不完全でうまく出来ないらしいのでinit()メソッド内でやるらしいっす。
ちなみに上がjavaファイルの文字コード、下がHTMLファイルの文字コード

実際にページを作成していく

Wicketはページとクラスのマッピングは規約によって行われるため設定ファイルは不要だ。その規約とは

HTMLファイル名とクラス名を同じにする(階層も同じにする)

これだけ注意して作成していく。

HTMLページを作成する

SamplePage.html

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:wicket="http://wicket.apache.org"
	xml:lang="ja" lang="ja">
  <head>
    <title>List Page</title>
    <style type="text/css" media="screen">
    <!--
        h1   { font-size: 16pt; background-color: orange; padding-top: 2px; padding-bottom: 2px }
    -->
    </style>
  </head>
  <body>
    <h1>Apache Wicketテスト</h1>
    <div wicket:id="test">テストだぜFuckin</div>
  </body>
</html>

Wicketで操作したい箇所にwicket:idでマークアップする。こうすることでjava内でその部分を動的に操作することが出来る。XHTMLなのでxmlnsを利用して独自の属性を定義してるんだね。xmlns:wicket="http://wicket.apache.org"の部分は別に書かなくてもいいらしいんだけど、個人的にはxmlとしておかしいから気持ち悪いし、警告も出るので書いている。

そのページのクラスを作成する

SamplePage.java

package application.pages;

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.model.Model;

public class SamplePage extends WebPage{
	public SamplePage() {
	    super();
            this.add( new Label("test", new Model("Hello, World!")));
	}
}

ページを作成するときは通常org.apache.wicket.markup.html.WebPageを継承する。swingと同じようにコンストラクタ内でページの部品を作成していく。名前から想像つくけど、
this.add( new Label("test", new Model("Hello, World!")));
の部分で、
自分自身(ページ)に"test"というIDがついたラベルに"Hello, World!"という文字列を持ったモデルを追加する
とすることでHTMLでマークアップした箇所を操作している。

動かしてみる

tomcatでもjettyでも何でもいいから、通常のwebアプリと同様に動かす。そしてブラウザから
http://localhost:8080/wicket
にアクセスする(/wicketの部分はコンテキスト)


このようになる。javaで挿入した"Hello, World!"という文字列がマークアップしたタグに表示されてれば成功。

う〜む。こんなに簡単に、しかもわかりやすく出来るなんて。。。。設定ファイルがないとかすばらしいね。javaもなんだかわかりやすくていいし。なによりコンセプトがいいと思う。

Apache Wicketなかなかいいな。好きになった。。もうちょっと勉強してみようかな。

今度はFormとかその辺をいじってみようっと。

以上。