Servlet - 调试


测试/调试 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,实际被调试的程序是 sun.applet.AppletViewer。

大多数调试器通过自动了解如何调试小程序来隐藏此细节。在它们对 servlet 执行相同操作之前,您必须通过执行以下操作来帮助您的调试器 -

  • 设置调试器的类路径,以便它可以找到 sun.servlet.http.Http-Server 和关联的类。

  • 设置调试器的类路径,以便它也可以找到您的 servlet 和支持类,通常是 server_root/servlet 和 server_root/classes。

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

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

使用注释

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

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

客户端和服务器标头

有时,当 servlet 的Behave不符合预期时,查看原始 HTTP 请求和响应会很有用。如果您熟悉 HTTP 的结构,则可以读取请求和响应,并准确了解这些标头的具体情况。

重要的调试技巧

以下是有关 servlet 调试的更多调试技巧的列表 -

  • 请记住,server_root/classes 不会重新加载,而 server_root/servlets 可能会重新加载。

  • 要求浏览器显示其正在显示的页面的原始内容。这可以帮助识别格式问题。它通常是“视图”菜单下的一个选项。

  • 通过强制完全重新加载页面,确保浏览器不会缓存先前请求的输出。对于 Netscape Navigator,请使用 Shift-Reload;对于 Internet Explorer,请使用 Shift-Refresh。

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