Struts 2.0 and JPA Integration

SHARE & COMMENT :

Struts 2.0 is the popular Open Source Presentation Tier framework developed by Apache Group. It is based on MVC Model 2 design pattern. Dispatcher Filter is the front controller for the struts2 based applications. Struts 2.0 has simplified web development for its users by introducing POJO based actions, interceptors, flexible validation and support for many different result types.

also read:

Struts can be used to build the user interface tier of the enterprise application. Whereas, any of the popular ORMs like Hibernate, JPA, iBatis can be used for the persistence tier of the application. Struts2 provides easy integration with these persistence tier frameworks.

This article demonstrates the integration of Struts 2.0 applications with the Java Persistence API (JPA). The concept is explained with the help of a sample application. Knowledge of JPA and Struts 2.0 is the prerequisite for this article.

Development Environment

  • NetBeans IDE 6.8
  • GlassFish V2.x
  • Apache Derby Database

Project Structure

The sample application developed in this article is “StrutsJPADemo” where an employee details are persisted to the database with the help of JPA.

Libraries/Jar Files Required

  • Struts 2.0 jar files
  • JPA jar files
  • Jar file for the database driver (derbyclient.jar, in our case) The complete application structure is shown below:
  • The User Interface (JSP pages) is created in the “Web Pages” directory. The java classes (Actions, Entities, Service classes, Resource Bundles, struts.xml) are created in the “Source Packages” directory. The required jar files are present in the “Libraries” directory. The web application deployment descriptor “web.xml” is created by the IDE in the “WEB-INF” subdirectory of “Web Pages”. This sample application stores the employee details into the Derby database.

Environment Set Up

Once the web application is created and all the required libraries are added to the classpath, we can start working on the different components of the application.

Before we start working on the different application components like JSP pages and Java classes, we must first configure the following resources in the application server:

  1. javax.transaction.UserTransaction
  2. In our application, we have created a UserTransaction and bound the same in JNDI with the name “UserTransaction”. The snapshot given below shows the same.
  3. Connection Pool & DSN
  4. For the database, we have created a connection pool in the application server to connect to ScrambleDatabase in the local machine running at port number 1527. The connection pool is bound to the name “scramblePool” as shown in the snapshot below.
  5. The next step is to configure the DSN in the application server. Our DSN is bound to the name “jdbc/scramdleDSN” in JNDI. This is shown below in the snapshot. This DSN will use “scramblePool”created in the previous step.

Create Entity Class in JPA

The entity class for our application “Employee.java” is created in the package “com.model.entities”.PFB the code of
“Employee.java”

package com.model.entities;
	import java.util.Date;
	import javax.persistence.Entity;
	import javax.persistence.Id;
	import javax.persistence.Table;
	@Entity
	@Table
	public class Employee {
	    @Id
	    private String empid;
	    private String password;
	    private String password1;
	    private String empname;
	    private int age;
	    private String city;
	    private String email;
		//getters & setters for all the attributes
	}

Service Layer

The service layer exposes an interface “EmployeeService” and an implementation class “EmployeeServiceImpl” to the users. These classes are defined in the package “com.service”

EmployeeService.java

package com.service;
	import com.model.entities.Employee;
	import java.util.List;
	public interface EmployeeService {
	    public void save(Employee user);
	}

EmployeeServiceImpl.java

package com.service;
	import com.model.entities.Employee;
	import javax.annotation.Resource;
	import javax.naming.Context;
	import javax.naming.InitialContext;
	import javax.naming.NamingException;
	import javax.persistence.EntityManager;
	import javax.persistence.EntityManagerFactory;
	import javax.persistence.PersistenceContext;
	import javax.persistence.PersistenceContextType;
	import javax.transaction.NotSupportedException;
	import javax.transaction.SystemException;
	import javax.transaction.UserTransaction;
	@PersistenceContext(name = "persistence/myStrutsJPA", unitName = "StrutsJPAPersistenceUnit", type = PersistenceContextType.EXTENDED)
	@javax.ejb.TransactionManagement(javax.ejb.TransactionManagementType.BEAN)
	public class EmployeeServiceImpl implements EmployeeService {
	    private EntityManager em;
	    @Resource
	    private UserTransaction utx;
	    private EntityManagerFactory emf = null;
	    public UserTransaction getUtx() {
			return utx;
		}
		public void setUtx(UserTransaction utx) {
			this.utx = utx;
		}
		public EmployeeServiceImpl() {
			try {
				Context envCtx = (Context) new InitialContext().lookup("java:comp/env");
				em = (EntityManager) envCtx.lookup("persistence/myStrutsJPA");
				utx = (UserTransaction) envCtx.lookup("UserTransaction");
			} catch (NamingException ex) {
				System.out.println("PU Not found");
				ex.printStackTrace();
			}
		}
		public void setEntityManager(EntityManager em) {
			this.em = emf.createEntityManager();
			System.out.println(em);
		}
		public void save(Employee Employee) {
			try {
				System.out.println("Tx Status in save:=" + utx.getStatus());
				if (utx.getStatus() == 6) { // Incase there's no active Transaction, we'll start one
					Context envCtx = (Context) new InitialContext().lookup("java:comp/env");
					utx = (UserTransaction) envCtx.lookup("UserTransaction");
					utx.begin();
				}
				em.persist(Employee);
				utx.commit();
			} catch (NotSupportedException ex) {
				ex.printStackTrace();
			} catch (SystemException ex) {
				ex.printStackTrace();
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
		public void setEm(EntityManager em) {
			this.em = em;
		}
		public void setEmf(EntityManagerFactory emf) {
			this.emf = emf;
		}
		public EntityManager getEm() {
			return em;
		}
		public EntityManagerFactory getEmf() {
			return emf;
		}
		private EntityManager getEntityManager() {
			return em;
		}
	}

Action Class

Struts does the request processing with the help of Action classes. Here’s the code for the EmployeeAction.java which handles the request to create a new Employee. This class is created in the package
“com.actions”.

EmployeeAction.java

package com.actions;
	import com.model.entities.Employee;
	import com.opensymphony.xwork2.ActionSupport;
	import com.opensymphony.xwork2.ModelDriven;
	import com.opensymphony.xwork2.Preparable;
	import com.service.EmployeeServiceImpl;
	import javax.servlet.http.HttpServletRequest;
	import org.apache.struts2.interceptor.ServletRequestAware;

	public class EmployeeAction extends ActionSupport implements ModelDriven, Preparable, ServletRequestAware {
		private Employee emp;
		private HttpServletRequest req;
		private EmployeeServiceImpl empService;
		public EmployeeAction() {
			this.empService=new EmployeeServiceImpl();
		}
		public Employee getEmp() {
			return emp;
		}
		public void setEmp(Employee emp) {
			this.emp = emp;
		}
		public EmployeeServiceImpl getEmpService() {
			return empService;
		}
		public void setEmpService(EmployeeServiceImpl empService) {
			this.empService = empService;
		}
		public String execute() throws Exception {
			empService.save(emp);
			return SUCCESS;
		}
		public Object getModel() {
			return emp;
		}
		public void prepare() throws Exception {
			emp=new Employee();
		}
		public void setServletRequest(HttpServletRequest hsr) {
			this.req=hsr;
		}
	}

Please note that there’s no validation logic in the action class. We have put the validation logic in the
“EmployeeAction-validation.xml” file kept in the “com.actions” package. Please note that the validation.xml file should always be kept in the same package where your action class is present.

<?xml version="1.0" encoding="UTF-8"?>
	<!DOCTYPE validators PUBLIC
		"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
		"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
	<validators>
		<field name="empid">
			<field-validator type="requiredstring">
				<message>Employee Id is a mandatory field</message>
			</field-validator>
			<field-validator type="regex">
				<param name="expression">
					<![CDATA[([E][m][p][0-9][0-9][0-9])]]>
				</param>
				<message>Valid Employee Id required e.g. Emp001</message>
			</field-validator>
		</field>
		<field name="age">
			<field-validator type="int">
				<param name="min">20</param>
				<param name="max">80</param>
				<message>Age needs to between ${min} and ${max}</message>
			</field-validator>
		</field>
		<field name="empname">
			<field-validator type="requiredstring">
				<param name="trim">true</param>
				<message>User Name is required</message>
			</field-validator>
		</field>
		<field name="password">
			<field-validator type="requiredstring">
				<message>Password is required</message>
			</field-validator>
			<field-validator type="stringlength">
				<param name="maxLength">10</param>
				<param name="minLength">5</param>
				<param name="trim">true</param>
				<message>
					Enter password between 5 and 10 characters
				</message>
			</field-validator>
		</field>
		<field name="password1">
			<field-validator type="fieldexpression">
				<param name="expression">(password==password1)</param>
				<message>
					Password and Re-enter password must be same
				</message>
			</field-validator>
		</field>

		<field name="city">
			<field-validator type="requiredstring">
				<param name="trim">true</param>
				<message>You can not leave city as blank</message>
			</field-validator>
		</field>
		<field name="email">
		<field-validator type="requiredstring">
				<param name="trim">true</param>
				<message>You can not leave email as blank</message>
			</field-validator>
			<field-validator type="email">
				<message>
					The email address you entered is not valid.
				</message>
			</field-validator>
		</field>
	</validators>

Let us understand the request processing in the action class. The Action class has implemented the following interfaces:

  1. ServletRequestAware:This simplifies access to the HttpServletRequest object representing the request.
  2. ModelDriven:This enables the use of a POJO class to contain the data (similar to ActionForm of Struts1, with an exception that the class here is a POJO and doesn’t extend from any framework specific classes/interfaces). In our case, the entity class “Employee.java” created inside the “com.entities” package acts
    as the model.
  3. PreparableThis prepares the action class for use.

The data validation is performed with the help of “EmployeeAction-validation.xml” file. Different validation routines
are configured for the different entity attributes.

The User Interface Tier

The user interface part of the application is created in JSP. The home page of the application is “RegisterEmp.jsp”, where a form is displayed to the users asking for few details for the registration
purpose. PFB the code of “RegisterEmp.jsp”

<%@ taglib prefix="s" uri="/struts-tags"%>
	<html>
	<head>
		<title>Add Employee Details Using Field Validators</title>
    </head>
    <body>
		<h1>Struts2 and JPA Integration Demo</h1>
			Enter the Employee Details Here
		<s:form action="addEmployee">
			<s:textfield name="empid" key="app.empid" />
			<br>
			<s:textfield name="empname" key="app.empname" />
			<br>
			<s:password key="app.password" name="password" />
			<br>
			<s:password key="app.password1" name="password1" />
			<br>
			<s:textfield name="city" key="app.city" />
			<br>
			<s:textfield name="age" key="app.age" />
			<br>
			<s:textfield name="email" key="app.email" />
			<br>
			<br>
			<s:submit value="Add Employee" />
		  </s:form>
		<s:actionerror/>
	</body>
	</html>

Once the user fills in the required details and clicks on the “Submit” button, the request is submitted to the action class. Upon successful validation, a new employee record is inserted in the database and user is navigated to
“RegisterEmp_Success.jsp”page. Here’s the code of “RegisterEmp_Success.jsp”.

<%@ taglib prefix="s" uri="/struts-tags"%>
	<html>
	<head>
		<title>Employee Registration Success Page</title>
	</head>
	<body>
		<h1>Employee Details saved Successfully</h1>
		Employee Name:
		<s:property value="empname" />
		<br>
		<br>
		Password:
		<s:property value="password" />
		<br>
		<br>
		Employee Id:
		<s:property value="empid" />
		<br>
		<br>
		Age:
		<s:property value="age" />
		<br>
		<br>
		City:
		<s:property value="city" />
		<br>
		<br>
		E-Mail:
		<s:property value="email" />
		<br>
		<br>
	</body>
	</html>

Struts 2.0 and JPA Configuration Files

  • Here’s the configuration added in the “web.xml” file:
<?xml version="1.0" encoding="UTF-8"?>
	<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<persistence-context-ref>
		<persistence-context-ref-name>
			persistence/myStrutsJPA
		</persistence-context-ref-name>
		<persistence-unit-name>
			StrutsJPAPersistenceUnit
		</persistence-unit-name>
	</persistence-context-ref>
	<resource-env-ref>
		<resource-env-ref-name>UserTransaction</resource-env-ref-name>
		<resource-env-ref-type>javax.transaction.UserTransaction</resource-env-ref-type>
	</resource-env-ref>
	<resource-env-ref>
		<resource-env-ref-name>jdbc/scrambleDSN</resource-env-ref-name>
		<resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type>
	</resource-env-ref>
	<session-config>
		<session-timeout>
			30
		</session-timeout>
	</session-config>
	<welcome-file-list>
		<welcome-file>RegisterEmp.jsp</welcome-file>
	</welcome-file-list>
	</web-app>

In the deployment descriptor, we have added the following configurations:

  • The Welcome File of the application
  • Struts2 Dispatcher Filter (Controller element of Struts2 applications)
  • UserTransaction
  • PersistenceUnit
  • Here’s the configuration added in the “struts.xml” file kept in the default package in the “Source Packages” directory.
<!DOCTYPE struts PUBLIC
		"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
		"http://struts.apache.org/dtds/struts-2.0.dtd">
	<struts>
	    <package name="default" extends="struts-default">
		<action name="addEmployee" class="com.actions.EmployeeAction">
			<interceptor-ref name="exception"/>
			<interceptor-ref name="alias"/>
			<interceptor-ref name="servletConfig"/>
			<interceptor-ref name="prepare"/>
			<interceptor-ref name="i18n"/>
			<interceptor-ref name="chain"/>
			<interceptor-ref name="debugging"/>
			<interceptor-ref name="profiling"/>
			<interceptor-ref name="model-driven"/>
			<interceptor-ref name="params"/>
			<interceptor-ref name="conversionError"/>
			<interceptor-ref name="validation"/>
			<interceptor-ref name="workflow"/>
			<result name="success">RegEmp_Success.jsp</result>
			<result name="error">RegisterEmp.jsp</result>
			<result name="input">RegisterEmp.jsp</result>  </action>
		</package>
	</struts>
  • The labels of various UI components on the JSP page are not hard coded and instead being derived from the resource bundle “ApplicationResources.properties” kept in the “com.messages” package in the “Source Packages” directory.

Here’s the code of “ApplicationResources.properties”
file:

app.title=Struts2 JPA Integration Application
	app.welcome=Welcome to Struts2 Application
	app.username=User Name
	app.city=City
	app.age=Age
	app.email=E-Mail
	button.save=Save
	app.username.blank=Please enter User Name
	app.email.blank=Please enter City
	app.age.blank=Please enter Age
	app.city.blank=Please enter city
	app.empid=Employee Id
	app.password=Password
	app.password1=Reenter Password
	app.empname=Employee Name
	app.doj=Date of joining

We configure “ApplicationResources.properties” as the default resource bundle for our application by configuring an entry in the “struts.properties” file kept in the default package in the “Source Packages” directory.

  • Here’s the configuration to be added in the “struts.properties”
    file:
struts.custom.i18n.resources=com.messages.ApplicationResources

Executing The Application using Struts 2.0 and JPA

Finally, we are ready to execute the application. Deploy the application to the container and execute. Depending on the configuration in the Persistence Unit to create/update/drop-create the database, the database schema is generated/updated.
In our application, we have set the configuration to create the database from scratch.Before executing the application here’s the database schema:No table with the name “Employee” is present.

Open the Register.jsp page.

Enter some invalid data, The snapshot given below shows the validation error messages

Once, all the validation error messages have been rectified, the user is forwarded to RegisterEmp_Success.jsp page, where the correct data submitted is displayed.

Check the database structure, by refreshing the database schema. A new table “Employee” is created with one record in the database.

Conclusion

Thus, any Struts application can seamlessly integrate with JPA easily.

Comments

comments

About Krishna Srinivasan

He is Founder and Chief Editor of JavaBeat. He has more than 8+ years of experience on developing Web applications. He writes about Spring, DOJO, JSF, Hibernate and many other emerging technologies in this blog.

Comments

  1. I new to Struts and JPA. While running this program i receive an error.

    Exception while preparing the app : Could not resolve a persistence unit corresponding to the persistence-context-ref-name [persistence/myStrutsJPA] in the scope of the module called [EmployeeProfile]. Please verify your application.

    Could you please tell me how to solve this.

Speak Your Mind

*

Close
Please support the site
By clicking any of these buttons you help our site to get better