阅读完需:约 5 分钟
上一篇我们介绍了在Spring Boot框架下使用WebSocket实现消息推送,消息推送是一对多,服务器发消息发送给所有的浏览器,这次我们来看看如何使用WebSocket实现消息的一对一发送,模拟的场景就是利用网页来实现两个人在线聊天。OK,那我们来看看这个要怎么实现。
项目的总目录:
因为是接着上一个群聊修改的,所有里面的Message,chat.html是没有用的。
1.首先还是创建项目:
这一次的项目要比上一次的群聊多出一个 Spring Security ,其他的一样:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
2.创建SecurityConfig的配置文件:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("java")
.password("123").roles("admin")
.and()
.withUser("sang")
.password("123").roles("user");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
}
1.在configure(HttpSecurity http)方法中,我们首先设置拦截规则,设置默认登录页面以及登录成功后的跳转页面
2.在configure(AuthenticationManagerBuilder auth)方法中,我们定义两个用户,设置用户名、用户密码、用户角色等信息。
3.在configure(WebSecurity web)方法中设置静态资源不被拦截。(这里我没有设置这个)
@Override
public void configure(WebSecurity web) throws Exception {
//设置不拦截规则
web.ignoring().antMatchers("/resources/static/**");
}
3.修改WebSocketConfig 配置:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic","/queue");
registry.setApplicationDestinationPrefixes("/app");
}
//注册连接点
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").withSockJS();
}
}
就添加了一个 “/queue”
4.创建一个新的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;
}
}
5.修改控制器:
@Controller
public class HelloController {
//可以随时随地的给前端发消息
@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);
}
// @MessageMapping("/hello") //接受游览器的消息
// @SendTo("/topic/greetings") //消息转发
// public Message greeting(Message message){
// return message;
// }//返回消息
}
1.SimpMessagingTemplate这个类主要是实现向浏览器发送消息的功能。 2.在Spring MVC中,可以直接在参数中获取Principal,Principal中包含有当前用户的用户名。 3.convertAndSendToUser方法是向用户发送一条消息,第一个参数是目标用户用户名,第二个参数是浏览器中订阅消息的地址,第三个参数是消息本身。
6.登录页面:
<!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>
<table>
<input type="button" id="connect" value="连接">
<input type="button" id="disconnect" disabled="disabled" value="断开连接">
消息内容:<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();//若要从客户端主动断开连接,可调用 disconnect() 方法
}
setConnected(false);
})
$("#send").click(function () {
//JSON.stringify()的作用是将 JavaScript 对象转换为 JSON 字符串,而JSON.parse()可以将JSON字符串转为一个对象。
//send():连接成功后,客户端可使用 send() 方法向服务器发送信息
stompClient.send("/app/chat",{},JSON.stringify({'to':$("#to").val(),'content':$("#content").val()}));
})
})
var stompClient =null;
function connect() {
var socket=new SockJS('/chat');//URL需要连接的地址
stompClient=Stomp.over(socket); // 获取 STOMP 子协议的客户端对象
stompClient.connect({},function (success) { // 向服务器发起websocket连接并发送
setConnected(true);
//订阅、接收信息,必须先订阅相应的URL,即发送一个 SUBSCRIBE 帧,然后才能不断接收来自服务器的推送消息;
//订阅和接收消息通过 subscribe() 方法实现
//点对点连接的时候后台是自动加上 /user 的所以现在也要加上才能匹配
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);//prop() 方法设置或返回被选元素的属性和值。
$("#disconnect").prop("disabled",!flag);//取反
if(flag){
$("#chat").show();//显示可见
}else {
$("#chat").hide();//隐藏可见
}
}
</script>
</body>
</html>
基本和前面的一样
stomp中的connect方法用来连接服务端,连接成功之后注册监听,在注册监听的时候,注册的地址/user/queue/notifications
比WebSocket配置文件中的多了一个/user,这个/user是必不可少的,使用了它消息才会点对点传送。
测试:
更多关于 stomp 的内容: