1.前言
實作聊天室有很多種方式 netty, websocket等,我們這裡直接使用websocket技術,websocket是一種伺服器向用戶端發送資訊的技術,而不是傳統的servlet用戶端發送請求,然後伺服器給出響應.
現在比較流行的架構是springboot,而且spring官方也支援websocket,這裡借鑒了spring的官網文檔,不排除以後技術會發生變化.
2.實作
2.1依賴
implementation 'org.springframework.boot:spring-boot-starter-websocket'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.webjars:webjars-locator-core'
implementation 'org.webjars:sockjs-client:1.0.2'
implementation 'org.webjars:stomp-websocket:2.3.3'
implementation 'org.webjars:bootstrap:3.3.7'
implementation 'org.webjars:jquery:3.1.1-1'
2.2配置檔案
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/gs-guide-websocket").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic","/user");
registry.setApplicationDestinationPrefixes("/app");
}
}
setApplicationDestinationPrefixes 定義了websocket應用的通路字首,
addEndpoint 定義了socketjs的連接配接,
enableSimpleBroker 定義了啟用的廣播路徑,如果這裡不加上路徑的話,websocket無法廣播,也就是不法向用戶端發送消息
2.3消息類
public class HelloMessage {
private String name;
public HelloMessage() {
super();
}
public HelloMessage(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Greeting {
private String content;
public Greeting() {
super();
// TODO Auto-generated constructor stub
}
public Greeting(String content) {
super();
this.content = content;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
沒什麼好說的,資訊載體類
2.4controller
@Controller
public class GreetingController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/hello")
//@SendTo
//@SendToUser
public Greeting greeting(HelloMessage message) throws InterruptedException {
Greeting result = new Greeting("Hello,"+HtmlUtils.htmlEscape(message.getName()));
TimeUnit.SECONDS.sleep(1L);
simpMessagingTemplate.convertAndSendToUser("bob", "/queue/position-updates", result);
return new Greeting("Hello,"+HtmlUtils.htmlEscape(message.getName()));
}
}
我們可以使用 SendTo 定義傳回路徑,也可以使用 SendToUser 定義傳回的使用者,這些都是使用注解定義的,如果想要更靈活的可以使用 SimpMessagingTemplate 這個類來廣播消息.
2.5 前端實作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<noscript>
<h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!</h2>
</noscript>
<div id="main-content" class="container">
<div class="row">
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="connect">WebSocket connection:</label>
<button id="connect" class="btn btn-default" type="submit">Connect</button>
<button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">Disconnect
</button>
</div>
</form>
</div>
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="name">What is your name?</label>
<input type="text" id="name" class="form-control" placeholder="Your name here...">
</div>
<button id="send" class="btn btn-default" type="submit">Send</button>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table id="conversation" class="table table-striped">
<thead>
<tr>
<th>Greetings</th>
</tr>
</thead>
<tbody id="greetings">
</tbody>
</table>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/stomp.min.js"></script>
<script>
var stompClient = null;
function setConnected(connected) {
$("#connect").prop("disabled", connected);
$("#disconnect").prop("disabled", !connected);
if (connected) {
$("#conversation").show();
}
else {
$("#conversation").hide();
}
$("#greetings").html("");
}
function connect() {
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/user/bob/queue/position-updates', function (greeting) {
console.log(greeting)
showGreeting(JSON.parse(greeting.body).content);
});
});
}
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendName() {
stompClient.send("/app/hello", {}, JSON.stringify({ 'name': $("#name").val() }));
}
function showGreeting(message) {
$("#greetings").append("<tr><td>" + message + "</td></tr>");
}
$(function () {
$("form").on('submit', function (e) {
e.preventDefault();
});
$("#connect").click(function () { connect(); });
$("#disconnect").click(function () { disconnect(); });
$("#send").click(function () { sendName(); });
});
</script>
</body>
</html>
自己看代碼吧 就不多解釋了,剩下就是根據業務需要改改就可以.
主要看 connect 和 sendName 方法
connect 方法中的
stompClient.subscribe('/user/bob/queue/position-updates', function (greeting) {}
語句就是接收服務端發送回來的消息,/user表示是使用者接收,/bob就是後端定義的

bob,/queue/position-updates也是後端定義的語句.