Servlet3.0 非同步處理 頁面推送 Comet 例項
阿新 • • 發佈:2019-01-24
本例參考:http://blog.csdn.net/chenxiang0207/article/details/14054681/
我按照上面博文的思路重新走了一遍
專案結構如下圖
/** * 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