当前位置: 首页 > news >正文

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上查看相关源代码。

相关文章:

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

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

数据结构-冒泡排序Java实现

目录 一、引言二、算法步骤三、原理演示四、代码实战五、结论 一、引言 冒泡排序是一种基础的比较排序算法&#xff0c;它的思想很简单&#xff1a;重复地遍历待排序的元素列表&#xff0c;比较相邻元素&#xff0c;如果它们的顺序不正确&#xff0c;则交换它们。这个过程不断重…...

完整教程:Java+Vue+Websocket实现OSS文件上传进度条功能

引言 文件上传是Web应用开发中常见的需求之一&#xff0c;而实时显示文件上传的进度条可以提升用户体验。本教程将介绍如何使用Java后端和Vue前端实现文件上传进度条功能&#xff0c;借助阿里云的OSS服务进行文件上传。 技术栈 后端&#xff1a;Java、Spring Boot 、WebSock…...

【微服务 SpringCloud】实用篇 · 服务拆分和远程调用

微服务&#xff08;2&#xff09; 文章目录 微服务&#xff08;2&#xff09;1. 服务拆分原则2. 服务拆分示例1.2.1 导入demo工程1.2.2 导入Sql语句 3. 实现远程调用案例1.3.1 案例需求&#xff1a;1.3.2 注册RestTemplate1.3.3 实现远程调用1.3.4 查看效果 4. 提供者与消费者 …...

Linux 下I/O操作

一、文件IO 文件 IO 是 Linux 系统提供的接口&#xff0c;针对文件和磁盘进行操作&#xff0c;不带缓存机制&#xff1b;标准IO是C 语言函数库里的标准 I/O 模型&#xff0c;在 stdio.h 中定义&#xff0c;通过缓冲区操作文件&#xff0c;带缓存机制。   标准 IO 和文件 IO 常…...

C#内映射lua表

都是通过同一个方法得到的 例如得到List List<int> list LuaMgr.GetInstance().Global.Get<List<int>>("testList"); 只要把Get的泛型换成对应的类型即可 得到Dictionnary Dictionary<string, int> dic2 LuaMgr.GetInstance().Global…...

android studio检测不到真机

我的情况是&#xff1a; 以前能检测到&#xff0c;有一天我使用无线调试&#xff0c;发现调试有问题&#xff0c;想改为USB调试&#xff0c;但是半天没反应&#xff0c;我就点了手机上的撤销USB调试授权&#xff0c;然后就G了。 解决办法&#xff1a; 我这个情况比较简单&…...

【Eclipse】设置自动提示

前言&#xff1a; eclipse默认有个快捷键&#xff1a;alt /就可以弹出自动提示&#xff0c;但是这样也太麻烦啦&#xff01;每次都需要手动按这个快捷键&#xff0c;下面给大家介绍的是&#xff1a;如何设置敲的过程中就会出现自动提示的教程&#xff01; 先按路线找到需要的页…...

单片机TDL的功能、应用与技术特点 | 百能云芯

在现代电子领域中&#xff0c;单片机&#xff08;Microcontroller&#xff09;是一种至关重要的电子元件&#xff0c;广泛应用于各种应用中。TDL&#xff08;Time Division Multiplexing&#xff0c;时分多路复用&#xff09;是一种数据传输技术&#xff0c;结合单片机的应用&a…...

解决笔记本无线网络5G比2.4还慢的奇怪问题

环境&#xff1a;笔记本Dell XPS15 9570&#xff0c;内置无线网卡Killer Wireless-n/a/ac 1535 Wireless Network Adapter&#xff0c;系统win10家庭版&#xff0c;路由器H3C Magic R2Pro千兆版 因为笔记本用的不多&#xff0c;一直没怎么注意网络速度&#xff0c;直到最近因为…...

GitHub Action 通过SSH 自动部署到云服务器上

准备 正式开始之前&#xff0c;你需要掌握 GitHub Action 的基础语法&#xff1a; workflow &#xff08;工作流程&#xff09;&#xff1a;持续集成一次运行的过程&#xff0c;就是一个 workflow。name: 工作流的名称。on: 指定次工作流的触发器。push 表示只要有人将更改推…...

【AOP系列】7.数据校验

在Java中&#xff0c;我们可以使用Spring AOP&#xff08;面向切面编程&#xff09;和自定义注解来做数据校验。以下是一个简单的示例&#xff1a; 首先&#xff0c;我们创建一个自定义注解&#xff0c;用于标记需要进行数据校验的方法&#xff1a; import java.lang.annotat…...

黑马JVM总结(三十七)

&#xff08;1&#xff09;synchronized-轻量级锁-无竞争 &#xff08;2&#xff09;synchronized-轻量级锁-锁膨胀 重量级锁就是我们前面介绍过的Monitor enter &#xff08;3&#xff09;synchronized-重量级锁-自旋 &#xff08;4&#xff09;synchronized-偏向锁 轻量级锁…...

企业如何通过媒体宣传扩大自身影响力

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 企业可以通过媒体宣传来扩大自身的影响力。可以通过以下的方法。 1. 制定媒体宣传战略&#xff1a; - 首先&#xff0c;制定一份清晰的媒体宣传战略&#xff0c;明确您的宣传目标、目标…...

处理vue直接引入图片地址时显示不出来的问题 src=“[object Module]“

在webpack中使用vue-loader编译template之后&#xff0c;发现图片加载不出来了&#xff0c;开发人员工具中显示src“[object Module]” 这是因为当vue-loader编译template块之后&#xff0c;会将所有的资源url转换为webpack模块请求 这是因为vue使用的是commonjs语法规范&…...

vue3 v-md-editor markdown编辑器(VMdEditor)和预览组件(VMdPreview )的使用

vue3 v-md-editor markdown编辑器和预览组件的使用 概述安装支持vue3版本使用1.使用markdown编辑器 VMdEditor2.markdown文本格式前端渲染 VMdPreview 例子效果代码部分 完整代码 概述 v-md-editor 是基于 Vue 开发的 markdown 编辑器组件 轻量版编辑器 轻量版编辑器左侧编辑…...

java正则表达式 及应用场景爬虫,捕获分组非捕获分组

正则表达式 通常用于校验 比如说qq号 看输入的是否符合规则就可以用这个 public class regex {public static void main(String[] args) {//正则表达式判断qq号是否正确//规则 6位及20位以内 0不能再开头 必须全是数子String qq"1234567890";System.out.println(qq…...

基于 Debian 稳定分支发行版的Zephix 7 发布

Zephix 是一个基于 Debian 稳定版的实时 Linux 操作系统。它可以完全从可移动媒介上运行&#xff0c;而不触及用户系统磁盘上存储的任何文件。 Zephix 是一个基于 Debian 稳定版的实时 Linux 操作系统。它可以完全从可移动媒介上运行&#xff0c;而不触及用户系统磁盘上存储的…...

MBR20100CT-ASEMI肖特基MBR20100CT参数、规格、尺寸

编辑&#xff1a;ll MBR20100CT-ASEMI肖特基MBR20100CT参数、规格、尺寸 型号&#xff1a;MBR20100CT 品牌&#xff1a;ASEMI 芯片个数&#xff1a;2 封装&#xff1a;TO-220 恢复时间&#xff1a;&#xff1e;50ns 工作温度&#xff1a;-65C~175C 浪涌电流&#xff1a…...

修炼k8s+flink+hdfs+dlink(五:安装dockers,cri-docker,harbor仓库)

一&#xff1a;安装docker。&#xff08;所有服务器都要安装&#xff09; 安装必要的一些系统工具 sudo yum install -y yum-utils device-mapper-persistent-data lvm2添加软件源信息 sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/cent…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...