2016-09-22 14 views
1

私の画像ファイルはデータベースに保存されています。 クライアント上でそれらをレンダリングできるようにするために、データベース列からバイナリストリームを読み込んでサーブレットレスポンスの出力ストリームに書き込むのに役立つ非同期サーブレットを実装しました。従来のIOはここでうまく動作します。非同期サーブレットとファイルをダウンロードするための非ブロックIOの使用方法は?

非ブロッキングIOを非同期サーブレット(パフォーマンスをテストする)で試してみたところ、応答に返されたバイナリデータは破損しています。

Oracle Blogから、非同期NIOサーブレットを使用したファイルアップロードのさまざまな例を見てきましたが、私の問題は助けになりません。

ここでは、サーブレットのコードがあります:

Response Data

私が間違って何をやっている:

@WebServlet(asyncSupported = true, urlPatterns = "/myDownloadServlet") 
public class FileRetrievalServletAsyncNIO extends HttpServlet 
{ 
    private static final long serialVersionUID = -6914766655133758332L; 

    @Override 
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
    { 
     Queue<byte[]> containerQueue = new LinkedList<byte[]>(); 

     AsyncContext asyncContext = request.startAsync(); 
     asyncContext.addListener(new AsyncListenerImpl()); 
     asyncContext.setTimeout(120000); 

     try 
     { 
      long attachmentId = Long.valueOf(request.getParameter("id")); 
      MyAttachmentDataObject retObj = ServletUtils.fetchAttachmentHeaders(attachmentId); 

      response = (HttpServletResponse) asyncContext.getResponse(); 
      response.setHeader("Content-Length", String.valueOf(retObj.getContentLength())); 
      if (Boolean.valueOf(request.getParameter(ServletConstants.REQ_PARAM_ENABLE_DOWNLOAD))) 
       response.setHeader("Content-disposition", "attachment; filename=" + retObj.getName()); 
      response.setContentType(retObj.getContentType()); 
      ServletOutputStream sos = response.getOutputStream(); 
      ServletUtils.fetchContentStreamInChunks(attachmentId, containerQueue); // reads from database and adds to the queue in chunks 
      sos.setWriteListener(new WriteListenerImpl(sos, containerQueue, asyncContext)); 
     } 
     catch (NumberFormatException | IOException exc) 
     { 
      exc.printStackTrace(); 
      request.setAttribute("message", "Failed"); 
     } 
    } 
} 

ここで応答データは次のようになり、ライトリスナーの実装

public class WriteListenerImpl implements WriteListener 
{ 

    private ServletOutputStream output = null; 
    private Queue<byte[]> queue = null; 
    private AsyncContext asyncContext = null; 
    private HttpServletRequest request = null; 
    private HttpServletResponse response = null; 

    public WriteListenerImpl(ServletOutputStream sos, Queue<byte[]> q, AsyncContext aCtx) 
    { 
     output = sos; 
     queue = q; 
     asyncContext = aCtx; 
     request = (HttpServletRequest) asyncContext.getRequest(); 
    } 

    @Override 
    public void onWritePossible() throws IOException 
    { 
     while(output.isReady()) 
     { 
      while (!queue.isEmpty()) 
      { 
       byte[] temp = queue.poll(); 
       output.write(temp, 0, temp.length); 
      } 

      asyncContext.complete(); 
      request.setAttribute("message", "Success"); 
     } 
    } 

    @Override 
    public void onError(Throwable t) 
    { 
     System.err.println(t); 
     try 
     { 
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 
     } 
     catch (IOException exc) 
     { 
      exc.printStackTrace(); 
     } 
     request.setAttribute("message", "Failure"); 
     asyncContext.complete(); 
    } 
} 

ですか?

答えて

0

出力がどのように表示されるかはっきりとは分かりませんが、非同期入出力に関しては、すべての書き込みの前にoutput.isReady()をチェックする必要があります。だからあなたのonWritePossibleコードは次のようになります。

while(output.isReady() && !queue.isEmpty()) 
{ 
     byte[] temp = queue.poll(); 
     output.write(temp, 0, temp.length); 
} 

if (queue.isEmpty()) { 
     asyncContext.complete(); 
     request.setAttribute("message", "Success"); 
} 

これは、書き込みは基本的に非同期のポイントI/OであるブロックさになるとonWritePossible()を返すことができます。

書き込みがブロックされたとき(output.isReady()がfalseを返す)、異なる実装は書き込みを無視するか、例外をスローすることがあります。どちらの方法でも、出力データに途中の書き込みが欠けているか、切り捨てられています。

+0

これはうまくいかなかった。ダウンロードしたファイルが不適切です。 – Chiranjib

+0

ファイルの問題は何ですか? async ioを使用しようとする前に、以前にファイルに書き込んだことはありますか? – mmulholl

+0

ファイルに問題はありません。ダウンロードは、非同期サーブレット+従来のIOで完璧に動作しています。何らかの理由で働いていないのはNIOだけです。 – Chiranjib

関連する問題