何以解忧?唯有Java

其实程序员也懂得浪漫!
posts - 90, comments - 637, trackbacks - 0, articles - 2
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
    最近在重构自己的小Demo 想把自己的下Demo 变成可以配置的程序。但是遇到了一些困难,走了不少的弯路,最终还是解决了。 如果你是个牛人,你不用看了,写这些东西是给和我一样的菜鸟看的。
先说说我的Demo吧,我写的是一个简单新闻管理系统,很简陋的那种,不过麻雀虽小,但是五脏俱全。
基本的增、删、查、改,都有,用到了FCKeditor。一开始我连接数据库用的是最原始的方法,把数据库的连接信息全写在代码里,写完以后就没去管他了,十一放假这几天,看了看自己的代码,觉得代码结果不好,于是就开始重构自己的代码,首先就是重写数据库的连接管理我把连接数据库的一些基本信息写到了database.properties 文件里,然后从程序中读取连接数据库所需要的信息。但是看似简单的东西,比且很容易的完成的工作,我却遇到了不少麻烦。首先就是路径的问题,其次是该以何种方式读取;就这两个问题困扰了两天。(呵呵,见笑了

java读取propterties文件有三种方法:
  ClassLoader.getResourceAsStream ("some/pkg/resource.properties");
  Class.getResourceAsStream (
"/some/pkg/resource.properties");
  ResourceBundle.getBundle (
"some.pkg.resource");
注意括号中代码的不同。

    先让大家看一段代码吧:
DataSource.java 文件:
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *一个单子设计模式数据库连接
 * 
@author guanminglin
 
*/
public class DataSource {

    
public static Connection conn;

    
public DataSource() throws IOException {
        {
            
try {

                Properties props 
= new Properties();
                
//一定要用DataSource 
                InputStream in = DataSource.class.getResourceAsStream("/org/news/comm/database.properties");

                
//原先试过这下面两种方法,但是都不行
                
//FileInputStream in = new FileInputStream("database.properties");
                //InputStream in = Object.class.getResourceAsStream("/org/news/comm/database.properties")

                //下面两行是用来测试的
                String s 
= in.toString();
                System.out.println(
"s=="+s);
                
                props.load(in);
                in.close();
                String drivers 
= props.getProperty("jdbc.drivers");
                String url 
= props.getProperty("jdbc.url");
                String username 
= props.getProperty("jdbc.username");
                String password 
= props.getProperty("jdbc.password");
                Class.forName(drivers);
                conn 
= DriverManager.getConnection(url, username, password);
                in.close();
            } 
catch (SQLException ex) {
                Logger.getLogger(DataSource.
class.getName()).log(Level.SEVERE, null, ex);
            } 
catch (ClassNotFoundException ex) {
                Logger.getLogger(DataSource.
class.getName()).log(Level.SEVERE, null, ex);
            }

        }



    }
   

    
/**
     *如果连接为空则建立一个新连接
     * 
@return
     
*/
    
public static Connection getConnection() throws IOException {
        
if (conn == null) {
            
new DataSource();
        }
        
return conn;
    }
    
public void test(){
        String str 
= new String();
        

    }

    
public static void main(String[] args) throws IOException {
        
// TODO code application logic here
        //用于测试
        new DataSource();
        System.out.print(conn);
    }
}

我的文件包结构:


第一个要说的是:FileInputStream in = new FileInputStream("database.properties");
网上有很多人说这条语句是从当前目录中加载database.properties文件的,但是我得出的结果是:它是从classpath 中加载database.properties文件的
因为我用的是IDE 是NetBeans 我以为直接放在当前包内就可以了,但是我发现这样不行。具体放哪里我也不知道,后来用了另一种方法:

InputStream in = Object.class.getResourceAsStream("/org/news/comm/database.properties")
基本上是可以用了,一开始测试的时候还挺开心的。很顺利的就通过了,但是当我真正运行项目的时候问题又来了,程序报了 空指针引用 错误。我就很纳闷了为什么在单个文件里测试可以很容易的通过,一运行项目就会报错呢?于是开始Debug,不Debug 不知道,一用吓一跳:
InputStream in = Object.class.getResourceAsStream("/org/news/comm/database.properties")

in的值竟然是空的,难怪会报空指针错误了。单独测试DataSource.java文件的时候运行正常啊,没有报错,in 也有值,但是为什么运行项目的时候又没有值了呢?很是不解。

于是我google 了一把,最后看现了几篇好文章 说的是如何读取 propterties 文件。最终我发现用第二种
方法是有弊端的,关键就在Object 上,它所有类的父类,在单个文件中用他来读取propterties文件还可以但是一运行项目,他就不起作用了,也不知道为什么。难道是java 的bug??或者说是NetBeans的bug??
我同样的Eclipse 下测试过,结果是一样的。

最后我将输入流语句稍微改了一下,变成下面的样子:
InputStream in = DataSource.class.getResourceAsStream("/org/news/comm/database.properties")

其实就是改个类名而已,让他自身去定位propterties文件,就解决问题了。(注意括号中红色的部分,org前面的 "/" 绝对不能少,要不然会报错的。
无论是测试单文件还是,测试整个项目都没问题了。(那个高兴啊

database.propterties 文件很简单:
jdbc.drivers = com.mysql.jdbc.Driver
jdbc.url 
= jdbc:mysql://localhost:3306/news
jdbc.username = root
jdbc.password 
= root

总结一下读取propterties文件方法的不同:(JavaWorld里的内容,呵呵拿来用一下)

Behavioral differences

Method Parameter format Lookup failure behavior Usage example
ClassLoader.
getResourceAsStream()
"/"-separated names; no leading "/" (all names are absolute) Silent (returns null) this.getClass().getClassLoader()
.getResourceAsStream
("some/pkg/resource.properties")
Class.
getResourceAsStream()
"/"-separated names; leading "/" indicates absolute names; all other names are relative to the class's package Silent (returns null) this.getClass()
.getResourceAsStream
("resource.properties")
ResourceBundle.
getBundle()
"."-separated names; all names are absolute; .properties suffix is implied Throws unchecked
java.util.MissingResourceException
ResourceBundle.getBundle
("some.pkg.resource")


推荐给大家一篇JavaWorld里面好的文章,里面讲述使用不同方式读出propterties文件的方式,以及他们之间的不同:Smartly load your properties


评论

# re: 关于java 读取propterties 文件的疑惑 和问题的解决  回复  更多评论   

2008-10-03 21:38 by 隔叶黄莺
关键是 ClassLoader 的问题,不同的环境可能不同的类加载器层次,比如单独应用程序跑得好好的,一放到 Tomcat 就不那么回事了。

比如你用 Object.class 作为参照就会有这样的问题,如果以 DataSource.class 作参照,基本能保证 DataSource.class 是最低层加载器加载的,所以能够一致。

可以看看 Hibernate 的 org.hibernate.util.ConfigHelper 是怎么在不同环境中找到配置文件的。它依据了 Thread.currentThread().contextClassLoader 来定位配置文件的。

# re: 关于java 读取propterties 文件的疑惑 和问题的解决  回复  更多评论   

2008-10-03 21:46 by 免费小说
老板用的什么IDE

# re: 关于java 读取propterties 文件的疑惑 和问题的解决  回复  更多评论   

2008-10-03 21:54 by 日月雨林@gmail.com
@隔叶黄莺
谢谢您的回复,有空我会去看的。因为我还没有用过Hibernate 。呵呵
我觉得Javaworld 上的那篇文章不错。

# re: 关于java 读取propterties 文件的疑惑 和问题的解决  回复  更多评论   

2008-10-03 21:55 by 日月雨林@gmail.com
@免费小说
我的在文章中说了啊,我用的是NetBeans IDE ,
还有我不是什么“老板” 哦

# re: 关于java 读取propterties 文件的疑惑 和问题的解决[未登录]  回复  更多评论   

2008-10-07 11:05 by Matthew
转载了,谢谢
http://blog.csdn.net/djsl6071/archive/2008/10/07/3026735.aspx

# re: 关于java 读取propterties 文件的疑惑 和问题的解决[未登录]  回复  更多评论   

2008-10-20 15:24 by Joe
看不懂DataSource类中的getConnection()方法在这里有什么作用,请解释一下,谢谢```````````````````

# re: 关于java 读取propterties 文件的疑惑 和问题的解决  回复  更多评论   

2008-10-20 15:40 by 日月雨林@gmail.com
@Joe
这个方法不是有注释吗?

"如果连接为空则建立一个新连接"

# re: 关于java 读取propterties 文件的疑惑 和问题的解决[未登录]  回复  更多评论   

2008-10-20 15:58 by Joe
哦。这个getConnection()方法是在其他类里被调用的。我刚才是看这个方法都没在这里用到,所以有点不解

# re: 关于java 读取propterties 文件的疑惑 和问题的解决[未登录]  回复  更多评论   

2008-11-08 19:16 by Java爱好者
楼主:
你看我的代码怎么可以用呢。FileInputStream和Properties。你的属性文件所在位置不对的问题。

Properties pros = new Properties();
fis = new FileInputStream("dbconnection.properties");
pros.load(fis);
driver=pros.getProperty("driver");
url=pros.getProperty("db_url");
name=pros.getProperty("user");
password=pros.getProperty("password");
其中属性文件位于项目的根目录下,和src同级就可以了。我试验了没有问题。没有你说的那么麻烦吧。?
我使用的Netbeans6.0.1 中文版

# re: 关于java 读取propterties 文件的疑惑 和问题的解决  回复  更多评论   

2009-06-08 08:01 by absolutej
读属性文件的时候,我以前会以一个同意的文件夹来存,但是那样在以后项目发布的时候会报FileNotFoundException之类的异常,参考朋友的建议后,以后直接把properties文件跟调用类的文件放在一起,用调用类文件的Class文件自身来调用
Object.Class.getResourceAsStream("*.properties"),这样用一直满好的!

# re: 关于java 读取propterties 文件的疑惑 和问题的解决[未登录]  回复  更多评论   

2009-06-08 18:02 by absolutej
楼主,什么是单子设计模式,是不是单体设计模式?
假如是SingleTon模式的话,你这段代码,我真的没有看出了,请指教下?

/**
*一个单子设计模式数据库连接
* @author guanminglin
*/
public class DataSource {

public static Connection conn;

public DataSource() throws IOException {
{
try {

Properties props = new Properties();
//一定要用DataSource
InputStream in = DataSource.class.getResourceAsStream("/org/news/comm/database.properties");

//原先试过这下面两种方法,但是都不行
//FileInputStream in = new FileInputStream("database.properties");
//InputStream in = Object.class.getResourceAsStream("/org/news/comm/database.properties")
//下面两行是用来测试的
String s = in.toString();
System.out.println("s=="+s);

props.load(in);
in.close();
String drivers = props.getProperty("jdbc.drivers");
String url = props.getProperty("jdbc.url");
String username = props.getProperty("jdbc.username");
String password = props.getProperty("jdbc.password");
Class.forName(drivers);
conn = DriverManager.getConnection(url, username, password);
in.close();
} catch (SQLException ex) {
Logger.getLogger(DataSource.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(DataSource.class.getName()).log(Level.SEVERE, null, ex);
}

}



}

# re: 关于java 读取propterties 文件的疑惑 和问题的解决[未登录]  回复  更多评论   

2009-06-08 18:04 by absolutej
呵呵,是singleton模式,体现在这一段代码
/**
*如果连接为空则建立一个新连接
* @return
*/
public static Connection getConnection() throws IOException {
if (conn == null) {
new DataSource();
}
return conn;
}

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


网站导航: