【发布时间】:2015-07-27 12:06:58
【问题描述】:
我有一个映射到 URL 的 servlet,它执行一项很长的任务并在工作时输出一些数据。
我想做的是调用这个 url 并实时查看输出。
我们以这个为例:
package com.tasks;
public class LongTaskWithOutput extends HttpServlet {
private static final long serialVersionUID = 2945022862538743411L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.addHeader("Content-Type", "text/plain");
PrintStream out = new PrintStream(response.getOutputStream(), true);
for(int i=0; i<10;i++) {
out.println("# " + i);
out.flush();
try {
Thread.sleep(1000);
} catch(Exception e){}
}
}
}
在web.xml:
...
<servlet>
<servlet-name>LongTaskServlet</servlet-name>
<servlet-class>com.tasks.LongTaskWithOutput</servlet-class>
<description>Long Task Servlet</description>
</servlet>
<servlet-mapping>
<servlet-name>LongTaskServlet</servlet-name>
<url-pattern>/longTask</url-pattern>
</servlet-mapping>
...
会发生什么
如果我浏览localhost/myApp/longTask,浏览器会让我等待 10 秒,然后立即打印出所有文本。
会发生什么
文本一写入输出流就应该发送到浏览器,并且浏览器应该每秒渲染一行。
如您所见,我已经放了一个out.flush() 以确保流每秒刷新一次,但它仍然不起作用。
我也尝试了response.flushBuffer(),但结果相同。
有没有办法做到这一点?
更新
正如@MadConan 建议的那样,我尝试直接使用输出流:
OutputStream out = response.getOutputStream();
for(int i=0; i<10;i++) {
out.write(("# " + i + "\n").getBytes());
out.flush();
try {
Thread.sleep(1000);
} catch(Exception e){}
}
不幸的是,结果还是一样。
【问题讨论】:
-
从
response.getOutputStream()获取的OutputStream具体实现是什么? -
@MadConan 对于第一点,请查看更新。对于第二点,实现是
org.apache.catalina.connector.CoyoteOutputStream(我用的是tomcat) -
我的直觉告诉我,这与您在缓冲区中放入的数据量有关,但如果不查看底层流的代码,我无法知道。即便如此,何时发送和使用数据最终取决于服务器和客户端的操作系统。
-
我跟着弹跳球上了这堂课。并不是说它真的有帮助。 grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/…
-
您使用的是哪个版本的 Java EE?如果您使用的是 java-ee 7,则可以利用异步处理和非阻塞 I/O(如果不启用异步处理,这将无法工作)
标签: java jakarta-ee servlets output real-time