一、websocket的介绍
WebSocket是一种网络通信协议,它可以在单个TCP连接上实现双向(全双工)通信。WebSocket使用HTML5标准,并且可以在客户端和服务器之间建立持久连接,这意味着连接在浏览器刷新或关闭后仍然保持打开状态。
WebSocket的主要优点包括:
1. 双向通信:WebSocket支持客户端和服务器之间的双向通信,这使得实时数据传输变得非常容易。
2. 持久连接:WebSocket使用单个TCP连接,这使得服务器可以保持与客户端的通信,即使浏览器被关闭或刷新。
3. 零延迟:由于WebSocket使用单个TCP连接,因此数据传输不会出现延迟。
4. 更好的性能:WebSocket使用二进制传输,这使得数据传输速度更快。
5. 更好的可伸缩性:WebSocket可以处理大量的并发连接,因为它使用单个TCP连接。
二、springboot集成websocket(用注解的方式)
1.创建一个springboot项目,测试是否成功
package com.dong.websocket.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping(value = "/")
public String index() {
return "Hello World!";
}
}
2.目录
3.依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dong</groupId>
<artifactId>springboot_websocket</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>SpringBootProject</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.配置类
package com.dong.websocket.websocket;
import javax.websocket.server.ServerEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter ServerEndpointExporter () {
return new ServerEndpointExporter();
}
}
5.监听类
package com.dong.websocket.websocket;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
/**
* 监听websocket地址/myWs
*/
@ServerEndpoint("/myWs")
@Component
@Slf4j
public class WsServeEndPont {
// 线程安全的Map,用来保存session, static用来确保是属于类的而不是对象的
static Map<String, Session> sessionMap = new ConcurrentHashMap<>();
// 连接建立时执行的操作
@OnOpen
public void OnOpen (Session session) {
sessionMap.put(session.getId(), session);
log.info("websocket is open");
}
// 收到客户端消息执行的操作
@OnMessage
public String onMessage(String text) {
log.info("收到了一条消息:" + text);
return "已收到你的消息";
}
// 连接关闭时执行的操作
@OnClose
public void OnClose (Session session) {
sessionMap.remove(session.getId());
log.info("websocket is close");
}
// 定时任务:间隔时间2s
@Scheduled(fixedRate = 2000)
public void sendMsg () {
sessionMap.keySet().forEach(item->{
try {
sessionMap.get(item).getBasicRemote().sendText("心跳");
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
6.前端页面ws-client
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ws client</title>
</head>
<body>
</body>
<script>
let ws = new WebSocket("ws://localhost:8080/myWs")
ws.onopen= function () {
ws.send("hello")
}
ws.onmessage = function (message) {
console.log(message.data)
}
</script>
</html>
三、springboot集成websocket(用spring框架实现)
1.Spring提供的类和接口
- HttpSessionHandshakeInterceptor(抽象类):握手拦截器,在握手钱后添加操作
- AbstractWebSocketHandler(抽象类):WebSocket处理程序,监听连接前,连接中,连接后
- WebSocketConfigurer(接口):配置程序,比如配置监听哪个端口,自定义的握手拦截器,处理程序的使用
2.项目结构
3.SessionBean类,封装websocketsession和用户id标识
package com.dong.websocket.spring;
import org.springframework.web.socket.WebSocketSession;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class SessionBean {
private WebSocketSession webSocketSession;
private Integer clientId;
}
4.MyWsInterceptor类,握手拦截器
package com.dong.websocket.spring;
import java.util.Map;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import lombok.extern.slf4j.Slf4j;
/**
* 握手拦截器
*/
@Component
@Slf4j
public class MyWsInterceptor extends HttpSessionHandshakeInterceptor{
@Override
public boolean beforeHandshake (ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes ) throws Exception {
log.info(request.getRemoteAddress().toString() + "开始握手");
return super.beforeHandshake(request, response, wsHandler, attributes);
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
log.info(request.getRemoteAddress().toString() + "完成握手");
super.afterHandshake(request, response, wsHandler, ex);
}
}
5.MyWsHander类
package com.dong.websocket.spring;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import lombok.extern.slf4j.Slf4j;
/**
* web socket 主处理程序
*/
@Slf4j
@Component
public class MyWsHandler extends AbstractWebSocketHandler {
private static Map<String,SessionBean> sessionBeanMap ;
private static AtomicInteger clientIdMaker;
private static StringBuffer stringBuffer;
static {
sessionBeanMap = new ConcurrentHashMap<>();
clientIdMaker = new AtomicInteger(0);
stringBuffer = new StringBuffer();
}
//连接建立
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
SessionBean sessionBean = new SessionBean(session,clientIdMaker.getAndIncrement());
sessionBeanMap.put(session.getId(),sessionBean);
log.info(sessionBeanMap.get(session.getId()).getClientId()+"建立了连接");
stringBuffer.append(sessionBeanMap.get(session.getId()).getClientId()+"进入了群聊<br/>");
sendMessage(sessionBeanMap);
}
//收到消息
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
log.info(sessionBeanMap.get(session.getId()).getClientId()+":"+message.getPayload());
stringBuffer.append(sessionBeanMap.get(session.getId()).getClientId()+":"+message.getPayload()+"<br/>");
sendMessage(sessionBeanMap);
}
//传输异常
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
super.handleTransportError(session, exception);
if(session.isOpen()){
session.close();
}
sessionBeanMap.remove(session.getId());
}
//连接关闭
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
super.afterConnectionClosed(session, status);
int clientId = sessionBeanMap.get(session.getId()).getClientId();
sessionBeanMap.remove(session.getId());
log.info(clientId+"关闭了连接");
stringBuffer.append(clientId+"退出了群聊<br/>");
sendMessage(sessionBeanMap);
}
// //每2s发送给客户端心跳消息
// @Scheduled(fixedRate = 2000)
// public void sendMsg() throws IOException {
// for(String key:sessionBeanMap.keySet()){
// sessionBeanMap.get(key).getWebSocketSession().sendMessage(new TextMessage("心跳"));
// }
// }
public void sendMessage(Map<String,SessionBean> sessionBeanMap){
for(String key:sessionBeanMap.keySet()){
try {
sessionBeanMap.get(key).getWebSocketSession().sendMessage(new TextMessage(stringBuffer.toString()));
} catch (IOException e) {
// e.printStackTrace();
log.error(e.getMessage());
}
}
}
}
6.MyWsConfig类
package com.dong.websocket.spring;
import javax.annotation.Resource;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class MyWsConfig implements WebSocketConfigurer {
@Resource
MyWsHandler myWsHandler;
@Resource
MyWsInterceptor myWsInterceptor;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myWsHandler, "/myWs1").addInterceptors(myWsInterceptor).setAllowedOrigins("*");
}
}
四、实现一个简单的聊天室功能
1.ws-client.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ws client</title>
</head>
<body>
<p style="border:1px solid black;width: 600px;height: 500px" id="talkMsg"></p>
<input id="message" /><button id="sendBtn" onclick="sendMsg()">发送</button>
</body>
<script>
let ws = new WebSocket("ws://localhost:8080/myWs1")
// ws.onopen=function () {
// }
ws.onmessage=function (message) {
document.getElementById("talkMsg").innerHTML = message.data
}
function sendMsg() {
ws.send(document.getElementById("message").value)
document.getElementById("message").value=""
}
</script>
</html>
2.MyWsHandler
package com.dong.websocket.spring;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import lombok.extern.slf4j.Slf4j;
/**
* web socket 主处理程序
*/
@Slf4j
@Component
public class MyWsHandler extends AbstractWebSocketHandler {
private static Map<String,SessionBean> sessionBeanMap ;
private static AtomicInteger clientIdMaker;
private static StringBuffer stringBuffer;
static {
sessionBeanMap = new ConcurrentHashMap<>();
clientIdMaker = new AtomicInteger(0);
stringBuffer = new StringBuffer();
}
//连接建立
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
SessionBean sessionBean = new SessionBean(session,clientIdMaker.getAndIncrement());
sessionBeanMap.put(session.getId(),sessionBean);
log.info(sessionBeanMap.get(session.getId()).getClientId()+"建立了连接");
stringBuffer.append(sessionBeanMap.get(session.getId()).getClientId()+"进入了群聊<br/>");
sendMessage(sessionBeanMap);
}
//收到消息
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
log.info(sessionBeanMap.get(session.getId()).getClientId()+":"+message.getPayload());
stringBuffer.append(sessionBeanMap.get(session.getId()).getClientId()+":"+message.getPayload()+"<br/>");
sendMessage(sessionBeanMap);
}
//传输异常
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
super.handleTransportError(session, exception);
if(session.isOpen()){
session.close();
}
sessionBeanMap.remove(session.getId());
}
//连接关闭
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
super.afterConnectionClosed(session, status);
int clientId = sessionBeanMap.get(session.getId()).getClientId();
sessionBeanMap.remove(session);
log.info(clientId+"关闭了连接");
stringBuffer.append(clientId+"退出了群聊<br/>");
sendMessage(sessionBeanMap);
}
// //每2s发送给客户端心跳消息
// @Scheduled(fixedRate = 2000)
// public void sendMsg() throws IOException {
// for(String key:sessionBeanMap.keySet()){
// sessionBeanMap.get(key).getWebSocketSession().sendMessage(new TextMessage("心跳"));
// }
// }
public void sendMessage(Map<String,SessionBean> sessionBeanMap){
for(String key:sessionBeanMap.keySet()){
try {
sessionBeanMap.get(key).getWebSocketSession().sendMessage(new TextMessage(stringBuffer.toString()));
} catch (IOException e) {
// e.printStackTrace();
log.error(e.getMessage());
}
}
}
}
效果:
第一个页面打开:
第二个页面打开并聊天
文章来源:https://www.toymoban.com/news/detail-842196.html
demo链接:springboot-demo集合: demo集合 - Gitee.com文章来源地址https://www.toymoban.com/news/detail-842196.html
到了这里,关于Springboot + Websocket的集成实现简单的聊天室功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!