本文实例为大家分享了SpringBoot的WebSocket实现单聊群聊,供大家参考,具体内容如下
说在开头
在HTTP协议中,所有的请求都是由客户端发送给服务端,然后服务端发送请求
要实现服务器向客户端推送消息有几种methods:
1、轮询
大量无效请求,浪费资源
2、长轮询
有新数据再推送,但这会导致连接超时,有一定隐患
3、Applet和Flash
过时,安全隐患,兼容性不好
消息群发
创建新项目:
添加依赖:
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
|
< 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 >
< dependency >
< groupId >org.webjars</ groupId >
< artifactId >sockjs-client</ artifactId >
< version >1.1.2</ version >
</ dependency >
< dependency >
< groupId >org.webjars</ groupId >
< artifactId >jquery</ artifactId >
< version >3.3.1</ version >
</ dependency >
< dependency >
< groupId >org.webjars</ groupId >
< artifactId >stomp-websocket</ artifactId >
< version >2.3.3</ version >
</ dependency >
< dependency >
< groupId >org.webjars</ groupId >
< artifactId >webjars-locator-core</ artifactId >
</ dependency >
|
创建WebSocket配置类:WebSocketConfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Configuration
@EnableWebSocketMessageBroker //注解开启webSocket消息代理
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
/**
* 配置webSocket代理类
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker( "/topic" ); //代理消息的前缀
registry.setApplicationDestinationPrefixes( "/app" ); //处理消息的方法前缀
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint( "/chat" ).withSockJS(); //定义一个/chat前缀的endpioint,用来连接
}
}
|
创建Bean
1
2
3
4
5
6
7
8
|
/**
* 群消息类
*/
public class Message {
private String name;
private String content;
//省略getter& setter
}
|
定义controller的方法:
1
2
3
4
5
6
7
8
9
10
11
12
|
/**
* MessageMapping接受前端发来的信息
* SendTo 发送给信息WebSocket消息代理,进行广播
* @param message 页面发来的json数据封装成自定义Bean
* @return 返回的数据交给WebSocket进行广播
* @throws Exception
*/
@MessageMapping ( "/hello" )
@SendTo ( "/topic/greetings" )
public Message greeting(Message message) throws Exception {
return message;
}
|
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< title >Title</ title >
< script src = "/webjars/jquery/jquery.min.js" ></ script >
< script src = "/webjars/sockjs-client/sockjs.min.js" ></ script >
< script src = "/webjars/stomp-websocket/stomp.min.js" ></ script >
< script >
var stompClient = null;
//点击连接以后的页面改变
function setConnected(connection) {
$("#connect").prop("disable",connection);
$("#disconnect").prop("disable",!connection);
if (connection) {
$("#conversation").show();
$("#chat").show();
} else {
$("#conversation").hide();
$("#chat").hide();
}
$("#greetings").html("");
}
//点击连接按钮建立连接
function connect() {
//如果用户名为空直接跳出
if (!$("#name").val()) {
return;
}
//创建SockJs实例,建立连接
var sockJS = new SockJS("/chat");
//创建stomp实例进行发送连接
stompClient = Stomp.over(sockJS);
stompClient.connect({}, function (frame) {
setConnected(true);
//订阅服务端发来的信息
stompClient.subscribe("/topic/greetings", function (greeting) {
//将消息转化为json格式,调用方法展示
showGreeting(JSON.parse(greeting.body));
});
});
}
//断开连接
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
setConnected(false);
}
//发送信息
function sendName() {
stompClient.send("/app/hello",{},JSON.stringify({'name': $("#name").val() , 'content': $("#content").val()}));
}
//展示聊天房间
function showGreeting(message) {
$("#greetings").append("< div >"+message.name + ":" + message.content + "</ div >");
}
$(function () {
$("#connect").click(function () {
connect();
});
$("#disconnect").click(function () {
disconnect();
});
$("#send").click(function () {
sendName();
})
})
</ script >
</ head >
< body >
< div >
< label for = "name" >用户名</ label >
< input type = "text" id = "name" placeholder = "请输入用户名" >
</ div >
< div >
< button id = "connect" type = "button" >连接</ button >
< button id = "disconnect" type = "button" >断开连接</ button >
</ div >
< div id = "chat" style = "display: none;" >
< div >
< label for = "name" ></ label >
< input type = "text" id = "content" placeholder = "聊天内容" >
</ div >
< button id = "send" type = "button" >发送</ button >
< div id = "greetings" >
< div id = "conversation" style = "display: none;" >群聊进行中</ div >
</ div >
</ div >
</ body >
</ html >
|
私聊
既然是私聊,就要有对象目标,也是用户,可以用SpringSecurity引入
所以添加额外依赖:
1
2
3
4
|
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-security</ artifactId >
</ dependency >
|
配置SpringSecurity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser( "panlijie" ).roles( "admin" ).password( "$2a$10$5Pf0KhCdnrpMxP5aRrHvMOsvV2fvfWJqk0SEDa9vQ8OWwV8emLFhi" )
.and()
.withUser( "suyanxia" ).roles( "user" ).password( "$2a$10$5Pf0KhCdnrpMxP5aRrHvMOsvV2fvfWJqk0SEDa9vQ8OWwV8emLFhi" );
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
}
}
|
在原来的WebSocketConfig配置类中修改:也就是多了一个代理消息前缀:"/queue"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Configuration
@EnableWebSocketMessageBroker //注解开启webSocket消息代理
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
/**
* 配置webSocket代理类
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker( "/topic" , "/queue" ); //代理消息的前缀
registry.setApplicationDestinationPrefixes( "/app" ); //处理消息的方法前缀
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint( "/chat" ).withSockJS(); //定义一个/chat前缀的endpioint,用来连接
}
}
|
创建Bean:
1
2
3
4
5
6
|
public class Chat {
private String to;
private String from;
private String content;
//省略getter& setter
}
|
添加controller方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/**
* 点对点发送信息
* @param principal 当前用户的信息
* @param chat 发送的信息
*/
@MessageMapping ( "chat" )
public void chat(Principal principal, Chat chat) {
//获取当前对象设置为信息源
String from = principal.getName();
chat.setFrom(from);
//调用convertAndSendToUser("用户名","路径","内容");
simpMessagingTemplate.convertAndSendToUser(chat.getTo(), "/queue/chat" , chat);
}
|
创建页面:
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
|
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< title >Title</ title >
< script src = "/webjars/jquery/jquery.min.js" ></ script >
< script src = "/webjars/sockjs-client/sockjs.min.js" ></ script >
< script src = "/webjars/stomp-websocket/stomp.min.js" ></ script >
< script >
var stompClient = null;
function connect() {
var socket = new SockJS("/chat");
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
stompClient.subscribe('/user/queue/chat', function (chat) {
showGreeting(JSON.parse(chat.body));
});
});
}
function sendMsg() {
stompClient.send("/app/chat",{},JSON.stringify({'content' : $("#content").val(), 'to': $("#to").val()}));
}
function showGreeting(message) {
$("#chatsContent").append("< div >" + message.from + ":" + message.content + "</ div >");
}
$(function () {
connect();
$("#send").click(function () {
sendMsg();
});
});
</ script >
</ head >
< body >
< div id = "chat" >
< div id = "chatsContent" >
</ div >
< div >
请输入聊天内容
< input type = "text" id = "content" placeholder = "聊天内容" >
< input type = "text" id = "to" placeholder = "目标用户" >
< button type = "button" id = "send" >发送</ button >
</ div >
</ div >
</ body >
</ html >
|
暂结!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/coding_deliver/article/details/109568091