当柳上原的风吹向天际的时候...

真正的快乐来源于创造

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks

#

     摘要: 对一个成规模的系统来说,缓存总是不可或缺的一个环节,甚至会成为系统成功的重要因素。 从原理来讲,缓存并不神秘,它本质上只是一个哈希表,内部包含许多提取关键字和缓存内容的键值对,当有读操作(如search)新的查询到来时,系统先到 这个哈希表中看看是否有同样的关键字存在,是则取出对应的值返回,否则进行查询,并把新的查询条件和结果存储进哈希表,以便下次提取;当有写操作(如 add,delet...  阅读全文
posted @ 2010-05-24 15:10 何杨 阅读(633) | 评论 (0)编辑 收藏

在交易系统的客户端中,涉及的业务种类有很多,如分类,商品,询价,协商等大类及其下的CRUD四个小类,每种操作几乎都需要一个界面供用户操作,这些界面及其内部处理如果安排不当会造成维护上的巨大麻烦,而且随着程序的发展,界面表现,用户交互和数据处理都会而变得越来越复杂,如果不在一开始就对它们进行分开处理,最后只能导致不可维护的结果,届时悔之晚矣。只有迈出了这坚实稳固的一步,后面的成功才有可靠的保证。因此我采用了MVC2模式来将每个操作界面的界面表现,用户交互和数据处理三部分分离,目的是为了提高系统的可维护性和可扩展性。下面是对交易系统采用的MVC2模式的简要介绍,以便于负责业务的程序员掌握之。

一.MVC2模式的来源
   这种模式首见于网络程序,起初因为Model无法通知到Web程序的界面而发明.这种模式采用Controller做中介者,一方面取得View的输入,然后交由Model层处理,之后再把返回的数据传递到View。在Web程序(典型例子如Struts1)中各层任务如下:View接受用户输入,并在并传递到Controller;Controller统一进行处理命令,交由Model处理具体的业务;进过处理Model更新后,Controller会选一个View并把Model内容传递(request,session)给它,然后View进行显示.

二.MVC2的优缺点
   MVC2相对MVC1优势很明显,首先Model和View无需继承别的类,其次Model和View无需了解对方的存在,只需准备相应的接口而已,最主要的是,是进行了数据部分,视图部分和控制部分三层的区分,程序的耦合度将大为降低,而可读性和可修改性将随之提高;缺点对于规模较小的程序或是组件,MVC2稍显费事,有些过度设计的嫌疑。

三.在客户端程序中MVC各层担负的职责

视图View:它担任数据的显示并接受用户的输入,其中不包括业务逻辑,但可以包含显示逻辑。

数据中心Model:它保存数据层和控制层所需要的数据并提供操作这些数据的方法。

控制器Ctrl:它是一个中介者,负责实例化视图和数据中心,由此View和Model并不需要知道对方的存在。View的事件在Ctrl中注册,这样当事件发生时Ctrl能调用Model取得相应的数据并显示在View中。Ctrl中包含处理逻辑。

下面的UML图形可以参考:
MVC2静态类图


MVC2顺序图


下面是最简化的MVC三层次代码示例:
控制类
public class Mvc2Ctrl {
    
private Mvc2View view;
    
private Mvc2Model model;
    
public Mvc2Ctrl() {
        view 
= new Mvc2View();
        model 
= new Mvc2Model();
        handleEvents();
    }
    
// 处理事件响应
    private void handleEvents() {
        addCloseLintener();
        addButtonListener();
        addButtonListener2();
    }
    
// 窗体关闭事件相应
    private void addCloseLintener() {
        view.addWindowListener(
new WindowAdapter() {
            
public void windowClosing(WindowEvent e) {
                System.out.println(
"Exit MVC2");
                System.exit(
0);
            }
        });
    }
    
private void addButtonListener() {
        view.getButton().addActionListener(
new ActionListener() {
            
public void actionPerformed(ActionEvent e) {
                view.getLabel().setText(model.getText());
            }
        });
    }
    
    
private void addButtonListener2() {
        view.getButton2().addActionListener(
new ActionListener() {
            
public void actionPerformed(ActionEvent e) {
                view.getLabel2().setText(model.getText2());
            }
        });
    }
}

视图类
public class Mvc2View extends JFrame {
    
private static final long serialVersionUID = 621145935910133202L;
    
private JButton button;
    
private JLabel label;
    
private JButton button2;
    
private JLabel label2;
    
public Mvc2View() {
        locateView(
300200);
        
this.setTitle("MVC2 Program");
        setupComponents();
        
this.setVisible(true);
    }
    
// 定位程序在屏幕正中并设置程序大小
    private void locateView(int width, int height) {
        Dimension screenSize 
= Toolkit.getDefaultToolkit().getScreenSize();
        
this.setSize(width, height);
        
this.setLocation(screenSize.width / 2 - width / 2, screenSize.height
                
/ 2 - height / 2);
    }
    
// 初始化内部组件
    private void setupComponents() {
        button 
= new JButton("点击响应事件1");
        label 
= new JLabel("  等待事件响应1");
        button2 
= new JButton("点击响应事件2");
        label2 
= new JLabel("  等待事件响应2");
        setLayout(
new GridLayout(22));
        add(button);
        add(label);
        add(button2);
        add(label2);
    }
    
public JButton getButton() {
        
return button;
    }
    
public JButton getButton2() {
        
return button2;
    }
    
public JLabel getLabel() {
        
return label;
    }
    
public JLabel getLabel2() {
        
return label2;
    }
}
模块类
public class Mvc2Model{
    
public String getText(){
        
return "  事件1响应完毕";
    }
    
    
public String getText2(){
        
return "  事件2响应完毕";
    }
}

小结:
一.越是大型程序,MVC越有必要;倒是小型程序不一定硬要遵守MVC。
二.以上代码抽象程度还不够,理论上说,应该阻止程序员在界面中写监听代码。
三.三部分应该实现相应的接口,这里是应该继续进化的地方。

posted @ 2010-05-23 13:56 何杨 阅读(292) | 评论 (0)编辑 收藏

在交易系统的C/S体系中,C只负责数据的输入和显示,相当于MVC中的View部分,S负责数据的操作和持久化,两者是通过WebService进行联系的,具体来说联系的方式是这样:C端将指定S端负责处理的Service类名,具体负责处理的函数名和函数的参数打包成一个XML传送到S端,S端解析后通过反射找到具体的函数进行处理,处理的结果会转化成XML形式的字符串传回。这就是设计梗概一中提到的内容。

如果这个过程交给负责具体业务的程序员自行完成的话,那无疑会给系统带来许多混乱和无序,程序员也无法将主要精力集中在业务上;另外,他们也无需了解每个细节是怎么完成的,他们真正需要的是框架提供好的接口,知道怎么调用取得结果就可以了。他们希望最好能像调用普通函数一样调用S中的方法并取得想要的结果,举例来说,如果客户端需要查询姓名以H开头的所有雇员,他们只需调用一个search函数就能得到查询出来的雇员集合,中间发生的组装请求XML,WebService调用,业务处理,从数据库查询数据,将数据转为XML传回和在客户端解析传回的XML再变成领域对象集合等都应该由框架来完成。这并不过分,而是很合理的需求,就像RMI曾经就是这样做的。

那么,客户端与服务器端的交互会有几种形式呢,从业务上来说无外乎下面五种形式:
1.调用S端的一个函数,只想知道这个函数是否正确运行了。典型例子如对象的删除操作。
2.调用S端的一个函数,想得到函数执行后返回的一个对象。典型例子如对象的添加操作,用户需要取回添加好的对象的ID。
3.调用S端的一个函数,想得到返回对象的集合列表。典型例子如对象的查询。
4.调用S端的一个函数,想得到分页后的某一页对象集合。典型例子如分页查询。
5.调用S端的一个函数,只想得到一个字符串。典型例子如改变一种商品的目录,得到某种商品的介绍文字等。
框架需要做的,就是把这五种形式做成通用的函数提供给负责业务的程序员,让他们仅需要这五个函数就能完成与WebService服务器的交互。这五种形式以第二种最为典型,也最为基础,完成了它其它的就可以依样画葫芦,下面请看具体过程:

首先,规定具体函数的形制为
public static BaseDomainObj fetchObject(String url,String serviceName,String mothodName,String[] args,Class<?> cls);
公有静态自不必说,BaseDomainObj是客户端领域对象的基类,fetchObject是函数名,接下来是四个参数,前三个分别是WebService所在URL,服务器上服务类注册在Spring上下文中的beanName,服务类具体的方法名,最后一个是取得对象的类型,在函数体中,会根据类型用反射生成一个实例,再通过实例的FromXML方法给实例的属性赋值,完成后就得到了负责业务的程序员想要的结果。

其次,fetchObject内部需要做的事情有:
1.将serviceName,mothodName,args三项组合成一段XML文本。此项工作由WSRequest类完成。
2.向位于url上的WebService服务器端发起请求,获得返回的文本。此项工作由WSInvoker类来完成。
3.将返回的文本转化出来,这一步是要检测服务器端函数执行是否顺畅,有无抛出异常等。因为服务器端如果发生异常是无法通过WebService传回的,只能变成文本后回传,那么客户端就需要解析一次,有问题就报出来,没问题再往下走。这一步是坚决不能忽视的。
4.通过反射得到对象,此时对象的属性还是原始状态,需要再通过反射注入相应的值,最后,客户端需要的对象就产生了。

具体的过程请参考下面的代码:
/**
 * 调用远程WebService端,将返回的XML转化为一个对象,最终返回.这种调用的典型例子是getById,add等
 * 
@param url WebService所在URL
 * 
@param serviceName 服务名,此名在appCtx.xml中定义
 * 
@param mothodName 方法名
 * 
@param args 方法的参数
 * 
@param cls 要返回的对象类型
 * 
@return
 
*/
public static BaseDomainObj fetchObject(String url,String serviceName,String mothodName,String[] args,Class<?> cls){
    
// 得到客户端请求XML文本
    WSRequest request=new WSRequest(serviceName,mothodName,args);
    String requestXML
=request.toXML();
    logger.info(
"准备向位于'"+url+"'发送的请求XML为'"+requestXML+"'.");
    
    
try{
        
// 调用远端WebService上的方法,得到返回的XML文本
        WSInvoker invoker=new WSInvoker(url);
        String responseXML
=invoker.getResponseXML(requestXML);
        logger.info(
"得到位于'"+url+"'响应XML为'"+responseXML+"'.");
        
        
// 转化响应
        WSResponse response=new WSResponse(responseXML);
        logger.info(response);
        
        
// 如果在调用过程中如通不过检测而被中断的话
        if(response.isBreaked()){
            String errTxt
="远程方法被中断,具体原因是"+response.getRemark();
            logger.error(errTxt);
            
throw new WSBreakException(errTxt+".(WSE05)");
        }
        
        
// 如果在调用过程中出现异常的话
        if(response.hasException()){
            String errTxt
="调用远程方法返回了异常,具体信息是"+response.getRemark();
            logger.error(errTxt);
            
throw new WSException(errTxt+".(WSE04)");
        }
        
        
try{
            
// 通过反射得到对象
            BaseDomainObj obj= (BaseDomainObj)cls.newInstance();
            
            
// 通过反射得到方法
            Method method = cls.getMethod("fromXML"new Class[] {String.class});
            
            
// 通过反射调用对象的方法
            method.invoke(obj, new Object[] {response.getMethodResonseXML()});
            
            
return obj;
        }
        
catch(Exception ex){
            String errTxt
="无法将"+response.getMethodResonseXML()+"转化为"+cls.getName()+"对象.(WSE06)";
            logger.error(errTxt);
            
throw new WSException(errTxt);
        }
    }
    
catch(MalformedURLException e){
        String errTxt
="无法调用'"+url+"'上的服务,因为它是畸形的.(WSE01)";
        logger.error(errTxt);    
        
throw new WSException(errTxt);
    }
    
catch(XFireRuntimeException e){
        String errTxt
="无法调用'"+url+"'上的服务.(WSE02)";
        logger.error(errTxt);    
        
throw new WSException(errTxt);
    }
    
catch(DocumentException e){
        String errTxt
="无法解析从服务器端'"+url+"'返回的XML文本.(WSE03)";
        logger.error(errTxt);    
        
throw new WSException(errTxt);
    }
}


我们再看看通过关键的注入属性值的fromXML函数做了些什么:
public void fromXML(String xml) throws DocumentException{
    Document doc
=DocumentHelper.parseText(xml);        
    
    Element root
=doc.getRootElement();        
    List
<Element> elms=root.elements();
    
    
for(Element elm:elms){
        
try {
            
// 借助于BeanUtils,给对象的属性赋值
            BeanUtils.setProperty(this,elm.getName(),elm.getText());
        } 
catch (IllegalAccessException e) {
            e.printStackTrace();
        } 
catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}


最后,我们可以看看负责业务的程序员需要书写的代码示例:
public Tmp add(String name,String age,String salary,String picture){
    String url
=CommonUtil.WebService_Url;
    String serviceName
="TmpService";
    String methodName
="add";
    String[] args
=new String[]{name,age,salary,picture};
    
    
try{
        
return (Tmp)WSUtil.fetchObject(url, serviceName, methodName, args, Tmp.class);
    }
    
catch(WSBreakException ex){
        DlgUtil.popupWarningDialog(ex.getMessage());
    }
    
catch(WSException ex){
        DlgUtil.popupErrorDialog(ex.getMessage());
    }
    
    
return null;
}


小结:
一.负责业务程序员不需要了解的细节,框架应该将它们隐藏起来。
二.负责业务程序员需要了解的接口,框架应该使它们尽量简单。
三.框架能做到的,就不该再让负责业务的程序员再重复的发明车轮。
posted @ 2010-05-21 00:18 何杨 阅读(196) | 评论 (0)编辑 收藏

下载地址
http://www.box.net/shared/o48fxqem61

SqlToolBox是一款纯绿色的免费数据库客户端软件,基于Java Swing编制而成,旨在于为开发人员,系统工程师和数据库管理员提供一种通用方便和快捷的数据库操作工具,使他们摆脱需要学习掌握使用多种数据库客户端 的苦恼,并减轻他们日常操作数据库和编写Sql语句的任务量,帮助他们把精力投入到解决更有意义的问题上去。

SqlToolBox现有功能

  1. 能连接到MySql,Oracle和Ms Sql Server三种数据库。
  2. 连接到数据库后,会提供数据库Schema和表的树视图以便用户进行浏览和查找,另外还提供了一个过滤器帮助用户缩小查找范围。
  3. 用户能自动快速获取单表的创建,查询,更新,删除,建表语句,整表全部数据插入语句,单表对应Pojo类和单表的Hibernate映射文件等常用文字,且可借此构造更复杂的Sql语句。
  4. 能执行Sql语句并显示执行结果,如果是查询语句会以表格形式显示结果,还提供CSV形式数据下载;如果是非查询语句或是错误的查询语句则会以文字形式告知用户。
  5. 在用户输入Sql语句的过程中提供Sql语法高亮功能,以助于Sql语句的识别。
  6. 提供Sql格式化功能以助于Sql语句的识别和整理。
  7. 提供Redo/Undo,Shift整体退格进格,大小写转化,将Sql语句用StringBuilder包容以及将Sql语句中关键字大写表示等常用文字编辑功能。这些都能帮助程序员在程序中书写Sql语句。
  8. 能保存和记忆数据库信息,以便下次打开。

运行SqlToolBox有何前提条件?

将SqlToolBox运行起来的唯一前提是安装JDK6或以上版本。

SqlToolBox需要安装吗?

SqlToolBox是一款纯绿色软件,它对您的系统不做出任何更改,因此不需要安装和卸载。

SqlToolBox安全吗?

由于软件使用Java编写而成,它本身就具有较高的安全性。此外作者保证在SqlToolBox整个系列中都不会加入病毒,木马,插件等坏东西。

如何运行SqlToolBox?

解开下载包,然后双击run.bat即可。

在Unix/Linux下如何运行SqlToolBox?

除了也需要安装JDK外,您还需要参照run.bat写一份脚本,然后执行它。

如何使用SqlToolBox打开一个数据库?

程序运行起来后,您将看到一个输入数据库信息的对话框,请依次填入数据库所在机器的IP地址,数据库的库名称,选择数据库的类型以及输入登录数据库的用户 名和密码等必要信息。此后再点击“连接数据库”按钮,程序将打开数据库。如果您将以上信息填错也不要紧,程序会提示哪里出现了问题。此外您可以在登录前点 击“测试连接”按钮,程序也会告诉您是否能连接到指定的数据库。

打开数据库后程序左边部分如何使用?

成功连接到数据库以后,数据库的Schema和table结构会在画面的左边以树的形式展现出来,如果展现的内容过多,您还可以在上方的“过滤器”输入栏 中输入关键字以缩小展现范围。在这颗树中,表格(table)是以小圆点的方式展现的,左键点击这个圆点,程序将在右侧打开一个Sql语句操作窗口,并执 行“select * from table”语句,最后在下方以表格的形式展现给您;如果您用右键点击这个圆点,程序将弹出一个右键菜单,选择其中的项目您将可以在右边的Sql语句操作 窗口中得到单表的字段信息,创建(insert),查询(select),更新(update),删除语句(delete)及建表语句(create table),单表对应Pojo文件,单表的Hibernate映射文件等文字。

打开数据库后程序右边部分是如何使用的?

用左右键点击表格后,您将在右侧看到一个“Sql语句操作窗口”,它分成三部分:工具栏菜单,输入窗口和输出窗口。输入窗口是用以输入,编辑和整理Sql 语句的;工具栏菜单中的一大排按钮都是为编辑处理输入窗口中的文字而准备的;输出窗口则是展示Sql语句执行后的结果的,如果是查询语句,它会以表格的形 式告知您查询的结果,如果是其它语句,它会以文字的形式告知。通常的操作手法是,先在输入窗口中用鼠标选中您要操作的文本,再在工具栏菜单中点击执行特定 操作的按钮,然后在下方的输出窗口中就能看到具体的结果,当然如果仅是文本编辑操作的话输出窗口是不会有反应的。

如何执行Sql语句?

程序员和数据库管理员总是习惯使用语句来操作数据库,这也是本软件的最重要功能之一。执行Sql语句的过程具体来说是这样做的,首先,在输入窗口输入您向 执行的Sql语句,如“select * from table”之类,当然您更可以通过表格的右键菜单来获得常用的sql语句(在输入或是粘贴文本的过程中,Sql语句中的关键字会以蓝色显示,这是语法高 亮功能所致);其次,你需要选中你想执行的文本,再点击工具栏菜单中的向右三角形按钮,这段文本将得到执行,执行结果将在下方的输出窗口得到展示。如果您 执行的是查询语句,输出窗口将以表格的形式列出查询结果集的字段和内容;如果您执行的是删除,更新,添加,修改表等语句或是执行错误的Sql文本,输出窗 口将以文本形式告知执行结果。另外工具栏菜单中的双向右三角形按钮用于批量执行Sql语句,它以分号“;”来作为每段Sql的分隔标志,然后分别执行每 段。

如何快速调整对执行查询语句后得到的表格列宽度?

如果您想自动调整某列的宽度,可以双击这列的表头,此后这列的宽度会根据这列的最长文字进行调整;您还可以在表格上点击右键,选择“调整列宽为最适合状态”一项,那么所有的列宽都会进行调整。

如何得到执行查询语句后得到的表格的内容?

您还可以在表格上点击右键,选择“下载表格为CSV文件”一项,此后查询语句和得到的结果都会被放入一个CSV文件中。CSV是一中文本文件,但您可以用Excel打开它,也会得到xls文件一样的效果。

在新增或是删除一张表后,在左边的树中为什么没有相应的变化?

新增或是删除一张表后,您需要手动执行一下左上方的更新按钮(最上方的大图标中第一个),此后程序会重新载入数据库的Schema和table,这样您刚才对表格进行增删操作就能体现出来。

如果我需要常打开数据库进行操作或是需要常操作多个数据库,程序能为我提供那些便利?

本软件有记忆功能,如果您正确连接到一个数据库,那么相应的信息如IP地址,数据库名,数据库类型,连接数据库的用户名和密码都会被记忆下来,这样下次打 开时就不用重复输入了。如果您需要常操作多个数据库,您可以通过保存按钮(最上方五个大图标中的第二个)将数据库信息保存成XML文件,这样在登录画面中 就可以通过“打开文件按钮”得到相应的数据库信息。

程序截图:












posted @ 2010-05-20 00:02 何杨 阅读(390) | 评论 (2)编辑 收藏

此项目是一个采购商和供货商之间的交易软件,双方可以在系统中发布供求信息,应答供求信息,与对方谈判敲定供求细节如品种,数量,交货地点,交货批次等,此外还有产品展示,信用记录等交易系统常用功能。

此系统难点在于大量即时信息的送达和交互信息的多样化,框架中采用了JMS和WebService两种手段来保证这两项的成功,并拟采用IM服务器来取代JMS。在层次上采用了WebService来屏蔽后台数据库,并用XML来传递前后台信息。由于采用了使用Java反射技术的控制中心方案和基于AOP的缓存方案,有效降低了系统的开发难度,使得系统的可扩展性和可维护性得到了较大提高。

项目使用的技术:
前台技术:Swing,XML,WebService,JMS。
后台技术:JMS,WebService,Spring,Hibernate等。

posted @ 2010-05-19 14:50 何杨 阅读(136) | 评论 (0)编辑 收藏

     摘要: 我在前一向做交易系统时的设计梗概之一,欢迎拍砖。  阅读全文
posted @ 2010-05-19 14:22 何杨 阅读(1900) | 评论 (0)编辑 收藏

     摘要: 如果有效利用XML和反射等手段,我们可以做到工具栏菜单项的可配置化。具体来说就是,将菜单项的文字,图片和点击后的响应函数都在XML配置文件中配置好,程序启动时去读取文件生成菜单,点击菜单项后会动态的找到具体需要处理的函数。这样做以后,修改一个按钮对应的功能定位代码,或是增删一个按钮及其功能就很容易了。  阅读全文
posted @ 2010-05-18 22:04 何杨 阅读(2376) | 评论 (7)编辑 收藏

XML文件如下:
<?xml version="1.0" encoding="GBK"?>

<menuItems>
    
<name>根节点</name>
    
<icon></icon>
    
<panelName></panelName>
    
<mothodName></mothodName>
    
<args></args>

    
<menuItem>
        
<name>节点一</name>
        
<icon>folder_fromFile.gif</icon>
        
<panelName>
            com.heyang.view.panel.content.folder.addfromfile.AddCategoryFromFilePanel
        
</panelName>
        
<mothodName></mothodName>
        
<args></args>
    
</menuItem>
    
<menuItem>
        
<name>节点二</name>
        
<icon>folder_attribute.gif</icon>
        
<panelName>
            com.heyang.view.panel.content.folder.attribute.AttributeMngPanel
        
</panelName>
        
<mothodName></mothodName>
        
<args></args>
    
</menuItem>
    
<menuItem>
        
<name>节点三</name>
        
<icon>folder_transfer.gif</icon>
        
<panelName>
            com.heyang.view.panel.content.folder.transfer.FolderTransferPanel
        
</panelName>
        
<mothodName></mothodName>
        
<args></args>
    
</menuItem>
</menuItems>

读取例程:
 /**
     * 按照XML文件建立一棵树
     * 
     * 
@author:何杨
     * @date:2009-12-22
     * @time:上午08:13:09
     
*/
    @SuppressWarnings(
"unchecked")
    
private void buildTree(){
        
// 建立树节点
        DefaultMutableTreeNode root = null;
                
        
try {
            SAXReader reader 
= new SAXReader();
            String xmlFile 
= TreeMenuPanel.class.getResource("/text.xml").getPath()
                    .toString();
            
            File file
=new File(xmlFile);
            
if(file.exists()==false){
                DlgUtil.popupErrorDialog(
"无法找到文件"+xmlFile+".");
                
return;
            }
            
            Document document 
= reader.read(file);
            Element rootElm 
= document.getRootElement();
            
// 遍历XML生成节点树
            root=getNode(rootElm);
        } 
catch (Exception ex) {
            ex.printStackTrace();
        }
        
        
// 将节点树赋予树组件
        DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
        model.setRoot(root);
        model.reload();    
        tree.updateUI();
    }
    
    
/**
     * 递归取得节点
     * 
     * 
@author:何杨
     * @date:2010-1-11
     * @time:上午08:31:12
     * 
@param elm
     * 
@return
     
*/
    @SuppressWarnings(
"unchecked")
    
private DefaultMutableTreeNode getNode(Element elm){        
        String name
=elm.elementText("name");
        String icon
=elm.elementText("icon");
        String panelName
=elm.elementText("panelName");
        String mothodName
=elm.elementText("mothodName");
        String args
=elm.elementText("args");
        
        MenuItem menuItem
=new MenuItem(name,icon,panelName,mothodName,args);
        DefaultMutableTreeNode leaf 
= new DefaultMutableTreeNode();
        leaf.setUserObject(menuItem);
        
        List
<Element> elms = elm.elements("menuItem");
        
for (Element element : elms) {
            leaf.add(getNode(element));
        }    
        
        
return leaf;
    }


posted @ 2010-01-14 21:56 何杨| 编辑 收藏

1.1 创建树组件
1.1.1 最简方式

    JTree tree = new JTree();

    在显示时,树组件会带上JTree默认的节点。

1.1.2 指定树的节点后创建树:   

    DefaultMutableTreeNode root = new DefaultMutableTreeNode("根节点");
    root.add(
new DefaultMutableTreeNode("子节点"));    
    JTree tree 
= new JTree(root);


1.1.3 将树加入到面板中
    以下是将树加上滚动窗格后加入一个面板的示例程序。    

   JPanel panel=new JPanel();
   panel.setLayout(
new GridLayout(1,1));
   panel.add(
new JScrollPane(tree));

   
1.2 树节点相关
1.2.1 取得树的根节点

    DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
    DefaultMutableTreeNode root 
=(DefaultMutableTreeNode)model.getRoot();

1.2.2 更新树的根节点

    DefaultMutableTreeNode newRoot=;
    DefaultTreeModel model 
= (DefaultTreeModel) tree.getModel();
    model.setRoot(newRoot);
    model.reload();  
    tree.updateUI();


1.2.3 从一个节点开始递归遍历其下的所有节点

private String getNodeText(DefaultMutableTreeNode node){
   Category category
=(Category)node.getUserObject();
   StringBuilder sb
=new StringBuilder(category.getText());
  
  
if (node.getChildCount() >= 0) {
            
for (Enumeration<?> e=node.children(); e.hasMoreElements(); ) {
             DefaultMutableTreeNode childNode 
= (DefaultMutableTreeNode)e.nextElement();
                sb.append(getNodeText(childNode));
            }
        }
  
  
return sb.toString();
}


1.2.4 在某节点下创建一个节点

    DefaultMutableTreeNode childNode = new DefaultMutableTreeNode();
    childNode.setUserObject();
    parentNode.add(childNode);

1.2.5 节点改名  

    Category selectedCategory=(Category)clickedNode.getUserObject();
    selectedCategory.setName(
"");
    clickedNode.setUserObject(selectedCategory);

 

1.2.6 删除节点   

    DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
    model.removeNodeFromParent(clickedNode);

    注意被删除的节点必须有父节点,若要删除根节点直接用null去替代原有根节点即可,

1.2.7 遍历用户选择的树节点   

    TreePath[] paths = tree.getSelectionPaths();
   
    
for(TreePath selPath:paths){
        Object[] nodes 
= selPath.getPath();
  
        DefaultMutableTreeNode node 
= (DefaultMutableTreeNode) nodes[nodes.length - 1];  
        
// 对node进行处理
    }

 

1.3 树的事件处理
1.3.1 左键点击事件处理
   

   tree.addMouseListener(new MouseAdapter() {
      
public void mousePressed(MouseEvent e) {
        
int selRow = tree.getRowForLocation(e.getX(), e.getY());// 返回节点所在的行,-1表示鼠标定位不在显示的单元边界内
        TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());// 返回指定节点的树路径
   
        
boolean condition = true;
        condition 
= condition && (selRow != -1);// 如果选中
        
//condition = condition && (e.getButton() == 1);// 左键 e.getButton() == 1  右键  e.getButton() == 3
        condition = condition && (e.getClickCount() == 1);// 单击
       
   
        
// 如果是左键点击
        if (condition == true && (e.getButton() == 1)) {
          Object[] nodes 
= selPath.getPath();
         
          DefaultMutableTreeNode node 
= (DefaultMutableTreeNode) nodes[nodes.length - 1];
          Category selectedCategory
=(Category)node.getUserObject();
   
        }
      }
    });

 

1.3.2 在树节点上点击右键弹出右键菜单 

   tree.addMouseListener(new MouseAdapter() {
      
public void mousePressed(MouseEvent e) {
        
int selRow = tree.getRowForLocation(e.getX(), e.getY());// 返回节点所在的行,-1表示鼠标定位不在显示的单元边界内
        TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());// 返回指定节点的树路径

        
boolean condition = true;
        condition 
= condition && (selRow != -1);// 如果选中
        condition = condition && (e.getClickCount() == 1);// 单击
       
        
// 如果是右键点击
        if(condition == true && (e.getButton() == 3)){
         
          Object[] nodes 
= selPath.getPath();
          DefaultMutableTreeNode rightClickedNode 
= (DefaultMutableTreeNode) nodes[nodes.length - 1];
          
          popupMenu.show(e.getComponent(), e.getX(), e.getY());
        }
      }
    });

 

1.4 树的渲染
1.4.1 树节点渲染器示例
 

  public class CategoryNodeRenderer extends DefaultTreeCellRenderer{
    
private static final long serialVersionUID = 8532405600839140757L;
   
    
private static final ImageIcon categoryLeafIcon = new ImageIcon(CategoryNodeRenderer.class.getResource("/categoryLeaf.gif"));
    
private static final ImageIcon openFolderIcon = new ImageIcon(CategoryNodeRenderer.class.getResource("/openFolder.gif"));
    
private static final ImageIcon closedFolderIcon = new ImageIcon(CategoryNodeRenderer.class.getResource("/closedFolder.gif"));
   
    
public Component getTreeCellRendererComponent(JTree tree,
                                              Object value,
                                              
boolean sel,
                                              
boolean expanded,
                                              
boolean leaf,
                                              
int row,
                                              
boolean hasFocus){
     
      
super.getTreeCellRendererComponent(tree,  
                  value,
                  sel,  
                  expanded,  
                  leaf,  
                  row,  
                  hasFocus);  
     
      
if(leaf){
        setIcon(categoryLeafIcon);
      }
      
else if(expanded){
        setIcon(openFolderIcon);
      }
      
else{
        setIcon(closedFolderIcon);
      }
         
      
return this;   
    }
  }

 

1.4.2 用树节点渲染器渲染一棵树 

  DefaultMutableTreeNode root = null;
  JTree tree 
= new JTree(root);
  tree.setCellRenderer(
new CategoryNodeRenderer());

 

posted @ 2010-01-14 15:13 何杨| 编辑 收藏

当不需要全体字段或是不必要的字段属性映射匹配影响效率时,我们可以使用在HQL语句中直接返回一个Java对象,如下:
select new com.heyang.domain.Folder(id,pid,name) from Category c

需要注意的是:
1.Folder类应该写全路径名,如上面的com.heyang.domain.Folder,否则Hibernate会说Unable to locate class ‘Folder’。

2.Folder类应该具有一个和参数相匹配的构造函数,如果上面的id,pid,name三个字段的类型分别是long,long,vchar,那么Folder类的构造函数应该是Folder(Long op1,Long op2,String op3);的形式。

就是这样,很简单,简单到Hibernate帮助手册都对之语焉不详,写出来注意一下就好了。
posted @ 2010-01-09 09:01 何杨| 编辑 收藏

仅列出标题
共28页: First 上一页 16 17 18 19 20 21 22 23 24 下一页 Last