如何以编程方式在嵌入式 tomcat 中添加 websocket 端点?
How can I programmatically add a websocket endpoint in embedded tomcat?
几周来我一直在尝试让 websockets 与嵌入式 tomcat 一起工作。我尝试模拟 tomcat 单元测试中的示例,但无济于事。这是我第一次尝试使用 websockets,所以我可能会犯一个愚蠢的错误。有没有人有嵌入式 tomcat websockets 的简单 "Echo" 示例?
public void run() {
if(!new File(consoleAppBase).isDirectory())
{
consoleAppBase = Paths.get("").toAbsolutePath().toString() + File.separatorChar + "wepapp";
}
tomcat = new Tomcat();
tomcat.getService().removeConnector(tomcat.getConnector()); // remove default
tomcat.getService().addConnector(createSslConnector(ConfigManager.getWeb_securePort())); // add secure option
StandardServer server = (StandardServer) tomcat.getServer();
AprLifecycleListener listener = new AprLifecycleListener();
server.addLifecycleListener(listener);
try {
SecurityConstraint constraint = new SecurityConstraint();
constraint.setDisplayName("SSL Redirect Constraint");
constraint.setAuthConstraint(true);
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
constraint.addAuthRole("administrator");
constraint.addCollection(collection);
//create the console webapp.
consoleContext = tomcat.addWebapp(consoleContextPath, consoleAppBase);
consoleContext.addConstraint(constraint);
//this allows that little login popup for the console webapp.
LoginConfig loginConfig = new LoginConfig();
loginConfig.setAuthMethod("BASIC");
consoleContext.setLoginConfig(loginConfig);
consoleContext.addSecurityRole("administrator");
//this creates a valid user.
tomcat.addUser(ConfigManager.getWeb_username(), Encryptor.decrypt(ConfigManager.getWeb_passwordEncrypted()));
tomcat.addRole("admin", "administrator");
} catch (ServletException e) {
LogMaster.getWebServerLogger().error("Error launching Web Application. Stopping Web Server.");
LogMaster.getErrorLogger().error("Error launching Web Application. Stopping Web Server.", e);
return;
}
addServlets(); // this is where I usually call a convenience method to add servlets
// How can I add websocket endpoints instead?
}
据我所知,配置 websocket 与配置 servlet(或 servlet 过滤器)是一样的。在 web.xml 中,您必须包含 <async-supported>true</async-supported>
.
我假设 java 配置中有一个类似的标志。
我是这样使用 WebSocket 的:
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
//...
@ServerEndpoint("/move")
public class TestWebSocketEndPoint {//@OnMessage
public void onMessage(Session session, String message) {}
private static final Queue<Session> QUEUE = new ConcurrentLinkedQueue<Session>();
@OnOpen
public void open(Session session) {
QUEUE.add(session);
}
@OnError
public void error(Session session, Throwable t) {
StaticLogger.log(TestWebSocketEndPoint.class, t);
QUEUE.remove(session);
}
@OnClose
public void closedConnection(Session session) {
QUEUE.remove(session);
}
public static void sendToAll(String message) throws IOException {
ArrayList<Session> closedSessions = new ArrayList<Session>();
for (Session session : QUEUE) {
if (!session.isOpen()) {
closedSessions.add(session);
} else {
session.getBasicRemote().sendText(message);
}
}
QUEUE.removeAll(closedSessions);
}
}
和JS调用:
var webSocket;
webSocket = new WebSocket("ws://localhost:8585/test/move");
webSocket.onmessage = function () {
alert('test');
}
Java 通话:
TestWebSocketEndPoint.sendToAll(result);
对于程序化(非注释)端点,您必须提供一个 class 实现 Endpoint
作为服务器端,然后:
- 在您的 WAR 文件中部署一个 class 实现
ServerApplicationConfig
,它提供 EndpointConfig
有关部分或全部未注释 Endpoint
的信息在 WAR 文件中找到的实例,或
- 在您的网络应用程序的部署阶段调用
ServerContainer.addEndpoint()
。
查看 WebSocket、JSR 356 的 Java™ API。
几周来我一直在尝试让 websockets 与嵌入式 tomcat 一起工作。我尝试模拟 tomcat 单元测试中的示例,但无济于事。这是我第一次尝试使用 websockets,所以我可能会犯一个愚蠢的错误。有没有人有嵌入式 tomcat websockets 的简单 "Echo" 示例?
public void run() {
if(!new File(consoleAppBase).isDirectory())
{
consoleAppBase = Paths.get("").toAbsolutePath().toString() + File.separatorChar + "wepapp";
}
tomcat = new Tomcat();
tomcat.getService().removeConnector(tomcat.getConnector()); // remove default
tomcat.getService().addConnector(createSslConnector(ConfigManager.getWeb_securePort())); // add secure option
StandardServer server = (StandardServer) tomcat.getServer();
AprLifecycleListener listener = new AprLifecycleListener();
server.addLifecycleListener(listener);
try {
SecurityConstraint constraint = new SecurityConstraint();
constraint.setDisplayName("SSL Redirect Constraint");
constraint.setAuthConstraint(true);
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
constraint.addAuthRole("administrator");
constraint.addCollection(collection);
//create the console webapp.
consoleContext = tomcat.addWebapp(consoleContextPath, consoleAppBase);
consoleContext.addConstraint(constraint);
//this allows that little login popup for the console webapp.
LoginConfig loginConfig = new LoginConfig();
loginConfig.setAuthMethod("BASIC");
consoleContext.setLoginConfig(loginConfig);
consoleContext.addSecurityRole("administrator");
//this creates a valid user.
tomcat.addUser(ConfigManager.getWeb_username(), Encryptor.decrypt(ConfigManager.getWeb_passwordEncrypted()));
tomcat.addRole("admin", "administrator");
} catch (ServletException e) {
LogMaster.getWebServerLogger().error("Error launching Web Application. Stopping Web Server.");
LogMaster.getErrorLogger().error("Error launching Web Application. Stopping Web Server.", e);
return;
}
addServlets(); // this is where I usually call a convenience method to add servlets
// How can I add websocket endpoints instead?
}
据我所知,配置 websocket 与配置 servlet(或 servlet 过滤器)是一样的。在 web.xml 中,您必须包含 <async-supported>true</async-supported>
.
我假设 java 配置中有一个类似的标志。
我是这样使用 WebSocket 的:
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
//...
@ServerEndpoint("/move")
public class TestWebSocketEndPoint {//@OnMessage
public void onMessage(Session session, String message) {}
private static final Queue<Session> QUEUE = new ConcurrentLinkedQueue<Session>();
@OnOpen
public void open(Session session) {
QUEUE.add(session);
}
@OnError
public void error(Session session, Throwable t) {
StaticLogger.log(TestWebSocketEndPoint.class, t);
QUEUE.remove(session);
}
@OnClose
public void closedConnection(Session session) {
QUEUE.remove(session);
}
public static void sendToAll(String message) throws IOException {
ArrayList<Session> closedSessions = new ArrayList<Session>();
for (Session session : QUEUE) {
if (!session.isOpen()) {
closedSessions.add(session);
} else {
session.getBasicRemote().sendText(message);
}
}
QUEUE.removeAll(closedSessions);
}
}
和JS调用:
var webSocket;
webSocket = new WebSocket("ws://localhost:8585/test/move");
webSocket.onmessage = function () {
alert('test');
}
Java 通话:
TestWebSocketEndPoint.sendToAll(result);
对于程序化(非注释)端点,您必须提供一个 class 实现 Endpoint
作为服务器端,然后:
- 在您的 WAR 文件中部署一个 class 实现
ServerApplicationConfig
,它提供EndpointConfig
有关部分或全部未注释Endpoint
的信息在 WAR 文件中找到的实例,或 - 在您的网络应用程序的部署阶段调用
ServerContainer.addEndpoint()
。
查看 WebSocket、JSR 356 的 Java™ API。