¿Dónde colocar y cómo leer los archivos de recursos de configuración en la aplicación basada en servlet?

222

En mi aplicación web tengo que enviar un correo electrónico a un conjunto de usuarios predefinidos [email protected], por lo que deseo agregarlo a un .propertiesarchivo y acceder a él cuando sea necesario. ¿Es este un procedimiento correcto? Si es así, ¿dónde debo colocar este archivo? Estoy usando Netbeans IDE que tiene dos carpetas separadas para los archivos fuente y JSP.

sansknwoledge
fuente
JNDI quizás podría ser una solución?
Basil Bourque

Respuestas:

464

Es tu elección. Básicamente, existen tres formas en un archivo de aplicación web Java (WAR):


1. Ponlo en classpath

Para que pueda cargarlo ClassLoader#getResourceAsStream()con una ruta relativa classpath:

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

Aquí foo.propertiesse supone que debe colocarse en una de las raíces que están cubiertas por el classpath predeterminado de una aplicación web, por ejemplo, aplicaciones web /WEB-INF/liby /WEB-INF/classesservidores /lib, o JDK / JRE /lib. Si el archivo de propiedades es específico de una aplicación web, lo mejor es colocarlo /WEB-INF/classes. Si está desarrollando un proyecto WAR estándar en un IDE, colóquelo en la srccarpeta (la carpeta de origen del proyecto). Si está utilizando un proyecto Maven, colóquelo en la /main/resourcescarpeta.

Alternativamente, también puede colocarlo en algún lugar fuera del classpath predeterminado y agregar su ruta al classpath del servidor de aplicaciones. En, por ejemplo, Tomcat puede configurarlo como shared.loaderpropiedad de Tomcat/conf/catalina.properties.

Si lo ha colocado foo.propertiesen una estructura de paquete Java como com.example, entonces necesita 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 a /. Solo cuando está utilizando un cargador de clases "relativo" como SomeClass.class.getClassLoader(), entonces realmente necesita comenzar con un /.

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 el que cargó la clase. Entonces, si la clase es cargada por, por ejemplo, el cargador de clases común del servidor en lugar del cargador de clases webapp, y el archivo de propiedades está dentro de la propia 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 todas partes" en el classpath y / o tiene la intención de poder anular uno proporcionado por el servidor desde la aplicación web.


2. Póngalo en contenido web

Para que pueda cargarlo ServletContext#getResourceAsStream()con una ruta relativa al contenido web:

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

Tenga en cuenta que he demostrado colocar el archivo en la /WEB-INFcarpeta, de lo contrario, cualquier navegador web hubiera podido acceder a él. También tenga en cuenta que el ServletContextestá en cualquier HttpServletclase solo accesible por el heredado GenericServlet#getServletContext()y Filterpor FilterConfig#getServletContext(). En caso de que no esté en una clase de servlet, generalmente solo es inyectable @Inject.


3. Póngalo en el sistema de archivos del disco local

Para que pueda cargarlo de la java.iomanera 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 de disco local son absolutamente imposibles en una aplicación web Java EE. Vea también el primer enlace "Ver también" a continuación.


¿Cuál elegir?

Solo sopese las ventajas / desventajas en su propia opinión de mantenibilidad.

Si los archivos de propiedades son "estáticos" y nunca necesitan cambiar durante el tiempo de ejecución, 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, póngalo 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 el interior de la aplicación web mediante el Properties#store()método, colóquelo fuera de la aplicación web. Como Properties#store()requiere a Writer, no puede usar una ruta de sistema de archivos de disco. Esa ruta a su vez se puede pasar a la aplicación web como argumento de VM o propiedad del sistema. Como precaución, nunca lo usegetRealPath() . Todos los cambios en la carpeta de implementación se perderán en una nueva implementación por la sencilla razón de que los cambios no se reflejan en el archivo WAR original.

Ver también:

BalusC
fuente
2
"Personalmente prefiero ponerlo en el classpath fuera del proyecto (agregar nueva ruta al classpath)" confundido, ¿puedes dar un ejemplo?
Blankman
44
@Blankman Probablemente signifique crear una nueva carpeta, poner todos sus archivos de configuración personalizados allí y agregar esa carpeta a la ruta de clase. Entonces: 1) Cree una carpeta llamada 'appconfs' en algún lugar (podría ser incluso /etc/appconfs2) Agregue esa carpeta al classpath del servidor / dominio de la aplicación. El segundo paso es específico del servidor de aplicaciones, no creo que haya un ejemplo genérico para eso.
Tuukka Mustonen
Re: 2: ¿Por qué ambos "WEB-INF/filename.properties"y "/WEB-INF/filename.properties"(fíjense /al principio) funcionarían? ¿Hay alguna razón para preferir uno sobre el otro?
Mr_and_Mrs_D
He solucionado este problema durante el último día. No puedo cargar mi archivo de propiedades. Puedo cargarlo desde dos lugares. Uno es el directorio del sistema y el otro es el disco local. Funciona con localhost. Pero quiero implementarlo en Amazon.
Arun Raja
Estoy usando netbeans IDE y mantengo el archivo de propiedades en páginas web / recursos. Intento acceder a él como "./Web Pages / resources / config.properties". No puedo acceder a él. Por favor, ayúdame.
Arun Raja
9

Palabra de advertencia: si coloca archivos de configuración en su WEB-INF/classescarpeta y su IDE, por ejemplo, Eclipse, realiza una limpieza / reconstrucción, destruirá sus archivos conf a menos que estén en el directorio fuente de Java. La gran respuesta de BalusC alude a eso en la opción 1, pero quería agregar énfasis.

Aprendí de la manera difícil que si "copia" un proyecto web en Eclipse, se limpia / reconstruye desde cualquier carpeta de origen. En mi caso, había agregado un "directorio fuente vinculado" de nuestra biblioteca POJO java, se compilaría en la WEB-INF/classescarpeta. Hacer una limpieza / reconstrucción en ese proyecto (no el proyecto de la aplicación web) causó el mismo problema.

Pensé en poner mis confs en la carpeta POJO src, pero estas confs son todas para librerías de terceros (como Quartz o URLRewrite) que están en la WEB-INF/libcarpeta, por lo que no tenía sentido. Planeo probar ponerlo en la carpeta "src" de proyectos web cuando lo encuentre, pero esa carpeta está actualmente vacía y tener archivos conf en ella parece poco elegante.

Así que voto por poner los archivos conf WEB-INF/commonConfFolder/filename.properties, al lado de la carpeta de clases, que es la opción 2 de Balus.

Ed Pike
fuente
1
si coloca su archivo de configuración en una subcarpeta de WEB_INF, ¿cómo lo alcanza? No he tenido suerte con decir 'configFiles / prop.properties'
JesseBoyd
ok, esto funciona colocando el archivo de propiedades en 'Java Resources / src /', no funciona desde uno de mis paquetes y debe estar en la raíz de src. su advertencia acerca de que la carpeta de clases se destruye es una preocupación válida.
JesseBoyd
6

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 puede declarar sus propiedades de esta manera

Por ej .:

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.
Subhash Pavuskar
fuente
5

Solo necesita estar en el classpath (también conocido como asegurarse de que termina bajo / WEB-INF / classes en .war como parte de la compilación).

Taylor Leese
fuente
hola gracias por la idea, pero me dice que no puede encontrar el archivo especificado, sí, es el problema del camino de cómo dar el camino
sansknwoledge
3

Puede hacerlo con su carpeta de origen para que cada vez que construya, esos archivos se copien automáticamente en el directorio de clases.

En lugar de usar el archivo de propiedades, use el archivo XML.

Si los datos son demasiado pequeños, incluso puede usar web.xml para acceder a las propiedades.

Tenga en cuenta que cualquiera de estos enfoques requerirá reiniciar el servidor de aplicaciones para que se reflejen los cambios.

Kalpak
fuente
coloqué en la carpeta de páginas web, pero no puedo acceder al archivo, no se encontró un error, aparece cómo configurar la ruta de acceso
sansknwoledge
1
si su archivo termina en la carpeta WEB-INF / classes, se configura automáticamente en el classpath
Kalpak
2

Suponga que su código está buscando el archivo, digamos app.properties. Copie este archivo a cualquier directorio y agregue este directorio a classpath, creando un setenv.sh en el directorio bin de tomcat.

En su setenv.sh de tomcat (si este archivo no existe, cree uno, tomcat cargará este archivo setenv.sh. #!/bin/sh CLASSPATH="$CLASSPATH:/home/user/config_my_prod/"

No debe tener sus archivos de propiedades en ./webapps//WEB-INF/classes/app.properties

El cargador de clases Tomcat anulará el del WEB-INF / classes /

Una buena lectura: https://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html

Thar
fuente