Servlet异常和错误处理示例教程

时间:2020-02-23 14:41:52  来源:igfitidea点击:

今天,我们将研究Servlet异常和错误处理。

Servlet异常

如果您注意到,doGet()和doPost()方法会抛出javax.servlet.ServletException和IOException,让我们看看从应用程序中抛出这些异常时会发生什么。
我将编写一个简单的Servlet,它将抛出ServletException。

package com.theitroad.servlet.exception;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MyExceptionServlet")
public class MyExceptionServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		throw new ServletException("GET method is 不支持.");
	}

}

现在,当我们使用GET方法通过浏览器调用此servlet时,将得到如下图所示的响应。

由于浏览器仅了解HTML,因此当我们的应用程序引发异常时,servlet容器将处理该异常并生成HTML响应。
此逻辑特定于servlet容器。
我正在使用tomcat并获取此错误页面。
如果您将使用其他一些服务器,例如JBoss或者Glassfish,则可能会收到不同的错误HTML响应。

此响应的问题在于,它对用户毫无价值。
它还向用户显示我们的应用程序类和服务器详细信息,这对用户没有意义,并且从安全角度来看也不是一件好事。

Servlet错误

我敢肯定,当您尝试访问不存在的URL时,您一定已经看到404错误。
让我们看看我们的servlet容器如何响应404错误。
如果我们发送无效URL的请求,则会得到响应HTML,如下图所示。

同样,它是服务器代表我们的应用程序生成的通用HTML,对用户几乎没有价值。

Servlet异常和错误处理

Servlet API支持可在部署描述符中配置的自定义Exception和Error Handler Servlet。
这些servlet的全部目的是处理应用程序引发的异常或者错误,并将有用HTML响应发送给用户。
我们可以提供指向应用程序主页的链接或者一些详细信息,以使用户知道出了什么问题。

因此,首先我们需要创建一个自定义的Exception and Error Handler servlet。
我们可以为应用程序提供多个异常和错误处理程序servlet,但为简单起见,我将创建一个servlet,并将其用于异常和错误。

AppExceptionHandler.java

package com.theitroad.servlet.exception;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/AppExceptionHandler")
public class AppExceptionHandler extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		processError(request, response);
	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		processError(request, response);
	}

	private void processError(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		//Analyze the servlet exception
		Throwable throwable = (Throwable) request
				.getAttribute("javax.servlet.error.exception");
		Integer statusCode = (Integer) request
				.getAttribute("javax.servlet.error.status_code");
		String servletName = (String) request
				.getAttribute("javax.servlet.error.servlet_name");
		if (servletName == null) {
			servletName = "Unknown";
		}
		String requestUri = (String) request
				.getAttribute("javax.servlet.error.request_uri");
		if (requestUri == null) {
			requestUri = "Unknown";
		}
		
		//Set response content type
	      response.setContentType("text/html");
	 
	      PrintWriter out = response.getWriter();
	      out.write("<html><head><title>Exception/Error Details</title></head><body>");
	      if(statusCode != 500){
	    	  out.write("<h3>Error Details</h3>");
	    	  out.write("Status Code:"+statusCode+"<br>");
	    	  out.write("Requested URI:"+requestUri);
	      }else{
	    	  out.write("<h3>Exception Details</h3>");
	    	  out.write("<ul><li>Servlet Name:"+servletName+"</li>");
	    	  out.write("<li>Exception Name:"+throwable.getClass().getName()+"</li>");
	    	  out.write("<li>Requested URI:"+requestUri+"</li>");
	    	  out.write("<li>Exception Message:"+throwable.getMessage()+"</li>");
	    	  out.write("</ul>");
	      }
	      
	      out.write("<br>");
	      out.write("<a href=\"index.html\">Home Page</a>");
	      out.write("</body></html>");
	}
}

让我们看看如何在部署描述符中对其进行配置,然后我们将了解其实现方式和工作方式。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>ServletExceptionHandling</display-name>
<welcome-file-list>
  <welcome-file>index.html</welcome-file>
</welcome-file-list>

<error-page>
	<error-code>404</error-code>
	<location>/AppExceptionHandler</location>
</error-page>

<error-page>
<exception-type>javax.servlet.ServletException</exception-type>
<location>/AppExceptionHandler</location>
</error-page>
</web-app>

如您所见,使用error-page元素为应用程序指定异常处理程序servlet非常容易。
每个错误页面元素应具有错误代码或者异常类型元素。
我们在location元素中定义异常处理程序servlet。

基于以上配置,如果应用程序抛出404错误或者ServletException,它将由AppExceptionHandler servlet处理。

当出现此类异常和错误情况时,servlet容器将调用Exception Handler servlet的相应HTTP方法,并传递请求和响应对象。
注意,我已经提供了doGet()和doPost()方法的实现,以便它可以处理GET和POST请求并使用通用方法来处理它们。

在servlet容器调用servlet处理异常之前,它在请求中设置了一些属性以获取有关异常的有用信息,其中一些是javax.servlet.error.exception,javax.servlet.error.status_code,javax.servlet。
error.servlet_name和javax.servlet.error.request_uri。

作为例外,状态代码始终为500,与"内部服务器错误"相对应,对于其他类型的错误,我们将获得不同的错误代码,例如404、403等。

使用状态代码,我们的实现将不同类型HTML响应呈现给用户。
它还提供了到应用程序主页的超链接。

现在,当我们点击抛出ServletException的servlet时,我们将得到如下图所示的响应。

如果我们尝试访问一个无效的URL,这将导致404响应,我们将得到如下图所示的响应。

它看起来不是很好,可以帮助用户轻松了解发生的情况并为他们提供前往正确位置的方法。
它还避免了将应用程序敏感信息发送给用户。
我们应该始终为我们的Web应用程序配备异常处理程序。

如果要在单个异常处理程序中处理运行时异常和所有其他异常,则可以将异常类型提供为Throwable。

<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/AppExceptionHandler</location>
</error-page>

如果有多个错误页面条目,例如,一个用于Throwable,一个用于IOException,并且应用程序抛出FileNotFoundException,则它将由IOException的错误处理程序处理。

您还可以将JSP页面用作异常处理程序,只需提供jsp文件的位置而不是servlet映射即可。