My Experiments with Technology

Before I forget, I better get it written and get it published!

Building Java Web Application Using Struts 2

Nov 21 st , 2013 | Comments

This post will show how to create a Student Enrollment Application using MYSQL DB with Struts 2 framework. This is a simple application that aims to collect the input details from the user during signup, save the details in the MYSQL DB and authenticate the same during login.

1. Create Java Web Application Project

To begin with, in the IDE, create a Java Dynamic Web project for the application. While creating the dynamic web project, enable the checkbox to generate web.xml deployment descriptor.

The sample web application directory structure is shown below with a standard deployment descriptor web.xml

Struts Dynamic Web Project Layout

2. Modify web.xml

Modify the contents of the web.xml to include the following:

Struts Library Layout

7. Create db.properties file

Create a file named db.properties under the src folder, where the properties of the MYSQL DB like url, username and password can be specified. Replace with the actual connection url for connecting to the MYSQL DB. Likewise, replace and with the actual username and password values.

1 2 3 4 
dbDriver=com.mysql.jdbc.Driver connectionUrl=jdbc:mysql://:3306/studentEnrollment userName= password= 

8. Create utility class

Create a POJO class named DbUtil.java under the package com.github.elizabetht.util to include a helper class functionality that would load the db.properties file and get the database connection.

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 
public class DbUtil  private static Connection dbConnection = null; public static Connection getConnection()  if (dbConnection != null)  return dbConnection; > else  try  InputStream inputStream = DbUtil.class.getClassLoader() .getResourceAsStream("db.properties"); Properties properties = new Properties(); if (properties != null)  properties.load(inputStream); String dbDriver = properties.getProperty("dbDriver"); String connectionUrl = properties .getProperty("connectionUrl"); String userName = properties.getProperty("userName"); String password = properties.getProperty("password"); Class.forName(dbDriver).newInstance(); dbConnection = DriverManager.getConnection(connectionUrl, userName, password); > > catch (Exception e)  e.printStackTrace(); > return dbConnection; > > >

9. Create class for Repository tier

Create a Repository tier POJO class named StudentRepository.java under the package com.github.elizabetht.repository to support the database operations of saving the student details, verifying the student login details and checking if the username exists when a save is attempted.

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 
public class StudentRepository  private Connection dbConnection; public StudentRepository()  dbConnection = DbUtil.getConnection(); > public void save(String userName, String password, String firstName, String lastName, String dateOfBirth, String emailAddress)  if (dbConnection != null)  try  PreparedStatement prepStatement = dbConnection .prepareStatement("insert into student(userName, password, firstName, lastName, dateOfBirth, emailAddress) values (?, ?, ?, ?, ?, ?)"); prepStatement.setString(1, userName); prepStatement.setString(2, password); prepStatement.setString(3, firstName); prepStatement.setString(4, lastName); prepStatement.setDate(5, new java.sql.Date(new SimpleDateFormat("MM/dd/yyyy") .parse(dateOfBirth.substring(0, 10)).getTime())); prepStatement.setString(6, emailAddress); prepStatement.executeUpdate(); > catch (SQLException e)  e.printStackTrace(); > catch (ParseException e)  e.printStackTrace(); > > > public boolean findByUserName(String userName)  if (dbConnection != null)  try  PreparedStatement prepStatement = dbConnection .prepareStatement("select count(*) from student where userName = ?"); prepStatement.setString(1, userName); ResultSet result = prepStatement.executeQuery(); if (result != null)  while (result.next())  if (result.getInt(1) == 1)  return true; > > > > catch (Exception e)  e.printStackTrace(); > > return false; > public boolean findByLogin(String userName, String password)  if (dbConnection != null)  try  PreparedStatement prepStatement = dbConnection .prepareStatement("select password from student where userName = ?"); prepStatement.setString(1, userName); ResultSet result = prepStatement.executeQuery(); if (result != null)  while (result.next())  if (result.getString(1).equals(password))  return true; > > > > catch (Exception e)  e.printStackTrace(); > > return false; > >

10. Create class for Service Tier

Create a Controller tier POJO class named StudentService.java inside the package com.github.elizabetht.service. This layer acts as a median between the Controller and Repository tier classes.

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 
public class StudentService  private StudentRepository studentRepository; public StudentService()  studentRepository = new StudentRepository(); > public String save(String userName, String password, String firstName, String lastName, String dateOfBirth, String emailAddress)  if (studentRepository != null)  if (studentRepository.findByUserName(userName))  return "SignupFailure-UserNameExists"; > studentRepository.save(userName, password, firstName, lastName, dateOfBirth, emailAddress); return "SignupSuccess"; > else  return "SignupFailure"; > > public String findByLogin(String userName, String password)  String result = "LoginFailure"; if (studentRepository != null)  boolean status = studentRepository.findByLogin(userName, password); if (status)  result = "LoginSuccess"; > > return result; > >

11. Create Action classes for Controller tier

Create a Controller tier POJO class named StudentController.java inside the package com.github.elizabetht.controller. This is where the routing logic of the application goes – whether a signup or login action is called. For simplicity sake, two separate action classes are created for each of the operation.

Each of the Action class has to implement the execute() method. Based on the String result returned from the execute() method of the action class, the appropriate view page is rendered.

In most cases, the action class is extended from the general ActionSupport class, which has a lot of easy to use convenient features. So, extend the ActionSupport class in the Action class, unless you have a reason not to!

The following snippet shows the SignupAction 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 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 
@SuppressWarnings("serial") public class SignupAction extends ActionSupport  private String pageName; private String userName; private String password; private String firstName; private String lastName; private String dateOfBirth; private String emailAddress; @Action("signup-input") public String input() throws Exception  return "signup"; > @Override @Action(value = "signup", results = < @Result(name = "login-input", location = "login-input", type = "redirect") >) public String execute() throws Exception  String result = ""; StudentService studentService = new StudentService(); if (pageName != null && studentService != null)  if (pageName.equals("signup"))  result = studentService.save(userName, password, firstName, lastName, dateOfBirth, emailAddress); if (result.equals("SignupSuccess"))  return "login-input"; > else  return "failure"; > > > return SUCCESS; > public String getPageName()  return pageName; > public void setPageName(String pageName)  this.pageName = pageName; > public String getUserName()  return userName; > @RequiredStringValidator(type = ValidatorType.FIELD, message = "UserName is a required field") @StringLengthFieldValidator(type = ValidatorType.FIELD, maxLength = "12", minLength = "6", message = "UserName must be of length between 6 and 12") public void setUserName(String userName)  this.userName = userName; > public String getPassword()  return password; > @RequiredStringValidator(type = ValidatorType.FIELD, message = "Password is a required field") @StringLengthFieldValidator(type = ValidatorType.FIELD, maxLength = "12", minLength = "6", message = "Password must be of length between 6 and 12") public void setPassword(String password)  this.password = password; > public String getFirstName()  return firstName; > @RequiredStringValidator(type = ValidatorType.FIELD, message = "FirstName is a required field") public void setFirstName(String firstName)  this.firstName = firstName; > public String getLastName()  return lastName; > @RequiredStringValidator(type = ValidatorType.FIELD, message = "LastName is a required field") public void setLastName(String lastName)  this.lastName = lastName; > public String getEmailAddress()  return emailAddress; > @RequiredStringValidator(type = ValidatorType.FIELD, message = "EmailAddress is a required field") @EmailValidator(type = ValidatorType.FIELD, message = "Email Address must be valid") public void setEmailAddress(String emailAddress)  this.emailAddress = emailAddress; > public String getDateOfBirth()  return dateOfBirth; > @RequiredStringValidator(type = ValidatorType.FIELD, message = "DateOfBirth is a required field") public void setDateOfBirth(String dateOfBirth)  this.dateOfBirth = dateOfBirth; > >

Similar to the SignupAction class, the LoginAction class also implements the execute() method as shown below

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 
@SuppressWarnings("serial") public class LoginAction extends ActionSupport  private String pageName; private String userName; private String password; @Action("login-input") public String input() throws Exception  return "login"; > @Action("login") public String execute() throws Exception  String result = ""; StudentService studentService = new StudentService(); if (pageName != null && studentService != null)  if (pageName.equals("login"))  result = studentService.findByLogin(userName, password); if (result.equals("LoginFailure"))  return "failure"; > else  return "success"; > > > return SUCCESS; > public String getPageName()  return pageName; > public void setPageName(String pageName)  this.pageName = pageName; > public String getUserName()  return userName; > @RequiredStringValidator(type = ValidatorType.FIELD, message = "UserName is a required field") @StringLengthFieldValidator(type = ValidatorType.FIELD, maxLength = "12", minLength = "6", message = "UserName must be of length between 6 and 12") public void setUserName(String userName)  this.userName = userName; > public String getPassword()  return password; > @RequiredStringValidator(type = ValidatorType.FIELD, message = "Password is a required field") @StringLengthFieldValidator(type = ValidatorType.FIELD, maxLength = "12", minLength = "6", message = "Password must be of length between 6 and 12") public void setPassword(String password)  this.password = password; > >

The @Action annotation is used to specify the incoming requested URL and results to be rendered. For results other than SUCCESS (or the equivalent success string), the resulting view will be rendered based on the value of the result. For instance, in SignupAction class, if “failure” string is returned from the execute() method, the result will be appended to the @Action value (which is “signup”, in this case) and the signup-failure.jsp page will be rendered. Similarly, in LoginAction class, if “failure” string is returned from the execute() method, the login-failure.jsp page will be rendered.

If SUCCESS (or the equivalent success string) is returned from the execute() method, the actual value of action will be the resulting view, unless there are no results specified using the @Result annotation. For instance, in LoginAction class, there are no @Result annotations used and hence, login-success.jsp will be rendered when execute() method returns a SUCCESS string.

But if there are results specified with @Result annotation as in SignupAction class, the name and location given by the results array will determine the view rendered – in this case, login-input action will be rendered (which is in-turn, an action specified by the LoginAction class).

12. Add Validators to the Form Fields

As shown in the above snippets of SignupAction and LoginAction classes, add the following required validators to the setter methods for the fields.

@RequiredStringValidator is used to check that a String field is not empty.

@StringLengthFieldValidator is used to check that a String field is of the right length. It assumes that the field is a String. If neither minLength nor maxLength is set, nothing will be done.

@EmailValidator is used to check that a field is a valid e-mail address if it contains a non-empty String.

13. Create the DB Schema in a MYSQL DB

Connect to the MySQL DB which is to be used for this application and create a new DB Schema named studentEnrollment using the MySQL Workbench. This is necessary as the DB Schema name of studentEnrollment is specified in the db.properties file.

Once the studentEnrollment DB Schema is created, create a table named student inside the DB Schema using the CREATE TABLE statement as follows:

1 2 3 4 5 6 7 8 9 10 
CREATE TABLE `student` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `dateOfBirth` datetime NOT NULL, `emailAddress` varchar(255) NOT NULL, `firstName` varchar(255) NOT NULL, `lastName` varchar(255) NOT NULL, `password` varchar(8) NOT NULL, `userName` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=latin1;

14. Deploying the Application on Tomcat Server

Once the above steps are complete and the project is successfully built, the Java web application is ready to deployed on the Tomcat Server 7.

The Java web application can be deployed locally by right clicking on the project and choosing the “Run As->Run on Server” option.

The same can be deployed remotely on any native server that supports Tomcat by copying the WAR file (Right click on the project and choose Export as WAR File option) to /var/lib/tomcat7 folder (or appropriate tomcat directory) and restarting the tomcat server.

15. Clone or Download code

In case of not using git, download the project as ZIP or tar.gz file here: https://github.com/elizabetht/StudentEnrollmentWithStruts/releases/tag/1.4

Posted by Elizabeth Thomas Nov 21 st , 2013 Struts2