最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決Spring國際化文案占位符失效問題的方法

 更新時間:2018年04月10日 14:28:01   作者:打破突破  
本篇文章主要介紹了解決Spring國際化文案占位符失效問題的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

寫在前面:接下來很長一段時間的文章主要會記錄一些項目中實際遇到的問題及對應(yīng)的解決方案,在相應(yīng)代碼分析時會直指問題所在,不會將無關(guān)的流程代碼貼出,感興趣的讀者可以自行跟蹤。同時希望大家能夠?qū)⑿牡皿w會在評論區(qū)分享出來,讓大家共同進(jìn)步!

環(huán)境或版本:Spring 3.2.3

現(xiàn)象:利用Spring自帶的MessageSource來處理國際化文案,us狀態(tài)下的文案有部分占位符未被替換,cn狀態(tài)下的正常。文案如下:

tms.pallet.order.box.qty=The total palletized boxes quantity {0} doesn't match with the received boxes quantity {1},Please double check!
tms.pallet.order.box.qty=打板總箱數(shù)件{0},與訂單收貨總箱數(shù){1}不一致。請檢查!

直覺:是不是英文文案太長了,Spring處理時對長度做了限制,仔細(xì)想了想Spring應(yīng)該不會設(shè)計的這么坑。

排查:斷點跟蹤Spring源碼(入口:MessageSource的getMessage方法),最后發(fā)現(xiàn)了MessageFormat中這樣的一段處理方法:

 // Indices for segments
  private static final int SEG_RAW   = 0;
  private static final int SEG_INDEX  = 1;
  private static final int SEG_TYPE   = 2;
  private static final int SEG_MODIFIER = 3; // modifier or subformat

/**
   * Sets the pattern used by this message format.
   * The method parses the pattern and creates a list of subformats
   * for the format elements contained in it.
   * Patterns and their interpretation are specified in the
   * <a href="#patterns" rel="external nofollow" >class description</a>.
   *
   * @param pattern the pattern for this message format
   * @exception IllegalArgumentException if the pattern is invalid
   */
  @SuppressWarnings("fallthrough") // fallthrough in switch is expected, suppress it
  public void applyPattern(String pattern) {
      StringBuilder[] segments = new StringBuilder[4];
      // Allocate only segments[SEG_RAW] here. The rest are
      // allocated on demand.
      segments[SEG_RAW] = new StringBuilder();

      int part = SEG_RAW;
      int formatNumber = 0;
      boolean inQuote = false;
      int braceStack = 0;
      maxOffset = -1;
      for (int i = 0; i < pattern.length(); ++i) {
        char ch = pattern.charAt(i);
        if (part == SEG_RAW) {
          if (ch == '\'') {
            if (i + 1 < pattern.length()
              && pattern.charAt(i+1) == '\'') {
              segments[part].append(ch); // handle doubles
              ++i;
            } else {
              inQuote = !inQuote;
            }
          } else if (ch == '{' && !inQuote) {
            part = SEG_INDEX;
            if (segments[SEG_INDEX] == null) {
              segments[SEG_INDEX] = new StringBuilder();
            }
          } else {
            segments[part].append(ch);
          }
        } else {
          if (inQuote) {       // just copy quotes in parts
            segments[part].append(ch);
            if (ch == '\'') {
              inQuote = false;
            }
          } else {
            switch (ch) {
            case ',':
              if (part < SEG_MODIFIER) {
                if (segments[++part] == null) {
                  segments[part] = new StringBuilder();
                }
              } else {
                segments[part].append(ch);
              }
              break;
            case '{':
              ++braceStack;
              segments[part].append(ch);
              break;
            case '}':
              if (braceStack == 0) {
                part = SEG_RAW;
                makeFormat(i, formatNumber, segments);
                formatNumber++;
                // throw away other segments
                segments[SEG_INDEX] = null;
                segments[SEG_TYPE] = null;
                segments[SEG_MODIFIER] = null;
              } else {
                --braceStack;
                segments[part].append(ch);
              }
              break;
            case ' ':
              // Skip any leading space chars for SEG_TYPE.
              if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {
                segments[part].append(ch);
              }
              break;
            case '\'':
              inQuote = true;
              // fall through, so we keep quotes in other parts
            default:
              segments[part].append(ch);
              break;
            }
          }
        }
      }
      if (braceStack == 0 && part != 0) {
        maxOffset = -1;
        throw new IllegalArgumentException("Unmatched braces in the pattern.");
      }
      this.pattern = segments[0].toString();
  }

上面的這段代碼寫的有點讓人費(fèi)解,略微奇特,我們主要看第一個邏輯分支:對每一個待處理的國際化文案模板串中的字符進(jìn)行遍歷,當(dāng)字符為"'"時,判斷后一個字符是否也為“'”,如果是則將“‘”拼接到已處理的StringBuilder中,不是則將inQuote至為True,如果該字符不會‘{'且inQuote為false則將part重新置為0,并且segments[SEG_INDEX]=null的話重新創(chuàng)建StringBuilder對象,否則繼續(xù)拼接。

原因分析:

  1. 結(jié)合我們配置的英文文案(其中一共有兩個占位符,在這這兩占位符之前有一個單引號),根據(jù)上面Spring的處理源碼看,實際處理會是:對該字符串進(jìn)行逐個字符處理,逐個拼接到已處理的StringBuilder中,當(dāng)處理到‘{'時,此處part將被置為1,同時segments第1個存儲位上會引用StringBuilder類型的對象,程序繼續(xù)處理下面的待處理的字符,繼續(xù)拼接(請自行看part!= SEG_RAW的邏輯分支),直到處理到‘}'時,part被重新賦值為0,sefgments的其他位被清空,于是繼續(xù)處理下面的字符串繼續(xù)拼接,處理到單引號時,inQuote被置為True,接下來就一路拼接了,不再對后面的“{“做占位符處理。
  2. 中文文案中兩個占位符之間并沒有出現(xiàn)單引號,因此解決了問題現(xiàn)象中的第二點,中文文案顯示正常。

解決方案:

從源碼看只有一種解決方式,{}之間的單引號需要成對出現(xiàn),我們的處理方式是將文案修改為了:

tms.pallet.order.box.qty=The total palletized boxes quantity {0} doesn''t match with the received boxes quantity {1},Please double check!

直接修改文案其實并不是一種很好的解決方法,最好是能夠重寫Spring調(diào)用applyPattern方法前的某一方法來將單引號替換為雙引號。無奈spring 3.2.3版本中對應(yīng)國際化的處理方法一路private,不給你重寫的機(jī)會。

查閱相關(guān)資料得知,在Spring4.3.2版本中可以通過重寫ResourceBundleMessageSource類中的getStringOrNull方法來實現(xiàn)。

長遠(yuǎn)方案:升級項目中的Spring版本,同時使用更多的新版特性。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 使用Feign實現(xiàn)微服務(wù)間文件下載

    使用Feign實現(xiàn)微服務(wù)間文件下載

    這篇文章主要為大家詳細(xì)介紹了使用Feign實現(xiàn)微服務(wù)間文件下載,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • 使用Idea快速搭建SpringMVC項目的詳細(xì)步驟記錄

    使用Idea快速搭建SpringMVC項目的詳細(xì)步驟記錄

    這篇文章主要給大家介紹了關(guān)于使用Idea快速搭建SpringMVC項目的詳細(xì)步驟,Spring?MVC是一種基于MVC模式的框架,它是Spring框架的一部分,它提供了一種更簡單和更有效的方式來構(gòu)建Web應(yīng)用程序,需要的朋友可以參考下
    2024-05-05
  • 解決SpringBoot ClassPathResource的大坑(FileNotFoundException)

    解決SpringBoot ClassPathResource的大坑(FileNotFoundException)

    這篇文章主要介紹了解決SpringBoot ClassPathResource的大坑(FileNotFoundException),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • SpringMVC之DispatcherServlet配置文件應(yīng)該放在哪里呢

    SpringMVC之DispatcherServlet配置文件應(yīng)該放在哪里呢

    這篇文章主要介紹了SpringMVC之DispatcherServlet配置文件應(yīng)該放在哪里的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • SpringMVC中Controller層獲取前端請求參數(shù)的方式匯總

    SpringMVC中Controller層獲取前端請求參數(shù)的方式匯總

    這篇文章主要介紹了SpringMVC中Controller層獲取前端請求參數(shù)的幾種方式,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • 在 Spring Boot 3 中接入生成式 AI的操作方法

    在 Spring Boot 3 中接入生成式 AI的操作方法

    本文介紹了如何在SpringBoot3中集成生成式AI,以O(shè)penAI的GPT模型為例,通過代碼示例展示了如何實現(xiàn),SpringBoot3的優(yōu)勢和OpenAI的生成式AI技術(shù)結(jié)合,為開發(fā)者提供了高效集成生成式AI的方法,感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • Java的動態(tài)分派和靜態(tài)分派的實現(xiàn)

    Java的動態(tài)分派和靜態(tài)分派的實現(xiàn)

    這篇文章主要介紹了Java的動態(tài)分派和靜態(tài)分派的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Java讀取文件及基于正則表達(dá)式的獲取電話號碼功能詳解

    Java讀取文件及基于正則表達(dá)式的獲取電話號碼功能詳解

    這篇文章主要介紹了Java讀取文件及基于正則表達(dá)式的獲取電話號碼功能,結(jié)合實例形式詳細(xì)分析了正則匹配操作的相關(guān)語法及電話號碼匹配的原理與實現(xiàn)技巧,需要的朋友可以參考下
    2017-09-09
  • MyBatisPlus+Spring實現(xiàn)聲明式事務(wù)的方法實現(xiàn)

    MyBatisPlus+Spring實現(xiàn)聲明式事務(wù)的方法實現(xiàn)

    本文主要介紹了MyBatisPlus+Spring實現(xiàn)聲明式事務(wù)的方法實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • SpringBoot整合sharding-jdbc實現(xiàn)分庫分表與讀寫分離的示例

    SpringBoot整合sharding-jdbc實現(xiàn)分庫分表與讀寫分離的示例

    本文主要介紹了SpringBoot整合sharding-jdbc實現(xiàn)分庫分表與讀寫分離的示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11

最新評論

清丰县| 白山市| 集安市| 高台县| 青冈县| 莱州市| 凤冈县| 蕉岭县| 安仁县| 洪湖市| 沈阳市| 仙游县| 长丰县| 孟村| 嘉黎县| 邹城市| 三门县| 滁州市| 兰溪市| 钦州市| 策勒县| 南康市| 梁河县| 旅游| 上杭县| 武宁县| 方山县| 北宁市| 保亭| 大化| 津市市| 南陵县| 青田县| 工布江达县| 海南省| 台南市| 萨迦县| 蕲春县| 文安县| 西昌市| 津南区|