一、根据《Thymeleaf获取用户名》添加 sec 标签支持;
- 点对点发送消息,需要用户信息,这里引入 Spring Security 依赖,因为集成更方便。
- 项目之前已经引入 Spring Security ,在这里直接使用即可。
- 添加 sec 标签支持,用来显示当前登录用户名。
二、WebSocketConfig配置类,加入一个点对点代理路径 /queue:
package com.mall.websocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker // 开启WebSocket代理
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// 设置消息代理前缀
// 即如果消息的前缀是 /topic ,就会将消息转发给消息代理(broker),
// 再由消息代理将消息广播给当前连接的客户端。
config.enableSimpleBroker("/topic","/queue");
// 表示配置一个或多个前缀,通过这些前缀过滤出需要被注解方法处理的消息。
// 例如,前缀为 /app 的 destination 可以通过@MessageMapping注解的方法处理,
// 而其他 destination (例如 /topic /queue)将被直接交给 broker 处理
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 表示定义一个前缀为 /chat 的 endPoint,并开启 sockjs 支持,
// sockjs 可以解决浏览器对 WebSocket 的兼容性问题,
// 客户端将通过这里配置的 URL 来建立 WebSocket 连接
registry.addEndpoint("/chat").withSockJS();
}
}
这里的修改是在 config.enableSimpleBroker("/topic") 方法的基础上又增加了 broker "/queue",方便对群发消息和点对点消息进行管理。
三、ChatRoomController控制类中,加入如下代码:
@Autowired
private SimpMessagingTemplate messagingTemplate;
@MessageMapping("/chat")
public void chat(Principal principal,SendChatEO chat) {
String from = principal.getName();
chat.setFrom(from);
messagingTemplate.convertAndSendToUser(chat.getTo(), "/queue/chat", chat);
}
@GetMapping("/chatroom_touser")
public String chatroom_touser(Model m) {
return "chatroom_touser";
}
- 除了@SendTo 注解外, Spring 还提供了 SimpMessagingTemplate 类来让开发者更加灵活地发送消息,使用 SimpMessagingTemplate 对ChatRoomController进行改造。
- 群发消息依然使 @SendTo 注解来实现,点对点的消息发送则使用 SimpMessagingTemplate来实现。
- public void chat 定义了一个新的消息处理接口,@MessageMapping("/chat") 注解表示来自 "/app/chat" 路径的消息将被 chat 方法处理。 chat 方法的 一个参数 Principal 可以用来获取当前登录用户的信息,第二个参数则是客户端发送来的消息。
- 在 chat 方法中, 首先获取当前用户的用户名,设置给 chat 对象的 from 属性,再将消息发送出去,发送的目标用户就是 chat 对象的 to 属性值。
- 消息发送使用的方法是 convertAndSendToUser,该方法内部调用了 convertAndSend 方法,并对消息路径做了处理。
- 消息的最终发送路径是 "/user/用户名/queue/chat"。
- SendChatEO 一个普通的 JavaBean, to 属性表示消息的目标用户,from 表示消息从哪里来,content 则是消息的主体内容。
package com.mall.websocket;
import lombok.Data;
@Data
public class SendChatEO {
private String to;
private String from;
private String content;
public SendChatEO(String to, String from, String content) {
super();
this.to = to;
this.from = from;
this.content = content;
}
public SendChatEO() {
super();
}
}
<!DOCTYPE html>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta charset="UTF-8">
<title>商城灌水集市</title>
</head>
<body>
<table border="1">
<tr><td><div id="msglist" style="width: 600px; height: 300px; border: 1px solid red; overflow-y: auto"></div></td></tr>
</table>
<table border="1" style="width: 600px;">
<tr><td>用户名:</td><td><span sec:authentication="name"></span></td></tr>
</table>
<table border="1" style="width: 600px;">
<tr>
<td>发送给用户:<input id="to" type="text" />
</td>
<td><input id="content" type="text" placeholder="聊天内容........." />
<button id="send" type="button">发送</button></td>
</tr>
</table>
<script type="text/javascript" th:src="@{/webjars/jquery/jquery.min.js}"></script>
<script type="text/javascript" th:src="@{/webjars/sockjs-client/sockjs.min.js}"></script>
<script type="text/javascript" th:src="@{/webjars/stomp-websocket/stomp.min.js}"></script>
<script type="text/javascript" th:src="@{/bizjs/chatroom_touser.js}"></script>
</body>
</html>
五、JavaScript页面:
let stompClient = null; /* 连接服务器 */
let 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() {
let sendData = {
'content' : $("#content").val(),
'to' : $("#to").val()
};
let dataJsonStr = JSON.stringify(sendData);
stompClient.send("/app/chat", {}, dataJsonStr);
}
function showGreeting(message) {
let msgHtml = "<span>" + message.from + ":" + message.content + "</span><br/>";
$("#msglist").append(msgHtml);
let div = document.getElementById('msglist');
div.scrollTop = div.scrollHeight;
}
$(function() {
$("#disconnect").click(function() {
disconnect();
});
$("#send").click(function() {
sendMsg();
});
});