1. 程式人生 > >Eclipse rap 開發經驗總結

Eclipse rap 開發經驗總結

1、 Eclipse rap專案目前的進度


   目前rap 的最新版本是 rap 1.5M4,最穩定版本是 rap 1.4.1,我們專案目前使用的版本是rap 1.4.1,Rap目前已經支援的部分是 swt,JFace,rap目前暫時不支援的部分是 dwaw2d、gef關於對dwaw2d、gef的支援目前正在開發中,原計劃在eclipse E4版本中支援,目前改版本已經延遲了,而且暫時不支援dwaw2d、gef,至於什麼時候完成,就不得而知了. 
關於版本和支援情況大家可以去這個頁面上看一下 
http://www.eclipse.org/rap/downloads/ 

2、目前rap上存在的問題   


   1、執行速度

速度上面不同瀏覽器支援情況不同,使用chrome瀏覽器速度最快,firefox其次,IE瀏覽器(所有IE核心的都一樣)最慢,而且不支援IE6(IE6上面跑介面上顯示有些小問題),其他瀏覽器沒有試過.大家有時間可以驗證下,目前官方上釋出支援的瀏覽器有 
Firefox 2+ 、IE 7+ 、Safari 3+ 、Chrome 3+ 、Opera 9+


   2、系統的bug 

       現在穩定版本的bug不少,開發中遇到的問題也不少,例如  treeViewer 會出現遮擋,系統自帶的提示框第一次彈出的時候只能展示一半,等等,當然這些bug都可以通過其他的方式給避免掉.  

鄭重提示:想在自己專案中使用rap朋友們一定要慎重考慮 
   是否有精力和人力來處理一下”小”問題 

雖然rap 是rcp的web版本,但是因為 一個是圖形介面,一個是web介面,它們之間還是存在一些差異,現在把我們專案中碰見的差異羅列一下,大家以後碰見了就不至於浪費時間找原因了.^_^

1、 Label和Button按鈕的顯示的差異

    當Label 和 Button顯示的文字過長顯示不開的時候,rcp、rap的處理方式就不一樣了,rap顯示不開會自己擷取掉後面的文字,rcp會在文字的中間加上省略號.

還有關於Label 和Button 設定圖片,文字過長的時候rap的圖片不會顯示,可以使用CLabel來替換Label

建議統一處理方式:不使用他們自帶的文字擷取方式,統一計算檔案的長度,在文字最後面加上… 來使二者統一

2、 TreeViewer的差異

     目前最新的rap 版本 TreeViewer偶爾有遮擋的問題,這個問題暫時不能有效的避免,

3、 屬性檢視 -tree無法設定行高的問題

     關於設定 treeViewer的高度,rcp支援設定行的高度,rap不支援,這個暫時沒有解決方法

4、 對GEF、draw2d的支援

     目前rap暫時不支援GEF draw2d,不過目前已經在開發中。

5、 paint監聽,rap沒有

        rap組建很多都沒有paint 重繪方法,導致很多介面不能進行重繪。比如treeVIewer上面新增cellEditor進行介面上直接編輯,因為不支援,paint 導致 cellEditor和當前的行的位置不匹配。在後續文章中會對此問題的解決方法進行專門的講解

6、 擴充套件點的差異控制檯擴充套件點

       Rap介面目前對擴充套件點的支援也不是很完善,控制檯擴充套件點和幫助檢視擴充套件點都不是很完善,不過大家可以自己實現.不是很複雜

7、 幫助系統的差異

         Rcp /rap的幫助系統完全不同,rap的幫助系統只是載入一個jsp頁面

         8、上傳下載的差異

一個是web 一個是圖形介面,後續會寫如何在rap實現上傳和下載

         9、檢視拖動

                   用過eclipse的朋友都知道,eclipse之間的檢視是可以任意拖動的,目前Rap不支援,檢視間的拖動,這個算是比較遺憾吧


完成後:


 

最後點finish。

重新開啟RAP程式,可以看到漢化結果。


1、  在工程的根目錄下面建立一個plugin.properties資原始檔;在此資原始檔中寫入需要國際化的內容(鍵/值對),舉例如下:

Java程式碼  收藏程式碼
  1. helloWorldView_name=eclipse國際化  
  2. helloWorldView_city=北京  
  3. ...  

 2、 

在 MANIFEST.MF檔案中增加程式碼行:Bundle-Localization: plugin;

說明:新增程式碼行中的plugin這個名稱是plugin.properties 這個檔案的名稱。也可以是其它的名稱但要與檔名保持一致。

3、  plugin.xml配置檔案對資原始檔進行引用時, 在引用的key前面加一個%即可;

plugin.xml引用資原始檔舉例如下:

Xml程式碼  收藏程式碼
  1. <extension  point="org.eclipse.ui.views">    
  2. <view    
  3.       id="org.eclipse.rap.helloworld.helloWorldView"    
  4.  class="org.eclipse.rap.helloworld.HelloWorldView"    
  5.  name="%helloWorldView_name">    
  6. </view>    
  7.  </extension>    

類檔案中中文內容的國際化

1、  建立一個messages_zh_CN.properties資原始檔;

說明:此資原始檔中的內容為需要國際化的鍵/值對;

2、  建立一個Messages.java類檔案,檔案內容如下:

Java程式碼  收藏程式碼
  1. import org.eclipse.osgi.util.NLS;  
  2. public class Messages extends NLS  
  3. {  
  4.      private static final String BUNDLE_NAME = "telecomui.nls.messages";   
  5. public static String PriceDomainDao_AddTextToBrower;  
  6. static {  
  7.             NLS.initializeMessages(BUNDLE_NAME, Messages.class);  
  8.         }  
  9.         private Messages(){  
  10.         }  
  11. }  

3、  在需要進行國際化的類檔案上點選右鍵,出現下圖的操作:



 

4、  點選藍色選單選項後,彈出下面的窗體,如圖:


5、  在上圖中列出的需要國際化的欄位中,對需要進行國際化的欄位前勾選加號,不需要進行國際化的欄位前勾選差號;

注意:

對於需要進行國際化的欄位項,如圖


 

中欄位Test_0是生成到資原始檔中的預設key值,建議進行重新命名下,建議命名規則是最好以當前類名做字首;如上欄位可命名為:Test_printStr;

6、  單擊窗體中的【Configure…】按鈕,彈出窗體,如圖:


 

 

7、  對上圖中的各選項進行設定後,點選【ok】按鈕—>【next】—>【finish】

 先下載以來的打包外掛

war products


 
 輸入下面的地址,選擇相應的外掛


新建一個 war product Configutation嚮導

 下面的war  product Configutation 配置面板

選擇外掛

將除了 自己專案 在外的所有外掛都刪除,然後點 Add Required Plug-ins 將需要的外掛新增進來,吧所有的關於 Jetty 和Juit 的外掛全部刪除掉,這樣在驗證的時候就不會出現什麼錯誤。避免把沒必要的外掛加進來。

在 Overview 中點 Validate 按鈕驗證是否存在問題:



 點選匯出war

 釋出成功

1、 Rap樣式原理

Rap的介面樣式目前是以css來配置的,程式啟動後加載相應的css配置檔案再對元件進行樣式設定,介面上的所有元件Label button composit等的樣式最開始都是通過css來確定顯示樣式的.因此只需要選擇不同的css檔案就可以控制css樣式了

2、 Rap如何選擇樣式

Plugin.xml – 擴充套件 – 新建 org.eclipse.rap.ui.branding 擴充套件點 – 在這個擴充套件點上新建branding .在 branding上就可以選擇樣式了,對應的選項是themdID ,點選瀏覽就可以選擇目前已經存在的樣式

目前rap自帶的樣式大約有2個 , Classis 樣式和 Default ,

建議大家使用Classis 樣式,因為預設的default樣式本身在介面顯示上面會有不少的問題.

3、 修改rap自帶的樣式

如果你覺得目前rap介面上的樣式不太符合你的要求,那麼你就可以新建自己的rap樣式 方法如下:

新建擴充套件點:org.eclipse.rap.ui.themes

在擴充套件點上新建 theme

點選 theme 會有一個屬性 file,這個是用來選擇對應的樣式css檔案的.

關於rap每個組建對應的樣式名稱,大家可以通過如下方式進行檢視

找到 org.eclipse.rap.rwt.theme.classes 外掛(直接通過外掛列表-匯出原始碼到目前工程)

在對應的 theme目錄下面就可以看到 classic.css檔案了

4、 Rap樣式的釋出

Rap最好按照預設的方式以外掛的形式進行釋出,這樣就可以鬆耦合了.

1 、解決 rap 字符集亂碼的問題

    字符集問題,解決辦法:   在plugin.xml - build.properties 中新增

      javacDefaultEncoding.. = UTF-8   即可解決字符集亂碼

2、解決web前臺輸入亂碼問題

    使用傳統的 字符集過濾器

    寫一個過濾器類

Java程式碼  收藏程式碼
  1. <span style="font-size: small;">public class CharacterEncodingFilter implements Filter  
  2. {  
  3.   private String edcoding;  
  4.   private FilterConfig filterConfig;  
  5.   private boolean ignore;  
  6.   public CharacterEncodingFilter()  
  7.   {  
  8.     this.edcoding = null;  
  9.     this.filterConfig = null;  
  10.     this.ignore = true; }  
  11.   public void destroy() {  
  12.     this.edcoding = null;  
  13.     this.filterConfig = null;  
  14.   }  
  15.   public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException  
  16.   {  
  17.     if ((this.ignore) || (request.getCharacterEncoding() == null)) {  
  18.       String encoding = setCharacterEncoding(request);  
  19.       if (encoding != null)  
  20.         request.setCharacterEncoding(encoding)  
  21.     }  
  22.     filterChain.doFilter(request, response);  
  23.   }  
  24.   public void init(FilterConfig filterConfig) throws ServletException {  
  25.     this.filterConfig = filterConfig;  
  26.     this.edcoding = filterConfig.getInitParameter("encoding");  
  27.     String value = filterConfig.getInitParameter("ignore");  
  28.     if (value == null)  
  29.       this.ignore = true;  
  30.     else if (value.equalsIgnoreCase("true")) {  
  31.       this.ignore = true;  
  32.     }  
  33.     else  
  34.       this.ignore = false;  
  35.   }  
  36.   public String setCharacterEncoding(ServletRequest request)  
  37.   {  
  38.     return this.edcoding;  
  39.   }  
  40. }  
  41. </span>  

然後達成 jar 包方式到 war /WEB_INF/lib 目錄下面

在 web.xml 新增

rap 匯出 war 包時,編碼問題處理,加入了字元過濾器的處理方式

1. 在匯出 WAR 後,修改 war 包裡面的 web.xml 檔案,新增過濾器,

內容如下

Java程式碼  收藏程式碼
  1. <span style="font-size: small;"><span>  <filter>    
  2.         <filter-name>CharacterEncodingFilter</filter-name>    
  3.         <filter-class>com.encoding.CharacterEncodingFilter</filter-class>    
  4.         <init-param>    
  5.             <param-name>encoding</param-name>    
  6.             <param-value>UTF-8</param-value>    
  7.         </init-param>    
  8.     </filter>    
  9.     <filter-mapping>    
  10.         <filter-name>CharacterEncodingFilter</filter-name>    
  11.         <url-pattern>/*</url-pattern>    
  12. </filter-mapping>  
  13. </span>  
  14. </span>  

2. 增加 jar 包

   把過濾器要用的 jar 包【 encoding.jar 】新增到匯出的 WAR 包的 lib 下面,這樣     WAR 包載入後,能夠找尋到過濾器用到的類。

上面 2 部分可以保證完美的解決中文問題

一 上傳

上傳即將檔案上傳到伺服器上,在客戶端需要寫相應的指令碼,伺服器端需要註冊相應的 handle 接受客戶端的請求。

原理:

  Rap 的上傳和下載是通過普通的 web 的方式進行上傳和下載的 , 但是和傳統的 wen 還不相同

1、  rap 本身就單執行緒在跑 , 和上傳下載的執行緒不能進行混淆

所以採用的方式如下:

上傳:通過傳統的方式上傳到指定目錄 ,rap 不能直接操作上傳的檔案流 , 如果想獲得上傳的資料必須要先上傳到指定檔案 , 然後讓 rap 去載入指定檔案即可

下載: 先通過 rap 程式生成需要下載的檔案到指定目錄 , 然後通過 rap 載入成檔案流的形式傳送給客戶端

1 在伺服器端註冊相應的 handler

  // 註冊上傳處理事件

  IServiceManager manager = RWT.getServiceManager ();

  IServiceHandler uploadHandler = new UploadServiceHandler();

manager.registerServiceHandler( "uploadServiceHandler" , uploadHandler); //$NON-NLS-1$

2 在客戶端的指令碼呼叫

目前的做法是建立上傳的 dialog, 在 dialog 裡面新增 browser 控制元件,然後 browser 裡書寫上傳的 javaScript 指令碼,指令碼請求的 url 格式可以通過以下類似的程式碼建立:

   private String createUploadUrl(String uploadFileName) {

      StringBuffer url = new StringBuffer();

      url.append(RWT.getRequest ().getContextPath());

      url.append(RWT.getRequest ().getServletPath());

      url.append( "?" ); //$NON-NLS-1$

      url.append(IServiceHandler . REQUEST_PARAM );

      url.append( "=uploadServiceHandler" ); //$NON-NLS-1$

      url.append( "&fileName=" ); //$NON-NLS-1$

      url.append(uploadFileName);

      return url.toString();

   }

3 伺服器端 handler 的寫法

public class UploadServiceHandler implements IServiceHandler {

   public void service() throws IOException, ServletException {

      HttpServletRequest request = RWT.getRequest ();

      request.setCharacterEncoding( "UTF-8" );

      String fileName = request.getParameter( "fileName" );

      FileOutputStream o = null ;

      BufferedReader bufferReader = null ;

      InputStream in = null ;

      try {

         in = request.getInputStream();

         File f = null ;

         try {

          f = new File(FileUtil.getTempFilePathAndName (RWT.getRequest ()

            .getSession().getAttribute( "userName" ).toString(),

                   fileName));

         } catch (Exception e) {

            throw new IOException(e);

         }

         o = new FileOutputStream(f);

         bufferReader = new BufferedReader( new InputStreamReader(in));

         String line = null ;

         boolean beginWrite = false ;

         boolean endWrite = false ;

         while ((line = bufferReader.readLine()) != null ) {

            if (line.indexOf(PriceDomainBean. class .getName()) != -1) {

                if (!beginWrite) {

                   beginWrite = true ;

                } else {

                   endWrite = true ;

                }

            }

            if (beginWrite) {

                o.write((line + "\r\n" ).getBytes());

            }

            if (endWrite) {

                break ;

            }

         }

      } catch (IOException e) {

         throw e;

      } finally {

         if null != o) {

            o.close();

         }

         in.close();

         if null != bufferReader) {

            bufferReader.close();

         }

      }

      HttpServletResponse response = RWT.getResponse ();

      response.setContentType( "text/html;charset=UTF-8" );

      response.getWriter().write(

            "<br><br><br><DIV align=center><h2> 上傳成功 !</h2>" );

   }

}

二 下載

下載和上傳採用的方式基本相同,只不過是將伺服器檔案讀取到本地,和上傳是一個相反的過程。

1 在伺服器端註冊相應的 handler

  // 註冊下載處理事件

  IServiceManager manager = RWT.getServiceManager ();

  IServiceHandler downloadHandler = new DownloadServiceHandler();

  manager.registerServiceHandler( "downloadServiceHandler" , downloadHandler);

2 在客戶端節本的呼叫

在 bowser 控制元件中書寫 js 請求指令碼,指令碼請求的 url 如下

    private String createDownloadUrl(String fileName) {

        StringBuffer url = new StringBuffer();

        url.append (RWT.getRequest ().getContextPath());

        url.append (RWT.getRequest ().getServletPath());

        url.append ( "?" );

        url.append (IServiceHandler. REQUEST_PARAM );

        url.append ( "=downloadServiceHandler" );

        url.append ( "&fileName='+encodeURI('" );

        url.append (fileName);

        url.append ( "')" );

        return url.toString();

    }

3 伺服器端 handler 的寫法

public class DownloadServiceHandler implements IServiceHandler {

   public void service() throws IOException, ServletException {

      String fileName = URLDecoder.decode (

            RWT.getRequest ().getParameter( "fileName" ), "UTF-8" );

      String filePathAndName = null ;

      try {

         filePathAndName = FileUtil

         .getTempFilePathAndName (RWT.getRequest ().getSession()

                      .getAttribute( "userName" ).toString(), fileName);

      } catch (Exception e) {

         throw new IOException(e);

      }

      File file = new File(filePathAndName);

      if (!file.exists()) {

         return ;

      }

      HttpServletResponse response = RWT.getResponse ();

      response.setHeader( "pragma" , "no-cache" );

      response.setHeader( "cache-control" , "no-cache" );

      response.setDateHeader( "Expires" , 0);

      response.setCharacterEncoding( "UTF-8" );

      response.setContentType( "text/html;charset=UTF-8" );

      response.setHeader( "Content-Disposition" , "attachment;filename="

            + new String(fileName.getBytes( "gb2312" ), "ISO8859-1" ));

      try {

         BufferedInputStream in = new BufferedInputStream(

                new FileInputStream(filePathAndName));

         ByteArrayOutputStream out = new ByteArrayOutputStream(1024);

         byte [] temp = new byte [1024];

         int size = 0;

         while ((size = in.read(temp)) != -1) {

            out.write(temp, 0, size);

         }

         in.close();

         byte [] content = out.toByteArray();

         response.setContentLength(content. length );

         response.getOutputStream().write(content);

      } catch (IOException ioe) {

         throw new RuntimeException(ioe);

      } finally {

         try {

            FileUtil.deleteTempFile (RWT.getRequest ().getSession()

                   .getAttribute( "userName" ).toString(), fileName);

         } catch (Exception e) {

            throw new IOException(e);

         }

      }

   }

}

 平常進行 rap 程式開發一般都是在 win 下面完成 , 然後在 tomcat 下面測試 , 但是程式最終釋出一般都是在linux  aix 上面 , 這個時候就有能會出現一下問題,下面 2 個問題是我們把在開發中真是出現的問題,與大家一起分享下 ;

1、   圖片路徑

這個是最常用的方法,就是在 rap 中載入圖片進行顯示,剛開始我們使用的是如下程式碼

Java程式碼  收藏程式碼
  1. public static String getRoot() {  
  2.         String path = null ;  
  3.         try {  
  4.      path = FileLocator.toFileURL (Platform.getBundle (Activator. PLUGIN_ID ).getEntry( "" )).getPath();  
  5.      path = path.substring(path.indexOf( "/" ) + 1, path.length());  
  6.         }  
  7.         catch (Exception e) {  
  8.            log .error( "getRoot method :" , e);  
  9.         }  
  10.         return path;  
  11.     }  

來獲得系統的跟路徑 . 但是當程式在移植到 linux 和 aix 上面的時候發現圖片路徑全部失效 . 可以使用如下方式進行定址來獲得圖片。

Java程式碼  收藏程式碼
  1. /** 
  2.      * 獲取圖片 
  3.      * @param fileName 
  4.      *            圖片的名稱 
  5.      * @return 先從快取物件中查詢,若有直接返回,若沒有,則將圖片載入到快取中,在從快取中將圖片傳給呼叫著 
  6.      */  
  7.     public static Image getImage(String fileName) {  
  8.         Bundle bundle = Platform.getBundle ( "TelecomUI" );  
  9.         URL url = bundle.getEntry( "icons" );  
  10.         try {  
  11.             url = Platform.asLocalURL (url) ;  
  12.         }  
  13.         catch (Exception e) {  
  14.         }  
  15.         Image image = registry .get(fileName);  
  16.         if ( null != image) {  
  17.             return image;  
  18.         }  
  19.         else {  
  20.             URL fullPathString = bundle.getEntry( "icons/" + fileName);  
  21.             ImageDescriptor des = ImageDescriptor.createFromURL (fullPathString);  
  22.             registry .put(fileName, des);  
  23.             return ImageDescriptor.createFromURL (fullPathString).createImage();  
  24.         }  
  25.     }   

2、   獲得螢幕的解析度

因為需要把一些彈出的元件居中顯示 , 這個時候就需要獲得系統的解析度

剛開始我們使用的方法如下;

Java程式碼  收藏程式碼
  1. screenH = Toolkit.getDefaultToolkit().getScreenSize ().height;  
  2.         screenW = Toolkit.getDefaultToolkit().getScreenSize ().width;   

上面這段程式碼在 window 下面是沒有問題的 , 可是到了 linux 和 aix 下面就報錯了 , 找不到

sun.awt.X11.XToolkit 類

可以採用如下方式來獲得螢幕的解析度     

Java程式碼  收藏程式碼
  1. DisPlay.getDefault().getClientArea();  

3、   其他如果有發現不相容會陸續補充