Struts2*SpringFrameworkの使い方(Spring plugin) 2017年6月Version

# Struts2とSpringFrameworkをつなぐ方法

Struts2は内部でDIコンテナを持っており、自らが使う設定ファイルから読み込み、指定したクラスのインスタンス化を行えます。DIコンテナの機能は他のDIコンテナに置き換えが可能で、Spring frameworkやJSR-330(Guice)も使えます。それぞれのコンテナごとにStruts2プラグインが用意されていますので、例えばSpring frameworkのDIを利用する場合は、Springプラグインを導入します。

Springプラグインを導入すると、以下の特徴が得られます。

1. ActionクラスとValidatorクラスがSpringの管理化に入ります
1. これらのクラスからSpringで管理しているBeanへアクセスできます
1. Spring frameworkが提供するさまざま機能、Springと他のフレームワークをつなぐ機能も使えます
    * 例えば、Spring+Mybatis でDBアクセス
    * 宣言的トランザクション管理
    * ViewからSpring管理beanへのアクセス
    * Spring標準のCache機構 を使ったキャッシュ利用
    * Spring+RabbitMQ で 非同期メッセージング
    * AOP(AspectJ)の導入

…と、その **ほとんどをSpring frameworkとSpringサブプロジェクトに置き換え可能** です。

残念ながらSpringBootの機能までは提供しませんが、Struts2標準のDIコンテナよりも強力な機能を持っていますので、使わない手はありません。対応するSpringのバージョンも、Struts2公式では4.2系までですが、実際のところ4.3系以降も今のところ利用可能です。

## 導入の仕方

導入の仕方は簡単で、プラグインの入手と、設定の追加をするだけです。

### プラグイン
Struts2のバージョンと全く同じStruts2-Spring-pluginを導入します。以下はmavenで指定する場合です。`<dependencies>`の子要素に追加します。

```xml:pom.xml
<dependency>
	<groupId>org.apache.struts</groupId>
	<artifactId>struts2-spring-plugin</artifactId>
	<version>${struts2.version}</version>
</dependency>
```

### 設定
設定ファイルの修正は2か所です。

1. Struts2の設定
2. web.xml

まずはStruts2の設定の1つである、struts.propertiesに次の行を追加します。場所は任意です。

```properties:struts.properties
struts.objectFactory=org.apache.struts2.spring.StrutsSpringObjectFactory
```

次にweb.xml(デプロイメント・ディスクリプタ)へSpringのコンテキストとリスナーを設定します。以下の設定は、クラスパス/spring/applicationContext.xmlおよび、applicationContext- から始まるxmlファイルをSpringの設定ファイルとして読み込む設定です。

```xml:web.xml
<web-app>
    <display-name>prototype_app</display-name>
    <context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath:spring/applicationContext.xml,classpath:spring/applicationContext-*.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
</web-app>
```

使うための設定は以上です。
この後、Spring管理に入れるBeanたちを登録するapplicationContext.xmlの設定をします。

## Actionクラスの実装例

Spring管理下にあるクラスはActionクラスにて`@Autowired`して利用できます。以下の例は、簡単な一覧検索のサンプルです。
※コードの一部に Lombok を利用しています。

```java:SampleAction.java
@Namespace("/")
@Results({@Result(name=ActionSupport.SUCCESS, location="list")})
@Log4j2
public class DisplayListAction extends ActionSupport {

    @Action("list")
    public String execute() throws Exception {
	products = service.search();
	log.info("- search:{}" , products);

        return SUCCESS;
    }

    @Autowired
    ProductService service;

    @Getter @Setter
    List<SampleProduct> products;
}
```

このActionクラスから利用するServiceクラス(ProductService)は次のような固定のリストを返します。

```java:ProductService.java
import java.util.Arrays;
import java.util.List;

import org.springframework.stereotype.Service;

@Service
public class ProductService {
	public List<SampleProduct> search() {
		List<SampleProduct> resultList =

		Arrays.asList(
			new SampleProduct().setProduct("A-1", "試作品X-290PA1", 10, true, true),
			new SampleProduct().setProduct("A-2", "試作品X-290PA2", 20, true, true),
			new SampleProduct().setProduct("B-3", "試作品X-B3", 10, true, true),
			new SampleProduct().setProduct("B-4", "試作品X-B4", 30, true, true),
			new SampleProduct().setProduct("C-5", "試作品X-C5", 10, true, false),
			new SampleProduct().setProduct("C-6", "試作品X-C6", 40, true, false),
			new SampleProduct().setProduct("D-7", "試作品X-D7", 10, false, true),
			new SampleProduct().setProduct("D-8", "試作品X-D8", 50, false, true),
			new SampleProduct().setProduct("E-9", "試作品X-E9", 10, true, true),
			new SampleProduct().setProduct("Z-1000", "試作品Z-1000", 0, false, false)
		);

		return resultList;
	}
}
```

ここで登場するSampleProductは単純なDataTransferObjectです。検索結果なのでValueObject化しても良いですね。

## Springのbean設定：applicationContext.xml

残念ながらJavaConfigは使えませんので、xmlファイルで定義します。component-scanは使えますので、beanを一気に登録できます。

```xml:applicationContext-service.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"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"
default-autowire="byName"
>	<!-- Spring管理になるServiceクラス定義 -->

	<context:component-scan base-package="seren.struts2.sampleapp.service" use-default-filters ="false" >
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
	</context:component-scan>
</beans>
```

component-scanの対象を、base-packageにある `@Service`アノテーションが付いているクラスを登録しています。

設定は以上になります。一度作っちゃえばカンタンですね v(・ω・|

## サンプルプロジェクトをgithubで公開しています

https://github.com/A-pZ/struts2-spring-sample

## おまけ

Struts2からThymeleaf3も使えます。Struts2のタグは一切使えませんが、Thymeleafの方がViewの記述がしやすいでしょう。Struts2からSpring frameworkなどに切り替える場合にはとても重宝するでしょう。

http://qiita.com/alpha_pz/items/5a43b4abb07141becbcd