Najprostszy sposób serwowania statycznych danych spoza serwera aplikacji w aplikacji internetowej Java

Mam uruchomioną aplikację internetową Java na Tomcat. Chcę załadować statyczne obrazy, które będą wyświetlane zarówno w Web UI, jak i w plikach PDF wygenerowanych przez aplikację. Również nowe obrazy będą dodawane i zapisywane poprzez przesyłanie za pośrednictwem interfejsu WWW.

Nie jest problemem, aby to zrobić, mając statyczne dane przechowywane w kontenerze internetowym, ale przechowywanie i ładowanie ich spoza kontenera internetowego przyprawia mnie o ból głowy.

Wolałbym nie używać oddzielnego serwera www jak Apache dla serwowanie danych statycznych w tym momencie. Nie podoba mi się też pomysł przechowywania obrazów w formacie binarnym w bazie danych.

Widziałem kilka sugestii, takich jak, że katalog obrazu jest dowiązaniem symbolicznym wskazującym na katalog poza kontenerem internetowym, ale czy takie podejście będzie działać zarówno w środowisku Windows, jak i *nix?

Niektórzy sugerują napisanie filtra lub servletu do obsługi serwowania obrazu, ale te sugestie były bardzo niejasne i na wysokim poziomie bez wskaźników do więcej szczegółowe informacje o tym, jak to osiągnąć.

Author: BalusC, 2009-11-28

10 answers

widziałem kilka sugestii, takich jak, że katalog obrazu jest dowiązaniem symbolicznym wskazującym na katalog poza kontenerem internetowym, ale czy takie podejście będzie działać zarówno w środowisku Windows, jak i *nix?

Jeśli zastosujesz się do reguł ścieżki systemu plików * nix (tzn. używasz wyłącznie ukośników do przodu, jak w /path/to/files), to będzie to działać również na Windows bez konieczności majstrowania z brzydkimi File.separator string-concatenations. Zostanie jednak zeskanowany tylko na ten sam dysk roboczy, z którego wywołano to polecenie. Jeśli więc Tomcat jest na przykład zainstalowany na C:, to /path/to/files faktycznie wskazuje na C:\path\to\files.

Jeśli wszystkie pliki znajdują się poza webapp i chcesz mieć Tomcat DefaultServlet, aby je obsługiwać, to wszystko, co musisz zrobić w Tomcat, to dodać następujący element kontekstowy do /conf/server.xml wewnątrz <Host> tagu:

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

W ten sposób będą dostępne przez http://example.com/files/.... Przykład konfiguracji GlassFish/Payara można znaleźć tutaj I przykład konfiguracji WildFly można znaleźć tutaj .

Jeśli chcesz mieć kontrolę nad samodzielnym odczytywaniem/zapisywaniem plików, musisz utworzyć Servlet do tego celu, który w zasadzie pobiera InputStream pliku w np. FileInputStream i zapisuje go do OutputStream z HttpServletResponse.

W odpowiedzi należy ustawić nagłówek Content-Type, aby klient wiedział, którą aplikację powiązać z dostarczonym plikiem. I powinieneś ustawić Content-Length nagłówek, aby klient mógł obliczyć postęp pobierania, w przeciwnym razie będzie nieznany. Jeśli chcesz mieć okno dialogowe Zapisz jako , powinieneś ustawić nagłówek Content-Dispositionnaattachment, w przeciwnym razie klient spróbuje wyświetlić go w linii. Na koniec wystarczy zapisać zawartość pliku do strumienia wyjściowego odpowiedzi.

Oto podstawowy przykład takiego servletu:
@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());
    }

}

Gdy mapowany jest na url-pattern na przykład /files/*, można go wywołać przez http://example.com/files/image.png. W ten sposób możesz mieć większą kontrolę nad żądaniami niż robi to DefaultServlet, np. dostarczanie domyślnego obrazu (np. if (!file.exists()) file = new File("/path/to/files", "404.gif") lub tak). Również użycie {[25] } jest preferowane powyżej request.getParameter(), ponieważ jest bardziej przyjazne dla SEO i w przeciwnym razie IE nie wybierze poprawnej nazwy pliku podczas Zapisz jako.

Możesz ponownie użyć tej samej logiki do serwowania plików z bazy danych. Wystarczy zastąpić new FileInputStream() przez ResultSet#getInputStream().

Mam nadzieję, że to pomoże.

Zobacz też:

 147
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:34

Możesz to zrobić, umieszczając swoje obrazy na ustalonej ścieżce (na przykład: / var / images, lub c:\images), Dodaj ustawienie w ustawieniach aplikacji (reprezentowane w moim przykładzie przez ustawienia.klasy), i załadować je tak, w HttpServlet swojej:

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

Lub jeśli chcesz manipulować obrazem:

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

Wtedy kod html będzie <img src="imageServlet?imageName=myimage.png" />

Oczywiście należy pomyśleć o serwowaniu różnych typów treści - "image / jpeg", na przykład w oparciu o rozszerzenie pliku. Również powinieneś podaj buforowanie.

Dodatkowo możesz użyć tego servletu do przeskalowania jakości obrazów, podając jako argumenty parametry szerokości i wysokości oraz używając image.getScaledInstance(w, h, Image.SCALE_SMOOTH), Oczywiście biorąc pod uwagę wydajność.

 9
Author: Bozho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-28 11:58:22

Wymagania: dostęp do zasobów statycznych (obrazy/filmy., itd.,) spoza katalogu WEBROOT lub z dysku lokalnego

Krok 1:
Utwórz folder pod webapps serwera tomcat., powiedzmy, że nazwa folderu to myproj

Krok 2:
pod myproj utwórz folder WEB-INF pod tym Utwórz prostą stronę internetową.xml

Kod pod web.xml

<web-app>
</web-app>

Struktura katalogów dla powyższych dwóch kroków

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

Krok 3:
Teraz Utwórz plik xml o nazwie myproj.xml w następującej lokalizacji

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

Kod w myproj.xml:

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

Krok 4:
4 A) teraz utwórz folder o nazwie myproj na dysku E Twojego dysku twardego i utwórz nowy

Folder z nazwą images i umieść niektóre obrazy w folderze images (e:myproj\images\)

Załóżmy, że myfoto.jpg znajduje się pod e:\myproj\images\myfoto.jpg

4 B) teraz utwórz folder o nazwie WEB-INF w e:\myproj\WEB-INF i utwórz web.xml w folderze WEB-INF

Kod w sieci.xml

<web-app>
</web-app>

Krok 5:
Utwórz teraz .dokument html z indeksem nazw.html i umieść pod e:\myproj

Kod pod indeksem.html Witamy w Myproj

Struktura katalogów dla powyższego kroku 4 i kroku 5 jest następująca

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

Krok 6:
Teraz uruchom serwer Apache tomcat

Krok 7:
otwórz przeglądarkę i wpisz adres url jako follows

http://localhost:8080/myproj    

Następnie u wyświetla zawartość podaną w indeksie.html

Krok 8:
Aby uzyskać dostęp do obrazów pod lokalnym dyskiem twardym (poza webroot)

http://localhost:8080/myproj/images/myfoto.jpg
 6
Author: sbabamca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-16 05:27:01

Dodaj do serwera.xml:

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

Włącz parametr listy plików dir w sieci web.xml:

    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>
 5
Author: blue-sky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-12 10:27:58

To jest historia z mojego miejsca pracy:
- Staramy się przesyłać mnożyć obrazy i pliki dokumentów za pomocą Struts 1 i Tomcat 7.x.
- Staramy się zapisywać przesłane pliki do systemu plików, nazwy pliku i pełną ścieżkę do rekordów bazy danych.
- Staramy się oddzielić foldery plików poza katalog aplikacji WWW. (*)

Poniższe rozwiązanie jest dość proste, skuteczne dla wymagań (*):

W pliku META-INF/context.xml plik o następującej treści: (Przykład, moja aplikacja run at http://localhost:8080/ABC, my application / project named ABC). (jest to również pełna zawartość pliku context.xml)

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ABC" aliases="/images=D:\images,/docs=D:\docs"/>
Tomcat w wersji 7 lub nowszej]}

Result: We have been created 2 alias. Na przykład, zapisujemy obrazy w: D:\images\foo.jpg i widok z linku lub za pomocą znacznika obrazka:

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

Lub

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

(używam Netbeans 7.x, NetBeans wydają się automatycznie tworzyć plik WEB-INF\context.xml)

 5
Author: Do Nhu Vy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-05 22:35:25

Jeśli zdecydujesz się wysłać do FileServlet, będziesz również potrzebował allowLinking="true" w context.xml, aby umożliwić FileServlet przemierzanie dowiązań symbolicznych.

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

 2
Author: cherouvim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-18 10:46:20

Jeśli ktoś nie jest w stanie rozwiązać swojego problemu z zaakceptowaną odpowiedzią, zwróć uwagę na poniższe rozważania:

  1. nie trzeba wspominać localhost:<port> z atrybutem <img> src.
  2. upewnij się, że uruchamiasz ten projekt poza eclipse, ponieważ eclipse tworzy wpis context docBase samodzielnie wewnątrz lokalnego pliku server.xml.
 0
Author: JPG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-26 08:37:03

Odczytaj strumień wejściowy pliku i zapisz go do ServletOutputStream do wysyłania danych binarnych do klienta.

  • plik lokalny możesz odczytać plik bezpośrednio używając FileInputStream('ścieżka/obraz.png") .
  • Plik bazy danych Mongo możeszget InputStream using 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));
    }
}

Wywołaj adres URL bezpośrednio do 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,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-12 11:13:45

Jeśli chcesz pracować z JAX-RS (np. RESTEasy) spróbuj tego:

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

Używając javax.ws.rs.core.Response i com.google.common.io.ByteStreams

 0
Author: electrobabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-03 01:04:21

Zrobiłem to jeszcze prościej. Problem: plik CSS miał linki url do folderu img. Dostaje 404.

Spojrzałem na url, http://tomcatfolder:port/img/blablah.png , który nie istnieje. Ale to naprawdę wskazuje na aplikację ROOT w Tomcat.

Więc po prostu skopiowałem folder img z mojej webapp do tej aplikacji ROOT. Działa!

Nie jest to oczywiście zalecane do produkcji, ale jest to wewnętrzna aplikacja do tworzenia narzędzi.

 -1
Author: Josef.B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-31 14:57:02