1. 最終效果與相關說明
1.1. 最終效果
1.2. 聊天過程演示
2. 工程的創建
筆者使用的開發工具是:STS4
- 創建SpringBoot2.x工程
-
添加相關starter
跟本次演示功能直接相關的依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
-
JavaConfig配置
/** * <pre> * - WebSocket的核心配置 * ClassName : com.teach.config.WebSocketConfig * Author : J.L.Zhou * E-Mail : [email protected] * Date : 2020-8-19 9:10:26 * Version : 1.0 * Copyright 2020 jlzhou.top Inc. All rights reserved. * Warning: this content is only for internal circulation of the company. It is forbidden to divulge it or use it for other commercial purposes * </pre> */ @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
-
WebSocket的服務器端
注意: @ServerEndpoint是原型模式
/** * <pre> * - 聊天 * ClassName : com.teach.endpoint.ChatEndpoint * Author : J.L.Zhou * E-Mail : [email protected] * Date : 2020-8-19 9:15:13 * Version : 1.0 * Copyright 2020 jlzhou.top Inc. All rights reserved. * Warning: this content is only for internal circulation of the company. It is forbidden to divulge it or use it for other commercial purposes * </pre> * */ @ServerEndpoint("/chat/{id}") @Component public class ChatEndpoint { /** * - 建立連接時調用的方法 * @param session - WebSocket的連接會話 * @param id - 連接路徑參數,這裏用做聊天室頻道 */ @OnOpen public void onOpen(Session session,@PathParam("id")String id) { } /** * - 發送消息時調用的方法 * @param message - 發送的消息 * @param session - 發送消息的會話 */ @OnMessage public void onMessage(String message,Session session) { } /** * - 發送錯誤時調用的方法 * @param session - 發送錯誤的會話 * @param throwable - 產生的異常 */ @OnError public void onError(Session session,Throwable throwable) { } /** * - 關閉時調用的方法 * @param session */ @OnClose public void onClose(Session session) { } }
3. 服務器端的功能實現
@ServerEndpoint("/chat/{id}/{name}")
@Component
@Slf4j
public class ChatEndpoint {
/**
* - 全局的聊天頻道和終端列表對應關係
*/
private final static Map<String, List<ChatEndpoint>> chats = new ConcurrentHashMap<>();
/**
* - 當前終端對應的聊天室頻道
*/
private String id;
/**
* - 當前終端的用戶名稱
*/
private String name;
/**
* - 當前終端對應的會話
*/
private Session session;
/**
* - 建立連接時調用的方法
* @param session - WebSocket的連接會話
* @param id - 連接路徑參數,這裏用做聊天室頻道
* @param name - 連接路徑參數,這裏用做聊天的名稱
*/
@OnOpen
public void onOpen(Session session,@PathParam("id")String id,@PathParam("name")String name) {
this.id = id;
this.session = session;
this.name = name;
List<ChatEndpoint> list = chats.get(id);
if(list==null) {
list = new CopyOnWriteArrayList<>();
list.add(this);
chats.put(id, list);
log.debug("創建了一個新頻道[{}],並加入了終端[{}]",id,session.getId());
}else {
list.add(this);
log.debug("在頻道[{}]加入了終端[{}]",id,session.getId());
}
}
/**
* - 發送消息時調用的方法
* - 接收到消息後,向所在頻道所有終端發送消息(不含自己)
* @param message - 發送的消息
* @param session - 發送消息的會話
*/
@OnMessage
public void onMessage(String message,Session session) {
final String msg = message.replace("\\", "\\\\").replace("\"", "\\\"");
chats.get(this.id).forEach((endpoint)->{
try {
if(ChatEndpoint.this!=endpoint) {
//發送的消息格式爲:msg("name","msg");
endpoint.session.getBasicRemote().sendText("msg(\""+name+"\",\""+msg+"\")");
log.debug("向終端{}發送了消息:{}",endpoint.session.getId(),msg);
}
} catch (IOException e) {
log.warn("向終端{}發送消息失敗",endpoint.session.getId());
}
});
}
/**
* - 發送錯誤時調用的方法
* @param session - 發送錯誤的會話
* @param throwable - 產生的異常
*/
@OnError
public void onError(Session session,Throwable throwable) {
log.warn("終端"+session.getId()+"發送了異常",throwable);
this.onClose(session);//發送錯誤後暫時直接關閉
}
/**
* - 關閉時調用的方法
* @param session
*/
@OnClose
public void onClose(Session session) {
chats.get(id).remove(this);
log.debug("將終端{}從所在頻道{}中刪除",session.getId(),id);
if(chats.get(id).size()==0) {//如果頻道中沒有了終端
chats.remove(id);
log.debug("將頻道{}刪除",id);
}
try {
session.close();//嘗試關閉終端
}catch (Exception e) {
}
}
}
4. 網頁端的實現
網頁代碼:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>聊天室</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/chat.css">
<script src="js/chat.js"></script>
</head>
<body>
<form autocomplete="off" class="setting"><input required name="id" placeholder="請輸入頻道id"><input required packageName = require('packageName'); name="name" placeholder="請輸入姓名"><button>進入</button></form>
<div class="chat-send"><textarea></textarea><button>發送</button></div>
</body>
</html>
核心JavaScript代碼:
window.onload = ()=> {
let setting = document.body.firstElementChild;
let msgEle = setting.nextElementSibling.firstElementChild;
let btnEle = msgEle.nextElementSibling;
console.debug(setting);
console.debug(msgEle);
console.debug(btnEle);
let id=1,name="張三";
setting.onsubmit = function(){
let temp = new FormData(this);
id = temp.get("id");
name = temp.get("name");
console.debug(`id=${id},name=${name}`);
this.remove();
temp=null;
setting=null;
initWebSocket();
return false;
}
let ws = null;
let initWebSocket = ()=>{
ws = new WebSocket(`ws://${location.host}/chat/${id}/${name}`);
ws.onopen = function(){
console.debug("onopen");
ws.send("我上線了");
}
ws.onerror = function(){
initWebSocket();
}
ws.onclose = function(){
initWebSocket();
}
ws.onmessage = function(msg){
console.debug(msg);
try{
eval("window."+msg.data);
}catch(e){
console.warn(e);
}
}
}
let domParser = new DOMParser();
window.msg = function(user,msg,me=false){
let d = new Date();
let html = `<div class="chat ${me?"":"chat-other"}">
<a href="javascript"><img onerror="this.src='imgs/48.jpg'" align="聊天頭像" src="imgs/48.jpg"></a>
<div>${user}</div>
<pre>${msg}
<time>${d.getFullYear()}-${d.getMonth()+1}-${d.getDate()} ${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}</time></pre>
</div>`;
html = domParser.parseFromString(html,"text/html");
document.body.appendChild(html.body.firstElementChild);
window.scrollTo(0,99999);
}
btnEle.onclick = function(){
window.msg(name,msgEle.value,true);
ws.send(msgEle.value);
msgEle.value="";
}
}
5. 總結與說明
本文的主要目的是用於學習,主要介紹在SpringBoot2下怎麼進行WebSocket編程,只完成了不同頻道的簡單的文字聊天,對於表情,圖片,拍照,文件,視頻等聊天內容本文未做描述.
PS:需要工程完整代碼的朋友,私聊就可以得到哦!