阅读量:0
直达电梯
项目背景
项目架构是通过网关模块(基于SpringCloud gateway)路由到业务接口模块(基于SpringBoot),没有独立的鉴权服务,“登录接口”集成在网关模块本身。
使用的框架版本如下:
- SpringBoot 2.7.5
- SpringCloud gateway 2021.0.9
提出问题
- SpringCloud Gateway是基于reactor模型的,按照SpringBoot那套以及所尝试网上以及AI的i18n国际化方案,都没有成功。
- 重点是我的网关模块自身提供了接口给前端调用,这些网关模块自身的接口的国际化有问题。
解决问题
基本思路跟SpringBoot项目的i18n一样
- 通过MessageSource加载messages国际化资源
- 通过基于WebFilter的过滤器从请求头获取Content-Language识别locale
- 需要国际化的地方通过MessageUtils.message()实现国际化
实现代码
项目结构
gateway src main java resources i18n messages.properties messages_en_US.properties test
配置文件(application.yml)
仅摘取跟i18n相关部分
spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages
代码
I18nGlobalFilter.java
import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; import java.util.Locale; /** * 国际化过滤器 * 根据浏览器请求头的里Content-Language实现国际化 * * @Description * @Author * @Date 2024/4/29 */ @Component public class I18nGlobalFilter implements WebFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { Locale locale = Locale.getDefault(); // 默认Locale HttpHeaders headers = exchange.getRequest().getHeaders(); String language = headers.getFirst("Content-Language"); if (language != null) { locale = Locale.forLanguageTag(language); } // 将Locale存储在ServerWebExchange的属性中,供后续逻辑使用 exchange.getAttributes().put(Locale.class.getName(), locale); // spring gateway手动处理,基于LocaleContextHolder LocaleContextHolder.setLocale(locale); return chain.filter(exchange); } }
MessageUtils.java
import com.siemens.tbds.gateway.util.SpringUtils; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; /** * 获取i18n资源文件 * * @Description * @Author * @Date 2024/4/29 */ public class MessageUtils { /** * 根据消息键和参数 获取消息 委托给spring messageSource * * @param code 消息键 * @param args 参数 * @return 获取国际化翻译值 */ public static String message(String code, Object... args) { MessageSource messageSource = SpringUtils.getBean(MessageSource.class); return messageSource.getMessage(code, args, LocaleContextHolder.getLocale()); } }
调用示例代码(仅调用片段)
return ApiResponse.error(MessageUtils.message("api.auth.username-password.error"));
messages.properties示例
api.auth.username-password.error=用户名或密码错误!
messages_en_US.properties示例
api.auth.username-password.error=username or password error.
接口调用测试结果
中文
英文
总结
- 要点1:
与常规SpringBoot的web项目不同之处在Filter,SpringBoot项目实现LocaleResolver接口即可(当然理论上跟SpringCloud gateway一样集成WebFilter也是可以的,因为WebFilter是spring-web里的接口); - 要点2
网上文章以及AI的回答均是通过实现SpringCloud gateway的GlobalFilter接口,我最终都没有成功,根据资料显示GloabalFilter是进入gateway的routes路由的接口才会触发;而我这里是网关模块自己有接口给前端调用,这个接口的国际化无法通过实现GlobalFilter实现。
附SpringBoot常规web项目的实现代码
仅I18nConfig.java替换上面的I18nGlobalFilter.java即可,其余MessageUtils.java、i18n资源文件、application.yml中i18n配置均与上面保持一致即可。
I18nConfig.java
import cn.hutool.core.util.StrUtil; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.LocaleResolver; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Locale; /** * 国际化配置 * * @author */ @Configuration public class I18nConfig { @Bean public LocaleResolver localeResolver() { return new I18nLocaleResolver(); } /** * 获取请求头国际化信息 */ static class I18nLocaleResolver implements LocaleResolver { @Override public Locale resolveLocale(HttpServletRequest httpServletRequest) { String language = httpServletRequest.getHeader("content-language"); Locale locale = Locale.getDefault(); if (StrUtil.isNotBlank(language)) { String[] split = language.split("-"); locale = new Locale(split[0], split[1]); } return locale; } @Override public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { } } }