How to configure i18n in Spring boot 2 + Webflux + Thymeleaf?

后端 未结 3 1830
清酒与你
清酒与你 2021-02-19 11:10

I just start a new project based on Spring boot 2 + Webflux. On upgrading version of spring boot and replace spring-boot-starter-web with spring-boot-starter-

相关标签:
3条回答
  • 2021-02-19 11:27

    Another solution with spring boot starter web flux, which is much more cleaner, is to define your own HttpHandler using WebHttpHandlerBuilder in which you can set your LocaleContextResolver.

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

    Then in a config file (annotated with @Configuration) or in your spring boot application file, defined your own 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();
    
        }
    
    }
    

    That's it!

    0 讨论(0)
  • 2021-02-19 11:28

    With spring-boot-starter-webflux, there are

    • DelegatingWebFluxConfiguration
    • LocaleContextResolver

    For example, to use a query parameter "lang" to explicitly control the locale:

    1. Implement LocaleContextResolver, so that resolveLocaleContext() returns a SimpleLocaleContext determined by a GET parameter of "lang". I name this implementation QueryParamLocaleContextResolver. Note that the default LocaleContextResolver is an org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver.

    2. Create a @Configuration class that extends DelegatingWebFluxConfiguration. Override DelegatingWebFluxConfiguration.localeContextResolver() to return QueryParamLocaleContextResolver that we just created in step 1. Name this configuration class WebConfig.

    3. In WebConfig, override DelegatingWebFluxConfiguration.configureViewResolvers() and add the ThymeleafReactiveViewResolver bean as a view resolver. We do this because, for some reason, DelegatingWebFluxConfiguration will miss ThymeleafReactiveViewResolver after step 2.

    Also, I have to mention that, to use i18n with the reactive stack, this bean is necessary:

        @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;
    }
    

    After creating a natural template, some properties files, and a controller, you will see that:

    • localhost:8080/test?lang=zh gives you the Chinese version

    • localhost:8080/test?lang=en gives you the English version

    Just don't forget <meta charset="UTF-8"> in <head>, otherwise you may see some nasty display of Chinese characters.

    0 讨论(0)
  • 2021-02-19 11:33

    Just add a WebFilter that sets the Accept-Language header from the value of a query parameter. The following example gets the language from the language query parameter on URIs like 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());
        }
    }
    

    It uses @EventListener(ApplicationReadyEvent.class) in order to avoid cyclic dependencies.

    Feel free to test it and provide feedback on this POC.

    0 讨论(0)
提交回复
热议问题