在基于 servlet 的应用程序中放置以及如何读取配置资源文件?
Posted
技术标签:
【中文标题】在基于 servlet 的应用程序中放置以及如何读取配置资源文件?【英文标题】:Where to place and how to read configuration resource files in servlet based application? 【发布时间】:2020-11-30 12:36:29 【问题描述】:在我的 Web 应用程序中,我必须向一组预定义用户发送电子邮件,例如 finance@xyz.com
,因此我希望将其添加到 .properties
文件并在需要时访问它。这是一个正确的程序,如果是,那么我应该把这个文件放在哪里?我正在使用 Netbeans IDE,它有两个单独的文件夹用于源文件和 JSP 文件。
【问题讨论】:
JNDI 也许是一个解决方案? 【参考方案1】:这是你的选择。 Java Web 应用程序归档 (WAR) 中基本上有三种方式:
1。放在类路径中
这样您就可以通过ClassLoader#getResourceAsStream()
使用类路径相对路径加载它:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("foo.properties");
// ...
Properties properties = new Properties();
properties.load(input);
这里 foo.properties
应该被放置在 webapp 的默认类路径所覆盖的根目录之一中,例如webapp 的/WEB-INF/lib
和/WEB-INF/classes
,服务器的/lib
,或JDK/JRE 的/lib
。如果属性文件是特定于 webapp 的,最好将其放在 /WEB-INF/classes
中。如果您在 IDE 中开发标准 WAR 项目,请将其放在 src
文件夹(项目的源文件夹)中。如果您使用的是 Maven 项目,请将其放在 /main/resources
文件夹中。
您也可以将其放在默认类路径之外的某个位置,并将其路径添加到应用服务器的类路径中。例如在 Tomcat 中,您可以将其配置为 Tomcat/conf/catalina.properties
的 shared.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");
// ...
但是,属性文件的可见性取决于相关的类加载器。它只对与加载该类的类加载器相同的类加载器可见。所以,如果类是由例如加载的服务器通用类加载器而不是webapp类加载器,并且属性文件在webapp本身内部,那么它是不可见的。上下文类加载器是您最安全的选择,因此您可以将属性文件“无处不在”放在类路径中和/或您打算能够从 webapp 覆盖服务器提供的文件。
2。放到网页内容中
这样您就可以通过 ServletContext#getResourceAsStream()
使用 webcontent-relative 路径加载它:
InputStream input = getServletContext().getResourceAsStream("/WEB-INF/foo.properties");
// ...
请注意,我已经演示了将文件放在/WEB-INF
文件夹中,否则任何网络浏览器都可以公开访问它。另请注意,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,则将其放在项目外部的类路径中(如果需要,将目录添加到类路径中)。
如果您希望能够使用Properties#store()
方法从Web 应用程序内部以编程方式编辑属性文件,请将其放在Web 应用程序外部。由于Properties#store()
需要Writer
,因此您不能使用磁盘文件系统路径。该路径又可以作为 VM 参数或系统属性传递给 Web 应用程序。作为预防措施,never use getRealPath()
。部署文件夹中的所有更改都将在重新部署时丢失,原因很简单,更改不会反映在原始 WAR 文件中。
另见:
getResourceAsStream() vs FileInputStream Adding a directory to tomcat classpath Accessing properties file in a JSF application programmatically【讨论】:
“我个人更喜欢把它放在项目外的classpath中(在classpath中添加新的路径)”迷茫,能举个例子吗? @Blankman 他可能的意思是创建一个新文件夹,将所有自定义配置文件放在那里,然后将该文件夹添加到类路径中。所以:1)在某处创建一个名为“appconfs”的文件夹(甚至可能是/etc/appconfs
2)将该文件夹添加到应用服务器/域的类路径中。第二步是特定于应用服务器的,我认为没有通用示例。
Re: 2: 为什么"WEB-INF/filename.properties"
和"/WEB-INF/filename.properties"
(注意开头的/
)都可以工作?有什么理由比另一个更喜欢一个吗?
过去一天我已经解决了这个问题。我无法加载我的属性文件。我可以从两个地方加载它。一个是系统目录,一个是本地驱动器。它适用于本地主机。但我想在亚马逊上部署它。
@Techguy:当路径无效或资源实际上没有放置在应该放置的位置时,它将返回 null。【参考方案2】:
警告词:如果您将配置文件放在 WEB-INF/classes
文件夹中,并且您的 IDE(例如 Eclipse)执行清理/重建,它将删除您的 conf 文件,除非它们位于 Java 源目录中。 BalusC 的出色回答在选项 1 中暗示了这一点,但我想强调一下。
我了解到,如果您在 Eclipse 中“复制”一个 Web 项目,它会从任何源文件夹进行清理/重建。在我的例子中,我从我们的 POJO java 库中添加了一个“链接源目录”,它将编译到 WEB-INF/classes
文件夹。在该项目(不是 Web 应用程序项目)中进行清理/重建会导致同样的问题。
我曾考虑将我的 conf 文件放在 POJO src 文件夹中,但这些 conf 文件都是用于 WEB-INF/lib
文件夹中的第 3 方库(如 Quartz 或 URLRewrite),所以这没有意义。当我开始使用它时,我计划测试将其放入 web 项目的“src”文件夹中,但该文件夹目前是空的,并且其中包含 conf 文件似乎不优雅。
所以我投票赞成将 conf 文件放在 WEB-INF/commonConfFolder/filename.properties
,next 到 classes 文件夹,这是 Balus 选项 2。
【讨论】:
如果你把你的配置文件放在 WEB_INF 的一个子文件夹中,那么你如何到达它呢?我没有说'configFiles/prop.properties' 好的,这确实可以将属性文件放在“Java Resources/src/”下,它在我的一个包中不起作用,需要位于 src 的根目录下。您对 classes 文件夹的警告是一个有效的问题。【参考方案3】:例如:在 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
文件应该放在哪里?
@LorisFoe 根据上下文,我认为 chat.properties 应该放在 web 内容根目录下(即 WEB-INF 的父目录)【参考方案4】:
它只需要在类路径中(也就是确保它作为构建的一部分在 .war 中的 /WEB-INF/classes 下结束)。
【讨论】:
嗨,谢谢你的想法,但它告诉我找不到指定的文件,是的,路径问题如何给出路径【参考方案5】:您可以使用您的源文件夹,这样无论何时构建,这些文件都会自动复制到类目录中。
不要使用属性文件,而是使用 XML 文件。
如果数据太小,你甚至可以使用 web.xml 来访问属性。
请注意,这些方法中的任何一种都需要重新启动应用服务器才能反映更改。
【讨论】:
我放在网页文件夹中但无法访问它找不到文件错误来了如何设置路径 如果您的文件最终位于 WEB-INF/classes 文件夹中,它会自动设置到类路径中【参考方案6】:假设您的代码正在寻找 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
【讨论】:
以上是关于在基于 servlet 的应用程序中放置以及如何读取配置资源文件?的主要内容,如果未能解决你的问题,请参考以下文章
为基于打字稿的库在 package.json 类型字段中放置啥
在导航栏中放置一个基于自定义视图的 UIBarButtonItem 而没有默认的水平填充