2012-08-02 3 views
0

pdf 생성 요청을 처리하는 데 약 10 분이 소요되는 서버에서 장기 실행 프로세스에 대한 솔루션을 구현하려고합니다. 5 분에 브라우저가 지루하거나 시간 초과되었습니다. 나는 Ajax와 쓰레드를 사용하여 이것을 처리하려고 생각했다. 나는 아약스를위한 정규 자바 스크립트를 사용하고있다. 그러나 나는 그것에 매달렸다.Ajax 및 스레드를 사용하여 서버에서 장기 실행 jsp 요청 처리

나는 그것이 서블릿에 요청을 전송하고 서블릿이 thread.Please이

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

그러나 아래의 코드 여기

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 호출이를보고 시작하는 지점까지 도달 스레드가 프로세스가 완료되었고 어떻게 AJAX가 호출하여 요청 상태를 확인해야하는지 브라우저와 통신하는 방법을 더 진행하는 방법을 알지 못합니다.

일부 자료가 누락 되었다면 알려주십시오. 유용한 경우 제안.

답변

0

Servlet 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 
     } 
    }   
} 

Asynchronous Support in Servlet 3.0 참조 : 여기

은 샘플 코드입니다.

라이브러리를 사용할 수도 있으며 매우 잘 작동합니다.

+0

대단히 감사합니다. 문제는 내가 서블릿 3.0을 사용할 자유가 없다는 것입니다. 레거시 애플리케이션이며 전체 시스템은 다시 구현됩니다. 서블릿 2.x에 충실해야 할 것입니다 : ( –

+0

@ JohnBlue :이 경우 주기적으로 백그라운드 프로세스 상태를 확인할 수 있습니다 - 약간 번거롭지만 작동하는 것으로 확인되었습니다 –

+0

물론 같은 생각입니다. 서블릿과 long 프로세스 스레드 간의 스레드 조합 및 AJAX에서의 폴링 중간 화면을 도입해야합니까? –

1

Jetty 9.0 배포에는 비동기 서블릿과 자바 스크립트 클라이언트가 함께 포함 된 긴 폴링 채팅 예제가 포함되어 있습니다. 폴링 요청은 클라이언트에 의해 시작되어 서블릿이 의도적으로 선택된 간격으로 시간 초과되는 비동기 루프를 시작하게합니다. 일부 브라우저는 오랜 시간 동안 지속되지만 일부 브라우저는 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(); 
    } 
} 

기본적으로 "poll"동작으로 클라이언트에 전송 된 모든 응답은 클라이언트가 자동으로 다시 연결하게하는 효과가 있습니다. 정말 잘 작동하는 것 같아서, 당신은 그것을 확인하고 싶어 할 것입니다.

관련 문제