程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 基於Eclipse的Birt國際化的分析與改進

基於Eclipse的Birt國際化的分析與改進

編輯:關於JAVA

開發環境

本文的開發環境為 Windows Vista Enterprise、birt-report-designer-all-in-one-2_2_2、Birt 2.2.2、Java EE 服務器使用 apache-tomcat-6.0.18,當然,您也可以使用 Jboss 等其他 Java EE 服務器。

初識 BIRT

BIRT 是一個 Eclipse-based 開放源代碼報表系統同 JasperReports 類似。它主要是用在基於 Java 與 J2EE 的 Web 應用程序上。BIRT 主要由兩部分組成:一個是基於 Eclipse 的報表設計和一個可以加到你應用服務的運行期組件。BIRT 同時也提供一個圖形報表制作引擎。

BIRT 報表文件的國際化

新建 birt 報表的過程請參考網站的其他文檔,現有一個名為 internationalization_file.rptdesign 報表文件,然後在 layout 視圖點擊報表的空白處如下所示:注意一定是空白處,點擊其他位置是不能出現這個菜單項的。

圖 1. 選擇報表的資源文件

然後點選 resources 標簽頁,點擊 Add 按鈕來加入資源文件或者輸入資源文件名稱。

注意:如果在屬性 Resources 中填寫了 MyResources, 那麼資源文件的名稱要以以下規律命名:

MyResources_en_US.properties、 MyResources_zh.properties 等,資源文件定義符合 Java I18N 格式。後面的 _en_US 或 _zh d 等由參數 __locale 傳遞。那麼資源文件要放到哪裡呢?我們通過在應用的 web.xml 中定義 <param-name>BIRT_RESOURCE_PATH</param-name> 來確定資源文件的位置,這也是指定報表文件路徑的參數。

報表文件國際化的實例演示

現在我們指定了 internationalization_file.rptdesign 報表文件的 Resources 為 MyResources,並建立兩個 property 文件,一個中文資源文件 MyResources_zh.properties, 另一個為英文資源文件 MyResources_en_US.properties,資源文件內容如下:

MyResources_zh.properties:name=\u663E\u793A\u53D8\u91CF

MyResources_en_US.properties:name=show param

將報表文件的字段指定為資源文件中定義的鍵值。

圖 2. 指定對應的鍵值

然後將報表文件及所需的資源文件放到服務器對應的目錄下,如:\webapps\WebViewerExample。在浏覽器中輸入 http://localhost:8080/WebViewerExample/frameset?__report=internationalization_file.rptdesign&sample=my+parameter&__locale=en_US顯示如下:

圖 3. 資源文件為英文的

然後將上面的 URL 中的 __locale=en_US 換成 __locale=zh, 顯示如下:

圖 4. 資源文件為中文的

BIRT-console 的國際化

通常情況下,我們還是用 birt 提供的 console 來展示報表的,如果 console 提供的功能不能滿足我們的要求,在上面做二次開發也是挺簡單的事情,如果重新再開發一個 birt 報表的展示 console,造同樣輪子的做法不是很值得提倡的。回到正題上來,我們怎樣國際化 birt-console 呢?國際化文件放到哪裡?是否可以將國際化文件移到一個可管理的路徑下呢?接下來,我們會一一解開這些疑惑。

Birt 提供了國際化 console 的方法,國際化文件放在一個名為 viewservlets.jar 包裡面,名稱為 Messages.properties。如果我們要實現中文的國際化,是否放入一個中文的資源文件就可以呢?實踐往往是驗證疑惑最有效的方法,實際結果驗證這樣是不行的。下面我們來看一下 birt 實現 console 國際化部分的代碼,類 BirtResources 調用的是 ViewerResourceHandle 類。

清單 1. BirtResources 類

public static String getMessage( String key )
 {
  ViewerResourceHandle resourceHandle = getResourceHandle( );
  if ( resourceHandle != null )
  return resourceHandle.getMessage( key );

  return key;
 }

類 ViewerResourceHandle 繼承自 ResourceHandle 類。

清單 2. ViewerResourceHandle 類

public class ViewerResourceHandle extends ResourceHandle

我們再看 ResourceHandle 類,這個類是組織資源文件的關鍵類:

清單 3. ResourceHandle 類

public ResourceHandle( ULocale locale )
  {
  String className = this.getClass( ).getName( );
  String bundleName = ""; //$NON-NLS-1$
 // Create the base message file name formatted like a Java class.
 // The Java class loader will search for the file using the same
 // algorithm used to find classes.
   int index = className.lastIndexOf( '.' );
   if ( index > -1 )
   {
 // e.g: "org.eclipse.birt.report.model.util.Test" 
 bundleName = className.substring( 0, index ) + ".";
 //$NON-NLS-1$
   }

   bundleName = bundleName + BUNDLE_NAME;
   if ( locale == null )
    locale = ULocale.getDefault( );
   resources = UResourceBundle.getBundleInstance(
        bundleName, locale.toString(), this.getClass().getClassLoader() );
 assert resources !=
     null : "ResourceBundle : " + BUNDLE_NAME + " for " + locale + " not found";
 //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
 }

從 this.getClass().getClassLoader()可以看出來 console 的國際化文件是放在類路徑下面的,文件的組織形式是文件名稱 +locale,再有資源文件放到 jar 包裡面類路徑下可不是什麼好的方法,那麼我們是否能提供一個外部變量來配置這個資源文件的路徑呢?後面我們會講到。先來看看為什麼中文資源文件放到 jar 包裡面的類路徑下不起作用,明明是有 locale 的,是不是感覺有點奇怪?我們接下來繼續跟蹤,進入類 ReportEngineService 中的方法 createGetParameterDefinitionTask, 看它的方法體:

清單 4. 原 createGetParameterDefinitionTask 方法

public IGetParameterDefinitionTask createGetParameterDefinitionTask(
    IReportRunnable runnable, InputOptions options )
  {
   IGetParameterDefinitionTask task = null;

   try
   {
 HttpServletRequest request =
      (HttpServletRequest) options.getOption( InputOptions.OPT_REQUEST );

    task =    engine.createGetParameterDefinitionTask( runnable );
    // set app context
  Map context = BirtUtility.getAppContext( request,
             ReportEngineService.class.getClassLoader( ) );
    task.setAppContext( context );
   }
   catch ( Exception e )
   {
   }

   return task;
  }

我們會注意到服務層的這個入口方法中沒有設置任何與 locale 相關的變量,添加設置 locale 變量的代碼,修改後的 createGetParameterDefinitionTask 如下所示:

清單 5. 修改後的 createGetParameterDefinitionTask

public IGetParameterDefinitionTask createGetParameterDefinitionTask(
    IReportRunnable runnable, InputOptions options )
  {
   IGetParameterDefinitionTask task = null;

   try
   {
 HttpServletRequest request =
   (HttpServletRequest) options.getOption( InputOptions.OPT_REQUEST );

    task = engine.createGetParameterDefinitionTask( runnable );
 task.setLocale(ParameterAccessor.getLocale(request));
    // set app context
  Map context = BirtUtility.getAppContext( request,
       ReportEngineService.class.getClassLoader( ) );
    task.setAppContext( context );
   }
   catch ( Exception e )
   {
   }

   return task;
  }

類 ParameterAccessor 感興趣的朋友可以研究一下,他是傳遞入口參數的。如 __action、__nocache、__report 等,參數說明如下。

表 1. 參數描述

參數名 參數說明 參數值 默認值 __format 指定報表輸出格式 html 或 pdf html __isnull 指明一個參數是 null,常用於字符串類型。如果提供參數且值為空: - 對於日期和數字類型,BIRT 會將它們當作 null 處理。 - 對於字符串,BIRT 會將它作為空字符串。因此,為了說明某個字符串是 null,通常寫為:__isnull= 參數。 報表輸入參數名 None. Required. __locale 本地化選項 en-us 或 ch-zh 虛擬機默認 __report 指定 *.rptdesign 文件路徑   None. Required. __svg 指定是否使用 SVG 矢量圖來顯示圖表。
SVG 矢量圖形是一種 XML 格式的文本文件,在 IE 下需要安裝 Adodb SVG Viewer 插件才能浏覽。
  true 或 false 安裝插件後浏覽時
frameset 下默認 true,run 下默認 false;不安裝插件時默認為 false

管理 console 國際化的資源文件

通過上面講解,我們知道 ViewerResourceHandle 繼承自 ResourceHandle 類,而 ResourceHandle 類是負責組織資源文件的,代碼默認是將資源文件放到類路徑下的,也就是該類的包路徑下。通過以上分析可知,如果我們想改變資源文件的路徑只能有這麼兩種方法。方法一,重寫一個 ResourceHandleNew 類 , 然後讓 ViewerResourceHandle 繼承自 ResourceHandleNew; 方法二,修改 public ResourceHandle( ULocale locale ) 方法,或添加一個新的方法 public ResourceHandleExtent( ULocale locale ),在 ResourceHandleExtent 方法中實現資源文件路徑可以通過外部變量來配置。其實兩種方法各有千秋,不過核心就是都要修改 ResourceHandle 方法來達到管理資源文件的目的。下面我們來重寫 ResourceHandle 方法。

清單 6. 修改後的 ResourceHandle

public ResourceHandle( ULocale locale )
  {
   if ( locale == null )
    locale = ULocale.getDefault( );
   // get resource path 
   String birtResourceFolder = ParameterAccessor.processRealPath( context,
   context.getInitParameter( INIT_PARAM_BIRT_RESOURCE_PATH ), null, false );
   // 這個地方是需要完善的
   String bundleName = birtResourceFolder+"/" + BUNDLE_NAME 
            +"_"+locale.getLanguage()+"_"+locale.getCountry();
    Reader reader = null;
    try {
      reader = new FileReader(bundleName);
      resource = new PropertyResourceBundle(reader);
    } catch (FileNotFoundException ex) {
      ex.printStackTrace();
    } catch (IOException ex) {
      ex.printStackTrace();
    } finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (IOException ex) {
          ex.printStackTrace();
        }
      }
    }
  }

INIT_PARAM_BIRT_RESOURCE_PATH 這個參數是不是有點熟悉,就是配置報表文件路徑的變量,是 web.xml 中定義的 <param-name>BIRT_RESOURCE_PATH</param-name> 這個變量的值。至此我們完全可以將 console 的資源文件放到 jar 外面來進行管理了。

經常遇到的一些 birt 相關問題的總結

Birt view 界面顯示紅叉如:

圖 5. 經常遇到的問題之一

解決方法:

viewer.properties 文件的 #base_url=http://127.0.0.1:8080

設置不對,該設置主要應用於代理服務器的情況下,在使用代理服務器後,從 request 裡獲取的 URI 並非真正的 URI,需要在這裡設置。

控制 birt 日志輸出級別

解決方法:

在 web.xml 中設置

<context-param>
   <description>
   Report engine log level.( ALL|SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST|OFF )
   </description>
   <param-name>BIRT_VIEWER_LOG_LEVEL</param-name>
   <param-value>ALL</param-value>
  </context-param>

訪問 http://[yourip]:[yourport]/WebViewerExample/ 然後點擊 View Example 後出現異常

解決方法:

將 common-logging.jar 包添加到 birt-runtime-2_2_2\WebViewerExample\WEB-INF\lib 目錄下。

說明:本文相關代碼的修改只為提供給開源愛好者研究代碼使用,如用於商業用途責任自負。

總結

文章主要講解了如何國際化 birt 的報表文件及 birt 提供的 console 界面,由於 birt 代碼本身的一些局限性,使得 birt console 的國際化文件管理起來有些問題,通過修改相關代碼來達到靈活管理 console 資源文件的目的,通過跟蹤相關類間關系,有助於我們更好的了解 birt 國際化的實現方式。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved