# websocket-study
**Repository Path**: ChengSongyun/websocket-study
## Basic Information
- **Project Name**: websocket-study
- **Description**: 关于全双工WebSocket协议的学习
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-09-18
- **Last Updated**: 2025-09-18
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# WebSocket
> websocket是一个全双工通讯协议,它只有一次握手,发送一个特殊的请求将http协议升级为Websocket协议
>
> 全双工:就是客户端可以随时向服务端发送消息,服务端也可以随时向客户端发送消息
## 一、引入依赖
> 在java中,我们想要使用websocket我们需要先引入两个依赖
```xml
jakarta.websocket
jakarta.websocket-api
2.2.0
provided
jakarta.websocket
jakarta.websocket-client-api
2.2.0
```
## 二、WebSocket基本使用
### 1、编写服务端
> 在服务端中,我们需要编写一个WebSocketServer类来实现Websocket的交互
```java
@ServerEndpoint
public class WebSocketServer{
@Onopen
public void onOpen(Session session){
System.out.println("客户端已连接");
}
@OnMessage
public void onMessage(String message,Session session){
System.out.println("接收到的消息:"+message);
session.getBasicRemote().sendText("Hello client");
}
@OnClose
public void onClose(Session session){
System.out.println("连接断开");
}
}
```
> 注解:
>
> @ServerEndpoint("/connection"):标注的类将成为WebSocket的端点,前端通过value值访问
>
> @Onopen:该注解标注的方法将在连接建立成功时调用
>
> @Message:该注解标注的方法将在客户端发送消息时调用
>
> @Close:该注解标注的方法将在连接关闭时调用
>
> @Error:该注解标注的方法将在连接错误时调用
>
> 方法:
>
> session.getBasicRemote().sendText():该方法用于给客户端发送消息
### 2、编写客户端
> 在客户端中也需要使用到WebSocket才能实现交互
#### 1.创建websocket对象
> 创建websocket对象用于发送请求和后续使用websocket的API方法
>
> 发送的不再是http请求,而是ws请求
```js
const ws = new WebSocket("ws://localhost:8080/connection")
```
#### 2.api方法
> 使用websocket对象中的api方法发送消息给服务端
>
> ws.onopen:连接成功时调用
>
> ws.onmessage:服务端发送消息时调用
>
> ws.onclose:连接关闭时调用
>
> ws.send():给服务端发送消息
```js
ws.onopen = function(){
console.log('与服务器建立连接');
//发送消息
ws.send('Hello Server!');
}
//onmessage方法,接收服务端发送的消息
ws.onmessage = function(event){
console.log(event.data);
}
//onclose方法
ws.onclose = function(){
console.log("与服务器断开连接")
}
```
## 三、WebSocket传参
> 在发送消息时,我们可以需要传递一些参数给服务端,让我们获取到一些信息(比如:谁发的,什么时候发的)
>
>
>
> 注意:关于WebSocket的更加深入的用法可以看work01项目下的案例
### 1、引入servlet依赖
> 我们需要使用servlet来进行测试
```xml
jakarta.servlet
jakarta.servlet-api
6.1.0
```
### 2、编写握手处理器
> 握手处理器用于在握手时获取servlet环境的对象信息
>
> (如:HttpSession,HttpRequest等)
>
> 并将这些数据保存到websocket的session对象中
>
> 需要继承Configurator并重写modifyHandshake()握手方法
```java
public class HandshakeHandler extends Configurator{
@Override
public void modifyHandshake(ServerEndpointConfig sec,HandshakeRequest request,HandshakeResponse reponse){
//获取HttpSession对象
HttpSession httpSession = (HttpSession) request.getHttpSession();
//从HttpSession中获取登录的用户信息
String user = (String) httpSession.getAttribute("user");
//将用户信息保存到WebSocket的Session对象中
//每一个WebSocket的session都维护了一个map集合
//getUserProperties()得到session的map
sec.getUserProperties.put("user",user);
}
}
```
### 3、编写WebSocketServer
> 在该类中我们需要一个存储Session的Map集合,并且还需要设置握手处理器,使握手处理器生效,还需要实现群发
>
> Session:这是WebSocketSession,每个websocket连接都有一个session对象
```java
//必须在configurator属性中设置握手处理器,不然握手处理器不会生效
@ServerEndpoint(value = "/chat",configurator = HandshakeHandler.class)
public class WebSocketServer{
/**
* 使用map集合维护一个用户列表
* key是一个唯一的id
* value是客户端session对象
*/
private static final Map users = new HashMap<>();
/**
* 每当有用户连接时,创建的session就保存到用户列表中
*/
@OnOpen
public void onopen(Session session) throw IOException{
//从WebSocket的session对象中获取到用户信息
String user = (String) session.getUserProperties().get("user");
users.put(user,session);
}
@OnMessage
public void onMessage(Session session,String message){
String user = (String) session.getUserProperties().get("user");
}
/**
* 给所有客户端发送消息
* 群发
*/
public void sendAllUser(String message){
users.forEach((id,session) -> {
try {
//注意:sendText()方法中的参数必须是String类型
session.getBasicRemote().sendText(message);
} catch (IOException e) {
throw new RuntimeException("发送失败:"+e);
}
});
}
/**
* 用户离线
* 每当用户离线后,就将该用户从用户列表中移除
* @param session
* @throws IOException
*/
@OnClose
public void onClose(Session session) throws IOException {
String user = (String) session.getUserProperties().get("user");
sessionMap.remove(user);
}
}
```
### 4、编写LoginServlet
> 编写登录的Servlet用于测试
```java
@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//从客户端中获取到name为user的表单的值
String user = req.getParameter("user");
//将用户保存到HttpSession,以便在握手处理器中使用
req.getSession().setAttribute("user", user);
//转发到聊天页面
req.getRequestDispatcher("/WEB-INF/index.html").forward(req, resp);
}
}
```
### 5、编写登录页面
> 编写登录页面用于传递用户信息
```html
Title
Login
```
### 6、编写聊天页面
> 编写聊天页面用于渲染消息
```html
聊天室
聊天室
```