【问题标题】:How to configure i18n in Spring boot 2 + Webflux + Thymeleaf?如何在 Spring boot 2 + Webflux + Thymeleaf 中配置 i18n?
【发布时间】:2018-05-11 16:04:38
【问题描述】:

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

  • WebMvcConfigurerAdapter
  • 语言环境解析器
  • 语言环境更改拦截器

不见了。现在如何配置 defaultLocale 和拦截器来更改语言?

【问题讨论】:

  • 能否提供WebMvcConfigurerAdapter、LocaleResolver、LocaleChangeInterceptor的内容?你是否为了你的目的扩展了这个类?
  • @virsha 再次阅读了我的问题。我没有这个实体。它们是我使用的 mvc 依赖项的一部分 webflux
  • Spring webflux 有一个用于 webflux 配置的 webflux 配置器适配器,例如。参见here,与WebMvcConfigurerAdapter类似,您可以找到WebFluxConfigurer 中提供的所有可选配置。
  • 希望对您有所帮助link

标签: spring-boot thymeleaf spring-webflux


【解决方案1】:

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

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 的反馈。

【讨论】:

  • 这个答案被低估了。感谢您的出色实施!
【解决方案2】:

用spring-boot-starter-webflux,有

  • 委派WebFlux配置
  • Lo​​caleContextResolver

例如,使用查询参数“lang”来显式控制语言环境:

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

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

  3. WebConfig 中,覆盖DelegatingWebFluxConfiguration.configureViewResolvers() 并添加ThymeleafReactiveViewResolver bean 作为视图解析器。我们这样做是因为,出于某种原因,DelegatingWebFluxConfiguration 在第 2 步之后会错过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;
}

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

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

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

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

【讨论】:

    【解决方案3】:

    另一个使用 spring boot starter web Flux 的解决方案更简洁,是使用 WebHttpHandlerBuilder 定义您自己的 HttpHandler,您可以在其中设置您的 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();
    
        }
    
    }
    

    就是这样!

    【讨论】:

      【解决方案4】:

      从 Spring Boot 2.4.0 开始,WebFluxAutoConfiguration 包含 LocaleContextResolver 的 bean 定义,它允许我们注入自定义 LocaleContextResolver。供参考,以下是 Spring Boot 2.5.4 中默认的 bean 定义(早期版本的实现可能不同):

      @Bean
      @Override
      @ConditionalOnMissingBean(name = WebHttpHandlerBuilder.LOCALE_CONTEXT_RESOLVER_BEAN_NAME)
      public LocaleContextResolver localeContextResolver() {
          if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {
              return new FixedLocaleContextResolver(this.webProperties.getLocale());
          }
          AcceptHeaderLocaleContextResolver localeContextResolver = new AcceptHeaderLocaleContextResolver();
          localeContextResolver.setDefaultLocale(this.webProperties.getLocale());
          return localeContextResolver;
      }
      

      您可以提供自己的 LocaleContextResolver 实现,通过提供自定义 bean 定义从查询参数中获取语言环境:

      //@Component("localeContextResolver")
      @Component(WebHttpHandlerBuilder.LOCALE_CONTEXT_RESOLVER_BEAN_NAME)
      public class RequestParamLocaleContextResolver implements LocaleContextResolver {
          @Override
          public LocaleContext resolveLocaleContext(ServerWebExchange exchange) {
              List<String> lang = exchange.getRequest().getQueryParams().get("lang");
              Locale targetLocale = null;
              if (lang != null && !lang.isEmpty()) {
                  targetLocale = Locale.forLanguageTag(lang.get(0));
              }
              if (targetLocale == null) {
                  targetLocale = Locale.getDefault();
              }
              return new SimpleLocaleContext(targetLocale);
          }
      
          @Override
          public void setLocaleContext(ServerWebExchange exchange, LocaleContext localeContext) {
              throw new UnsupportedOperationException(
                  "Cannot change lang query parameter - use a different locale context resolution strategy");
          }
      }
      

      请注意,框架使用具有特定名称 localeContextResolver (WebHttpHandlerBuilder.LOCALE_CONTEXT_RESOLVER_BEAN_NAME) 的 LocaleContextResolver。您需要为 bean 提供给定的名称。见#24209

      【讨论】:

        猜你喜欢
        • 2016-07-31
        • 2018-09-24
        • 2018-06-21
        • 2018-03-16
        • 2021-03-26
        • 2018-08-09
        • 2020-12-12
        • 2021-05-10
        • 2016-09-05
        相关资源
        最近更新 更多