Bir Java web uygulamasında uygulama sunucusunun dışından statik verileri sunmanın en basit yolu


131

Tomcat üzerinde çalışan bir Java web uygulamam var. Hem Web kullanıcı arayüzünde hem de uygulama tarafından oluşturulan PDF dosyalarında gösterilecek statik görüntüleri yüklemek istiyorum. Ayrıca Web Kullanıcı Arayüzü üzerinden yüklenerek yeni resimler eklenecek ve kaydedilecektir.

Statik verileri web konteynerinde depolayarak bunu yapmak sorun değil, ancak bunları web konteynerinin dışından depolamak ve yüklemek başımı ağrıtıyor.

Bu noktada statik verileri sunmak için Apache gibi ayrı bir web sunucusu kullanmamayı tercih ederim. Ayrıca görüntüleri bir veritabanında ikili olarak saklama fikrini de sevmiyorum.

Görüntü dizininin web kapsayıcısı dışındaki bir dizine işaret eden sembolik bir bağlantı olması gibi bazı öneriler gördüm, ancak bu yaklaşım hem Windows hem de * nix ortamlarında çalışacak mı?

Bazıları, görüntü sunumunu işlemek için bir filtre veya sunucu uygulaması yazmayı önerir, ancak bu öneriler, bunun nasıl gerçekleştirileceğine dair daha ayrıntılı bilgilere işaret etmeden çok belirsiz ve yüksek düzeylidir.

Yanıtlar:


161

Görüntü dizininin web kapsayıcısı dışındaki bir dizine işaret eden sembolik bir bağlantı olması gibi bazı öneriler gördüm, ancak bu yaklaşım hem Windows hem de * nix ortamlarında çalışacak mı?

* Nix dosya sistemi yolu kurallarına uyarsanız (yani /path/to/files, özellikle eğik çizgi kullanırsanız ), o zaman çirkin File.separatordizge birleştirmeleriyle uğraşmanıza gerek kalmadan Windows'ta da çalışacaktır . Ancak, yalnızca bu komutun çalıştırıldığı yerden aynı çalışma diskinde taranacaktır. Öyleyse, örneğin Tomcat yüklü ise, C:o /path/to/fileszaman aslında işaret eder C:\path\to\files.

Dosyaların tümü web uygulamasının dışında bulunuyorsa DefaultServletve Tomcat'in bunları işlemesini istiyorsanız, Tomcat'te temel olarak yapmanız gereken tek şey aşağıdaki Bağlam öğesini /conf/server.xml<Host>etikete eklemektir :

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

Bu yolla erişilebilir olacaklar http://example.com/files/.... GlassFish / Payara yapılandırma örneği burada bulunabilir ve WildFly yapılandırma örneği burada bulunabilir .

Eğer dosyaları yazma / okuma kendinizi üzerinde kontrole sahip olmak istiyorsanız, o zaman bir oluşturmanız gerekir Servlettemelde sadece bir aldığı Bunun için InputStreamörneğin lezzet dosyanın FileInputStreamve yazar OutputStreamarasında HttpServletResponse.

Yanıtta, Content-Typeistemcinin sağlanan dosyayla hangi uygulamayı ilişkilendireceğini bilmesi için üstbilgiyi ayarlamalısınız . Content-LengthÜstbilgiyi istemcinin indirme ilerlemesini hesaplayabileceği şekilde ayarlamalısınız , aksi takdirde bilinmeyecektir. Ayrıca, Farklı Kaydet iletişim kutusu istiyorsanız Content-Dispositionbaşlığı olarak ayarlamalısınız , aksi takdirde istemci bunu satır içi olarak görüntülemeye çalışacaktır. Son olarak, dosya içeriğini yanıt çıktı akışına yazın.attachment

İşte böyle bir sunucu uygulamasının temel bir örneği:

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

}

url-patternÖrneğin bir ile eşleştirildiğinde, /files/*onu arayabilirsin http://example.com/files/image.png. Bu şekilde DefaultServlet, varsayılan bir görüntü (yani if (!file.exists()) file = new File("/path/to/files", "404.gif")veya benzeri) sağlamak gibi istekler üzerinde olduğundan daha fazla kontrole sahip olabilirsiniz . Ayrıca , daha SEO dostu olduğu için request.getPathInfo()yukarıda tercih edilir request.getParameter()ve aksi takdirde IE Farklı Kaydet sırasında doğru dosya adını seçmez .

Veritabanından dosya sunmak için aynı mantığı yeniden kullanabilirsiniz. Basitçe yerine new FileInputStream()göre ResultSet#getInputStream().

Bu yardımcı olur umarım.

Ayrıca bakınız:


1
@SalutonMondo: en az çabayla yol.
BalusC

@BalusC, bunu denedim: <Context docBase="/path/to/images" path="/images" />Windows'ta, ancak webapps klasörüne göre yol alıyorum:C:\install\apache-tomcat-8.0.26\webapps\tmp] is not valid
ACV

Windows'ta şu şekilde olmalıdır:<Context docBase="C:\tmp\" path="/images" />
ACV

Ve HTTP Status 404 - /images/bunu yaparken:, http://localhost:8080/images/AMA under works'den belirli bir dosya tmp: http://localhost:8080/images/Tulips.jpgTAMAM
ACV

Bu şekilde klasörün içine bir resim koyarsam, sunucuyu yeniden başlatmadığınız sürece resmin bağlantısı 404 cevabını verecektir, bunun herhangi bir sebebi var mı?
Mateus Viccari

9

Bunu, resimlerinizi sabit bir yola (örneğin: / var / images veya c: \ images) yerleştirerek, uygulama ayarlarınıza bir ayar ekleyerek (benim örneğimde Settings.class ile temsil edilmektedir) ve bunları yükleyerek yapabilirsiniz. bunun gibi HttpServlet, sizinkilerden:

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

Veya resmi değiştirmek istiyorsanız:

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

o zaman html kodu <img src="imageServlet?imageName=myimage.png" />

Elbette farklı içerik türleri sunmayı düşünmelisiniz - örneğin dosya uzantısına bağlı olarak "resim / jpeg". Ayrıca biraz önbelleğe alma sağlamalısınız.

Buna ek olarak, bu servlet'i görüntülerinizin kalitesini yeniden ölçeklendirmek için, genişlik ve yükseklik parametrelerini bağımsız değişken olarak sağlayarak ve image.getScaledInstance(w, h, Image.SCALE_SMOOTHelbette performansı göz önünde bulundurarak) kullanarak kullanabilirsiniz .


2
Bunun için Java 2D API'ye gerçekten ihtiyacınız yok, yalnızca gereksiz yere daha fazla ek yük getirecektir. Sadece bir InputStream okuyun ve OutputStream'e yazın.
BalusC

1
Evet, yanıtı yeniden ölçeklendirme ve diğer manipülasyon fikriyle başlattım, ancak sonunda basitleştirdim.
Bozho

7

Server.xml dosyasına ekleyin:

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

Dir dosyası listeleme parametresini web.xml'de etkinleştirin:

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

Web.xml'deki değişiklikle birlikte, seçim kutusuna göndermek için bir dosya listesi alabilir miyim?
Tomasz Waszczyk

1
bu değişiklik sizin uygulamanızın değil
tomcat'in web.xml'sinde olacak

Bunun için teşekkürler! Dir dosyası listeleme parametresini web.xml'de etkinleştirmek gerekli mi?
dariru

6

Gereksinim: Statik Kaynaklara (resimler / videolar, vb.) WEBROOT dizininin dışından veya yerel diskten erişim

Adım 1:
tomcat sunucusunun web uygulamaları altında bir klasör oluşturun, klasör adının myproj olduğunu söyleyelim.

Adım 2:
myproj altında, bunun altında bir WEB-INF klasörü oluşturun, basit bir web.xml oluşturun

web.xml altındaki kod

<web-app>
</web-app>

Yukarıdaki iki adım için Dizin Yapısı

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

Adım 3:
Şimdi aşağıdaki konum altında myproj.xml adında bir xml dosyası oluşturun

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

Myproj.xml'deki KOD:

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

Adım 4:
4 A) Şimdi sabit diskinizin E sürücüsünde myproj adında bir klasör oluşturun ve yeni bir

ad resimleri içeren klasör ve bazı resimleri resimler klasörüne yerleştirin (e:myproj\images\)

Myfoto.jpg dosyasının e:\myproj\images\myfoto.jpg

4 B) Şimdi içinde WEB-INF adında bir klasör e:\myproj\WEB-INFoluşturun ve WEB-INF klasöründe bir web.xml oluşturun

Web.xml'deki kod

<web-app>
</web-app>

Adım 5:
Şimdi index.html adıyla bir .html belgesi oluşturun ve e: \ myproj altına yerleştirin

İndex.html altında KOD Myproj'a Hoş Geldiniz

Yukarıdaki Adım 4 ve Adım 5 için Dizin Yapısı aşağıdaki gibidir

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

Adım 6:
Şimdi apache tomcat sunucusunu başlatın

Adım 7:
Tarayıcıyı açın ve aşağıdaki gibi url'yi yazın

http://localhost:8080/myproj    

index.html'de sağlanan içeriği görüntüler.

Adım 8:
Yerel sabit diskiniz altındaki Görüntülere Erişmek İçin (webroot dışında)

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

dinamik değerler için aynı şeyin nasıl yapılacağını bana önerebilir misiniz? Demek istediğim, verileri (xml) yerel dizinime veya ve jsp sayfamda okumak istiyorum. Yukarıdaki prosedürü kullanarak onlara erişebilmem için dizine yönetilen sunucuya yazmanın herhangi bir yolu var mı?
Sudip7

index.html dosyasını düzgün çalıştırabilsem, ancak web tarayıcısında görüntüler görüntülenmiyor
rogerwar

Hata mesajım iyi çalışıyor Sadece E: / myproj'un sonuna / yazmayı unuttum Bunu E: / myproj / olarak değiştirdim ve çalışıyor Teşekkürler @sbabamca
rogerwar

Merhaba, Gönderi için teşekkürler ve çok kullanışlı. Burada, dosyaları arayüz aracılığıyla bu dizine yüklemek istiyorum. Aynı şekilde POST yöntemini etkinleştirmek istiyorum. Biri bana aynı konuda yardım edebilir mi?
vicky

6

Bu benim iş yerimden bir hikaye:
- Birden çok görüntü yüklemeye çalışıyoruz ve belge dosyaları Struts 1 ve Tomcat 7.x kullanıyor.
- Yüklenen dosyaları dosya sistemine, dosya adına ve veritabanı kayıtlarının tam yolunu yazmaya çalışıyoruz.
- Web uygulama dizini dışındaki dosya klasörlerini ayırmaya çalışıyoruz . (*)

Aşağıdaki çözüm oldukça basittir ve gereksinim için etkilidir (*):

META-INF/context.xmlAşağıdaki içeriğe sahip dosya dosyasında: (Örnek, uygulamam çalışıyor, http://localhost:8080/ABCuygulamam / projem adlandırılıyor ABC). (bu aynı zamanda dosyanın tam içeriğidir context.xml)

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

(Tomcat sürüm 7 veya üzeri ile çalışır)

Sonuç: 2 takma ad oluşturduk. Örneğin, resimleri şuraya kaydediyoruz: D:\images\foo.jpg ve bağlantıdan veya resim etiketi kullanarak görüntülüyoruz:

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

veya

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

(Netbeans 7.x kullanıyorum, Netbeans otomatik olarak dosya oluşturuyor gibi görünüyor WEB-INF\context.xml)



0

Sorununu kabul edilen cevapla çözemeyen biri varsa, aşağıdaki hususlara dikkat edin:

  1. söz ihtiyacını hiçbir localhost:<port>ile <img> srcöznitelik.
  2. Bu projeyi tutulmanın dışında çalıştırdığınızdan emin olun, çünkü tutulma context docBasekendi yerel server.xmldosyasında kendi başına girdi oluşturur .

0

Bir dosyanın InputStream'ini okuyun ve ServletOutputStreamistemciye ikili veri göndermek için yazın.

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

URL'yi doğrudan srcniteliğe getirin.

<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

JAX-RS (örn. RESTEasy) ile çalışmak istiyorsanız şunu deneyin:

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

kullanarak javax.ws.rs.core.Responsevecom.google.common.io.ByteStreams


-1

Daha da basit yaptım. Sorun: Bir CSS dosyasının img klasörüne url bağlantıları vardı. 404 alır.

Var olmayan url, http: // tomcatfolder: port / img / blablah.png adresine baktım . Ancak, bu gerçekten Tomcat'teki ROOT uygulamasına işaret ediyor.

Bu yüzden img klasörünü web uygulamamdan bu ROOT uygulamasına kopyaladım. İşler!

Elbette üretim için tavsiye edilmez, ancak bu dahili bir araç geliştirme uygulaması içindir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.