前面我们已经学习了 WebSocket 的在线群聊实现 本篇文章主要来学习使用 WebSocket 实现消息的一对一发送。
一、前期配置
前面依赖部分和 WebSocket 的在线群聊实现 的一致,不过这里还需要添加 Spring Security 的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
二、配置 Chat 类
Chat 类用来承载服务器返回给浏览器的消息
public class Chat {
private String from;//消息从哪来
private String content;//消息内容
private String to;//消息到哪去
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
}
三、配置 WebSocket
@Configuration
//开启使用STOMP协议来传输基于代理的消息,Broker就是代理的意思
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
/**
* 配置消息代理
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
//定义消息代理的前缀,topic 表示群聊,queue 表示单聊
registry.enableSimpleBroker("/topic","/queue");
//配置一个或者多个前缀,过滤出需要代理方法处理的消息
registry.setApplicationDestinationPrefixes("/app");
}
/**
* 注册STOMP协议的节点,并指定映射的URL
* @param registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//注册STOMP协议节点,同时指定使用 SockJS 协议
registry.addEndpoint("/chat").withSockJS();
}
}
四、配置控制器
这里多了个 Principal
,也就是用户必须登录之后才可以聊,点对点聊必须要知道信息发给谁
@Controller
public class GreetingController {
@Autowired
SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/hello")
public void greeting(Message message) {
simpMessagingTemplate.convertAndSend("/topic/greetings", message);
}
@MessageMapping("/chat")
public void chat(Principal principal, Chat chat) {
//消息从哪来
chat.setFrom(principal.getName());
//要发给谁,要发的地址,要发的对象
simpMessagingTemplate.convertAndSendToUser(chat.getTo(), "/queue/chat", chat);
}
}
(1)
SimpMessagingTemplate
这个类主要是实现向浏览器发送消息的功能。
(2)在Spring MVC中,可以直接在参数中获取Principal
,Principal
中包含有当前用户的用户名。
(3)convertAndSendToUser
方法是向用户发送一条消息,第一个参数是目标用户用户名,第二个参数是浏览器中订阅消息的地址,第三个参数是消息本身。
五、配置 SecurityConfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("yolo")
.password("123")
.roles("admin")
.and()
.withUser("nlcs")
.password("123")
.roles("user");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//所有请求登录后访问
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
}
六、配置 前端页面 onlineChat.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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>
<input type="button" id="connect" value="连接">
<input type="button" id="disconnect" disabled="disabled" value="断开连接">
<hr>
消息内容:<input type="text" id="content">目标用户:<input type="text" id="to"><input type="button" value="发送" id="send">
<div id="conversation"></div>
<script>
$(function () {
$("#connect").click(function () {
connect();
})
$("#disconnect").click(function () {
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
})
$("#send").click(function () {
stompClient.send('/app/chat', {
}, JSON.stringify({
'to': $("#to").val(),
'content': $("#content").val()
}))
})
})
var stompClient = null;
function connect() {
var socket = new SockJS('/chat');
stompClient = Stomp.over(socket);
stompClient.connect({
}, function (success) {
setConnected(true);
//订阅消息,需要加上 /user/,因为 WebSocket 后台调整时会自动加上该前缀
stompClient.subscribe('/user/queue/chat', function (msg) {
showGreeting(JSON.parse(msg.body));
});
})
}
function showGreeting(msg) {
$("#conversation").append('<div>' + msg.from + ':' + msg.content + '</div>');
}
function setConnected(flag) {
$("#connect").prop("disabled", flag);
$("#disconnect").prop("disabled", !flag);
if (flag) {
$("#chat").show();
} else {
$("#chat").hide();
}
}
</script>
</body>
</html>
七、测试
只有登录用户才能互相通信