一、根据《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();
   }
}


四、HTML页面:
<!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();
   });
});