Server-side WebSocket handshake processing, protocol upgrade strategies, and integration with WebSocket server implementations. Handles HTTP to WebSocket protocol upgrades and provides adapters for standard JSR-356 and Jetty servers.
Processes the WebSocket handshake request and performs the protocol upgrade.
/**
* Contract for processing a WebSocket handshake request. Implementations
* handle the HTTP upgrade protocol to establish a WebSocket connection.
*/
public interface HandshakeHandler {
/**
* Initiate the handshake by processing the request and upgrading to
* the WebSocket protocol.
*
* @param request the HTTP request
* @param response the HTTP response
* @param wsHandler the WebSocket handler for the connection
* @param attributes attributes from HandshakeInterceptors
* @return true if the handshake succeeds, false otherwise
* @throws HandshakeFailureException if the handshake fails
*/
boolean doHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes) throws HandshakeFailureException;
}Intercepts WebSocket handshake requests before and after the handshake is processed.
/**
* Allows interception of WebSocket handshake requests. Interceptors can
* inspect the request, modify attributes, or prevent the handshake from
* proceeding.
*/
public interface HandshakeInterceptor {
/**
* Invoked before the handshake is processed. Return false to prevent
* the handshake from proceeding.
*
* @param request the HTTP request
* @param response the HTTP response
* @param wsHandler the target WebSocket handler
* @param attributes attributes to pass to the WebSocket session
* @return true to proceed with the handshake, false to abort
* @throws Exception if an error occurs
*/
boolean beforeHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception;
/**
* Invoked after the handshake is processed, regardless of outcome.
*
* @param request the HTTP request
* @param response the HTTP response
* @param wsHandler the target WebSocket handler
* @param exception the exception if handshake failed, null otherwise
*/
void afterHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Exception exception);
}Server-specific strategy for upgrading HTTP requests to WebSocket connections.
/**
* A server-specific strategy for performing the actual HTTP to WebSocket
* protocol upgrade. Different WebSocket server implementations require
* different upgrade mechanisms.
*/
public interface RequestUpgradeStrategy {
/**
* Return the WebSocket protocol versions supported by this strategy.
*
* @return an array of supported version strings (e.g., "13")
*/
String[] getSupportedVersions();
/**
* Return the WebSocket extensions supported by the server for the
* given request.
*
* @param request the HTTP request
* @return list of supported extensions
*/
List<WebSocketExtension> getSupportedExtensions(ServerHttpRequest request);
/**
* Perform the actual upgrade from HTTP to WebSocket protocol.
*
* @param request the HTTP request
* @param response the HTTP response
* @param selectedProtocol the selected sub-protocol, may be null
* @param selectedExtensions the selected extensions
* @param user the user principal, may be null
* @param wsHandler the WebSocket handler
* @param attributes attributes from interceptors
* @throws HandshakeFailureException if upgrade fails
*/
void upgrade(
ServerHttpRequest request,
ServerHttpResponse response,
String selectedProtocol,
List<WebSocketExtension> selectedExtensions,
Principal user,
WebSocketHandler wsHandler,
Map<String, Object> attributes) throws HandshakeFailureException;
}Base implementation of HandshakeHandler with common handshake logic.
/**
* Abstract base class for HandshakeHandler implementations. Provides
* common handshake processing logic including sub-protocol negotiation,
* extension negotiation, and user principal determination.
*/
public abstract class AbstractHandshakeHandler implements HandshakeHandler {
/**
* Create a new handshake handler with default RequestUpgradeStrategy.
* The strategy is auto-detected based on the runtime environment.
*/
public AbstractHandshakeHandler();
/**
* Create a new handshake handler with the given upgrade strategy.
*
* @param upgradeStrategy the upgrade strategy to use
*/
public AbstractHandshakeHandler(RequestUpgradeStrategy upgradeStrategy);
/**
* Determine the user principal to associate with the WebSocket session.
* Default implementation returns the principal from the HTTP request.
*
* @param request the HTTP request
* @param wsHandler the WebSocket handler
* @param attributes handshake attributes
* @return the user principal, or null if none
*/
protected Principal determineUser(
ServerHttpRequest request,
WebSocketHandler wsHandler,
Map<String, Object> attributes);
@Override
public boolean doHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes) throws HandshakeFailureException;
}Default HandshakeHandler implementation supporting standard WebSocket servers.
/**
* Default HandshakeHandler implementation. Auto-detects the WebSocket
* server runtime and uses the appropriate RequestUpgradeStrategy.
* Supports JSR-356 (Jakarta WebSocket), Jetty, and other standard
* WebSocket server implementations.
*/
public class DefaultHandshakeHandler extends AbstractHandshakeHandler {
/**
* Create a handler with auto-detected RequestUpgradeStrategy.
* Detects Jetty, Tomcat, Undertow, or uses standard JSR-356.
*/
public DefaultHandshakeHandler();
/**
* Create a handler with a specific RequestUpgradeStrategy.
*
* @param upgradeStrategy the upgrade strategy to use
*/
public DefaultHandshakeHandler(RequestUpgradeStrategy upgradeStrategy);
/**
* Set the supported sub-protocols. Used during sub-protocol negotiation.
*
* @param protocols the supported sub-protocols
*/
public void setSupportedProtocols(String... protocols);
/**
* Get the list of supported sub-protocols.
*
* @return the supported sub-protocols
*/
public String[] getSupportedProtocols();
}Copies HTTP session attributes to the WebSocket session.
/**
* HandshakeInterceptor that copies HTTP session attributes into the
* WebSocket session attributes map. Useful for passing HTTP session
* data to the WebSocket handler.
*/
public class HttpSessionHandshakeInterceptor implements HandshakeInterceptor {
/**
* Attribute name for the HTTP session ID in WebSocket attributes.
* Value: "HTTP.SESSION.ID"
*/
public static final String HTTP_SESSION_ID_ATTR_NAME = "HTTP.SESSION.ID";
/**
* Create an interceptor that copies all HTTP session attributes.
*/
public HttpSessionHandshakeInterceptor();
/**
* Create an interceptor with configuration for which attributes to copy.
*
* @param copyAllAttributes whether to copy all HTTP session attributes
*/
public HttpSessionHandshakeInterceptor(boolean copyAllAttributes);
/**
* Set the names of specific HTTP session attributes to copy.
* If not set and copyAllAttributes is true, all attributes are copied.
*
* @param attributeNames the attribute names to copy
*/
public void setAttributeNames(Collection<String> attributeNames);
/**
* Get the configured attribute names to copy.
*
* @return the attribute names, or null if all attributes are copied
*/
public Collection<String> getAttributeNames();
/**
* Whether to create an HTTP session if one doesn't exist.
* Default is true.
*
* @param createSession whether to create HTTP session
*/
public void setCreateSession(boolean createSession);
/**
* Whether to create an HTTP session if one doesn't exist.
*
* @return true if session creation is enabled
*/
public boolean isCreateSession();
@Override
public boolean beforeHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception;
@Override
public void afterHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Exception exception);
}Validates the Origin header to implement cross-origin request security.
/**
* HandshakeInterceptor that checks the Origin header against allowed
* origins to implement same-origin policy or CORS security.
*/
public class OriginHandshakeInterceptor implements HandshakeInterceptor {
/**
* Create an interceptor that rejects all cross-origin requests.
*/
public OriginHandshakeInterceptor();
/**
* Create an interceptor with allowed origins.
*
* @param allowedOrigins the allowed origin values (e.g., "https://example.com")
*/
public OriginHandshakeInterceptor(Collection<String> allowedOrigins);
/**
* Set allowed origin values. An origin is allowed if it matches one
* of these values. Use "*" to allow all origins.
*
* @param allowedOrigins the allowed origins
*/
public void setAllowedOrigins(Collection<String> allowedOrigins);
/**
* Set allowed origin patterns with wildcard support.
* Example: "https://*.example.com"
*
* @param allowedOriginPatterns the allowed origin patterns
*/
public void setAllowedOriginPatterns(Collection<String> allowedOriginPatterns);
@Override
public boolean beforeHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception;
@Override
public void afterHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Exception exception);
}HTTP request handler that processes WebSocket handshake requests.
/**
* HttpRequestHandler that processes WebSocket handshake requests.
* Delegates to HandshakeHandler and applies HandshakeInterceptors.
*/
public class WebSocketHttpRequestHandler implements HttpRequestHandler {
/**
* Create a request handler for the given WebSocket handler.
*
* @param wsHandler the WebSocket handler
*/
public WebSocketHttpRequestHandler(WebSocketHandler wsHandler);
/**
* Create a request handler with a custom handshake handler.
*
* @param wsHandler the WebSocket handler
* @param handshakeHandler the handshake handler
*/
public WebSocketHttpRequestHandler(
WebSocketHandler wsHandler,
HandshakeHandler handshakeHandler);
/**
* Set the HandshakeHandler to use for processing handshakes.
*
* @param handshakeHandler the handshake handler
*/
public void setHandshakeHandler(HandshakeHandler handshakeHandler);
/**
* Get the configured HandshakeHandler.
*
* @return the handshake handler
*/
public HandshakeHandler getHandshakeHandler();
/**
* Set HandshakeInterceptors to apply to handshake requests.
*
* @param interceptors the interceptors to apply
*/
public void setHandshakeInterceptors(List<HandshakeInterceptor> interceptors);
/**
* Get the configured HandshakeInterceptors.
*
* @return the interceptors
*/
public List<HandshakeInterceptor> getHandshakeInterceptors();
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}JSR-356 (Jakarta WebSocket) implementation of RequestUpgradeStrategy.
/**
* RequestUpgradeStrategy for standard JSR-356 runtimes (Jakarta WebSocket).
* Works with any servlet container that supports JSR-356 including Tomcat,
* Jetty, Undertow, and WildFly.
*/
public class StandardWebSocketUpgradeStrategy implements RequestUpgradeStrategy {
/**
* Create an upgrade strategy using the default WebSocketContainer.
*/
public StandardWebSocketUpgradeStrategy();
/**
* Create an upgrade strategy using a specific WebSocketContainer.
*
* @param webSocketContainer the WebSocket container to use
*/
public StandardWebSocketUpgradeStrategy(WebSocketContainer webSocketContainer);
/**
* Set extensions to enable. By default, all supported extensions are enabled.
*
* @param extensions the extensions to enable
*/
public void setExtensions(List<Extension> extensions);
/**
* Get the configured extensions.
*
* @return the extensions
*/
public List<Extension> getExtensions();
@Override
public String[] getSupportedVersions();
@Override
public List<WebSocketExtension> getSupportedExtensions(ServerHttpRequest request);
@Override
public void upgrade(
ServerHttpRequest request,
ServerHttpResponse response,
String selectedProtocol,
List<WebSocketExtension> selectedExtensions,
Principal user,
WebSocketHandler wsHandler,
Map<String, Object> attributes) throws HandshakeFailureException;
}Jetty-specific implementation of RequestUpgradeStrategy.
/**
* RequestUpgradeStrategy for Jetty WebSocket server.
* Provides native Jetty WebSocket support with better performance
* than the standard JSR-356 approach.
*/
public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy {
/**
* Create a Jetty upgrade strategy with default configuration.
*/
public JettyRequestUpgradeStrategy();
/**
* Create a Jetty upgrade strategy with a specific WebSocketPolicy.
*
* @param policy the WebSocket policy for configuration
*/
public JettyRequestUpgradeStrategy(WebSocketPolicy policy);
/**
* Set the WebSocketPolicy for configuring buffer sizes, timeouts, etc.
*
* @param policy the policy to use
*/
public void setPolicy(WebSocketPolicy policy);
/**
* Get the configured WebSocketPolicy.
*
* @return the policy
*/
public WebSocketPolicy getPolicy();
@Override
public String[] getSupportedVersions();
@Override
public List<WebSocketExtension> getSupportedExtensions(ServerHttpRequest request);
@Override
public void upgrade(
ServerHttpRequest request,
ServerHttpResponse response,
String selectedProtocol,
List<WebSocketExtension> selectedExtensions,
Principal user,
WebSocketHandler wsHandler,
Map<String, Object> attributes) throws HandshakeFailureException;
}Extension of SimpleUrlHandlerMapping with WebSocket-specific handler mapping.
/**
* Extension of SimpleUrlHandlerMapping with support for more precise
* mapping of WebSocket handshake requests to handlers of type
* WebSocketHttpRequestHandler. Also delegates Lifecycle methods to
* handlers that implement it.
*
* @since 4.2
*/
public class WebSocketHandlerMapping extends SimpleUrlHandlerMapping
implements SmartLifecycle {
/**
* When enabled, if the matched handler is WebSocketHttpRequestHandler,
* ensures the request is a WebSocket handshake (HTTP GET with
* "Upgrade:websocket" header), or suppresses the match returning null
* to allow another HandlerMapping to match.
*
* @param match whether to enable matching on "Upgrade: websocket"
* @since 5.3.5
*/
public void setWebSocketUpgradeMatch(boolean match);
/**
* Set the phase that this handler should run in.
* By default, this is SmartLifecycle.DEFAULT_PHASE, but with
* @EnableWebSocketMessageBroker configuration it is set to 0.
*
* @param phase the lifecycle phase
* @since 6.1.4
*/
public void setPhase(int phase);
@Override
public int getPhase();
@Override
public void start();
@Override
public void stop();
@Override
public boolean isRunning();
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception;
}Spring provides comprehensive support for Jakarta WebSocket (JSR-356) endpoints, enabling dependency injection and Spring-based configuration for standard WebSocket endpoints.
Detects and registers @ServerEndpoint annotated beans with the WebSocket runtime.
/**
* Detects beans of type ServerEndpointConfig and registers with the
* standard Jakarta WebSocket runtime. Also detects beans annotated with
* @ServerEndpoint and registers them as well. Although not required, it
* is likely annotated endpoints should have their configurator property
* set to SpringConfigurator.
*
* When this class is used, by declaring it in Spring configuration, it
* should be possible to turn off a Servlet container's scan for WebSocket
* endpoints. This can be done with the help of the <absolute-ordering>
* element in web.xml.
*
* @since 4.0
* @see ServerEndpointRegistration
* @see SpringConfigurator
* @see ServletServerContainerFactoryBean
*/
public class ServerEndpointExporter extends WebApplicationObjectSupport
implements InitializingBean, SmartInitializingSingleton {
/**
* Explicitly list annotated endpoint types that should be registered
* on startup. This can be done if you wish to turn off a Servlet
* container's scan for endpoints, which goes through all 3rd party
* jars in the classpath, and rely on Spring configuration instead.
*
* @param annotatedEndpointClasses @ServerEndpoint-annotated types
*/
public void setAnnotatedEndpointClasses(Class<?>... annotatedEndpointClasses);
/**
* Set the JSR-356 ServerContainer to use for endpoint registration.
* If not set, the container is going to be retrieved via the ServletContext.
*
* @param serverContainer the ServerContainer to use
*/
public void setServerContainer(ServerContainer serverContainer);
/**
* Return the JSR-356 ServerContainer to use for endpoint registration.
*
* @return the ServerContainer
*/
protected ServerContainer getServerContainer();
@Override
public void afterPropertiesSet();
@Override
public void afterSingletonsInstantiated();
/**
* Actually register the endpoints. Called by afterSingletonsInstantiated().
*/
protected void registerEndpoints();
}FactoryBean for configuring the JSR-356 ServerContainer.
/**
* A FactoryBean for configuring ServerContainer. Since there is usually
* only one ServerContainer instance accessible under a well-known
* ServletContext attribute, simply declaring this FactoryBean and using
* its setters allows for configuring the ServerContainer through Spring
* configuration.
*
* This is useful even if the ServerContainer is not injected into any
* other bean within the Spring application context. For example, an
* application can configure a DefaultHandshakeHandler, a SockJsService,
* or ServerEndpointExporter, and separately declare this FactoryBean in
* order to customize the properties of the (one and only) ServerContainer
* instance.
*
* @since 4.0
*/
public class ServletServerContainerFactoryBean
implements FactoryBean<WebSocketContainer>, ServletContextAware, InitializingBean {
/**
* Set the timeout for async sending operations in milliseconds.
*
* @param timeoutInMillis the async send timeout
*/
public void setAsyncSendTimeout(Long timeoutInMillis);
/**
* Get the configured async send timeout.
*
* @return the timeout in milliseconds
*/
public Long getAsyncSendTimeout();
/**
* Set the maximum idle timeout for WebSocket sessions in milliseconds.
*
* @param timeoutInMillis the max session idle timeout
*/
public void setMaxSessionIdleTimeout(Long timeoutInMillis);
/**
* Get the configured max session idle timeout.
*
* @return the timeout in milliseconds
*/
public Long getMaxSessionIdleTimeout();
/**
* Set the maximum size of text message buffers.
*
* @param bufferSize the buffer size in bytes
*/
public void setMaxTextMessageBufferSize(Integer bufferSize);
/**
* Get the configured max text message buffer size.
*
* @return the buffer size in bytes
*/
public Integer getMaxTextMessageBufferSize();
/**
* Set the maximum size of binary message buffers.
*
* @param bufferSize the buffer size in bytes
*/
public void setMaxBinaryMessageBufferSize(Integer bufferSize);
/**
* Get the configured max binary message buffer size.
*
* @return the buffer size in bytes
*/
public Integer getMaxBinaryMessageBufferSize();
@Override
public void setServletContext(ServletContext servletContext);
@Override
public void afterPropertiesSet();
@Override
public ServerContainer getObject();
@Override
public Class<?> getObjectType();
@Override
public boolean isSingleton();
}JSR-356 Configurator that enables Spring dependency injection in @ServerEndpoint annotated classes.
/**
* A ServerEndpointConfig.Configurator for initializing @ServerEndpoint
* annotated classes through Spring.
*
* Example usage:
* <pre class="code">
* @ServerEndpoint(value = "/echo", configurator = SpringConfigurator.class)
* public class EchoEndpoint {
* // ...
* }
* </pre>
*
* @since 4.0
* @see ServerEndpointExporter
*/
public class SpringConfigurator extends ServerEndpointConfig.Configurator {
/**
* Get an endpoint instance from the Spring ApplicationContext. First
* attempts to find the endpoint as a Spring bean by short name, then
* by @Component value, then by type. If no bean is found, creates a
* new instance using Spring's AutowireCapableBeanFactory to enable
* dependency injection.
*
* @param endpointClass the endpoint class
* @return the endpoint instance
* @throws InstantiationException if the endpoint cannot be instantiated
*/
@Override
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException;
}Programmatic registration for JSR-356 ServerEndpoint without using annotations.
/**
* An implementation of ServerEndpointConfig for use in Spring-based
* applications. A ServerEndpointRegistration bean is detected by
* ServerEndpointExporter and registered with a Jakarta WebSocket runtime
* at startup.
*
* Class constructors accept a singleton Endpoint instance or an Endpoint
* specified by type Class. When specified by type, the endpoint will be
* instantiated and initialized through the Spring ApplicationContext
* before each client WebSocket connection.
*
* This class also extends ServerEndpointConfig.Configurator to make it
* easier to override methods for customizing the handshake process.
*
* @since 4.0
* @see ServerEndpointExporter
*/
public class ServerEndpointRegistration extends ServerEndpointConfig.Configurator
implements ServerEndpointConfig, BeanFactoryAware {
/**
* Create a new ServerEndpointRegistration instance from an
* Endpoint instance.
*
* @param path the endpoint path
* @param endpoint the endpoint instance
*/
public ServerEndpointRegistration(String path, Endpoint endpoint);
/**
* Create a new ServerEndpointRegistration instance from an
* Endpoint class.
*
* @param path the endpoint path
* @param endpointClass the endpoint class
*/
public ServerEndpointRegistration(String path, Class<? extends Endpoint> endpointClass);
@Override
public String getPath();
@Override
public Class<? extends Endpoint> getEndpointClass();
/**
* Get the endpoint instance. If a class was specified in the
* constructor, this creates a new instance using Spring.
*
* @return the endpoint instance
*/
public Endpoint getEndpoint();
/**
* Set the sub-protocols this endpoint supports.
*
* @param subprotocols the supported sub-protocols
*/
public void setSubprotocols(List<String> subprotocols);
@Override
public List<String> getSubprotocols();
/**
* Set the extensions this endpoint supports.
*
* @param extensions the supported extensions
*/
public void setExtensions(List<Extension> extensions);
@Override
public List<Extension> getExtensions();
/**
* Set encoders for this endpoint.
*
* @param encoders the encoder classes
*/
public void setEncoders(List<Class<? extends Encoder>> encoders);
@Override
public List<Class<? extends Encoder>> getEncoders();
/**
* Set decoders for this endpoint.
*
* @param decoders the decoder classes
*/
public void setDecoders(List<Class<? extends Decoder>> decoders);
@Override
public List<Class<? extends Decoder>> getDecoders();
/**
* Set user properties for this endpoint.
*
* @param userProperties the user properties map
*/
public void setUserProperties(Map<String, Object> userProperties);
@Override
public Map<String, Object> getUserProperties();
@Override
public Configurator getConfigurator();
@Override
public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException;
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request,
HandshakeResponse response);
@Override
public void setBeanFactory(BeanFactory beanFactory);
}Exception thrown when a WebSocket handshake fails.
/**
* Exception thrown to indicate a WebSocket handshake failure.
*/
public class HandshakeFailureException extends Exception {
/**
* Create an exception with a message.
*
* @param message the error message
*/
public HandshakeFailureException(String message);
/**
* Create an exception with a message and cause.
*
* @param message the error message
* @param cause the underlying cause
*/
public HandshakeFailureException(String message, Throwable cause);
}import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/ws")
.setHandshakeHandler(handshakeHandler())
.addInterceptors(new HttpSessionHandshakeInterceptor());
}
@Bean
public HandshakeHandler handshakeHandler() {
return new DefaultHandshakeHandler();
}
@Bean
public WebSocketHandler myHandler() {
return new MyWebSocketHandler();
}
}import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
import org.springframework.http.server.ServerHttpRequest;
@Bean
public HandshakeHandler customHandshakeHandler() {
return new DefaultHandshakeHandler() {
@Override
protected Principal determineUser(
ServerHttpRequest request,
WebSocketHandler wsHandler,
Map<String, Object> attributes) {
// Extract user from custom header
HttpHeaders headers = request.getHeaders();
String username = headers.getFirst("X-User-Name");
if (username != null) {
return new SimplePrincipal(username);
}
// Fall back to authenticated principal
return request.getPrincipal();
}
};
}
// Simple Principal implementation
class SimplePrincipal implements Principal {
private final String name;
public SimplePrincipal(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}import org.springframework.web.socket.server.HandshakeInterceptor;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
public class AuthenticationHandshakeInterceptor implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
// Extract authentication token
String token = extractToken(request);
if (token == null || !isValidToken(token)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return false; // Reject handshake
}
// Store authenticated user in attributes
User user = getUserFromToken(token);
attributes.put("user", user);
return true; // Proceed with handshake
}
@Override
public void afterHandshake(
ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler wsHandler,
Exception exception) {
if (exception != null) {
// Log handshake failure
System.err.println("Handshake failed: " + exception.getMessage());
}
}
private String extractToken(ServerHttpRequest request) {
// Extract from query parameter or header
URI uri = request.getURI();
String query = uri.getQuery();
if (query != null && query.contains("token=")) {
return query.split("token=")[1].split("&")[0];
}
return request.getHeaders().getFirst("Authorization");
}
private boolean isValidToken(String token) {
// Validate token
return token != null && token.length() > 0;
}
private User getUserFromToken(String token) {
// Decode and return user
return new User(token);
}
}import org.springframework.web.socket.server.support.OriginHandshakeInterceptor;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
OriginHandshakeInterceptor originInterceptor = new OriginHandshakeInterceptor(
Arrays.asList(
"https://example.com",
"https://app.example.com"
)
);
registry.addHandler(myHandler(), "/ws")
.addInterceptors(originInterceptor);
}
}import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// Copy specific HTTP session attributes
HttpSessionHandshakeInterceptor sessionInterceptor =
new HttpSessionHandshakeInterceptor();
sessionInterceptor.setAttributeNames(
Arrays.asList("userId", "sessionData")
);
registry.addHandler(myHandler(), "/ws")
.addInterceptors(sessionInterceptor);
}
}
// Access attributes in handler
public class MyHandler extends TextWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
// Access HTTP session attributes
String userId = (String) session.getAttributes().get("userId");
String sessionData = (String) session.getAttributes().get("sessionData");
System.out.println("User " + userId + " connected with data: " + sessionData);
}
}import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
@Component
@ServerEndpoint("/chat")
public class ChatEndpoint {
// Spring dependency injection works!
@Autowired
private MessageService messageService;
@OnOpen
public void onOpen(Session session) {
System.out.println("Connected: " + session.getId());
}
@OnMessage
public void onMessage(String message, Session session) {
// Use injected service
String response = messageService.processMessage(message);
try {
session.getBasicRemote().sendText(response);
} catch (IOException e) {
e.printStackTrace();
}
}
@OnClose
public void onClose(Session session) {
System.out.println("Disconnected: " + session.getId());
}
@OnError
public void onError(Session session, Throwable error) {
System.err.println("Error: " + error.getMessage());
}
}import org.springframework.web.socket.server.standard.ServerEndpointRegistration;
import jakarta.websocket.Endpoint;
import jakarta.websocket.EndpointConfig;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointRegistration myEndpoint() {
return new ServerEndpointRegistration("/programmatic", MyEndpoint.class)
.setSubprotocols("chat", "superchat")
.setEncoders(Arrays.asList(MessageEncoder.class))
.setDecoders(Arrays.asList(MessageDecoder.class));
}
}
class MyEndpoint extends Endpoint {
@Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String message) {
try {
session.getBasicRemote().sendText("Echo: " + message);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}import org.springframework.web.socket.server.RequestUpgradeStrategy;
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/ws")
.setHandshakeHandler(handshakeHandlerWithCustomStrategy());
}
@Bean
public HandshakeHandler handshakeHandlerWithCustomStrategy() {
// Use Jetty-specific upgrade strategy
RequestUpgradeStrategy strategy = new JettyRequestUpgradeStrategy();
return new DefaultHandshakeHandler(strategy);
}
}import org.springframework.web.socket.server.support.WebSocketHandlerMapping;
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;
@Configuration
public class WebSocketConfig {
@Bean
public WebSocketHandlerMapping webSocketHandlerMapping() {
WebSocketHandlerMapping mapping = new WebSocketHandlerMapping();
// Enable WebSocket upgrade matching to ensure only WebSocket
// handshake requests (GET with "Upgrade: websocket" header)
// are matched
mapping.setWebSocketUpgradeMatch(true);
// Configure lifecycle phase for ordered startup/shutdown
mapping.setPhase(0);
// Map WebSocket handlers to URL patterns
Map<String, Object> urlMap = new HashMap<>();
urlMap.put("/ws/chat", chatWebSocketHandler());
urlMap.put("/ws/notifications", notificationWebSocketHandler());
mapping.setUrlMap(urlMap);
// Set handler order
mapping.setOrder(1);
return mapping;
}
@Bean
public WebSocketHttpRequestHandler chatWebSocketHandler() {
return new WebSocketHttpRequestHandler(
new ChatWebSocketHandler(),
new DefaultHandshakeHandler()
);
}
@Bean
public WebSocketHttpRequestHandler notificationWebSocketHandler() {
return new WebSocketHttpRequestHandler(
new NotificationWebSocketHandler(),
new DefaultHandshakeHandler()
);
}
}import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
@Configuration
public class WebSocketConfig {
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container =
new ServletServerContainerFactoryBean();
// Set async send timeout (in milliseconds)
container.setAsyncSendTimeout(30000L);
// Set max session idle timeout (in milliseconds)
container.setMaxSessionIdleTimeout(300000L);
// Set max text message buffer size (in bytes)
container.setMaxTextMessageBufferSize(8192);
// Set max binary message buffer size (in bytes)
container.setMaxBinaryMessageBufferSize(8192);
return container;
}
}