SpringBoot整合WebSocket服务 springboot整合websocket springboot使用websocket springboot使用websocket
SpringBoot整合WebSocket服务 springboot整合websocket springboot使用websocket springboot使用websocket
1、前言
注意: 仅使用 SpringBoot封装好的 spring-boot-starter-websocket
服务,并不是使用第三方 Netty
或者 Apache MINA
spring-boot-starter-web
: 底层使用 Java WebSocket API (JSR-356)
实现
spring-boot-starter-webflux
: 底层使用 Netty
实现(没有使用过,不知道具体)
2、开始使用
2.1、加入Maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.2 (推荐方式) 使用 WebSocketConfigurer方式创建 WebSocket端点 (二选一)
2.2.1 创建一个 测试 WebSocket处理器
类名称:TestSocketHandler
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.*;
/**
* <h2>测试 - socket连接处理器</h2>
* <p>
*
* </p>
*
* @author LiYang
* @createTime 2022年07月19日 9:58 上午
*/
public class TestSocketHandler implements WebSocketHandler {
private final static Logger LOGGER = LoggerFactory.getLogger(TestSocketHandler.class);
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
LOGGER.info("Test Socket 连接成功,sessionId:{}", session.getId());
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
if (message instanceof TextMessage) {
handlerTextMessage(session, (TextMessage) message);
} else {
LOGGER.error("Test Socket 消息处理失败,只接受 文本消息,sessionId:{}", session.getId());
}
}
public void handlerTextMessage(WebSocketSession session, TextMessage message) throws Exception {
final String msg = message.getPayload();
LOGGER.info("Test Socket 收到消息:{}", msg);
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
LOGGER.error("Test Socket 处理异常,sessionId:{}, 异常原因:{}", session.getId(), exception.getMessage());
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
LOGGER.info("Test Socket 关闭,sessionId:{}", session.getId());
}
@Override
public boolean supportsPartialMessages() {
return false;
}
}
2.2.2 开启 WebSocket 并且注册WebSocket处理器
类名称: WebSocketConfig
import com.ddt.wms.handler.BlankingPdaSocketHandler;
import com.ddt.wms.handler.StretchingStationPdaSocketHandler;
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;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
/**
* <h2></h2>
* <p>
*
* </p>
*
* @author LiYang
* @createTime 2022年07月19日 9:57 上午
*/
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 注册 socket处理器
registry.addHandler(testSocketHandler (), "/ws/test").setAllowedOrigins("*");
}
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
// 消息缓冲区大小的大小
container.setMaxTextMessageBufferSize(8192);
container.setMaxBinaryMessageBufferSize(8192);
return container;
}
@Bean
public WebSocketHandler testSocketHandler () {
return new TestSocketHandler();
}
}
2.3 使用 ServerEndpoint方式创建 WebSocket端点 (二选一)
这个方式创建 Websocket仅在 web
环境下测试过,并没有在 webflux
测试,如果你使用的是 webflux
可以使用第一种方式创建
一个demo,在线编辑Excel,使用的就是 ServerEndpoint方式创建 WebSocket端点 LuckySheet-Java
2.3.1创建一个 测试 WebSocket处理器
类名称:TestSocketHandler
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* <h2></h2>
*
* @author LiYang
* @since 2022年12月05日 16:52
*/
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@ServerEndpoint(value = "/ws/test")
public class TestSocketHandler{
public final static Logger LOGGER = LoggerFactory.getLogger(TestSocketHandler.class);
/**
* WebSocket 连接成功调用方法
*
* @param session 连接对象
*/
@OnOpen
public void onOpen(Session session) throws IOException {
LOGGER.info("Test Socket 连接成功,sessionId:{}", session.getId());
}
/**
* 接收普通文本消息
*
* @param message 消息
* @param session 当前socket连接对象
*/
@OnMessage
public void onMessage(String message, Session session) {
if (StringUtils.isBlank(message)) {
return;
}
LOGGER.info("Test Socket 收到消息:{}", msg);
}
/**
* 关闭连接调用的方法
*/
@OnClose
public void onClose(Session session) {
LOGGER.info("Test Socket 关闭,sessionId:{}", session.getId());
}
/**
* socket 异常调用的方法
*/
@OnError
public void onError(Session session, Throwable error) {
LOGGER.error("Test Socket 处理异常,sessionId:{}, 异常原因:{}", session.getId(), error.getMessage());
}
}
2.3.2 开启 WebSocket
类名称: WebSocketConfig
import com.ddt.wms.handler.BlankingPdaSocketHandler;
import com.ddt.wms.handler.StretchingStationPdaSocketHandler;
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;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
/**
* <h2></h2>
* <p>
*
* </p>
*
* @author LiYang
* @createTime 2022年07月19日 9:57 上午
*/
@Configuration
@EnableWebSocket
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3、 连接访问
连接地址:ws://127.0.0.1:8080/ws/test
注意事项:如果使用了Shiro
、Spring Security
等认证鉴权框架,一定要将 WebSocket访问路径/ws/test
加入到白名单
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() // 禁用CSRF保护
.authorizeRequests()
.antMatchers("/websocket/**").permitAll() // 允许所有对"/ws/**"的请求
.anyRequest().authenticated() // 所有其他请求都需要认证
.and()
.headers().frameOptions().sameOrigin() // 允许同源策略下的iframe加载
.and()
.httpBasic(); // 启用基本HTTP身份验证
// 配置WebSocket握手请求的安全性
http.headers().frameOptions().disable(); // 必须在生产环境中重新启用frameOptions,以防止点击劫持
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(new CorsFilter(corsConfigurationSource()), UsernamePasswordAuthenticationFilter.class);
}
private CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://your-frontend-origin.com"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("header1", "header2", "header3"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
如果配置了白名单也就还是连接不上,需要检查 还有没有其他的过滤器拦截问题
、跨域问题
,请考虑下面两个方法
- 将Websocket服务独立为一个web服务部署
- 使用第三方socket框架内嵌到项目里面,例如
Netty(推荐)
、Mina
4、两种方式如何选择
ServerEndpointExporter
和registerWebSocketHandlers
是两种不同的方式,用于在Spring应用中配置和注册WebSocket端点。它们分别属于不同的技术栈:ServerEndpointExporter
用于JSR-356 WebSocket规范,而registerWebSocketHandlers
则是在Spring的WebSocket抽象之上。
ServerEndpointExporter
ServerEndpointExporter
是Spring框架为了支持JSR-356 WebSocket规范提供的一个组件。它会自动查找带有@ServerEndpoint
注解的类,并将它们注册为WebSocket端点。ServerEndpointExporter
适用于那些直接使用Java WebSocket API编写WebSocket端点的场景。当使用@ServerEndpoint
注解来定义WebSocket端点时,ServerEndpointExporter
会处理端点的发现和注册。
registerWebSocketHandlers
registerWebSocketHandlers
方法是WebSocketConfigurer
接口的一部分,这个接口允许手动配置和注册WebSocket处理器。当使用Spring的WebSocket抽象时,通常会使用这个方法。在这个方法中,可以指定一个WebSocketHandler
实例,以及该处理器应当监听的URL映射。此外,还可以添加拦截器,例如HttpSessionHandshakeInterceptor
,来处理握手过程中的会话管理。
主要区别
-
自动化与手动配置:
ServerEndpointExporter
自动扫描和注册@ServerEndpoint
标注的类,不需要显式配置。registerWebSocketHandlers
要求明确指定处理器和URL映射。
-
API和编程模型:
ServerEndpointExporter
适用于原生的Java WebSocket API,遵循JSR-356规范。registerWebSocketHandlers
则基于Spring的WebSocket抽象,提供更高级别的控制和灵活性。
-
应用场景:
- 如果想要使用JSR-356的WebSocket API,并且的WebSocket端点使用
@ServerEndpoint
注解定义,那么ServerEndpointExporter
是一个合适的选择。 - 如果更倾向于使用Spring的WebSocket抽象,或者需要更精细的控制,如添加自定义的拦截器或使用Spring的注解驱动(如
@MessageMapping
),那么应该使用registerWebSocketHandlers
。
- 如果想要使用JSR-356的WebSocket API,并且的WebSocket端点使用
选择哪一种方法取决于的具体需求和对WebSocket API的偏好。在Spring Boot中,通常会更倾向于使用registerWebSocketHandlers
方法,因为它更好地集成了Spring的特性。