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:需要工程完整代码的朋友,私聊就可以得到哦!