Play wechat everyday, Spring Boot develops private instant messaging system

1/ overview

Using Spring Boot as the basic framework, Spring Security as the security framework and WebSocket as the communication framework, point-to-point chat and group chat are realized.

2 / dependence required

Spring Boot version 1.5.3 uses MongoDB to store data (not required). Maven relies on the following:

<properties>
    <java.version>1.8</java.version>
    <thymeleaf.version>3.0.0.RELEASE</thymeleaf.version>
    <thymeleaf-layout-dialect.version>2.0.0</thymeleaf-layout-dialect.version>
  </properties>

  <dependencies>

    <!-- WebSocket Dependencies, removing Tomcat container -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-websocket</artifactId>
      <exclusions>
        <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <!-- Use Undertow container -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-undertow</artifactId>
    </dependency>

    <!--  Spring Security frame -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <!-- MongoDB data base -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>

    <!-- Thymeleaf template engine -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.16.16</version>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.30</version>
    </dependency>

    <!-- Static resources -->
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>webjars-locator</artifactId>
    </dependency>
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>sockjs-client</artifactId>
      <version>1.0.2</version>
    </dependency>
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>stomp-websocket</artifactId>
      <version>2.3.3</version>
    </dependency>
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>bootstrap</artifactId>
      <version>3.3.7</version>
    </dependency>
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>jquery</artifactId>
      <version>3.1.0</version>
    </dependency>

  </dependencies>

Profile content:

server:
  port: 80

# If MongoDB is used, configure the following parameters
spring:
  data:
    mongodb:
      uri: mongodb://username:password@172.25.11.228:27017
      authentication-database: admin
      database: chat

General program structure, for reference only:

Program structure

3 / create program startup class and enable WebSocket

Use @ EnableWebSocket annotation

@SpringBootApplication
@EnableWebSocket
public class Application {

 public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
 }

}

4 / configure Spring Security

This chapter is omitted. (with Spring Security configured, users can log in normally.)
Refer to: Spring Boot full stack development: user security

5 / configure Web Socket (refer to JS in Section 7)

@Configuration
@EnableWebSocketMessageBroker
@Log4j
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

  // You can inject your own Service here

  @Override
  public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
    // Connection point between client and server
    stompEndpointRegistry.addEndpoint("/any-socket").withSockJS();
  }

  @Override
  public void configureMessageBroker(MessageBrokerRegistry messageBrokerRegistry) {
    // Configure the prefix of the path the client sends information to
    messageBrokerRegistry.setApplicationDestinationPrefixes("/app");
    messageBrokerRegistry.enableSimpleBroker("/topic");
  }

  @Override
  public void configureWebSocketTransport(final WebSocketTransportRegistration registration) {
    registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
      @Override
      public WebSocketHandler decorate(final WebSocketHandler handler) {
        return new WebSocketHandlerDecorator(handler) {
          @Override
          public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
            // After the client establishes a connection with the server, who is online is recorded here
            String username = session.getPrincipal().getName();
            log.info("online: " + username);
            super.afterConnectionEstablished(session);
          }

          @Override
          public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
            // After the client is disconnected from the server, who is offline is recorded here
            String username = session.getPrincipal().getName();
            log.info("offline: " + username);
            super.afterConnectionClosed(session, closeStatus);
          }
        };
      }
    });
    super.configureWebSocketTransport(registration);
  }
}

6 / peer to peer message, group message

@Controller
@Log4j
public class ChatController {

  @Autowired
  private SimpMessagingTemplate template;

  // Inject other services

  // Group chat
  @MessageMapping("/notice")
  public void notice(Principal principal, String message) {  
    // Parameter Description: the current login user of principal, and the content sent by message client
    // principal.getName() to get the current user's username  

    // Send messages to users who subscribe to "/ topic/notice" and are online
    template.convertAndSend("/topic/notice", message); 
  }

  // Point to point chat
  @MessageMapping("/chat")
  public void chat(Principal principal, String message){
    // Parameter Description: the currently logged in user of principal, and the content sent by message client (at least including the sending object toUser and message content)
    // principal.getName() to get the current user's username

    // Send a message to the user who subscribes to "/ user/topic/chat" and whose user name is toUser
    template.convertAndSendToUser(toUser, "/topic/chat", content);
  }

}

7 / interaction between client and server

var stompClient = null;

    function connect() {
        var socket = new SockJS('/any-socket');
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function (frame) {
            // Subscribe to / topic/notice to realize group chat
            stompClient.subscribe('/topic/notice', function (message) {
                showMessage(JSON.parse(message.body));
            });
            // Subscribe / user/topic/chat to implement point-to-point chat
            stompClient.subscribe('/user/topic/chat', function (message) {
                showMessage(JSON.parse(message.body));
            });
        });
    }

    function showMessage(message) {
        // Display of processing messages on the page
    }

    $(function () {
        // Establish websocket connection
        connect();
        // Send Message button event
        $("#send").click(function () {
            if (target == "TO_ALL"){
                // Mass message
                // Match @ MessageMapping("/notice") in the backend ChatController
                stompClient.send("/app/notice", {}, 'Message content');
            }else{
                // Peer to peer message, which must contain the username of the other party
                // Match @ MessageMapping("/chat") in the backend ChatController
                var content = "{'content':'Message content','receiver':'anoy'}";
                stompClient.send("/app/chat", {}, content);
            }
        });
    });

8 / effect test

Login to three users: Anoyi, Jock and super administrator.
Group message test, super administrator group message:

Super administrator

Anoyi

Jock

In point-to-point message test, Anoyi sends a message to Jock, only Jock receives the message, and Anoyi and super administrator do not receive the message:

Jock

Super administrator

Anoyi

9 / lightweight DEMO (full runnable code)

Spring Boot develops WebSocket (Continued)

10 / references

  • Official document of spring mongodb
  • Official Spring Framework documentation
  • Spring Guide - stomp websocket

Copyright belongs to the author. Please contact the author for reprint or content cooperation

If you have any questions, please leave a message to let us know.

Spring Boot custom parent quick build application

Spring Boot containerized deployment Docker

How to configure https in SpringBot

Spring Boot log processing are you still using Logback?

[behind the double 11 Carnival] how does the micro service registration center carry tens of millions of visits to large-scale systems?

Spring Boot new generation monitoring you should play like this

Spring Boot exception handling

Spring Boot configuration - configuration information encryption

Reject black box application - visual monitoring of Spring Boot application

There are three sources of concurrent bugs. Please open your eyes to see them

This article is based on the platform of blog one article multiple sending OpenWrite Release!

Tags: Java Spring MongoDB Thymeleaf Session

Posted on Sat, 09 Nov 2019 04:49:06 -0500 by yong