0

pdf生成リクエストの処理に約10分かかるサーバーで、長時間実行されるプロセスのソリューションを実装しようとしています。ブラウザは5分で退屈/タイムアウトしました。私はAjaxとスレッドを使用してこれに対処することを考えていました。私はajaxに通常のJavaScriptを使用しています。しかし、私はそれに固執しています。

リクエストがサーブレットに送信され、サーブレットがスレッドを開始するところまで到達しました。以下のコードを参照してください。

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 ディストリビューションには、長いポーリング チャットの例が含まれています。これには、連携して動作する非同期サーブレットと JavaScript クライアントが含まれています。クライアントがポーリング要求を開始すると、サーブレットは、選択した間隔で意図的にタイムアウトする非同期ループを開始します。一部のブラウザーは長時間持続しますが、30 秒しか持続しないブラウザーもあります。そのため、タイムアウトを 30 秒未満に設定することをお勧めします。サーブレットがタイムアウトすると、クライアントにシグナルが送信され、クライアントは別のポーリングを開始します。データは応答を介していつでも送信でき、クライアントはその後、必要に応じて簡単に再接続できます。これには、サーバーからクライアントへのオープン チャネルを確立する効果があります。

// 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

サーブレット 3.0 非同期処理またはのような既存のライブラリを使用できます (下でサーブレット 3.0 を使用)。

アイデアは、サーブレットを呼び出して開始すること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 に答える