Simple Login Application using Struts 2 - Development & Testing

Article Index

1 1 1 1 1 1 1 1 1 1 Rating 3.00 (2 Votes)

 

Development

We will first start by adding a struts.xml for our project. In eclipse, you will have to create a folder 'classes' under \workspace\Struts2LoginApp\WebContent\WEB-INF\ and add struts.xml in that folder.

Below is the struts.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
   "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.devMode" value="true" />
   <package name="loginapp" extends="struts-default">
     
      <action name="logon" 
            class="com.tech_freaks.action.LogonAction" 
            method="execute">
            <result name="success">/Home.jsp</result>
            <result name="input">/Login.jsp</result>
            <result name="error">/Login.jsp</result>
      </action>
   </package>
</struts>

 The configuration file is straightforward and easy to understand. <constant> is setting the project in a development mode. This will give helpful errors in the logs / screen while debugging issues.

<package> is applicable when we divide the configure into multiple logical parts instead of having all action definition inside single file.
Let us take a careful look at the entry for <action> and ensure all mapping components are named to match the entries in here.

• “name” attribute needs to be mapped to the <form action=””> in the Login.jsp. This is how struts knows which Action class to invoke. We leave the method to “execute” as our Action class will extend ActionSupport class and override the execute method.
• “class” should be fully qualified class name of the Action class.
• When the Action executes, we can configure different JSPs / views to invoke after completion. The String value returned from Action.execute() method should match the “name” attribute in one of the “result”. However, it is important to note that, if we are using struts validation framework, we need to have an <result> with name=”input”. The framework will redirect to the view configured for <result> name="input" with the error message. If you do not have entry for “input” you will see an error saying that “No result defined for action and result input - action –“

Next, we take a look at the LogonAction.java.
As we plan to validate for empty fields, we need to extend the ActionSupport class. Once extended, we need to override the methods execute() and validate(). The next thing is we need to have instance variables for user fields in the Login.jsp. Note that the instance variable (mainly the getter/ setters for the instance variables) must match exactly to the “name” attribute on the <input> fields on the JSP. This is also a difference between struts 1.1 were we had separate ActionForms which had the fields mapped to the <input>. 
The complete java code is below

package com.tech_freaks.action;

import java.util.HashMap;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;
import com.tech_freaks.utils.DBHelper;

public class LogonAction extends ActionSupport {
	
	public static final String LOGIN_SUCCESS = "success";
	public static final String LOGIN_FAILED = "error";
	
	private static final String LOGIN_QUERY = "select * from users where user_name=? and password=?";
	
	private String userName;
	private String password;

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getPassword() {
		return password;
	}

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

	@Override
	public String execute() throws Exception {
		ValueStack stack = ActionContext.getContext().getValueStack();
		String[] params = new String[] {userName, password};
		DBHelper dbHelper = new DBHelper();
		
		boolean isSuccess = dbHelper.containsResult(LOGIN_QUERY, params);
		if(isSuccess)
			return LOGIN_SUCCESS;
		else {
			Map<String, Object> context = new HashMap<String, Object>();
			context.put("errorMsg", new String("Invalid user name or password. Try again.")); 
			stack.push(context);
			return LOGIN_FAILED;
		}
	}

	@Override
	public void validate() {
		 if (userName == null || userName.trim().equals(""))
	      {
	         addFieldError("userName","Please enter a user name to login with.");
	      }
		 if (password == null || password.trim().equals(""))
	      {
	         addFieldError("password","Please enter a password.");
	      }
	}
}

 

Let’s take a close look at validate(). Use the addFieldError() method with the first parameter matching the field name which has the validation error. Again, this name needs to exactly match with <input> name attribute in the JSP. If we use the struts taglib in the JSP, it also takes care of showing the error message for each field inline to the field.

Next, we take a look at the execute() method. It is fairly straightforward. It calls the DBHelper class to verify in the database, if a record exists for the supplied userName and password combination. Based on the result, it returns “success” or “error”. The value returned needs to match with the <result> name attribute defined in the struts.xml which we examined before. The appropriate view will be displayed.

For the failed login attempt, we have to go back to the login page and display an error message. We use this requirement to explain ActionContext and ValueStack concept in struts 2. The ActionContext has access to variables like session, request params etc. It also contains a value stack. You can put objects into value stack. As the name suggests, it is a stack with push, pop, peek methods in it. In the JSP, when you want to access the variables in the ActionContext using the struts taglib, you use #<attribute> say #session. However, for accessing value stack, we do not have to use the #. As you can see, we are pushing a Map with key errorMsg into the value stack, with value containing the error message which needs to be displayed to the user on failed login attempt.

Login.jsp
This page is modified from our previous version of Login.jsp. The main change is the struts taglib usage. We use the <s:property> to pull the attribute from the value stack which we previously discussed. This is used where the login attempt fails. We have used <s:form>, <s:textfield> etc. They help giving inline errors for each field as per the login in the validate() method.

Below is the complete Login.jsp 

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
   pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>
Tech-freaks.com - Struts2 - SimpleLogin App Login Page
</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
</head>
<body>
<s:property value="errorMsg"/><br/>
<s:form method="POST" action="logon">
	<s:textfield  name="userName" label="User Name"/>
	<s:password  name="password" label="Password" />
	<s:submit name="submit" label="Submit" align="center" />
		
</s:form>
</body>
</html>

 

Home.jsp
Simple page, which when requested due to successful login, fetches the “username” field and displays the welcome message. Below is the complete JSP

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><%@page
	language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
	<head>
		<title>
		Tech-freaks.com - Struts 2 SimpleLogin App Home Page
		</title>
		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
	</head>
	<body>
	 	<h1> Welcome to Tech-freaks.com - Struts2 Simple Logon App, <s:property value="userName"/></h1>
	</body>
</html>

 

Testing 

Once you have all the components put in, right click the project in Eclipse and Export as WAR. Drop the generated WAR in <Tomcat>\webapps folder and start Tomcat. Verify Tomcat logs, if the deployment of the WAR was successful. 
Test by accessing the URL : http://localhost:8080/Struts2LoginApp/Login.jsp (Modify the port and context name as per your customization)
Run and verify each scenario mentioned in the requirement.


Congratulations, on completing your first “Non-Hello World” project using struts 2!!!


You can download the complete Eclipse project from Github by clicking the link below.

Download complete Struts 2 Login App Source code from Github


Joomla SEO by MijoSEF