我们难保自己写的程序不会出错,所以需要一些错误处理机制来帮我们更好的解决异常,处理错误。在浏览网页的时候,如果访问的页面不存在,那么会收到一个HTTP 404错误信息。这个问题的发生,可能是因为用户输入了错误的URL,但更多的情况是服务器端的链接出现了错误,页面移动了位置或者删除了,却忘记修改原来的链接。另外一种情况就是,我们开发的web应用程序本身有bug,在运行时出现了异常。
所以,这就要求我们在开发web应用时,对于可能出现的错误或异常,提前做好处理,即使错误不可避免,也应该提供一些友好的信息。在servlet中,有两种服务器处理机制:声明式异常处理(declarative exception handling)和程序式异常处理(programmatic exception handling)。
声明式异常处理
这种异常处理方式是在web.xml文件中声明对各种异常的处理方法。其格式如下:
<?xml version='1.0' encoding='utf-8'?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<error-page>
<error-code>404</error-code>
<location>/FileNotFound.html</location>
</error-page>
</web-app>
可以看出来,<error-code>指定HTTP的错误代码,<location>制定了错误出现时的页面路径。还有一种格式如下:
<?xml version='1.0' encoding='utf-8'?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<error-page>
<error-type>java.io.FileNotFoundException</error-type>
<location>/ExceptionHandle</location>
</error-page>
</web-app>
其中<error-type>指定了java异常类的完整限定名,而<location>指定了处理异常的处理类(Servlet类)。在上面的那中格式中,<location>也可以这样指定。
HTTP常见的错误代码详见HTTP解析,文章有对HTTP的详细说明。
一个异常处理类的详细代码如下所示:
package com.shan.web;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HttpErrorHandleServlet extends HttpServlet{
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException,ServletException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=UTF-8");
Integer status_code = (Integer)request.getAttribute("javax.servlet.error.status_code");
out.println("<html><head><title>");
out.println("错误页面");
out.println("</title></head>");
out.println("<body>");
switch(status_code) {
case 401: break;
case 404:
out.println("HTTP状态码:"+status_code);
out.println("您访问的页面不存在,或者已被移动到其他位置。");
break;
default:
break;
}
out.println("</body></html>");
out.close();
}
}
为了帮助进行错误处理的servlet分析问题,以及生成详细的响应,servlet容器在将请求转发给错误页面之前,会在请求中设置某些有用的属性,如表1所示:
属性的名字 | 属性的类型 | 属性说明 |
javax.servlet.error.status_code | java.lang.Integer | HTTP协议的状态代码 |
javax.servlet.error.exception_type | java.lang.Class | 未捕获异常的Class类的对象 |
javax.servlet.error.message | java.lang.String | 传递给sendError()方法的消息,或者是在未捕获异常中的消息 |
javax.servlet.error.exception | java.lang.Throwable | 调用错误页面的未捕获异常 |
javax.servlet.error.request_uri | java.lang.String | 当前请求的URI |
javax.servlet.error.servlet_name | java.lang.String | 导致错误页面被调用的servlet的名字 |
<?xml version='1.0' encoding='utf-8'?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<servlet>
<servlet-name>HttpErrorHandleServlet</servlet-name>
<servlet-class>com.shan.web.HttpErrorHandleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HttpErrorHandleServlet</servlet-name>
<url-pattern>/ExceptionHandle</url-pattern>
</servlet-mapping>
<error-page>
<error-code>401</error-code>
<location>/ExceptionHandle</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/ExceptionHandle</location>
</error-page>
</web-app>
程序式异常处理
这种异常处理方式利用try-catch来捕获异常,并对捕获的异常进行相应的处理。可在catch块中利用如下语句将异常信息输出到log日志中。
getServletContext().log("ServletContext.log():异常信息"+ex.toString());
log("GenericServlet.log():异常信息"+ex.toString());
这两句话都可以将异常信息记录到log日志中,他们的区别在于:如果调用GenericServlet类的log()方法,它会在日志消息前面加上servlet的名字,而调用ServletContext的log()方法,则只记录消息本身。
也可以使用response的sendError()方法将错误消息发送到错误页面。
利用RequestDispatcher来处理异常
之前介绍过页面转发机制,所以也可以将异常封装到一个请求中,然后利用ServletContext.log()转发一个异常处理servlet进行统一的处理。