Я опирался на идею @ Dániel Kis и реализовал управление сеансами веб-сокетов с ключевой точкой хранения сеансов веб-сокетов для аутентифицированных пользователей в объекте типа Singleton.
// WebSocketConfig.java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
@Override
public WebSocketHandler decorate(final WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
@Override
public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
// We will store current user's session into WebsocketSessionHolder after connection is established
String username = session.getPrincipal().getName();
WebsocketSessionHolder.addSession(username, session);
super.afterConnectionEstablished(session);
}
};
}
});
}
}
Класс для хранения сеансов пользователей веб-сокетов WebsocketSessionHolder. Я использую «синхронизированные» блоки для обеспечения безопасности потоков. На самом деле эти блоки не являются дорогостоящими операциями, потому что каждый из методов (addSession и closeSessions) используется не так часто (при установлении и завершении соединения). Здесь нет необходимости использовать ConcurrentHashMap или SynchronizedMap, потому что мы выполняем множество операций со списком в этих методах.
// WebsocketSessionHolder.java
public class WebsocketSessionHolder {
static {
sessions = new HashMap<>();
}
// key - username, value - List of user's sessions
private static Map<String, List<WebSocketSession>> sessions;
public static void addSession(String username, WebSocketSession session)
{
synchronized (sessions) {
var userSessions = sessions.get(username);
if (userSessions == null)
userSessions = new ArrayList<WebSocketSession>();
userSessions.add(session);
sessions.put(username, userSessions);
}
}
public static void closeSessions(String username) throws IOException
{
synchronized (sessions) {
var userSessions = sessions.get(username);
if (userSessions != null)
{
for(var session : userSessions) {
// I use POLICY_VIOLATION to indicate reason of disconnecting for a client
session.close(CloseStatus.POLICY_VIOLATION);
}
sessions.remove(username);
}
}
}
}
И последний штрих - завершение (отключение) определенных пользовательских сеансов веб-сокетов (ADMIN в примере), скажем, в каком-то контроллере
//PageController.java
@Controller
public class PageController {
@GetMapping("/kill-sessions")
public void killSessions() throws Exception {
WebsocketSessionHolder.closeSessions("ADMIN");
}
}
person
Rustam Shafigullin
schedule
30.06.2020