平台奖励创作,可能会升级VIP文章,可以移步我的公众号:【编程朝花夕拾】,且可获取首发内容。
01 引言
之前探索了一下直播间实时评论的的背后技术,这一节,我们将选用最经典的WebSocket
的模拟这一功能的实现。
WebSocket
可以基于Netty
实现,也可以基于Springboot
实现。本节使用Springboot
自带的WebSocket
实现。
02 Maven依赖的引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 编写页面使用 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 序列化对象工具类 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
03 直播间实时评论模拟实战
下来我们将一步步搭建WebSocket
,实现模拟直播间。具体的使用可以参见官方的文档说明:
https://docs.spring.io/spring-framework/docs/5.3.31/reference/html/web.html#websocket-server
3.1 创建WebSocket
处理器
官方案例给的比较简单,我们来实现属于我们自己的处理器。
- ① 建立连接,保存当前的客户端
- ② 处理文本消息
- ③ 连接关闭后,删除当前客户端
- ④ 模拟敏感词处理-
建立连接
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
log.info("链接建立成功......");
String sessionId = session.getId();
WebSocketSession webSocketSession = SESSION_MAP.get(sessionId);
if (webSocketSession == null) {
SESSION_MAP.put(sessionId, session);
}
// 发送消息
noticeClient(session, sessionId.substring(0, 5) + "*** 进入了直播间");
}
接收消息
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 收到客户端发送的消息
String sessionId = session.getId();
// 敏感词操作
String msg = doSensitivewords(message);
log.info("sessionId={} 收到消息={}", sessionId, msg);
noticeClient(session, msg);
}
关闭连接
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
log.info("链接关闭......");
String sessionId = session.getId();
SESSION_MAP.remove(sessionId);
noticeClient(session, sessionId.substring(0, 5) + "*** 离开了直播间");
}
模拟敏感词处理
private String doSensitivewords(TextMessage message) {
String payload = message.getPayload();
// 假设敏感词为【死亡】
if (payload.contains("死亡")) {
payload = payload.replace("死亡", "***");
}
return payload;
}
通知客户端
这里通知客户端,是需要通知所有的已连接的客户端。
private void noticeClient(WebSocketSession session, String message) {
String sessionId = session.getId();
// 发送消息,在线人数加1
Map<String, Object> msgMap = new HashMap<>();
msgMap.put("msg", message);
msgMap.put("time", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
msgMap.put("sessionId", sessionId.substring(0, 5)+ "***");
msgMap.put("count", SESSION_MAP.values().size());
SESSION_MAP.values().forEach(item -> {
try {
item.sendMessage(new TextMessage(JSON.toJSONString(msgMap)));
log.info("发送消息完成");
} catch (IOException e) {
log.error("发送消息异常......", e);
}
});
}
3.2 配置WebSocket
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer{
@Autowired
MyWebSocketHandler myWebSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myWebSocketHandler, "/ws/live").setAllowedOrigins("*");
}
}
/ws/live
为WebSocket
的连接。另外还需要设置允许的请求源,这里允许所有,否则无法连接服务器。
myWebSocketHandler
是上一节创建的处理器。
3.3 客户端的处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模拟直播室实时评论的功能</title>
</head>
<body>
<div style="width: 700px; margin: 0 auto;">
<div>
<h1>直播间</h1>
<div>
<span>直播间人数:</span>
<span style="color: blue" id="count">1</span>
</div>
<div id="message" style="height: 300px; overflow: auto; border: 1px solid #ccc;"></div>
</div>
<div style="margin-top: 10px;">
<input type="text" id="messageInput">
<button onclick="sendMessage()">发送评论</button>
</div>
</div>
</body>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
let socket = new WebSocket("ws://localhost:8080/ws/live");
// 打来链接
socket.onopen = function(event) {
console.log("WebSocket is open now.");
};
// 处理消息
socket.onmessage = function(event) {
let message = event.data;
console.log(event);
console.log("Received message: " + message);
let json = JSON.parse(message);
$("#message").append('<p><span style="color: blueviolet">'+json.time+ '('+json.sessionId+'):</span>'+ json.msg + '</p>');
$("#count").text(json.count);
};
// 关闭链接
socket.onclose = function(event) {
console.log("WebSocket is closed now.");
};
// 发送消息
function sendMessage() {
let message = $("#messageInput").val();
socket.send(message);
$("#messageInput").val("");
}
</script>
</html>
客户端主要功能,就是建立连接,接收消息和发送消息。
3.4 测试
第一个人进入直播间
第二个人进入直播间
发送消息
任何一个人发送消息后,都会显示在直播间里面。
敏感词处理
用户输入了【死亡笔记】,检测到【死亡】,直接处理成【***】
关闭客户端
04 小结
上面简单的模拟实现了直播间实时评论的功能。业务功能的大致实现思路就是如此。但是在实际应用中需要考虑很多因素,比如安全、性能、资源等。
安全性,需要在进入直播间校验当前用户的身份或者其他限制。
性能,直播间能够抗住多少并发,限制在线人数等。
资源,用户正常关闭客户端本身没有问题,如果因为网络问题,用户无法关闭客户端,或者服务端没有及时删除掉已经离线的客户端,就会造成服务端资源的浪费
如何检测客户端是否已经掉线,敏感词的动态处理、用户禁言、提出直播间等这些隐藏功能可能都需要实现的。
万丈高楼平地起,任何复杂的业务都是由简单的逻辑一点点的积累而成的。希望这次简单的分享,能够带给你灵感。