digression
There are too many things recently, and I haven’t updated for a long time. Thank you all for your continued attention. If you have any questions, please send me a private message to discuss with you.
An overview of the
This article, part 2 of part 3 of the WebSocket story series, provides a simple example of STOMP implementing point-to-point messaging based on the code described in the previous article. The WebSocket story series is planned as a six-part, step-by-step introduction to WebSocket and how to quickly build and use the capabilities WebSocket provides in Springboot.
This series is planned to include the following articles:
Part 1: What WebSocket is and what it Does Part 2: How to Use STOMP to Quickly Build WebSocket broadcast message Patterns in Spring In Springboot, how to use WebSocket and STOMP to quickly build point-to-point messaging mode (2) in Springboot, how to implement custom WebSocket message proxy in web chat rooms
The main line of this article
The last article started with @sendto and @sendtouser and went deep into Spring’s key code for sending WebSocket messages. This article will implement an example of point-to-point messaging based on STOMP and provide specific explanations.
In the process of writing this article, I also looked at some online examples, most of them have more or less problems, few can run, so I also give Github sample link at the end of the article, students who need to help themselves.
This article is suitable for readers
Students who want to learn about STOMP, the details of Spring’s internal code, and how to build WebSocket services using Springboot.
Implement a point-to-point messaging pattern
A, introducingWebSecurity
Implementing User Management
When it comes to point-to-point messaging, imagine the common chat tools such as wechat and QQ, which have user management modules, including databases and so on. In order to simplify, we use WebSecurity to achieve a simple user login management based on memory. We can save two user information on the server and let the two users send messages to each other.
1. Introduce dependencies
<! -- add security module -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Copy the code
2. ImplementWebSecurityConfig
Here we build two memory-level user accounts so that we can simulate messaging each other later.
package com.xnpe.chat.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;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/"."/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/chat")
.permitAll()
.and()
.logout()
.permitAll();
}
// Declare two memory storage users
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("Xiao Ming").password(new BCryptPasswordEncoder().encode("123")).roles("USER")
.and().passwordEncoder(new BCryptPasswordEncoder())
.withUser("Suby").password(new BCryptPasswordEncoder().encode("123")).roles("USER");
}
@Override
public void configure(WebSecurity web){
web.ignoring().antMatchers("/resources/static/**"); }}Copy the code
Second, the implementationWebSocket
And page configuration
With the two memory level user accounts set up, let’s configure websockets and pages.
1. Configure resource routes
package com.xnpe.chat.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/chat").setViewName("chat");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); }}Copy the code
2. The configurationWebSocket STOMP
Here we register an Endpoint named Chat and a message broker named Queue.
package com.xnpe.chat.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/Chat").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue"); }}Copy the code
Three, implementation,WebSocket
Message processing of
The client sends the message to chat at the specified address, which is captured and processed by handleChat. We have done some hard logic here. If the message is sent by Xiao Ming, we will route it to Suby. And vice versa.
1. Implementation of Controller
It is important to note that the Mapping address we are listening to is chat, so when the client sends messages later, pay attention to this address of the server. After receiving the message, the server will route the message to the address /queue/notification. In other words, our client WebSocket subscribed to the address /queue/notification.
package com.xnpe.chat.controller;
import com.xnpe.chat.data.Info;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import java.security.Principal;
@Controller
public class WebSocketController {
@Autowired
private SimpMessagingTemplate messagingTemplate;
@MessageMapping("/chat")
public void handleChat(Principal principal, Info info) {
if (principal.getName().equals("Xiao Ming")) {
messagingTemplate.convertAndSendToUser("Suby"."/queue/notification", principal.getName() + " send message to you: "
+ info.getInfo());
} else {
messagingTemplate.convertAndSendToUser("Xiao Ming"."/queue/notification", principal.getName() + " send message to you: "+ info.getInfo()); }}}Copy the code
2. Message Bean
A structure used to host messages exchanged
package com.xnpe.chat.data;
public class Info {
private String info;
public String getInfo(a) {
returninfo; }}Copy the code
Compile the Html page of the client
1. Implement the login pagelogin.html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8" />
<head>
<title>Landing page</title>
</head>
<body>
<div th:if="${param.error}">Invalid account and password</div>
<div th:if="${param.logout}">You have been logout</div>
<form th:action="@{/login}" method="post">
<div><label>Account:<input type="text" name="username"/> </label></div>
<div><label>Password:<input type="password" name="password"/> </label></div>
<div><input type="submit" value="Login"/></div>
</form>
</body>
</html>
Copy the code
2. Implement chat pageschat.html
Two important points to emphasize:
- When we connect to WebSocket, we specify
Chat
This Endpoint. When sending a message, we need to send the message to the address mapped by the server, that is/chat
. - Because the server will send the information to
/queue/notification
So we subscribe to this address as well, because we want to implement one-to-one messaging (according to the content of the previous article, you can refer to the previous article), here we need to add when subscribinguser
Prefix.
<html xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8" />
<head>
<title>Welcome to the chat room</title>
<script th:src="@{sockjs.min.js}"></script>
<script th:src="@{stomp.min.js}"></script>
<script th:src="@{jquery.js}"></script>
</head>
<body>
<p>The chat room</p>
<form id="chatForm">
<textarea rows="4" cols="60" name="text"></textarea>
<input type="submit"/>
</form>
<script th:inline="javascript">
$('#chatForm').submit(function(e){
e.preventDefault();
var text = $('#chatForm').find('textarea[name="text"]').val();
sendSpittle(text);
$('#chatForm').clean();
});
// Link to an endpoint named "/Chat".
var sock = new SockJS("/Chat");
var stomp = Stomp.over(sock);
stomp.connect('abc'.'abc'.function(frame) {
stomp.subscribe("/user/queue/notification", handleNotification);
});
function handleNotification(message) {$('#output').append("<b>Received: " + message.body + "</b><br/>")}function sendSpittle(text) {
stomp.send("/chat", {}, JSON.stringify({ 'info': text }));
}
$('#stop').click(function() {sock.close()});
</script>
<div id="output"></div>
</body>
</html>
Copy the code
Demonstrates point-to-point messaging
Above, all the key code of our program has been implemented. After startup, access localhost:8080/login to get to the login page.
Open two separate pages and enter the account number and password (the two account information hard-coded in the code). The Chat page is displayed.
Enter information in the input box, then click Submit, and the message will be sent to another user.
code
The code project used in this article has been uploaded to Github for those who want to experience it.
GitHub-STOMP implements point-to-point messaging
conclusion
This article Outlines the basic steps for implementing point-to-point messaging based on STOMP. It is easy to note the address where the client sends the message and the address to which it subscribes. With STOMP, we implemented point-to-point messaging based on the user’s address, that is, STOMP implemented a mapping of the user’s address to the session, which also helped us easily send messages to the peer user without worrying about the details of the underlying implementation. But if we want to encapsulate more complex business logic ourselves, manage the user’s WebSocket session, and be more flexible in sending messages to the user, that’s what we’ll be looking at in our next article, without STOMP, to see how we can achieve more flexible WebSocket point-to-point communication.
Welcome to continue to follow
Xiaoming produced, must be a boutique
Welcome to pay attention to xNPE technology forum, more original dry goods daily push.