Java Servlet生成PDF,但有时调用行为会陷入困境

Java Servlet生成PDF,但有时调用行为会陷入困境,java,javascript,servlets,thread-safety,method-invocation,Java,Javascript,Servlets,Thread Safety,Method Invocation,servlet在最初生成的iframe中生成预览页面后生成PDF文档。这通常有效,如下所示: public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if ("directPrintDocumentDoIt".equals(request.getParameter("method"))) {

servlet在最初生成的iframe中生成预览页面后生成PDF文档。这通常有效,如下所示:

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if ("directPrintDocumentDoIt".equals(request.getParameter("method")))  {
            generatePDF(request, response);
        }
        if ("directPrintDocumentWaiting".equals(request.getParameter("method")))  {
            String queryString = request.getQueryString().replace("directPrintDocumentWaiting", "directPrintDocumentDoIt");
            renderWaiting(request, response, queryString);
        }
        if ("directPrintDocument".equals(request.getParameter("method")))  {
            String queryString = request.getQueryString().replace("directPrintDocument", "directPrintDocumentWaiting");
            renderIFrameWaiting(request, response, queryString);
        }
    }
        response.reset();
        response.setContentType("application/pdf");
        response.setContentLength(pdfContent.length);
        response.setHeader("Content-Disposition", "inline; filename=RANDOMFILE.pdf");
        response.addHeader("Accept-Ranges", "bytes");
        response.getOutputStream().write(pdfContent);
        response.getOutputStream().flush();
        response.getOutputStream().close(); 
首先调用“directPrintDocument”和方法“RenderFrameWaiting”,该方法生成iframe页面并将内容写入servlet响应(iframe src调用doPost的下一部分。我确信这不会产生错误,因此我省略了此代码片段)。然后调用“directPrintDocumentWaiting”和方法“renderWaiting”,该方法在先前生成的iframe页面中生成预览页面,而生成的javascript调用“directPrintDocumentDoIt”,最终生成PDF:

private void renderWaiting(HttpServletRequest request, HttpServletResponse response, String queryString) throws IOException  {
    StringBuffer output = new StringBuffer();
    response.setContentType("text/html; charset=ISO-8859-1");
    response.setHeader("Cache-Control", "no-cache");
    output.append("<html>\n");
    output.append("<head>\n");
    output.append("<meta http-equiv='Content-Type' content='text/html;charset=iso-8859-1'>\n");
    output.append("<meta http-equiv='expires' content='0'>\n");
    output.append("<meta http-equiv='cache-control' content='no-cache'>\n");
    output.append("<meta http-equiv='pragma' content='no-cache'>\n");
    output.append("</head>\n");
    output.append("<script type=\"text/javascript\">\n");
    output.append("function formSubmit() {\n");
    output.append("document.forms[0].target=\'_self\';\n");
    output.append("document.body.style.cursor = \"wait\";\n");
    output.append("var formAction = document.forms[0].action;\n");
    output.append("document.forms[0].submit();\n");
    output.append("}\n");
    output.append("</script>\n");
    output.append("<body onload=\"self.focus(); formSubmit();\">\n");
    output.append("<form name=\"druckenForm\" method=\"post\" action=\"" + request.getRequestURI() + "?" + queryString + "\" onsubmit=\"return false;\">\n");
    output.append("<p align=\"center\" valign=\"center\">Druck wird erzeugt...\n</p>\n");
    output.append("<p align=\"center\" valign=\"center\">Der erstmalige Start kann etwas l&auml;nger dauern.</p>\n");
    output.append("</form>\n");
    output.append("</body>\n");
    output.append("</html>");
    response.setContentLength(output.length());
    response.getOutputStream().write(output.toString().getBytes());
    response.getOutputStream().flush();
    response.getOutputStream().close();
}

线程id总是相同的,所以我怀疑这是否真的是线程问题。让我困惑的是,当这个错误发生时,fiddler会在javascript后期调用执行之后记录第四次调用。通常有3个调用(“directPrintDocument”、“directPrintDocumentWaiting”和“directPrintDocumentDoIt”)。当有4次调用时,它总是以相同的方式发生:“directPrintDocumentDoIt”将被调用两次(与POST请求相同的URL),但会作为GET请求突然被调用。我不知道这个GET请求来自哪里(在“generatePDF”中没有其他请求调用)。因此,要么javascript产生了一些奇怪的行为(但为什么很少),要么web容器(Websphere)产生了一些我不理解的奇怪行为。有趣的是,fiddler在第3次和第4次调用时显示了不同的实体大小。右后调用的实体大小为84.138字节。第四次调用(错误的调用)有83.883字节。我不知道这意味着什么,但也许这些信息是有用的。我觉得在我重新启动或发布到Websphere之后,这种错误会更频繁地发生。在这种情况下,它发生在第一次尝试(但并不总是)。这不可能是巧合。你知道这是怎么回事吗

显然,错误是由PDF编写器引起的。容易出错的代码如下所示:

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if ("directPrintDocumentDoIt".equals(request.getParameter("method")))  {
            generatePDF(request, response);
        }
        if ("directPrintDocumentWaiting".equals(request.getParameter("method")))  {
            String queryString = request.getQueryString().replace("directPrintDocumentWaiting", "directPrintDocumentDoIt");
            renderWaiting(request, response, queryString);
        }
        if ("directPrintDocument".equals(request.getParameter("method")))  {
            String queryString = request.getQueryString().replace("directPrintDocument", "directPrintDocumentWaiting");
            renderIFrameWaiting(request, response, queryString);
        }
    }
        response.reset();
        response.setContentType("application/pdf");
        response.setContentLength(pdfContent.length);
        response.setHeader("Content-Disposition", "inline; filename=RANDOMFILE.pdf");
        response.addHeader("Accept-Ranges", "bytes");
        response.getOutputStream().write(pdfContent);
        response.getOutputStream().flush();
        response.getOutputStream().close(); 
我不知道为什么,但有时这个标题会导致第二个请求。当我将其更改为以下内容时,在生成pdf后,我将不再看到白页。所以这似乎是解决办法

response.setContentType("application/pdf");
response.setContentLength(pdfContent.length);
response.getOutputStream().write(pdfContent);
response.getOutputStream().flush();
response.getOutputStream().close(); 

renderWaiting
在我看来,它不会生成预览。它生成一个自动提交表单。为什么需要这个步骤?为什么初始操作不能呈现指向PDF呈现操作的iframe?带有“p align”的两行生成“预览”。调用自动提交后,需要几秒钟才能生成pdf。在此期间,只要尚未生成PDF,客户端就会看到此页面。这就是为什么这一步很重要。如果你直接点击PDF URL,会发生什么。你有双重要求吗?此外,您在HTTP头和
标记中使用ISO8859-1,但随后使用
getBytes()
,这并不保证使用该编码。使用
getBytes(“ISO-8859-1”)
。好的,为了测试,我将省略第二次调用(带有预览的部分),直接调用directPrintDocumentDoIt。在第一次尝试时,PDF再次被空白页面覆盖,因此显然这不是javascript的错误,因为在这种情况下javascript没有被调用。不幸的是,我错过了“renderframewaiting”中的getBytes调用。在第一次测试中,我忘记了将其更改为getBytes(“ISO-8859-1”)。目前我正在用这个修改重新测试它。我还不能重现这个错误。如果这不是解决方案,则需要一些时间来复制。不幸的是,getBytes(“ISO-8859-1”)也不起作用。再一次,打印输出被一个空白页面覆盖(在我重新启动Websphere之后)。因此,在重新启动Websphere之后,这是我今天第三次遇到此错误。这不可能是巧合。