nighty

          折騰的年華
          posts - 37, comments - 143, trackbacks - 0, articles - 0

              ActionSet是Eclipse RCP里面一非常重要的概念,因為菜單、工具欄、上下文菜單、狀態(tài)欄很多操作都是共享的,所以Action就是用來處理重復(fù)出現(xiàn)的東西。至于Eclipse里面定義ActionSet有非常多的技巧,可能無法一一列舉,而且使用方法也多種多樣。下面介紹的是RssOwl2項目的ui源代碼部分的一小塊。
             1.  菜單的插入點(diǎn) -- GroupMarker和Separator的使用
                  ApplicationActionBarAdvisor類是定義全局所有Action插入點(diǎn)和入口,查看fillMenuBar(IMenuManager)方法,為了簡化,以其中的輔助方法createFileMenu(IMenuManager)為例,講述一下實(shí)現(xiàn)菜單“文件”的內(nèi)容,先看一下菜單的結(jié)構(gòu)

                 像Close,Import...之類的非常簡單,看一下它是如何實(shí)現(xiàn)New這個子菜單的。首先看一下它的源代碼如何定義插入點(diǎn)
               
          /* Menu: File */
            
          private void createFileMenu(IMenuManager menuBar) {
              MenuManager fileMenu 
          = new MenuManager("&File", IWorkbenchActionConstants.M_FILE);
              menuBar.add(fileMenu);

              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.FILE_START));
              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.NEW_EXT));
              fileMenu.add(
          new Separator());

              fileMenu.add(getAction(ActionFactory.CLOSE.getId()));
              fileMenu.add(getAction(ActionFactory.CLOSE_ALL.getId()));
              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.CLOSE_EXT));
              fileMenu.add(
          new Separator());
              fileMenu.add(getAction(ActionFactory.SAVE_AS.getId()));
              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.SAVE_EXT));
              fileMenu.add(
          new Separator());
              fileMenu.add(getAction(ActionFactory.PRINT.getId()));

              fileMenu.add(
          new Separator());
              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));

              fileMenu.add(fReopenEditors); 
          // TODO Consider moving into a "Go" Menu!

              fileMenu.add(
          new Separator());
              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.FILE_END));
              fileMenu.add(
          new Separator());

              fileMenu.add(getAction(ActionFactory.QUIT.getId()));
            }
                 其中有一行fileMenu.add(new GroupMarker(IWorkbenchActionConstants.NEW_EXT)); 這里是定義一個GroupMarker作為組標(biāo)記,把子菜單New容納進(jìn)來。這個NEW_EXT的值是:new.ext
                現(xiàn)在跳回到plugin.xml去看一下它的ActionSet定義,結(jié)構(gòu)如下:
          ,點(diǎn)擊New(menu),它的path值為:file/new.ext,這個路徑就是在createFileMenu方法定義的路徑,第一個是“File”本身的ID。也就是把子菜單New(menu)插入到指定的那個GroupMarker,ID為new.ext。然后定義了三個ID分別為bookmark,newsbin,searchmark,的groupmarker和一個folder的separator,這個三ID分別就對應(yīng)上面actionSet定義的三個action,以其中的Bookmark(action)為例,它的menubarPath為:file/new_sub/bookmark,代表插入到"File"主菜單中定義的new_sub子菜單中,new_sub是New(menu)的ID。因為folder是定義為separator,所以它會有一條分隔線。這只是RssOwl的定義方法,其實(shí)以前自己做開發(fā)的時候是沒有這樣定義的,而且把子菜單New也寫在方法fillMenuBar中的,菜單把ID都寫在里面,ActionSet的配置就沒有子菜單出現(xiàn)了,但是這樣定義看起來就比較亂。采用這種寫法感覺比較簡潔。
              2.  Action的實(shí)現(xiàn)
                 仍以bookmark為例,它的實(shí)現(xiàn)類是NewBookMarkAction,實(shí)現(xiàn)了IWorkbenchWindowActionDelegate, IObjectActionDelegate二個接口,第一個是ActionSet指定實(shí)現(xiàn)接口,第二個是對象操作菜單要求實(shí)現(xiàn)的接口(但事實(shí)發(fā)現(xiàn)沒有再定義它的配置,可能是internal版本的原因),也就是說這個Action是多功能,它將會出現(xiàn)在主菜單,工具欄,和局部的右鍵菜單上。主菜單和工具欄的位置都在ActionSet配置定義了,看看它的右鍵菜單實(shí)現(xiàn)是在哪里的,這個右鍵是在視圖Bookmarks定義的,那么跳轉(zhuǎn)到org.rssowl.ui.internal.views.explorer.BookMarkExplorer類去看看。里面有一個hookContextualMenu()方法,就是定義它的右鍵菜單的,看一下代碼實(shí)現(xiàn):
          private void hookContextualMenu() {
              MenuManager manager 
          = new MenuManager();

              
          /* New Menu */
              MenuManager newMenu 
          = new MenuManager("New");
              manager.add(newMenu);

              
          /* New BookMark */
              newMenu.add(
          new Action("Bookmark"{
                @Override
                
          public void run() {
                  IStructuredSelection selection 
          = (IStructuredSelection) fViewer.getSelection();
                  IFolder parent 
          = getParent(selection);
                  IMark position 
          = (IMark) ((selection.getFirstElement() instanceof IMark) ? selection.getFirstElement() : null);
                  
          new NewBookMarkAction(fViewSite.getShell(), parent, position).run(null);
                }


                @Override
                
          public ImageDescriptor getImageDescriptor() {
                  
          return OwlUI.BOOKMARK;
                }

              }
          );

             
          //其它定義
          }
               原來實(shí)現(xiàn)也很簡單,只是往MenuManager里面添加一個Action而已,而且run方法就是直接調(diào)用定義好的NewBookMarkAction的run方法,但是把選中對象做為參數(shù)傳進(jìn)去,因為這個new是涉及當(dāng)前上下文選擇對象的。
              3. 下拉類型的工具按鈕定義
              非常常見的Dropdown類型的工具欄按鈕可以把功能類型的按鈕歸為一類,做成一個下拉菜單形式,有默認(rèn)的按下功能,也有可以選擇其它類似功能的下三角形式,樣子如下:

              這個dropdown的Action是定義在ActionSet配置里的。style是pulldown類型的,所以實(shí)現(xiàn)類NewTypeDropdownAction實(shí)現(xiàn)了IWorkbenchWindowPulldownDelegate接口,它的run方法就是定義默認(rèn)點(diǎn)擊不做選擇時的事情,這個下拉菜單是實(shí)現(xiàn)getMenu(Control parent)方法而來,它定義了如何生成這個菜單,這就用到了最原始的SWT中的MenuItem了,并且為它們添加SelectionListener,方法實(shí)現(xiàn),不用說都知道了,又是New一個先前定義好的NewBookMarkAction類,然后又是調(diào)用它的run方法。所以總結(jié)一下,Action的重用不一定是這個類的重用,關(guān)鍵是它的run方法的重用,在不同的場景下它的外在表現(xiàn)形式可能會多種多樣,但是它的run內(nèi)容是一致的。像添加這種添加的run大部分時候都是彈出一個對話框,而對話框大都又是Winzard類型的,因為Winzard可以共享放到dialog里面。所以這種復(fù)用的思想在Eclipse里面隨處可見。
             歸結(jié)一下,其實(shí)這些技巧都是次要的,因為做GUI一個比較痛苦的事情就是經(jīng)常要寫很多重復(fù)類似的代碼,抽取的不好,可能就變得不倫不類了。怎么利用它的這種思想,把復(fù)用的代碼都抽取在一起,而閱讀起來又比較輕松才是關(guān)鍵。
             知道的就這些,先介紹到這里,下次再談?wù)勂渌碌陌l(fā)現(xiàn)。

          posted @ 2008-08-21 11:29 寒武紀(jì) 閱讀(1804) | 評論 (0)編輯 收藏

               摘要:     許久沒有弄RCP了,剛好近來閑暇一點(diǎn),找來個RSSOwl的源代碼看看,有點(diǎn)收獲。RssOwl非常出名,只是可能很多人不知道它是用Java做的。以前看過RssOwl第一版的源碼,沒有詳細(xì)研究,down下來之后放上公司的共享CVS服務(wù)器,倒是幾個同事饒有興趣地研究起來。第一個版本寫得較早,可能Eclipse的RCP框架都還沒有出來,所以全部采用的SWT/JFace...  閱讀全文

          posted @ 2008-07-31 15:13 寒武紀(jì) 閱讀(2089) | 評論 (5)編輯 收藏

              最近一個程序出了點(diǎn)問題,對于中文參數(shù)的GET請求,服務(wù)器無法解析出正確的參數(shù)。剛好服務(wù)器的那端是另一個項目組負(fù)責(zé),是異構(gòu)系統(tǒng),當(dāng)初測試的時候也是走流程化,涉及到很多工作上的協(xié)調(diào)就比較麻煩,測試也不充分,像趕鴨子上架一樣就上線了,催說是項目緊急。當(dāng)然這是話外,不多廢話。
              httpClient的GetMethod類加入?yún)?shù)的方法是如下:
          void setQueryString(NameValuePair[] params)
                    Sets the query string of this HTTP method.
           void setQueryString(String queryString)
             跟蹤一下httpClient的GetMethod的源代碼,繼承自HttpMethodBase,源碼如下:
            
          public void setQueryString(String queryString) {
             
          this.queryString = queryString;
          }

              
          public void setQueryString(NameValuePair[] params) {
             LOG.trace(
          "enter HttpMethodBase.setQueryString(NameValuePair[])");
             queryString 
          = EncodingUtil.formUrlEncode(params, "UTF-8");
          }
             EncodingUtil是httpClient定義的一個編碼工具類,由于默認(rèn)設(shè)置的是UTF-8,所以對于一些系統(tǒng)可能就無法識別??梢栽谕獠窟@樣更改:
          method.setQueryString(EncodingUtil.formUrlEncode(pair, "GB2312"));另外,注意請求頭也要修改為對應(yīng)的一致編碼方式,method.addRequestHeader("Content-type" , "text/html; charset=GB2312");如果這二個編碼不一致,就會引起亂碼。
             剛開始的時候嘗試過都使用一致的UTF-8,但是發(fā)現(xiàn)還是亂碼,這應(yīng)該是服務(wù)器的原因。IE默認(rèn)的就是采用操作系統(tǒng)Windows的中文編碼去進(jìn)行Encoder的,服務(wù)器原先基本上都為IE服務(wù)的,所以改為GB2312就能正常識別得到。
             另外,上面提到的EncodingUtil這個工具是從apache的另一個組件codec包裝而來的,而非SUN的URLEncoder。有興趣的可以研讀一下源代碼。

          posted @ 2008-07-16 10:31 寒武紀(jì) 閱讀(5209) | 評論 (2)編輯 收藏

          Jakarta的httpclient3.1是最新版本,項目中需要用程序模擬瀏覽器的GET和POST動作。在使用過程中遇到不少問題。
          1. 帶附件的POST提交
              最開始都是使用MultipartPostMethod這個類,現(xiàn)在已經(jīng)廢棄這個類了。API說明:Deprecated. Use MultipartRequestEntity in conjunction with PostMethod instead.   使用PostMethod可以實(shí)現(xiàn)的功能,就沒有必要再弄一個MultipartPostMethod了。下面是一段最簡單的示例:

          PostMethod post = new PostMethod();
                  NameValuePair[] pairs 
          = new NameValuePair[2];
                  pairs[
          0= new NameValuePair("para1""value1");
                  pairs[
          0= new NameValuePair("para2""value2");
                  post.setRequestBody(pairs);
                  HttpClient client 
          = new HttpClient();
                  
          try {
                      client.executeMethod(post);
                  }
           catch (HttpException e) {
                      e.printStackTrace();
                  }
           catch (IOException e) {
                      e.printStackTrace();
                  }
             這是針對一般的form形式的提交,而且這個form里面不帶附件的。如果帶附件,那么這種方法就不起作用,附件上傳的參數(shù)和普通參數(shù)無法一同在服務(wù)器獲取到。org.apache.commons.httpclient.methods.multipart 這個包就是為處理文件上傳這種多形式參數(shù)的情況的。最主要的類是Part(代表一種post object),它有二個比較重要的子類:FilePart和StringPart,一個是文件的參數(shù),另一個就是普通的文本參數(shù)。它的典型使用方法如下:
          String url = "http://localhost:8080/HttpTest/Test";
                   PostMethod postMethod 
          = new PostMethod(url);
                   
                   StringPart sp 
          = new StringPart("TEXT""testValue");
                   FilePart fp 
          = new FilePart("file""test.txt"new File("./temp/test.txt"));
                   
                   MultipartRequestEntity mrp
          = new MultipartRequestEntity(new Part[]{sp, fp}, postMethod
                           .getParams());
                   postMethod.setRequestEntity(mrp);
                   
                   
          //執(zhí)行postMethod
                   HttpClient httpClient = new HttpClient();
                   
          try {
                      httpClient.executeMethod(postMethod);
                  }
           catch (HttpException e) {
                      e.printStackTrace();
                  }
           catch (IOException e) {
                      e.printStackTrace();
                  }
              在第二行PostMethod postMethod = new PostMethod();后面,有人說需要使用postMehtod.setRequestHeader("Content-type", "multipart/form-data"); Content-type的請求類型進(jìn)行更改。但是我在使用過程沒有加上這一句,查了一下httpCleint的默認(rèn)Content-type是application/octet-stream。應(yīng)該是沒有影響的。對于MIME類型的請求,httpclient建議全用MulitPartRequestEntity進(jìn)行包裝,就是上面的用法。

          2.  參數(shù)中文的處理問題
              httpclient的默認(rèn)編碼都是ISO-8859-1,那肯定就無法支持中文參數(shù)了。引用一下這篇文章:http://thinkbase.net/w/main/Wiki?HttpClient+POST+%E7%9A%84+UTF-8+%E7%BC%96%E7%A0%81%E9%97%AE%E9%A2%98 ,按照作者的說法,就可以正常解決中文編碼的問題。其中最關(guān)鍵的是修改EncodingUtil這個類的一個方法實(shí)現(xiàn)。另外,F(xiàn)ilePart和StringPart的構(gòu)造方法都有一個帶編碼指定的參數(shù),為了減少問題的出現(xiàn),建議所有的都帶上統(tǒng)一的編碼,包括postMethod.getParams()。示例如下:
          String url = "http://localhost:8080/HttpTest/Test";
                   PostMethod postMethod 
          = new PostMethod(url);
                   
                   StringPart sp 
          = new StringPart("TEXT""testValue""GB2312");
                   FilePart fp 
          = new FilePart("file""test.txt"new File("./temp/test.txt"), null"GB2312");
                   
                   postMethod.getParams().setContentCharset(
          "GB2312");
                   MultipartRequestEntity mrp
          = new MultipartRequestEntity(new Part[]{sp, fp}, postMethod
                           .getParams());
                   postMethod.setRequestEntity(mrp);
                   
                   
          //執(zhí)行postMethod
                   HttpClient httpClient = new HttpClient();
                   
          try {
                      httpClient.executeMethod(postMethod);
                  }
           catch (HttpException e) {
                      e.printStackTrace();
                  }
           catch (IOException e) {
                      e.printStackTrace();
                  }

          posted @ 2008-06-11 15:18 寒武紀(jì) 閱讀(6932) | 評論 (8)編輯 收藏

             1. 先下載VMWare Tools for linux,下面是一個下載鏈接 http://vmware.cn/Soft/UploadSoft9f4/VMware%20Workstation%206.02%C2%CC%C9%AB%BE%AB%BC%F2%D3%A2%CE%C4%B0%E6/vmware_tools_linux.rar
             2. 解壓出一個linux.iso文件,這個就是tools工具的安裝光盤鏡像。事先你必須正確安裝了Linux,我安裝的ubuntu8.04,在VM上點(diǎn)擊“編輯虛擬機(jī)設(shè)置”,CD-ROM方式改為“使用ISO鏡像”,選擇linux.iso,確定
             3. 啟動你的虛擬機(jī)操作系統(tǒng),然后切換出來鼠標(biāo),選擇主菜單“虛擬機(jī)”--> “安裝VMware Tools”,ubuntu會自動搜索到該CDROM,直接打個桌面的圖標(biāo)即可??梢钥吹蕉€文件:VMwareTools-xxx-i386.rpm和VMwareTools- xxx.tar.gz。rpm是RedHat的安裝包,這里我們應(yīng)該使用gz文件,把這個gz文件直接復(fù)制到桌面,解壓,生成一個-tools-distrib 目錄。
             4. 打開終端,跳桌面這個-tools-distrib 目錄。輸入下面的命令:$ sudo ./-install.pl(回車后會提示輸入你的密碼,并且密碼不會顯示出來,表明你將以更高級權(quán)限執(zhí)行一個動作——安裝軟件;再次回車后安裝開始)
             5. 安裝過程會有一系列的問題確認(rèn),類似windows的安裝向?qū)崾?,一路回車下去,采用默認(rèn)方式就可以。
             6. 最后安裝成功會提示選擇桌面環(huán)境的默認(rèn)分辨率。分辨率可以以后再調(diào)整。
             7. 安裝后鼠標(biāo)的滑輪可能不好使了。我們這樣解決這個問題,還是打開終端,輸入:$ sudo gedit /etc/X11/xorg.conf   這個命令使系統(tǒng)以root權(quán)限打開鼠標(biāo)配置文件/etc/X11/xorg.conf。把文件中的 Option “Protocol” “ps/2”改成 Option “Protocol” “IMPS/2” 。保存,然后重新啟動ubuntu。

             補(bǔ)充:關(guān)于VMware安裝ubuntu8.04和VMware tools以后,真實(shí)系統(tǒng)和虛擬系統(tǒng)的文件共享仍存在問題的,無法直接從外部的windows拖文件放入虛擬系統(tǒng)里面。掛載U盤或是分區(qū)也比較麻煩。后來想可以利用光驅(qū),自己把要共享的文件制作成Windows下面的ISO文件,然后裝截入光驅(qū),直接在虛擬光驅(qū)里面打開,就可以直接操作。

          posted @ 2008-06-03 17:27 寒武紀(jì) 閱讀(6872) | 評論 (3)編輯 收藏

             Eclipse3.3出來很久了,一直都使用英文版,剛好看到有網(wǎng)友介紹Eclipse的一個Project,叫Babel,官方的描述這樣:Eclipse is a global community. It is in everyone's interest to ensure that Eclipse is available and translated in as many locales as possible. 項目的主頁地址是:http://www.eclipse.org/babel/ 。按照說明從這里可以下載安裝到語言包。
             直接從Eclipse3.3的菜單"Help --> Software Updates --> Find and Insatll...",新建一個遠(yuǎn)程站點(diǎn),URL為 http://download.eclipse.org/technology/babel/update-site/ ,然后直接在線安裝。在彈出的語言選擇界面上選擇中文簡體。如下圖:
             

              網(wǎng)絡(luò)情況如果正常的話,安裝應(yīng)該不會有問題的,中間可能會彈出幾次下載jar文件失敗的對話框,繼續(xù)retry就行。
             
              最后重啟一下,可以看到都變成中文界面的。
             
           
            原來是3.3的Eclipse,怎么變成3.2呢?原因估計是語言插件的版本是3.2的導(dǎo)致的,所以你看到有一些地方漢化并不完全,像Error Log視圖的標(biāo)題,項目右鍵菜單,以及一些頂級菜單都沒有完全漢化。
            希望以后Babel項目后面更新跟得上主版本的變化,不過習(xí)慣了英文版的,其實(shí)也是差不多的。

          posted @ 2008-05-30 15:44 寒武紀(jì) 閱讀(13946) | 評論 (13)編輯 收藏

             普通的程序交互方式有命令行和GUI形式。對于GUI樣式,交互的設(shè)計可以多種多樣,但是Java做命令行交互,似乎存在著一些不足。
             命令行交互是傳統(tǒng)的交互方式,如果程序有時候需要在Unix或是Linux等系統(tǒng)上運(yùn)動時,以這種方式出現(xiàn)的可能性就比較大。命令行包括
             輸入和回顯問題,一般是以行結(jié)束,或是以某個結(jié)束符為終命令終止標(biāo)識。System.out 和System.err就用于標(biāo)準(zhǔn)的輸出和錯誤輸出,System.in用于標(biāo)準(zhǔn)的輸入接受,一般情況下都是指鍵盤。
             如果接受參數(shù)輸入,一般的程序結(jié)構(gòu)如下:
            
          BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
          System.out.println(
          "==Please input password==:");
          String pass 
          = in.readLine();
             輸入的時候顯示屏自動進(jìn)行輸入回顯。這個時候如果遇到輸入密碼等敏感數(shù)據(jù)的時候,就無法用*或是#這樣的符號進(jìn)行回顯屏蔽,容易暴露安全問題。
             解決的可能想法:
             1.  通過監(jiān)聽鍵盤事件,對輸入的回顯進(jìn)行截獲取,把回顯進(jìn)行屏蔽,但是監(jiān)聽器如何知道何時是輸入密碼,何時是輸入普通數(shù)據(jù)?比較難以控制,而且這種監(jiān)聽?wèi)?yīng)該是線程化的,可能會存在一些意想不到的問題。
             2.  如果用純Java難以實(shí)現(xiàn),那么是否可以使用其它語言的功能進(jìn)行補(bǔ)充,比如JNI,或是Windows下面的Dos腳本,Linux平臺的Shell腳本來進(jìn)行補(bǔ)充。不過這樣就不太平臺無關(guān)了。
             3.  可能sun發(fā)現(xiàn)了這個不足之處,從1.6版本開始,增加了一個java.io.Console類,代表與當(dāng)前 Java 虛擬機(jī)關(guān)聯(lián)的基于字符的控制臺設(shè)備,這個Console是對原來System.in這種不足的補(bǔ)充,提供了像readPassword()等這樣的實(shí)用方法,具體請參考API文檔,就是專門用于對敏感信息的讀取。但是這是基于Java1.6的,如果有些場景受限制,不能使用1.6,那么還是無法解決上面的問題。后來查閱了一下Console類的實(shí)現(xiàn)方式,想直接把它的實(shí)現(xiàn)方式移植到1.4.xx上是比較難的,因為用到了一些高版本的新特性。使用Console要注意的是:虛擬機(jī)是否具有控制臺取決于底層平臺,還取決于調(diào)用虛擬機(jī)的方式。如果虛擬機(jī)從一個交互式命令行開始啟動,且沒有重定向標(biāo)準(zhǔn)輸入和輸出流,那么其控制臺將存在,并且通常連接到鍵盤并從虛擬機(jī)啟動的地方顯示。如果虛擬機(jī)是自動啟動的(例如,由后臺作業(yè)調(diào)度程序啟動),那么它通常沒有控制臺。如果你在Eclipse里面啟動程序調(diào)用Console,那么通常是沒有控制臺,還是得從外部的命令行方式才能調(diào)用得到。
             總體想一下,感覺應(yīng)該還是從第2點(diǎn)出發(fā),犧牲掉一點(diǎn)通用性,這樣才能滿足這種功能需求。

          posted @ 2008-05-23 09:41 寒武紀(jì) 閱讀(4135) | 評論 (1)編輯 收藏

              剛好最近項目中需要用到一點(diǎn)加密的東西,java安全類庫提供了一個java.security.MessageDigest類,此 MessageDigest 類為應(yīng)用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的單向哈希函數(shù),它接收任意大小的數(shù)據(jù),并輸出固定長度的哈希值。有現(xiàn)成的當(dāng)然是最好的,省事省力。
              MD5的非常有實(shí)際應(yīng)用性。有網(wǎng)友給出這樣的描述,可以參照一下:http://blog.csdn.net/Daping_Zhang/archive/2005/05/28/382688.aspx
               該類的getInstance(String algorithm) 方法返回一個MessageDigest的實(shí)體,加密的一系統(tǒng)的digest()方法和update(byte input)方法。加密后返回一個byte[],16位,我們經(jīng)常見到很多開源網(wǎng)站的下載地址會有一個[md5]的鏈接,打開其實(shí)就是一小段文本內(nèi)容。例如:
              MD5 (commons-logging-1.1.1-bin.zip) = f88520ed791673aed6cc4591bc058b55
              這是Jakarta的logging組件下載時提供的MD5摘要信息,是對這個zip包進(jìn)行全文加密生成的摘要,摘要碼就是后面的f88520ed791673aed6cc4591bc058b55,如果你下載以后,按照MD5的算法生成自己的摘要,如果這二個摘要一樣,就證明這個文件是沒有被人篡改過的。
              遇到的問題是Java的MessageDigest類執(zhí)行后返回的byte[16]得轉(zhuǎn)換成十六進(jìn)制的字符串,如果直接用new String(byte[]),得到的結(jié)果將是不正確的。算法有很多網(wǎng)友提供了,照搬了。比較有趣的是,commons-logging提供的那個MD5居然和我自己生成的不一樣(難道文件被修改過?),后來嘗試了其它地方提供的MD5碼,都沒有問題。
              有很多相關(guān)的現(xiàn)成代碼,搜集了一下整理如下(經(jīng)過驗證):

          public class MD5Builder {

              
          static Logger logger = Logger.getLogger(MD5Builder.class);
               
          // 用來將字節(jié)轉(zhuǎn)換成 16 進(jìn)制表示的字符
              static char hexDigits[] = '0''1''2''3''4''5''6''7''8',
                      
          '9''a''b''c''d''e''f' }

              
              
          /**
               * 對文件全文生成MD5摘要
               * 
          @param file   要加密的文件
               * 
          @return MD5摘要碼
               
          */

              
          public static String getMD5(File file) {
                  FileInputStream fis 
          = null;
                  
          try {
                      MessageDigest md 
          = MessageDigest.getInstance("MD5");

                      logger.info(
          "MD5摘要長度:" + md.getDigestLength());
                      fis 
          = new FileInputStream(file);
                      
          byte[] buffer = new byte[2048];
                      
          int length = -1;
                      logger.info(
          "開始生成摘要");
                      
          long s = System.currentTimeMillis();
                      
          while ((length = fis.read(buffer)) != -1{
                          md.update(buffer, 
          0, length);
                      }

                      logger.info(
          "摘要生成成功,總用時: "
                              
          + (System.currentTimeMillis() - s) + "ms");
                      
          byte[] b = md.digest();
                      
          return byteToHexString(b);
                      
          // 16位加密
                      
          // return buf.toString().substring(8, 24);
                  }
           catch (Exception ex) {
                      logger.error(ex);
                      ex.printStackTrace();
                      
          return null;
                  }
          finally {
                      
          try {
                          fis.close();
                      }
           catch (IOException ex) {
                          ex.printStackTrace();
                      }

                  }

              }


              
          /**
               * 對一段String生成MD5加密信息
               * 
          @param message 要加密的String
               * 
          @return 生成的MD5信息
               
          */

              
          public static String getMD5(String message){
                  
          try {
                      MessageDigest md 
          = MessageDigest.getInstance("MD5");
                      logger.info(
          "MD5摘要長度:" + md.getDigestLength());
                      
          byte[] b = md.digest(message.getBytes());
                      
          return byteToHexString(b);
                  }
           catch (NoSuchAlgorithmException e) {
                      logger.error(e);
                      e.printStackTrace();
                      
          return null;
                  }

              }

              
              
          /**
               * 把byte[]數(shù)組轉(zhuǎn)換成十六進(jìn)制字符串表示形式
               * 
          @param tmp    要轉(zhuǎn)換的byte[]
               * 
          @return 十六進(jìn)制字符串表示形式
               
          */

              
          private static String byteToHexString(byte[] tmp) {
                  String s;
                  
          // 用字節(jié)表示就是 16 個字節(jié)
                  char str[] = new char[16 * 2]; // 每個字節(jié)用 16 進(jìn)制表示的話,使用兩個字符,
                  
          // 所以表示成 16 進(jìn)制需要 32 個字符
                  int k = 0// 表示轉(zhuǎn)換結(jié)果中對應(yīng)的字符位置
                  for (int i = 0; i < 16; i++// 從第一個字節(jié)開始,對 MD5 的每一個字節(jié)
                      
          // 轉(zhuǎn)換成 16 進(jìn)制字符的轉(zhuǎn)換
                      byte byte0 = tmp[i]; // 取第 i 個字節(jié)
                      str[k++= hexDigits[byte0 >>> 4 & 0xf]; // 取字節(jié)中高 4 位的數(shù)字轉(zhuǎn)換, 
                      
          // >>> 為邏輯右移,將符號位一起右移
                      str[k++= hexDigits[byte0 & 0xf]; // 取字節(jié)中低 4 位的數(shù)字轉(zhuǎn)換
                  }

                  s 
          = new String(str); // 換后的結(jié)果轉(zhuǎn)換為字符串
                  return s;
              }

          }

            

          posted @ 2008-05-08 15:02 寒武紀(jì) 閱讀(6545) | 評論 (2)編輯 收藏

              一般而言,我們平常接觸的大多數(shù)項目都應(yīng)該是單純使用B/S或是C/S,除非在特殊場合,否則比較少混合使用B/S,C/S架構(gòu)。首先說一下對這二種架構(gòu)特點(diǎn)的一些個人理解。B/S應(yīng)該是目前很多項目都應(yīng)用的架構(gòu),瀏覽器的方式使得用戶的使用十分方便,用戶可以何時何地通過Internet訪問URL而進(jìn)行相應(yīng)的工作,升級維護(hù)也能比較集中,缺點(diǎn)就是瀏覽器的表現(xiàn)能力受限以及常常受非議的安全性問題,如果軟件的應(yīng)用范圍區(qū)域不集中,而且用戶經(jīng)常變換地點(diǎn)進(jìn)行訪問,那么這種架構(gòu)是非常適合的。C/S架構(gòu)的C端有非常強(qiáng)的處理能力,所以在交互表現(xiàn)和安全方面可以做得比瀏覽器強(qiáng),但是缺點(diǎn)也是非常明顯的,安裝部署、升級維護(hù)、版本兼容都是比較頭大的事情,一般的適用場景是集中的辦公室場所,用戶使用范圍相對穩(wěn)定,以及一些對業(yè)務(wù)處理非常復(fù)雜的場合,為了降低服務(wù)器的負(fù)荷,同樣需要C模式的支持。
              以前接觸過的電信領(lǐng)域,就有過混合架構(gòu)的軟件。但是都是非常寵大,一直都對其實(shí)現(xiàn)方案比較感興趣,但是都沒有機(jī)會進(jìn)一步了解。最近搜索了一下相關(guān)的資料,總結(jié)一下混合應(yīng)用的一些想法(只針對Java方向)。
              ①混合架構(gòu)的問題集中點(diǎn)。服務(wù)端共享,客戶端采用不同的表現(xiàn)方式,共享的應(yīng)該是業(yè)務(wù)層接口,持久層應(yīng)該是屏蔽的。應(yīng)用層的消息傳遞就是整個應(yīng)用的關(guān)鍵所在,雖然像Jakarta提供的httpClient這種模仿瀏覽器的組件,但是畢竟是模仿,在很多方面的功能還是缺失的。
              ②最傳統(tǒng)的方式是采用EJB做為服務(wù),這個寵然大物容易讓人害怕,不過在分布式的系統(tǒng)中它還是有應(yīng)用優(yōu)勢的,像電信和金融這種行業(yè)應(yīng)用還是比較廣的,而且現(xiàn)成的中間件和應(yīng)用服務(wù)器商都比較多,像Oracel、BEA、IBM、Sun都有成熟的應(yīng)用產(chǎn)品,當(dāng)然開發(fā)的成本和人力投入也是恐龍級數(shù)據(jù)的。
              ③有網(wǎng)友說在C端直接訪問數(shù)據(jù)庫,B/S結(jié)構(gòu)不變,也就是通過數(shù)據(jù)庫進(jìn)行共享。這種方式是不可取的,二個缺點(diǎn):把服務(wù)器的業(yè)務(wù)邏輯搬到了C端上,嚴(yán)格上講是不安全的,升級維護(hù)也非常麻煩;并發(fā)控制的壓力都在數(shù)據(jù)庫上。
              ④采用RMI,這個老古董相信應(yīng)該很多人都不使用了,因為它的使用要一連串的手續(xù),比如服務(wù)接口定義必須實(shí)現(xiàn)Remote接口,服務(wù)Server在實(shí)現(xiàn)時必須繼承UnicastRemoteobject類,必須使用rmic指令產(chǎn)生stub和skeleton等,設(shè)置上繁雜。
              ⑤Spring 遠(yuǎn)程服務(wù)。這個應(yīng)該說是比較可取的,大家都比較喜歡輕量級的東西。就如第一點(diǎn)所說的,通過遠(yuǎn)程服務(wù),我們可以在客戶直接調(diào)用服務(wù)端的服務(wù)接口,就像本地調(diào)用一樣,Spring對遠(yuǎn)程服務(wù)提供了好幾種實(shí)現(xiàn)方案。
              ⑥WebService。適合異構(gòu)環(huán)境,但是WSDL的這種方式相對來說會比較耗費(fèi)資料,因為標(biāo)準(zhǔn)定義除了業(yè)務(wù)內(nèi)容外,還有許多另外的說明內(nèi)容。
              Spring遠(yuǎn)程服務(wù)實(shí)現(xiàn)方案介紹:
              ⑴Spring + RMI。Spring把傳統(tǒng)的RMI方式的繁雜設(shè)置去掉,只要配置Bean文件就和定義服務(wù)接口可以。RMI的服務(wù)啟動和管理都交給Spring來處理。RMI訪問的缺點(diǎn)就是對防火墻的穿透力比較差。
              ⑵Spring + Caucho的Hessian、Burlap。Hessian使用Http將對象以中性的二進(jìn)制消息進(jìn)行傳送,而不像RMI使用Java的序列化格式(這種序列化是專制的,不是Sun提供的序列化機(jī)制),由于是二進(jìn)制消息,所以不受限于某種實(shí)現(xiàn)語言,傳輸時所需要的帶寬較小是其優(yōu)點(diǎn)。Burlap是以XML文件格式傳送對象,XML文件有較高可讀性,應(yīng)用程序只要能解釋XML就能接收消息,當(dāng)然也不限于某種語言,但是組裝XML和解釋XML都需要消耗資源,當(dāng)傳輸大數(shù)據(jù)時性能應(yīng)該存在問題。
              ⑶Spring + Http Invoker。由于Hessian的序列化機(jī)制不是正統(tǒng)的Java序列化機(jī)制,所以當(dāng)遇到傳輸復(fù)雜的業(yè)務(wù)模型時,就會存在各種問題,為此,Spring又提供了Http Invoker,同樣是使用Http傳送對象,而且是使用Java的序列化機(jī)制。相比RMI,Http對防火墻的穿透力要強(qiáng)。
              后來嘗試了最后的這種Http Invoker方式,是在Spring2.0版本下嘗試的,開發(fā)非常簡單,網(wǎng)上也有大量的資料介紹。應(yīng)該說從這里入口可以做一些嘗試。目前遇到的一個項目就需要混合架構(gòu),B/S采用Spring2 + Struts2 + Hiberntae3,瀏覽器只提供一些查詢功能和數(shù)據(jù)展現(xiàn),C端采用Eclipse的RCP平臺,共享服務(wù)器的業(yè)務(wù)接口,調(diào)用就采用Http Invoker遠(yuǎn)程服務(wù),復(fù)雜的業(yè)務(wù)功能都集中在C端上。

          posted @ 2008-05-06 12:43 寒武紀(jì) 閱讀(13770) | 評論 (25)編輯 收藏

              1. 驅(qū)動器
                      如果安裝了DB2客戶端,則到安裝目錄下的sqllib/java目錄下面找到二個jar包:db2jcc.jar和db2jcc_license_cu.jar,把它們添加到你的classpath中去,有的人說用db2java.zip也可以連接,但是我嘗試了,總是無法連接。如果沒有這二個jar包,到網(wǎng)上搜索一下,有些網(wǎng)友已經(jīng)上傳了。驅(qū)動器名稱是:com.ibm.db2.jcc.DB2Driver。
              2. URL寫法
                     連接的URL正確寫法是:jdbc:db2://[IP地址]:[端口]/[數(shù)據(jù)庫名],例如:jdbc:db2://99.1.99.114:50000/dwsdemo,要確保URL正確,你可以先在DB2的命令行測試一下是否能正確連接上。
              有個不太明白的地方就是為什么IBM提供的驅(qū)動器包命名有的地方是大寫,比如:COM.ibm.db2.app

          posted @ 2008-04-17 11:14 寒武紀(jì) 閱讀(7282) | 評論 (8)編輯 收藏

          僅列出標(biāo)題
          共4頁: 上一頁 1 2 3 4 下一頁 
          主站蜘蛛池模板: 泗洪县| 泰安市| 松原市| 揭东县| 安吉县| 吴旗县| 海门市| 四会市| 奉节县| 鄂尔多斯市| 城口县| 定西市| 社旗县| 河津市| 山阴县| 若尔盖县| 武城县| 颍上县| 芷江| 临沭县| 沁源县| 乌苏市| 衡阳市| 抚宁县| 许昌市| 巴楚县| 莒南县| 宜宾县| 嫩江县| 遂宁市| 澄城县| 沧州市| 赣榆县| 清水河县| 尼木县| 九龙坡区| 商洛市| 霸州市| 科尔| 陕西省| 昌都县|