如何在 Spring boot 2 + Webflux + Thymeleaf 中配置 i18n?
Posted
技术标签:
【中文标题】如何在 Spring boot 2 + Webflux + Thymeleaf 中配置 i18n?【英文标题】:How to configure i18n in Spring boot 2 + Webflux + Thymeleaf? 【发布时间】:2018-05-11 16:04:38 【问题描述】:我刚开始一个基于 Spring boot 2 + Webflux 的新项目。在升级版本的 spring boot 并将spring-boot-starter-web
替换为spring-boot-starter-webflux
类,如
不见了。现在如何配置 defaultLocale 和拦截器来更改语言?
【问题讨论】:
使用 LocaleContextResolver 检查docs.spring.io/spring/docs/current/spring-framework-reference/…。 能否提供WebMvcConfigurerAdapter、LocaleResolver、LocaleChangeInterceptor的内容?你是否为了你的目的扩展了这个类? @virsha 再次阅读了我的问题。我没有这个实体。它们是我使用的 mvc 依赖项的一部分 webflux Spring webflux 有一个用于 webflux 配置的 webflux 配置器适配器,例如。参见here,与WebMvcConfigurerAdapter
类似,您可以找到WebFluxConfigurer
中提供的所有可选配置。
希望对您有所帮助link
【参考方案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配置 LocaleContextResolver例如,使用查询参数“lang”来显式控制语言环境:
实现LocaleContextResolver
,这样
resolveLocaleContext()
返回由“lang”的 GET 参数确定的 SimpleLocaleContext
。我将此实现命名为QueryParamLocaleContextResolver
。请注意,默认的LocaleContextResolver
是org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver
。
创建一个扩展DelegatingWebFluxConfiguration
的@Configuration
类。覆盖DelegatingWebFluxConfiguration.localeContextResolver()
以返回我们刚刚在步骤1 中创建的QueryParamLocaleContextResolver
。将此配置类命名为WebConfig
。
在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
给你英文版
请不要忘记<head>
中的<meta charset="UTF-8">
,否则您可能会看到一些令人讨厌的汉字显示。
【讨论】:
【参考方案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。
【讨论】:
以上是关于如何在 Spring boot 2 + Webflux + Thymeleaf 中配置 i18n?的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 2.0:Spring Boot 如何解决项目启动时初始化资源
Spring Boot 2.0:Spring Boot 如何解决项目启动时初始化资源
如何在 Spring Boot 2.2.6 中提供静态内容?