通过Servlet3.0添加对异步的支持实现后台推送

本例参考:http://blog.csdn.NET/chenxiang0207/article/details/14054681/

http://blog.csdn.net/u010497228/article/details/43387575   

感谢上面的两位大佬,转载只是为了方便浏览。


我按照上面博文的思路重新走了一遍

项目结构如下图



[html] view plain copy
  1. /**  
  2.  * AsyncServlet  
  3.  *   
  4.  * 支持异步处理的Servlet  
  5.  * 页面中隐藏的iframe通过访问此Servlet来建立HTTP长连接  
  6.  * 从而后台能实时的推送javascript代码给页面调用  
  7.  *  
  8.  */  
  9. @WebServlet(urlPatterns = "/Async"asyncSupported = true)  
  10. public class AsyncServlet extends HttpServlet {  
  11.   
  12.     private static final long serialVersionUID = 822178713133426493L;  
  13.     private final static int DEFAULT_TIME_OUT = 10 * 60 * 1000;  
  14.   
  15.     @Override  
  16.     protected void doGet(HttpServletRequest req, HttpServletResponse res) {  
  17.         AsyncContext actx = req.startAsync();  
  18.         actx.setTimeout(DEFAULT_TIME_OUT);  
  19.         actx.addListener(new AsyncListener() {  
  20.   
  21.             @Override  
  22.             public void onComplete(AsyncEvent arg0) throws IOException {  
  23.                 // TODO Auto-generated method stub  
  24.                 ClientComet.getInstance().removeAsyncContext(actx);  
  25.                 System.out.println("AsyncListener-->onComplete");  
  26.             }  
  27.   
  28.             @Override  
  29.             public void onError(AsyncEvent arg0) throws IOException {  
  30.                 // TODO Auto-generated method stub  
  31.                 ClientComet.getInstance().removeAsyncContext(actx);  
  32.                 System.out.println("AsyncListener-->onError");  
  33.             }  
  34.   
  35.             @Override  
  36.             public void onStartAsync(AsyncEvent arg0) throws IOException {  
  37.                 // TODO Auto-generated method stub  
  38.                 System.out.println("AsyncListener-->onStartAsync");  
  39.             }  
  40.   
  41.             @Override  
  42.             public void onTimeout(AsyncEvent arg0) throws IOException {  
  43.                 // TODO Auto-generated method stub  
  44.                 ClientComet.getInstance().removeAsyncContext(actx);  
  45.                 System.out.println("AsyncListener-->onTimeout");  
  46.             }  
  47.   
  48.         });  
  49.         ClientComet.getInstance().addAsyncContext(actx);  
  50.     }  
  51. }  

[java] view plain copy
  1. /** 
  2.  * ClientComet 
  3.  *  
  4.  * 管理用户的AsyncContext(添加、删除) 
  5.  *  
  6.  * 通过开启一个线程来不断地从mesgQueue获取javascript 并遍历用户的AsyncContext来吧javascript推送给每个用户 
  7.  * 
  8.  */  
  9. public class ClientComet {  
  10.     private static ClientComet instance;  
  11.     private ConcurrentLinkedQueue<AsyncContext> actxQueue;  
  12.     private LinkedBlockingQueue<Javascript> mesgQueue;  
  13.   
  14.     private ClientComet() {  
  15.         actxQueue = new ConcurrentLinkedQueue<AsyncContext>();  
  16.         mesgQueue = new LinkedBlockingQueue<Javascript>();  
  17.         new ClientCometThread().start();  
  18.     }  
  19.   
  20.     public static ClientComet getInstance() {  
  21.         if (instance == null) {  
  22.             instance = new ClientComet();  
  23.         }  
  24.         return instance;  
  25.     }  
  26.   
  27.     public void addAsyncContext(AsyncContext actx) {  
  28.         actxQueue.add(actx);  
  29.     }  
  30.   
  31.     public void removeAsyncContext(AsyncContext actx) {  
  32.         actxQueue.remove();  
  33.     }  
  34.   
  35.     public void callClient(Javascript javascript) {  
  36.         mesgQueue.add(javascript);  
  37.     }  
  38.   
  39.     protected class ClientCometThread extends Thread {  
  40.   
  41.         @Override  
  42.         public void run() {  
  43.             while (true) {  
  44.                 try {  
  45.                     Javascript javascript = mesgQueue.take();  
  46.                     for (AsyncContext actx : actxQueue) {  
  47.                         PrintWriter writer = actx.getResponse().getWriter();  
  48.                         writer.write(javascript.getScript());  
  49.                         writer.flush();  
  50.                         System.out  
  51.                                 .println("ClientCometThread-->sendJavaScript");  
  52.                     }  
  53.                 } catch (InterruptedException | IOException e) {  
  54.                     // TODO Auto-generated catch block  
  55.                     e.printStackTrace();  
  56.                 }  
  57.   
  58.             }  
  59.         }  
  60.     }  
  61.   
  62. }  

[java] view plain copy
  1. /** 
  2.  * Javascript 
  3.  * 
  4.  * 提供将javascript的方法调用补全到一个script标签中的功能 
  5.  */  
  6. public class Javascript {  
  7.     private String script;  
  8.   
  9.     public Javascript(String func) {  
  10.         script = "<script type='text/javascript'>" + "\n" + "window.parent."  
  11.                 + func + "\n" + "</script>" + "\n";  
  12.     }  
  13.   
  14.     public String getScript() {  
  15.         return script;  
  16.     }  
  17. }  

[java] view plain copy
  1. /** 
  2.  * TestServlet 
  3.  *  
  4.  * 访问此Servlet能够给ClientComet的mesgQueue添加对象 
  5.  * 
  6.  */  
  7. @WebServlet(urlPatterns = "/Test")  
  8. public class TestServlet extends HttpServlet {  
  9.   
  10.     private static final long serialVersionUID = -7817902387051107187L;  
  11.   
  12.     @Override  
  13.     protected void doGet(HttpServletRequest req, HttpServletResponse res) {  
  14.         int times = 5;  
  15.         while (--times >= 0) {  
  16.             try {  
  17.                 Thread.sleep(5000);  
  18.                 ClientComet.getInstance().callClient(  
  19.                         new Javascript("append(" + "\'"  
  20.                                 + new Date().toGMTString() + "\'" + ")"));  
  21.                 System.out.println("TestServlet-->callClient");  
  22.             } catch (InterruptedException e) {  
  23.                 // TODO Auto-generated catch block  
  24.                 e.printStackTrace();  
  25.             }  
  26.         }  
  27.     }  
  28. }  

[html] view plain copy
  1. Comet.jsp  
  2.   
  3. <%@ page language="java" contentType="text/html; charset=utf-8"  
  4.     pageEncoding="utf-8"%>  
  5. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  6. <html>  
  7. <head>  
  8. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
  9. <title>Comet Test</title>  
  10. <script type='text/javascript'>  
  11.     function append(str) {  
  12.         var textField = document.getElementById("textField");  
  13.         textField.innerHTML = textField.innerHTML + str + "<br/>";  
  14.     };  
  15. </script>  
  16. </head>  
  17. <body>  
  18.     <!-- textField——用来显示服务器推送的内容 -->  
  19.     <p id="textField"></p>  
  20.     <!-- cometFrame——隐藏的iframe,用来访问AsyncServlet,建立长连接(注意,这样做window.onload的函数将失效,或直到此连接断开才执行) -->  
  21.     <iframe id="cometFrame" style="display: none;" src="/CometTest/Async"></iframe>  
  22. </body>  
  23. </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

阅读更多

没有更多推荐了,返回首页