Servlet的异常处理机制
一 声明式异常处理
在web.xml中对声明对各种异常的处理方法。
通过 <error-page>元素来声明。 此元素的结构如下:
+------<error-code> or <exception-type>
|
<error-page> ----+
|
+------<location>
1 HTTP错误代码的处理
4**代码表示客户端错误:请求有语法错误或者请求无法实现。
5**代码表示服务器端错误:服务器未能实现合法的请求。
例:为404错误指定相应的错误处理页面
在web.xml中
- <error-page>
- <error-code>404</error-code>
- <location>/FileNotFound.html</location>
- </error-page>
编写FileNotFound.html
同时 也可以编写一个专门处理HTTP错误代码的HttpErrorHandlerServlet类来进行响应
- package servlet;
- import java.io.PrintWriter;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class HttpErrorHandlerServlet extends HttpServlet
- {
- protected void service(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, java.io.IOException
- {
- resp.setContentType("text/html;charset=GB2312");
- PrintWriter out = resp.getWriter();
- Integer status_code=(Integer)req.getAttribute("javax.servlet.error.status_code");
- out.println("<html><head><title>错误页面</title></head>");
- out.println("<body>");
- //如果你的JDK版本低于1.5,那么你应该按照如下方式调用
- //int status=status_code.intValue();
- //switch(status){...}
- switch(status_code)
- {
- case 401:
- break;
- case 404:
- out.println("<h2>HTTP状态代码:"+status_code+"</h2>");
- out.println("你所访问页面并不存在,或者已经被移动到其它位置。");
- out.println("
如有其它问题,请<a href=mailto:admin@sunxin.org>联系管理员</a>。");
- break;
- default:
- break;
- }
- out.println("</body></html>");
- out.close();
- }
- }
重写HttpServlet类的service()方法。调用请求对象getAttribute()方法得到javax.servlet.error.status_code属性的值,当发生HTTP错误的时候,
Servlet容器会自动将HTTP的错误代码作为javax.servlet.error.status_code
属性的值,保存在请求的对象中。
部署好这个servlet。location修改为servlet的location
2 Java异常的处理
例:一个Servlet从文件中读取配置信息,如果文件不存在的,就会抛出java.io.FileNotFoundException异常。
====第一步:FileExceptionServlet.java
- package org.sunxin.ch06.servlet;
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.util.Properties;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class FileExceptionServlet extends HttpServlet
- {
- public void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException,IOException
- {
- FileInputStream fis=new FileInputStream("config.inc");
- Properties pps=new Properties();
- pps.load(fis);
- //读取属性的代码,省略。
- fis.close();
- }
- }
如果找不到config.inc文件,FileExceptionServlet就会抛出java.io.FileNotFoundException异常
========第二步:异常处理Servlet类。ExceptionHandlerServlet.java
- package servlet;
- import java.io.PrintWriter;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class ExceptionHandlerServlet2 extends HttpServlet
- {
- protected void service(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, java.io.IOException
- {
- resp.setContentType("text/html;charset=GB2312");
- PrintWriter out = resp.getWriter();
- out.println("<html><head><title>错误页面</title></head>");
- out.println("<body>");
- String uri=(String)req.getAttribute("javax.servlet.error.request_uri");
- Object excep=req.getAttribute("javax.servlet.error.exception");
- out.println(uri+" 运行错误。");
- out.println("<p>错误原因:"+excep);
- out.println("</body></html>");
- out.close();
- }
- }
========第三步:web.xml文件中声明Servlet
- <error-page>
- <exception-type>java.io.FileNotFoundException</exception-type>
- <location>/ExcepHandler</location>
- </error-page>
<exception-type>子元素指定了Java异常类的名字
<locaiton>子元素指定了对异常处理的Servlet类
二 程序式异常处理
程序式异常处理就是在Web程序中利用try-catch语句进行捕获异常,并对捕获异常进行响应的处理。
1 在try-catch语句中处理异常
- catch(SQLException se)
- {
- getServletContext().log("ServletContext.log(): 数据库操作失败!"+
- se.toString());
- log("GenericServlet.log(): 数据库操作失败!"+se.toString());
- resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
- "数据库操作出现问题,请联系管理员。");
- }
[1] 捕捉到异常时,分别用ServletContext接口的log()方法和GenericServlet抽象类的log()方法记录数据库操作失败的原因。
区别:
如果调用GenericServlet类的log()方法 它会在日志消息的前面加上Servlet的名字
而调用ServletContext接口的log()方法 则只记录消息本身
这两个log()方法会把日志信息写入到日志文件中。 在tomcat6 产生的日志文件名以及文件存放的位置是
%CATALINA_HOME%\logs\localhost.当前日期.log。
[2] 调用响应对象的sendError()方法发送HTTP错误代码,Servlet容器会发送一个包含了这些信息的错误页面到浏览器
2 使用RequestDispatcher来处理异常
产生异常的Servlet
- try
- {
- int a=5;
- int b=0;
- int c=a/b;
- }
- catch(ArithmeticException ae)
- {
- req.setAttribute("javax.servlet.error.exception",ae);
- req.setAttribute("javax.servlet.error.request_uri",req.getRequestURI());
- RequestDispatcher rd=req.getRequestDispatcher("ExcepHandler2");
- rd.forward(req,resp);
- }
处理异常的Servlet
- package servlet;
- import java.io.PrintWriter;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class ExceptionHandlerServlet2 extends HttpServlet
- {
- protected void service(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, java.io.IOException
- {
- resp.setContentType("text/html;charset=GB2312");
- PrintWriter out = resp.getWriter();
- out.println("<html><head><title>错误页面</title></head>");
- out.println("<body>");
- String uri=(String)req.getAttribute("javax.servlet.error.request_uri");
- Object excep=req.getAttribute("javax.servlet.error.exception");
- out.println(uri+" 运行错误。");
- out.println("<p>错误原因:"+excep);
- out.println("</body></html>");
- out.close();
- }
- }
说明:
[1] 将异常对象和抛出异常的servlet的位置作为HttpServletRequest对象的属性保存到请求对象中。
[2] 通过请求对象的getRequestDispatcher()方法得到RequestDispatcher对象 调用RequestDispatcher对象的forward()方法将请求转发给 ExcepHandler2
[3] ExcepHandler2可以从请求对象中取出javax.servlet.error.exception和javax.servlet.error.request_uri属性