¿Dónde colocar y cómo leer los archivos de recursos de configuración en una aplicación basada en servlet?
En mi aplicación web tengo que enviar correos electrónicos a un conjunto de usuarios predefinidos como [email protected]
, por lo que deseo agregarlo a un .properties
archivo y acceder a él cuando sea necesario. ¿Es este un procedimiento correcto? De ser así, ¿dónde debo colocar este archivo? Estoy usando Netbeans IDE, que tiene dos carpetas separadas para los archivos fuente y JSP.
Es tu elección. Básicamente, existen tres formas en un archivo de aplicación web Java (WAR):
1. Ponlo en classpath
Para que puedas cargarlo ClassLoader#getResourceAsStream()
con una ruta relativa a classpath:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("foo.properties");
// ...
Properties properties = new Properties();
properties.load(input);
Se supone que aquí foo.properties
debe colocarse en una de las raíces que están cubiertas por la ruta de clase predeterminada de una aplicación web, por ejemplo, la aplicación web /WEB-INF/lib
y /WEB-INF/classes
el servidor /lib
o JDK/JRE /lib
. Si el archivo de propiedades es específico de la aplicación web, lo mejor es colocarlo en formato /WEB-INF/classes
. Si está desarrollando un proyecto WAR estándar en un IDE, colóquelo en src
la carpeta (la carpeta de origen del proyecto). Si está utilizando un proyecto Maven, colóquelo en /main/resources
la carpeta.
Alternativamente, también puede colocarlo en algún lugar fuera de la ruta de clase predeterminada y agregar su ruta a la ruta de clase del servidor de aplicaciones. Por ejemplo, en Tomcat puedes configurarlo como shared.loader
propiedad de Tomcat/conf/catalina.properties
.
Si lo ha colocado foo.properties
en una estructura de paquete Java como com.example
, entonces debe cargarlo como se muestra a continuación
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("com/example/foo.properties");
// ...
Tenga en cuenta que esta ruta de un cargador de clases de contexto no debe comenzar con un archivo /
. Solo cuando estás usando un cargador de clases "relativo" como SomeClass.class.getClassLoader()
, entonces necesitas iniciarlo con un archivo /
.
ClassLoader classLoader = getClass().getClassLoader();
InputStream input = classLoader.getResourceAsStream("/com/example/foo.properties");
// ...
Sin embargo, la visibilidad del archivo de propiedades depende del cargador de clases en cuestión. Solo es visible para el mismo cargador de clases que cargó la clase. Entonces, si la clase se carga, por ejemplo, mediante el cargador de clases común del servidor en lugar del cargador de clases de la aplicación web, y el archivo de propiedades está dentro de la aplicación web, entonces es invisible. El cargador de clases de contexto es su apuesta más segura, por lo que puede colocar el archivo de propiedades "en cualquier lugar" del classpath y/o desea poder anular uno proporcionado por el servidor desde la aplicación web.
2. Ponlo en contenido web.
Para que puedas cargarlo con ServletContext#getResourceAsStream()
una ruta relativa al contenido web:
InputStream input = getServletContext().getResourceAsStream("/WEB-INF/foo.properties");
// ...
Tenga en cuenta que he demostrado cómo colocar el archivo en /WEB-INF
una carpeta; de lo contrario, cualquier navegador web podría acceder a él de forma pública. También tenga en cuenta que ServletContext
está en cualquier HttpServlet
clase a la que solo pueda acceder el heredado GenericServlet#getServletContext()
y Filter
en FilterConfig#getServletContext()
. En caso de que no esté en una clase de servlet, generalmente solo se puede inyectar a través de @Inject
.
3. Ponlo en el sistema de archivos del disco local.
Para que puedas cargarlo de la java.io
forma habitual con una ruta absoluta del sistema de archivos del disco local:
InputStream input = new FileInputStream("/absolute/path/to/foo.properties");
// ...
Tenga en cuenta la importancia de utilizar una ruta absoluta. Las rutas relativas del sistema de archivos del disco local son absolutamente prohibidas en una aplicación web Java EE. Consulte también el primer enlace "Ver también" a continuación.
¿Cuál elegir?
Simplemente sopese las ventajas/desventajas en su propia opinión sobre la mantenibilidad.
Si los archivos de propiedades son "estáticos" y nunca necesitan cambiar durante el tiempo de ejecución, entonces puede mantenerlos en WAR.
Si prefiere poder editar archivos de propiedades desde fuera de la aplicación web sin la necesidad de reconstruir y volver a implementar el WAR cada vez, colóquelo en el classpath fuera del proyecto (si es necesario, agregue el directorio al classpath).
Si prefiere poder editar archivos de propiedades mediante programación desde dentro de la aplicación web utilizando Properties#store()
el método, colóquelo fuera de la aplicación web. Como Properties#store()
requiere un archivo Writer
, no puede utilizar una ruta del sistema de archivos del disco. Esa ruta, a su vez, se puede pasar a la aplicación web como un argumento de VM o propiedad del sistema. Como precaución, nunca utilizargetRealPath()
. Todos los cambios en la carpeta de implementación se perderán al volver a implementar por la sencilla razón de que los cambios no se reflejan en el archivo WAR original.
Ver también:
- getResourceAsStream() frente a FileInputStream
- Agregar un directorio al classpath de Tomcat
- Acceder al archivo de propiedades en una aplicación JSF mediante programación
Una advertencia: si coloca archivos de configuración en su WEB-INF/classes
carpeta y su IDE, digamos Eclipse, realiza una limpieza/reconstrucción, destruirá sus archivos de configuración a menos que estuvieran en el directorio fuente de Java. La excelente respuesta de BalusC alude a eso en la opción 1, pero quería agregar énfasis.
Aprendí por las malas que si "copias" un proyecto web en Eclipse, se limpia/reconstruye desde cualquier carpeta de origen. En mi caso, agregué un "directorio de origen vinculado" de nuestra biblioteca POJO java, se compilaría en la WEB-INF/classes
carpeta. Hacer una limpieza/reconstrucción en ese proyecto (no en el proyecto de la aplicación web) causó el mismo problema.
Pensé en poner mis configuraciones en la carpeta POJO src, pero estas configuraciones son todas para bibliotecas de terceros (como Quartz o URLRewrite) que están en la WEB-INF/lib
carpeta, por lo que no tenía sentido. Planeo probar a colocarlo en la carpeta "src" de proyectos web cuando lo haga, pero esa carpeta está actualmente vacía y tener archivos conf en ella parece poco elegante.
Así que voto por poner los archivos conf junto WEB-INF/commonConfFolder/filename.properties
a la carpeta de clases, que es la opción 2 de Balus.
Ej: en el archivo web.xml la etiqueta
<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>
Y chat.properties puedes declarar tus propiedades así
Por ejemplo:
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.