Доступ к ServletContext и HttpSession в @OnMessage JSR-356 @ServerEndpoint
мне нужно ServletContext
внутри @ServerEndpoint
для того, чтобы найти Spring ApplicationContext
и поиск Боба.
на данный момент мой лучший подход-связать этот компонент в контексте именования JNDI и найти его в Endpoint
. Любое лучшее решение приветствуется.
Я также ищу разумный способ синхронизации сервлета HttpSession
С websocket в Session
.
3 ответов
сервлет HttpSession
в JSR-356 доступно по HandshakeRequest#getHttpSession()
который, в свою очередь, доступен, когда запрос рукопожатия сделан прямо перед @OnOpen
of a @ServerEndpoint
. The ServletContext
в свою очередь доступен только через HttpSession#getServletContext()
. Это две птицы одним выстрелом.
для того, чтобы захватить запрос рукопожатия, реализовать ServerEndpointConfig.Configurator
и переопределить modifyHandshake()
метод. The HandshakeRequest
здесь доступно как аргумент метода. Вы можете поставить HttpSession
на EndpointConfig#getUserProperties()
. The EndpointConfig
в свою очередь доступен в качестве метода аргумент @OnOpen
.
вот пример стартового ServerEndpointConfig.Configurator
реализация:
public class ServletAwareConfig extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
HttpSession httpSession = (HttpSession) request.getHttpSession();
config.getUserProperties().put("httpSession", httpSession);
}
}
вот как вы можете использовать его, Примечание configurator
на @ServerEndpoint
:
@ServerEndpoint(value="/your_socket", configurator=ServletAwareConfig.class)
public class YourSocket {
private EndpointConfig config;
@OnOpen
public void onOpen(Session websocketSession, EndpointConfig config) {
this.config = config;
}
@OnMessage
public void onMessage(String message) {
HttpSession httpSession = (HttpSession) config.getUserProperties().get("httpSession");
ServletContext servletContext = httpSession.getServletContext();
// ...
}
}
как подсказка дизайна, лучше всего сохранить ваш @ServerEndpoint
полностью свободен от зависимостей API сервлетов. Ты в the modifyHandshake()
реализация лучше сразу извлечь именно это информация (обычно изменяемый Javabean) вам нужно из сеанса сервлета или контекста и поместить их в карту свойств пользователя. Если вы этого не сделаете, то вы должны иметь в виду, что сеанс websocket может жить дольше, чем сеанс HTTP. Поэтому, когда вы все еще носите HttpSession
в конечную точку, затем вы можете столкнуться с IllegalStateException
при попытке доступа к нему во время истeкший.
если у вас есть CDI (и, возможно, JSF), вы можете получить вдохновение от исходного кода OmniFaces <o:socket>
(ссылки в самом низу витрины).
Читайте также:
обновленный код для ответа BalusC, метод onOpen должен быть украшен @OnOpen. Тогда больше нет необходимости расширять класс Endpoint:
@ServerEndpoint(value="/your_socket", configurator=ServletAwareConfig.class)
public class YourSocket {
private EndpointConfig config;
@OnOpen
public void onOpen(Session websocketSession, EndpointConfig config) {
this.config = config;
}
@OnMessage
public void onMessage(String message) {
HttpSession httpSession = (HttpSession) config.getUserProperties().get("httpSession");
ServletContext servletContext = httpSession.getServletContext();
// ...
}
}
Я попробовал ответ BalusC на Tomcat (версии 7.0.56 и 8.0.14). В обоих контейнерах параметр запроса modifyHandshake не содержит HttpSession (и, следовательно, никакого servletContext). Поскольку мне нужен был контекст сервлета только для доступа к "глобальным" переменным (то есть к глобальному веб-приложению), я просто сохранил эти переменные в обычном статическом поле класса holder. Это неэлегантно, но сработало.
Это Оки, как ошибка в этой конкретной версии tomcat-есть кто-нибудь там тоже видели это?