0

我正在尝试在服务器上为长时间运行的进程实施解决方案,在该服务器上处理 pdf 生成请求大约需要 10 分钟。浏览器在 5 分钟内无聊/超时。我正在考虑使用 Ajax 和线程来处理这个问题。我正在为 ajax 使用常规 javascript。但我坚持下去。

我已经到达了将请求发送到 servlet 并且 servlet 启动线程的地步。请参阅下面的代码

public class HelloServlet extends javax.servlet.http.HttpServlet 
     implements javax.servlet.Servlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {      
    }   

    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
        System.out.println("POST request!!");
        LongProcess longProcess = new LongProcess();
        longProcess.setDaemon(true);
        longProcess.start();
        request.getSession().setAttribute("longProcess", longProcess);
        request.getRequestDispatcher("index.jsp").forward(request, response);
    }   
 }

    class LongProcess extends Thread {

        public void run() {
            System.out.println("Thread Started!!");
            while (progress < 10) {             
                try { sleep(2000); } catch (InterruptedException ignore) {}
                progress++;
            }
        }           
    }

这是我的 AJax 调用

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>My Title</title>
<script language="JavaScript" >
function getXMLObject()  //XML OBJECT
    {
       var xmlHttp = false;
         xmlHttp = new XMLHttpRequest();        //For Mozilla, Opera Browsers
       return xmlHttp;  // Mandatory Statement returning the ajax object created
    }

    var xmlhttp = new getXMLObject();   //xmlhttp holds the ajax object

    function ajaxFunction() {
        xmlhttp.open("GET","HelloServlet" ,true);
        xmlhttp.onreadystatechange  = handleServerResponse;
        xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xmlhttp.send(null);
      }

    function handleServerResponse() {
       if (xmlhttp.readyState == 4) {
         if(xmlhttp.status == 200) {           
           document.forms[0].myDiv.value = xmlhttp.responseText;
           setTimeout(ajaxFunction(), 2000);
         }
         else {
            alert("Error during AJAX call. Please try again");
         }
       }
    }
    function openPDF() {    
           document.forms[0].method = "POST";
        document.forms[0].action = "HelloServlet";
        document.forms[0].submit();     
    }
    function stopAjax(){
         clearInterval(intervalID);
     }
</script>
</head> 
<body><form name="myForm">
<table><tr><td>
<INPUT TYPE="BUTTON" NAME="Download" VALUE="Download Queue ( PDF )" onclick="openPDF();">
</td></tr>
<tr><td>
Current status: <div id="myDiv"></div>%
</td></tr></table>
</form></body></html>

但我不知道如何进一步进行,例如线程如何与浏览器通信该进程已完成,以及 ajax 应如何调用我并检查请求的状态。

如果我遗漏了一些片段,请告诉我。任何建议,如果有帮助。

4

2 回答 2

1

Jetty 9.0 Distribution 包括一个长轮询聊天示例,其中包括协同工作的异步 servlet 和 javascript 客户端。轮询请求由客户端发起,这会导致 servlet 启动一个异步循环,该循环故意以选定的时间间隔超时。有些浏览器可以持续很长时间,但有些只能持续 30 秒。因此,建议将超时设置为小于 30 秒。当 servlet 超时时,它会向客户端发送一个信号,导致客户端启动另一个轮询。可以通过响应随时发送数据,并且客户端可以在必要时再次连接。这具有建立从服务器到客户端的开放通道的效果。

// This starts an async request
AsyncContext asyncCtx = request.startAsync();
asyncCtx.setTimeout(10000);   // 10 seconds
asyncCtx.addListener(member);

// This is the timeout handler which tells the client to continue to poll
@Override
public void onTimeout(AsyncEvent event) throws IOException {
    System.out.println("Client onTimeout\r\n");
    AsyncContext asyncCtx = asyncCtxAtomRef.get();
    if ((asyncCtx != null) && asyncCtxAtomRef.compareAndSet(asyncCtx, null))
    {
        HttpServletResponse response = (HttpServletResponse)asyncCtx.getResponse();
        response.setContentType("text/json;charset=utf-8");
        PrintWriter out=response.getWriter();
        out.print("{action:\"poll\"}");
        asyncCtx.complete();
    }
}

本质上,任何以“轮询”动作发送给客户端的响应都会导致客户端自动重新连接。它似乎工作得很好,所以你可能想检查一下。

于 2012-12-12T04:54:34.553 回答
0

您可以使用 Servlet 3.0 异步处理或现有的库,如(使用下面的 servlet 3.0)。

这个想法是调用 servlet 并启动AsyncContext。然后,您将该上下文传递给您的线程并使用它定期发送一些进度。在客户端读取这个流有点棘手,请参阅:jquery ajax, read the stream incrementally? 不要在线程访问原始HttpServletResponse文件,它不起作用。

这是一个示例代码:

@WebServlet("/hello" asyncSupported=true)
public class HelloServlet extends HttpServlet {
    public void doGet(HttpServletRequest req, HttpServletResponse res) {
        AsyncContext async = request.startAsync(req, res);
        LongProcess longProcess = new LongProcess();
        longProcess.setDaemon(true);
        longProcess.start();
    }
}

class LongProcess extends Thread {

    private final AsyncContext asyncContext;

    public LongProcess(AsyncContext asyncContext) {
        this.asyncContext = asyncContext;
    }

    public void run() {
        System.out.println("Thread Started!!");
        while (progress < 10) {             
            try { sleep(2000); } catch (InterruptedException ignore) {}
            progress++;
            //use asyncContext here to send progress to the client incrementally
        }
    }           
}

另请参阅Servlet 3.0 中的异步支持

您还可以使用库,它会为您完成并且效果很好。

于 2012-08-02T16:16:06.267 回答