Il modo più semplice per servire dati statici dall'esterno del server delle applicazioni in un'applicazione Web Java


Ho un'applicazione Web Java in esecuzione su Tomcat. Voglio caricare immagini statiche che verranno mostrate sia sull'interfaccia utente Web che nei file PDF generati dall'applicazione. Anche nuove immagini verranno aggiunte e salvate caricando tramite l'interfaccia utente Web.

Non è un problema farlo avendo i dati statici memorizzati all'interno del contenitore web, ma memorizzarli e caricarli dall'esterno del contenitore web mi sta dando mal di testa.

Preferirei non utilizzare un server Web separato come Apache per servire i dati statici a questo punto. Inoltre non mi piace l'idea di memorizzare le immagini in binario in un database.

Ho visto alcuni suggerimenti come avere la directory immagine come un collegamento simbolico che punta a una directory al di fuori del contenitore Web, ma questo approccio funzionerà sia su ambienti Windows che *nix?

Alcuni suggeriscono di scrivere un filtro o un servlet per gestire il servizio di immagini, ma questi suggerimenti sono stati molto vaghi e di alto livello senza puntatori a più informazioni dettagliate su come realizzare questo.

Author: BalusC, 2009-11-28

10 answers

Ho visto alcuni suggerimenti come avere la directory immagine come un collegamento simbolico che punta a una directory al di fuori del contenitore Web, ma questo approccio funzionerà sia su ambienti Windows che *nix?

Se si rispettano le regole del percorso del filesystem *nix (cioè si usano esclusivamente barre in avanti come in /path/to/files), funzionerà anche su Windows senza la necessità di giocherellare con brutte File.separator concatenazioni di stringhe. Sarebbe tuttavia solo essere scansionato sul stesso disco di lavoro da cui è stato richiamato questo comando. Quindi, se Tomcat è ad esempio installato su C:, /path/to/files punterebbe effettivamente a C:\path\to\files.

Se i file si trovano tutti all'esterno della webapp e si desidera avere DefaultServlet di Tomcat per gestirli, tutto ciò che è fondamentalmente necessario fare in Tomcat è aggiungere il seguente elemento di contesto a /conf/server.xml all'interno del tag <Host>:

<Context docBase="/path/to/files" path="/files" />

In questo modo saranno accessibili attraverso http://example.com/files/.... GlassFish / Payara esempio di configurazione può essere trovato qui e l'esempio di configurazione WildFly può essere trovato qui.

Se si desidera avere il controllo sulla lettura/scrittura di file da soli, è necessario creare un Servlet per questo che in pratica ottiene solo un InputStream del file in flavor di ad esempio FileInputStream e lo scrive su OutputStream di HttpServletResponse.

Nella risposta, è necessario impostare l'intestazione Content-Type in modo che il client sappia quale applicazione associare al file fornito. E, si dovrebbe impostare il Content-Length intestazione in modo che il client possa calcolare l'avanzamento del download, altrimenti sarà sconosciuto. E, dovresti impostare l'intestazione Content-Disposition su attachmentse vuoi una finestra di dialogo Salva come, altrimenti il client tenterà di visualizzarla in linea. Infine basta scrivere il contenuto del file nel flusso di output della risposta.

Ecco un esempio di base di tale 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());
    }

}

Quando mappato su un url-pattern di ad esempio /files/*, puoi chiamarlo da http://example.com/files/image.png. In questo modo si può avere più controllo oltre le richieste rispetto a DefaultServlet, ad esempio fornendo un'immagine predefinita (cioè if (!file.exists()) file = new File("/path/to/files", "404.gif") o giù di lì). Anche l'utilizzo di request.getPathInfo() è preferito sopra request.getParameter()perché è più SEO friendly e altrimenti IE non sceglierà il nome file corretto durante Salva come.

È possibile riutilizzare la stessa logica per servire i file dal database. Basta sostituire new FileInputStream() con ResultSet#getInputStream().

Spero che questo aiuti.

Vedi anche:

 147
Author: BalusC, 2017-05-23 12:34:34

Puoi farlo mettendo le tue immagini su un percorso fisso (ad esempio: / var / images, o c:\images), aggiungi un'impostazione nelle impostazioni dell'applicazione (rappresentata nel mio esempio dalle Impostazioni.classe), e caricarli in questo modo, in un HttpServlet del tuo:

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 se vuoi manipolare l'immagine:

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());

Quindi il codice html sarebbe <img src="imageServlet?imageName=myimage.png" />

Ovviamente dovresti pensare di servire diversi tipi di contenuto - "image/jpeg", ad esempio in base all'estensione del file. Inoltre si dovrebbe fornire alcuni caching.

Inoltre è possibile utilizzare questo servlet per il ridimensionamento di qualità delle immagini, fornendo parametri di larghezza e altezza come argomenti e utilizzando image.getScaledInstance(w, h, Image.SCALE_SMOOTH), considerando le prestazioni, ovviamente.

 9
Author: Bozho, 2009-11-28 11:58:22

Requisito: Accesso alle risorse statiche (immagini / video., ecc.,) dall'esterno della directory WEBROOT o dal disco locale

Fase 1:
Creare una cartella sotto webapps di tomcat server., diciamo che il nome della cartella è myproj

Passo 2:
Sotto myproj creare una cartella WEB-INF sotto questo creare un semplice web.xml

Codice sotto web.xml

<web-app>
</web-app>

Struttura di directory per i due passaggi precedenti

c:\programfile\apachesoftwarefoundation\tomcat\...\webapps
                                                            |
                                                            |---myproj
                                                            |   |
                                                            |   |---WEB-INF
                                                                |   |
                                                                    |---web.xml

Fase 3:
Ora crea un file xml con nome myproj.xml nella seguente posizione

c:\programfile\apachesoftwarefoundation\tomcat\conf\catalina\localhost

CODICE in myproj.xml:

<Context path="/myproj/images" docBase="e:/myproj/" crossContext="false" debug="0" reloadable="true" privileged="true" /> 

Fase 4:
4 A) Ora creare una cartella con il nome myproj in E unità del disco rigido e creare un nuovo

Cartella con nome immagini e inserire alcune immagini nella cartella immagini (e:myproj\images\)

Supponiamo myfoto.jpg è posto sotto e:\myproj\images\myfoto.jpg

4 B) Ora creare una cartella con nome WEB-INF in e:\myproj\WEB-INF e creare un web.xml nella cartella WEB-INF

Codice

Nel web.xml

<web-app>
</web-app>

Passo 5:
Ora creare un .documento html con indice nome.html e posto sotto e:\myproj

CODICE nell'indice.HTML Benvenuti a Myproj

La struttura di directory per i passaggi 4 e 5 precedenti è la seguente

E:\myproj
    |--index.html
    |
    |--images
    |     |----myfoto.jpg
    |
    |--WEB-INF
    |     |--web.xml

Passo 6:
Ora avvia il server apache tomcat

Passaggio 7:
aprire il browser e digitare l'URL come segue

http://localhost:8080/myproj    

Quindi u visualizza il contenuto fornito nell'indice.html

Passaggio 8:
Per accedere alle immagini sotto il disco rigido locale (al di fuori di webroot)

http://localhost:8080/myproj/images/myfoto.jpg
 6
Author: sbabamca, 2013-03-16 05:27:01

Aggiungi al server.xml :

 <Context docBase="c:/dirtoshare" path="/dir" />

Abilita il parametro elenco file dir nel web.xml :

    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>
 5
Author: blue-sky, 2015-05-12 10:27:58

Questa è la storia dal mio posto di lavoro:
- Cerchiamo di caricare immagini moltiplicare e file di documenti utilizzare Struts 1 e Tomcat 7.x.
- Cerchiamo di scrivere i file caricati sul file system, il nome del file e il percorso completo dei record del database.
- Cerchiamo di cartelle di file separate al di fuori web app directory . (*)

La soluzione qui sotto è piuttosto semplice, efficace per il requisito ( * ):

Nel file META-INF/context.xml file con il seguente contenuto: (Esempio, la mia applicazione esegui su http://localhost:8080/ABC, la mia applicazione / progetto denominato ABC). (questo è anche il contenuto completo del file context.xml)

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ABC" aliases="/images=D:\images,/docs=D:\docs"/>

(funziona con Tomcat versione 7 o successiva)

Risultato: Sono stati creati 2 alias. Ad esempio, salviamo le immagini in: D:\images\foo.jpg e visualizza dal link o usando il tag immagine:

<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">

(io uso Netbeans 7.x, Netbeans sembrano creare automaticamente il file WEB-INF\context.xml)

 5
Author: Do Nhu Vy, 2015-06-05 22:35:25

Se decidi di inviare a FileServlet allora avrai anche bisogno di allowLinking="true" in context.xml per consentire a FileServlet di attraversare i collegamenti simbolici.

Vedere http://tomcat.apache.org/tomcat-6.0-doc/config/context.html

 2
Author: cherouvim, 2012-07-18 10:46:20

Se qualcuno non è in grado di risolvere il suo problema con una risposta accettata, nota queste considerazioni di seguito:

  1. non c'è bisogno di menzionare localhost:<port> con l'attributo <img> src.
  2. assicurati di eseguire questo progetto al di fuori di eclipse, perché eclipse crea context docBase entry da solo all'interno del suo file server.xml locale.
 0
Author: JPG, 2017-10-26 08:37:03

Leggere l'InputStream di un file e scriverlo in ServletOutputStream per l'invio di dati binari al client.

  • File locale È possibile leggere un file direttamente utilizzando FileInputStream('percorso/immagine.png').
  • Il file di database Mongo è possibile ottieni 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));
    }
}

Risultato l'URL direttamente 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>
 0
Author: Yash, 2018-01-12 11:13:45

Se vuoi lavorare con JAX-RS (ad esempio RESTEasy) prova questo:

@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);
        }
    };
}

Utilizzando javax.ws.rs.core.Response e com.google.common.io.ByteStreams

 0
Author: electrobabe, 2018-04-03 01:04:21

L'ho fatto ancora più semplice. Problema: un file CSS aveva collegamenti URL alla cartella img. Ottiene 404.

Ho guardato l'url, http://tomcatfolder:port/img/blablah.png, che non esiste. Ma questo sta davvero puntando all'app ROOT in Tomcat.

Quindi ho appena copiato la cartella img dalla mia webapp in quell'app PRINCIPALE. Funziona!

Non raccomandato per la produzione, ovviamente, ma questo è per un'app di sviluppo di strumenti interni.

 -1
Author: Josef.B, 2016-08-31 14:57:02