基于 SpringBoot+WebSocket 無DB實現(xiàn)在線聊天室
0 項目說明
0.1 樣例展示
0.2 源碼地址
GitHub:https://github.com/ShiJieCloud/web-chat
Gitee:https://gitee.com/suitbaby/web-chat
GitCode:I’m Jie / web-chat · GitCode
1 WebSocket 簡介
1.1 HTTP
常用的 HTTP 協(xié)議是一種無狀態(tài)的、無連接的、單向的應(yīng)用層協(xié)議。它采用了請求/響應(yīng)模型。通信請求只能由客戶端發(fā)起,服務(wù)端對請求做出應(yīng)答處理。這種通信模型有一個弊端:HTTP 協(xié)議無法實現(xiàn)服務(wù)器主動向客戶端發(fā)起消息。
這種單向請求的特點,注定了如果服務(wù)器有連續(xù)的狀態(tài)變化,客戶端要獲知就非常麻煩。大多數(shù) Web 應(yīng)用程序?qū)⑼ㄟ^頻繁的異步 AJAX 請求實現(xiàn)長輪詢。輪詢的效率低,非常浪費資源(因為必須不停連接,或者 HTTP 連接始終打開)。
HTTP 協(xié)議交互流程如下:
1.2 WebSocket
1.2.1 WebSocket 協(xié)議
為了實現(xiàn)服務(wù)器主動向客戶端發(fā)起消息,WebSocket 產(chǎn)生了,WebSocket 是 HTML5 開始提供的一種在單個 TCP 連接上進行全雙工通訊的協(xié)議。
WebSocket 協(xié)議有兩部分:握手(基于 HTTP 協(xié)議)和數(shù)據(jù)傳輸:
-
來自客戶端的握手,形式如下:
GET ws://localhost/chat HTTP/1.1 Host:localhost Upgrade:websocket Connection:Upgrade Sec-websocket-Key:dGh1IHNhbXBsZSBub25jZQ== Sec-WebSocket-Extensions:permessage-deflate Sec-WebSocket-Version:13
-
來自服務(wù)器的握手,形式如下:
HTTP/1.1 101 switching Protocols Upgrade:websocket Connection:Upgrade Sec-Websocket-Accept:s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Sec-Websocket-Extensions:permessage-deflate
字段說明:
頭名稱 | 說明 |
---|---|
Connection:Upgrade | 標(biāo)識該HTTP請求是一個協(xié)議升級請求 |
Upgrade:WebSocket | 協(xié)議升級為WebSocket協(xié)議 |
Sec-WebSocket-Version:13 | 客戶端支持WebSocket的版本 |
Sec-WebSocket-Key: | 客戶端采用base64編碼的24位隨機字符序列,服務(wù)器接受客戶端HTTP協(xié)議升級的證明。要求服務(wù)端響應(yīng)一個對應(yīng)加密的sec-WebSocket-Accept頭信息作為應(yīng)答 |
Sec-WebSocket-Extensions | 協(xié)議擴展類型 |
1.2.2 WebSocket 交互
WebSocket 協(xié)議客戶端服務(wù)端交互流程如圖:
2 使用教程
2.1 客戶端(瀏覽器)
2.1.1 WebSocket 對象
實現(xiàn) WebSocket 的 Web 瀏覽器將通過 WebSocket 對象公開所有必需的客戶端功能(主要指支持HTML5的瀏覽器)。
使用以下方式創(chuàng)建 WebSocket 對象:
var ws = new Websocket(url);
參數(shù) url
格式說明:ws://ip地址:端口號/資源名稱
,例如:let ws = new WebSocket("ws://localhost:8080/wechat")
2.1.2 WebSocket 事件
WebSocket 對象的相關(guān)事件
事件 | 事件處理程序 | 描述 |
---|---|---|
open | websocket對象.onopen | 連接建立時觸發(fā) |
message | websocket對象.onmessage | 客戶端接收服務(wù)端數(shù)據(jù)時觸發(fā) |
error | websocket對象.onerror | 通信發(fā)生錯誤時觸發(fā) |
close | websocket對象.onclose | 連接關(guān)閉時觸發(fā) |
2.1.3 WebSocket 方法
WebSocket 對象的相關(guān)方法:
方法 | 描述 |
---|---|
send() | 使用連接發(fā)送數(shù)據(jù) |
2.2 服務(wù)端(JAVA)
Tomcat 的 7.0.5 版本開始支持 WebSocket,并且實現(xiàn)了 Java WebSocket 規(guī)范(JSR356)。Java WebSocket 應(yīng)用由一系列的WebSocketEndpoints組成。Endpoint 是一個 Java 對象,代表 WebSocket 鏈接的一端,對于服務(wù)端,我們可以視為處理具體 WebSocket 消息的接口,類似一個 Controller
處理 HTTP 請求一樣。
我們可以通過使用編程式或注解的方式定義 Endpoint。
2.2.1 編程式
第一種是編程式,即繼承 javax.websocket.Endpoint
類并實現(xiàn)其方法。
public abstract class Endpoint {
/**
* 新會話啟動時觸發(fā)的事件。
*/
public abstract void onOpen(Session session, EndpointConfig config);
/**
* 會話關(guān)閉時觸發(fā)的事件。
*/
public void onClose(Session session, CloseReason closeReason) {
// NO-OP by default
}
/**
* 發(fā)生協(xié)議錯誤時觸發(fā)的事件。
*/
public void onError(Session session, Throwable throwable) {
// NO-OP by default
}
}
2.2.2 注解式
第二種是注解式,即定義一個 PoJo 類,在類上添加 @ServerEndpoint
注解,標(biāo)識該類為 Endpoint 實例。
Endpoint 實例會在 WebSocket 握手時創(chuàng)建,并在客戶端與服務(wù)端鏈接過程中長時間有效,最后在鏈接關(guān)閉時結(jié)束。在 Endpoint 接口中明確定義了與其生命周期相關(guān)的方法,規(guī)范實現(xiàn)者確保生命周期的各個階段調(diào)用實例的相關(guān)方法。生命周期方法如下:
方法 | 含義描述 | 注解 |
---|---|---|
onClose | 當(dāng)會話關(guān)閉時調(diào)用。 | @OnClose |
onOpen | 當(dāng)開啟一個新的會話時調(diào)用,該方法是客戶端與服務(wù)端握手成功后調(diào)用的方法。 | @onOpen |
onError | 當(dāng)連接過程中異常時調(diào)用。 | @OnError |
2.2.3 服務(wù)端接收客戶端數(shù)據(jù)
- 編程式:通過為
javax.websocket
包下的Session
對象添加MessageHandler
消息處理器來接收消息 - 注解式:定義Endpoint時,可以在PoJo類上添加
@OnMessage
注解指定接收消息的方法。
2.2.4 服務(wù)端發(fā)送數(shù)據(jù)給客戶端
發(fā)送消息則由RemoteEndpoint
完成,其實例由Session維護,根據(jù)使用情況,我們可以通過javax.websocket
包下的Session
對象的getBasicRemote()
獲取同步消息發(fā)送的實例,然后調(diào)用其sendXxx()
方法就可以發(fā)送消息,可以通過Session.getAsyncRemote
獲取異步消息發(fā)送實例。
3 聊天室實現(xiàn)
3.1 頁面布局
3.1.1 登錄頁面
用戶輸入昵稱即可登錄聊天室
3.1.2 聊天界面
聊天室主界面左部分為用戶列表,顯示聊天室所有在線用戶,右部分為聊天區(qū),包含聊天記錄和消息輸入框
3.2 實現(xiàn)流程
聊天室項目,WebSocket 工作流程圖如下:
3.3 WebSocket 消息格式
-
客戶端→服務(wù)端
{ "toName":"張三", "message":"你好" }
-
服務(wù)端→客戶端
-
系統(tǒng)消息格式
{ "isSystem":true, "status":true, "fromName":null, "message":[ "李四","王五" ] }
-
推送聊天消息格式
{ "isSystem":false, "status":false, "fromName":"張三", "message":"你好" }
-
3.4 工程創(chuàng)建
3.4.1 創(chuàng)建項目
創(chuàng)建一個 SpringBoot 項目,導(dǎo)入以下依賴:
<!--web 依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--thymeleaf 依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--lombok 依賴-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- WebSocket 依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>3.0.0</version>
</dependency>
3.4.2 引入靜態(tài)資源文件
3.5 登錄功能
3.5.1 HTML 代碼
由于只需要用戶輸入昵稱,所以使用最簡單的 form 表單提交即可,Controller 接口為/chat
,提交方式為 Post
:
<form class="theme-form" action="/chat" method="post">
<h2 class="text-center">聊天室</h2>
<p class="text-center">我們一起聊天吧</p>
<div class="form-group">
<input class="form-control" type="text" name="username" placeholder="請輸入自定義昵稱" required>
</div>
<div class="form-group mb-0">
<div class="text-end mt-3">
<button class="btn btn-primary btn-block w-100" type="submit">進入聊天室</button>
</div>
</div>
</form>
3.5.2 Java 代碼
在Controller中添加處理登錄的方法,用于接收前端傳來的登錄請求。
@PostMapping("/chat")
public String doLogin(String username,HttpSession httpSession, Model model){
//生成用戶信息
String userId = UUID.randomUUID().toString().replace("-", "");
String avatarUrl = "/static/image/avatar/avatar-"+(System.currentTimeMillis()%43+1)+".png";
User user = new User(userId, username, avatarUrl);
//存儲user到userMap中
UserDb.userMap.put(userId,user);
//將用戶id保存到 HttpSession 中
httpSession.setAttribute("loginUserId", userId);
model.addAttribute("loginUser", user);
return "chat";
}
3.6 聊天功能
3.6.1 Java 代碼
-
創(chuàng)建 pojo 類
ChatEndPoint
,在類上添加@ServerEndpoint
注解,并指定 WebSocket 請求路徑。在類中創(chuàng)建onOpen()、onMessage()、onClose()
方法,并標(biāo)注對應(yīng)的注解,用于處理對應(yīng)的WS事件:@Component @ServerEndpoint(value = "/wechat") public class ChatEndPoint { /** * 連接建立時被調(diào)用 */ @OnOpen public void onOpen(Session session, EndpointConfig config) { } /** * 接收到客戶端發(fā)送的數(shù)據(jù)時被調(diào)用 */ @OnMessage public void onMessage(String message, Session session) { } /** * 連接關(guān)閉時被調(diào)用 */ @OnClose public voidonClose(Session session) { } }
-
我們需要在
ChatEndPoint
對象中添加HttpSession
成員變量,用于取出登錄邏輯中存入的用戶id// 聲明一個httpSession對象,從中獲取登錄用戶id private HttpSession httpSession;
-
再聲明一個
javax.websocket
包下的Session
對象,通過該對象可以調(diào)用方法向指定的客戶端(用戶)發(fā)送消息private Session session;
-
因為每一個客戶端都會對應(yīng)一個
ChatEndPoint
對象,所以我們需要使用集合將所有客戶端的ChatEndPoint
對象保存起來,方便后續(xù)對指定用戶單獨操作// 用Map集合存儲所有客戶端對應(yīng)的ChatEndPoint對象 private static Map<String, ChatEndPoint> onlineUsers = new ConcurrentHashMap<>();
-
接下來我們需要實現(xiàn)
onOpen()
方法,在方法體中完成 WebSocket 連接建立后的需要執(zhí)行的操作邏輯:- 保存當(dāng)前WS Session對象
- 保存HTTPSession 對象
- 將當(dāng)前
ChatEndPoint
對象存儲到Map集合中 - 遍歷Map集合,調(diào)用
ChatEndPoint
對象的 WebSocket Session 成員變量的sendText()
方法將當(dāng)前所有在線用戶推送給所有客戶端,如:chatEndPoint.session.getBasicRemote().sendText(message)
@OnOpen public void onOpen(Session session, EndpointConfig config) { //將局部Session對象賦值給成員session this.session = session; //獲取httpSession對象 HttpSession httpSession = (HttpSession)config.getUserProperties().get(HttpSession.class.getName()); this.httpSession = httpSession; String userId = (String) httpSession.getAttribute("loginUserId"); System.out.println(userId+"登錄聊天室...."+HttpSession.class.getName()); //將當(dāng)前 ChatEndPoint 對象存儲到onlineUsers Map中 onlineUsers.put(userId, this); //將當(dāng)前在線用戶的用戶名推送給所有的客戶端 //1.生成系統(tǒng)消息 String message = MessageUtils.getMessage(true, true,null, UserDb.userMap.values()); //2.調(diào)用方法推送消息 broadcastAllUsers(message); }
-
由于在聊天室項目中,當(dāng)用戶向另一個用戶發(fā)送消息時,客戶端才會向服務(wù)端發(fā)送消息,所以在
onMessage()
方法中,只實現(xiàn)轉(zhuǎn)發(fā)消息的邏輯即可:- 將客戶端傳來的JSON字符串格式的數(shù)據(jù)轉(zhuǎn)為對象
- 獲取需要轉(zhuǎn)發(fā)的用戶id
- 獲取需要向用戶轉(zhuǎn)發(fā)的消息
- 通過用戶id從Map集合中獲取客戶端對應(yīng)的
ChatEndPoint
對象,調(diào)用sendText()
方法將消息發(fā)送
//將消息轉(zhuǎn)發(fā)送給指定用戶 @OnMessage public void onMessage(String message, Session session) { try { //將message的json格式轉(zhuǎn)為message對象 ObjectMapper mapper = new ObjectMapper(); Message mess = mapper.readValue(message, Message.class); //獲取接收數(shù)據(jù) String toUserId = mess.getToUserId(); String data = mess.getMessage(); //獲取當(dāng)前登錄的用戶 String loginUserId = (String) httpSession.getAttribute("loginUserId"); //生成推送給用戶的消息格式 String resultMessage = MessageUtils.getMessage(false, false, loginUserId, data); //使用指定用戶的session對象發(fā)送消息給指定用戶 onlineUsers.get(toUserId).session.getBasicRemote().sendText(resultMessage); } catch (JsonProcessingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
-
當(dāng)用戶關(guān)閉瀏覽器時,我們需要在
onClose()
中將用戶下線的消息發(fā)送給客戶端@OnClose public void onClose(Session session) { String loginUserId = (String) httpSession.getAttribute("loginUserId"); System.out.println(loginUserId + "WS連接關(guān)閉了...."); //移除用戶Session onlineUsers.remove(loginUserId); //移除用戶昵稱 UserDb.userMap.remove(loginUserId); //通知所有客戶端用戶下線 Set<String> set = new HashSet<>(); set.add(loginUserId); //1.生成系統(tǒng)消息 String message = MessageUtils.getMessage(true,false, null, set); //2.調(diào)用方法推送消息 broadcastAllUsers(message); }
-
服務(wù)端的主要代碼已經(jīng)完成,除此之外,我們還需要添加一些配置,否則我們編寫的WebSocket并不會起到作用。
我們需要將 ServerEndpointExporter 的實例添加到Spring容器中,ServerEndpointExporter實例會自動掃描所有的服務(wù)器端點,并添加所有帶有 @ServerEndpoint 注解的類
@Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); }
注:如果使用的是外置的 Tomcat 容器,則不需要自己提供 ServerEndpointExporter,因為它將由 Tomcat 容器自己提供和管理。
-
假如我們啟動項目,此時會報空異常,因為我們在處理用戶登錄的邏輯中,將登錄用戶的id存儲在HttpSession中,而我們在處理WebSocket連接建立后的
onOpen()
中,用EndpointConfig
對象的getUserProperties()
去獲取存儲的HttpSession對象,因為我們沒有將HttpSession存儲到EndpointConfig
中,所以獲取不到,返回Null。我們需要重寫
ServerEndpointConfig.Configurator
類的modifyHandshake()
方法,通過HandshakeRequest
對象獲取我們需要的HttpSession,存儲到ServerEndpointConfig
中,才能通過getUserProperties()
去獲取存儲的HttpSession對象:@Configuration public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator { @Override public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { HttpSession httpSession = (HttpSession) request.getHttpSession(); //將httpsession對象存儲到配置對象ServerEndpointConfig中 sec.getUserProperties().put(HttpSession.class.getName(),httpSession); } }
其中ServerEndpointConfig 接口繼承了 EndpointConfig 接口,源碼如下:
public interface ServerEndpointConfig extends EndpointConfig{ ······ }
3.6.2 HTML 代碼
-
在頁面上使用
ul li
標(biāo)簽顯示聊天室用戶列表<ul class="list custom-scrollbar" id="chat-user-list"> <!--用戶列表--> </ul>
-
顯示正在聊天的用戶信息:用戶頭像、用戶昵稱
<div class="d-flex chat-header clearfix"> <!--用戶頭像--> <img id="to-user-avatar" class="rounded-circle" src="/static/image/avatar/avatar-1.png"> <div class="flex-grow-1"> <div class="about"> <span class="name" id="to-user-name">用戶昵稱</span> </div> </div> </div>
-
聊天記錄區(qū)域
<ul id="chat-note"> <!--聊天記錄--> </ul>
-
信息輸入?yún)^(qū)域
<div class="input-group text-box"> <input class="form-control input-txt-bx" id="message-to-send" type="text" name="message-to-send" placeholder="輸入信息"> <button id="send-message" class="btn btn-primary input-group-text" type="button">發(fā)送</button> </div>
3.6.3 JS 代碼
-
當(dāng)點擊左側(cè)用戶列表的用戶頭像時,顯示與該用戶聊天的聊天界面
- 設(shè)置用戶頭像、用戶昵稱
- 顯示聊天界面
- 從
sessionStorage
中獲取到與該用戶的聊天記錄并顯示到聊天界面
/*切換聊天界面*/ function open_chat(toUId,toUname,toAUrl) { //設(shè)置聊天區(qū)用戶信息 toUserAvatar.attr('src',toAUrl); toUserName.text(toUname); //顯示聊天框 $('.call-chat-body').removeClass('fade'); toUserId = toUId; //獲取歷史聊天記錄 let chatData = sessionStorage.getItem(toUId); if (chatData != null) { //將聊天記錄渲染到聊天區(qū) $('#chat-note').html(chatData); } else { $('#chat-note').html(""); } }
注:聊天記錄存儲到
sessionStorage
,key為聊天用戶的id,非當(dāng)前登錄用戶的id,獲取聊天記錄時通過用戶id獲取即可 -
創(chuàng)建 WebSocket 對象,指定 URL,
url
格式為:ws://ip地址:端口號/資源名稱
//創(chuàng)建ws對象 let ws = new WebSocket("ws://localhost:8080/wechat");
注:
/wechat
為服務(wù)端的@ServerEndpoint(value = "/wechat")
的 value 值 -
綁定 WebSocket 接收服務(wù)端發(fā)送數(shù)據(jù)的
onmessage
事件。- 通過事件對象獲取服務(wù)端發(fā)送的數(shù)據(jù)并轉(zhuǎn)為JSON對象。
- 如果是系統(tǒng)消息,則進一步判斷是同步在線用戶還是通知用戶下線:
- 同步在線用戶:即遍歷用戶列表拼接HTML字符串,渲染到頁面中。
- 通知用戶下線:則將該用戶從用戶列表中移除,如果有用戶正和該用戶聊天,則隱藏聊天界面。
- 如果不是系統(tǒng)消息,則為轉(zhuǎn)發(fā)用戶發(fā)送的消息,首先判斷當(dāng)前是否正在與發(fā)消息的人聊天:
- 如果是,則直接渲染到聊天界面中,并存儲到
sessionStorage
中。 - 如果不是,則直接存儲到
sessionStorage
中。
- 如果是,則直接渲染到聊天界面中,并存儲到
//接收到服務(wù)端推送的消息后觸發(fā) ws.onmessage = function (e) { //獲取服務(wù)端推送的消息 let dataStr = e.data; //將dataStr轉(zhuǎn)為json對象 let res = JSON.parse(dataStr); //判斷是否是系統(tǒng)消息 if (res.system) { //系統(tǒng)消息 //用戶列表 let message = res.message; if (res.status) { //用戶在線,拼接html let str = ""; for (let user of message) { let userId = user.id; let username = user.username; let userAvatarUrl = user.avatarUrl; if (userId != loginUserId) { str += "<li id='" + userId + "' class=\"clearfix\"><div class=\"d-flex\"><img class=\"rounded-circle user-image\" src='" + userAvatarUrl + "' <div class=\"flex-grow-1\">" + "<div class=\"about\"><span class=\"name\" οnclick=\"open_chat('" + userId+"','"+username+"','"+userAvatarUrl + "')\">" + username + "</span></div></div></div></li>"; } } //添加html chat_user_list.html(str); } else { //下線用戶 for (let id of message) { $("#" + id).remove() if(toUserId==id){ $('.call-chat-body').addClass('fade'); } } } } else { //不是系統(tǒng)消息 let fromUserId = res.fromUserId; let message = res.message; let str = "<li><div class=\"message my-message\">"+message+"</div></li>"; //是否正在與發(fā)消息的人聊天 if(toUserId==fromUserId){ //是,顯示 $('#chat-note').append(str); } //存儲 let chatData = sessionStorage.getItem(fromUserId); if (chatData != null) { chatData+=str; } else { chatData=str; } sessionStorage.setItem(fromUserId,chatData); } }
-
點擊【發(fā)送】按鈕,發(fā)送消息。
- 獲取用戶輸入的消息內(nèi)容。
- 渲染到聊天界面中。
- 將消息數(shù)據(jù)轉(zhuǎn)為JSON格式的字符串,并調(diào)用WebSocket 的send()方法將數(shù)據(jù)發(fā)送給服務(wù)端,服務(wù)端在收到消息后會調(diào)用對應(yīng)的
onMessage()
方法進行處理。
$('#send-message').click(function () { //獲取輸入的內(nèi)容 let data = $('#message-to-send').val(); //清空輸入框內(nèi)容 $('#message-to-send').val(""); let str = "<li class=\"clearfix\"><div class=\"message other-message\" style='float:right'>" + data + "</div></li>"; $('#chat-note').append(str); //推送消息給服務(wù)器 let json = {"toUserId": toUserId, "message": data} ws.send(JSON.stringify(json)); })
-
到此,聊天室項目就結(jié)束了,使用Maven打包成jar包部署到服務(wù)器上試試吧??????。
4 Docker 部署服務(wù)器
4.1 修改 WS URL 地址
-
我們需要修改
JS
代碼中的 WebSocket 地址,將localhost:8080
改為服務(wù)器的公網(wǎng)IP
和服務(wù)端的端口號,否則客戶端無法正確鏈接到服務(wù)端(這里我將服務(wù)端的端口改為80端口,瀏覽器訪問時無需在 IP 地址后添加端口號)。//創(chuàng)建ws對象 let ws = new WebSocket("ws://43.143.180.243:80/wechat");
4.2 Maven 打包
-
在 Pom.xml 文件中添加
spring-boot-maven-plugin
插件依賴:<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
否則打包運行時會出現(xiàn)沒有主清單命令:
-
執(zhí)行 Maven 的
install
命令會將項目打包成 jar 包: -
進入jar包所在目錄,使用cmd命令打開命令行,運行命令查看jar包能否在正常啟動:
java -jar chat-0.0.1-SNAPSHOT.jar
輸出以下內(nèi)容,表示正常啟動 :
4.3 Dockerfile 文件
創(chuàng)建一個名為 Dockerfile 的文件,添加以下內(nèi)容:
FROM jdk1.8
ADD chat-0.0.1-SNAPSHOT.jar chat-0.0.1-SNAPSHOT.jar
EXPOSE 80
ENTRYPOINT ["java","-jar","chat-0.0.1-SNAPSHOT.jar"]
FROM jdk1.8
:我們的項目需要java8環(huán)境,所以基于 jdk1.8 鏡像部署,jdk1.8 鏡像構(gòu)建教程可以查看這篇文章:https://zsjie.blog.csdn.net/article/details/122202628。ADD chat-0.0.1-SNAPSHOT.jar chat-0.0.1-SNAPSHOT.jar
:類似COPY
命令,復(fù)制文件或者目錄到容器。EXPOSE 80
:聲明容器需要使用的端口。ENTRYPOINT ["java","-jar","chat-0.0.1-SNAPSHOT.jar"]
:類似 CMD 指令,這些命令行參數(shù)會被當(dāng)作參數(shù)送給 ENTRYPOINT 指令指定的程序。
4.4 上傳服務(wù)器
使用 XShell7 遠程連接服務(wù)器,創(chuàng)建目錄:
mkdir -p /usr/local/dockers/web-chat
使用 Xftp7 將項目的 jar 包和 Dockerfile 文件上傳到目錄下:
4.5 Docker 運行
-
使用 XShell7 遠程連接服務(wù)器,將目錄切換到 jar 包和 Dockerfile 文件所在的目錄下,執(zhí)行 build 命令構(gòu)建鏡像:
docker build -t='web-chat' .
-
查看 Docker 下的鏡像:
-
最后,我們只需要基于
web-chat
鏡像創(chuàng)建容器并運行即可:docker run -di --name=web-chat -p 80:80 web-chat
-
使用命令查看輸出日志,項目已經(jīng)成功運行了:
docker logs web-chat
4.6 項目結(jié)果
瀏覽器地址欄中輸入服務(wù)器的ip地址訪問項目:
文章來源:http://www.zghlxwxcb.cn/news/detail-453800.html
到此,我們的在線聊天室項目就完成了。文章來源地址http://www.zghlxwxcb.cn/news/detail-453800.html
到了這里,關(guān)于基于 SpringBoot+WebSocket 無DB實現(xiàn)在線聊天室(附源碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!