HTTP长连接。在index.html,发起一个异步请求。在请求的Servlet里,把当前sessionId和线程加入到映射列表中,然后把当前线程wait()。在其他人登陆或者发消息的时候,让映射里的所有线程notify(),notify()之后会返回一些数据到页面,页面接收处理之后,再次发起一个新的请求。
1.Constants.java,存储会话,消息,会话线程映射集合.
package com.rx.chart.common; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 公共属性 * * @author Renxin * */ public class Constants { /** * Session集合 */ public static List<String> users = new ArrayList<String>(); /** * 消息集合 */ public static List<String> messages = new ArrayList<String>(); /** * 会话线程映射 * Key:SessionId * Value:Thread */ public static Map<String, Thread> sessionThreadMapping = new HashMap<String, Thread>(); }
2.SessionListener.java,监听Session的创建和销毁,维护会话列表.
package com.rx.chart.listener; import static com.rx.chart.common.Constants.users; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import com.rx.chart.util.Util; /** * Session监听器 * * @author Renxin * */ public class SessionListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent httpsessionevent) { // 加入到Session集合 users.add(httpsessionevent.getSession().getId()); // 唤醒全部更新列表 Util.wakeUpAllThread(); } public void sessionDestroyed(HttpSessionEvent httpsessionevent) { // 从Session集合移除 users.remove(httpsessionevent.getSession().getId()); // 唤醒全部更新列表 Util.wakeUpAllThread(); } }
3.Initialization.java,获取用户列表和消息列表
package com.rx.chart.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.rx.chart.util.Util; /** * 初始化 * * @author Renxin * */ public class Initialization extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 返回消息 Util.out(response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
4.RefreshUserList.java,长连接刷新信息.
package com.rx.chart.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.rx.chart.common.Constants; import com.rx.chart.util.Util; /** * 刷新 * * @author Renxin * */ public class RefreshUserList extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); // 加入映射 Constants.sessionThreadMapping.put(session.getId(), Thread .currentThread()); // 当前线程等待 try { synchronized (Thread.currentThread()) { Thread.currentThread().wait(); } } catch (InterruptedException e) { e.printStackTrace(); } // 返回消息 Util.out(response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
5.SendMessage,发送消息.
package com.rx.chart.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.rx.chart.common.Constants; import com.rx.chart.util.Util; /** * 发送消息 * * @author Renxin * */ public class SendMessage extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); String message = request.getParameter("message"); message = session.getId() + ":" + message; Constants.messages.add(message); // 唤醒全部更新列表 Util.wakeUpAllThread(); // 返回消息 Util.out(response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
6.Util,工具类.
package com.rx.chart.util; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import com.rx.chart.common.Constants; import flexjson.JSONSerializer; /** * 工具类 * * @author Renxin * */ public class Util { /** * 唤醒全部 */ public static void wakeUpAllThread() { Iterator<Map.Entry<String, Thread>> iterator = Constants.sessionThreadMapping .entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Thread> entry = iterator.next(); Thread thread = entry.getValue(); synchronized (thread) { thread.notify(); } } } /** * 唤醒指定 * * @param sessionId */ public static void wakeUpAllThread(String sessionId) { Iterator<Map.Entry<String, Thread>> iterator = Constants.sessionThreadMapping .entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Thread> entry = iterator.next(); if (sessionId.equals(entry.getKey())) { Thread thread = entry.getValue(); synchronized (thread) { thread.notify(); } } } } /** * 输出用户列表 * * @param response * @throws IOException */ public static void out(HttpServletResponse response) throws IOException { Map<String, List<String>> map = new HashMap<String, List<String>>(); map.put("users", Constants.users); map.put("messages", Constants.messages); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.print(new JSONSerializer().serialize(map)); out.flush(); out.close(); } }
7.页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>首页</title> <script type="text/javascript" src="js/jquery-1.7.1.min.js"> </script> </head> <body> <div> <div> <h2> 用户列表 </h2> </div> <div id="userList"></div> </div> <div> <div> <h2> 消息列表 </h2> </div> <div id="messageList"></div> </div> <div> <input type="text" id="message" /> <input type="button" value="发送" onclick="subMsg();" /> </div> </body> </html> <script type="text/javascript"> //处理内容 function handlerContent(content) { eval('var c=' + content); if (c.users) { var html; html = '<ul>'; for ( var u in c.users) { html += '<li>'; html += c.users[u]; html += '</li>'; } html += '</ul>'; $('#userList').html(html); } if (c.messages) { var html; html = '<ul>'; for ( var m in c.messages) { html += '<li>'; html += c.messages[m]; html += '</li>'; } html += '</ul>'; $('#messageList').html(html); } } //发消息 function subMsg() { $.post('SendMessage', { 'message' : $('#message').val() }, function(content) { handlerContent(content); }); $('#message').val(''); } //初始化 function init() { $.post('Initialization', function(content) { handlerContent(content); refreshUserList(); }); } //刷新列表 function refreshUserList() { $.post('RefreshUserList', function(content) { handlerContent(content); refreshUserList(); }); } window.onload = init(); </script>