本例参考:http://blog.csdn.NET/chenxiang0207/article/details/14054681/
http://blog.csdn.net/u010497228/article/details/43387575
感谢上面的两位大佬,转载只是为了方便浏览。
我按照上面博文的思路重新走了一遍
项目结构如下图
- /**
- * AsyncServlet
- *
- * 支持异步处理的Servlet
- * 页面中隐藏的iframe通过访问此Servlet来建立HTTP长连接
- * 从而后台能实时的推送javascript代码给页面调用
- *
- */
- @WebServlet(urlPatterns = "/Async", asyncSupported = true)
- public class AsyncServlet extends HttpServlet {
- private static final long serialVersionUID = 822178713133426493L;
- private final static int DEFAULT_TIME_OUT = 10 * 60 * 1000;
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse res) {
- AsyncContext actx = req.startAsync();
- actx.setTimeout(DEFAULT_TIME_OUT);
- actx.addListener(new AsyncListener() {
- @Override
- public void onComplete(AsyncEvent arg0) throws IOException {
- // TODO Auto-generated method stub
- ClientComet.getInstance().removeAsyncContext(actx);
- System.out.println("AsyncListener-->onComplete");
- }
- @Override
- public void onError(AsyncEvent arg0) throws IOException {
- // TODO Auto-generated method stub
- ClientComet.getInstance().removeAsyncContext(actx);
- System.out.println("AsyncListener-->onError");
- }
- @Override
- public void onStartAsync(AsyncEvent arg0) throws IOException {
- // TODO Auto-generated method stub
- System.out.println("AsyncListener-->onStartAsync");
- }
- @Override
- public void onTimeout(AsyncEvent arg0) throws IOException {
- // TODO Auto-generated method stub
- ClientComet.getInstance().removeAsyncContext(actx);
- System.out.println("AsyncListener-->onTimeout");
- }
- });
- ClientComet.getInstance().addAsyncContext(actx);
- }
- }
- /**
- * ClientComet
- *
- * 管理用户的AsyncContext(添加、删除)
- *
- * 通过开启一个线程来不断地从mesgQueue获取javascript 并遍历用户的AsyncContext来吧javascript推送给每个用户
- *
- */
- public class ClientComet {
- private static ClientComet instance;
- private ConcurrentLinkedQueue<AsyncContext> actxQueue;
- private LinkedBlockingQueue<Javascript> mesgQueue;
- private ClientComet() {
- actxQueue = new ConcurrentLinkedQueue<AsyncContext>();
- mesgQueue = new LinkedBlockingQueue<Javascript>();
- new ClientCometThread().start();
- }
- public static ClientComet getInstance() {
- if (instance == null) {
- instance = new ClientComet();
- }
- return instance;
- }
- public void addAsyncContext(AsyncContext actx) {
- actxQueue.add(actx);
- }
- public void removeAsyncContext(AsyncContext actx) {
- actxQueue.remove();
- }
- public void callClient(Javascript javascript) {
- mesgQueue.add(javascript);
- }
- protected class ClientCometThread extends Thread {
- @Override
- public void run() {
- while (true) {
- try {
- Javascript javascript = mesgQueue.take();
- for (AsyncContext actx : actxQueue) {
- PrintWriter writer = actx.getResponse().getWriter();
- writer.write(javascript.getScript());
- writer.flush();
- System.out
- .println("ClientCometThread-->sendJavaScript");
- }
- } catch (InterruptedException | IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
- }
- /**
- * Javascript
- *
- * 提供将javascript的方法调用补全到一个script标签中的功能
- */
- public class Javascript {
- private String script;
- public Javascript(String func) {
- script = "<script type='text/javascript'>" + "\n" + "window.parent."
- + func + "\n" + "</script>" + "\n";
- }
- public String getScript() {
- return script;
- }
- }
- /**
- * TestServlet
- *
- * 访问此Servlet能够给ClientComet的mesgQueue添加对象
- *
- */
- @WebServlet(urlPatterns = "/Test")
- public class TestServlet extends HttpServlet {
- private static final long serialVersionUID = -7817902387051107187L;
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse res) {
- int times = 5;
- while (--times >= 0) {
- try {
- Thread.sleep(5000);
- ClientComet.getInstance().callClient(
- new Javascript("append(" + "\'"
- + new Date().toGMTString() + "\'" + ")"));
- System.out.println("TestServlet-->callClient");
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
- Comet.jsp
- <%@ page language="java" contentType="text/html; charset=utf-8"
- pageEncoding="utf-8"%>
- <!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=utf-8">
- <title>Comet Test</title>
- <script type='text/javascript'>
- function append(str) {
- var textField = document.getElementById("textField");
- textField.innerHTML = textField.innerHTML + str + "<br/>";
- };
- </script>
- </head>
- <body>
- <!-- textField——用来显示服务器推送的内容 -->
- <p id="textField"></p>
- <!-- cometFrame——隐藏的iframe,用来访问AsyncServlet,建立长连接(注意,这样做window.onload的函数将失效,或直到此连接断开才执行) -->
- <iframe id="cometFrame" style="display: none;" src="/CometTest/Async"></iframe>
- </body>
- </html>
开启Tomcat
开启一个页面A先访问http://localhost:8080/CometTest/Comet.jsp
再打开一个新的页面B访问http://localhost:8080/CometTest/Test
此时能够看到A的内容不断的增加
PS:若想让onload函数不失效可以把对iframe的src的赋值操作放在onload中,而一开始src为空
项目打包:http://download.csdn.net/detail/u010497228/8415545