Post by mazdotnetI'm pretty new to jsp. I have a class set up that connects to the
database and returns the result if successul. I call it from my .jsp
which works fine. My question is lets say I force it to cause an
exception by chaging the word microsoft in the following statement
'Class.forName("com.microsoftssss.sqlserver.jdbc.SQLServerDriver"); .
How do I show that exception in my jsp since it's been thrown in my
class and being caught in the class as well too. What's the best way
of doing this?
You might throw a new exception (of your own exception type) from
the class, and let the JSP handle that (or, more properly, to set
up an error handler page in your web-application to catch the
exception type and show a suitable error message).
Here is a set of files for a mini-application that will demonstrate
the error-handling capabilities of a Java web-application.
First, the file/directory layout
WEB-INF/
web.xml
classes/
errordemo/
business/
BusinessException.class
FailClass.class
web/
FailServlet.class
lib/
jstl.jar
standard.jar
web.xml
errorHandler.jsp
index.jsp
web.xml declares the servlets used, and also the index/error page locations:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>FailServlet</servlet-name>
<servlet-class>errordemo.web.FailServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FailServlet</servlet-name>
<url-pattern>/FailServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>
index.jsp
</welcome-file>
</welcome-file-list>
<error-page>
<exception-type>errordemo.business.BusinessException</exception-type>
<location>/errorHandler.jsp</location>
</error-page>
</web-app>
index.jsp just contains a link to something that throws an exception:
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!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>Failure routing demo</title>
</head>
<body>
<h1>Failure routing demo</h1>
<a href="<c:url value="/FailServlet" />">Cause a failure</a>
</body>
</html>
Clicking on the "Cause a failure" link will take the user to the
/FailServlet page, provided by the FailServlet servlet:
package errordemo.web;
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
import errordemo.business.*;
public class FailServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
FailClass fc = new FailClass();
try {
fc.doSomething();
} catch (BusinessException be) {
throw new ServletException(be);
}
}
}
So, the servlet calls another class (part of the "business" domain of the
application), and if that part does fail, the resulting exception is
wrapped into a newly created ServletException.
The FailClass then does what is expected of it; generates a "business
exception":
package errordemo.business;
public class FailClass {
public FailClass() {
}
public void doSomething() throws BusinessException {
throw new BusinessException("Description / detailed error message");
}
}
BusinessException is just a minimal Exception subclass:
package errordemo.business;
public class BusinessException extends java.lang.Exception {
public BusinessException() {
}
public BusinessException(String msg) {
super(msg);
}
}
So, after clicking on the "Cause a failure" link, the code has now nested
into the following:
- the servlet (/FailServlet, errordemo.web.FailServlet)
- a business domain class (errordemo.business.FailClass)
- a business domain exception (errordemo.business.BusinessException)
At this point, the servlet container (Tomcat, Jetty, whatever), will take
up the control, as it notices (when the servlet execution is interrupted
by the exception) that web.xml contains an error page for the
BusinessException (which was returned wrapped within a ServletException),
and directs the user to the designated error page, /errorHandler.jsp,
which I've written to expose all available details of the error:
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!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 handler</title>
</head>
<body>
<h1>Error handler</h1>
Error detected, details:
<ul>
<li>
<strong>Error message:</strong>
<%= request.getAttribute("javax.servlet.error.message") %>
</li>
<li>
<strong>Requested URL was:</strong>
<%= request.getAttribute("javax.servlet.error.request_uri") %>
</li>
<li>
<strong>Error occurred in servlet:</strong>
<%= request.getAttribute("javax.servlet.error.servlet_name") %>
</li>
<li>
<strong>Exception was:</strong>
<%= ((Exception) (request.getAttribute("javax.servlet.error.exception"))).toString() %>
</li>
<li>
<strong>Exception type was:</strong>
<%= ((Class) (request.getAttribute("javax.servlet.error.exception_type"))).getName() %>
</li>
<li>
<strong>Exception stack trace:</strong><pre>
<% ((Exception) (request.getAttribute("javax.servlet.error.exception"))).printStackTrace(new java.io.PrintWriter(out)); %>
</pre>
</li>
</ul>
<a href="<c:url value="/"/>">Back to main page</a>
</body>
</html>
So, when the container trapped the exception, it dug out a set of data
about the exception, and placed all that available in a set of request
attributes. You can use these attributes either just for logging the
error information, or even for automated recovery (if at this level you
can do something that corrects the error). But anyway, you can nest deep
into your business domain, and if they are programmed to flag exceptional
situations as exceptions, you can pretty much separate the exception
handling from your other UI code. You'll have to be careful in what you
do in your error handler pages, though -- f.ex. it is not wise to have
them fetch anything from a database, because it could just be that
they'll be called in a situation where the database is not available.
So, whatever your error handler does, it should work with static
resources as much as possible.
I hope this helps in finding a suitable solution for your problem.
There are other ways, too -- instead of exception, return some data
structure that indicates a failure, and somehow contains also details
on the failure. But then, you've just reinvented exceptions, poorly.
So, when reporting exceptional situations, use exceptions. When
required by the interface specs, wrap exceptions into suitable
types. On the other hand, improve level of detail by subclassing
your own exception types as appropriate. Always strive to maintain
the exception stack all the way through the original exception that
was thrown (so, wrap/rethrow exceptions, do not just drop the old
exception on the floor and throw a new one: that way you'll lose
information on what the initial problem was).
--
Wolf a.k.a. Juha Laiho Espoo, Finland
(GC 3.0) GIT d- s+: a C++ ULSH++++$ P++@ L+++ E- W+$@ N++ !K w !O !M V
PS(+) PE Y+ PGP(+) t- 5 !X R !tv b+ !DI D G e+ h---- r+++ y++++
"...cancel my subscription to the resurrection!" (Jim Morrison)