【问题标题】:tomcat - start thread in servlet and send responsetomcat - 在 servlet 中启动线程并发送响应
【发布时间】:2011-07-19 21:51:42
【问题描述】:

如何启动一个在后台运行但响应会立即发送给用户的线程?

我正在尝试从 Android 设备上传文件。虽然上传过程正常,但我想告诉用户,一旦文件从他端上传,该过程就完成了。

我检查了对 ServletFileUpload.parseRequest() 的调用需要很长时间。

        ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);

        List items = uploadHandler.parseRequest(request);

所以基本上我正在寻找一种方法来告诉用户“嘿,你已经完成了你的工作”,现在轮到 servlet 来完成所有处理了。

但我不能,因为 parseRequest 阻塞。

我错了,因为它实际上是由设备发送的,所以它阻塞了?

在安卓上上传:

        while (bytesRead > 0)
        {
            task.myPublishProgress(totalBytesRead, fileSize);

            dos.write(buffer, 0, bufferSize);

            bytesAvailable = fileInputStream.available();

            bufferSize = Math.min(bytesAvailable, maxBufferSize);

            bytesRead = fileInputStream.read(buffer, 0, bufferSize);

            totalBytesRead+= bytesRead;

        }

        // send multipart form data necesssary after file data...
        dos.writeBytes(lineEnd);

        dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

        // close streams

        fileInputStream.close();

        dos.flush();

        Log.i(TAG ,"Database file with name " + this.fileName + " has been successfully written");

        InputStream is = conn.getInputStream();

        // retrieve the response from server

        int ch;

        StringBuilder b = new StringBuilder();

        while( ( ch = is.read() ) != -1 ){
            b.append( (char)ch );
        }

        dos.close();

在服务器上处理:

                DiskFileItemFactory  fileItemFactory = new DiskFileItemFactory ();

            ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
            /*
             * Parse the request
             */
            System.out.println("parsing the request....");
            **List items = uploadHandler.parseRequest(request);**
            FileItem item = (FileItem) items.get(0);
            fileName = item.getName();

            File file = new File(destinationDir, fileName);
            item.write(file);

我希望 servlet 在 parseRequest 上不要太阻塞,而是可能在一个线程中处理它,并将响应发送给客户端。

谢谢

【问题讨论】:

  • 您能否提供更多详细信息,例如您想做什么以及您在哪里受到打击?
  • @anubhava 查看已编辑的问题。如果您想了解更多详情,请告诉我。
  • @kkudi:谢谢,我对 Android 编码了解不多,但设备向您的服务器发送 AJAX 请求是一种选择吗?这样您就不必在服务器端构建此解决方案。
  • 设备正在发送 HttpURLConnection,将数据写入服务器并等待响应。
  • 好的,在这种情况下,您可以选择使用异步 http 客户端吗?请查看github.com/AsyncHttpClient/async-http-client

标签: java android multithreading servlets httpclient


【解决方案1】:

这在标准 HTTP 中是不可能的。只有在请求正文被完全消耗后才能发送响应。只要不拨打uploadHandler.parseRequest(request);,文件就不会上传。如果你说“你完成了!”,那你就是在撒谎。在此之前。

只有在 调用uploadHandler.parseRequest(request) 并拥有物品之后,您才能诚实地告诉用户他已经完成了。然而,剩余部分可以完美地在单独的线程中完成。我建议为由ServletContextListener 管理的线程池创建一个固定的线程池。但是,我认为当您不使用上传的文件执行任何昂贵的任务时,这有点夸张。

至于具体问题(应用程序在忙于上传文件时似乎什么都不做),我宁愿建议在客户端解决问题。获取文件的大小,获取发送到输出流的字节数,然后在客户端显示一些进度条,以便客户端了解进度。

【讨论】:

  • 这正是我正在做的。我正在使用发送到输出流的字节显示进度对话框,但仅此而已。您自己说,如果我只是告诉用户仅通过更新上传过程已完成,我会撒谎文件已上传进度对话框使用写入输出流的字节数。这并不意味着上传过程已经成功,直到请求被消费并且响应已经发送给客户端。
  • 这不是真的。您似乎认为在调用 Servlet 的 doPost() 时所有文件都已发送到服务器端。这是不真实的。在您致电parseRequest() 之前,文件仍在客户端上。一旦您调用parseRequest(),服务器将开始读取带有上传文件的请求正文,从而开始真正的字节流。一旦parseRequest() 方法完成并且代码继续运行,所有文件都被读取。
  • 啊,我明白了!那么如何获取 parseRequest 实际处理的字节数呢?我用于进度对话框的唯一信息是读取到 DataOutputStream 的字节数,如客户端代码所示。
  • 创建一个HttpServletRequestWrapper,它将HttpServletRequest#getInputStream() 包装在CountingInputStream 中(你应该已经拥有的commons-io 的一部分)。在解析之前将它的引用存储在会话中,并在解析后将其删除。然后在某个 servlet 上触发 async/ajax 请求,该 servlet 在会话中检查它并返回状态。
猜你喜欢
  • 1970-01-01
  • 2011-09-21
  • 2018-02-07
  • 1970-01-01
  • 1970-01-01
  • 2012-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多