spring

Spring struts integration example

We have studied about  configuring a web-application to use Spring MVC in the previous example.
In this example we will talk about how we integrate the Spring and Struts framework to get the best of both worlds.

Struts2 is a quite popular MVC framework. It has an XML file : struts.xml which is mainly responsible for all the configuration. This results in less code for compilation when making a change to the web-application.

It has custom JSP tags that make it easier to represent data on the view layer. In the same way, the values entered by the user can be pushed on the value-stack and can be available on the controller layer. This helps the developer to focus mainly on the domain and business logic.

Struts2 has built-in Framework for validation of the input which is robust and extensible.

Spring, on the other hand, has a very powerful and robust Inversion of Control feature. IoC helps in loosely coupled code,seperation of concern and easy testing of the web-application.

 
Here we will try to merge the two frameworks and see how it can be done to get the best out of the both. Let’s start with the web.xml

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>SpringMVCloginExample</display-name>
  
  <welcome-file-list>  
    <welcome-file>jsp/login.jsp</welcome-file>  
  </welcome-file-list>
  
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
		classpath://resource//springBeanConfiguration.xml
    </param-value>
</context-bparam>
  
<listener>
      <listener-class>
         org.springframework.web.context.ContextLoaderListener
      </listener-class>
   </listener>



   <filter>
      <filter-name>struts2</filter-name>
      <filter-class>
		org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
      </filter-class>
   </filter>

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

We configure the ContextLoaderListener to start the spring-bean factory, so that it can inject the bean where they are to be injected. The StrutsPrepareAndExecuteFilter filter intercepts each request and maps it to the struts.xml.

struts.xml

<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
	<constant name="struts.devMode" value="true" />
	<package name="helloworld" extends="struts-default">
		<action name="login" class="strutsController" method="execute">
			<result name="SUCCESS">/jsp/welcome.jsp</result>

			<result name="Failure">/jsp/login.jsp</result>
		</action>
	</package>
</struts>

The struts.xml redirects the requests it receives to the appropriate Action class files. The struts.xml invokes the proper method and returns the view as per the string returned by the action class. In the struts.xml instead of passing the fully qualified name of the class we are passing the name of the bean we have registered with the spring-bean factory. The spring bean factory is defined using the springBeanConfiguration.xml file.

springBeanConfiguration.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
   http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<bean id="strutsController" class="com.jcg.examples.controller.StrutsController">
		<property name="loginDelegate" ref="loginDelegate"></property>
		<property name="loginBean" ref="loginBean"></property>
	</bean>

	<bean id="loginDelegate" class="com.jcg.examples.delegate.LoginDelegate">
		<property name="userService" ref="userService"></property>
	</bean>

	<bean id="loginBean" class="com.jcg.examples.viewBean.LoginBean"></bean>

	<bean id="userService" class="com.jcg.examples.service.impl.UserServiceImpl">
		<property name="userDao" ref="userDao"></property>
	</bean>

	<bean name="userDao" class="com.jcg.examples.dao.impl.UserDaoImpl">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/jcg" />
		<property name="username" value="root" />
		<property name="password" value="toor" />
	</bean>

</beans>

The Spring-bean factory instantiates and injects the action class and other classes like the bean classes and the delegates into the struts.xml for serving the request.

We have created a sample Login JSP, wherein the user enters the username and password to login into the web-application.

Here’s the login.jsp

<%@include file="include.jsp"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
		<title>Login</title>
	</head>
	<body>
		<font color="red">${message}</font>
		<s:form action="login">
      <s:textfield name="username" label="Enter User Name"/><br/>
      <s:password name="password" label="Enter Password"/><br/>
      <s:submit></s:submit>
   </s:form>
	</body>
</html>

In the include.jsp we can import the common files like the tag libraries, javascript libraries etc.

include.jsp

<%@ taglib prefix="s" uri="/struts-tags"%>

When the user submits the form using the submit button, the request reaches the StrutsController via the struts.xml and the execute method is invoked.

StrutsController.java

package com.jcg.examples.controller;


import java.sql.SQLException;

import org.apache.struts2.ServletActionContext;

import com.jcg.examples.delegate.LoginDelegate;
import com.jcg.examples.viewBean.LoginBean;
import com.opensymphony.xwork2.ModelDriven;


public class StrutsController implements ModelDriven<LoginBean>
{

		private LoginDelegate loginDelegate;

		public LoginBean loginBean;

		public LoginBean getLoginBean()
		{
				return this.loginBean;
		}

		public void setLoginBean(LoginBean loginBean)
		{
				this.loginBean = loginBean;
		}

		public String execute() throws SQLException
		{
				String target = "";
				boolean isValidUser = loginDelegate.isValidUser(loginBean.getUsername(), loginBean.getPassword());
				if (isValidUser)
				{
						System.out.println("User Login Successful");
						ServletActionContext.getRequest().setAttribute("loggedInUser", loginBean.getUsername());
						target = "SUCCESS";
				}
				else
				{
						ServletActionContext.getRequest().setAttribute("message", "Invalid credentials!!");
						target = "Failure";
				}
				return target;
		}

		public LoginDelegate getLoginDelegate()
		{
				return this.loginDelegate;
		}

		public void setLoginDelegate(LoginDelegate loginDelegate)
		{
				this.loginDelegate = loginDelegate;
		}

		@Override
		public LoginBean getModel()
		{
				return loginBean;
		}
}

We have implemented the ModelDriven interface so that the values entered by the user are directly made available into the Java Object. This frees up the developer’s time to concentrate on the business logic rather than the minor request tit-bits. The LoginBean is injected into the Action class from the Spring-Bean factory and is populated with the values entered by the user.

LoginBean.java

package com.jcg.examples.viewBean;

public class LoginBean
{
		private String username;

		private String password;

		public String getPassword()
		{
				return this.password;
		}

		public String getUsername()
		{
				return this.username;
		}

		public void setUsername(String username)
		{
				this.username = username;
		}

		public void setPassword(String password)
		{
				this.password = password;
		}

		@Override
    public String toString()
    {
		    return "LoginBean [username=" + this.username + ", password=" + this.password + "]";
    }


}

We extract the username and password from the loginbean and forward it to the LoginDelegate which does the task of authenticating the user. The LoginDelegate is itself injected into the action class via the Spring-Bean Factory.

Here’s the LoginDelegate.java

package com.jcg.examples.delegate;

import java.sql.SQLException;

import com.jcg.examples.service.UserService;

public class LoginDelegate
{
		private UserService userService;

		public UserService getUserService()
		{
				return this.userService;
		}

		public void setUserService(UserService userService)
		{
				this.userService = userService;
		}

		public boolean isValidUser(String username, String password) throws SQLException
    {
		    return userService.isValidUser(username, password);
    }
}

The LoginDelegates delegates to the UserService the task to manage the authentication of the user. The UserService interface is implemented by the UserServiceImpl.

UserService.java

/**
 *
 */
package com.jcg.examples.service;

import java.sql.SQLException;

/**
 * @author CENTAUR
 *
 */
public interface UserService
{
		public boolean isValidUser(String username, String password) throws SQLException;
}


UserServiceImpl.java

package com.jcg.examples.service.impl;

import java.sql.SQLException;

import com.jcg.examples.dao.UserDao;
import com.jcg.examples.service.UserService;

public class UserServiceImpl implements UserService
{

		private UserDao userDao;

		public UserDao getUserDao()
		{
				return this.userDao;
		}

		public void setUserDao(UserDao userDao)
		{
				this.userDao = userDao;
		}

		@Override
		public boolean isValidUser(String username, String password) throws SQLException
		{
				return userDao.isValidUser(username, password);
		}

}

The UserServiceImpl communicates with the UserDao to connect with the Database to determine if the user is present in the database and the password is correct.

UserDao.java

package com.jcg.examples.dao;

import java.sql.SQLException;

/**
 * @author CENTAUR
 * This interface will be used to communicate with the
 * Database
 */
public interface UserDao
{
		public boolean isValidUser(String username, String password) throws SQLException;
}

UserDaoImpl.java

package com.jcg.examples.dao.impl;


import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.jcg.examples.dao.UserDao;


/**
 * @author CENTAUR
 */
public class UserDaoImpl implements UserDao
{

		DataSource dataSource;

		public DataSource getDataSource()
		{
				return this.dataSource;
		}

		public void setDataSource(DataSource dataSource)
		{
				this.dataSource = dataSource;
		}

		@Override
		public boolean isValidUser(String username, String password) throws SQLException
		{
				String query = "Select count(1) from user where username = ? and password = ?";
				PreparedStatement pstmt = dataSource.getConnection().prepareStatement(query);
				pstmt.setString(1, username);
				pstmt.setString(2, password);
				ResultSet resultSet = pstmt.executeQuery();
				if (resultSet.next())
						return (resultSet.getInt(1) > 0);
				else
						return false;
		}

}

Based on the output returned by the UserDaoImpl the user is redirected to the appropriate view.

If the login is successful the user is shown the welcome.jsp :

welcome.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Welcome</title>
</head>
<body>
	<center>Welcome ${loggedInUser}</center>
</body>
</html>

If the login fails, the user is shown the same login.jsp with the Invalid Credentials message.

Here’s the output:

LoginView :

Figure 1. Login View
Figure 1. Login View

On Successful login :

Figure 2. Success View
Figure 2. Success View

On Failed Login:

Figure 3. Login Failure
Figure 3. Login Failure

Download the Source Code:

In this example, we studied how to use Spring IoC to inject beans into a Struts web-application.

Download
You can download the source code of this example here: SpringStrutsIntegrationExample.zip

Chandan Singh

Chandan holds a degree in Computer Engineering and is a passionate software programmer. He has good experience in Java/J2EE Web-Application development for Banking and E-Commerce Domains.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button