最近在学习websocket,做份笔记和大家分享一下
1、引入相关依赖springboot相关依赖就不写了,这里只写websocket的依赖
org.springframework.boot spring-boot-starter-websocket
2、写配置文件
这里注意不要漏了 @EnableWebSocket,用于开启websocket支持,同时 @Configuration将配置类注入spring容器
package com.websocket.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
@Configuration
//开启websocket支持
@EnableWebSocket
public class WebsocketConfig
{
@Bean
public ServerEndpointExporter serverEndpointExporter()
{
return new ServerEndpointExporter();
}
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer()
{
ServletServerContainerFactoryBean bean = new ServletServerContainerFactoryBean();
//文本缓冲区大小
bean.setMaxTextMessageBufferSize(8192);
//字节缓冲区大小
bean.setMaxBinaryMessageBufferSize(8192);
return bean;
}
}
3、开始愉快的使用啦
这里先介绍几个websocket的注解
| 注解 | 作用 | 备注 |
|---|---|---|
| @ServerEndpoint | 用于声明websocket响应类,有点像@RequestMapping | @ServerEndpoint("/websocket") |
| @OnOpen | websocket连接时触发 | 参数有:Session session, EndpointConfig config |
| @OnMessage | 有消息时触发 | 参数很多,一会再说 |
| @OnClose | 连接关闭时触发 | 参数有:Session session, CloseReason closeReason |
| @OnError | 有异常时触发 | 参数有:Session session, Throwable throwable |
3.1(重要) 将@ServerEndpoint标注在类上,然后依次创建4个方法,参数见上表,方法名随意
注意类上需要有 @Component 扫描哦,我这里用的时@Controller
@Log4j2
@Controller
@ServerEndpoint("/websocket")
public class baseWebsocketController
{
//使用 ConcurrentHashMap, 保证线程安全, static全局共享 session
//这里之所以static,是因为这个类不是单例的!!
//他虽然有@Controller注解,但是不适用Ioc容器中拿对象,每一次请求过来都是一个新的对象
//存放 session
private final static Map sessions = new ConcurrentHashMap<>();
//onopen 在连接创建(用户进入聊天室)时触发
@OnOpen
public void openSession(Session session, EndpointConfig config)
{
}
//响应字符串
@OnMessage
public void onMessage(Session session, String message)
{
}
//响应字节流
@OnMessage
public void onMessage(Session session, byte[] message)
{
}
//onclose 在连接断开(用户离开聊天室)时触发
@OnClose
public void closeSession(Session session, CloseReason closeReason)
{
}
@OnError
public void sessionError(Session session, Throwable throwable)
{
}
}
说明
细心的小伙伴可能发现,我有两个 @OnMessage, 这是因为websocket能发送三种请求(我知道的三种),一种是字符串,一种是字节流(用于上传文件),一种是ping-pong(乒乓机制),因为js不好发送ping请求,我这里就只有响应字符串和字节流两种方法。
接下来的篇幅将只演示字符串的,字节流咱再另一篇说,不然太多了看的头痛3.2 往方法里面写点简单的东西
里面注释写个很清楚哦,慢慢瞅,咱就解释一下流程:
1、再OnOpen中将session存起来,并通知其他用户,有人来啦。
2、有消息来的时候,再OnMessage中,通知其他用户
3、OnClose中,通知其他用户,别人溜了
4、OnError中,有异常就关闭websocket
@Log4j2
@Controller
@ServerEndpoint("/websocket")
public class baseWebsocketController
{
//使用 ConcurrentHashMap, 保证线程安全, static全局共享 session
//这里之所以static,是因为这个类不是单例的!!
//他虽然有@Controller注解,但是不适用Ioc容器中拿对象,每一次请求过来都是一个新的对象
//存放 session
private final static Map sessions = new ConcurrentHashMap<>();
//onopen 在连接创建(用户进入聊天室)时触发
@OnOpen
public void openSession(Session session, EndpointConfig config)
{
//将session存起来, 用于服务器向浏览器发送消息
sessions.put(session.getId(), session);
sendAll("[" + session.getId() + "]进入房间");
}
//响应字符串
@OnMessage
public void onMessage(Session session, String message)
{
sendAll("[" + session.getId() + "]" + message);
}
//响应字节流
@OnMessage
public void onMessage(Session session, byte[] message)
{
//这个咱以后再说
}
//onclose 在连接断开(用户离开聊天室)时触发
@OnClose
public void closeSession(Session session, CloseReason closeReason)
{
//记得移除相对应的session
sessions.remove(session.getId());
sendAll("[" + session.getId() + "]离开了房间");
}
@OnError
public void sessionError(Session session, Throwable throwable)
{
//通常有异常会关闭session
try {
session.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
private void sendAll(String message)
{
for (Session s : sessions.values()) {
//获得session发送消息的对象
//Basic是同步, 会阻塞
//Async是异步, 这个会有多线程并发导致异常, 发送消息太快也会有并发异常, 需要有 消息队列 来辅助使用
final RemoteEndpoint.Basic remote = s.getBasicRemote();
try {
//发送消息
remote.sendText(message);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.3 写个页面使用websocket
4、最后填下坑 4.1@OnOpen、@OnMessage…那些参数是咋来滴?websocket-demo
当然是看注释啦!转到源码,再类的上边有一大串注释,百度翻译看下就行。
我上边还有漏的哦~~
and Zero to n String or Java primitive parameters
annotated with the {@link javax.websocket.server.PathParam} annotation for server endpoints.
意思是可以再路径中加入参数,然后用 @PathParam注解获得该参数(是不是和web很像呢)
也就是说,可以这样
@ServerEndpoint("/websocket/{username}")
然后这样获得参数(所有方法都可以加),而且可以不止一个
//响应字符串
@OnMessage
public void onMessage(@PathParam("username") String username, Session session, String message)
{
sendAll("[" + username + "]" + message);
}
再html连接时,url就这么写
let username = $('#username').val();
let url = 'ws://127.0.0.1:8080/websocket';
url = url+'/'+username;
所以啊,刚刚我们demo的用户名是可以显示出来的(这个就交给大家了,懒 >_<)。
End
以后有时间写下关于websocket文件上传的,着急的小伙伴下面评论,我开个小灶丫~



