数据库参数的可配置性(web.xml)
为了达到松耦合,数据库的连接参数具有可配置性是比较重要的,这样如果迁移到其他的数据库也比较方便,而且代码更易于维护,代码与数据库连接参数完全分离。
具体做法:
1. 将所有的数据库连接参数配置在web.xml文件中,当然也可以写在db.properties属性文件中,文件名db可以随便改。例如:
<!-- 数据库连接参数的可配置性 --> <context-param> <param-name>dburl</param-name> <param-value>jdbc:mysql://localhost/tyy</param-value> </context-param>
<context-param> <param-name>username</param-name> <param-value>root</param-value> </context-param>
<context-param> <param-name>password</param-name> <param-value>passwd</param-value> </context-param>
<context-param> <param-name>driver</param-name> <param-value>com.mysql.jdbc.Driver</param-value> </context-param>
|
这样,就将所有的数据库连接参数配置到了web应用中,下面就看怎样读取这些配置信息,从而来连接数据库
2. 编写工具类Config.java 和 AppListener.java
Config.java 的代码如下:
package com.tyy.news.db;
import java.util.HashMap; import java.util.Map;
public class Config {
private static Config instance; private Map<String, String> map = new HashMap<String, String>(); // 通过一个Map来存储配置信息 static { //初始化Config,使用单例,保持其在应用期间只有一个实例,避免不必要的内存损耗 if (instance == null) { instance = new Config(); } }
private Config() { }
public static Config getInstance() { //静态工厂方法获取Config实例 return instance; } /** * 由于在容器初始化的时候map的值已经被初始化,且值在运行期间也不会改变,故不需要 * 考虑addKeyValue()和getValue()的同步性. * @param key * @param value */ public void addKeyValue(String key, String value) { map.put(key, value); }
public String getValue(String key) { return map.get(key); }
public Map<String, String> getMap() { return map; } } |
AppListener.java代码如下:该类必须实现javax.servlet.ServletContextListener接口
package com.tyy.news.db;
import java.util.Enumeration;
import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener;
public class AppListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent event) { System.out.println("============contextDestroyed()================");
} /** * 读取web.xml中的初始化信息,并将其放入Config对象中map里面,从而达到全局调用。 * 在容器初始化的时候,肯定会调用该方法,故在该方法中对这些数据进行初始化是比较合适的。 */ public void contextInitialized(ServletContextEvent event) { System.out.println("before contextInitialized");
ServletContext context = event.getServletContext(); Config config = Config.getInstance(); Enumeration<String> parameters = context.getInitParameterNames(); while(parameters.hasMoreElements()) { String parameter = parameters.nextElement(); config.addKeyValue(parameter, context.getInitParameter(parameter)); }
System.out.println("map.size() = > " + config.getInstance().getMap().size());
System.out.println("after contextInitialized");
}
}
|
AppListener是一个过滤器,故需要在web.xml中进行注册
<listener>
<listener-class>com.tyy.news.db.AppListener</listener-class>
</listener>
AppListener主要是在容器启动的时候,自动读取web.xml中的配置信息,并以此来初始化Config对象的内部数据结构,也即一个Map。这样在整个应用期间,都可以通过此Map来获取信息。
3. 编写数据库连接类
public static Connection getConnection() { // 不通过容器的话,Config.getInstance()所获得实例则是另外的实例,其中的Map数据结构为空,也即取不到任何有用的信息,全部都为空,这也是为什么无法脱离容器的原因。 String DBURL = Config.getInstance().getValue("dburl"); String USERNAME = Config.getInstance().getValue("username"); String PASSWORD = Config.getInstance().getValue("password"); String DRIVER = Config.getInstance().getValue("driver");
Connection conn = null; try { Class.forName(DRIVER); conn = DriverManager.getConnection(DBURL, USERNAME, PASSWORD); } catch (Exception e) { e.printStackTrace(); } return conn; } |
可以通过这种方式来获得数据库连接,但是此连接不可以脱离容器,也即如果通过下面这种方法进行测试的话,会返回错误的结果。
/** * 此处测试不成功,说明不能够脱离容器进行测试。所有的连接参数都在容器初始化的时候从web.xml中 * 取出来,而单独运行的话,则无法获得这些连接参数,故会出现java.lang.NullPointException异常 * @param args */ public static void main(String[] args) { System.out.println("conn => " + DBConnection.getConnection()); } |
这样获得的数据库简介会不能够脱离容器的,因为一旦离开容器,所有的值都无法从数据库中获得。
接下来就可以利用数据库的连接来进行一系列的CRUD操作了。
使用web.xml文件来配置数据库连接参数的目的也达到了。
数据库参数的可配置性(dbinfo.properties)
1. 类似使用web.xml文件,只需要将其中的连接参数放入属性文件中即可,这次是放在了dbinfo.properties中,当然可以改名
dbinfo.properties文件内容如下:我使用的是Access数据库,通过配置数据源来实现的
dburl = jdbc:odbc:newspublish driver = sun.jdbc.odbc.JdbcOdbcDriver |
接下来编写AppListener 文件,该文件用来读取配置信息,当然相对于之前的读取方式会有所不同,但原理还是一致的。该类必须实现javax.servlet.ServletContextListener接口
内容如下:
package com.tyy.news.db;
import java.util.Enumeration; import java.util.ResourceBundle;
import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener;
public class AppListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent event) { System.out.println("============contextDestroyed()================");
} /** * 读取dbinfo.properties中的初始化信息,并将其放入Config对象中map里面,从而达到全局调用。 * 在容器初始化的时候,肯定会调用该方法,故在该方法中对这些数据进行初始化是比较合适的。 */ public void contextInitialized(ServletContextEvent event) { Config config = Config.getInstance();
ResourceBundle rb = ResourceBundle.getBundle("dbinfo"); Enumeration<String> parameters= rb.getKeys(); while(parameters.hasMoreElements()) { String parameter = parameters.nextElement(); config.addKeyValue(parameter, rb.getString(parameter)); } }
}
|
java.util.ResourceBundle是用来读取属性文件的,相信用过国际化的人都知道该类。
其中包含了一系列读取国际化资源文件的方法,此处并没有使用这些,只是简单的使用了其查找属性文件并读取之的功能。
Config类并没有任何的改变。
接下来就是在数据库连接类中来建立数据库连接了。方法也和之前的相似。
public static Connection getConnection() {
String DBDRIVER = Config.getInstance().getValue("driver"); String DBURL = Config.getInstance().getValue("dburl");
Connection conn = null; try { Class.forName(DBDRIVER); conn = DriverManager.getConnection(DBURL); } catch (Exception e) { e.printStackTrace(); } return conn; } |
这样,就获得了数据库连接。通过属性文件来加载数据库配置信息也完成了。
当然获得数据库配置参数的方式还有很多种,很多种框架(如Hibernate)都提供了非常优秀的解决方法,但目的都是达到分离的作用。
此种方法也可以用在类似的实现的配置与代码分离的功能。