概要
Springは2.x時代のxml地獄で「こんなところにいられるか、俺はGuiceに戻る!」と離れてしまい、その後もなかなか手を出しづらい気持ちがあったのだけれど、Spring BootがJJUG CCC 2014 fall でもかなり取り上げられていて、ずいぶん便利そうなので試してみたいなと思った。
業務では普段からApache Wicketを使っているので、Spring Boot + Wicketにしたいなあと思って検索してみたところ、GitHubでGradleプロジェクトのサンプルが公開されていた。これを参考にMavenプロジェクトを作成してみることにした。
といってもほぼ参考サイトから得たコード例そのままだけれども、実行例のひとつとして残しておく。
Spring Bootプロジェクトの作成
Spring BootのMavenプロジェクトを作成するために、まずMavenでノーマルなプロジェクトを作成する。
$ mvn archetype:create -DgroupId=com.example -DartifactId=wicket-springboot-sample
作成したプロジェクトの中のpom.xmlを編集して、Spring-Bootのプロジェクトにする。ついでにWicketも仕込んでおく。以下、追加分を抜粋。
<properties>
<java.version>1.8</java.version>
<tomcat.version>8.0.15</tomcat.version>
<!-- 以下略 -->
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.9.RELEASE</version>
</parent>
<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利用時とほぼ同じ。
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によれば、web.xmlのfilter設定の代わりをここで行っている。
なお @Configuration
を忘れるとSpring Bootが設定用のクラスだと認識してくれず、WicketApplicationが起動できないので注意(見落としていてハマった)。
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を作成する。
通常の配置に戻せる方法もあるのかもしれないけど、現時点ではちょっと分からなかった。
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())));
}
}
<!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もしておく。
package com.example.service;
public interface IBarService {
public String createMessage();
}
package com.example.service;
import org.springframework.stereotype.Service;
@Service
public class BarService implements IBarService {
@Override
public String createMessage() {
return "Hello, Spring Boot + Wicket!";
}
}
実行
$ 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/ にアクセスする。
うごいたー。
なお、ここまでのコード+αはgishi-yama/wicket-on-spring-boot/tree/0712034d61にpushしてある。