1. 程式人生 > >基於springboot實現http響應異常資訊國際化

基於springboot實現http響應異常資訊國際化

背景

國際化是指在設計軟體,將軟體與特定語言及地區脫鉤的過程。當軟體被移植到不同的語言及地區時,軟體本身不用做內部工程上的改變或修正。

本文提到的異常響應資訊國際化是指:前端向後臺發起請求,後臺在處理邏輯中發生異常,把異常資訊返回給前端,返回的異常資訊應該支援國際化,能夠對應特定的語言、地區等環境。例如,中文語言環境下返回的異常資訊應該是中文的,英文語言環境下返回的則是對應的英文。

javaweb專案中,不管是對底層的資料操作,還是業務層的處理過程,還是控制層的處理,都不可避免的會遇到各種可預知的(業務異常主動丟擲)、不可預知的異常需要處理。一般dao層、service層的異常都會直接丟擲,最後由controller統一進行處理,並對前端請求進行異常響應。針對此處的業務異常應該做到設計合理,統一格式,並且支援國際化。

springboot是一個開源的Java/Java EE的應用程式框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。利用springboot提供的API庫,我們能方便地做到全域性異常統一攔截,並且Spring提供了完善的國際化支援,在此基礎上,我們能方便地做到全域性異常資訊的國際化。

原來存在的方案:

  1. 區域性的異常資訊國際化:程式在丟擲異常時手動設定好國際化之後的異常message。

    此種方案程式碼耦合性強,程式碼繁瑣,處理邏輯過程中丟擲異常時還得額外考慮對異常進行國際化操作,使得程式碼邏輯無法很好的集中在業務邏輯的處理。示意圖如圖1.1。

  2. 半異常資訊國際化:程式中未採用配置檔案來記錄國際化資源,而是直接在程式中寫死了固定的異常值,每條異常值記錄分別對應著不同的異常編號、某幾種語言的異常資訊。

    這是目前比較常見的方式,寫起來方便,不需要在程式丟擲異常時做國際化,只需在全域性異常攔截中做統一的異常返回。但是,這種方式支援的異常資訊比較單一,不能輕易新增多種語言的支援,只能改動現有程式的程式碼。示意圖如圖1.2。

  3. 使用程式語言自帶的異常本地化介面。

    不少後臺語言提供了異常資訊本地化介面,比如java提供的java.lang.Throwable#getLocalizedMessage方法,但是這種方式只能獲取到本地語言相關的對應的資訊,並不能很好的支援多種語言,以及多種語言間的自由切換。

現在的方案

此方案結合異常碼、字串佔位符和資原始檔的特點及優勢。異常碼可理解為一個異常資訊的ID,具有唯一性,必要性;異常資訊資原始檔中的值可包含佔位符(格式為{n}),處理異常時可用實際值替換,達到異常資訊的進一步具體化,但不是必須的。資原始檔就是內容為“異常碼=提心資訊”的記錄的檔案。

方案具體描述如下:

  1. 首先,在springboot專案中定義系統的http請求統一返回的資料格式,此處我們的定義包含三個屬性: code(業務異常狀態碼)、message(異常提示資訊)、data(無異常時返回的資料體)。對異常資訊國際化主要體現在message屬性,也就是返回前端給使用者展示的異常提示資訊。code屬性用於確定唯一的異常。其次定義需要丟擲的業務異常,其中主要包括code(異常碼)和params(用於替換異常資訊字串佔位符{n}的實際值)屬性。

  2. 在專案路徑下定義異常資訊的資原始檔,檔案內容包含多條記錄,每條記錄為鍵值對的形式,即key=value。對需要實現的語言種類分別提供一份對應的檔案,這些檔名除預設資訊外,均包含語言(地區資訊),檔案中包含中key是一致的,value為相應語言的字串組成。如果新增語言的支援,只需要新增一份對應的資原始檔即可。以下包含預設、英文環境和簡體中文環境下對應的異常提示資訊國際化資原始檔,如圖2.1

  3. 利用springboot的提供的介面定義統一攔截器,並且注入http請求上下文和資源獲取器,在攔截器中對應用丟擲的異常進行捕獲,針對上述特定的異常做國際化處理。
    其國際化處理邏輯如下:根據http請求傳入的語言資訊指定特定的語言(地區)環境,如沒有傳入語言資訊,則採用應用預設的語言配置;據此讀取上述編寫好的對應的異常資訊資原始檔,並依據捕獲的異常中的code(異常碼)查到到對應的字串,將params實際值替換掉字串中的佔位符,完成後即為返回給前端的異常提示資訊。

  4. 在controller、service和dao層中根據程式邏輯丟擲相應異常,其中異常碼應該在資原始檔中已定義。示例程式碼如下圖2.3

  5. 整體流程圖如下圖2.4

demo

以下是一個demo,其中提供了必要的程式碼註釋,以便於理解。

  • 自定義異常結構,包含code和params

  • 異常資原始檔定義

  • 全域性異常攔截

  • 程式碼邏輯中丟擲異常

  • 請求響應示例

請求1:http://127.0.0.1:8080/demo?lang=en&msg=a

返回:

請求2:http://127.0.0.1:8080/demo?lang=zh_CN&msg=a

返回:

請求3:http://127.0.0.1:8080/demo?lang=en&msg=c

返回:

請求4:http://127.0.0.1:8080/demo?lang=zh_CN&msg=c
返回:

總結

  1. 此方案能較好地處理異常資訊的國際化,能自如地新增資原始檔,不需要改動此方案的現有程式碼,這也使得程式耦合性降低;
  2. 統一的異常格式定義、全域性異常攔截極大程度上減少了程式碼耦合性,大大簡化了團隊編碼中對異常邏輯的處理,能減少重複性編碼,有利於提高工作效率;
  3. 現有方案未能較好地支援異常資訊中特定值的支援,此方案利用設定佔位符的方式,較好地做到了支援,靈活方便;
  4. springboot支援的國際化實現中預設提供了快取支援,效能良好。

參考

(文中配圖有空再改!!)