/**
* Copyright (c) 2005-2012 https://github.com/zhangkaitao
*
* Licensed under the Apache License, Version 2.0 (the "License");
*/
package com.sishuok.chapter3.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* streaming
*
* spring mvc没有提供streaming实现,所以此处需要还原到原始做法上
*
* 如下代码直接复制在chapter3下的com.sishuok.chapter3.web.servlet.AsyncServlet3
*
* <p>User: Zhang Kaitao
* <p>Date: 13-7-18 下午8:05
* <p>Version: 1.0
*/
@Controller
public class StreamingController {
private final Queue<AsyncContext> queue = new ConcurrentLinkedQueue();
{
new Thread(new Runnable() {
@Override
public void run() {
//模拟推送消息,主要实现方式两种方式:长轮询 + iframe长连接,具体自己搜索,本系列不介绍这些内容
while (true) {
//一秒执行一次
try {
Thread.sleep(5L * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//注意这种方式不能用于实际环境,因为没有考虑过期情况 所以每刷新一次页面会创建一个新的AsyncContext
Iterator<AsyncContext> iter = queue.iterator();
while (iter.hasNext()) {
AsyncContext asyncContext = iter.next();
//此处应该判断超时时间,如果超时了 直接移除即可
try {
ServletResponse response = asyncContext.getResponse();
PrintWriter out = response.getWriter();
String msg = "new message : " + System.currentTimeMillis();
out.write("<script>parent.callback('" + msg + "');</script>");
try {
response.flushBuffer();
} catch (IOException e) {
//远程主机可能强制关闭一个链接 直接把连接移除
iter.remove();
asyncContext.complete();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// System.out.println("push message count : " + queue.size());
}
}
}).start();
}
@RequestMapping("/async3")
public void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("Connection", "Keep-Alive");
resp.addHeader("Cache-Control", "private");
resp.addHeader("Pragma", "no-cache");
resp.setContentType("text/html;charset=utf-8");
resp.flushBuffer();
//1、开启异步
final AsyncContext asyncContext = req.startAsync();
asyncContext.addListener(new AsyncListener() {
@Override
public void onComplete(final AsyncEvent event) throws IOException {
queue.remove(event.getAsyncContext());
}
@Override
public void onTimeout(final AsyncEvent event) throws IOException {
event.getAsyncContext().complete();
queue.remove(event.getAsyncContext());
}
@Override
public void onError(final AsyncEvent event) throws IOException {
queue.remove(event.getAsyncContext());
}
@Override
public void onStartAsync(final AsyncEvent event) throws IOException {
}
});
//将异步上下文加入到队列中,这样在未来可以推送消息
queue.add(asyncContext);
}
}