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

Lesezeit: 10 Minuten

Benutzeravatar von Janne
Janne

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 von der Anwendung generierten PDF-Dateien angezeigt werden. Auch neue Bilder werden hinzugefügt und gespeichert, indem sie über die Web-Benutzeroberfläche hochgeladen werden.

Es ist kein Problem, die statischen Daten im Webcontainer zu speichern, aber das Speichern und Laden von außerhalb des Webcontainers bereitet mir Kopfschmerzen.

Ich würde es vorziehen, an dieser Stelle keinen separaten Webserver wie Apache für die Bereitstellung der statischen Daten zu verwenden. Ich mag auch nicht die Idee, die Bilder binär in einer Datenbank zu speichern.

Ich habe einige Vorschläge gesehen, wie das Bildverzeichnis ein symbolischer Link ist, der auf ein Verzeichnis außerhalb des Webcontainers 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 Bildbereitstellung zu handhaben, aber diese Vorschläge waren sehr vage und auf hohem Niveau, ohne Hinweise auf detailliertere Informationen, wie dies zu erreichen ist.

Benutzeravatar von BalusC
BalusC

Ich habe einige Vorschläge gesehen, wie das Bildverzeichnis ein symbolischer Link ist, der auf ein Verzeichnis außerhalb des Webcontainers verweist, aber funktioniert dieser Ansatz sowohl in Windows- als auch in *nix-Umgebungen?

Wenn Sie sich an die Pfadregeln des *nix-Dateisystems halten (d. h. Sie verwenden ausschließlich Schrägstriche wie in /path/to/files), dann funktioniert es auch unter Windows, ohne dass man mit ugly herumspielen muss File.separator Zeichenfolgenverkettungen. Es würde jedoch nur auf derselben Arbeitsplatte gescannt, von der aus dieser Befehl aufgerufen wurde. Also wenn zB Tomcat auf installiert ist C: dann ist die /path/to/files würde eigentlich darauf hinweisen C:\path\to\files.

Wenn sich die Dateien alle außerhalb der Webapp befinden und Sie Tomcats haben möchten DefaultServlet Um sie zu handhaben, müssen Sie in Tomcat im Grunde nur das folgende Context-Element hinzufügen /conf/server.xml innen <Host> Schild:

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

Auf diese Weise werden sie durch zugänglich sein http://example.com/files/.... Für Tomcat-basierte Server wie JBoss EAP 6.x oder älter ist der Ansatz im Grunde gleich, siehe auch Hier. Ein GlassFish/Payara-Konfigurationsbeispiel finden Sie hier und ein WildFly-Konfigurationsbeispiel finden Sie hier.

Wenn Sie selbst die Kontrolle über das Lesen/Schreiben von Dateien haben möchten, müssen Sie eine Servlet dafür bekommt das im Grunde nur eine InputStream der Datei in Geschmack von zum Beispiel FileInputStream und schreibt es an die OutputStream des HttpServletResponse.

Auf die Antwort sollten Sie die setzen Content-Type -Header, damit der Client weiß, welche Anwendung er der bereitgestellten Datei zuordnen soll. Und Sie sollten das einstellen Content-Length Header, damit der Client den Download-Fortschritt berechnen kann, andernfalls ist er unbekannt. Und Sie sollten das einstellen Content-Disposition Kopfzeile zu attachment wenn du willst Speichern als andernfalls versucht der Client, es inline anzuzeigen. Schreiben Sie abschließend einfach den Dateiinhalt in den Antwortausgabestrom.

Hier ist ein einfaches 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());
    }

}

Bei Zuordnung zu einem url-pattern von zum Beispiel /files/*dann kannst du es anrufen http://example.com/files/image.png. Auf diese Weise haben Sie mehr Kontrolle über die Anfragen als die DefaultServlet tut, wie das Bereitstellen eines Standardbildes (dh if (!file.exists()) file = new File("/path/to/files", "404.gif") oder so). Auch mit der request.getPathInfo() wird oben bevorzugt request.getParameter() weil es SEO-freundlicher ist und IE sonst nicht den richtigen Dateinamen auswählt Speichern als.

Sie können dieselbe Logik zum Bereitstellen von Dateien aus der Datenbank wiederverwenden. Einfach austauschen new FileInputStream() von ResultSet#getInputStream().

Siehe auch:

  • Empfohlene Methode zum Speichern hochgeladener Dateien in einer Servlet-Anwendung
  • Abstrakte Vorlage für ein statisches Ressourcen-Servlet (unterstützt HTTP-Cache)
  • Wie kann ich Bilder aus einer Datenbank auf einer JSP-Seite abrufen und anzeigen?
  • So streamen Sie Audio-/Videodateien wie MP3, MP4, AVI usw. mit einem Servlet

  • @SalutonMondo: der Weg mit dem geringsten Aufwand.

    – BalusC

    11. Februar 2015 um 13:30 Uhr

  • @BalusC, ich habe das versucht: <Context docBase="/path/to/images" path="/images" /> in Windows, aber Pfad relativ zum Ordner webapps erhalten: C:\install\apache-tomcat-8.0.26\webapps\tmp] is not valid

    – ACV

    12. September 2015 um 16:50 Uhr


  • Unter Windows sollte es sein: <Context docBase="C:\tmp\" path="/images" />

    – ACV

    12. September 2015 um 16:52 Uhr

  • Es gibt ein paar Probleme mit dieser Antwort, obwohl sie die ursprüngliche Frage sehr prägnant beantwortet. Ich poste dies in der Hoffnung, dass der Antwort eine Klarstellung hinzugefügt wird, damit die Leser verstehen, dass dies nicht “die Lösung” ist. Erstens fügt dieses Servlet jeder Anwendung, in der es bereitgestellt wird, einen riesigen Path-Traversal-Bug hinzu. Das ist das Wichtigste zu erwähnen.

    – Christoph Schultz

    3. August 2020 um 3:18 Uhr

  • @BalusC Ja, ich schätze, dass es möglich ist, aus dieser Antwort eine sicherere und funktionsreichere Lösung zu finden. Ich denke nur, dass es sich lohnt, einen Code-Kommentar in Ihr Beispiel einzufügen, der so etwas wie “TODO: MITIGATE DIRECTORY TRAVERSAL” oder so ähnlich sagt. SO ist leider eine großartige Quelle für Copy/Paste-Lösungen in der heutigen Software.

    – Christoph Schultz

    3. August 2020 um 14:41 Uhr

Benutzeravatar von Bozho
Bozo

Sie können dies tun, indem Sie Ihre Bilder in einem festen Pfad ablegen (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 a 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 manipulieren 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="https://stackoverflow.com/questions/1812244/imageServlet?imageName=myimage.png" />

Natürlich sollten Sie daran denken, unterschiedliche Inhaltstypen auszuliefern – „Bild/jpeg“, zum Beispiel basierend auf der Dateiendung. Außerdem sollten Sie etwas Caching bereitstellen.

Darüber hinaus können Sie dieses Servlet zur qualitativen Neuskalierung Ihrer Bilder verwenden, indem Sie Breiten- und Höhenparameter als Argumente angeben und verwenden image.getScaledInstance(w, h, Image.SCALE_SMOOTH), natürlich unter Berücksichtigung der Leistung.

  • Sie brauchen die Java 2D API dafür wirklich nicht, es würde nur unnötig mehr Overhead hinzufügen. Lesen Sie einfach einen InputStream und schreiben Sie in OutputStream.

    – BalusC

    28. November 2009 um 11:44 Uhr

  • Ja, ich begann die Antwort mit der Idee der Neuskalierung und anderer Manipulationen, aber am Ende vereinfachte ich sie.

    – Bozo

    28. November 2009 um 11:59 Uhr

Benutzeravatar von sbabamca
sbabamca

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 webapps des Tomcat-Servers. Sagen wir, der Ordnername ist myproj

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

Code unter web.xml

<web-app>
</web-app>

Verzeichnisstruktur für die beiden oben genannten 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 dem folgenden 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 E-Laufwerk Ihrer Festplatte und erstellen Sie einen neuen

Ordner mit dem Namen Bilder und legen Sie einige Bilder im Bilderordner ab (e:myproj\images\)

Nehmen wir an, myfoto.jpg wird darunter platziert 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 Ordner WEB-INF

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:
So greifen Sie auf die Bilder unter Ihrer lokalen Festplatte (außerhalb von Webroot) zu

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

  • können Sie mir bitte vorschlagen, wie man dasselbe für dynamische Werte macht. Ich meine, ich möchte die Daten (XML) in mein lokales Verzeichnis schreiben oder und und das auf meiner JSP-Seite lesen. Gibt es eine Möglichkeit, in das vom Server verwaltete Verzeichnis zu schreiben, damit ich mit dem obigen Verfahren darauf zugreifen kann?

    – Sudip7

    21. November 2014 um 13:03 Uhr

  • Obwohl ich die Datei index.html ordnungsgemäß ausführen kann, werden im Webbrowser keine Bilder angezeigt

    – Rogerkrieg

    29. Mai 2015 um 3:00 Uhr

  • Mein Fehlerbeitrag funktioniert gut. Ich habe nur vergessen, / am Ende von E:/myproj zu setzen. Ich ändere dies in E:/myproj/ und es funktioniert gut. Danke @sbabamca

    – Rogerkrieg

    29. Mai 2015 um 3:08 Uhr


  • Hallo, danke für den Beitrag und er ist sehr nützlich. Hier möchte ich Dateien über die Schnittstelle in dieses bestimmte Verzeichnis hochladen. Ich möchte die POST-Methode dafür aktivieren. Kann mir bitte jemand dabei helfen.

    – Vicky

    13. Juni 2015 um 10:58 Uhr


Zu server.xml hinzufügen:

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

Aktivieren Sie den Listenparameter für die dir-Datei in web.xml :

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

Benutzeravatar von Raphaël Colantonio
Raphael Colantonio

Dies ist die Geschichte von meinem Arbeitsplatz:
– Wir versuchen, Bilder und Dokumentdateien mehrfach hochzuladen, indem wir Struts 1 und Tomcat 7.x verwenden.
– Wir versuchen, hochgeladene Dateien in das Dateisystem, den Dateinamen und den vollständigen Pfad zu den Datenbankeinträgen zu schreiben.
– Wir versuchen es getrennte Dateiordner außen Web-App-Verzeichnis.

Die folgende Lösung ist ziemlich einfach und effektiv für die Anforderungen META-INF/context.xml : http://localhost:8080/ABCIm Ordner ABCDatei mit folgendem Inhalt: (Beispiel, meine Anwendung läuft unter context.xmlmeine Anwendung / mein Projekt mit dem Namen

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

). (Dies ist auch der vollständige Inhalt der Datei

) (funktioniert mit Tomcat Version 7 oder höher) D:\images\foo.jpg
Ergebnis:

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

Wir haben 2 Alias ​​erstellt. Beispielsweise speichern wir Bilder unter:

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

und über den Link oder mit dem Bild-Tag anzeigen: WEB-INF\context.xmloder

(Ich verwende Netbeans 7.x, Netbeans scheint eine Datei automatisch zu erstellen
)

Benutzeravatar von Shantha Kumara FileServlet Shantha Kumara allowLinking="true" Wenn Sie sich für den Versand entscheiden context.xml dann brauchst du auch FileServlet In

um zu erlauben um die Symlinks zu durchlaufen.

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

Benutzeravatar von electrobabe Elektrobabe Wenn Sie mit arbeiten möchten

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

JAX-RS javax.ws.rs.core.Response (z. B. RESTEasy) versuchen Sie Folgendes: com.google.common.io.ByteStreams

1449980cookie-checkEinfachste Möglichkeit, statische Daten von außerhalb des Anwendungsservers in einer Java-Webanwendung bereitzustellen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy