wake-up-neo.com

Einfachste Möglichkeit, statische Daten außerhalb des Anwendungsservers in einer Java-Webanwendung bereitzustellen

Ich habe eine Java-Webanwendung, die auf Tomcat ausgeführt wird. Ich möchte statische Bilder laden, die sowohl auf der Web-Benutzeroberfläche als auch in PDF -Dateien angezeigt werden, die von der Anwendung generiert werden. Auch neue Bilder werden hinzugefügt und gespeichert, indem sie über die Web-Benutzeroberfläche hochgeladen werden.

Es ist kein Problem, dies zu tun, indem die statischen Daten im Webcontainer gespeichert werden, das Speichern und Laden von Daten außerhalb des Webcontainers bereitet mir jedoch Kopfschmerzen.

Ich möchte lieber keinen separaten Webserver wie Apache verwenden, um die statischen Daten an dieser Stelle bereitzustellen. Mir gefällt auch nicht die Idee, die Bilder binär in einer Datenbank zu speichern. 

Ich habe einige Vorschläge gesehen, wie beispielsweise, dass das Image-Verzeichnis ein symbolischer Link ist, der auf ein Verzeichnis außerhalb des Web-Containers verweist. Aber funktioniert dieser Ansatz sowohl in Windows- als auch in * Nix-Umgebungen? 

Einige schlagen vor, einen Filter oder ein Servlet zu schreiben, um die Bildausgabe zu handhaben, aber diese Vorschläge waren sehr vage und auf hohem Niveau ohne Hinweis auf detailliertere Informationen, wie dies erreicht werden kann. 

124
Janne

Ich habe einige Vorschläge gesehen, wie beispielsweise, dass das Image-Verzeichnis ein symbolischer Link ist, der auf ein Verzeichnis außerhalb des Web-Containers verweist. Aber funktioniert dieser Ansatz sowohl in Windows- als auch in * Nix-Umgebungen?

Wenn Sie die * nix-Dateisystempfadregeln einhalten (d. H. Sie verwenden ausschließlich Schrägstriche wie in /path/to/files), funktioniert sie auch unter Windows, ohne dass Sie mit hässlichen File.separator-String-Verkettungen herumspielen müssen. Es würde jedoch nur auf derselben Arbeitsplatte gescannt, von der aus dieser Befehl aufgerufen wurde. Wenn Tomcat beispielsweise auf C: installiert ist, würde der /path/to/files tatsächlich auf C:\path\to\files zeigen.

Wenn sich die Dateien alle außerhalb der webapp befinden und Sie möchten, dass Tomcat mit DefaultServlet behandelt wird, müssen Sie in Tomcat im Grunde nur das folgende Context-Element zu /conf/server.xml im <Host>-Tag hinzufügen:

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

Auf diese Weise sind sie über http://example.com/files/... erreichbar. Das Konfigurationsbeispiel für GlassFish/Payara ist hier und das Konfigurationsbeispiel für WildFly hier .

Wenn Sie das Lesen/Schreiben von Dateien selbst steuern möchten, müssen Sie hierfür eine Servlet erstellen, die im Grunde nur eine InputStream der Datei im Namen von FileInputStream erhält und in die OutputStream der HttpServletResponse schreibt.

In der Antwort sollten Sie den Content-Type-Header so einstellen, dass der Client weiß, welche Anwendung der bereitgestellten Datei zugeordnet werden soll. Sie sollten den Content-Length-Header so einstellen, dass der Client den Download-Fortschritt berechnen kann, andernfalls ist er unbekannt. Und Sie sollten den Content-Disposition-Header auf attachment setzen, wenn Sie ein Save As -Dialogfeld möchten, andernfalls versucht der Client, ihn inline anzuzeigen. Zum Schluss schreiben Sie einfach den Dateiinhalt in den Antwortausgabestrom.

Hier ist ein grundlegendes Beispiel für ein solches 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());
    }

}

Wenn ein url-pattern von beispielsweise /files/* zugeordnet ist, können Sie ihn mit http://example.com/files/image.png aufrufen. Auf diese Weise haben Sie mehr Kontrolle über die Anforderungen als DefaultServlet, z. B. indem Sie ein Standardbild (d. H. if (!file.exists()) file = new File("/path/to/files", "404.gif")) bereitstellen. Die Verwendung von request.getPathInfo() wird auch vor request.getParameter() bevorzugt, da es eher SEO-freundlicher ist. Andernfalls wählt IE nicht den korrekten Dateinamen während Save As aus.

Sie können dieselbe Logik für das Bereitstellen von Dateien aus der Datenbank verwenden. Ersetzen Sie einfach new FileInputStream() durch ResultSet#getInputStream().

Hoffe das hilft.

Siehe auch:

151
BalusC

Sie können dies tun, indem Sie Ihre Bilder in einen festen Pfad setzen (z. B./var/images oder c:\images), eine Einstellung in Ihren Anwendungseinstellungen hinzufügen (in meinem Beispiel durch die Settings.class dargestellt) und sie laden so, in einer HttpServlet von dir:

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

Oder wenn Sie das Bild bearbeiten möchten:

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

dann wäre der HTML-Code <img src="imageServlet?imageName=myimage.png" />

Natürlich sollten Sie verschiedene Inhaltstypen bereitstellen - "image/jpeg", beispielsweise basierend auf der Dateierweiterung. Sie sollten auch etwas Caching bereitstellen.

Außerdem können Sie dieses Servlet für die Qualitätsskalierung Ihrer Bilder verwenden, indem Sie Parameter für Breite und Höhe als Argumente angeben und image.getScaledInstance(w, h, Image.SCALE_SMOOTH) verwenden, wobei natürlich die Leistung berücksichtigt wird.

9
Bozho

Anforderung: Zugriff auf die statischen Ressourcen (Bilder/Videos usw.) von außerhalb des WEBROOT-Verzeichnisses oder von der lokalen Festplatte

Schritt 1 :
Erstellen Sie einen Ordner unter den Webapps des Tomcat-Servers. Angenommen, der Ordnername lautet myproj

Schritt 2 : 
Erstellen Sie unter myproj einen WEB-INF-Ordner, und erstellen Sie eine einfache web.xml

code unter web.xml

<web-app>
</web-app>

Verzeichnisstruktur für die obigen zwei Schritte

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

Schritt 3:
Erstellen Sie nun eine XML-Datei mit dem Namen myproj.xml unter folgendem Speicherort

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

CODE in myproj.xml:

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

Schritt 4:
4 A) Erstellen Sie nun einen Ordner mit dem Namen myproj im Laufwerk E Ihrer Festplatte und erstellen Sie einen neuen 

ordner mit Namensbildern und einige Bilder im Bilderordner (e:myproj\images\)

Nehmen wir an, myfoto.jpg befindet sich unter e:\myproj\images\myfoto.jpg.

4 B) Erstellen Sie nun einen Ordner mit dem Namen WEB-INF in e:\myproj\WEB-INF und erstellen Sie eine web.xml im WEB-INF-Ordner

Code in web.xml

<web-app>
</web-app>

Schritt 5: 
Erstellen Sie nun ein .html-Dokument mit dem Namen index.html und legen Sie es unter e:\myproj ab

CODE unter index.html Willkommen bei Myproj

Die Verzeichnisstruktur für die obigen Schritte 4 und 5 ist wie folgt 

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

Schritt 6: 
Starten Sie nun den Apache Tomcat-Server

Schritt 7: 
Öffnen Sie den Browser und geben Sie die URL wie folgt ein

http://localhost:8080/myproj    

dann zeigen Sie den Inhalt an, der in index.html bereitgestellt wird

Schritt 8: 
Zugriff auf die Bilder unter Ihrer lokalen Festplatte (außerhalb von Webroot)

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

Dies ist eine Geschichte von meinem Arbeitsplatz:
- Wir versuchen, mehrere Bilder und Dokumentdateien mit Struts 1 und Tomcat 7.x hochzuladen.
- Wir versuchen, hochgeladene Dateien in das Dateisystem, den Dateinamen und den vollständigen Pfad zu den Datenbankeinträgen zu schreiben.
- Wir versuchen, separate Dateiordner außerhalb Web-App-Verzeichnis . (*)

Die folgende Lösung ist ziemlich einfach und für die Anforderung (*) effektiv:

In der DateiMETA-INF/context.xmlmit dem folgenden Inhalt: (Beispiel: Meine Anwendung läuft bei http://localhost:8080/ABC, meine Anwendung/mein Projekt mit dem Namen ABC) . (Dies ist auch der gesamte Inhalt der Datei context.xml).

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

(funktioniert mit Tomcat Version 7 oder höher)

Ergebnis: Wir haben 2 Alias ​​erstellt. Zum Beispiel speichern wir Bilder unter: D:\images\foo.jpg 

<img src="http://localhost:8080/ABC/images/foo.jsp" alt="Foo" height="142" width="142">

oder 

<img src="/images/foo.jsp" alt="Foo" height="142" width="142">

(Ich verwende Netbeans 7.x, Netbeans scheint automatisch die Datei WEB-INF\context.xml zu erstellen.)

5
foobarfuu

Zu server.xml hinzufügen: 

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

Aktivieren Sie den Parameter für die Dateiliste in web.xml: 

    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>
5
blue-sky

Wenn Sie sich entscheiden, an FileServlet zu versenden, benötigen Sie auch allowLinking="true" in context.xml, damit FileServlet die symbolischen Links durchlaufen kann.

Siehe http://Tomcat.Apache.org/Tomcat-6.0-doc/config/context.html

2
cherouvim

Wenn Sie mit JAX-RS (z. B. RESTEasy) arbeiten möchten, versuchen Sie Folgendes:

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

mit javax.ws.rs.core.Response und com.google.common.io.ByteStreams

0
electrobabe

Lesen Sie den InputStream einer Datei und schreiben Sie sie in ServletOutputStream , um binäre Daten an den Client zu senden.

  • Lokale Datei Sie können eine Datei direkt mit FileInputStream ('path/image.png') lesen.
  • Mongo DataBase-Datei Sie können InputStream mit GridFS abrufen.
@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));
    }
}

Ermitteln Sie die URL direkt zur src-Datei.

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

wenn jemand mit der akzeptierten Antwort nicht in der Lage ist, sein Problem zu lösen, beachten Sie die folgenden Überlegungen:

  1. localhost:<port> muss nicht mit <img> src-Attribut angegeben werden.
  2. stellen Sie sicher, dass Sie dieses Projekt außerhalb von Eclipse ausführen, da Eclipse den context docBase-Eintrag in seiner lokalen server.xml-Datei selbst erstellt.
0
JPG