webSocket簡介
webSocket是ajax輪詢與long pull方式的改進。ajax輪詢:每隔一段時間請求一次,不管有沒有新信息;long pull:每次請求之後,等到有新信息才會返回;webSocket:客戶端發送一次請求之後,只要有新信息,服務器就會主動把數據推送過去。
效果截圖
參考了網上的例子來實現聊天室,實驗樓的那個不錯!但是,打開兩個頁面卻不能真正的聊天,後面參考Tomcat下的ChatAnnotation.Java綜合兩者,才有了這個聊天室。
效果圖1:
效果圖2:
增加代碼
後臺代碼增加以下幾點:
- 1、在會話打開時,將對應的session添加到對應map中;
- 2、當發送消息時,遍歷整個map,然後對每個session發送消息;
- 3、關閉時,將對應的session從map中刪除,不再接收消息,並且如果此用戶有發送過消息,系統將提示該用戶已下線
/**
* 聊天服務器類
*
* @author yuechang
*
*/
@ServerEndpoint("/websocket")
public class ChatServer {
private Session session;
private static final Map<ChatServer, String> connections = new ConcurrentHashMap<ChatServer, String>();
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm"); // 日期格式化
/**
* @category 添加初始化操作
* @param session
*/
@OnOpen
public void open(Session session) {
// 開啟會話,將session存入map中,不過此時的nikename存入的為空字符串
this.session = session;
connections.put(this, "");
}
/**
* @category 接受客戶端的消息,並把消息發送給所有連接的會話
* @param message 客戶端發來的消息
* @param session 客戶端的會話
*/
@OnMessage
public void getMessage(String message, Session session) {
// 把客戶端的消息解析為JSON對象
JSONObject jsonObject = JSONObject.fromObject(message);
// 獲得昵稱
String nikename = (String) jsonObject.get("nickname");
// 存入map中
connections.put(this, nikename);
broadcast(message);
}
/**
* @category 添加關閉會話時的操作
* @param reason
*/
@OnClose
public void close(CloseReason reason) {
String nikename = connections.get(this);
// 下線時,得從總人數中移除,否則信息公布時找不到下線的session報錯的
connections.remove(this);
// 如果這個人有在聊天室中發過言,則向聊天室中發送nikename已下線消息
if (StringUtils.isNotBlank(nikename)) {
String msg = "{'content':'<p>用戶[ ".concat(nikename).concat(" ]下線了!<br/></p>','nickname':'系統消息'}");
broadcast(msg);// 這是告知所還在線聊天的人下線了
}
}
/**
* @category 添加處理錯誤的操作
* @param t
*/
@OnError
public void error(Throwable t) {
// 添加處理錯誤的操作
}
/**
* @category 廣播消息
* @param msg 消息JSON串
*/
private void broadcast(String msg) {
Iterator<ChatServer> iterator = connections.keySet().iterator();
while (iterator.hasNext()) {
ChatServer client = iterator.next();
synchronized (client) {
// 把客戶端的消息解析為JSON對象
JSONObject jsonObject = JSONObject.fromObject(msg);
// 在消息中添加發送日期
jsonObject.put("date", DATE_FORMAT.format(new Date()));
// 添加本條消息是否為當前會話本身發的標誌
jsonObject.put("isSelf", client.session.equals(session));
// 發送JSON格式的消息
client.session.getAsyncRemote().sendText(jsonObject.toString());
}
}
}
}
遇到的問題
在Maven項目中,由於web.xml申明的web-app是2.3版本的,不支持JSP內置對象,需要進行web.xml申明為:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
</web-app>
然後再JSP頁面加上:
<%@ page isELIgnored="false" %>
項目下載地址
https://github.com/yuechang/webSocket.git
博文參考:
- http://zhihu.com/question/20215561/answer/40316953
- http://shiyanlou.iteye.com/blog/2182565
- apache-tomcat-7.0.63\webapps\examples\WEB-INF\classes\websocket\chat\ChatAnnotation.java
Tags: 聊天室 private 效果圖 public 服務器
文章來源: