SpringBoot整合websocket
群聊案例
创建项目
前端库可以自己下载对应需要的js文件放入项目中的static中(前后端分离需要处理跨域),这里为了演示方便,以下我采取单应用webjar模式
maven仓库 mvnrepository.com/ 下载需要的前端库
原生的websocket兼容性较差,这里我们在引入一个兼容性更好的stomp-websocket
定位器依赖(不需要指定版本)
完整的依赖配置
<dependencies>
<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.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/sockjs-client -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>sockjs-client</artifactId>
<version>1.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/stomp-websocket -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>stomp-websocket</artifactId>
<version>2.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/jquery -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/webjars-locator-core -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
</dependencies>
复制代码
项目结构
@Configuration
@EnableWebSocketMessageBroker // 开启消息代理
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {
/**
* 注册端点
* @param registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 定义一个 前缀为 chat 的端点,开启 socketjs 支持,前端需要连接这个端点
registry.addEndpoint("/chat").withSockJS();
}
/**
* 配置消息代理
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 设置消息代理前缀,发送消息的前缀如果是 /topic ,就会把消息转发给消息代理(Broker)
// 代理再把消息广播给所有的客户端
registry.enableSimpleBroker("/topic");
// 上一行配置后,消息代理就配置好了,但是如果有些消息不想采取代理处理,想自己处理,可以自定义
// 下面这行配置的意思是,如果消息的前缀是 /app ,采取特殊处理
// 这里用不到,注释掉先
// registry.setApplicationDestinationPrefixes("/app");
}
}
复制代码
public class Message {
private String name;// 消息来源
private String content;// 消息内容
//getter,setter...
}
复制代码
@Controller
public class GreetingController {
@MessageMapping("/hello") // 接收消息地址
@SendTo("/topic/greeting") // 转发给广播地址,前端监听这个地址就能收到消息
public Message greeting(Message message) {
return message;
}
}
复制代码
<!DOCTYPE html>
<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>
</head>
<body>
<!-- 模拟用户名 -->
<div>
<input id="username" type="text" placeholder="用户名">
</div>
<!--连接断开按钮-->
<div>
<button type="button" id="connect">连接</button>
<button type="button" id="disconnect" disabled="disabled">断开连接</button>
</div>
<!--输入聊天内容-->
<div>
<input type="text" id="content">
<button id="send" type="button" disabled="disabled">发送</button>
</div>
<!--显示聊天内容-->
<div id="chat" style="border:5px solid #000"></div>
<script>
var stompClient;
$(function () {
// 点击连接按钮
$('#connect').click(function () {
connect();
})
// 点击断开连接按钮
$('#disconnect').click(function () {
stompClient.disconnect();
setConnect(false);
})
// 点击发送内容按钮
$('#send').click(function () {
// 参数1:发送 消息的地址接口
// 参数2:优先级 一般空着就行
// 参数3:消息本身 json格式字符串
stompClient.send('/hello',{},JSON.stringify({
'name':$('#username').val(),
'content':$('#content').val()
}))
})
})
// 建立连接
function connect() {
// 判断是否添加用户名
if (!$('#username').val()) {
return;
}
// 指定端点
var socketjs = new SockJS("/chat");
// 创建 Stomp 对象来操作 websocket
stompClient = Stomp.over(socketjs);
// 建立连接
stompClient.connect({},function (frame) {// 连接成功的回调函数
// 连接成功 连接按钮禁用,断开连接按钮启用
setConnect(true);
// 监听 广播地址
// greeting是返回的消息
stompClient.subscribe('/topic/greeting',function (greeting) {
var msgBody = JSON.parse(greeting.body);
$('#chat').append('<div>'+msgBody.name+' : '+ msgBody.content +'</div>')
})
})
}
// 按钮状态设置
function setConnect(connected) {
$('#connect').prop('disabled',connected);
$('#disconnect').prop('disabled',!connected);
$('#send').prop('disabled',!connected);
}
</script>
</body>
</html>
复制代码
启动浏览器测试(启动两个不同的浏览器,Chrome可以采取访客模式模拟)
私聊案例
私聊中涉及用户概念,配合security将非常的舒服,如果采取shiro就比较麻烦了,案例采取security来配置用户
依赖配置
<dependencies>
<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.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/sockjs-client -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>sockjs-client</artifactId>
<version>1.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/stomp-websocket -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>stomp-websocket</artifactId>
<version>2.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/jquery -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/webjars-locator-core -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
复制代码
项目结构
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("southyin")
.password("{noop}123")
.roles("admin")
.and()
.withUser("root")
.password("{noop}123")
.roles("admin");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and().formLogin().permitAll();
}
}
复制代码
@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {
/**
* 注册端点
* 新版的 springboot 配合 security 在配置端点时,需要指定允许连接的域
* @param registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 定义一个 前缀为 chat 的端点,开启 socketjs 支持
registry.addEndpoint("/chat").setAllowedOriginPatterns("http://localhost:8080").withSockJS();
}
/**
* 配置消息代理
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 设置消息代理前缀,发送消息的前缀如果是 /topic ,就会把消息转发给消息代理(Broker)
// 代理再把消息广播给所有的客户端
// /queue 用来做点对点,不影响群聊
registry.enableSimpleBroker("/topic","/queue");
}
}
复制代码
@Controller
public class GreetingController {
@MessageMapping("/hello") // 消息地址
@SendTo("/topic/greeting") // 转发给广播地址,前端监听这个地址就能收到消息
public Message greeting(Message message) {
// 作用和 SendTo 注解等效
// messagingTemplate.convertAndSend("/topic/greeting",message);
return message;
}
// 点对点需要的对象
@Autowired
SimpMessagingTemplate messagingTemplate;
/**
* @param principal 用户信息
* @param chat 发过来的具体消息
*/
@MessageMapping("/online_chat")
public void chat(Principal principal, Chat chat) {
// 获取登录者用户名
String name = principal.getName();
chat.setFrom(name);
// 私聊的消息转发到 /queue/chat 前端监控获取信息
messagingTemplate.convertAndSendToUser(chat.getTo(),"/queue/chat",chat);
}
}
复制代码
public class Chat {
private String to;// 发给谁
private String from;// 谁发的
private String content;//内容
// getter,setter
}
复制代码
<!DOCTYPE html>
<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>
</head>
<body>
<!-- 模拟用户名 -->
<div>
<input id="username" type="text" placeholder="目标用户名">
</div>
<!--输入聊天内容-->
<div>
<input type="text" id="content">
<button id="send" type="button">发送</button>
</div>
<!--显示聊天内容-->
<div id="chat" style="border:5px solid #000"></div>
<script>
var stompClient;
$(function () {
// 建立连接
connect();
// 点击发送内容按钮
$('#send').click(function () {
// 参数1:发送 消息的地址接口
// 参数2:优先级 一般空着就行
// 参数3:消息本身
stompClient.send('/online_chat',{},JSON.stringify({
'to':$('#username').val(),
'content':$('#content').val()
}))
})
})
// 建立连接
function connect() {
// 指定端点
var socketjs = new SockJS("/chat");
// 创建 Stomp 对象来操作 websocket
stompClient = Stomp.over(socketjs);
// 建立连接
stompClient.connect({},function (frame) {// 连接成功的回调函数
// 监听 广播地址
// 私聊需要添加 user 前缀,不可省略!!!!!!
// greeting是返回的消息
stompClient.subscribe('/user/queue/chat',function (greeting) {
var msgBody = JSON.parse(greeting.body);
$('#chat').append('<div>'+msgBody.from+' : '+ msgBody.content +'</div>')
})
})
}
</script>
</body>
</html>
复制代码
测试
近期评论