为减少硬编码,项目中要使用配置文件存储一些会随部署环境的变化而改变的变量值,比如别的web容器发布的子系统的跳转地址,下面是几个比较简单的实现方式。
- 1. 利用ServletContext
servlet容器在启动时会为每个web应用创建唯一的servlet context对象,可以把ServletContext看成是一个Web 应用的服务器端组件的共享内存,在ServletContext中可以存放共享数据。ServletContext对象只在web应用被关闭的时候才被销毁,不同的web应用,ServletContext各自独立存在,其内提供的方法可以在同一web应用下的所有servlet中被使用。利用ServletContext有以下两种方式:
- 直接将配置写在web.xml文件中。
如果需要配置的变量值比较少,放在web.xml文件中可谓是简单明了。在web.xml文件的根节点前面的位置写下类似的配置,就可以为本web应用设置context参数:
<context-param> <param-name>Author</param-name> <param-value>NearEast</param-value> </context-param>
获取context-param可以使用ServletContext对象。Servlet中通过[getServletconfig().]getServletContext()来获取一个ServletContext对象,使用该对象的getInitParameter(String name)方法即可获取指定名称的参数。
在JSP中,application内置对象就是ServletContext。
- 利用ServletContext对象读取额外的资源文件。
添加额外的配置文件放到classpath中,例如db.properties,放在src的根目录下;其内容如下:
url=jdbc\:mysql\://localhost\:3306/3g ; user=neareast; password=123;
假定我们已经获取了ServletContext对象,并保存在context变量中,如:
ServletContext context =this.getServletContext();
我们有多种方式来读取资源文件
//第一种方式 URL url = context.getResource("WEB-INF/classes/db.properties"); InputStream is = url.openStream(); //第二种方式 /*读取db.properties文件*/ String path =context.getRealPath("WEB-INF/classes/db.properties"); /*根据文件的路径 构建文件对象*/ File file = new File(path); /*根据file文件对象 创建输入流*/ InputStream is = new FileInputStream(file); //第三种方式 InputStream is = context.getResourceAsStream("WEB-INF/classes/db.properties ");
得到文件流之后,就可以用Properties类来对该文件解析了(如果是xml配置文件,则应该使用相应的解析工具):
/* 解析properties的文件 */ Properties prop = new Properties(); // 从输入流中读取属性列表(键和元素对)。 prop.load(is); Set<String> set = prop.stringPropertyNames(); // 遍历set集合 Iterator<String> it = set.iterator(); while (it.hasNext()) { String key = it.next(); String value = prop.getProperty(key); System.out.println(key + "-----" + value); }
- 2. 利用ServletConfig
config对象与context相比,就有了很大的局限性。为一个servlet配置初始化参数可以这么写:
<servlet> <servlet-name>DemoServlet</servlet-name> <servlet-class>com.neareast.DemoServlet</servlet-class> <init-param> <param-name>College</param-name> <param-value>JiLin University</param-value> </init-param> </servlet>
由于init-param是配置在<servlet>标签里的,只能由这个Servlet来读取。当ServletConfig对象在servlet中被实例化后,对任何客户端在任何时候访问有效。但是一个servlet的ServletConfig对象不能被另一个servlet访问,也就是说,在本servlet声明后的ServletConfig只能在本servlet内被访问,属于内部持久有效的变量。
配置完毕后,直接在Servlet中调用getInitParameter(String name)方法即可获取相应的参数。也可以用ServletConfig对象来获得参数,而ServletConfig可以通过在Servlet中调用getServletConfig()方法来得到。
在JSP中,config内置对象就是ServletConfig。
- 3. 利用Spring配置专用的常量Bean属性
此方法是笔者在总结前两条的时候突然想到的。笔者常常会使用一个常量类统一封装项目中用到的所有常量,将这些常量声明为常量类的public static final属性,这样就可以随时在程序中的其它地方引用了。既然spring的核心就是IoC,我们可以用Spring来初始化这个类的static属性。由于static属性是类属性,不依赖具体的实例对象,这样我们就可以达到在配置文件中配置常量的目的了。
final属性的初始化比较特殊,final static的属性只能在类的静态块中初始化,或者在定义的时候初始化,所以本方法中常量属性不能是final类型的,项目中要确保没有代码会对这些公有的static属性随意更改。
具体做法是,声明一个普通的类,定义几个public static的属性,同时给这几个属性声明相应的setter方法;然后在任意spring的配置文件中,配置该类的初始化属性即可。相应的Java类如下:
package com.neareast.commons; public class Constants { public static String YAGL_LOGINACTION = "#"; public static String ZHDD_LOGINACTION = "#"; public static String QWDD_LOGINACTION = "#"; public static String SPJK_LOGINACTION = "#"; public String getYAGL_LOGINACTION() { return YAGL_LOGINACTION; } public String getZHDD_LOGINACTION() { return ZHDD_LOGINACTION; } public String getQWDD_LOGINACTION() { return QWDD_LOGINACTION; } public String getSPJK_LOGINACTION() { return SPJK_LOGINACTION; } public static void setYAGL_LOGINACTION(String yAGL_LOGINACTION) { YAGL_LOGINACTION = yAGL_LOGINACTION; } public static void setZHDD_LOGINACTION(String zHDD_LOGINACTION) { ZHDD_LOGINACTION = zHDD_LOGINACTION; } public static void setQWDD_LOGINACTION(String qWDD_LOGINACTION) { QWDD_LOGINACTION = qWDD_LOGINACTION; } public static void setSPJK_LOGINACTION(String sPJK_LOGINACTION) { SPJK_LOGINACTION = sPJK_LOGINACTION; } }
配置示意如下:
<bean id="constants" class="com.neareast.commons.Constants"> <property name="YAGL_LOGINACTION"> <value>http://192.168.19.133:8003/yagl/tiles/login.action</value> </property> <property name="ZHDD_LOGINACTION"> <value>http://192.168.19.133:7001/MonitorFJ/tiles/login.action</value> </property> <property name="QWDD_LOGINACTION"> <value>http://192.168.19.133:8081/gwqw-webapp/system/FJlogin.action</value> </property> <property name="SPJK_LOGINACTION"> <value>#</value> </property> </bean>
注意Eclipse自动生成的setter方法是静态的static方法,使用Spring初始化该类时,在Spring3.0.x版本下报错:
解决办法是将项目使用的spring升级到3.1.x版本,或者把setter方法的static修饰去掉即可。
本文前两节涉及到的完整的配置文件如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="NearEast_Demo" version="2.5"> <context-param> <param-name>Author</param-name> <param-value>NearEast</param-value> </context-param> <context-param> <param-name>PersonalPage</param-name> <param-value>http://blog.csdn.net/NearEast</param-value> </context-param> <servlet> <servlet-name>DemoServlet</servlet-name> <servlet-class>com.neareast.DemoServlet</servlet-class> <init-param> <param-name>College</param-name> <param-value>JiLin University</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>DemoServlet</servlet-name> <url-pattern>/servlet/DemoServlet</url-pattern> </servlet-mapping> <servlet> <servlet-name>jspServlet</servlet-name> <servlet-class>/servlet.jsp</servlet-class> <init-param> <param-name>nationality</param-name> <param-value>China</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>jspServlet</servlet-name> <url-pattern>/servlet/jspServlet</url-pattern> </servlet-mapping> </web-app>