1.点对点消息发送
1.1 加入依赖
既然是点对点发送,就会涉及到用户的概念,因此,需要在项目中先加入Spring Security的依赖,代码如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
1.2 配置Spring Security
在Spring Security进行配置,添加两个用户,同时配置所有地址认证后才能访问。
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("123456").roles("admin")
.and()
.withUser("jiangbin").password("123456").roles("user");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.csrf().disable();
}
}
1.3 配置 WebSocket
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
/**
* 消息代理
* @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"的Endpoint,同时开启sockJS支持
}
}
这里新增了一个消息代理broker前缀"/queue",用来管理点对点消息。前缀"/topic"用来管理群发消息。
1.4 配置Controller
@Controller
public class GreetingController {
@Autowired
SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/chatPerson")
public void chat(Principal principal, Chat chat){ //Principal获取当前登录用户的信息
chat.setFrom(principal.getName());
simpMessagingTemplate.convertAndSendToUser(chat.getTo(),"/queue/chat",chat);
}
}
public class Chat {
private String from;
private String content;
private String to;
//省略getter/setter
}
@MessageMapping("/chatPerson")注解表示来自"/app/chatPerson"路径的消息会被chat方法处理,chat方法的第一个参数Principal可以获取当前登录用户的信息,第二个参数是客户端发送来的消息。在chat方法中,首先获取登录用户的用户名,设置给chat对象的from属性,在将消息出去,发送的目标用户就是chat对象的to属性值。
1.5 创建在线聊天界面
<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>
<div id="chatContent"></div>
<div>
<label for="content">请输入聊天内容</label>
<input type="text" id="content" placeholder="聊天内容">
<br>
<label for="to">目标用户</label>
<input type="text" id="to" placeholder="目标用户">
<br>
<button type="button" id="send">发送</button>
<button id="connect" type="button">连接</button>
<button id="disconnect" disabled="disabled" type="button">断开连接</button>
</div>
<script>
var stompClient = null;
$(function () {
$("#connect").click(function () {
connect();
});
$("#disconnect").click(function () {
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
});
$("#send").click(function () {
sendMsg();
})
});
function sendMsg() {
stompClient.send("/app/chatPerson", {}, JSON.stringify({'content': $("#content").val(), 'to': $("#to").val()}));
}
function connect() {
var stomp = new SockJS('/chat'); //建立连接
stompClient = Stomp.over(stomp); //通过stomp实例发起连接请求
stompClient.connect({}, function (success) {
setConnected(true);
stompClient.subscribe('/user/queue/chat', function (msg) {
showGreeting(JSON.parse(msg.body))
});
});
}
function showGreeting(message) {
$("#chatContent").append("<div>" + message.from + ":" + message.content + "<div>");
}
function setConnected(flag) {
$("#connect").prop("disabled", flag);
$("#disconnect").prop("disabled", !flag);
}
</script>
</body>
</html>
连接成功后,订阅服务端返回数据的地址为’/user/queue/chat’,该地址比服务端配置的地址多了"user"前缀,这是因为SimpMessagingTemplate类中自动添加路径前缀。接着进行测试即可。