java - 如何在 Spring Boot 中将区域设置从 http 请求传递到 websocket?

标签 java spring spring-boot locale spring-websocket

如何在 Spring Boot 中将区域设置从 http 请求传递到 websocket?

我的区域设置已经在 LocaleContextHolder 中设置,但是当我移交给 websocket 时,它消失了并且再次默认。 将区域设置移交给 websockets 的正确方法是什么?

最佳答案

好的,我找到了解决方案。 由于 LocaleContextHolder 是基于线程的,并且 websocket 是异步运行的,因此请求中的内容会丢失。 但幸运的是,有 HandshakeInterceptor 将某些事情交给 websocket session 。

我的配置:

@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketBrokerConfig extends AbstractSessionWebSocketMessageBrokerConfigurer<Session> {

    // ...

    @Override
    protected void configureStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
        .setAllowedOrigins("*")
        .addInterceptors(new HttpWebsocketHandshakeInterceptor()) // <-- The interceptor
        .withSockJS();
    }

    // ...

}

拦截器:

public class HttpWebsocketHandshakeInterceptor implements HandshakeInterceptor {

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception {

        if (request instanceof ServletServerHttpRequest) {
            Locale locale = LocaleContextHolder.getLocale();
            attributes.put(WSConstants.HEADER_HTTP_LOCALE, locale);

            // hand over more stuff, if needed ...
        }
        return true;
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
            Exception exception) {

    }

}

WSConstants.HEADER_HTTP_LOCALE 只是一个字符串常量。随便你怎么调用它。

然后在你的 Controller 中:

@Controller
public class WSController {

    @MessageMapping("/somewhere/")
    public void message(
                SimpMessageHeaderAccessor headerAccessor,
                Principal principal,
                WSMessage frame) {

        // update locale to keep it up to date
        Map<String, Object> sessionHeaders = headerAccessor.getSessionAttributes();
        Locale locale = (Locale) sessionHeaders.get(WSConstants.HEADER_HTTP_LOCALE);
        if (locale != null) {
            LocaleContextHolder.setLocale(locale);
        }

        // use your localized stuff as you used to

    }

    @SubscribeMapping("/somewhereelse/")
    public ChannelPayload bubble(
            SimpMessageHeaderAccessor headerAccessor,
            Principal principal
            ) {

        // update locale to keep it up to date
        Map<String, Object> sessionHeaders = headerAccessor.getSessionAttributes();
        Locale locale = (Locale) sessionHeaders.get(WSConstants.HEADER_HTTP_LOCALE);
        if (locale != null) {
            LocaleContextHolder.setLocale(locale);
        }

        // use your localized stuff as you used to

        return null;
    }

}

希望这可以帮助其他遇到同样问题的人。

关于java - 如何在 Spring Boot 中将区域设置从 http 请求传递到 websocket?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56878771/

相关文章:

spring-boot - Spring Boot自定义异常未在日志中打印

java - 添加 Openfeign 依赖时出现 java.lang.IllegalStateException

java - 我可以通过编程方式确定 spring bean 是否不是单例吗?

java - 我应该用@NonNull 注释标记接口(interface)及其实现吗?

java - REST Controller 中具有一对多关系的实体的递归 JSON View

java - 在 Spring 启动一段时间后,数据库连接丢失

java - 使用类图在java中实现聚合和组合

java - 将请求参数从托管 Bean 传递到 jsf 页面

java - 当我在 for 循环中使用 ArrayList 时,如何将对象添加到 ArrayList 中?

spring-boot - 如何访问 Thymeleaf 中的 contextPath?