Spring Boot是一个快速开发框架,可以帮助我们快速构建Web应用程序。在本攻略中,我们将使用Spring Boot和WebSocket创建一个私有即时通信系统。以下是完整攻略:
- 创建一个Maven项目,并在pom.xml文件添加以下依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- 创建一个WebSocket配置类,并使用
@Configuration
注解将其标记为Spring配置类。在配置类中,创建一个WebSocketHandler
实例,并使用@Bean
注解将其注入到Spring容器中。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler").setAllowedOrigins("*");
}
@Bean
public WebSocketHandler myHandler() {
return new MyHandler();
}
}
在上面的示例中,我们使用@EnableWebSocket
注解启用WebSocket支持。我们还使用registerWebSocketHandlers()
方法注册WebSocket处理程序,并使用setAllowedOrigins()
方法设置允许的来源。我们还使用@Bean
注解将MyHandler
实例注入到Spring容器中。
- 创建一个WebSocket处理程序类,并实现
WebSocketHandler
接口。在处理程序类中,实现afterConnectionEstablished()
方法和handleTextMessage()
方法。
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class MyHandler extends TextWebSocketHandler {
private Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.put(session.getId(), session);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
String[] parts = payload.split(":");
String recipient = parts[0];
String content = parts[1];
WebSocketSession recipientSession = sessions.get(recipient);
if (recipientSession != null && recipientSession.isOpen()) {
recipientSession.sendMessage(new TextMessage(content));
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session.getId());
}
}
在上面的示例中,我们使用ConcurrentHashMap
来存储WebSocket会话。我们实现了afterConnectionEstablished()
方法来添加新的会话。我们还实现了handleTextMessage()
方法来处理文本消息。在该方法中,我们解析消息的接收者和内容,并将消息发送给接收者。最后,我们实现了afterConnectionClosed()
方法来删除会话。
- 创建一个控制器类,并使用
@RestController
注解将其标记为控制器。在控制器类中,创建一个处理HTTP GET请求的方法,并使用@RequestMapping
注解将其映射到URL路径。
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@RequestMapping("/")
public String index() {
return "Hello, World!";
}
}
- 在
src/main/resources/static
目录下创建一个index.html
文件,并添加以下内容:
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Example</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
var socket = new WebSocket("ws://" + window.location.host + "/myHandler");
socket.onmessage = function(event) {
var message = event.data;
$("#messages").append("<p>" + message + "</p>");
};
function sendMessage() {
var recipient = $("#recipient").val();
var content = $("#content").val();
var message = recipient + ":" + content;
socket.send(message);
}
</script>
</head>
<body>
<h1>WebSocket Example</h1>
<div>
<label for="recipient">Recipient:</label>
<input type="text" id="recipient">
</div>
<div>
<label for="content">Content:</label>
<input type="text" id="content">
</div>
<button onclick="sendMessage()">Send</button>
<div id="messages"></div>
</body>
</html>
在上面的示例中,我们使用JavaScript创建一个WebSocket连接,并使用onmessage
事件处理程序来处理接收到的消息。我们还创建了一个sendMessage()
函数来发送消息。在HTML中,我们使用<input>
元素来获取接收者和内容,并使用<button>
元素来触发sendMessage()
函数。我们还使用<div>
元素来显示接收到的消息。
- 运行应用程序。在浏览器中访问
http://localhost:8080/
,将看到一个Web页面。在页面中,输入接收者和内容,并单击“Send”按钮。在页面下方,将显示接收到的消息。
以上是使用Spring Boot和WebSocket创建私有即时通信系统的完整攻略。下面是两个示例,演示如何使用Spring Boot和WebSocket创建更复杂的Web应用程序:
示例1:使用Spring Security保护WebSocket连接
在这个示例中,我们将使用Spring Security来保护WebSocket连接。我们将创建一个控制器类,并使用Spring Security来限制访问WebSocket连接。
- 在pom.xml文件中添加以下依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- 创建一个Spring Security配置类,并使用
@Configuration
注解将其标记为Spring配置类。在配置类中,创建一个UserDetailsService
实例,并使用@Bean
注解将其注入到Spring容器中。我们还使用configure()
方法配置Spring Security。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());
return manager;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/myHandler").hasRole("USER")
.and()
.formLogin();
}
}
在上面的示例中,我们使用@EnableWebSecurity
注解启用Spring Security支持。我们使用userDetailsService()
方法创建一个InMemoryUserDetailsManager
实例,并使用withDefaultPasswordEncoder()
方法设置密码编码器。我们还使用configure()
方法配置Spring Security,限制访问WebSocket连接。
- 创建一个控制器类,并使用
@RestController
注解将其标记为控制器。在控制器类中,创建一个处理HTTP GET请求的方法,并使用@RequestMapping
注解将其映射到URL路径。
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@RequestMapping("/")
public String index() {
return "Hello, World!";
}
}
- 创建一个WebSocket处理程序类,并实现
WebSocketHandler
接口。在处理程序类中,实现afterConnectionEstablished()
方法和handleTextMessage()
方法。
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class MyHandler extends TextWebSocketHandler {
private Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
sessions.put(username, session);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
String payload = message.getPayload();
String[] parts = payload.split(":");
String recipient = parts[0];
String content = parts[1];
WebSocketSession recipientSession = sessions.get(recipient);
if (recipientSession != null && recipientSession.isOpen()) {
recipientSession.sendMessage(new TextMessage(username + ": " + content));
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
sessions.remove(username);
}
}
在上面的示例中,我们使用SecurityContextHolder
来获取当前用户的身份验证信息。我们使用身份验证信息的用户名来存储WebSocket会话。在handleTextMessage()
方法中,我们将发送者的用户名添加到消息中。
- 在
src/main/resources/static
目录下创建一个index.html
文件,并添加以下内容:
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Example</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
var socket = new WebSocket("ws://" + window.location.host + "/myHandler");
socket.onmessage = function(event) {
var message = event.data;
$("#messages").append("<p>" + message + "</p>");
};
function sendMessage() {
var recipient = $("#recipient").val();
var content = $("#content").val();
var message = recipient + ":" + content;
socket.send(message);
}
</script>
</head>
<body>
<h1>WebSocket Example</h1>
<div>
<label for="recipient">Recipient:</label>
<input type="text" id="recipient">
</div>
<div>
<label for="content">Content:</label>
<input type="text" id="content">
</div>
<button onclick="sendMessage()">Send</button>
<div id="messages"></div>
</body>
</html>
在上面的示例中,我们使用JavaScript创建一个WebSocket连接,并使用onmessage
事件处理程序来处理接收到的消息。我们还创建了一个sendMessage()
函数来发送消息。在HTML中,我们使用<input>
元素来获取接收者和内容,并使用<button>
元素来触发sendMessage()
函数。我们还使用<div>
元素来显示接收到的消息。
- 运行应用程序。在浏览器中访问
http://localhost:8080/
,将看到一个Web页面。在页面中,输入接收者和内容,并单击“Send”按钮。在页面下方,将显示接收到的消息。
示例2:使用SockJS和STOMP协议
在这个示例中,我们将使用SockJS和STOMP协议来创建一个更高级的WebSocket应用程序。我们将创建一个控制器类,并使用SockJS和STOMP协议来实现WebSocket连接。
- 在pom.xml文件中添加以下依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>sockjs-client</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>stomp-websocket</artifactId>
<version>2.3.3</version>
</dependency>
- 创建一个控制器类,并使用
@RestController
注解将其标记为控制器。在控制器类中,创建一个处理HTTP GET请求的方法,并使用@RequestMapping
注解将其映射到URL路径。
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@RequestMapping("/")
public String index() {
return "Hello, World!";
}
}
- 创建一个WebSocket处理程序类,并实现
WebSocketHandler
接口。在处理程序类中,实现afterConnectionEstablished()
方法和handleTextMessage()
方法。
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class MyHandler extends TextWebSocketHandler {
private Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
private SimpMessagingTemplate messagingTemplate;
public MyHandler(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.put(session.getId(), session);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
String[] parts = payload.split(":");
String recipient = parts[0];
String content = parts[1];
messagingTemplate.convertAndSendToUser(recipient, "/queue/messages", content);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session.getId());
}
}
在上面的示例中,我们使用ConcurrentHashMap
来存储WebSocket会话。我们实现了afterConnectionEstablished()
方法来添加新的会话。我们还实现了handleTextMessage()
方法来处理文本消息。在该方法中,我们解析消息的接收者和内容,并使用SimpMessagingTemplate
来发送消息。最后,我们实现了afterConnectionClosed()
方法来删除会话。
- 创建一个WebSocket配置类,并使用
@Configuration
注解将其标记为Spring配置类。在配置类中,创建一个WebSocketHandler
实例,并使用@Bean
注解将其注入到Spring容器中。我们还使用configureMessageBroker()
方法配置消息代理。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler").setAllowedOrigins("*");
}
@Bean
public WebSocketHandler myHandler() {
return new MyHandler(messagingTemplate());
}
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxTextMessageBufferSize(8192);
container.setMaxBinaryMessageBufferSize(8192);
return container;
}
@Bean
public SimpMessagingTemplate messagingTemplate() {
return new SimpMessagingTemplate(createWebSocketClient());
}
@Bean
public WebSocketClient createWebSocketClient() {
return new StandardWebSocketClient();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue");
registry.setApplicationDestinationPrefixes("/app");
}
}
在上面的示例中,我们使用@EnableWebSocket
注解启用WebSocket支持。我们使用registerWebSocketHandlers()
方法注册WebSocket处理程序,并使用setAllowedOrigins()
方法设置允许的来源。我们还使用@Bean
注解将MyHandler
实例注入到Spring容器中。我们使用createWebSocketContainer()
方法创建一个ServletServerContainerFactoryBean
实例,并设置最大消息缓冲区大小。我们还使用messagingTemplate()
方法创建一个SimpMessagingTemplate
实例,并使用createWebSocketClient()
方法创建一个WebSocketClient
实例。最后,我们使用configureMessageBroker()
方法配置消息代理。
- 在
src/main/resources/static
目录下创建一个index.html
文件,并添加以下内容:
```html