Skip to content

Commit 4b85e38

Browse files
committed
Merge branch 'dev' of https://gitee.com/opensolon/solon-jakarta into dev
2 parents b7abb41 + 27ea78c commit 4b85e38

File tree

4 files changed

+155
-34
lines changed

4 files changed

+155
-34
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2017-2025 noear.org and authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.noear.solon.server.tomcat.websocket;
17+
18+
import java.util.List;
19+
import java.util.Map;
20+
21+
import org.noear.solon.Utils;
22+
import org.noear.solon.net.websocket.SubProtocolCapable;
23+
import org.noear.solon.net.websocket.WebSocketRouter;
24+
import org.noear.solon.server.util.DecodeUtils;
25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
27+
28+
import jakarta.websocket.HandshakeResponse;
29+
import jakarta.websocket.server.HandshakeRequest;
30+
import jakarta.websocket.server.ServerEndpointConfig;
31+
32+
/**
33+
* Tomcat WebSocket 配置器
34+
*
35+
* @author 小xu中年
36+
* @since 3.7.3
37+
*/
38+
public class TcWebSocketConfigurator extends ServerEndpointConfig.Configurator {
39+
private static final Logger log = LoggerFactory.getLogger(TcWebSocketConfigurator.class);
40+
41+
@Override
42+
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
43+
// 存储握手请求信息,供后续使用
44+
sec.getUserProperties().put("handshakeRequest", request);
45+
46+
// 处理子协议协商
47+
String path = DecodeUtils.rinseUri(request.getRequestURI().getPath());
48+
SubProtocolCapable subProtocolCapable = WebSocketRouter.getInstance().getSubProtocol(path);
49+
50+
if (subProtocolCapable != null) {
51+
List<String> clientProtocols = request.getHeaders().get("Sec-WebSocket-Protocol");
52+
if (clientProtocols != null && !clientProtocols.isEmpty()) {
53+
String protocols = subProtocolCapable.getSubProtocols(clientProtocols);
54+
55+
if (Utils.isNotEmpty(protocols)) {
56+
response.getHeaders().put("Sec-WebSocket-Protocol", List.of(protocols));
57+
}
58+
}
59+
}
60+
61+
// 存储请求头信息
62+
for (Map.Entry<String, List<String>> entry : request.getHeaders().entrySet()) {
63+
if (!entry.getValue().isEmpty()) {
64+
sec.getUserProperties().put("header." + entry.getKey(), entry.getValue().get(0));
65+
}
66+
}
67+
}
68+
69+
@Override
70+
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
71+
try {
72+
return endpointClass.getDeclaredConstructor().newInstance();
73+
} catch (Exception e) {
74+
log.error("Tomcat WebSocket Failed to create endpoint instance: {}", endpointClass.getName(), e);
75+
throw new InstantiationException("Tomcat WebSocket Failed to create endpoint instance: " + e.getMessage());
76+
}
77+
}
78+
}

solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/main/java/org/noear/solon/server/tomcat/websocket/TcWebSocketEndpoint.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,23 @@
3030
* Tomcat WebSocket端点实现
3131
*
3232
* @author 小xu中年
33-
* @since 3.7
33+
* @since 3.7.3
3434
*/
3535
public class TcWebSocketEndpoint extends Endpoint {
36-
private final String SESSION_KEY = "session";
36+
private final String SESSION_KEY = "session";
3737
private static final WebSocketRouter webSocketRouter = WebSocketRouter.getInstance();
3838

3939
@Override
4040
public void onOpen(Session session, EndpointConfig endpointConfig) {
41+
// 设置最大消息大小,与Jetty保持一致
42+
session.setMaxTextMessageBufferSize(17_000_000);
43+
session.setMaxBinaryMessageBufferSize(17_000_000);
44+
45+
// 创建WebSocket实例
4146
WebSocket socket = new WebSocketImpl(session);
4247
session.getUserProperties().put(SESSION_KEY, socket);
48+
49+
// 注册消息处理器
4350
session.addMessageHandler(new BufferMessageHandler(socket));
4451
session.addMessageHandler(new TextMessageHandler(socket));
4552

@@ -71,9 +78,9 @@ public TextMessageHandler(WebSocket socket) {
7178
}
7279

7380
@Override
74-
public void onMessage(String s) {
81+
public void onMessage(String text) {
7582
try {
76-
webSocketRouter.getListener().onMessage(socket, s);
83+
webSocketRouter.getListener().onMessage(socket, text);
7784
} catch (Throwable e) {
7885
webSocketRouter.getListener().onError(socket, e);
7986
}
@@ -88,9 +95,9 @@ public BufferMessageHandler(WebSocket socket) {
8895
}
8996

9097
@Override
91-
public void onMessage(ByteBuffer s) {
98+
public void onMessage(ByteBuffer buffer) {
9299
try {
93-
webSocketRouter.getListener().onMessage(socket, s);
100+
webSocketRouter.getListener().onMessage(socket, buffer);
94101
} catch (Throwable e) {
95102
webSocketRouter.getListener().onError(socket, e);
96103
}

solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/main/java/org/noear/solon/server/tomcat/websocket/TcWebSocketManager.java

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,26 @@
2828

2929
/**
3030
* Tomcat WebSocket 管理器
31-
*
31+
*
3232
* @author 小xu中年
33-
* @since 3.7
33+
* @since 3.7.3
3434
*/
3535
public class TcWebSocketManager {
3636
private static final Logger log = LoggerFactory.getLogger(TcWebSocketManager.class);
37+
private static boolean enableWebSocket = false;
3738

3839
private TcWebSocketManager() {}
3940

40-
private static boolean enableWebSocket = false;
41-
4241
/**
4342
* 在Tomcat上下文中初始化WebSocket支持
4443
* 注意:此方法需要在上下文初始化之前调用
4544
*/
4645
public static void init(Context context) {
46+
if (context == null) {
47+
log.error("Tomcat Context is null, cannot initialize WebSocket");
48+
return;
49+
}
50+
4751
try {
4852
// 注册WebSocket容器初始化器
4953
context.addServletContainerInitializer(new WsSci(), null);
@@ -59,39 +63,57 @@ public static void init(Context context) {
5963
* 注意:此方法需要在服务器启动后调用
6064
*/
6165
public static void registerEndpoints(Context context) {
66+
if (context == null) {
67+
log.error("Tomcat Context is null, cannot register WebSocket endpoints");
68+
return;
69+
}
70+
6271
try {
63-
if (context == null) {
64-
log.error("Tomcat Context is null, cannot register WebSocket endpoints");
65-
return;
66-
}
6772
// 获取ServerContainer
6873
ServerContainer serverContainer = (ServerContainer) context.getServletContext()
6974
.getAttribute("jakarta.websocket.server.ServerContainer");
7075

7176
if (serverContainer == null) {
72-
throw new IllegalStateException("Missing jakarta.websocket.server.ServerContainer");
77+
log.error("Tomcat Context Missing jakarta.websocket.server.ServerContainer");
78+
return;
7379
}
7480

7581
// 获取所有注册的路径
7682
Collection<String> paths = WebSocketRouter.getInstance().getPaths();
7783

7884
for (String path : paths) {
7985
if (path.startsWith("/")) {
86+
// 使用自定义配置器创建端点配置
8087
ServerEndpointConfig endpointConfig = ServerEndpointConfig.Builder
8188
.create(TcWebSocketEndpoint.class, path)
89+
.configurator(new TcWebSocketConfigurator())
8290
.build();
91+
8392
serverContainer.addEndpoint(endpointConfig);
8493
log.info("Tomcat Registered WebSocket endpoint: {}", path);
8594
}
8695
}
8796
} catch (Throwable e) {
88-
log.error("Failed to register WebSocket endpoints", e);
89-
throw new RuntimeException(e);
97+
log.error("Failed to register Tomcat WebSocket endpoints", e);
9098
}
9199
}
92100

93-
public static boolean isEnableWebSocket() {
94-
return enableWebSocket;
95-
}
101+
/**
102+
* 检查WebSocket是否已启用
103+
*/
104+
public static boolean isEnableWebSocket() {
105+
return enableWebSocket;
106+
}
96107

108+
/**
109+
* 获取WebSocket容器
110+
*/
111+
// public static ServerContainer getServerContainer(Context context) {
112+
// if (context == null) {
113+
// return null;
114+
// }
115+
//
116+
// return (ServerContainer) context.getServletContext()
117+
// .getAttribute("jakarta.websocket.server.ServerContainer");
118+
// }
97119
}

solon-jakarta-projects/solon-server/solon-server-tomcat-jakarta/src/main/java/org/noear/solon/server/tomcat/websocket/WebSocketImpl.java

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,49 @@
1515
*/
1616
package org.noear.solon.server.tomcat.websocket;
1717

18-
import jakarta.websocket.CloseReason;
19-
import jakarta.websocket.Session;
18+
import java.net.InetSocketAddress;
19+
import java.net.URI;
20+
import java.nio.ByteBuffer;
21+
import java.util.concurrent.Future;
22+
2023
import org.noear.solon.net.websocket.WebSocketBase;
24+
import org.noear.solon.server.util.DecodeUtils;
2125
import org.slf4j.Logger;
2226
import org.slf4j.LoggerFactory;
2327

24-
import java.net.InetSocketAddress;
25-
import java.nio.ByteBuffer;
26-
import java.util.concurrent.Future;
28+
import jakarta.websocket.CloseReason;
29+
import jakarta.websocket.Session;
2730

2831
/**
29-
*
30-
* @author 小xu中年
31-
* @since 3.7
32-
* */
32+
* Tomcat WebSocket 实现
33+
*
34+
* @author noear
35+
* @since 3.7.3
36+
*/
3337
public class WebSocketImpl extends WebSocketBase {
3438
private static final Logger log = LoggerFactory.getLogger(WebSocketImpl.class);
35-
private Session real;
39+
private final Session real;
3640

3741
public WebSocketImpl(Session real) {
3842
this.real = real;
39-
this.init(real.getRequestURI());
43+
String uri = DecodeUtils.rinseUri(real.getRequestURI().toString());
44+
this.init(URI.create(uri));
45+
46+
// 从会话属性中获取请求头信息
47+
for (String key : real.getUserProperties().keySet()) {
48+
if (key.startsWith("header.")) {
49+
String headerName = key.substring(7); // 移除"header."前缀
50+
Object value = real.getUserProperties().get(key);
51+
if (value instanceof String) {
52+
this.param(headerName, (String) value);
53+
}
54+
}
55+
}
4056
}
4157

4258
@Override
4359
public boolean isValid() {
44-
return isClosed() == false && real.isOpen();
60+
return !isClosed() && real.isOpen();
4561
}
4662

4763
@Override
@@ -51,13 +67,11 @@ public boolean isSecure() {
5167

5268
@Override
5369
public InetSocketAddress remoteAddress() {
54-
// Tomcat的Session不直接提供远程地址,这里返回null
5570
return null;
5671
}
5772

5873
@Override
5974
public InetSocketAddress localAddress() {
60-
// Tomcat的Session不直接提供本地地址,这里返回null
6175
return null;
6276
}
6377

0 commit comments

Comments
 (0)