Archive for September 8th, 2009

08
Sep
09

Integrating Core Spring with the Struts Framework

This page explains how to take the “core spring hello world application” and integrate it with struts framework.

Requirements

A typical Struts application is a collection of Action classes. The trick to integrating spring framework into one of these application is to convert the action classes to spring beans. Spring beans are managed by the spring container. The container is initialized via xml configuration file.

In the Example application listed at the above URL you were introduced with an account transfer process. The customer wanted some amount of money transferred between 2 accounts. For this we used the AccountTransferService. The service used 2 data mangers configured as spring beans. Once the datamangers were configured they were “injected” into the AccountTransferService. All of this was done thru XML configuration and none of the components of the system knew how to construct each other. This leads to a loosely coupled system since we can swap out the implementation of the datamangers for testing or development purposes.

In this page we will convert the Struts Actions into spring enabled beans. We will “inject” the objects that the action needs to do its job. In this case the AccountTransferService will be injected into the Action. The action will handle the request, delegate the processing of the request to the AccountTransferService, then forward to the success page.

ContextLoaderPlugin

This plugin loads a spring context file for the struts ActionServlet. This allows your struts actions to be managed by Spring. You can do this 2 ways.

  • Override Struts’ default RequestProcessor with Spring’s DelegatingRequestProcessor
  • Use the DelegatingActionProxy class in the type attribute of your action-mapping element.

In the first method the type attribute of the struts action element will be ignored. In the second method you can use the DelegatingActionProxy as the type in your action-mapping. This is the approach we will cover here.

DelegatingActionProxy

The job of this class is to delegate the handling of a request to an Action Bean that is “spring enabled”. Spring enabling a bean means that we have defined it in a spring configuration file and injected it with the dependencies it needs to do its job.

It will chose the spring-enabled bean based on the URI of the incoming request. If we are asking for accountTransfer.do it will look for a spring bean named “/accountTransfer” in the spring application context.

The bridge between the Action in struts-config.xml and the strutsConfiguration.xml is built with the action-mapping’s “path” and the bean’s “name”. If you have the following in your struts-config.xml


<action path="/users" .../>

You must define that Action’s bean with the “/users” name in the strutsConfiguration.xml file.


<bean name="/users" .../>

Before we can start making this we need to add a few things to the pom.xml file.

Insert the pom file modifications here.

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc-struts</artifactId>
	<version>2.5.5</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc-struts</artifactId>
	<version>2.5.5</version>
</dependency>

Modify the struts-config.xml and add the following towards the end of the file.

<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
 <set-property property="contextConfigLocation" value="/WEB-INF/spring-config.xml"/>
</plug-in>

We will create an Action called AccountTransferAction. We will have this action spring enabled by putting it into the spring configuration file.

Modify application.xml and add the following section.

<bean name="/accountTransfer" class="strutsexample.AccountTransferAction">
<property name="accountTransferService" ref="accountTransferService"/>
</bean>

Update the struts-config.xml file and replace the strutsexample.AccountTransferAction with org.springframework.web.struts.DelegatingActionProxy. As you can see in the above bean definition the “accountTransferService” is injected into the “Spring Enabled” struts action.

<action path="/AccountTransfer" forward="/pages/accountInput.jsp" />
<!--
 <action path="/AccountTransferSubmit"  type="strutsexample.AccountTransferAction">
 <forward name="success" path="/pages/accountTransferSuccess.jsp"></forward>
 </action>

 <action path="/AccountTransferSubmit"  type="org.springframework.web.struts.DelegatingActionProxy">
 <forward name="success" path="/pages/accountTransferSuccess.jsp"></forward>
 </action>
 -->

The code in comments represents 2 ways to define an action. The first one is how you would typically define a struts action. The second element represents a spring enabled struts action. Go ahead and copy the second element outside the comments and save the file.

The following is the

src/main/webapp/WEB-INF/spring-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
	"-//SPRING//DTD BEAN//EN"
	"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
	<bean name="/AccountTransferSubmit" class="strutsexample.AccountTransferAction">
		<property name="accountTransferService" ref="accountTransferService"/>
	</bean>
</beans>

The following is the

src/main/webapp/WEB-INF/applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
	"-//SPRING//DTD BEAN//EN"
	"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
	<bean name="accountDataManager" class="accountTransfer.AccountDataManagerImpl"/>
	<bean name="customerDataManager" class="accountTransfer.CustomerDataManagerImpl"/>
	<bean name="accountTransferService" class="accountTransfer.AccountTransferServiceImpl">
		<property name="accountDataManager" ref="accountDataManager"/>
		<property name="customerDataManager" ref="customerDataManager"/>
	</bean>
</beans>

Add the following Action class file to the project

package strutsexample;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import accountTransfer.AccountTransferServiceIF;

public class AccountTransferAction extends Action {
	private static final Log logger = LogFactory.getLog(AccountTransferAction.class);

	private AccountTransferServiceIF accountTransferService;

	public AccountTransferServiceIF getAccountTransferService() {
		return accountTransferService;
	}

	public void setAccountTransferService(
			AccountTransferServiceIF accountTransferService) {
		this.accountTransferService = accountTransferService;
	}

	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		logger.info("struts action ran with: " + accountTransferService);

		return mapping.findForward("success");
	}
}

Add the following JSP’s to the project.

src/main/webapp/pages/accountTransferSuccess.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
 <head>
 <title>XHTML 1.0 Strict Template</title>
 <meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />
 <meta http-equiv="Content-Language" content="en-us" />
 </head>
 <body>

Account Transfer Success!

</body>
</html>

src/main/webapp/pages/accountInput.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
	<title>XHTML 1.0 Strict Template</title>
	<meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />
	<meta http-equiv="Content-Language" content="en-us" />
</head>
<body>
	<form action="AccountTransferSubmit.do">
	<input type="text" value="test" />
	<input type="submit"/>
	</form>
</body>
</html>

That’s all! you just spring enabled your struts application!

package strutsexample;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import accountTransfer.AccountTransferServiceIF;

public class AccountTransferAction extends Action {
private static final Log logger = LogFactory.getLog(AccountTransferAction.class);

private AccountTransferServiceIF accountTransferService;

public AccountTransferServiceIF getAccountTransferService() {
return accountTransferService;
}

public void setAccountTransferService(
AccountTransferServiceIF accountTransferService) {
this.accountTransferService = accountTransferService;
}

@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {

logger.info(“struts action ran with: ” + accountTransferService);

return mapping.findForward(“success”);
}
}




Follow

Get every new post delivered to your Inbox.

Join 34 other followers