WebSocket實(shí)現(xiàn)聊天室業(yè)務(wù)
WebSocket實(shí)現(xiàn)聊天室業(yè)務(wù)的具體代碼,供大家參考,具體內(nèi)容如下
頁面效果圖

pom.xml
主要是spring-boot-starter-websocket包,websocket連接、發(fā)送信息。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency><!--Webjars版本定位工具--> <groupId>org.webjars</groupId> <artifactId>webjars-locator-core</artifactId> </dependency> <dependency> <groupId>org.webjars.npm</groupId> <artifactId>mdui</artifactId> <version>0.4.0</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.3.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.49</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
前臺(tái)
html + js
websocket 前臺(tái)主要包括四種方法:
- 打開連接:onopen
- 服務(wù)端發(fā)來消息:1.廣播消息 2.更新在線人數(shù) : onmessage
- 關(guān)閉連接 :onclose
- 通信失敗 :onerror
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>WebSocket簡單聊天室</title>
<meta charset="utf-8" name="viewport" content="width=device-width">
<link rel="stylesheet" th:href="@{/webjars/mdui/dist/css/mdui.css}">
<script th:src="@{/webjars/jquery/jquery.min.js}"></script>
<script th:src="@{/webjars/mdui/dist/js/mdui.js}"></script>
</head>
<body class="mdui-theme-primary-indigo mdui-theme-accent-pink">
<div class="mdui-container">
<div class="mdui-toolbar mdui-color-theme">
<a class="mdui-btn mdui-btn-icon"><i class="mdui-icon material-icons">menu</i></a>
<span class="mdui-typo-title">簡單聊天室</span>
<div class="mdui-toolbar-spacer"></div>
<a class="mdui-btn mdui-btn-icon" target="_blank"><i
class="mdui-icon material-icons">search</i></a>
<a class="mdui-btn mdui-btn-icon" th:href="@{/}"><i
class="mdui-icon material-icons">exit_to_app</i></a>
<a class="mdui-btn mdui-btn-icon"><i class="mdui-icon material-icons">more_vert</i></a>
</div>
</div>
<div>
<div class="mdui-container container_text">
<div class="mdui-row">
<div class="mdui-col-xs-12 mdui-col-sm-6">
<div class="mdui-col-xs-12 mdui-col-sm-10">
<div class="mdui-textfield-floating-label" style="margin-top:15px">
<i class="mdui-icon material-icons">歡迎:</i>
<i class="mdui-icon" id="username" th:text="${username}"></i>
</div>
</div>
<div class="mdui-col-xs-12 mdui-col-sm-10">
<div class="mdui-textfield mdui-textfield-floating-label">
<i class="mdui-icon material-icons">textsms</i>
<label class="mdui-textfield-label">發(fā)送內(nèi)容</label>
<input class="mdui-textfield-input" id="msg"/>
</div>
<div class="mdui-container" style="padding:20px 35px">
<button class="mdui-btn mdui-color-theme-accent mdui-ripple"
onclick="sendMsgToServer()">發(fā)送 (enter)
</button>
<button class="mdui-btn mdui-color-theme mdui-ripple"
onclick="clearMsg()">清屏
</button>
</div>
</div>
</div>
<div class="mdui-col-xs-6 mdui-col-sm-5" style="padding:10px 0">
<div class="mdui-chip">
<span class="mdui-chip-icon mdui-color-blue">
<i class="mdui-icon material-icons"></i></span>
<span class="mdui-chip-title">聊天內(nèi)容</span>
</div>
<div class="mdui-chip">
<span class="mdui-chip-icon mdui-color-blue">
<i class="mdui-icon material-icons">face</i></span>
<span class="mdui-chip-title">在線人數(shù)</span>
<span class="mdui-chip-title chat-num">0</span>
</div>
<div class="message-container">
</div>
</div>
</div>
</div>
</div>
<script th:inline="javascript">
/**
* WebSocket客戶端
*
* 使用說明:
* 1、WebSocket客戶端通過回調(diào)函數(shù)來接收服務(wù)端消息。例如:webSocket.onmessage
* 2、WebSocket客戶端通過send方法來發(fā)送消息給服務(wù)端。例如:webSocket.send();
*/
function getWebSocket() {
/**
* WebSocket客戶端 PS:URL開頭表示W(wǎng)ebSocket協(xié)議 中間是域名端口 結(jié)尾是服務(wù)端映射地址
*/
var webSocket = new WebSocket(/*[[${webSocketUrl}]]*/ 'ws://localhost:8080/chat');
/**
* 當(dāng)服務(wù)端打開連接
*/
webSocket.onopen = function (event) {
console.log('WebSocket打開連接');
};
/**
* 當(dāng)服務(wù)端發(fā)來消息:1.廣播消息 2.更新在線人數(shù)
*/
webSocket.onmessage = function (event) {
console.log('WebSocket收到消息:%c' + event.data, 'color:green');
//獲取服務(wù)端消息
var message = JSON.parse(event.data) || {};
var $messageContainer = $('.message-container');
//喉嚨發(fā)炎
if (message.type === 'SPEAK') {
$messageContainer.append(
'<div class="mdui-card" style="margin: 10px 0;">' +
'<div class="mdui-card-primary">' +
'<div class="mdui-card-content message-content">' + message.username + ":" + message.msg + '</div>' +
'</div></div>');
}
$('.chat-num').text(message.onlineCount);
//防止刷屏
var $cards = $messageContainer.children('.mdui-card:visible').toArray();
if ($cards.length > 5) {
$cards.forEach(function (item, index) {
index < $cards.length - 5 && $(item).slideUp('fast');
});
}
};
/**
* 關(guān)閉連接
*/
webSocket.onclose = function (event) {
console.log('WebSocket關(guān)閉連接');
};
/**
* 通信失敗
*/
webSocket.onerror = function (event) {
console.log('WebSocket發(fā)生異常');
};
return webSocket;
}
var webSocket = getWebSocket();
/**
* 通過WebSocket對(duì)象發(fā)送消息給服務(wù)端
*/
function sendMsgToServer() {
var $message = $('#msg');
if ($message.val()) {
webSocket.send(JSON.stringify({username: $('#username').text(), msg: $message.val()}));
$message.val(null);
}
}
/**
* 清屏
*/
function clearMsg() {
$(".message-container").empty();
}
/**
* 使用ENTER發(fā)送消息
*/
document.onkeydown = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
e.keyCode === 13 && sendMsgToServer();
};
</script>
</body>
</html>
后臺(tái)
WebSocketChatApplication - 啟動(dòng)類
@SpringBootApplication
@RestController
public class WebSocketChatApplication {
/**
* 登陸界面
*/
@GetMapping("/")
public ModelAndView login() {
return new ModelAndView("/login");
}
/**
* 聊天界面
*/
@GetMapping("/index")
public ModelAndView index(String username, String password, HttpServletRequest request) throws UnknownHostException {
if (StringUtils.isEmpty(username)) {
username = "匿名用戶";
}
ModelAndView mav = new ModelAndView("/chat");
mav.addObject("username", username);
mav.addObject("webSocketUrl", "ws://"+InetAddress.getLocalHost().getHostAddress()+":"+request.getServerPort()+request.getContextPath()+"/chat");
return mav;
}
public static void main(String[] args) {
SpringApplication.run(WebSocketChatApplication.class, args);
}
}
WebSocketConfig - WebSocket配置類
@Configuration
public class WebSocketConfig {
/**
* 用于掃描和注冊所有攜帶ServerEndPoint注解的實(shí)例。
* <p>
* PS:若部署到外部容器 則無需提供此類。
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
Message - 封裝信息類
/**
* WebSocket 聊天消息類
*/
public class Message {
public static final String ENTER = "ENTER";
public static final String SPEAK = "SPEAK";
public static final String QUIT = "QUIT";
private String type;//消息類型
private String username; //發(fā)送人
private String msg; //發(fā)送消息
private int onlineCount; //在線用戶數(shù)
public static String jsonStr(String type, String username, String msg, int onlineTotal) {
return JSON.toJSONString(new Message(type, username, msg, onlineTotal));
}
public Message(String type, String username, String msg, int onlineCount) {
this.type = type;
this.username = username;
this.msg = msg;
this.onlineCount = onlineCount;
}
public static String getENTER() {
return ENTER;
}
public static String getSPEAK() {
return SPEAK;
}
public static String getQUIT() {
return QUIT;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getOnlineCount() {
return onlineCount;
}
public void setOnlineCount(int onlineCount) {
this.onlineCount = onlineCount;
}
}
WebSocketChatServer - 聊天服務(wù)端
前臺(tái)對(duì)應(yīng)的四種傳輸,后臺(tái)進(jìn)行處理操作
/**
* WebSocket 聊天服務(wù)端
*
* @see ServerEndpoint WebSocket服務(wù)端 需指定端點(diǎn)的訪問路徑
* @see Session WebSocket會(huì)話對(duì)象 通過它給客戶端發(fā)送消息
*/
@Component
@ServerEndpoint("/chat")
public class WebSocketChatServer {
/**
* 全部在線會(huì)話 PS: 基于場景考慮 這里使用線程安全的Map存儲(chǔ)會(huì)話對(duì)象。
*/
private static Map<String, Session> onlineSessions = new ConcurrentHashMap<>();
/**
* 當(dāng)客戶端打開連接:1.添加會(huì)話對(duì)象 2.更新在線人數(shù)
*/
@OnOpen
public void onOpen(Session session) {
onlineSessions.put(session.getId(), session);
sendMessageToAll(Message.jsonStr(Message.ENTER, "", "", onlineSessions.size()));
}
/**
* 當(dāng)客戶端發(fā)送消息:1.獲取它的用戶名和消息 2.發(fā)送消息給所有人
* <p>
* PS: 這里約定傳遞的消息為JSON字符串 方便傳遞更多參數(shù)!
*/
@OnMessage
public void onMessage(Session session, String jsonStr) {
Message message = JSON.parseObject(jsonStr, Message.class);
sendMessageToAll(Message.jsonStr(Message.SPEAK, message.getUsername(), message.getMsg(), onlineSessions.size()));
}
/**
* 當(dāng)關(guān)閉連接:1.移除會(huì)話對(duì)象 2.更新在線人數(shù)
*/
@OnClose
public void onClose(Session session) {
onlineSessions.remove(session.getId());
sendMessageToAll(Message.jsonStr(Message.QUIT, "", "", onlineSessions.size()));
}
/**
* 當(dāng)通信發(fā)生異常:打印錯(cuò)誤日志
*/
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
/**
* 公共方法:發(fā)送信息給所有人
*/
private static void sendMessageToAll(String msg) {
onlineSessions.forEach((id, session) -> {
try {
session.getBasicRemote().sendText(msg);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 使用Java和WebSocket實(shí)現(xiàn)網(wǎng)頁聊天室實(shí)例代碼
- php+html5基于websocket實(shí)現(xiàn)聊天室的方法
- 使用WebSocket實(shí)現(xiàn)即時(shí)通訊(一個(gè)群聊的聊天室)
- php基于websocket搭建簡易聊天室實(shí)踐
- 微信小程序websocket聊天室的實(shí)現(xiàn)示例代碼
- golang基于websocket實(shí)現(xiàn)的簡易聊天室程序
- 基于Swoole實(shí)現(xiàn)PHP與websocket聊天室
- 基于Tomcat7、Java、WebSocket的服務(wù)器推送聊天室實(shí)例
- 用java WebSocket做一個(gè)聊天室
- Android使用Websocket實(shí)現(xiàn)聊天室
相關(guān)文章
深入學(xué)習(xí)java并發(fā)包ConcurrentHashMap源碼
這篇文章主要介紹了深入學(xué)習(xí)java并發(fā)包ConcurrentHashMap源碼,整個(gè) ConcurrentHashMap 由一個(gè)個(gè) Segment 組成,Segment 代表”部分“或”一段“的意思,所以很多地方都會(huì)將其描述為分段鎖。,需要的朋友可以參考下2019-06-06
Spring中使用Async進(jìn)行異步功能開發(fā)實(shí)戰(zhàn)示例(大文件上傳為例)
本文以大文件上傳為例,首先講解在未進(jìn)行程序異步化時(shí),程序的運(yùn)行機(jī)制和具體表現(xiàn),然后講解如何進(jìn)行異步化的改造,讓程序進(jìn)行異步執(zhí)行,通過本文不僅能讓你掌握如何進(jìn)行Event的事件開發(fā),同時(shí)還能掌握在Spring中如何進(jìn)行異步開發(fā),熟悉@Async的具體用法,感興趣的朋友一起看看吧2024-08-08
通過簡單步驟實(shí)現(xiàn)SpringMVC文件上傳
這篇文章主要介紹了通過簡單步驟實(shí)現(xiàn)SpringMVC文件上傳,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
java數(shù)據(jù)結(jié)構(gòu)排序算法之樹形選擇排序詳解
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)排序算法之樹形選擇排序,結(jié)合具體實(shí)例形式分析了java樹形選擇排序的原理、實(shí)現(xiàn)技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-05-05
hibernate測試時(shí)遇到的幾個(gè)異常及解決方法匯總
今天小編就為大家分享一篇關(guān)于hibernate測試時(shí)遇到的幾個(gè)異常及解決方法匯總,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03
Java正則驗(yàn)證正整數(shù)的方法分析【測試可用】
這篇文章主要介紹了Java正則驗(yàn)證正整數(shù)的方法,結(jié)合實(shí)例形式對(duì)比分析了java針對(duì)正整數(shù)的驗(yàn)證方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-08-08
springboot?serviceImpl初始化注入對(duì)象實(shí)現(xiàn)方式
這篇文章主要介紹了springboot?serviceImpl初始化注入對(duì)象實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05

