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

时间:2017-11-28 08:59:47

标签: spring-boot thymeleaf spring-webflux

我刚刚开始一个基于Spring boot 2 + Webflux的新项目。在升级spring boot版本时,将spring-boot-starter-web替换为spring-boot-starter-webflux类,如

  • WebMvcConfigurerAdapter
  • LocaleResolver
  • LocaleChangeInterceptor

缺少。我现在怎样才能配置defaultLocale和拦截器来改变语言?

3 个答案:

答案 0 :(得分:4)

只需添加WebFilter即可从查询参数的值设置Accept-Language标头。以下示例从http://localhost:8080/examples?language=es等URI上的语言查询参数中获取语言:

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());
    }
}

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

随意测试并提供有关此POC的反馈。

答案 1 :(得分:2)

使用spring-boot-starter-webflux,有

  • DelegatingWebFluxConfiguration
  • LocaleContextResolver

例如,要使用查询参数“lang”显式控制语言,您可以执行以下操作:

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

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

  3. 在WebConfig中,覆盖DelegatingWebFluxConfiguration.configureViewResolvers()并将ThymeleafReactiveViewResolver bean添加为视图解析器。我们这样做是因为,出于某种原因,DelegatingWebFluxConfiguration将在第2步之后错过ThymeleafReactiveViewResolver。我们只需修复它。

  4. 另外,我必须提一下,要将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;
    }
    

    创建自然模板,一些属性文件和控制器后,您应该实现:

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

    localhost:8080 / test?lang = zh-CN为您提供英文版

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

答案 2 :(得分:0)

使用Spring Boot Starter Web磁通的另一种解决方案更加简洁,它是使用HttpHandler定义自己的WebHttpHandlerBuilder,您可以在其中设置LocaleContextResolver

文档(请参阅1.2.2 WebHandler API):https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-config-customize

MyLocaleContextResolver.java

public class MyLocaleContextResolver implements LocaleContextResolver {


    @Override
    public LocaleContext resolveLocaleContext(ServerWebExchange exchange) {      
        return new SimpleLocaleContext(Locale.FRENCH);        
    }

    @Override
    public void setLocaleContext(ServerWebExchange exchange, LocaleContext localeContext) {
        throw new UnsupportedOperationException();
    }
}

然后在配置文件(带有@Configuration注释)或您的spring boot应用程序文件中,定义您自己的HttpHandler bean。

Application.java

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public HttpHandler httpHandler(ApplicationContext context) {

        MyLocaleContextResolver localeContextResolver = new MyLocaleContextResolver();

        return WebHttpHandlerBuilder.applicationContext(context)
                .localeContextResolver(localeContextResolver) // set your own locale resolver
                .build();

    }

}

就是这样!