In earlier tutorials, we’ve developed different types of Portlet. Portlets are developed using of JSP & Servlet at once and then we learned using of JSF with Portlets. This time we’re going to develop a Portlet using another famous framework like Apache Struts.
Srtuts framework is an MVC-based one, we’ve already covered a lot of topics onto Apache Struts as you can refer for all of them, but this is the first time you will get a Struts application deployed into a Portlet container like Apache Pluto.
You’re likely going to use Apache Struts Bridge that is already maintained by Apache itself. However, the same application that you’ve implemented before (Employee Registration Form) will be used in this tutorial but with Struts2 framework.
The main goal of this application is to help you know all the details required for getting the application deployed and running properly onto any JSR-168/JSR-286 compliant Portlet container.
Final Project Structure
Employee Table Design
This section would clarify you what the Employee Table is and what are these columns used.
Employee.sql
1 2 3 4 5 6 7 8 9 |
CREATE TABLE `employee` ( `EMP_ID` int(11) NOT NULL AUTO_INCREMENT, `EMP_NAME` varchar(45) DEFAULT NULL, `EMP_JOB` varchar(45) DEFAULT NULL, `EMP_SALARY` int(11) DEFAULT NULL, PRIMARY KEY (`EMP_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; |
Let’s see the Employee
entity (Model) that would be used for holding the data that are going back and forth between the application and the database store.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package com.journaldev.data; public class Employee { private String id; private String name; private String job; private String salary; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getSalary() { return salary; } public void setSalary(String salary) { this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } } |
Create Template Application Using Eclipse IDE
You may save your time instead of getting delve into creating the project by yourself, by using an Apache Struts Archetype. Following steps will help you creating a Struts Portlet application easily.
- Add Remote Archetype Catalog https://struts.apache.org/ into your Maven Archetypes.
- Create a new Maven project. This time you will get stopped into Catalog selection, instead of using All Catalogs, you must select that’s one registered.
- Fill in the all required information, GroupId, ArtifactId, version, and Package.
- Click Finish and waiting your Eclipse displaying created application into your Project Explorer.
- Though the application is created successfully, but it’s likely want some of in-hand adjustment as the Archetype’s Maven dependencies isn’t updated somehow. That’s why you may notice some errors in the created application.
- Delete all undesired Java files under com.journaldev package.
- Delete all undesired JSP files/folders under WEB-INF/jsp.
Modify Maven Dependencies
The Maven dependency file has got modified to serve two wanted features:
- Add required dependencies for Struts2 and its relevant Portlet container Bridge.
- Add all required Apache Pluto accompanies that would lead us for a healthy deployment onto Apache Pluto itself.
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.journaldev</groupId> <artifactId>EmployeeRegistration-StrutsBridge</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>EmployeeRegistration-StrutsBridge</name> <properties> <struts2.version>2.3.16.3</struts2.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <deployFolder>D:/Apache Pluto/pluto-2.0.3/webapps</deployFolder> </properties> <dependencies> <!-- Java Portlet Specification V2.0 --> <dependency> <groupId>org.apache.portals</groupId> <artifactId>portlet-api_2.0_spec</artifactId> <version>1.0</version> <scope>provided</scope> </dependency> <!-- Apache Struts & Core --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>${struts2.version}</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-config-browser-plugin</artifactId> <version>${struts2.version}</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-portlet-plugin</artifactId> <version>2.3.16.3</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-junit-plugin</artifactId> <version>${struts2.version}</version> <scope>test</scope> </dependency> <!-- Commons logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </dependency> <!-- Log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.5</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <!-- Apache Struts Portlet Bridge --> <dependency> <groupId>org.apache.portals.bridges</groupId> <artifactId>portals-bridges-struts-1.2.7</artifactId> <version>1.0.4</version> </dependency> <!-- MySQL driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.32</version> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <!-- bind 'pluto2:assemble' goal to 'process-resources' lifecycle --> <!-- This plugin will read your portlet.xml and web.xml and injects required lines --> <plugin> <groupId>org.apache.portals.pluto</groupId> <artifactId>maven-pluto-plugin</artifactId> <version>2.1.0-M3</version> <executions> <execution> <phase>generate-resources</phase> <goals> <goal>assemble</goal> </goals> </execution> </executions> </plugin> <!-- configure maven-war-plugin to use updated web.xml --> <!-- This plugin will make sure your WAR will contain the updated web.xml --> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.1.1</version> <configuration> <webXml>${project.build.directory}/pluto-resources/web.xml</webXml> </configuration> </plugin> <plugin> <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> <id>copy</id> <phase>integration-test</phase> <configuration> <tasks> <copy file="target/${project.artifactId}.war" tofile="${deployFolder}/${project.artifactId}.war" /> </tasks> </configuration> <goals> <goal>run</goal> </goals> </execution> <execution> <id>delete</id> <phase>clean</phase> <configuration> <tasks> <delete file="${deployFolder}/${project.artifactId}.war" /> <delete dir="${deployFolder}/${project.artifactId}" /> </tasks> <detail>true</detail> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> </project> |
Employee Registration Views
As you may know, Apache Struts has considered JSP as a view technology, so we would add a three distinct files, register.jsp
, success.jsp
and failure.jsp
.
According for Apache Struts Archetype, the files would be added under WEB-INF/jsp/employee folder.
register.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Register Employee</title> </head> <body> <s:form action="register"> <s:textfield name="id" label="Identifier"></s:textfield> <s:textfield name="name" label="Name"></s:textfield> <s:textfield name="job" label="Job"></s:textfield> <s:textfield name="salary" label="Salary"></s:textfield> <s:submit value="Register"></s:submit> </s:form> </body> </html> |
failure.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Failure</title> </head> <body> <span style="color:red">Unfortunately! The Employee hasn't been registered successfully</span> </br> <a href="https://www.journaldev.com/5035/<s:url action="index" portletMode="view"/>">Try Again!</a> </body> </html> |
success.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Success</title> </head> <body> <span style="color:green">Congratulations! The Employee has been registered successfully</span> <br/> <a href="https://www.journaldev.com/5035/<s:url action="index" portletMode="view"/>">Register Another</a> </body> </html> |
As you’ve noticed, we used a Struts Tag library for providing a form component and its relevant parameters. If you’re not so good with a Struts, it’s so good for you return here to read some articles about it as it’s very elegant framework.
Struts Tag library has provided a <url/> Tag for creating a Struts-based link. Struts-based link is a link that uses the Struts framework vocabulary like action.
One important thing you should notice that and it’s the action attribute for the form that’s referred for action it’s name is register. That name would be provided by the struts.xml
file that would be discussed later on.
Register Action
It’s may be known for you that a Struts is an action-based framework. In that, every form submission should be delegated into action based class that’s implemented to be extended from DefaultActionSupport
class. Following RegisterAction
Struts action class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
package com.journaldev.action; import java.io.IOException; import java.sql.SQLException; import javax.portlet.PortletPreferences; import org.apache.log4j.Logger; import org.apache.struts2.dispatcher.DefaultActionSupport; import org.apache.struts2.portlet.interceptor.PortletPreferencesAware; import com.journaldev.dao.EmployeeDAO; import com.journaldev.data.Employee; public class RegisterAction extends DefaultActionSupport implements PortletPreferencesAware { private static Logger logger = Logger.getLogger(RegisterAction.class); private static final long serialVersionUID = 1L; private PortletPreferences preferences; private String id; private String name; private String job; private String salary; public PortletPreferences getPreferences() { return preferences; } public void setPreferences(PortletPreferences preferences) { this.preferences = preferences; } @Override public void setPortletPreferences(PortletPreferences prefs) { this.preferences = prefs; } @Override public String execute() throws Exception { try { Employee employee = new Employee(); employee.setId(id); employee.setName(name); employee.setJob(job); employee.setSalary(salary); // Register Employee employee = EmployeeDAO.getInstance().createEmployee(employee); logger.debug("Employee Has Registered"); return "SUCCESS"; } catch (IllegalAccessException | ClassNotFoundException | SQLException | IOException e) { logger.debug("Registration Process Has Failed",e); return "FAILURE"; } } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public String getSalary() { return salary; } public void setSalary(String salary) { this.salary = salary; } } |
Here’s detailed explanation for the RegisterAction
class figured out:
- Notice the class’s properties id, name, job and salary are analogous for these parameters’ names that are provided by the
register.jsp
page. RegisterAction
has overridden anexecute
method for serving the employee registration purposes.- Struts framework will binded all form’s parameters with those corresponding ones at the action class. Id, name, job and salary will be passed automatically.
- RegisterAction has used the EmployeeDAO (The same utility class that we’ve impelemnted previously, that it would handle the all database manipulation code) for registering the employee instance.
- In case the registration process has failed the Struts framework would take you into failure page. The page success.jsp is that one, the Struts framework will redirect you into as soon as the registration has finished successfully.
Struts Application Configuration & Portlet.xml
Struts.xml file is an XML-based file that used by the Apache Struts framework for getting connected the different components that you’re developed.
Wiring of mentioned actions within your <s:form/> with the Struts-action must be defined as an entries within struts.xml
file. Following Struts configuration file required:
struts.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "https://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="default" extends="struts-portlet-default" namespace="/employee"> <action name="index"> <result>/WEB-INF/jsp/employee/register.jsp</result> </action> </package> <package name="employee" namespace="/employee" extends="struts-portlet-default"> <action name="register" class="com.journaldev.action.RegisterAction"> <result name="SUCCESS">/WEB-INF/jsp/employee/success.jsp</result> <result name="FAILURE">/WEB-INF/jsp/employee/failure.jsp</result> </action> </package> </struts> |
Integration of Apache Struts with the given Portlet container has been done through using of portlet.xml file. In that, a new init-param should be used for this purpose. Following the Portlet.xml file that’s used.
portlet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<?xml version="1.0" encoding="UTF-8"?> <portlet-app xmlns="https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"> <portlet> <description>Register Employee</description> <portlet-name>RegisterEmployee</portlet-name> <portlet-class>org.apache.struts2.portlet.dispatcher.Jsr286Dispatcher</portlet-class> <init-param> <name>actionPackages</name> <value>com.journaldev.action</value> </init-param> <!-- The namespace for the actions configured for view mode --> <init-param> <name>viewNamespace</name> <value>/employee</value> </init-param> <!-- The default action to invoke in view mode. --> <init-param> <name>defaultViewAction</name> <value>index</value> </init-param> <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> </supports> <supported-locale>en</supported-locale> <portlet-info> <title>Register Employee</title> <short-title>Register Employee</short-title> <keywords>Employee,Registration</keywords> </portlet-info> </portlet> </portlet-app> |
Here’s detailed explanation for both of the Struts and Portlet configuration files listed above:
- Your Portlets must be an instance of
JSR286Dispatcher
class. - We’ve defined three additional parameters, actionPackages, viewNamespace and defaultViewAction.
- Defined
defaultViewAction
will be used once you’ve opened the Portal page that’s contained the deployed Portlet. As being index is the value, the index should be defined as an action in the struts.xml file. - Defined
actionPackages
will be used for determining the Java package that contains the Struts-actions classes. - Defined
viewNamespace
will determine the namespace for the actions configured forview mode
. It’s also applicable to define actions foredit
andhelp
modes. - Struts configuration file has defined an
register
action that would be used as soon as the user has submitted the form’s register. - Defined
register
action has had two different results, success and failure are used to determine the next view that Struts framework uses after finishing the calling of execute against action class.
Deployment Descriptor
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "https://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>RegisterEmployee</display-name> <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> |
EmployeeDAO & ConnectionUtility
Following below both of EmployeeDAO and ConnectionUtility that help you getting database connection and creating the user after then.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
package com.journaldev.dao; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import com.journaldev.dao.utility.ConnectionUtility; import com.journaldev.data.Employee; public class EmployeeDAO { public static EmployeeDAO employeeDAO = null; private EmployeeDAO(){ } public static EmployeeDAO getInstance(){ synchronized(EmployeeDAO.class){ if(employeeDAO == null){ employeeDAO = new EmployeeDAO(); } } return employeeDAO; } public Employee createEmployee(Employee employee) throws SQLException, IllegalAccessException, IOException, ClassNotFoundException{ // Get connection instance Connection connection = ConnectionUtility.getInstance().getConnection(); // Create Prepared Statement PreparedStatement query = connection.prepareStatement("INSERT INTO EMPLOYEE VALUES (?,?,?,?)"); // Set variables query.setInt(1, Integer.parseInt(employee.getId())); query.setString(2, employee.getName()); query.setString(3, employee.getJob()); query.setInt(4, Integer.parseInt(employee.getSalary())); try { // Execute query.execute(); // Return employee instance return employee; } catch(Exception e){ // Close statement query.close(); // Close connection connection.close(); // Throw another exception for notifying the Servlet throw new SQLException(e); } } public boolean deleteEmployee(Employee employee){ return false; } public boolean updateEmployee(Employee employee, int employeeId){ return false; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package com.journaldev.dao.utility; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; public class ConnectionUtility { private static ConnectionUtility connectionUtiliy = null; private Connection connection = null; private ConnectionUtility() { } public static ConnectionUtility getInstance() throws IOException, IllegalAccessException, SQLException, ClassNotFoundException{ // Synchronized against connectionUtility instance synchronized(ConnectionUtility.class){ // Check whether the connectionUtility is null or not if(connectionUtiliy == null){ // Create a properties instance Properties properties = new Properties(); // Load properties from classpath properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("connection.properties")); // Set connection with connectionUtility connectionUtiliy = new ConnectionUtility(); // Load driver class Class.forName("com.mysql.jdbc.Driver"); // Create connection connectionUtiliy.setConnection(DriverManager.getConnection("jdbc:mysql://localhost:3306/journaldev", properties)); } return connectionUtiliy; } } public Connection getConnection() throws ClassNotFoundException, SQLException, IOException { if(connection.isClosed()){ // Create a properties instance Properties properties = new Properties(); // Load properties from classpath properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("connection.properties")); // Load driver class Class.forName("com.mysql.jdbc.Driver"); // Create connection connectionUtiliy.setConnection(DriverManager.getConnection("jdbc:mysql://localhost:3306/journaldev", properties)); } return connection; } public void setConnection(Connection connection) { this.connection = connection; } } |
Registration Employee Demo
To get started showing your Portlet, you must logged into your Apache Pluto and navigating into JournalDev page. Typically, we have added a Portal page that’s contained for our developed Portlet. The process of creating a Portal page and add the Portlets upon it is discussed at Apache Pluto Introduction Tutorial.
Summary
Apache Struts is an elegant framework that’s used for creating an MVC-based enterprise application. Apache has also provided you a ready made Portlet bridge that could be used for creating JSR-168/286 Struts-based Portlet. Contribute us by commenting below and find the downloaded source code.