在基于servlet的应用程序中,配置资源文件应该放在哪里,如何读取?

230

在我的Web应用程序中,我需要向一组预定义的用户(如finance@xyz.example)发送电子邮件,因此我希望将其添加到一个.properties文件中,并在需要时访问它。如果是这样,请问我应该将此文件放在哪里?我正在使用具有源文件和JSP文件两个单独文件夹的Netbeans IDE。


JNDI也许是一个解决方案? - Basil Bourque
6个回答

476

这是你的选择。在Java web应用程序存档(WAR)中,基本上有三种方法:


1. 将其放入类路径中

这样你就可以通过ClassLoader#getResourceAsStream()方法使用相对于类路径的路径进行加载:

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("foo.properties");
// ...
Properties properties = new Properties();
properties.load(input);

在一个Web应用程序的默认类路径下,例如Web应用程序的/WEB-INF/lib/WEB-INF/classes、服务器的/lib或JDK/JRE的/lib之一,应该放置foo.properties。如果属性文件是特定于Web应用程序的,则最好将其放置在/WEB-INF/classes中。如果您正在使用IDE开发标准WAR项目,请将其放入src文件夹(即项目的源文件夹)。如果您正在使用Maven项目,请将其放入/main/resources文件夹。
您还可以将其放置在默认类路径之外的某个位置,并将其路径添加到应用程序服务器的类路径中。例如,在Tomcat中,您可以将其配置为Tomcat/conf/catalina.propertiesshared.loader属性。
如果您已经将foo.properties放置在像com.example这样的Java包结构中,则需要按照以下方式加载它。
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("com/example/foo.properties");
// ...

请注意,上下文类加载器的路径不应以/开头。只有当您使用“相对”类加载器(例如SomeClass.class.getClassLoader())时,才确实需要以/开头。
ClassLoader classLoader = getClass().getClassLoader();
InputStream input = classLoader.getResourceAsStream("/com/example/foo.properties");
// ...

然而,属性文件的可见性取决于类加载器。它只对与加载该类的类加载器相同的类加载器可见。因此,如果该类由服务器共享类加载器而不是Web应用程序类加载器加载,并且属性文件位于Web应用程序本身内部,则该文件将不可见。上下文类加载器是最安全的选择,因此您可以在类路径中“随处”放置属性文件和/或打算能够在Web应用程序上覆盖服务器提供的文件。

2. 将其放入WebContent文件夹下

这样你就可以通过ServletContext#getResourceAsStream()并使用相对于WebContent文件夹的路径来加载它:

InputStream input = getServletContext().getResourceAsStream("/WEB-INF/foo.properties");
// ...

请注意,我已经演示了将文件放置在/WEB-INF文件夹中,否则它将可以被任何Web浏览器公开访问。另请注意,ServletContext在任何HttpServlet类中只能通过继承的GenericServlet#getServletContext()访问,在Filter中可以通过FilterConfig#getServletContext()访问。如果您不在servlet类中,则通常可以通过@Inject注入。

3. 将其放入本地磁盘文件系统中

这样,您就可以使用绝对本地磁盘文件系统路径以通常的java.io方式加载它:

InputStream input = new FileInputStream("/absolute/path/to/foo.properties");
// ...

注意使用绝对路径的重要性。相对于本地磁盘文件系统路径在Java EE Web应用程序中是绝对不可行的。另请参见下面第一个“参见”链接。


选择哪个?

只需根据您自己对可维护性的优缺点进行权衡。

如果属性文件是“静态”的,不需要在运行时更改,则可以将其保留在WAR中。

如果您希望能够在Web应用程序之外编辑属性文件,而无需每次重新构建和部署WAR,则将其放在项目之外的类路径中(如果必要,请添加目录到类路径中)。

如果您希望能够在Web应用程序内部以编程方式编辑属性文件,使用Properties#store()方法,请将其放在Web应用程序之外。由于Properties#store()需要一个Writer,因此不能使用磁盘文件系统路径。该路径可以作为VM参数或系统属性传递给Web应用程序。作为预防措施,永远不要使用getRealPath()。重新部署时,部署文件夹中的所有更改都会丢失,因为这些更改没有反映在原始WAR文件中。

另请参阅:


2
我个人更喜欢将其放在项目之外的类路径中(将新路径添加到类路径中)。困惑吗?你需要一个例子吗? - Blankman
4
@Blankman他可能指的是创建一个新文件夹,将所有自定义配置文件放在那里,并将该文件夹添加到类路径中。因此:1)在某处创建一个名为'appconfs'的文件夹(甚至可以是/etc/appconfs);2)将该文件夹添加到应用服务器/域的类路径中。第二步是应用服务器特定的,我认为没有通用的示例。 - Tuukka Mustonen
我已经困扰于这个问题一整天了。我无法加载我的属性文件。我可以从两个地方加载它。一个是系统目录,另一个是本地驱动器。它在本地主机上可以工作。但我想将其部署到亚马逊。 - Arun Raja
我正在使用NetBeans IDE,并将属性文件保存在Web Pages/resources中。我尝试通过"./Web Pages/resources/config.properties"访问它,但无法访问。请帮助我。 - Arun Raja
1
@Techguy:当路径无效或资源实际未放置在应放置的位置时,它将返回null。 - BalusC
显示剩余6条评论

10
警告:如果您将配置文件放在WEB-INF/classes文件夹中,并且您的IDE(例如Eclipse)进行了清除/重建操作,则会删除您的配置文件,除非它们位于Java源目录中。BalusC的答案在选项1中提到了这一点,但我想要强调一下。
我通过艰难的方式得知,如果您在Eclipse中“复制”Web项目,它会从任何源文件夹进行清理/重建。在我的情况下,我添加了一个“链接源目录”来自我们的POJO Java库,它将编译到 WEB-INF / classes 文件夹中。在该项目中进行清理/重建(而不是Web应用程序项目)会导致相同的问题。
我考虑将我的配置文件放在POJO src文件夹中,但是这些配置文件都是为第三方库(如Quartz或URLRewrite)而准备的,它们位于WEB-INF/lib文件夹中,因此这没有意义。计划在忙完后将其放入Web项目的“src”文件夹中进行测试,但是该文件夹目前为空,因此在其中放置配置文件似乎不太优雅。
因此,我建议将conf文件放在WEB-INF/commonConfFolder/filename.properties中,即类文件夹旁边,这是Balus选项2。

1
如果您将配置文件放在WEB_INF的子文件夹中,那么该如何访问它呢?我尝试使用'configFiles/prop.properties'但没有成功。 - JesseBoyd
好的,这个确实有效。将属性文件放在“Java Resources/src/”下可以工作,但是如果放在我的某个包内部就无法工作,必须放在src的根目录下。你关于classes文件夹被删除的警告是一个有效的问题。 - JesseBoyd

6

例如,在web.xml文件中标签

<context-param>
        <param-name>chatpropertyfile</param-name>
        <!--  Name of the chat properties file. It contains the name and description                   of rooms.-->     
        <param-value>chat.properties</param-value>
    </context-param>

在 chat.properties 文件中,您可以像这样声明属性:
例如:
Jsp = Discussion about JSP can be made here.
Java = Talk about java and related technologies like J2EE.
ASP = Discuss about Active Server Pages related technologies like VBScript and JScript etc.
Web_Designing = Any discussion related to HTML, JavaScript, DHTML etc.
StartUp = Startup chat room. Chatter is added to this after he logs in.

但是chat.properties文件应该放在哪里呢? - LetsGoBrandon
根据上下文,我认为chat.properties应该放在Web内容根目录下(即WEB-INF的父目录)。 - torez233

5

只需要将它放在类路径下(也就是确保它在构建过程中作为一部分以 /WEB-INF/classes 结尾的 .war 文件出现)即可。


嗨,感谢您的想法,但它告诉我找不到指定的文件,是的,这是路径问题,如何提供路径? - sansknwoledge

3
你可以使用源文件夹,这样每次构建时,这些文件会自动复制到类目录中。
不要使用属性文件,而要使用XML文件。
如果数据量很小,甚至可以使用web.xml来访问属性。
请注意,任何这些方法都需要应用服务器重新启动才能反映更改。

我把文件放在了webpages文件夹里,但无法访问它,提示文件未找到错误,如何设置路径? - sansknwoledge
1
如果您的文件最终位于WEB-INF/classes文件夹中,则它会自动设置为类路径。 - Kalpak

2
假设您的代码正在寻找名为app.properties的文件。将此文件复制到任何目录中,并通过在tomcat的bin目录中创建setenv.sh来将此目录添加到类路径中。
在tomcat的setenv.sh中(如果该文件不存在,则创建一个,tomcat将加载此setenv.sh文件):
#!/bin/sh CLASSPATH="$CLASSPATH:/home/user/config_my_prod/"
您不应该将属性文件放在./webapps//WEB-INF/classes/app.properties中。
Tomcat类加载器将使用WEB-INF/classes/中的属性文件覆盖该文件。
阅读推荐:https://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接