Springboot與WebSocket整合實現聊天功能
- 首先要在pom.xml中匯入websocket的依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>sockjs-client</artifactId> <version>1.0.2</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>stomp-websocket</artifactId> <version>2.3.3</version> </dependency> <!--thymeleaf--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
用到websocket只需要第一個spring-boot-starter-websocket依賴就可以了,因為該專案還實現了和前臺的互動,所以匯入了sockjs-client和stomp-websocket依賴(如果不想在pom.xml中匯入,可以直接引用/sockjs.min.js和stomp.min.js連結:http://www.bootcdn.cn/stomp.js/) 2. 後臺新建WebSocketConfig.java
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{ @Override public void registerStompEndpoints(StompEndpointRegistry registry) { //新增服務端點,接收客戶端的連線 //引數/any-socket要和前臺對應一致 registry.addEndpoint("/any-socket") //開啟SockJS支援 .withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { //服務端接收地址的字首 registry.setApplicationDestinationPrefixes("/app"); //客戶端訂閱地址的字首資訊 registry.enableSimpleBroker("/topic","/user"); } @Override public void configureWebSocketTransport(WebSocketTransportRegistration registration) { registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() { @Override public WebSocketHandler decorate(WebSocketHandler handler) { return new WebSocketHandlerDecorator(handler){ /* (non-Javadoc) * 客戶端與服務端建立連線後的服務端的操作 */ @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { String username = session.getPrincipal().getName(); System.out.println("online:"+username); super.afterConnectionEstablished(session); } /* (non-Javadoc) * 客戶端與服務端斷開連線後服務端的操作 */ @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { String username = session.getPrincipal().getName(); System.out.println("offline:"+username); super.afterConnectionClosed(session, closeStatus); } }; } }); } }
@Configuration 說明該java類是一個配置類 @EnableWebSocketMessageBroker 用於開始使用STOMP協議來傳輸基於MessageBroken的訊息,這時controller可以使用@MessageMapping來攔截訊息 registry.setApplicationDestinationPrefixes()用來設定伺服器接收訊息的字首 3.聊天訊息的controller
@Controller public class ChatController { private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Autowired private SimpMessagingTemplate template; /** * 群聊模式 * @param principal 當前使用者 * @param message 接收到的客戶端的訊息 * @return 包裝後的訊息 */ @MessageMapping("/all") @SendTo("/topic/all") public String all(Principal principal,String message){ BaseMessage baseMessage = new BaseMessage(); baseMessage.setType("to_all"); baseMessage.setContent(message); baseMessage.setSender(principal.getName()); System.out.println(principal.getName()+"++++++++++++++++++++++++++++++++++"); baseMessage.setSendTime(format.format(new Date())); System.out.println(JSON.toJSONString(baseMessage)); return JSON.toJSONString(baseMessage); } /** * 私聊 * */ @MessageMapping("/chat")//接收發送到/app/chat的訊息 public void chat(Principal principal,String message){ ChatMessage chatMessage = JSON.parseObject(message,ChatMessage.class); BaseMessage baseMessage = new BaseMessage(); baseMessage.setType("to_one"); baseMessage.setSender(principal.getName()); System.out.println(principal.getName()+"++++++++++++++++++++++++++++++++++"); baseMessage.setContent(chatMessage.getContent()); baseMessage.setSendTime(format.format(new Date())); //轉發包裝後的訊息至使用者 template.convertAndSendToUser(chatMessage.getReceiver(),"/topic/chat",JSON.toJSONString(baseMessage)); } }
@MessageMapping("/chat") 攔截髮送到"/app/chat"的訊息 @SendTo 註解重寫了訊息代理的目的地,如果不指定@SendTo,幀所發往的目的地會與觸發處理器方法的目的地相同,只不過會新增上“/topic”字首 3.前臺js的實現
var target = "to_all";
var stompClient = null;
function connect() {
var socket = new SockJS('/any-socket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/all', function (message) {
showMessage(JSON.parse(message.body));
});
stompClient.subscribe('/user/topic/chat', function (message) {
showMessage(JSON.parse(message.body));
});
});
}
stompClient.connect(header,connectionCallback,errorCallback);第一個引數是header,包含客戶端的認證資訊,可如下所示;connectionCallback是表示連線成功時(伺服器響應 CONNECTED 幀)的回撥方法 errorCallback是連線失敗時的回撥方法,非必需
var headers = {
login: 'mylogin',
passcode: 'mypasscode',
// additional header
'client-id': 'my-client-id'
};
subscribe(destination url, callback[, headers]) 訂閱伺服器的訊息 destination url 為伺服器 @SendTo 匹配的 URL,字串; callback 為每次收到伺服器推送的訊息時的回撥方法 showMessage為自定義訊息用於在客戶端展示訊息
$(function () {
connect();
$("#send").click(function () {
if (target == "to_all"){
if($("#message").val()){
stompClient.send("/app/all", {}, $("#message").val());
}
}else{
var content = "{'type':'to_one','content':'" + $("#message").val() + "','receiver':'"+target+"'}";
stompClient.send("/app/chat", {}, content);
}
$("#message").val("");
});
$(".friend").click(function () {
target = $(this).find("p.f-name").text();
var username = $(this).find("h4.f-name").text();
$("#target").text(username);
$("#groupBtn").attr("class","btn btn-default");
});
$("#groupBtn").click(function(){
$(this).attr("class","btn btn-default disabled");
target = "to_all";
$("#target").text("所有人");
});
}
僅為部分程式碼。