読者です 読者をやめる 読者になる 読者になる

#18 基本に立ち返る

AdventCalendar2013

どうも。運用のプロフェッショナル、セト神こと @mix3 です。(ゝω・)vキャピ

teck.kayac.com Advent Calender 2013 18日目のエントリです。

最近の自分は割と真面目に人生の迷子みたいな感じになってきているので、一旦立ち止まって基本に立ち返ろうと思います。

自分の基本 それは Wicket!

Wicket は Java のウェブアプリケーションフレームワークで結構特徴的だったやつです。

  • XMLレス
  • web.xmlへの単純な記述のみ 設定はコードで
  • オブジェクト指向
  • ページもコンポーネントという形でオブジェクトにし、匿名クラスで振る舞いを変える
  • よく説明で使われてたのが「Swingみたい」
  • ステートフル
  • モデルはシリアライズ可能にしておいて、セッションにぶち込む 結構豪気

こんな感じ。

Java で ウェブアプリで何が辛いって xml地獄が本当に地獄だった(自分にとっては)ので、当時 Wicket が xmlレスだったというのが本当に輝いて見えてました。

まあ、そんな Wicket 大好きだったけれども

2014ブレイク確実!JavaベースのポータブルなWebフレームワーク Dropwizard | yojikのlog

とか

今どきのJava Webフレームワークってどうなってるの? | きしだのはてな

とかあって、今となっては Wicket の優位性ってどうなんだろうなぁ、とか時間の流れを感じて感慨深いです。

でもそんなの関係ねぇ! 俺は Wicket が好きなんだ!

ということで、昔を思い出しながら Wicketを 触ろうと思います。ここの執筆時点でもう21時半の今日この頃。

最近では Maven より Gradle でしょ? みたいな声も聞きますので、Gradle で Wicket を扱ってみようかと思います。

Gradle は Groovy製らしく、gvmなるもので使えるようにするのが今時らしいので、さくっと入れましょう。

curl -s get.gvmtool.net | bash

入れたら Gradle もさくっと入れましょう。

 gvm install gradle 1.9 (執筆時点で最新が1.9)

これだけでもう Gradle が使える。はやい! Mavenとは違うのだよMavenとは!

でも Gradleの使い方全く分からないので、「 gradle wicket 」でググると svi3c / WicketAndSpringDemo がとっても参考になりそうなので、ここから Gradle の設定を引っ張ってきましょう。

$ cat build.gradle

apply plugin: 'java'
apply plugin: 'war'
apply from: 'eclipsePaths.gradle'
apply from: 'jettyConfig.gradle'

version = 0.1

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.apache.wicket:wicket:6.+'
    compile 'org.apache.wicket:wicket-extensions:6.+'
    compile 'org.slf4j:slf4j-log4j12:1.+'
    testCompile 'junit:junit:4.+'
}

task copyMarkup(type: Copy) {
    from(mainSrc) { include '**/*.html', '**/*.properties' }
    into mainOutCls
}

[jettyRun, war]*.dependsOn copyMarkup

$ cat eclipsePaths.gradle

import org.gradle.plugins.ide.eclipse.model.SourceFolder

apply plugin: 'eclipse'

eclipse.classpath.file.whenMerged { cp ->
    cp.entries.findAll { it instanceof SourceFolder && it.path.startsWith(mainSrc) }*.output = mainOutCls
    cp.entries.findAll { it instanceof SourceFolder && it.path.startsWith(testSrc) }*.output = testOutCls
    cp.entries.findAll { it instanceof SourceFolder && it.path.startsWith(mainRes) }*.output = mainOutRes
    cp.entries.findAll { it instanceof SourceFolder && it.path.startsWith(testRes) }*.output = testOutRes
}

eclipseClasspath.doFirst { file('.classpath').delete() }

$ cat gradle.properties

mainSrc=src/main/java
mainRes=src/main/resources
testSrc=src/test/java
testRes=src/test/resources

mainOutCls=build/classes/main
mainOutRes=build/resources/main
testOutCls=build/classes/test
testOutRes=build/resources/test

$ cat jettyConfig.gradle

apply plugin: 'jetty'

[jettyRun,jettyRunWar]*.with {
    httpPort = 8081
    scanIntervalSeconds = 1
}

apply from で分割して eclipsejetty の設定しつつ、ビルドの設定してるっぽいですね。(丸写しなのでよくわかっていません)

この時点で gradle jettyRun とかすると怒られました まあ設定もコードも無いので当然ですね。ということで動くようにコードも追加します。

$ tree src/

src/
└── main
    ├── java
    │   ├── Application.java
    │   ├── HomePage.html
    │   └── HomePage.java
    ├── resources
    │   └── log4j.properties
    └── webapp
        └── WEB-INF
            └── web.xml

$ cat src/main/resources/log4j.properties

log4j.appender.Stdout=org.apache.log4j.ConsoleAppender
log4j.appender.Stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.Stdout.layout.conversionPattern=%-5p - %-26.26c{1} - %m\n

log4j.rootLogger=INFO,Stdout

log4j.logger.org.apache.wicket=INFO
log4j.logger.org.apache.wicket.protocol.http.HttpSessionStore=INFO
log4j.logger.org.apache.wicket.version=INFO
log4j.logger.org.apache.wicket.RequestCycle=INFO

$ cat src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
    <display-name>wicket-quickstart</display-name>
    <filter>
        <filter-name>wicket.quickstart</filter-name>
        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
        <init-param>
            <param-name>applicationClassName</param-name>
            <param-value>Application</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>wicket.quickstart</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

xml 必要なのマジでここだけ。素晴らしい。

$ cat src/main/java/Application.java

import org.apache.wicket.protocol.http.WebApplication;

public class Application extends WebApplication {
    public Application() {
    }

    @Override
    public Class getHomePage() {
        return HomePage.class;
    }
}

ここがアプリケーションの大本になり、xml地獄だったものがコードで設定出来るようになってます。DIコンテナの設定をしたり、セッションの実装を差し替えたりなどなど。

$ cat src/main/java/HomePage.java

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

public class HomePage extends WebPage {
    public HomePage() {
        add(new Label("message", "Hello World!"));
    }
}

$ cat src/main/java/HomePage.html

<html>
<body>
    <span wicket:id="message">Message goes here</span>
</body>
</html>

xmlレスなのも特徴的ですが テンプレートとなる HomePage.html がプレーンなHTMLというのもWicketにおける特徴的な部分ですね。テンプレートにロジックがいっさい入らない。他のフレームワークだと大なり小なりHTMLを弄るロジックが入るところですが。(例えばループの表現とか)

さてコードが用意出来たので改めて gradle jettyRun

$ gradle jettyRun

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:copyMarkup UP-TO-DATE
:jettyRun
SLF4J: Class path contains multiple SLF4J bindings.
(...略...)
********************************************************************
*** WARNING: Wicket is running in DEVELOPMENT mode.              ***
***                               ^^^^^^^^^^^                    ***
*** Do NOT deploy to your live server(s) without changing this.  ***
*** See Application#getConfigurationType() for more information. ***
********************************************************************
> Building > :jettyRun > Running at http://localhost:8081/wicket-gradle-sample

いけた感じがするのでアクセスしてみます。

$ wget http://localhost:8081/wicket-gradle-sample

$ cat wicket-gradle-sample

<html>
<body>
    <span wicket:id="message">Hello World!</span>
</body>
</html>

curlだとうまく取れなかったので wget & cat ブラウザで見ても当然OK。うまく動いてます。spanの中がLabelコンポーネントで設定したものに差し代わってますね。成し遂げたぜ。

もっと動的なの書いたり、Wicket のコンポーネントとはなんぞやーとか Guice とか ActiveObjects とか昔あったんだぜー みたいなことまでやれるのが本当は良かったんですがそれを書くには余白が狭すぎるということで、ここまでにしておきます。

まとめ

  • Gradle 導入は簡単そうなのと、設定じゃなくてコードで書けるってのが良いみたい
  • ただ Maven との互換はあんまり良い話を聞かないので導入するならMavenと絡めないほうが良いみたい
  • Wicket も Gradle でさくっといける 素晴らしい
  • WicketのテンプレートはHTMLがプレーン(ロジックがいっさい入らない)
  • 良いか悪いかは別として、自分はとても好きです
  • ネタが無いとこんな垂れ流し記事になる
  • Wicketの事書こうと思いついたのは当日
  • そして3時間ぐらいでぐわーって書いてる 良くないね 反省してこ!

次の人

明日は@nobu_ohtaです。

きっと自分のような垂れ流しじゃない素晴らしい記事が来る事は間違いないでしょう!お楽しみに!