网关的国际化改造

网关的国际化改造和web服务的改造有所不同。

问题

SpringCloud Gateway是基于reactor模型的,按照SpringBoot那套以及所尝试网上以及AI的i18n国际化方案,都没有成功。

解决问题

基本思路跟SpringBoot项目的i18n一样

通过MessageSource加载messages国际化资源

通过基于WebFilter的过滤器从请求头获取Content-Language识别locale

需要国际化的地方通过MessageUtils.message()实现国际化

项目结构

配置文件(application.yml)

配置资源文件路径

复制代码
spring:
  messages:
    basename: messages,commons # 多个资源文件路径
    encoding: UTF-8         

配置i18n过滤器

复制代码
/**
 * 国际化过滤器
 *
 *
 * @Description
 * @Author
 * @Date 2024/4/29
 */
@Component
@Order(-1)
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("Accept-Language");
        if (language != null) {
            locale = Locale.forLanguageTag(language);
        }

        // 将Locale存储在ServerWebExchange的属性中,供后续逻辑使用
        exchange.getAttributes().put(Locale.class.getName(), locale);
        // spring gateway手动处理,基于LocaleContextHolder
        LocaleContextHolder.setLocale(locale);
        SystemEnum.SERVICE_TEMPORARILY_UNAVAILABLE.getMessage();

        return chain.filter(exchange);
    }
}

工具类

复制代码
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());
    }
}

要点1:

与常规SpringBoot的web项目不同之处在Filter,SpringBoot项目实现LocaleResolver接口即可(当然理论上跟SpringCloud gateway一样集成WebFilter也是可以的,因为WebFilter是spring-web里的接口);

要点2

网上文章以及AI的回答均是通过实现SpringCloud gateway的GlobalFilter接口,我最终都没有成功,根据资料显示GloabalFilter是进入gateway的routes路由的接口才会触发;(而我这里是网关模块自己有接口给前端调用,这个接口的国际化无法通过实现GlobalFilter实现。)

然而按照上述方法实现后将网关上到生产后却出现了问题。

问题

虽然在我本机上测试没有问题,但在Linux服务器上却出现了很多问题

问题1:

Locale.getDefault()在Linux的默认语言为en,在我本机上却是中文(zh-CN还是zh忘了)。

解决办法:

使用Locale.CHINA

问题2:

Locale.forLanguageTag(language);这个方法用于根据语言标签字符串创建一个 Locale 对象,但

浏览器传的值类似于

复制代码
zh-CN,zh;q=0.9,en;q=0.8

这个方法会尝试解析这个字符串,解析为zh,并不是权重最高的zh-CN

在我本机上虽然资源文件为zh-CN但依然 能够识别到,但在Linux环境下就不行了

解决方法:

复制代码
@Component
public class I18nGlobalFilter implements WebFilter,Ordered  {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        Locale locale = Locale.CHINA; // 默认Locale
        HttpHeaders headers = exchange.getRequest().getHeaders();
        // 浏览器传递的语言偏好值
        String language = headers.getFirst("Accept-Language");

        if (language != null) {
            // 解析语言偏好值
            List<Locale.LanguageRange> ranges = Locale.LanguageRange.parse(language);
            // 获取优先级最高的语言标签
            locale = Locale.forLanguageTag(ranges.get(0).getRange());
        }

        // 将Locale存储在ServerWebExchange的属性中,供后续逻辑使用
        exchange.getAttributes().put(Locale.class.getName(), locale);
        // spring gateway手动处理,基于LocaleContextHolder
        LocaleContextHolder.setLocale(locale);

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE+500;
    }
}
相关推荐
lybugproducer1 小时前
创建型设计模式之:简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式
java·设计模式·建造者模式·简单工厂模式·工厂方法模式·抽象工厂模式·面向对象
南客先生1 小时前
马架构的Netty、MQTT、CoAP面试之旅
java·mqtt·面试·netty·coap
Minyy111 小时前
SpringBoot程序的创建以及特点,配置文件,LogBack记录日志,配置过滤器、拦截器、全局异常
xml·java·spring boot·后端·spring·mybatis·logback
百锦再1 小时前
Java与Kotlin在Android开发中的全面对比分析
android·java·google·kotlin·app·效率·趋势
武昌库里写JAVA2 小时前
39.剖析无处不在的数据结构
java·vue.js·spring boot·课程设计·宠物管理
Nelson_hehe4 小时前
Java基础第四章、面向对象
java·语法基础·面向对象程序设计
Thomas_YXQ4 小时前
Unity3D Lua集成技术指南
java·开发语言·驱动开发·junit·全文检索·lua·unity3d
ShiinaMashirol5 小时前
代码随想录打卡|Day27(合并区间、单调递增的数字、监控二叉树)
java·算法
东阳马生架构7 小时前
Nacos简介—3.Nacos的配置简介
java
北极的企鹅887 小时前
XML内容解析成实体类
xml·java·开发语言