Web層(Struts部分)の作成(SpringとStrutsの連携)

Webデプロイメントディスクリプタファイル(WEB-INF/web.xml)を作成

次の内容でStruts2とSpring2の設定を記述する。
Struts2に関する設定
全てのリクエストに対してFilterDispatcherを定義する。また、設定ファイルstruts.xmlを書かないので、actionPackagesパラメータにアクションクラスのパッケージを設定をする必要がある。

	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>
			org.apache.struts2.dispatcher.FilterDispatcher
		</filter-class>
		<init-param>
			<param-name>actionPackages</param-name>
			<param-value>sample.test</param-value>
		</init-param>
	</filter>

	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

Spring2に関する設定
Spring では Web アプリケーション起動時に Bean 定義ファイルを読み込み ApplicationContext を生成する機能が提供されている。

	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/applicationContext.xml
		</param-value>
	</context-param>

StrutsとSpringを連携させるための設定

WEB-INF/classesに、次の内容でstruts.propertiesを作成する。

struts.objectFactory = spring
struts.objectFactory.spring.autoWire = type
struts.objectFactory.spring.autoWire = typeにするとアクションクラスのBean定義をSpringの設定ファイルに記述しなくても、型が一致していればオブジェクトを自動的にインジェクションしてくれる。

アクションクラスの作成

アクションが実行された時に呼ばれるクラス、アクションクラスを作成する。Struts 2でのアクションクラスはPOJO(Plain Old Java Objects、すなわち何も継承/実装しない普通のクラス)で実装する事ができる。また次の規約を守ることで設定ファイルstruts.xmlを記述する必要がなくなる。
  • アクションクラスの名前の末尾に「Action」をつける
  • アクションクラスを実行した後の遷移先をResultアノテーションで定義する
今回は従業員全情報を取得するEmployeeInfoActionクラスと遷移先画面のEmployeeInfoList.jspを作成した。 EmployeeInfoActionクラスの内容 EmployeeServiceクラスのオブジェクトをSpringでインジェクションさせるため、Setter、Getterメソッドを実装する。また従業員情報をemployeelistプロパティに設定することによって、Struts 2が提供するタグを利用してJSPで値を参照できるようになる。
package sample.test;

import org.apache.struts2.config.Result;

import sample.test.iface.EmployeeService;

import java.util.*;

@Result(name = "success", value = "EmployeeInfoList.jsp")
public class EmployeeInfoAction {
	private EmployeeService employeeService;
	private List<Employee> employeelist;

	public EmployeeService getEmployeeService() {
		return employeeService;
	}

	public void setEmployeeService(EmployeeService employeeService) {
		this.employeeService = employeeService;
	}

	public List<Employee> getEmployeelist() {
		return employeelist;
	}

	public void setEmployeelist(List<Employee> employeelist) {
		this.employeelist = employeelist;
	}

	public String execute() throws Exception {
		setEmployeelist(employeeService.findAll());
		return "success";
	}

}
EmployeeInfoList.jspの内容
<?xml version="1.0" encoding="windows-31j" ?>
<%@ page language="java" contentType="text/html; charset=windows-31j"
    pageEncoding="windows-31j"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-31j" />
<title>Emplyee List</title>
</head>
<body>
<p>従業員情報一覧</p>
<s:if test="employeelist.size > 0">
	<table>
		<s:iterator value="employeelist">
			<tr>
				<td>
					<s:property value="userId" />
				</td>
				<td>
					<s:property value="firstName" />
				</td>
				<td>
					<s:property value="lastName" />
				</td>
				<td>
					<s:property value="firstKananame" />
				</td>
				<td>
					<s:property value="lastKananame" />
				</td>
				<td>
					<s:property value="email" />
				</td>
				<td>
					<s:property value="phoneNumber" />
				</td>
				<td>
					<s:property value="birthDate" />
				</td>
			</tr>
		</s:iterator>
	</table>
</s:if>
</body>
</html>
準備ができたら http://localhost:8080/コンテキストルート/employeeInfo.actionのURLにアクセスして動作確認を行う。しかし、動作確認の際に次の二つのエラーが発生した これはTomcatのインストール先のlibディレクトリにJDBCドライバのJarファイルを置くことで解決した。(Tomcat5以前はcommon/lib配下に置く必要あり)
  • org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'txProxyTemplate' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'target' is required
これは下記のようにlazy-init="true"を追記することで解決した。
	<bean id="txProxyTemplate" lazy-init="true"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">