无码人妻精品一区二区三18禁,影音先锋男人AV橹橹色,污污污污污污www网站免费,日韩成人av无码一区二区三区,欧美性受xxxx狂喷水

TDengine 資深研發整理:基于 SpringBoot 多語言實現 API 返回消息國際化

爾悅

2023-10-11 / ,

作為一款在 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{
 @Override
 public 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.java

public 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.java
    
    private 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.java

protected 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.java

public 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 的功能基礎上有更多加強,用戶可根據自身業務體量和需求進行版本選擇。