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 :
On Successful login :
On Failed Login:
Download the Source Code:
In this example, we studied how to use Spring IoC to inject beans into a Struts web-application.
You can download the source code of this example here: SpringStrutsIntegrationExample.zip