tomcat - La forma más simple de servir datos estáticos desde fuera del servidor de aplicaciones en una aplicación web Java
java-ee servlets (10)
He visto algunas sugerencias como que el directorio de imágenes sea un enlace simbólico que apunta a un directorio fuera del contenedor web, pero ¿funcionará este enfoque tanto en entornos Windows como * nix?
Si sigue las reglas de ruta del sistema de archivos * nix (es decir, usa barras diagonales exclusivas como en /path/to/files
), entonces funcionará también en Windows sin la necesidad de File.separator
con File.separator
concatenaciones de cadenas File.separator
. Sin embargo, solo se escaneará en el mismo disco de trabajo desde donde se invocó este comando. Entonces, si Tomcat, por ejemplo, está instalado en C:
entonces, los /path/to/files
realmente apuntan a C:/path/to/files
.
Si todos los archivos están ubicados fuera de la aplicación web, y desea que Tomcat''s DefaultServlet
maneje, entonces todo lo que necesita hacer en Tomcat es agregar el siguiente elemento Context a /conf/server.xml
dentro de la etiqueta <Host>
:
<Context docBase="/path/to/files" path="/files" />
De esta forma, estarán accesibles a través de http://example.com/files/...
El ejemplo de configuración GlassFish / Payara se puede encontrar here y el ejemplo de configuración de WildFly se puede encontrar here .
Si desea tener control sobre la lectura / escritura de archivos usted mismo, entonces necesita crear un Servlet
para esto que básicamente obtiene un InputStream
del archivo en el sabor de, por ejemplo, FileInputStream
y lo escribe en OutputStream
de HttpServletResponse
.
En la respuesta, debe establecer el encabezado Content-Type
para que el cliente sepa qué aplicación asociar con el archivo proporcionado. Y debe configurar el encabezado Content-Length
para que el cliente pueda calcular el progreso de la descarga, de lo contrario será desconocido. Y, debe establecer el encabezado Content-Disposition
en los attachment
si desea un cuadro de diálogo Guardar como ; de lo contrario, el cliente intentará mostrarlo en línea. Finalmente, solo escriba el contenido del archivo en la secuencia de salida de respuesta.
Aquí hay un ejemplo básico de dicho 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 a un url-pattern
de url-pattern
de, por ejemplo, /files/*
, puede llamarlo por http://example.com/files/image.png
. De esta forma puede tener más control sobre las solicitudes que las que ofrece DefaultServlet
, como proporcionar una imagen predeterminada (es decir, if (!file.exists()) file = new File("/path/to/files", "404.gif")
o menos). También se utiliza el request.getPathInfo()
sobre request.getParameter()
porque es más amigable con los request.getPathInfo()
request.getParameter()
SEO) y, de lo contrario, IE no elegirá el nombre de archivo correcto durante la operación Guardar como .
Puede reutilizar la misma lógica para servir archivos desde la base de datos. Simplemente reemplace el new FileInputStream()
por ResultSet#getInputStream()
.
Espero que esto ayude.
Ver también:
- Forma recomendada para guardar archivos cargados en una aplicación servlet
- Plantilla abstracta para un servlet de recursos estáticos (soporta caché HTTP)
- ¿Cómo recuperar y visualizar imágenes desde una base de datos en una página JSP?
- Cómo transmitir archivos de audio / video como MP3, MP4, AVI, etc. usando un Servlet
Tengo una aplicación web Java ejecutándose en Tomcat. Quiero cargar imágenes estáticas que se mostrarán en la interfaz de usuario web y en los archivos PDF generados por la aplicación. Además, se agregarán y guardarán nuevas imágenes al cargarlas a través de la interfaz de usuario web.
No es un problema hacer esto al tener los datos estáticos almacenados dentro del contenedor web, pero almacenarlos y cargarlos desde fuera del contenedor web me está dando dolores de cabeza.
Preferiría no utilizar un servidor web independiente como Apache para servir los datos estáticos en este momento. Tampoco me gusta la idea de almacenar las imágenes en binario en una base de datos.
He visto algunas sugerencias como que el directorio de imágenes sea un enlace simbólico que apunta a un directorio fuera del contenedor web, pero ¿funcionará este enfoque tanto en entornos Windows como * nix?
Algunos sugieren escribir un filtro o un servlet para manejar la publicación de imágenes, pero esas sugerencias han sido muy vagas y de alto nivel sin indicadores para obtener información más detallada sobre cómo lograr esto.
Agregar 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 imágenes múltiples 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 la aplicación web . (*)
La siguiente solución es bastante simple, efectiva para los requisitos (*):
En el archivo META-INF/context.xml
, con el siguiente contenido: (Por 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 sido creados 2 alias. Por ejemplo, guardamos imágenes en: D:/images/foo.jpg
y D:/images/foo.jpg
desde un enlace o usando una 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">
(Uso Netbeans 7.x, Netbeans parece auto crear el archivo WEB-INF/context.xml
)
Lea el InputStream de un archivo y escríbalo en ServletOutputStream
para enviar datos binarios al cliente.
- Archivo local Puede leer un archivo directamente usando FileInputStream (''path / image.png'') .
- En el archivo de 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://.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));
}
}
Resultado 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>
Lo hice aún más simple. Problema: un archivo CSS tenía enlaces de URL a la carpeta img. Obtiene 404.
Miré url, http://tomcatfolder:port/img/blablah.png , que no existe. Pero, eso realmente apunta a la aplicación ROOT en Tomcat.
Así que simplemente copié 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 de desarrollo de herramienta interna.
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 Settings.class) y cárguela 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 quieres 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, basado en la extensión del archivo. También debe proporcionar algo de almacenamiento en caché.
Además, podría usar este servlet para mejorar el cambio de calidad de sus imágenes, proporcionando parámetros de ancho y alto como argumentos y utilizando image.getScaledInstance(w, h, Image.SCALE_SMOOTH
), considerando el rendimiento, por supuesto.
Si decide enviarlo a FileServlet
, también necesitará allowLinking="true"
en context.xml
para permitir que FileServlet
recorra los enlaces simbólicos.
Ver http://tomcat.apache.org/tomcat-6.0-doc/config/context.html
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
si alguien no puede resolver su problema con la respuesta aceptada, tenga en cuenta estas consideraciones a continuación:
- no es necesario mencionar
localhost:<port>
con el atributo<img> src
. - asegúrese de ejecutar este proyecto fuera de eclipse, ya que eclipse crea la entrada de
context docBase
por sí mismo dentro de su archivoserver.xml
local.
Requisito: Acceder a los recursos estáticos (imágenes / videos, etc.) desde fuera del directorio de WEBROOT o desde el disco local
Paso 1 :
Cree una carpeta debajo de webapps del servidor de tomcat, digamos que el nombre de la carpeta es myproj
Paso 2 :
En myproj, cree una carpeta WEB-INF en este crear un simple web.xml
código bajo web.xml
<web-app>
</web-app>
Estructura del directorio para los dos pasos anteriores
c:/programfile/apachesoftwarefoundation/tomcat/.../webapps
|
|---myproj
| |
| |---WEB-INF
| |
|---web.xml
Paso 3:
Ahora crea un archivo xml con el nombre myproj.xml en la siguiente ubicación
c:/programfile/apachesoftwarefoundation/tomcat/conf/catalina/localhost
CÓDIGO en myproj.xml:
<Context path="/myproj/images" docBase="e:/myproj/" crossContext="false" debug="0" reloadable="true" privileged="true" />
Etapa 4:
4 A) Ahora cree una carpeta con el nombre myproj en la unidad E de su disco duro y cree una nueva
carpeta con imágenes de nombre y colocar algunas imágenes en la carpeta de imágenes (e:myproj/images/)
Supongamos que myfoto.jpg se coloca debajo de e:/myproj/images/myfoto.jpg
4 B) Ahora crea una carpeta con el nombre WEB-INF en e:/myproj/WEB-INF
y crea un web.xml en la carpeta WEB-INF
Código en web.xml
<web-app>
</web-app>
Paso 5:
Ahora crea un documento .html con el nombre index.html y colócalo en e: / myproj
CÓDIGO en index.html Bienvenido a Myproj
La estructura del directorio para los pasos 4 y 5 anteriores es la siguiente
E:/myproj
|--index.html
|
|--images
| |----myfoto.jpg
|
|--WEB-INF
| |--web.xml
Paso 6:
Ahora inicia el servidor de apache tomcat
Paso 7:
abra el navegador y escriba la URL de la siguiente manera
http://localhost:8080/myproj
a continuación, muestra 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