Spring Boot + Apache Wicket

## 概要

Springは2.x時代のxml地獄で「こんなところにいられるか、俺はGuiceに戻る!」と離れてしまい、その後もなかなか手を出しづらい気持ちがあったのだけれど、Spring Bootが[JJUG CCC 2014 fall](http://www.java-users.jp/?page_id=1284) でもかなり取り上げられていて、ずいぶん便利そうなので試してみたいなと思った。

業務では普段からApache Wicketを使っているので、Spring Boot + Wicketにしたいなあと思って検索してみたところ、GitHubでGradleプロジェクトのサンプルが公開されていた。これを参考にMavenプロジェクトを作成してみることにした。

といってもほぼ参考サイトから得たコード例そのままだけれども、実行例のひとつとして残しておく。

## Spring Bootプロジェクトの作成

Spring BootのMavenプロジェクトを作成するために、まずMavenでノーマルなプロジェクトを作成する。

```bash
$ mvn archetype:create -DgroupId=com.example -DartifactId=wicket-springboot-sample
```

作成したプロジェクトの中のpom.xmlを編集して、Spring-Bootのプロジェクトにする。ついでにWicketも仕込んでおく。以下、追加分を抜粋。

```xml:pom.xml
  <properties>
    <java.version>1.8</java.version>
    <tomcat.version>8.0.15</tomcat.version>
    <!-- 以下略 -->
  </properties>
```

```xml:pom.xml
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.1.9.RELEASE</version>
  </parent>
```

```xml:pom.xml
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.wicket</groupId>
      <artifactId>wicket-spring</artifactId>
      <version>6.18.0</version>
    </dependency>
    <!-- 以下略 -->
  <dependencies>
```

## 不要なファイルの削除

src/main/java のApp.java は不要になるので削除する。

## Wicketの準備

WicketApplicationクラスを作成する。WicketのQuickStartで作成させるWicketApplicaitonとほぼ同じだが、アノテーションや実行用のmainメソッドが必要。

`@Component`でWicketApplicaiton自体がSpringのComponentになって、`@EnableAutoConfiguration`でSpring Boot用の設定がなされて、`@ComponentScan`でサブパッケージも含めたクラスをDI対象にしてくれる。（このあたり、勉強し直さないと駄目だわ）

SpringComponentInjectorの使い方は、通常のWicket-Spring利用時とほぼ同じ。

```java:WicketApplication.java
package com.example;

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import org.apache.wicket.util.crypt.CharEncoding;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import com.example.page.FooPage;

@Component
@EnableAutoConfiguration
@ComponentScan
public class WicketApplication extends WebApplication {

  @Autowired
  private ApplicationContext applicationContext;

  @Override
  public Class<? extends WebPage> getHomePage() {
    return FooPage.class;
  }

  public static void main(String[] args) {
    SpringApplication.run(WicketApplication.class, args);
  }

  @Override
  public void init() {
    super.init();
    getRequestCycleSettings().setResponseRequestEncoding(CharEncoding.UTF_8);
    getMarkupSettings().setDefaultMarkupEncoding(CharEncoding.UTF_8);
    
    getComponentInstantiationListeners().add(new SpringComponentInjector(this, applicationContext));
    mountPage("/FooPage", FooPage.class);
  }

}
```

次に、Spring BootでWicketを起動してもらうためのServletContextInitializerの実装クラスを作成する。[Pentadrago](https://github.com/Pentadrago/spring-boot-example-wicket/blob/master/README.md)によれば、**web.xmlのfilter設定の代わり**をここで行っている。

なお `@Configuration`を忘れるとSpring Bootが設定用のクラスだと認識してくれず、WicketApplicationが起動できないので注意（見落としていてハマった）。

```java:WebInitializer.java
package com.example;

import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.apache.wicket.protocol.http.WicketFilter;
import org.apache.wicket.spring.SpringWebApplicationFactory;
import org.springframework.boot.context.embedded.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WebInitializer implements ServletContextInitializer {

  @Override
  public void onStartup(ServletContext context) throws ServletException {
    FilterRegistration filter = context.addFilter("wicket-filter", WicketFilter.class);
    filter.setInitParameter(WicketFilter.APP_FACT_PARAM, SpringWebApplicationFactory.class.getName());
    filter.setInitParameter("applicationBean", "wicketApplication");
    filter.setInitParameter(WicketFilter.FILTER_MAPPING_PARAM, "/*");
    filter.addMappingForUrlPatterns(null, false, "/*");
      filter.setInitParameter("configuration", "development");
  }

}
```

## WicketのPageクラスの作成

通常のWicket用のプロジェクトならPageクラス用のJavaファイルと同じディレクトリにHTMLも入れておくのだけれども、Spring Bootの場合は src/main/resource の中に同パッケージになるようにフォルダを掘って、そこにHTMLを作成する。

通常の配置に戻せる方法もあるのかもしれないけど、現時点ではちょっと分からなかった。

```java:FooPage.java
package com.example.page;

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.model.Model;
import org.apache.wicket.spring.injection.annot.SpringBean;

import com.example.service.IBarService;

public class FooPage extends WebPage {
	
  @SpringBean
  private IBarService barService;

  public FooPage() {
    this.add(new Label("label", Model.of(barService.createMessage())));
  }

}
```

```html:FooPage.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:wicket="http://wicket.apache.org">
<head>
<meta charset="UTF-8" />
</head>
<body>
  <p wicket:id="label"></p>
</body>
</html>
```

せっかくなのでDIもしておく。

```java:IBarService
package com.example.service;

public interface IBarService {

  public String createMessage();
	
}
```

```java:BarService
package com.example.service;

import org.springframework.stereotype.Service;

@Service
public class BarService implements IBarService {

  @Override
  public String createMessage() {
    return "Hello, Spring Boot + Wicket!";
  }

}
```



## 実行


```bash
$ mvn spring-boot:run
```

```
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.9.RELEASE)
（中略）
2014-11-27 22:51:21.477  INFO 18262 --- [ost-startStop-1] o.a.wicket.protocol.http.WebApplication  : [wicket-filter] Started Wicket version 6.18.0 in DEVELOPMENT mode
********************************************************************
*** WARNING: Wicket is running in DEVELOPMENT mode.              ***
***                               ^^^^^^^^^^^                    ***
*** Do NOT deploy to your live server(s) without changing this.  ***
*** See Application#getConfigurationType() for more information. ***
********************************************************************
```

http://localhost:8080/ にアクセスする。

![スクリーンショット 2014-11-27 23.23.57.png](https://qiita-image-store.s3.amazonaws.com/0/8064/f11570cc-f551-5641-0a63-b93fedd5ea71.png)

うごいたー。

なお、ここまでのコード+αは[gishi-yama/wicket-on-spring-boot/tree/0712034d61](https://github.com/gishi-yama/springboot-wicket-sample/tree/0712034d61)にpushしてある。


## 参考サイト
- [Pentadrago/spring-boot-example-wicket](https://github.com/Pentadrago/spring-boot-example-wicket)
- [Spring Boot](http://projects.spring.io/spring-boot/)
- [Spring Bootで高速アプリ開発](http://dev.classmethod.jp/server-side/java/springboot/)
- [Spring Bootで遊ぶ](http://qiita.com/don_hanabi/items/fe5223c64ecc44a0d944)
- [Spring Boot その5](http://www.riem.nagoya-u.ac.jp/~ohta/etc/springboot-5.html)