SpringBoot actual combat (17) | integration of WebSocket to realize chat room

  java-web, spring-security, springboot, websocket

WeChat Public Number: An Outstanding Disabled Person. If you have any questions, please leave a message backstage. I won’t listen anyway.


Yesterday’s article introduced the implementation of WebSocket broadcasting, that is, when the server side has a message, it sends the message to all browsers connected to the current endpoint. However, this cannot solve the problem of who sends the message and who receives it. So, today, write a chat room to realize one-on-one communication.

Today’s article is based on yesterday’s one. In order to better understand today’s article, it is recommended to read it first. “SpringBoot integrates WebSocket to realize broadcast message

Preparatory work

  • Spring Boot 2.1.3 RELEASE
  • Spring Security 2.1.3 RELEASE
  • IDEA
  • JDK8

Pom dependency

Because chat rooms involve users, Spring Security 2.1.3 RELEASE dependency is introduced on the basis of the previous article.

<!-- Spring Security 依赖 -->

Configuration of Spring Security

Although Spring Security is involved, due to the limited space, only relevant parts of this project will be introduced here. The specific Spring Security tutorial will be published later.

Spring Security configuration here is very simple, specifically setting login path, setting security resources, and creating users and passwords in memory. Passwords need to be encrypted. BCrypt encryption algorithm is used here to encrypt passwords when users log in. The code comments are very detailed, not much said.

package com.nasus.websocket.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

// 开启Spring Security的功能
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    protected void configure(HttpSecurity http) throws Exception {
             // 设置 SpringSecurity 对 / 和 "/login" 路径不拦截
            // 设置 Spring Security 的登录页面访问路径为/login
            // 登录成功后转向 /chat 路径

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            // 在内存中分配两个用户 nasus 和 chenzy ,用户名和密码一致
            // BCryptPasswordEncoder() 是 Spring security 5.0 中新增的加密方式
            // 登陆时用 BCrypt 加密方式对用户密码进行处理。
            .passwordEncoder(new BCryptPasswordEncoder())
            // 保证用户登录时使用 bcrypt 对密码进行处理再与内存中的密码比对
            .password(new BCryptPasswordEncoder().encode("nasus")).roles("USER")
            // 登陆时用 BCrypt 加密方式对用户密码进行处理。
            .passwordEncoder(new BCryptPasswordEncoder())
            // 保证用户登录时使用 bcrypt 对密码进行处理再与内存中的密码比对
            .password(new BCryptPasswordEncoder().encode("chenzy")).roles("USER");

    public void configure(WebSecurity web) throws Exception {
        // /resource/static 目录下的静态资源,Spring Security 不拦截

Configuration of WebSocket

On the basis of the previous article, another node named “/Endpointhat” is registered for users to subscribe to. Only users who subscribe to this node can receive messages. Then, add a message agent named “/queue”.

// @EnableWebSocketMessageBroker 注解用于开启使用 STOMP 协议来传输基于代理(MessageBroker)的消息,这时候控制器(controller)
// 开始支持@MessageMapping,就像是使用 @requestMapping 一样。
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    public void registerStompEndpoints(StompEndpointRegistry registry) {
        //注册一个名为 /endpointNasus 的 Stomp 节点(endpoint),并指定使用 SockJS 协议。
        //注册一个名为 /endpointChat 的 Stomp 节点(endpoint),并指定使用 SockJS 协议。

    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 广播式配置名为 /nasus 消息代理 , 这个消息代理必须和 controller 中的 @SendTo 配置的地址前缀一样或者全匹配
        // 点对点增加一个 /queue 消息代理


Specify the format and template for sending messages. For details, see the code notes.

//使用 SimpMessagingTemplate 向浏览器发送信息
private SimpMessagingTemplate messagingTemplate;

public void handleChat(Principal principal,String msg){
    // 在 SpringMVC 中,可以直接在参数中获得 principal,principal 中包含当前用户信息
    if (principal.getName().equals("nasus")){
        // 硬编码,如果发送人是 nasus 则接收人是 chenzy 反之也成立。
        // 通过 messageingTemplate.convertAndSendToUser 方法向用户发送信息,参数一是接收消息用户,参数二是浏览器订阅地址,参数三是消息本身
                "/queue/notifications",principal.getName()+"-send:" + msg);
    } else {
               "/queue/notifications",principal.getName()+"-send:" + msg);

Login page

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
<meta charset="UTF-8" />
<div th:if="${param.error}">
<div th:if="${param.logout}">
<form th:action="@{/login}" method="post">
    <div><label> 账号 : <input type="text" name="username"/> </label></div>
    <div><label> 密码: <input type="password" name="password"/> </label></div>
    <div><input type="submit" value="登陆"/></div>

Chat page

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8" />
    <script th:src="@{sockjs.min.js}"></script>
    <script th:src="@{stomp.min.js}"></script>
    <script th:src="@{jquery.js}"></script>

<form id="nasusForm">
    <textarea rows="4" cols="60" name="text"></textarea>
    <input type="submit"/>

<script th:inline="javascript">
        var text = $('#nasusForm').find('textarea[name="text"]').val();

    // 连接 SockJs 的 endpoint 名称为 "/endpointChat"
    var sock = new SockJS("/endpointChat");
    var stomp = Stomp.over(sock);
    stomp.connect('guest', 'guest', function(frame) {
        // 订阅 /user/queue/notifications 发送的消息,这里与在控制器的
        // messagingTemplate.convertAndSendToUser 中订阅的地址保持一致
        // 这里多了 /user 前缀,是必须的,使用了 /user 才会把消息发送到指定用户
        stomp.subscribe("/user/queue/notifications", handleNotification);

    function handleNotification(message) {
        $('#output').append("<b>Received: " + message.body + "</b><br/>")

    function sendSpittle(text) {
        stomp.send("/chat", {}, text);
    $('#stop').click(function() {sock.close()});

<div id="output"></div>

Page controller

public class ViewController {

    public String getView(){
        return "nasus";

    public String getLoginView(){
        return "login";

    public String getChatView(){
        return "chat";



The expected result should be that two users log into the system and can send messages to each other. However, the session of the user session of the same browser is shared, and another user needs to be added to Chrome browser.

The specific operation is in Chrome settings-> manage users-> add users:


The two users visit separatelyhttp://localhost: 8080/login login system, jump to chat interface:


Send messages to each other:


Complete code

https://github.com/turoDog/De …

If you think it is helpful to you, please give a Star before you leave. thank you very much.


If this article is of any help to you, please help me look good. Your good looks are my motivation to persist in writing.

In addition, after the attention is sent1024Free study materials are available.

For details, please refer to this old article:Python, C++, Java, Linux, Go, Front End, Algorithm Data Sharing