nighty

折腾的年华
posts - 37, comments - 143, trackbacks - 0, articles - 0

    ActionSet是Eclipse RCP里面一非常重要的概念,因为菜单、工具栏、上下文菜单、状态栏很多操作都是共享的,所以Action就是用来处理重复出现的东西。至于Eclipse里面定义ActionSet有非常多的技巧,可能无法一一列举,而且使用方法也多种多样。下面介绍的是RssOwl2项目的ui源代码部分的一小块。
   1.  菜单的插入点 -- GroupMarker和Separator的使用
        ApplicationActionBarAdvisor类是定义全局所有Action插入点和入口,查看fillMenuBar(IMenuManager)方法,为了简化,以其中的辅助方法createFileMenu(IMenuManager)为例,讲述一下实现菜单“文件”的内容,先看一下菜单的结构

       像Close,Import...之类的非常简单,看一下它是如何实现New这个子菜单的。首先看一下它的源代码如何定义插入点
     
/* 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作为组标记,把子菜单New容纳进来。这个NEW_EXT的值是:new.ext
      现在跳回到plugin.xml去看一下它的ActionSet定义,结构如下:
,点击New(menu),它的path值为:file/new.ext,这个路径就是在createFileMenu方法定义的路径,第一个是“File”本身的ID。也就是把子菜单New(menu)插入到指定的那个GroupMarker,ID为new.ext。然后定义了三个ID分别为bookmark,newsbin,searchmark,的groupmarker和一个folder的separator,这个三ID分别就对应上面actionSet定义的三个action,以其中的Bookmark(action)为例,它的menubarPath为:file/new_sub/bookmark,代表插入到"File"主菜单中定义的new_sub子菜单中,new_sub是New(menu)的ID。因为folder是定义为separator,所以它会有一条分隔线。这只是RssOwl的定义方法,其实以前自己做开发的时候是没有这样定义的,而且把子菜单New也写在方法fillMenuBar中的,菜单把ID都写在里面,ActionSet的配置就没有子菜单出现了,但是这样定义看起来就比较乱。采用这种写法感觉比较简洁。
    2.  Action的实现
       仍以bookmark为例,它的实现类是NewBookMarkAction,实现了IWorkbenchWindowActionDelegate, IObjectActionDelegate二个接口,第一个是ActionSet指定实现接口,第二个是对象操作菜单要求实现的接口(但事实发现没有再定义它的配置,可能是internal版本的原因),也就是说这个Action是多功能,它将会出现在主菜单,工具栏,和局部的右键菜单上。主菜单和工具栏的位置都在ActionSet配置定义了,看看它的右键菜单实现是在哪里的,这个右键是在视图Bookmarks定义的,那么跳转到org.rssowl.ui.internal.views.explorer.BookMarkExplorer类去看看。里面有一个hookContextualMenu()方法,就是定义它的右键菜单的,看一下代码实现:
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;
      }

    }
);

   
//其它定义
}
     原来实现也很简单,只是往MenuManager里面添加一个Action而已,而且run方法就是直接调用定义好的NewBookMarkAction的run方法,但是把选中对象做为参数传进去,因为这个new是涉及当前上下文选择对象的。
    3. 下拉类型的工具按钮定义
    非常常见的Dropdown类型的工具栏按钮可以把功能类型的按钮归为一类,做成一个下拉菜单形式,有默认的按下功能,也有可以选择其它类似功能的下三角形式,样子如下:

    这个dropdown的Action是定义在ActionSet配置里的。style是pulldown类型的,所以实现类NewTypeDropdownAction实现了IWorkbenchWindowPulldownDelegate接口,它的run方法就是定义默认点击不做选择时的事情,这个下拉菜单是实现getMenu(Control parent)方法而来,它定义了如何生成这个菜单,这就用到了最原始的SWT中的MenuItem了,并且为它们添加SelectionListener,方法实现,不用说都知道了,又是New一个先前定义好的NewBookMarkAction类,然后又是调用它的run方法。所以总结一下,Action的重用不一定是这个类的重用,关键是它的run方法的重用,在不同的场景下它的外在表现形式可能会多种多样,但是它的run内容是一致的。像添加这种添加的run大部分时候都是弹出一个对话框,而对话框大都又是Winzard类型的,因为Winzard可以共享放到dialog里面。所以这种复用的思想在Eclipse里面随处可见。
   归结一下,其实这些技巧都是次要的,因为做GUI一个比较痛苦的事情就是经常要写很多重复类似的代码,抽取的不好,可能就变得不伦不类了。怎么利用它的这种思想,把复用的代码都抽取在一起,而阅读起来又比较轻松才是关键。
   知道的就这些,先介绍到这里,下次再谈谈其它新的发现。

posted @ 2008-08-21 11:29 寒武纪 阅读(1774) | 评论 (0)编辑 收藏

     摘要:     许久没有弄RCP了,刚好近来闲暇一点,找来个RSSOwl的源代码看看,有点收获。RssOwl非常出名,只是可能很多人不知道它是用Java做的。以前看过RssOwl第一版的源码,没有详细研究,down下来之后放上公司的共享CVS服务器,倒是几个同事饶有兴趣地研究起来。第一个版本写得较早,可能Eclipse的RCP框架都还没有出来,所以全部采用的SWT/JFace...  阅读全文

posted @ 2008-07-31 15:13 寒武纪 阅读(2068) | 评论 (5)编辑 收藏

    最近一个程序出了点问题,对于中文参数的GET请求,服务器无法解析出正确的参数。刚好服务器的那端是另一个项目组负责,是异构系统,当初测试的时候也是走流程化,涉及到很多工作上的协调就比较麻烦,测试也不充分,像赶鸭子上架一样就上线了,催说是项目紧急。当然这是话外,不多废话。
    httpClient的GetMethod类加入参数的方法是如下:
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定义的一个编码工具类,由于默认设置的是UTF-8,所以对于一些系统可能就无法识别。可以在外部这样更改:
method.setQueryString(EncodingUtil.formUrlEncode(pair, "GB2312"));另外,注意请求头也要修改为对应的一致编码方式,method.addRequestHeader("Content-type" , "text/html; charset=GB2312");如果这二个编码不一致,就会引起乱码。
   刚开始的时候尝试过都使用一致的UTF-8,但是发现还是乱码,这应该是服务器的原因。IE默认的就是采用操作系统Windows的中文编码去进行Encoder的,服务器原先基本上都为IE服务的,所以改为GB2312就能正常识别得到。
   另外,上面提到的EncodingUtil这个工具是从apache的另一个组件codec包装而来的,而非SUN的URLEncoder。有兴趣的可以研读一下源代码。

posted @ 2008-07-16 10:31 寒武纪 阅读(5179) | 评论 (2)编辑 收藏

Jakarta的httpclient3.1是最新版本,项目中需要用程序模拟浏览器的GET和POST动作。在使用过程中遇到不少问题。
1. 带附件的POST提交
    最开始都是使用MultipartPostMethod这个类,现在已经废弃这个类了。API说明:Deprecated. Use MultipartRequestEntity in conjunction with PostMethod instead.   使用PostMethod可以实现的功能,就没有必要再弄一个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里面不带附件的。如果带附件,那么这种方法就不起作用,附件上传的参数和普通参数无法一同在服务器获取到。org.apache.commons.httpclient.methods.multipart 这个包就是为处理文件上传这种多形式参数的情况的。最主要的类是Part(代表一种post object),它有二个比较重要的子类:FilePart和StringPart,一个是文件的参数,另一个就是普通的文本参数。它的典型使用方法如下:
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);
         
         
//执行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的请求类型进行更改。但是我在使用过程没有加上这一句,查了一下httpCleint的默认Content-type是application/octet-stream。应该是没有影响的。对于MIME类型的请求,httpclient建议全用MulitPartRequestEntity进行包装,就是上面的用法。

2.  参数中文的处理问题
    httpclient的默认编码都是ISO-8859-1,那肯定就无法支持中文参数了。引用一下这篇文章: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 ,按照作者的说法,就可以正常解决中文编码的问题。其中最关键的是修改EncodingUtil这个类的一个方法实现。另外,FilePart和StringPart的构造方法都有一个带编码指定的参数,为了减少问题的出现,建议所有的都带上统一的编码,包括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);
         
         
//执行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 寒武纪 阅读(6889) | 评论 (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上点击“编辑虚拟机设置”,CD-ROM方式改为“使用ISO镜像”,选择linux.iso,确定
   3. 启动你的虚拟机操作系统,然后切换出来鼠标,选择主菜单“虚拟机”--> “安装VMware Tools”,ubuntu会自动搜索到该CDROM,直接打个桌面的图标即可。可以看到二个文件:VMwareTools-xxx-i386.rpm和VMwareTools- xxx.tar.gz。rpm是RedHat的安装包,这里我们应该使用gz文件,把这个gz文件直接复制到桌面,解压,生成一个-tools-distrib 目录。
   4. 打开终端,跳桌面这个-tools-distrib 目录。输入下面的命令:$ sudo ./-install.pl(回车后会提示输入你的密码,并且密码不会显示出来,表明你将以更高级权限执行一个动作——安装软件;再次回车后安装开始)
   5. 安装过程会有一系列的问题确认,类似windows的安装向导提示,一路回车下去,采用默认方式就可以。
   6. 最后安装成功会提示选择桌面环境的默认分辨率。分辨率可以以后再调整。
   7. 安装后鼠标的滑轮可能不好使了。我们这样解决这个问题,还是打开终端,输入:$ sudo gedit /etc/X11/xorg.conf   这个命令使系统以root权限打开鼠标配置文件/etc/X11/xorg.conf。把文件中的 Option “Protocol” “ps/2”改成 Option “Protocol” “IMPS/2” 。保存,然后重新启动ubuntu。

   补充:关于VMware安装ubuntu8.04和VMware tools以后,真实系统和虚拟系统的文件共享仍存在问题的,无法直接从外部的windows拖文件放入虚拟系统里面。挂载U盘或是分区也比较麻烦。后来想可以利用光驱,自己把要共享的文件制作成Windows下面的ISO文件,然后装截入光驱,直接在虚拟光驱里面打开,就可以直接操作。

posted @ 2008-06-03 17:27 寒武纪 阅读(6847) | 评论 (3)编辑 收藏

   Eclipse3.3出来很久了,一直都使用英文版,刚好看到有网友介绍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...",新建一个远程站点,URL为 http://download.eclipse.org/technology/babel/update-site/ ,然后直接在线安装。在弹出的语言选择界面上选择中文简体。如下图:
   

    网络情况如果正常的话,安装应该不会有问题的,中间可能会弹出几次下载jar文件失败的对话框,继续retry就行。
   
    最后重启一下,可以看到都变成中文界面的。
   
 
  原来是3.3的Eclipse,怎么变成3.2呢?原因估计是语言插件的版本是3.2的导致的,所以你看到有一些地方汉化并不完全,像Error Log视图的标题,项目右键菜单,以及一些顶级菜单都没有完全汉化。
  希望以后Babel项目后面更新跟得上主版本的变化,不过习惯了英文版的,其实也是差不多的。

posted @ 2008-05-30 15:44 寒武纪 阅读(13914) | 评论 (13)编辑 收藏

   普通的程序交互方式有命令行和GUI形式。对于GUI样式,交互的设计可以多种多样,但是Java做命令行交互,似乎存在着一些不足。
   命令行交互是传统的交互方式,如果程序有时候需要在Unix或是Linux等系统上运动时,以这种方式出现的可能性就比较大。命令行包括
   输入和回显问题,一般是以行结束,或是以某个结束符为终命令终止标识。System.out 和System.err就用于标准的输出和错误输出,System.in用于标准的输入接受,一般情况下都是指键盘。
   如果接受参数输入,一般的程序结构如下:
  
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.println(
"==Please input password==:");
String pass 
= in.readLine();
   输入的时候显示屏自动进行输入回显。这个时候如果遇到输入密码等敏感数据的时候,就无法用*或是#这样的符号进行回显屏蔽,容易暴露安全问题。
   解决的可能想法:
   1.  通过监听键盘事件,对输入的回显进行截获取,把回显进行屏蔽,但是监听器如何知道何时是输入密码,何时是输入普通数据?比较难以控制,而且这种监听应该是线程化的,可能会存在一些意想不到的问题。
   2.  如果用纯Java难以实现,那么是否可以使用其它语言的功能进行补充,比如JNI,或是Windows下面的Dos脚本,Linux平台的Shell脚本来进行补充。不过这样就不太平台无关了。
   3.  可能sun发现了这个不足之处,从1.6版本开始,增加了一个java.io.Console类,代表与当前 Java 虚拟机关联的基于字符的控制台设备,这个Console是对原来System.in这种不足的补充,提供了像readPassword()等这样的实用方法,具体请参考API文档,就是专门用于对敏感信息的读取。但是这是基于Java1.6的,如果有些场景受限制,不能使用1.6,那么还是无法解决上面的问题。后来查阅了一下Console类的实现方式,想直接把它的实现方式移植到1.4.xx上是比较难的,因为用到了一些高版本的新特性。使用Console要注意的是:虚拟机是否具有控制台取决于底层平台,还取决于调用虚拟机的方式。如果虚拟机从一个交互式命令行开始启动,且没有重定向标准输入和输出流,那么其控制台将存在,并且通常连接到键盘并从虚拟机启动的地方显示。如果虚拟机是自动启动的(例如,由后台作业调度程序启动),那么它通常没有控制台。如果你在Eclipse里面启动程序调用Console,那么通常是没有控制台,还是得从外部的命令行方式才能调用得到。
   总体想一下,感觉应该还是从第2点出发,牺牲掉一点通用性,这样才能满足这种功能需求。

posted @ 2008-05-23 09:41 寒武纪 阅读(4099) | 评论 (1)编辑 收藏

    刚好最近项目中需要用到一点加密的东西,java安全类库提供了一个java.security.MessageDigest类,此 MessageDigest 类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。有现成的当然是最好的,省事省力。
    MD5的非常有实际应用性。有网友给出这样的描述,可以参照一下:http://blog.csdn.net/Daping_Zhang/archive/2005/05/28/382688.aspx
     该类的getInstance(String algorithm) 方法返回一个MessageDigest的实体,加密的一系统的digest()方法和update(byte input)方法。加密后返回一个byte[],16位,我们经常见到很多开源网站的下载地址会有一个[md5]的链接,打开其实就是一小段文本内容。例如:
    MD5 (commons-logging-1.1.1-bin.zip) = f88520ed791673aed6cc4591bc058b55
    这是Jakarta的logging组件下载时提供的MD5摘要信息,是对这个zip包进行全文加密生成的摘要,摘要码就是后面的f88520ed791673aed6cc4591bc058b55,如果你下载以后,按照MD5的算法生成自己的摘要,如果这二个摘要一样,就证明这个文件是没有被人篡改过的。
    遇到的问题是Java的MessageDigest类执行后返回的byte[16]得转换成十六进制的字符串,如果直接用new String(byte[]),得到的结果将是不正确的。算法有很多网友提供了,照搬了。比较有趣的是,commons-logging提供的那个MD5居然和我自己生成的不一样(难道文件被修改过?),后来尝试了其它地方提供的MD5码,都没有问题。
    有很多相关的现成代码,搜集了一下整理如下(经过验证):

public class MD5Builder {

    
static Logger logger = Logger.getLogger(MD5Builder.class);
     
// 用来将字节转换成 16 进制表示的字符
    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[]数组转换成十六进制字符串表示形式
     * 
@param tmp    要转换的byte[]
     * 
@return 十六进制字符串表示形式
     
*/

    
private static String byteToHexString(byte[] tmp) {
        String s;
        
// 用字节表示就是 16 个字节
        char str[] = new char[16 * 2]; // 每个字节用 16 进制表示的话,使用两个字符,
        
// 所以表示成 16 进制需要 32 个字符
        int k = 0// 表示转换结果中对应的字符位置
        for (int i = 0; i < 16; i++// 从第一个字节开始,对 MD5 的每一个字节
            
// 转换成 16 进制字符的转换
            byte byte0 = tmp[i]; // 取第 i 个字节
            str[k++= hexDigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换, 
            
// >>> 为逻辑右移,将符号位一起右移
            str[k++= hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换
        }

        s 
= new String(str); // 换后的结果转换为字符串
        return s;
    }

}

  

posted @ 2008-05-08 15:02 寒武纪 阅读(6520) | 评论 (2)编辑 收藏

    一般而言,我们平常接触的大多数项目都应该是单纯使用B/S或是C/S,除非在特殊场合,否则比较少混合使用B/S,C/S架构。首先说一下对这二种架构特点的一些个人理解。B/S应该是目前很多项目都应用的架构,浏览器的方式使得用户的使用十分方便,用户可以何时何地通过Internet访问URL而进行相应的工作,升级维护也能比较集中,缺点就是浏览器的表现能力受限以及常常受非议的安全性问题,如果软件的应用范围区域不集中,而且用户经常变换地点进行访问,那么这种架构是非常适合的。C/S架构的C端有非常强的处理能力,所以在交互表现和安全方面可以做得比浏览器强,但是缺点也是非常明显的,安装部署、升级维护、版本兼容都是比较头大的事情,一般的适用场景是集中的办公室场所,用户使用范围相对稳定,以及一些对业务处理非常复杂的场合,为了降低服务器的负荷,同样需要C模式的支持。
    以前接触过的电信领域,就有过混合架构的软件。但是都是非常宠大,一直都对其实现方案比较感兴趣,但是都没有机会进一步了解。最近搜索了一下相关的资料,总结一下混合应用的一些想法(只针对Java方向)。
    ①混合架构的问题集中点。服务端共享,客户端采用不同的表现方式,共享的应该是业务层接口,持久层应该是屏蔽的。应用层的消息传递就是整个应用的关键所在,虽然像Jakarta提供的httpClient这种模仿浏览器的组件,但是毕竟是模仿,在很多方面的功能还是缺失的。
    ②最传统的方式是采用EJB做为服务,这个宠然大物容易让人害怕,不过在分布式的系统中它还是有应用优势的,像电信和金融这种行业应用还是比较广的,而且现成的中间件和应用服务器商都比较多,像Oracel、BEA、IBM、Sun都有成熟的应用产品,当然开发的成本和人力投入也是恐龙级数据的。
    ③有网友说在C端直接访问数据库,B/S结构不变,也就是通过数据库进行共享。这种方式是不可取的,二个缺点:把服务器的业务逻辑搬到了C端上,严格上讲是不安全的,升级维护也非常麻烦;并发控制的压力都在数据库上。
    ④采用RMI,这个老古董相信应该很多人都不使用了,因为它的使用要一连串的手续,比如服务接口定义必须实现Remote接口,服务Server在实现时必须继承UnicastRemoteobject类,必须使用rmic指令产生stub和skeleton等,设置上繁杂。
    ⑤Spring 远程服务。这个应该说是比较可取的,大家都比较喜欢轻量级的东西。就如第一点所说的,通过远程服务,我们可以在客户直接调用服务端的服务接口,就像本地调用一样,Spring对远程服务提供了好几种实现方案。
    ⑥WebService。适合异构环境,但是WSDL的这种方式相对来说会比较耗费资料,因为标准定义除了业务内容外,还有许多另外的说明内容。
    Spring远程服务实现方案介绍:
    ⑴Spring + RMI。Spring把传统的RMI方式的繁杂设置去掉,只要配置Bean文件就和定义服务接口可以。RMI的服务启动和管理都交给Spring来处理。RMI访问的缺点就是对防火墙的穿透力比较差。
    ⑵Spring + Caucho的Hessian、Burlap。Hessian使用Http将对象以中性的二进制消息进行传送,而不像RMI使用Java的序列化格式(这种序列化是专制的,不是Sun提供的序列化机制),由于是二进制消息,所以不受限于某种实现语言,传输时所需要的带宽较小是其优点。Burlap是以XML文件格式传送对象,XML文件有较高可读性,应用程序只要能解释XML就能接收消息,当然也不限于某种语言,但是组装XML和解释XML都需要消耗资源,当传输大数据时性能应该存在问题。
    ⑶Spring + Http Invoker。由于Hessian的序列化机制不是正统的Java序列化机制,所以当遇到传输复杂的业务模型时,就会存在各种问题,为此,Spring又提供了Http Invoker,同样是使用Http传送对象,而且是使用Java的序列化机制。相比RMI,Http对防火墙的穿透力要强。
    后来尝试了最后的这种Http Invoker方式,是在Spring2.0版本下尝试的,开发非常简单,网上也有大量的资料介绍。应该说从这里入口可以做一些尝试。目前遇到的一个项目就需要混合架构,B/S采用Spring2 + Struts2 + Hiberntae3,浏览器只提供一些查询功能和数据展现,C端采用Eclipse的RCP平台,共享服务器的业务接口,调用就采用Http Invoker远程服务,复杂的业务功能都集中在C端上。

posted @ 2008-05-06 12:43 寒武纪 阅读(13701) | 评论 (25)编辑 收藏

    1. 驱动器
            如果安装了DB2客户端,则到安装目录下的sqllib/java目录下面找到二个jar包:db2jcc.jar和db2jcc_license_cu.jar,把它们添加到你的classpath中去,有的人说用db2java.zip也可以连接,但是我尝试了,总是无法连接。如果没有这二个jar包,到网上搜索一下,有些网友已经上传了。驱动器名称是:com.ibm.db2.jcc.DB2Driver。
    2. URL写法
           连接的URL正确写法是:jdbc:db2://[IP地址]:[端口]/[数据库名],例如:jdbc:db2://99.1.99.114:50000/dwsdemo,要确保URL正确,你可以先在DB2的命令行测试一下是否能正确连接上。
    有个不太明白的地方就是为什么IBM提供的驱动器包命名有的地方是大写,比如:COM.ibm.db2.app

posted @ 2008-04-17 11:14 寒武纪 阅读(7256) | 评论 (8)编辑 收藏

仅列出标题
共4页: 上一页 1 2 3 4 下一页