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

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

Domanda

Ho un'applicazione Web Java in esecuzione su Tomcat.Desidero caricare immagini statiche che verranno visualizzate sia sull'interfaccia utente Web che nei file PDF generati dall'applicazione.Verranno aggiunte e salvate anche nuove immagini caricandole tramite l'interfaccia utente Web.

Non è un problema farlo avendo i dati statici archiviati nel contenitore web, ma memorizzarli e caricarli dall'esterno del contenitore web mi dà mal di testa.

A questo punto preferirei non utilizzare un server Web separato come Apache per fornire i dati statici.Inoltre non mi piace l'idea di archiviare le immagini in formato binario in un database.

Ho visto alcuni suggerimenti come far sì che la directory delle immagini sia un collegamento simbolico che punta a una directory esterna al contenitore Web, ma questo approccio funzionerà sia su ambienti Windows che *nix?

Alcuni suggeriscono di scrivere un filtro o un servlet per gestire la pubblicazione delle immagini, ma tali suggerimenti sono molto vaghi e di alto livello senza indicazioni a informazioni più dettagliate su come raggiungere questo obiettivo.

È stato utile?

Soluzione

Ho visto alcuni suggerimenti come far sì che la directory delle immagini sia un collegamento simbolico che punta a una directory esterna al contenitore Web, ma questo approccio funzionerà sia su ambienti Windows che *nix?

Se rispetti le regole del percorso del filesystem *nix (ad es.usi esclusivamente le barre come in /path/to/files), funzionerà anche su Windows senza la necessità di perdere tempo con il brutto File.separator concatenazioni di stringhe.Verrebbe tuttavia scansionato solo sullo stesso disco di lavoro da cui è stato richiamato questo comando.Quindi, se Tomcat è ad esempio installato su C: poi il /path/to/files indicherebbe effettivamente C:\path\to\files.

Se i file si trovano tutti all'esterno della webapp e desideri avere Tomcat's DefaultServlet per gestirli, tutto ciò che devi fare in pratica in Tomcat è aggiungere il seguente elemento Context a /conf/server.xml dentro <Host> etichetta:

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

In questo modo saranno accessibili tramite http://example.com/files/....È possibile trovare un esempio di configurazione GlassFish/Payara Qui ed è possibile trovare un esempio di configurazione di WildFly Qui.

Se vuoi avere tu stesso il controllo sulla lettura/scrittura dei file, devi creare un file Servlet per questo che fondamentalmente ottiene solo un InputStream del file nel sapore di ad esempio FileInputStream e lo scrive al OutputStream del HttpServletResponse.

Nella risposta, dovresti impostare il file Content-Type intestazione in modo che il client sappia quale applicazione associare al file fornito.E dovresti impostare il file Content-Length intestazione in modo che il client possa calcolare l'avanzamento del download, altrimenti sarà sconosciuto.E dovresti impostare il file Content-Disposition intestazione a attachment se vuoi un Salva come dialog, altrimenti il ​​client tenterà di visualizzarlo 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 file url-pattern di per esempio /files/*, allora puoi chiamarlo http://example.com/files/image.png.In questo modo puoi avere un maggiore controllo sulle richieste rispetto a DefaultServlet fa, ad esempio fornendo un'immagine predefinita (ad es. if (!file.exists()) file = new File("/path/to/files", "404.gif") o giù di lì).Anche utilizzando il 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 sostituirlo new FileInputStream() di ResultSet#getInputStream().

Spero che questo ti aiuti.

Guarda anche:

Altri suggerimenti

Puoi farlo inserendo 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 da Settings.class), e caricali così, in un HttpServlet 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, dovresti fornire un po 'di cache.

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), ovviamente considerando le prestazioni.

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

Passaggio 1:
 Crea una cartella sotto webapps del server tomcat. Supponiamo che il nome della cartella sia myproj

Passaggio 2:
Sotto myproj crea una cartella WEB-INF e crea un semplice web.xml

codice in web.xml

<web-app>
</web-app>

Struttura delle directory per i due passaggi precedenti

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

Passaggio 3:
Ora crea un file xml con il 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" /> 

Passaggio 4:
 4 A) Ora crea una cartella con nome myproj nell'unità E del tuo hard disk e creane una nuova

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

Supponiamo che myfoto.jpg sia posizionato in e:\myproj\images\myfoto.jpg

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

Codice in web.xml

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

Passaggio 5:
Ora crea un documento .html con il nome index.html e posizionalo sotto e: \ myproj

CODICE in index.html                                                       Benvenuti in Myproj                               

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

http://localhost:8080/myproj    

Passaggio 6:
Ora avvia il server apache tomcat

Passaggio 7:
apri il browser e digita l'URL come segue

http://localhost:8080/myproj/images/myfoto.jpg

quindi visualizzi il contenuto fornito in index.html

Passaggio 8:
per accedere alle immagini dal disco rigido locale (al di fuori di webroot)

<*>

Aggiungi a server.xml:

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

Abilita il parametro di elenco dei file dir in web.xml:

    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>

Questa è la storia dal mio posto di lavoro:
- Cerchiamo di caricare immagini multiple e file di documenti utilizzando Struts 1 e Tomcat 7.x.
- Proviamo a scrivere i file caricati nel file system, nel nome file e nel percorso completo dei record del database.
- Cerchiamo di separare le cartelle di file all'esterno della directory delle app web . (*)

La soluzione di seguito è piuttosto semplice, efficace per il requisito (*):

Nel file META-INF/context.xml con il seguente contenuto: (Esempio, la mia applicazione viene eseguita 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 successive)

Risultato: siamo 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">

(Uso Netbeans 7.x, Netbeans sembra creare automaticamente il file WEB-INF\context.xml)

Se decidi di inviare a FileServlet, dovrai anche allowLinking="true" in context.xml per consentire a <=> di attraversare i collegamenti simbolici.

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

se qualcuno non è in grado di risolvere il suo problema con una risposta accettata, prendere nota delle seguenti considerazioni:

  1. non è necessario menzionare localhost:<port> con l'attributo <img> src.
  2. assicurati di eseguire questo progetto al di fuori di eclipse, poiché eclipse crea context docBase la voce da sola all'interno del suo file server.xml locale.

Leggi InputStream di un file e scrivilo su < code> ServletOutputStream per l'invio di dati binari al client.

@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 dell'URL direttamente su 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>

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

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

Ho guardato 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 ROOT. Lavori!

Non consigliato per la produzione, ovviamente, ma è per un'app di sviluppo strumenti interna.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top