TDengine 资深研发整理:基于 SpringBoot 多语言实现 API 返回消息国际化

作为一款在 Java 开发社区中广受欢迎的技术框架,SpringBoot 在开发者和企业的具体实践中应用广泛。具体来说,它是一个用于构建基于 Java 的 Web 应用程序和微服务的框架,通过简化开发流程、提供约定大于配置的原则以及集成大量常用库和组件,SpringBoot 能够帮助开发者更快速、更高效地构建应用程序。

为了帮助开发者更好地进行 SpringBoot 的开发,避免开发盲点,我们将 TDengine 资深研发所做的内部分享——《SpringBoot 多语言支持方案》进行了相关整理,给到有需要的开发者参考。

添加依赖

首先,SpringBoot 作为一个强大的 Java 开发脚手架工具框架,已经提供了多语言定义、解析底层工具,我们只需要在项目依赖中引入 spring-boot-starter 和 spring-boot-autoconfigure 两个包。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId>
</dependency>

分析 spring-boot-autoconfigure 的源码我们可以看到,在 MessageSourceAutoConfiguration 类中,默认已经自动装配了 MessageSource 对象。

TDengine 资深研发整理:基于 SpringBoot 多语言实现 API 返回消息国际化 - TDengine Database 时序数据库

添加多语言 message 配置文件

在 IDEA 中我们只需要在 resources 资源包上右键:新建–>资源包,在弹出窗口填写资源包名如:messages 选择区域设置,默认的有 en、zh_CN、zh_TC 选项。

TDengine 资深研发整理:基于 SpringBoot 多语言实现 API 返回消息国际化 - TDengine Database 时序数据库

添加完即可在 resources 包内看到绑定的多语言文件。

TDengine 资深研发整理:基于 SpringBoot 多语言实现 API 返回消息国际化 - TDengine Database 时序数据库

注意:在配置文件里查看编辑中文,需要在 IDEA 中修改 message 配置文件。

TDengine 资深研发整理:基于 SpringBoot 多语言实现 API 返回消息国际化 - TDengine Database 时序数据库

在配置文件中我们添加 message ,格式为:{code}={message}
METHOD_NOT_ALLOWED=Http method is not supported!
INTERFACE_NOT_FOUND=Interface does not exist!
UNSUPPORTED_MEDIA_TYPE=Not supported MediaType!
ILLEGAL_REQUEST=Illegal request!
SERVICE_UNAVAILABLE=Server resources are unavailable!
SERVER_ERROR=Sorry, an internal server error occurred, please try again later.
INTERNAL_SERVER_ERROR=Internal Server Error.field.validity.check.failed=Field validity check failed!
bill.account.not-found=bill account not found!
grant.role-group.failed=grant role to group failed!
grant.role-user.failed=grant role to user failed!
add.user-group.failed=add user to group failed!
del.user-group.failed=delete user from group failed!
create.org.failed=create organization failed!
cannot.visit.org=you cannot visit this organization!
wrong.value.parameter=wrong value for parameter!
role.not-found=role not found!
role.update.failed=update role failed!
role.delete.failed=can not delete role!
account.in.arrears=The account is in arrears. Please recharge and try again!
如何使用公共 jar 包内 i18n 资源文件
  • 创建公共资源包 i18n 目录:在 commons 包里添加一个文件夹 i18n-base,这里可以通过一个文件夹避免资源包的覆盖。

TDengine 资深研发整理:基于 SpringBoot 多语言实现 API 返回消息国际化 - TDengine Database 时序数据库

  • 依赖 commons 包的模块,在 yaml 配置文件中添加路径。
spring:messages:basename: i18n-base/messages,messages

以上,我们的多语言框架支持配置、初始化已经完成,接下来就是如何在业务中使用了。

在模块中使用多语言消息

首先我们来看一个典型的 API 服务请求响应流程。客户端发出一个接口请求,会经过多个过滤器进行身份认证、API 接口鉴权认证、权限识别,验证通过后即可进入业务逻辑,最后通过接口返回。返回结果有两种:

  • 过滤器认证失败直接返回包装结果 BaseApiResponse
  • 认证通过进入业务逻辑,这里又包含两种情况:
    • 业务异常,统一通过 GlobalExceptionHandler 拦截,最后由 ResponseAdvice 处理最终返回结果;
    • 无异常,返回业务数据由 ResponseAdvice 处理最终返回结果。

一般来说,外层可以通过 ErrorHandler 捕获整个流程的异常,包括拦截器、框架层的调用出现的异常,最终由 ResponseAdvice 统一处理并最终返回结果。

整个流程如下图:

TDengine 资深研发整理:基于 SpringBoot 多语言实现 API 返回消息国际化 - TDengine Database 时序数据库

基于这个业务处理流程我们来封装异常信息国际化的逻辑,如下:

定义多语言 message 获取 LocaleMessageProvider
  • 定义接口
public interface LocaleMessageProvider {String get(String msgCode, Object... args);}
  • 配置实现类
@Bean
public LocaleMessageProvider localeMessageProvider(MessageSource messageSource){return (msgCode, args) -> {Locale locale = LocaleContextHolder.getLocale();return messageSource.getMessage(msgCode,args,locale);};
}
  • 在返回结构体中使用 LocaleMessageProvider 获取 message;在 ResponseBodyAdvice 可以为每个 Response 对象设置 messageProvider。
BaseApiResponse.class
private LocaleMessageProvider messageProvider;public String getmsg() {String localeMsg = msg;if (messageProvider != null){if (StringUtils.hasText(this.msgCode)){try {localeMsg = messageProvider.get(this.msgCode, getArgs());} catch (Exception e) {if (!StringUtils.hasText(localeMsg)){localeMsg = this.msgCode;}}if (!StringUtils.hasText(localeMsg)){localeMsg = StringUtils.hasText(this.msgCode) ? this.msgCode : localeMsg;}return  localeMsg;
}public class ResponseAdvice implements ResponseBodyAdvice{@Overridepublic Object beforeBodyWrite(Object body, @NotNull MethodParameter returnType,@NotNull MediaType selectedContentType, @NotNull Class selectedConverterType,@NotNull ServerHttpRequest request,@NotNull ServerHttpResponse response) {int code = ServiceInfoEnum.valueOf(key).getServiceCode() * 1000 + 200;if (body instanceof BaseApiResponse) {BaseApiResponse res = (BaseApiResponse) body;res.setMessageProvider(messageProvider);}
}
}

在这里提出一个问题,SpringBoot 框架是如何处理语言设置的?在我们定义的 LocaleMessageProvider 里可以使用 LocaleContextHolder.getLocale() 来获取 Locale。

接下来我们继续遵循 LocaleContextHolder 的方法,可以先尝试从内部 localeContext 对象进行获取,获取不到的话则取 Locale 的缺省值。

org.springframework.context.i18n.LocaleContextHolder.javapublic static Locale getLocale() {return getLocale(getLocaleContext());
}public static Locale getLocale(@Nullable LocaleContext localeContext) {if (localeContext != null) {Locale locale = localeContext.getLocale();if (locale != null) {return locale;}}return (defaultLocale != null ? defaultLocale : Locale.getDefault());
}

在 Locale 类中,我们看到缺省的 locale 最终从系统变量 user.language 获取,缺省是 en。

    java.util.Locale.javaprivate static volatile Locale defaultLocale = initDefault();private static Locale initDefault() {String language, region, script, country, variant;Properties props = GetPropertyAction.privilegedGetProperties();language = props.getProperty("user.language", "en");......//省略代码
}

接下来我们看下 LocaleContextHolder 中的 Locale 是何时设置的,实际就是在 request 请求过滤器基类 RequestContextFilter 里,通过 request.getLocale() 获取到 request 的 locale,然后使用 LocaleContextHolder 设置到 LocaleContext 中。

RequestContextFilter.javaprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {ServletRequestAttributes attributes = new ServletRequestAttributes(request, response);initContextHolders(request, attributes);......//省略代码
}
private void initContextHolders(HttpServletRequest request, ServletRequestAttributes requestAttributes) {LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable);......//省略代码
}

最终我们看到在 Request 对象里,成功获取了“accept-lunguage” 请求。

org.apache.catalina.connector.Request.javapublic Locale getLocale() {if (!localesParsed) {parseLocales();}if (locales.size() > 0) {return locales.get(0);}return defaultLocale;
}protected void parseLocales() {......//省略代码TreeMap<Double, ArrayList<Locale>> locales = new TreeMap<>();Enumeration<String> values = getHeaders("accept-language");while (values.hasMoreElements()) {String value = values.nextElement();parseLocalesHeader(value, locales);}for (ArrayList<Locale> list : locales.values()) {for (Locale locale : list) {addLocale(locale);}}
}
添加一个多语言消息
  1. 如果是异常消息,定义异常消息编码在代码中 exception 需使用 msgCode,如果是业务包装类型,那 BaseApiResponse 消息也要使用 msgCode
  2. 在 message 配置文件中添加对应的 {code}={message}

至此,我们的异常国际化配置就完成了,在客户端我们只需要在请求里添加一个 header:Accept-Language=zh-CN,就可以验证返回的结果。例如登录出错客户端接收到的信息为:

{"code": 500,"message": "用户名或者密码错误,请重新输入。","data":{}
}

结语

以上就是基于 SpringBoot 多语言支持方案的完整分享内容,现在你可以操作体验了,希望本篇文章能带给你一些帮助。更多示例可参考:

  • 异常中使用 messageCode
if (pricePlan.getClusterNum() >= 0 && appNum >= pricePlan.getClusterNum()) {throw new CommonsException(HttpResponseStatus.PAYMENT_REQUIRED.code(),"price.plan.limit.instance.number","instance number is over limit!");
}
  • 国际化文件中添加 message
#messages_en.properties
price.plan.limit.instance.number=instance number is over limit
#messages_zh_CN.properties
price.plan.limit.instance.number=实例数量超过限制

如果你在实操过程中还遇到了其他技术问题,或者正面临着时序数据的处理难题,也可以添加小T vx:tdengine,和 TDengine 的技术研发人员进行直接沟通。

关于 TDengine

TDengine 核心是一款高性能、集群开源、云原生的时序数据库(Time Series Database,TSDB),专为物联网、工业互联网、电力、IT 运维等场景设计并优化,具有极强的弹性伸缩能力。同时它还带有内建的缓存、流式计算、数据订阅等系统功能,能大幅减少系统设计的复杂度,降低研发和运营成本,是一个高性能、分布式的物联网、工业大数据平台。当前 TDengine 主要提供两大版本,分别是支持私有化部署的 TDengine Enterprise 以及全托管的物联网、工业互联网云服务平台 TDengine Cloud,两者在开源时序数据库 TDengine OSS 的功能基础上有更多加强,用户可根据自身业务体量和需求进行版本选择。


了解更多 TDengine Database的具体细节,可在GitHub上查看相关源代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/140000.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【OpenVINO】OpenVINO C# API 常用 API 详解与演示

OpenVINO C# API 常用 API 详解与演示 1 安装OpenVINO C# API2 导入程序集 3 初始化OpenVINO 运行时内核4 加载并获取模型信息4.1 加载模型4.2 获取模型信息 5 编译模型并创建推理请求6 张量Tensor6.1 张量的获取与设置6.2 张量的信息获取与设置 7 加载推理数据7.1 获取输入张量…

ChatGPT在测试计划中的应用策略

简介 测试计划是指描述了要进行的测试活动的范围、方法、资源和进度的文档。它主要包括测试项、被测特性、测试任务和风险控制等。 所以在使用ChatGPT输出结果之前&#xff0c;我们需要先将文档的内容框架梳理好&#xff0c;以及将内容范围划定好&#xff0c;必要的时候&#x…

【Hello Algorithm】暴力递归到动态规划(三)

暴力递归到动态规划&#xff08;三&#xff09; 最长公共子序列递归版本动态规划 最长回文串子序列方法一方法二递归版本动态规划 象棋问题递归版本动态规划 咖啡机问题递归版本动态规划 最长公共子序列 这是leetcode上的一道原题 题目连接如下 最长公共子序列 题目描述如下…

【Golang】grpc环境踩的坑

关于’protoc-gen-go’ 不是内部或外部命令 这个问题的出现是因为没有这个文件导致的 这个文件要通过我们下载的google.golang.org这个文件编译生成的 这里建议下载google提供的grpc包 protobuf的源码&#xff1a; git clone https://github.com/golang/protobuf 下载好之后进…

MATLAB——RBF、GRNN和PNN神经网络案例参考程序

欢迎关注“电击小子程高兴的MATLAB小屋” GRNN_PNN程序 %% I. 清空环境变量 clear all clc %% II. 训练集/测试集产生 %% % 1. 导入数据 load iris_data.mat %% % 2 随机产生训练集和测试集 P_train []; T_train []; P_test []; T_test []; for i 1:3 temp_input …

Spring框架

文章目录 Spring 框架1 概述2 IOC3 Bean管理3.1 XML配置方式3.2 Java注解方式3.3 Java代码方式3.4 对象之间调用示例3.5 自动装配 4 单例和多例4.1 单例&#xff08;Singleton&#xff09;4.2 多例&#xff08;Prototype&#xff09; 5 生命周期6 注解管理Bean6.1 Component、S…

【数据可视化】—大屏数据可视化展示

【数据可视化】—大屏数据可视化展示 一、数据可视化 数据可视化的目的&#xff1a;借助于图形化工具&#xff0c;清晰有效的传达与沟通信息。 数据可视化可以把数据从冰冷的数字转换成图形&#xff0c;揭示蕴含在数据中的规律和道理。 二、 免费数据可视化库 Echarts 百度…

stable-diffusion-webui sdxl模型代码分析

采样器这块基本都是用的k-diffusion&#xff0c;模型用的是stability的原生项目generative-models中的sgm&#xff0c;这点和fooocus不同&#xff0c;fooocus底层依赖comfyui中的models&#xff0c;comfy是用load_state_dict的方式解析的&#xff0c;用的load_checkpoint_guess…

【从零开始学习Redis | 第三篇】在Java中操作Redis

前言&#xff1a; 本文算是一期番外&#xff0c;介绍一下如何在Java中使用Reids &#xff0c;而其实基于Java我们有很多的开源框架可以用来操作redis&#xff0c;而我们今天选择介绍的是其中比较常用的一款&#xff1a;Spring Data Redis 目录 前言&#xff1a; Spring Data…

萝卜刀真的太危险了,于是我用Cocos做了一个

点击上方亿元程序员关注和★星标 引言 大家好&#xff0c;我是亿元程序员&#xff0c;一位有着8年游戏行业经验的主程。 昨天&#xff0c;我女儿和我说想买一把萝卜刀&#xff0c;众所周知&#xff0c;萝卜刀在潜意识当中是存在一定的危险的&#xff0c;所以我果断拒绝了&…

安防视频监控EasyCVR视频汇聚平台与萤石云平台的适配方案分析

随着科技的不断发展&#xff0c;互联网技术逐渐深入到我们生活的各个领域。其中&#xff0c;安防监控领域受益于互联网技术的发展&#xff0c;逐渐呈现出智能化、高清化、远程化的趋势。本文将介绍一种基于萤石云与EasyCVR平台的安防视频监控解决方案&#xff0c;以满足用户对安…

MTK6877/MT6877天玑900安卓5G核心板_安卓开发板主板定制开发

2021年5月13日&#xff0c;MediaTek 宣布发布旗下的天玑900系列芯片&#xff0c;又名MT6877。天玑900基于6nm先进工艺制造&#xff0c;搭载硬件级4K HDR视频录制引擎&#xff0c;支持1.08亿像素摄像头、5G双全网通和Wi-Fi 6连接、旗舰级存储规格和120Hz的FHD超高清分辨率显示&a…