Struts provides an easy way for handling uncaught exceptions which might be thrown during execution of action classes. Uncaught exceptions are ones which are not caught by the regular try-catch clause. There are two methods for handing uncaught exceptions in Struts:

    • Global exception handling: specifies exception mappings (exception type - view name) which apply to all action classes in a Struts package.
    • Exception handling per action: specifies exception mappings which apply to a specific action class.

Both methods require adding exception mappings in struts.xml configuration file. Let’s go through each method in details.

 

1. Global exception handling in Struts

Add the following code snippet just after the <package> element in struts.xml file:

<global-results>
	<result name="error">/Error.jsp</result>
</global-results>

<global-exception-mappings>
	<exception-mapping exception="java.lang.Exception" result="error"/>
</global-exception-mappings>

The <global-results> element defines global view names. Here the view named “error” is mapped with the actual view page “/Error.jsp”.

The <global-exception-mappings> element specifies a set of <exception-mapping> element which maps an exception type to a view name. Here the exception of type java.lang.Exception is mapped to the view name “error”. That means when any uncaught exception of type java.lang.Exception or its sub types is thrown, Struts will redirect users to the view page mapped with the name “error”.

In the Error.jsp page we can access information of the exception as follows:

Exception name: <s:property value="exception"/>
Exception stack trace: <s:property value="exceptionStack"/>

Or simpler with expression language (EL):

Exception name: ${exception}
Exception stack trace: ${exceptionStack}

Let’s see a complete example in action. Consider the following Struts action class:

package net.codejava.struts;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.interceptor.ServletRequestAware;

import com.opensymphony.xwork2.ActionSupport;

public class SumAction extends ActionSupport implements ServletRequestAware {
	private HttpServletRequest request;
	private int sum;

	public int getSum() {
		return sum;
	}

	public String execute() {
		// an exception might be thrown here if x/y is not a number
		int x = Integer.parseInt(request.getParameter("x"));
		int y = Integer.parseInt(request.getParameter("y"));
		sum = x + y;
		return SUCCESS;
	}

	@Override
	public void setServletRequest(HttpServletRequest request) {
		this.request = request;
	}
}

The execute() method parses two numbers x and y from the request and produces sum of both. In this case, an exception might be thrown if either x or y is not a number (a java.lang.NumberFormatException exception is raised).

Code of the Error.jsp page:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>    
<!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=UTF-8">
<title>Error page</title>
</head>
<body>
	<center>
		<h1>Sorry, unexpected exception occurred:</h1>
		<h2>Exception name: ${exception}</h2>
	</center>
</body>
</html>

Code of the JSP page which will be displayed when the execute() method returns successfully (Sum.jsp):

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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=UTF-8">
<title>Sum Result</title>
</head>
<body>
	<center>
		<h1>Sum is: ${sum}</h1>
	</center>
</body>
</html>

Code of struts.xml file:

<?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>
	<package name="Struts2ExceptionHandling" extends="struts-default">

		<global-results>
			<result name="error">/Error.jsp</result>
		</global-results>

		<global-exception-mappings>
			<exception-mapping exception="java.lang.Exception" result="error"/>
		</global-exception-mappings>

		<action name="sum" class="net.codejava.struts.SumAction">
			<result name="success">/Sum.jsp</result>
		</action>

	</package>
</struts>

The following screenshot is output of the application when passing two numeric parameters:

Struts2 exception handling test - success

If either a parameter is not a number, an exception is thrown and our Error.jsp page will be displayed instead:

Struts2 exception handling test - error

Of course we can specify multiple exception mappings as follows:

<global-results>
	<result name="error">/Error.jsp</result>
	<result name="dbError">/DBError.jsp</result>
</global-results>

<global-exception-mappings>
	<exception-mapping exception="java.lang.Exception" result="error"/>
	<exception-mapping exception="java.sql.SQLException" result="dbError"/>
</global-exception-mappings>

The mapping with most specific exception type will take precedence.

NOTES: With global exception handling method, the view names specified in the <exception-mapping> elements must be declared in the <global-results> element.

 

2. Exception handling per action in Struts

This method specifies the <exception-mapping> elements inside the <action> element, for example:

<action name="connectDB" class="net.codejava.struts.ConnectDBAction">

	<exception-mapping result="dbError" exception="java.sql.SQLException" />

	<result name="success">/DBConnect.jsp</result>
	<result name="dbError">/DBError.jsp</result>
</action>

That tells Struts to redirect the users to the view “dbError” when an exception of type java.sql.SQLException (or its sub type) is thrown inside the action class ConnectDBAction.

Code of the action class (ConnectDBAction.java) file:

package net.codejava.struts;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import com.opensymphony.xwork2.ActionSupport;

public class ConnectDBAction extends ActionSupport {
	public String execute() throws SQLException, ClassNotFoundException {
		
		String databaseURL = "jdbc:mysql://localhost:3306/test?user=root&password=secret";
		Connection conn = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection(databaseURL);
		} finally {
			if (conn != null) {
				conn.close();
			}
		}
		
		return SUCCESS;
	}
}

The action method execute() simply tries to connect to a MySQL database. If success, return the view named “success”.

Code of the success view (DBConnect.jsp):

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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=UTF-8">
<title>Database Connection Result</title>
</head>
<body>
	<center>
		<h1>Connected to database successfully!</h1>
	</center>
</body>
</html>

Code of the error page (DBError.jsp):

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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=UTF-8">
<title>Database Error page</title>
</head>
<body>
	<center>
		<h1>Sorry, a database exception occurred:</h1>
		<h2>Exception name: ${exception}</h2>
	</center>
</body>
</html>

Output when connecting to the database successfully:

Struts2 exception handling test - database success

Output when an exception is thrown (e.g the username/password is incorrect):

Struts2 exception handling test - database error

NOTE: In this exception handling per action method, the view names specified in the <exception-mapping> elements can refer to either views declared in the enclosing action or in the <global-results> element.

 

3. Logging exceptions in Struts

In addition to redirect the users to a specific error handling page, Struts also allows us to log exceptions in servlet container’s console and/or in log files. To enable logging exceptions, place the following code just after the <package> element:

<interceptors>
	<interceptor-stack name="appDefaultStack">
		<interceptor-ref name="defaultStack">
			<param name="exception.logEnabled">true</param>
			<param name="exception.logLevel">ERROR</param>
		</interceptor-ref>
	</interceptor-stack>
</interceptors>

That declares an interceptor named “appDefaultStack” which extends from the Struts default stack and configures two attributes of the Struts exception interceptor: logEnabled and logLevel. Behind the scene, the Struts exception interceptor looks at the exception mappings, and redirects the users to the appropriate view when an exception is raised. But the exceptions logging is not enabled by default. The logLevel can be one of the following values: trace, debug, info, warn, error and fatal.

When enabled, Struts logs the exceptions in servlet container’s console as in the following example:

Struts2 logging exceptions

If a file logging is configured (such as log4j), the exceptions are also written into the log files.

So far the struts.xml file used in this tutorial’s examples is as follows:

<?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>
	<package name="Struts2ExceptionHandling" extends="struts-default">
		<interceptors>
			<interceptor-stack name="appDefaultStack">
				<interceptor-ref name="defaultStack">
					<param name="exception.logEnabled">true</param>
					<param name="exception.logLevel">ERROR</param>
				</interceptor-ref>
			</interceptor-stack>
		</interceptors>
	
		<default-interceptor-ref name="appDefaultStack" />
	
		<global-results>
			<result name="error">/Error.jsp</result>
		</global-results>
		
		<global-exception-mappings>
			<exception-mapping exception="java.lang.Exception" result="error"/>
		</global-exception-mappings>
		
		<action name="sum" class="net.codejava.struts.SumAction">
			<result name="success">/Sum.jsp</result>
		</action>
		
		<action name="connectDB" class="net.codejava.struts.ConnectDBAction">
			<exception-mapping result="dbError" exception="java.sql.SQLException" />
			<result name="success">/DBConnect.jsp</result>
			<result name="dbError">/DBError.jsp</result>
		</action>
		
	</package>
</struts>

NOTE: If a same exception mapping is declared both globally and per action, then the action-specific exception mapping will take precedence.

 

Related Java Exception Handling Tutorials:

 

Other Struts Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (Struts2ExceptionHandling.war)Struts2ExceptionHandling.war[Deployable WAR file]4186 kB
Download this file (Struts2ExceptionHandling.zip)Struts2ExceptionHandling.zip[Eclipse project]4190 kB

Add comment