随笔-67  评论-522  文章-0  trackbacks-0
    目前XML文件的应用越来越广泛,而操作XML的技术更有不少,其中以dom4j强大的性能,丰富的API以及简单的易用性,受到了很多人的喜爱,本文以一个读取数据源的小例子,来说明一下dom4j的一些基本操作。
    dom4j一个JavaXML API,同时也是一种解析XML文档的开源软件。由dom4j.org开发,具有性能优异、功能强大和极端易用的特点,大名鼎鼎的Hibernate就是用它来读取配置文件滴。本文只是对dom4j的一些基本操作进行说明,不包含深入分析。(本文最后有源码和相关JAR包下载)
    开发环境:Eclipse 3.2.1 MyEclipse 5.1.0GA dom4j-1.6.1.jar jaxen-1.1-beta-7.jar
    1、创建Web Project
       Web Project来演示的原因一是因为WEB-INF目录下有一个lib目录,例子中需要用到的jar包,直接放进去就行了,二是这个系列后面讲的内容会需要。如果建Java Project则还要设置库路径,为了方便,就用Web Project吧。点击"File"->"New"->"Project",选择"Web Project",在"Project Name"中输入demo,点击"Finish"。然后我们把dom4j-1.6.1.jarjaxen-1.1-beta-7.jar还有MySQL的连接驱动放到WEB-INF\lib目录下。
    2、创建DBConnect.xml
       src目录下建一个DBConnect.xml文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<demo>
    
<database>
        
<driver>com.mysql.jdbc.Driver</driver>
        
<url>jdbc:mysql://127.0.0.1:3306/mysql</url>
        
<username>root</username>
        
<password>123</password>
    
</database>
</demo>
       大象在这里用MySQL的数据库,当然你也可以换成SQL Server或是Oracle,不过XML文件中对应的配置都要作相应的改动!
    3、创建DataBaseConnect.java
       在src上点右键,选择"New->Package",输入:com.demo.database,在database下新建一个类,类名为:DataBaseConnect下面我们先写一段简单的代码,测试一下,看看能否从这个XML文件中读取到配置信息。在DataBaseConnect类中加入main函数,然后写上如下代码:
    public static void main(String[] args){
        
try{
            SAXReader saxReader 
= new SAXReader(); //使用SAXReader方式读取XML文件
            //加载数据库XML配置文件,得到Document对象
            Document document = saxReader.read(new File("src/DBConnect.xml")); 
            Element root = document.getRootElement(); //获得根节点
            //得到database节点
            Element database = (Element)root.selectSingleNode("//demo/database"); 
            List list = database.elements(); //得到database元素下的子元素集合
            /*
             * 循环遍历集合中的每一个元素
             * 将每一个元素的元素名和值在控制台中打印出来
             
*/
            
for(Object obj:list){
                Element element 
= (Element)obj;
                
//getName()是元素名,getText()是元素值
                System.out.println(element.getName()+""+element.getText());
            }
        }
catch(Exception e){
            e.printStackTrace();
        }
    }
       这里有三点要说明一下:
         a、saxReader.read(new File("src/DBConnect.xml")),这个read方法是一个重载的方法,里面的参数可以为FileFileInputStreamURL等。所以这里还可以写成new FileInputStream ("src/DBConnect.xml"),另外还可以用ClassLoader来加载:getClass().getClassLoader().getResourceAsStream("DBConnect.xml"),注意,这里不能加"src/",因为它是在WEB-INF\classes里面找文件,另外不能写在静态的main函数里,可以在main方法外,创建一方法,在main中通过实例化类对象来调用,这里不再详述,大家自己去试下。
         b、root.selectSingleNode("//demo/database"),这里的"//demo/database"其实是一个XPATH语法,关于XPATH请参考相关资料,这里不作讨论。这样写的意思是指:demo根节点下的database节点,"selectSingleNode"是得到database这个单独的元素,至于database下面是否还包含别的信息,则是通过其它的API来操作。
          c、如果你在使用XPATH语法的时候没有加入jaxen-1.1-beta-7.jar这个包,就会出现如下异常:
Exception in thread "main" java.lang.NoClassDefFoundError: org/jaxen/JaxenException
    at org.dom4j.DocumentFactory.createXPath(DocumentFactory.java:230)
    at org.dom4j.tree.AbstractNode.createXPath(AbstractNode.java:207)
    at org.dom4j.tree.AbstractNode.selectSingleNode(AbstractNode.java:183)
    at com.demo.database.DataBaseConnect.main(DataBaseConnect.java:16)
       如果没有问题的话,应该可以在控制台看到下面的结果:
driver: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mysql
username: root
password: 
123

       到此,我们已经成功使用dom4jXML中读取文件,下面我们对DataBaseConnect作一下修改,毕竟上面这种写法是测试用的,真正的类怎么可能这样写?
    4、创建ClassUtils.java
       新建com.demo.util包,在util包下新建ClassUtils类,用来处理资源加载方面的事情,内容如下:

    /*
     * 这里使用的是单态模式
     
*/
    
private static ClassUtils instance = new ClassUtils(); //实例化私有静态对象
    
    
/**
     * 通过资源名称或资源路径得到资源输入流
     * 
@param name 资源名称或资源路径
     
*/
    
public static InputStream getResourceAsStream(String name) {
        
/*
         * 这里用到了回调方法
         * 使用静态的私有对象,在静态方法中调用非静态的方法
         * 并且loadResource是私有方法,对外不可见
         
*/
        
return instance.loadResource(name);
    }
    
    
/**
     * 私有构造函数,不能在外部被实例化
     
*/
    
private ClassUtils() {}
    
    
/**
     * 通过资源名称或资源路径加载资源
     * 
@param name 资源名称或资源路径
     * 
@return InputStream
     
*/
    
private InputStream loadResource(String name) {
        
return getClass().getClassLoader().getResourceAsStream(name);
    }
    5、创建Constant接口
       在util包下再建一个Constant接口,里面放的是数据源配置常量字符串,与XML文件中的元素名对应,在这里是将DBConnect.xml放在src目录下,如果你想放到其它的目录下,则要加上包名,比如放在database包下,那么应该写成:com/demo/database/DBConnect.xml。
    String DRIVER = "driver";
    String URL 
= "url";
    String USERNAME 
= "username";
    String PASSWORD 
= "password";
    String DB_CONFIG 
= "DBConnect.xml";
       在接口中,方法自动定义成public的,域自动的被定义为publicstaticfinal的,因此不用显式的声明。
    6、修改DataBaseConnect
       最后我们来修改DataBaseConnect类,首先我们定义几个静态变量:
    private static Element coreModel; //根元素
    private static String driver; //连接驱动
    private static String url;    //数据库连接地址
    private static String username; //用户名
    private static String password; //密码
       读取DBConnect.xml文件,获得根元素:
    /**
     * 加载数据源配置文件,取得根元素
     
*/
    
private static void load(){
        SAXReader saxReader 
= new SAXReader();
        //加载数据库XML配置文件
        InputStream in 
= ClassUtils.getResourceAsStream(Constant.DB_CONFIG); 
        try{
            Document document 
= saxReader.read(in); //得到Document对象
            coreModel = document.getRootElement(); //得到根元素
        }catch(Exception e){
            System.out.println(
"XML配置文件未加载成功,请检查");
            
throw new RuntimeException(e);
        }
    }
       将load方法静态初始化:
    static{
        load();
    }
       通过XPATH路径得到对应的元素:
    /**
     * 通过XPATH得到元素对象
     * 
@param xPath XPATH路径
     * 
@return 获得Element对象
     
*/
    
public static Element getElement(String xPath){
        
return (Element)coreModel.selectSingleNode(xPath);
    }
       再写一个方法,读取数据源配置信息,将之放入HashMap中:
    /**
     * 取得数据源配置信息放入HashMap中
     * 
@param hashmap 存放取得的数据源键值对
     * 
@return 返回存放信息的HashMap
     
*/
    
public static HashMap<String,String> iterateXML(HashMap<String,String> hashmap){
        
try{
            Element database 
= getElement("//demo/database"); //得到database节点
            List list = database.elements(); //得到database元素下的子元素集合
            /*
             * 循环遍历集合中的每一个元素
             * 将每一个元素的元素名和值作为键值对放入HashMap中
             
*/
            
for(Object obj:list){
                Element element 
= (Element)obj;
                
//getName()是元素名,getText()是元素值
                hashmap.put(element.getName(), element.getText());
            }        
        }
catch(Exception e){
            e.printStackTrace();
        }
        
return hashmap;
    }
       构造函数:
    /**
     * 构造函数初始化
     
*/
    
public DataBaseConnect(){
        HashMap
<String,String> hashmap = new HashMap<String,String>();
        hashmap 
= iterateXML(hashmap);//取得数据源配置信息
        driver = hashmap.get(Constant.DRIVER);
        url 
= hashmap.get(Constant.URL);
        username 
= hashmap.get(Constant.USERNAME);
        password 
= hashmap.get(Constant.PASSWORD);
    }
       创建数据库连接及关闭等操作,此处省略,请查看源码。
       最后我们写一个main方法来测试一下是否能够连接数据库:

    public static void main(String[] args){
        DataBaseConnect db 
= new DataBaseConnect();
        Connection con 
= db.getConnection();
        
try{
            PreparedStatement psmt 
= con.prepareStatement("select count(*) from help_keyword");
            ResultSet rs 
= psmt.executeQuery();
            rs.next();
            System.out.println(rs.getString(
1));
            rs.close();
            psmt.close();
            db.close(con);
        }
catch(Exception e){
            
throw new RuntimeException(e);
        }
    }
       如果没问题,控制台将打印出:381 的结果。
       这里附上DBConnect.xml中SQL Server 2000和Oracle的配置,其中SQL Server采用JTDS驱动。
<?xml version="1.0" encoding="UTF-8"?>
<demo>
    
<database>
        
<driver>net.sourceforge.jtds.jdbc.Driver</driver>
        
<url>jdbc:jtds:sqlserver://127.0.0.1:1433/pubs</url>
        
<username>sa</username>
        
<password>自己密码(无密码就空着)</password>
    
</database>
</demo>

<?xml version="1.0" encoding="UTF-8"?>
<demo>
    
<database>
        
<driver>oracle.jdbc.driver.OracleDriver</driver>
        
<url>jdbc:oracle:thin:@127.0.0.1:1521:自己的SID</url>
        
<username>system</username>
        
<password>自己密码(无密码就空着)</password>
    
</database>
</demo>
    本着对别人负责,同时也是对自己负责,全部代码,大象都是亲手写出来在电脑上测试过,并且还模拟了产生异常的环境,请大家放心使用。
    点击下载:dom4j-1.6.1.jar  jaxen-1.1-beta-7.jar  mysql-connector.jar  jtds.jar  classes12.jar
    点击下载:demo  (直接导入即可,加入上面的jar包)
    本文为菠萝大象原创,如要转载请注明出处。
posted on 2008-08-09 22:24 菠萝大象 阅读(7081) 评论(8)  编辑  收藏 所属分类: dom4j&jdom

评论:
# re: dom4j实战(一)——使用dom4j从XML中读取数据源配置 2008-08-18 10:49 | 昨夜流星
顶一下,呵呵,正想学习DOM4J,希望楼主能继续写下去!  回复  更多评论
  
# re: dom4j实战(一)——使用dom4j从XML中读取数据源配置 2009-01-04 16:59 | 王维娜
支持,谢谢搂主  回复  更多评论
  
# re: dom4j实战(一)——使用dom4j从XML中读取数据源配置 2010-05-24 21:32 | 大灰狼
我把你的demo下载后,导入myeclipse中,运行时出现如下的错误提示:
XML配置文件未加载成功,请检查
java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: org.dom4j.DocumentException: null Nested exception: null
at com.demo.database.DataBaseConnect.load(DataBaseConnect.java:50)
at com.demo.database.DataBaseConnect.<clinit>(DataBaseConnect.java:36)
Caused by: org.dom4j.DocumentException: null Nested exception: null
at org.dom4j.io.SAXReader.read(SAXReader.java:484)
at org.dom4j.io.SAXReader.read(SAXReader.java:343)
at com.demo.database.DataBaseConnect.load(DataBaseConnect.java:46)
... 1 more
Exception in thread "main"
我把文件路径改为了tring DB_CONFIG = "/DBConnect.xml";如果是原来的tring DB_CONFIG = "DBConnect.xml";则不提示出错,但是输出的,url,username,password等全是NUll  回复  更多评论
  
# re: dom4j实战(一)——使用dom4j从XML中读取数据源配置 2010-05-25 08:47 | 菠萝大象
@大灰狼
你的这个问题应该是把路径设置错了,你如果没改动配置文件的位置,就不要改动常量中设置的值,这两者一定要对应,我的例子都测试过的,不然我也不敢放上来。  回复  更多评论
  
# re: dom4j实战(一)——使用dom4j从XML中读取数据源配置 2010-05-25 10:49 | 大灰狼
我是把你的demo全部导入的,jar包是有的dom4j-1.6.1.jar,导进来直接运行的时候输出的url,username,password等全是NULL  回复  更多评论
  
# re: dom4j实战(一)——使用dom4j从XML中读取数据源配置 2010-05-25 10:59 | 大灰狼
发现DataBaseConnect()这个构造函数没有运行  回复  更多评论
  
# re: dom4j实战(一)——使用dom4j从XML中读取数据源配置 2010-05-25 11:14 | 大灰狼
现在好了,谢谢菠萝大象同志,原因是我没有导入jaxen-1.1-beta-6.jar,加入这个一切顺利  回复  更多评论
  
# re: dom4j实战(一)——使用dom4j从XML中读取数据源配置 2010-05-25 21:48 | 菠萝大象
@大灰狼
呵呵,恭喜你,自己调试成功,又积累了一次经验。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: