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

StackOverflow https://stackoverflow.com/questions/1812244

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.

¿Fue útil?

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:

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:

  1. no es necesario mencionar localhost:<port> con <img> src atributo.
  2. asegúrese de ejecutar este proyecto fuera de eclipse, porque eclipse crea una entrada context docBase por sí sola dentro de su archivo server.xml local.

Lea el InputStream de un archivo y escríbalo en < code> ServletOutputStream para enviar datos binarios al cliente.

@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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top