如何在Spring boot 2 + Webflux + Thymeleaf中配置i18n?

GVA*_*Art 13 thymeleaf spring-boot spring-webflux

我刚刚开始一个基于Spring boot 2 + Webflux的新项目.在升级版本的spring boot并替换spring-boot-starter-webspring-boot-starter-webflux

  • WebMvcConfigurerAdapter
  • 的LocaleResolver
  • LocaleChangeInterceptor

缺失.我现在如何配置defaultLocale和拦截器来改变语言?

Jon*_*oza 5

只需添加一个WebFilterAccept-Language根据查询参数值设置标头的。以下示例从URI之类的language查询参数获取语​​言http://localhost:8080/examples?language=es

import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.adapter.HttpWebHandlerAdapter;
import reactor.core.publisher.Mono;

import static org.springframework.util.StringUtils.isEmpty;

@Component
public class LanguageQueryParameterWebFilter implements WebFilter {

    private final ApplicationContext applicationContext;

    private HttpWebHandlerAdapter httpWebHandlerAdapter;

    public LanguageQueryParameterWebFilter(final ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @EventListener(ApplicationReadyEvent.class)
    public void loadHttpHandler() {
        this.httpWebHandlerAdapter = applicationContext.getBean(HttpWebHandlerAdapter.class);
    }

    @Override
    public Mono<Void> filter(final ServerWebExchange exchange, final WebFilterChain chain) {
        final ServerHttpRequest request = exchange.getRequest();
        final MultiValueMap<String, String> queryParams = request.getQueryParams();
        final String languageValue = queryParams.getFirst("language");

        final ServerWebExchange localizedExchange = getServerWebExchange(languageValue, exchange);
        return chain.filter(localizedExchange);
    }

    private ServerWebExchange getServerWebExchange(final String languageValue, final ServerWebExchange exchange) {
        return isEmpty(languageValue)
                ? exchange
                : getLocalizedServerWebExchange(languageValue, exchange);
    }

    private ServerWebExchange getLocalizedServerWebExchange(final String languageValue, final ServerWebExchange exchange) {
        final ServerHttpRequest httpRequest = exchange.getRequest()
                .mutate()
                .headers(httpHeaders -> httpHeaders.set("Accept-Language", languageValue))
                .build();

        return new DefaultServerWebExchange(httpRequest, exchange.getResponse(),
                httpWebHandlerAdapter.getSessionManager(), httpWebHandlerAdapter.getCodecConfigurer(),
                httpWebHandlerAdapter.getLocaleContextResolver());
    }
}
Run Code Online (Sandbox Code Playgroud)

它使用@EventListener(ApplicationReadyEvent.class)以避免循环依赖。

随时对其进行测试并提供有关此POC的反馈。


Pet*_*mer 3

使用 spring-boot-starter-webflux,有

  • 委托WebFlux配置
  • 语言环境上下文解析器

例如,要使用查询参数“lang”来显式控制区域设置:

  1. 实现LocaleContextResolver,以便 resolveLocaleContext()返回SimpleLocaleContext由“lang”的 GET 参数确定的值。我将这个实现命名为QueryParamLocaleContextResolver. 请注意,默认值LocaleContextResolverorg.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver.

  2. 创建一个@Configuration扩展的类DelegatingWebFluxConfiguration。覆盖DelegatingWebFluxConfiguration.localeContextResolver()以返回QueryParamLocaleContextResolver我们刚刚在步骤 1 中创建的配置。将此配置类命名为WebConfig

  3. 在 中WebConfig,覆盖BeanDelegatingWebFluxConfiguration.configureViewResolvers()并将其添加ThymeleafReactiveViewResolver为视图解析器。我们这样做是因为,由于某种原因,在第 2 步之后DelegatingWebFluxConfiguration将会错过ThymeleafReactiveViewResolver

另外,我必须提到,要将 i18n 与反应式堆栈一起使用,这个 bean 是必要的:

    @Bean
    public MessageSource messageSource() {
        final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasenames("classpath:/messages");
        messageSource.setUseCodeAsDefaultMessage(true);
        messageSource.setDefaultEncoding("UTF-8");
        messageSource.setCacheSeconds(5);
        return messageSource;
}
Run Code Online (Sandbox Code Playgroud)

创建自然模板、一些属性文件和控制器后,您将看到:

  • localhost:8080/test?lang=zh给你中文版

  • localhost:8080/test?lang=en给你英文版本

只是不要忘记<meta charset="UTF-8">in <head>,否则你可能会看到一些令人讨厌的汉字显示。