使用Vert.x實現一個簡單的websocket聊天室
小菜一枚,公司業務使用了基於netty的websocket,奈何不會netty,索性之前瞭解到一個基於netty的toolkit,也就是Vert.x。
Vert.x是一個基於事件和異步,依託於全異步Java服務器Netty,並擴展了很多其他特性,以其輕量、高性能、支持多語言開發而備受開發者青睞的工具集(注意,不是說的框架,而是工具集)。點擊進入Vert.x官網。目前Vert.x以更新到了3.5.0
它支持的語言:Java、JavaScript、Groovy、Ruby、Ceylon、Kotlin、Scala……未來也許會增加更多的語言支持。
言歸正傳,這個小東西代碼不多,僅作爲個人學習Vert.x使用,預期實現目標如下:
- 使用Maven搭建Vert.x程序框架
- 使用Vert.x的WebSocket實現一個簡易的局域網聊天室(僅支持文本消息)
Step1 開發環境
Vert.x3.5.0因爲使用了大量的Java8的特性,比如lambda表達式,所以要求JDK版本爲JDK8+
Maven我使用的3.3.9
IDE使用的Intellij IDEA 2017.2
Step2 項目搭建
新建一個Maven項目,名稱什麼的隨便
pom.xml文件中引入Vert.x 3.5.0版本的依賴
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
<version>3.5.0</version>
</dependency>
引入了vertx-web自動引入了vertx-core,所以不用手動添加core的依賴
Step3 編寫代碼
- 創建WebSocketVerticle.java
import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.ServerWebSocket;
import io.vertx.ext.web.Router;
import java.util.HashMap;
import java.util.Map;
public class WebSocketVerticle extends AbstractVerticle {
// 保存每一個連接到服務器的通道
private Map<String, ServerWebSocket> connectionMap = new HashMap<>(16);
@Override
public void start() throws Exception {
HttpServer server = vertx.createHttpServer();
Router router = Router.router(vertx);
router.route("/").handler(routingContext -> {
routingContext.response().sendFile("html/ws.html");
});
websocketMethod(server);
server.requestHandler(router::accept).listen(8080);
}
public void websocketMethod(HttpServer server) {
server.websocketHandler(webSocket -> {
// 獲取每一個鏈接的ID
String id = webSocket.binaryHandlerID();
// 判斷當前連接的ID是否存在於map集合中,如果不存在則添加進map集合中
if (!checkID(id)) {
connectionMap.put(id, webSocket);
}
// WebSocket 連接
webSocket.frameHandler(handler -> {
String textData = handler.textData();
String currID = webSocket.binaryHandlerID();
//給非當前連接到服務器的每一個WebSocket連接發送消息
for (Map.Entry<String, ServerWebSocket> entry : connectionMap.entrySet()) {
if (currID.equals(entry.getKey())) {
continue;
}
/* 發送文本消息
文本信息似乎不支持圖片等二進制消息
若要發送二進制消息,可用writeBinaryMessage方法
*/
entry.getValue().writeTextMessage(textData);
}
});
// 客戶端WebSocket 關閉時,將當前ID從map中移除
webSocket.closeHandler(handler -> connectionMap.remove(id) );
});
}
// 檢查當前ID是否已經存在與map中
public boolean checkID(String id) {
return connectionMap.containsKey(id);
}
整個websocket的服務器端代碼就這麼點。沒有用過其它的框架實現過websocket聊天室,不知道代碼量如何。但就Vert.x的實現方式來說,個人覺得還是很方便的。
- 部署Verticle
public class Main {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(WebSocketVerticle.class.getName());
}
}
- 最後HTML文件放置在resources/html下
ws.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocketTest</title>
<script type="text/javascript" src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js"></script>
</head>
<body>
<script>
var socket;
if(window.WebSocket){
socket = new WebSocket("ws://localhost:8080/");
// websocket收到消息
socket.onmessage = function(event){
// 如果服務端是寫的二進制數據,則此處的blob也是一個二進制對象,提取數據時需要Blob類和FileReader類配合使用
var blob = event.data;
var content = $("#content").html();
blob += content;
$("#content").html(blob);
};
// websocket連接打開
socket.onopen = function (event) {
console.log("websocket 連接打開");
};
// websocket連接關閉
socket.onclose = function (event) {
console.log("websocket 連接關閉");
};
}else{
alert("你的瀏覽器不支持websocket");
}
function send(message) {
if(!window.WebSocket){
return;
}
if(socket.readyState == WebSocket.OPEN){
socket.send(message);
}else{
alert("websocket連接未打開,請檢查網絡設置");
}
}
</script>
<form onsubmit="return false;">
<input type="text" name="message">
<input type="button" value="提交" onclick="send(this.form.message.value)">
<div id="content"></div>
</form>
</body>
</html>
羣推薦:如果對Vert.x技術感興趣,可以加QQ羣: 515203212。
轉載請註明出處:http://blog.csdn.net/zhhactj/article/details/78728899