Servlets - 调试

测试/调试servlet总是很困难. Servlet往往涉及大量的客户端/服务器交互,可能会出错但很难重现.

这里有一些提示和建议可以帮助您进行调试.

System.out.println()

System.out.println()很容易用作标记来测试某段代码是否正在执行与否.我们也可以打印出变量值.另外 :

  • 由于System对象是核心Java对象的一部分,因此可以在任何地方使用它而无需安装任何额外的类.这包括Servlet,JSP,RMI,EJB,普通Bean和类以及独立应用程序.

  • 在断点处停止技术会停止正常执行,因此需要更多时间.写入System.out不会对应用程序的正常执行流程造成太大影响,这使得它在时间关键时非常有价值.

以下是使用System.out.println() :

System.out.println("Debugging message");

上述语法生成的所有消息都将记录在Web服务器日志文件中.

消息记录

使用正确的日志记录方法使用标准日志记录方法记录所有调试,警告和错误消息始终是个好主意.我使用 log4J 来记录所有消息.

Servlet API还提供了一种简单的方法通过使用log()方法输出信息如下 :

// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class ContextLog extends HttpServlet {
   public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, java.io.IOException {
    
      String par = request.getParameter("par1");
      
      //Call the two ServletContext.log methods
      ServletContext context = getServletContext( );

      if (par == null || par.equals(""))
         //log version with Throwable parameter
         context.log("No message received:", new IllegalStateException("Missing parameter"));
      else
         context.log("Here is the visitor's message: " + par);
      
      response.setContentType("text/html");
      java.io.PrintWriter out = response.getWriter( );
      String title = "Context Log";
      String docType =
         "<!doctype html public -//w3c//dtd html 4.0 " + "transitional//en>\n";
      
      out.println(docType +
         "<html>\n" +
            "<head><title>" + title + "</title></head>\n" +
            "<body bgcolor = #f0f0f0>\n" +
               "<h1 align = center>" + title + "</h1>\n" +
               "<h2 align = center>Messages sent</h2>\n" +
            "</body>
         </html>"
      );
   } //doGet
}

ServletContext将其文本消息记录到servlet容器的日志文件中.使用Tomcat,可以在< Tomcat-installation-directory>/logs中找到这些日志.

日志文件确实指出了新出现的错误或问题的频率.因此,最好在异常的catch子句中使用log()函数,这通常不会发生.

使用JDB调试器

你可以使用用于调试applet或应用程序的相同jdb命令调试servlet.

要调试servlet,我们调试sun.servlet.http.HttpServer并仔细观察HttpServer执行servlet响应从浏览器发出的HTTP请求.这与applet的调试方式非常相似.不同之处在于,对于applet,正在调试的实际程序是sun.applet.AppletViewer.

大多数调试器通过自动知道如何调试applet来隐藏这个细节.在他们为servlet执行相同操作之前,您必须通过执行以下操作来帮助您的调试器;

  • 设置调试器的类路径这样它就可以找到sun.servlet.http.Http-Server和相关的类.

  • 设置调试器的类路径,这样它也可以找到你的servlet和支持类,通常是server_root/servlets和server_root/classes.

您通常不希望类路径中有server_root/servlets,因为它会禁用servlet重装.但是,这种包含对于调试很有用.它允许调试器在HttpServer中的自定义servlet加载器加载servlet之前在servlet中设置断点.

一旦设置了正确的类路径,就开始调试sun.servlet.http.HttpServer.您可以在任何您想调试的servlet中设置断点,然后使用Web浏览器向HttpServer请求给定的servlet(http://localhost:8080/servlet/ServletToDebug).您应该看到在断点处停止执行.

使用注释

代码中的注释可以通过各种方式帮助调试过程.在调试过程中,可以通过许多其他方式使用注释.

Servlet使用Java注释和单行(//...)和多行(/* ... */)注释可用于临时删除部分Java代码.如果错误消失,请仔细查看您刚评论的代码并找出问题.

客户端和服务器标头

有时候servlet没有按预期运行,查看原始HTTP请求和响应很有用.如果您熟悉HTTP的结构,则可以阅读请求和响应,并确切了解这些标头的确切内容.

重要的调试提示

下面列出了一些关于servlet调试的更多调试技巧 :

  • 请记住server_root/classes不重新加载,server_root/servlets可能会这样做.

  • 要求浏览器显示它正在显示的页面的原始内容.这有助于识别格式问题.它通常是View菜单下的一个选项.

  • 确保浏览器没有通过强制完全重新加载页面来缓存先前请求的输出.使用Netscape Navigator,使用Shift-Reload;使用Shift-Refresh.使用Shift-Refresh.

  • 验证servlet的init()方法是否采用ServletConfig参数并立即调用super.init(config).