Forma más sencilla para servir estática de datos desde fuera de la aplicación de servidor en una aplicación web de Java
-
06-07-2019 - |
Pregunta
Tengo una aplicación web Java que se ejecuta en Tomcat.Quiero cargar las imágenes estáticas que se muestra tanto en la interfaz de usuario Web y en los archivos PDF generados por la aplicación.También nuevas imágenes serán guardadas por la carga a través de la interfaz de usuario Web.
No es un problema para hacer esto a través de la estática de los datos almacenados en el contenedor web, pero el almacenamiento y la carga de ellos desde fuera del contenedor web me está dando dolor de cabeza.
Prefiero no usar un servidor web como Apache para servir a los datos estáticos en este punto.Yo también no me gusta la idea de almacenar las imágenes en formato binario en una base de datos.
He visto algunas sugerencias de como tener el directorio de la imagen sea un enlace simbólico que apunta a un directorio fuera del contenedor web, pero se que este enfoque funciona tanto en Windows y *nix ambientes?
Algunos sugieren que la escritura de un filtro o un servlet para el manejo de la imagen de la porción, pero estas sugerencias han sido muy vaga y de alto nivel sin punteros a información más detallada sobre cómo lograr esto.
Solución
He visto algunas sugerencias de como tener el directorio de la imagen sea un enlace simbólico que apunta a un directorio fuera del contenedor web, pero se que este enfoque funciona tanto en Windows y *nix ambientes?
Si se adhiere de los *nix sistema de ficheros reglas de ruta de acceso (es decir,utilice exclusivamente las barras como en /path/to/files
), entonces funcionará en Windows, así sin la necesidad de jugar un poco con feo File.separator
cadena-concatenaciones.Sin embargo sólo se puede escanear en el mismo disco de trabajo como desde donde este comando se ha invocado.Así que si Tomcat es, por ejemplo, instalado en C:
a continuación, el /path/to/files
en realidad iba a apuntar a C:\path\to\files
.
Si los archivos están ubicados fuera de la webapp, y quieres tener Tomcat DefaultServlet
manejar, entonces todo lo que básicamente tiene que hacer en Tomcat es agregar el siguiente elemento de Contexto para /conf/server.xml
dentro de <Host>
etiqueta:
<Context docBase="/path/to/files" path="/files" />
De esta manera van a ser accesibles a través de http://example.com/files/...
.GlassFish/Payara ejemplo de configuración se puede encontrar aquí y WildFly ejemplo de configuración se puede encontrar aquí.
Si usted quiere tener el control sobre la lectura/escritura de archivos de ti mismo, entonces usted necesita para crear un Servlet
para este que básicamente se obtiene un InputStream
del archivo en el sabor de, por ejemplo, FileInputStream
y lo escribe en el OutputStream
de la HttpServletResponse
.
En la respuesta, debe establecer el Content-Type
cabecera para que el cliente conoce la aplicación que asociar el archivo.Y, debe establecer el Content-Length
encabezado de manera que el cliente puede calcular el progreso de la descarga, de lo contrario será desconocido.Y, debe establecer el Content-Disposition
encabezado attachment
si quieres un Guardar Como de diálogo, de lo contrario, el cliente intentará mostrar en línea.Finalmente, sólo se escribe el contenido del archivo a la respuesta de la secuencia de salida.
Aquí tenemos un ejemplo de un servlet:
@WebServlet("/files/*")
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String filename = URLDecoder.decode(request.getPathInfo().substring(1), "UTF-8");
File file = new File("/path/to/files", filename);
response.setHeader("Content-Type", getServletContext().getMimeType(filename));
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
Files.copy(file.toPath(), response.getOutputStream());
}
}
Cuando se asigna un url-pattern
de por ejemplo /files/*
, entonces usted puede llamar por http://example.com/files/image.png
.De esta manera usted puede tener más control sobre las solicitudes de la DefaultServlet
no, tales como proporcionar una imagen por defecto (es decir, if (!file.exists()) file = new File("/path/to/files", "404.gif")
o así).También el uso de la request.getPathInfo()
es preferido por encima de request.getParameter()
porque es más SEO friendly y de lo contrario, es decir, no elija el nombre de archivo correcto durante Guardar Como.
Se puede reutilizar la misma lógica para que sirven los archivos de base de datos.Simplemente reemplazar new FileInputStream()
por ResultSet#getInputStream()
.
Espero que esto ayude.
Vea también:
- Forma recomendada para guardar los archivos subidos en un servlet aplicación
- Resumen de la plantilla de un recurso estático servlet (en apoyo de caché de HTTP)
- Cómo recuperar y visualizar imágenes de una base de datos en una página JSP?
- Cómo transferir archivos de audio/vídeo como MP3, MP4, AVI, etc el uso de un Servlet
Otros consejos
Puede hacerlo colocando sus imágenes en una ruta fija (por ejemplo: / var / images, o c: \ images), agregue una configuración en la configuración de su aplicación (representada en mi ejemplo por la clase Settings.class), y cargarlos así, en un HttpServlet
tuyo:
String filename = Settings.getValue("images.path") + request.getParameter("imageName")
FileInputStream fis = new FileInputStream(filename);
int b = 0;
while ((b = fis.read()) != -1) {
response.getOutputStream().write(b);
}
O si desea manipular la imagen:
String filename = Settings.getValue("images.path") + request.getParameter("imageName")
File imageFile = new File(filename);
BufferedImage image = ImageIO.read(imageFile);
ImageIO.write(image, "image/png", response.getOutputStream());
entonces el código html sería <img src="imageServlet?imageName=myimage.png" />
Por supuesto, debería pensar en servir diferentes tipos de contenido: " image / jpeg " ;, por ejemplo, en función de la extensión del archivo. También debe proporcionar un poco de almacenamiento en caché.
Además, podría usar este servlet para reescalar la calidad de sus imágenes, proporcionando parámetros de ancho y alto como argumentos, y usando image.getScaledInstance(w, h, Image.SCALE_SMOOTH
), considerando el rendimiento, por supuesto.
Requisito :El acceso a los Recursos estáticos (imágenes/vídeos., etc.,) desde fuera de directorio de WEBROOT o desde un disco local
Paso 1 :
Crear una carpeta dentro de webapps de tomcat servidor., digamos que el nombre de la carpeta es myproj
Paso 2 :
Bajo myproj crear una WEB-INF de la carpeta en virtud de este crear un simple web.xml
código bajo web.xml
<web-app>
</web-app>
Estructura de directorios para los dos pasos anteriores
c:\programfile\apachesoftwarefoundation\tomcat\...\webapps
|
|---myproj
| |
| |---WEB-INF
| |
|---web.xml
Paso 3:
Ahora hay que crear un archivo xml con el nombre de myproj.xml en la siguiente ubicación
c:\programfile\apachesoftwarefoundation\tomcat\conf\catalina\localhost
CÓDIGO myproj.xml:
<Context path="/myproj/images" docBase="e:/myproj/" crossContext="false" debug="0" reloadable="true" privileged="true" />
Paso 4:
4) Ahora hay que crear una carpeta con el nombre myproj en el Correo de la unidad de disco duro y crear una nueva
carpeta con el nombre de las imágenes y el lugar de algunas de las imágenes de la carpeta imágenes (e:myproj\images\)
Supongamos myfoto.jpg se coloca debajo de e:\myproj\images\myfoto.jpg
4 B) crear una carpeta con el nombre de WEB-INF en e:\myproj\WEB-INF
y crear un web.xml en WEB-INF de la carpeta
Código web.xml
<web-app>
</web-app>
Paso 5:
Ahora crear una .documento html con el nombre de index.html y de lugar en las e:\myproj
CÓDIGO bajo index.html Bienvenido a Myproj
La Estructura de Directorios para el anterior Paso 4 y el Paso 5 es el siguiente
E:\myproj
|--index.html
|
|--images
| |----myfoto.jpg
|
|--WEB-INF
| |--web.xml
Paso 6:
Ahora inicie el servidor apache tomcat
Paso 7:
abra el navegador y escriba la dirección url de la siguiente manera
http://localhost:8080/myproj
entonces u mostrar el contenido que se proporciona en index.html
Paso 8:
Para Acceder a las Imágenes en su disco duro local (fuera de webroot)
http://localhost:8080/myproj/images/myfoto.jpg
Añadir a server.xml:
<Context docBase="c:/dirtoshare" path="/dir" />
Habilite el parámetro de listado de archivos dir en web.xml:
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
Esta es la historia de mi lugar de trabajo:
- Intentamos cargar múltiples imágenes y archivos de documentos usando Struts 1 y Tomcat 7.x.
- Intentamos escribir archivos cargados en el sistema de archivos, nombre de archivo y ruta completa a los registros de la base de datos.
- Intentamos separar las carpetas de archivos fuera del directorio de aplicaciones web . (*)
La siguiente solución es bastante simple, efectiva para el requisito (*):
En el archivo META-INF/context.xml
con el siguiente contenido:
(Ejemplo, mi aplicación se ejecuta en http://localhost:8080/ABC
, mi aplicación / proyecto llamado ABC
).
(esto también es contenido completo del archivo context.xml
)
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ABC" aliases="/images=D:\images,/docs=D:\docs"/>
(funciona con Tomcat versión 7 o posterior)
Resultado: Hemos creado 2 alias. Por ejemplo, guardamos imágenes en: D:\images\foo.jpg
y ver desde el enlace o usando la etiqueta de imagen:
<img src="http://localhost:8080/ABC/images/foo.jsp" alt="Foo" height="142" width="142">
o
<img src="/images/foo.jsp" alt="Foo" height="142" width="142">
(Yo uso Netbeans 7.x, Netbeans parece crear automáticamente el archivo WEB-INF\context.xml
)
Si decide enviar a FileServlet
, entonces también necesitará allowLinking="true"
en context.xml
para permitir que <=> atraviese los enlaces simbólicos.
Ver http://tomcat.apache.org/tomcat-6.0 -doc / config / context.html
si alguien no puede resolver su problema con la respuesta aceptada, tenga en cuenta las siguientes consideraciones:
- no es necesario mencionar
localhost:<port>
con<img> src
atributo. - asegúrese de ejecutar este proyecto fuera de eclipse, porque eclipse crea una entrada
context docBase
por sí sola dentro de su archivoserver.xml
local.
Lea el InputStream de un archivo y escríbalo en < code> ServletOutputStream para enviar datos binarios al cliente.
- Archivo local Puede leer un archivo directamente usando FileInputStream ('path / image.png') .
- archivos Mongo DataBase puede obtener InputStream usando GridFS .
@WebServlet("/files/URLStream")
public class URLStream extends HttpServlet {
private static final long serialVersionUID = 1L;
public URLStream() {
super();
}
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
File source = new File("D:\\SVN_Commit.PNG");
long start = System.nanoTime();
InputStream image = new FileInputStream(source);
/*String fileID = request.getParameter("id");
System.out.println("Requested File ID : "+fileID);
// Mongo DB GridFS - https://stackoverflow.com/a/33544285/5081877
image = outputImageFile.getInputStream();*/
if( image != null ) {
BufferedInputStream bin = null;
BufferedOutputStream bout = null;
ServletOutputStream sos = response.getOutputStream();
try {
bin = new BufferedInputStream( image );
bout = new BufferedOutputStream( sos );
int ch =0; ;
while((ch=bin.read())!=-1) {
bout.write(ch);
}
} finally {
bin.close();
image.close();
bout.close();
sos.close();
}
} else {
PrintWriter writer = response.getWriter();
writer.append("Something went wrong with your request.");
System.out.println("Image not available.");
}
System.out.println("Time taken by Stream Copy = "+(System.nanoTime()-start));
}
}
Resulta la URL directamente al src
attibute.
<img src='http://172.0.0.1:8080/ServletApp/files/URLStream?id=5a575be200c117cc2500003b' alt="mongodb File"/>
<img src='http://172.0.0.1:8080/ServletApp/files/URLStream' alt="local file"/>
<video controls="controls" src="http://172.0.0.1:8080/ServletApp/files/URLStream"></video>
Si desea trabajar con JAX-RS (por ejemplo, RESTEasy) intente esto:
@Path("/pic")
public Response get(@QueryParam("url") final String url) {
String picUrl = URLDecoder.decode(url, "UTF-8");
return Response.ok(sendPicAsStream(picUrl))
.header(HttpHeaders.CONTENT_TYPE, "image/jpg")
.build();
}
private StreamingOutput sendPicAsStream(String picUrl) {
return output -> {
try (InputStream is = (new URL(picUrl)).openStream()) {
ByteStreams.copy(is, output);
}
};
}
utilizando javax.ws.rs.core.Response
y com.google.common.io.ByteStreams
Lo hice aún más simple. Problema: un archivo CSS tenía enlaces URL a la carpeta img. Obtiene 404.
Miré la url, http: // tomcatfolder: port / img / blablah.png , que no existe Pero, eso realmente apunta a la aplicación ROOT en Tomcat.
Así que acabo de copiar la carpeta img de mi aplicación web en esa aplicación ROOT. ¡Trabajos!
No recomendado para producción, por supuesto, pero esto es para una aplicación interna de desarrollo de herramientas.