本文参考自:
https://blog.lqdev.cn/2018/08/14/springboot/chapter-nineteen/
搭建一个简易聊天室
0.加入POM
依赖。
1
2
3
4
5
6
7
8
| <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
|
1.编写控制层,对应WebSocket
的各事件。同时抽取了个公用类,进行通用方法调用。
WebSocketController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
| /**
* websocket 简易聊天
* @author oKong
*
*/
//由于是websocket 所以原本是@RestController的http形式
//直接替换成@ServerEndpoint即可,作用是一样的 就是指定一个地址
//表示定义一个websocket的Server端
@Component
@ServerEndpoint(value = "/my-chat/{usernick}")
@Slf4j
public class WebSocketController {
/**
* 连接事件 加入注解
* @param session
*/
@OnOpen
public void onOpen(@PathParam(value = "usernick") String userNick,Session session) {
String message = "有新游客[" + userNick + "]加入聊天室!";
log.info(message);
WebSocketUtil.addSession(userNick, session);
//此时可向所有的在线通知 某某某登录了聊天室
WebSocketUtil.sendMessageForAll(message);
}
@OnClose
public void onClose(@PathParam(value = "usernick") String userNick,Session session) {
String message = "游客[" + userNick + "]退出聊天室!";
log.info(message);
WebSocketUtil.remoteSession(userNick);
//此时可向所有的在线通知 某某某登录了聊天室
WebSocketUtil.sendMessageForAll(message);
}
@OnMessage
public void OnMessage(@PathParam(value = "usernick") String userNick, String message) {
//类似群发
String info = "游客[" + userNick + "]:" + message;
log.info(info);
WebSocketUtil.sendMessageForAll(message);
}
@OnError
public void onError(Session session, Throwable throwable) {
log.error("异常:", throwable);
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
throwable.printStackTrace();
}
}
|
WebSocketUtil.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| public class WebSocketUtil {
/**
* 简单使用map进行存储在线的session
*
*/
private static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<>();
public static void addSession(String userNick,Session session) {
//putIfAbsent 添加键—值对的时候,先判断该键值对是否已经存在
//不存在:新增,并返回null
//存在:不覆盖,直接返回已存在的值
// ONLINE_SESSION.putIfAbsent(userNick, session);
//简单示例 不考虑复杂情况。。怎么简单怎么来了。。
ONLINE_SESSION.put(userNick, session);
}
public static void remoteSession(String userNick) {
ONLINE_SESSION.remove(userNick);
}
/**
* 向某个用户发送消息
* @param session 某一用户的session对象
* @param message
*/
public static void sendMessage(Session session, String message) {
if(session == null) {
return;
}
// getAsyncRemote()和getBasicRemote()异步与同步
Async async = session.getAsyncRemote();
//发送消息
async.sendText(message);
}
/**
* 向所有在线人发送消息
* @param message
*/
public static void sendMessageForAll(String message) {
//jdk8 新方法
ONLINE_SESSION.forEach((sessionId, session) -> sendMessage(session, message));
}
}
|
注意点:
- @ServerEndpoint的value值填写时,开头需要加上
/
,不然会提示路径无效。 - 需要加上类型
@Component
注解,使得能被扫描到。 - 这里的
session
等,都在包javax.websocket
包下的,注意区分。
2.编写主启动类,主要是加入注解@EnableWebSocket
和申明一个Websocket endpoint
类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| @SpringBootApplication
@EnableWebSocket
@Slf4j
public class Chapter19Application {
public static void main(String[] args) {
SpringApplication.run(Chapter19Application.class, args);
log.info("Chapter19启动!");
}
/**
* 会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
* 要注意,如果使用独立的servlet容器,
* 而不是直接使用springboot的内置容器,
* 就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
|
3.启动应用,利用在线的测试工具进行测试。这里直接使用了http://coolaf.com/tool/chattest进行测试。当然也可以自己写一个html
了。
首先,输入我们的服务地址:ws://127.0.0.1:8080/my-chat/okong,(127.0.0.1代表本机)
这里我报错了

发现是写的拦截器拦截了请求,修改拦截器

成功!
再开一个
