Cara termudah untuk menyajikan data statis dari luar server aplikasi dalam aplikasi web Java

131

Saya memiliki aplikasi web Java yang berjalan di Tomcat. Saya ingin memuat gambar statis yang akan ditampilkan di Web UI dan dalam file PDF yang dihasilkan oleh aplikasi. Juga gambar baru akan ditambahkan dan disimpan dengan mengunggah melalui UI Web.

Ini bukan masalah untuk melakukan ini dengan memiliki data statis yang disimpan di dalam wadah web tetapi menyimpan dan memuatnya dari luar wadah web membuat saya sakit kepala.

Saya lebih suka tidak menggunakan server web terpisah seperti Apache untuk menyajikan data statis pada saat ini. Saya juga tidak suka ide menyimpan gambar dalam biner dalam database.

Saya telah melihat beberapa saran seperti menjadikan direktori gambar sebagai tautan simbolis yang menunjuk ke direktori di luar wadah web, tetapi apakah pendekatan ini akan berfungsi baik di lingkungan Windows dan * nix?

Beberapa menyarankan untuk menulis filter atau servlet untuk menangani penyajian gambar tetapi saran-saran itu sangat samar dan tingkat tinggi tanpa petunjuk untuk informasi yang lebih rinci tentang cara melakukannya.

Janne
sumber

Jawaban:

161

Saya telah melihat beberapa saran seperti menjadikan direktori gambar sebagai tautan simbolis yang menunjuk ke direktori di luar wadah web, tetapi apakah pendekatan ini akan berfungsi baik di lingkungan Windows dan * nix?

Jika Anda mematuhi aturan jalur sistem file * nix (yaitu Anda menggunakan garis miring maju seperti pada /path/to/files), maka itu akan bekerja pada Windows juga tanpa perlu bermain-main dengan File.separatorrangkaian-string yang jelek . Namun itu hanya akan dipindai pada disk kerja yang sama seperti dari tempat perintah ini dipanggil. Jadi jika Tomcat misalnya diinstal pada C:maka /path/to/filesakan benar-benar menunjuk ke C:\path\to\files.

Jika semua file berada di luar webapp, dan Anda ingin memiliki Tomcat DefaultServletuntuk menanganinya, maka yang perlu Anda lakukan di Tomcat adalah menambahkan elemen Konteks berikut ke /conf/server.xmldalam <Host>tag:

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

Dengan cara ini mereka akan dapat diakses http://example.com/files/.... Contoh konfigurasi GlassFish / Payara dapat ditemukan di sini dan contoh konfigurasi WildFly dapat ditemukan di sini .

Jika Anda ingin memiliki kontrol atas membaca / menulis file Anda sendiri, maka Anda perlu membuat Servletuntuk ini yang pada dasarnya hanya mendapat InputStreamfile di rasa misalnya FileInputStreamdan menulis ke OutputStreamdari HttpServletResponse.

Pada tanggapannya, Anda harus mengatur Content-Typetajuk sehingga klien tahu aplikasi mana yang harus dikaitkan dengan file yang disediakan. Dan, Anda harus mengatur Content-Lengthtajuk agar klien dapat menghitung progres unduhan, jika tidak maka tidak akan diketahui. Dan, Anda harus mengatur Content-Dispositiontajuk ke attachmentjika Anda ingin dialog Simpan Sebagai , jika tidak klien akan berusaha untuk menampilkannya sebaris. Terakhir, cukup tulis konten file ke aliran output respons.

Berikut adalah contoh dasar dari servlet tersebut:

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

}

Ketika dipetakan pada suatu url-patterncontoh /files/*, maka Anda dapat memanggilnya dengan http://example.com/files/image.png. Dengan cara ini Anda dapat memiliki kontrol lebih besar atas permintaan daripada yang DefaultServletdilakukan, seperti memberikan gambar default (yaitu if (!file.exists()) file = new File("/path/to/files", "404.gif")atau lebih). Juga menggunakan request.getPathInfo()lebih disukai di atas request.getParameter()karena lebih SEO friendly dan jika tidak IE tidak akan memilih nama file yang benar selama Save As .

Anda dapat menggunakan kembali logika yang sama untuk menyajikan file dari database. Cukup ganti new FileInputStream()dengan ResultSet#getInputStream().

Semoga ini membantu.

Lihat juga:

BalusC
sumber
1
@SalutonMondo: jalan dengan sedikit usaha.
BalusC
@BalusC, saya mencoba ini: <Context docBase="/path/to/images" path="/images" />di Windows, tetapi mendapatkan jalur relatif ke folder webapps:C:\install\apache-tomcat-8.0.26\webapps\tmp] is not valid
ACV
Pada Windows seharusnya:<Context docBase="C:\tmp\" path="/images" />
ACV
Dan mendapatkan HTTP Status 404 - /images/ketika melakukan http://localhost:8080/images/:, TAPI file tertentu dari bawah tmpberfungsi: http://localhost:8080/images/Tulips.jpgOK
ACV
Dengan cara ini jika saya meletakkan gambar di dalam folder, tautan ke gambar akan memberikan respons 404 kecuali Anda me-restart server, apakah ada alasan untuk ini?
Mateus Viccari
9

Anda dapat melakukannya dengan meletakkan gambar Anda pada jalur yang tetap (misalnya: / var / images, atau c: \ images), menambahkan pengaturan dalam pengaturan aplikasi Anda (diwakili dalam contoh saya oleh Settings.class), dan memuatnya seperti itu, di salah HttpServletsatu milik Anda:

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

Atau jika Anda ingin memanipulasi gambar:

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

maka kode html akan menjadi <img src="imageServlet?imageName=myimage.png" />

Tentu saja Anda harus mempertimbangkan untuk menyajikan berbagai jenis konten - "image / jpeg", misalnya berdasarkan ekstensi file. Anda juga harus memberikan caching.

Selain itu, Anda dapat menggunakan servlet ini untuk mengubah kualitas gambar Anda, dengan memberikan parameter lebar dan tinggi sebagai argumen, dan menggunakan image.getScaledInstance(w, h, Image.SCALE_SMOOTH), tentu saja mempertimbangkan kinerja.

Bozho
sumber
2
Anda benar-benar tidak memerlukan Java 2D API untuk ini, itu hanya akan menambah overhead yang tidak perlu. Cukup baca InputStream dan tulis ke OutputStream.
BalusC
1
Yup, saya memulai respon dengan ide penyelamatan dan manipulasi lainnya, tetapi akhirnya menyederhanakannya.
Bozho
7

Tambahkan ke server.xml:

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

Aktifkan parameter daftar file dir di web.xml:

    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>
langit biru
sumber
Dengan perubahan di web.xml saya bisa mendapatkan daftar file untuk mengirimnya ke kotak pilih?
Tomasz Waszczyk
1
perubahan ini akan ada di web.xml tomcat, bukan aplikasi Anda
vsingh
Terima kasih untuk ini! Apakah mengaktifkan parameter daftar file dir di web.xml diperlukan?
dariru
6

Persyaratan: Mengakses Sumber Daya statis (gambar / video., Dll.) Dari luar direktori WEBROOT atau dari disk lokal

Langkah 1:
Buat folder di bawah webapps dari tomcat server., Katakanlah nama foldernya adalah myproj

Langkah 2:
Di bawah myproj buat folder WEB-INF di bawah ini buat web.xml sederhana

kode di bawah web.xml

<web-app>
</web-app>

Struktur Direktori untuk dua langkah di atas

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

Langkah 3:
Sekarang buat file xml dengan nama myproj.xml di bawah lokasi berikut

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

KODE di myproj.xml:

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

Langkah 4:
4 A) Sekarang buat folder dengan nama myproj di drive E hard disk Anda dan buat yang baru

folder dengan nama gambar dan letakkan beberapa gambar di folder gambar (e:myproj\images\)

Mari kita anggap myfoto.jpg ditempatkan di bawah e:\myproj\images\myfoto.jpg

4 B) Sekarang buat folder dengan nama WEB-INF e:\myproj\WEB-INFdan buat web.xml dalam folder WEB-INF

Kode di web.xml

<web-app>
</web-app>

Langkah 5:
Sekarang buat dokumen .html dengan nama index.html dan letakkan di bawah e: \ myproj

CODE di bawah index.html Selamat datang di Myproj

Struktur Direktori untuk Langkah 4 dan 5 di atas adalah sebagai berikut

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

Langkah 6:
Sekarang mulai server apache tomcat

Langkah 7:
buka browser dan ketik url sebagai berikut

http://localhost:8080/myproj    

lalu u tampilkan konten yang disediakan di index.html

Langkah 8:
Untuk Mengakses Gambar di bawah hard disk lokal Anda (di luar webroot)

http://localhost:8080/myproj/images/myfoto.jpg
sbabamca
sumber
dapatkah Anda menyarankan saya, bagaimana melakukan hal yang sama untuk nilai-nilai dinamis. Maksud saya, saya ingin menulis data (xml) ke direktori lokal saya atau dan dan untuk membacanya di halaman jsp saya. Apakah ada cara untuk menulis ke server dikelola ke direktori sehingga saya mengaksesnya menggunakan prosedur di atas ??
Sudip7
meskipun saya dapat menjalankan file index.html dengan benar tetapi tidak ada gambar yang ditampilkan di browser web
rogerwar
Posting kesalahan saya berfungsi dengan baik. Saya lupa meletakkan / di akhir E: / myproj Saya mengubahnya ke E: / myproj / dan berfungsi dengan baik Terima kasih @sbabamca
rogerwar
Hai, Terima kasih atas postingnya dan ini sangat berguna. Di sini saya ingin mengunggah file melalui antarmuka ke direktori tertentu. Saya ingin mengaktifkan metode POST untuk hal yang sama. Adakah yang bisa bantu saya di sama.
vicky
6

Ini adalah cerita dari tempat kerja saya:
- Kami mencoba mengunggah banyak gambar dan dokumen dokumen menggunakan Struts 1 dan Tomcat 7.x.
- Kami mencoba menulis file yang diunggah ke sistem file, nama file, dan jalur lengkap ke catatan basis data.
- Kami mencoba memisahkan folder file di luar direktori aplikasi web . (*)

Solusi di bawah ini cukup sederhana, efektif untuk kebutuhan (*):

Dalam file META-INF/context.xmlfile dengan konten berikut: (Contoh, aplikasi saya berjalan pada http://localhost:8080/ABC, nama aplikasi / proyek saya ABC). (ini juga isi penuh file context.xml)

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

(bekerja dengan Tomcat versi 7 atau lebih baru)

Hasil: Kami telah membuat 2 alias. Misalnya, kami menyimpan gambar di: D:\images\foo.jpg dan melihat dari tautan atau menggunakan tag gambar:

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

atau

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

(Saya menggunakan Netbeans 7.x, Netbeans sepertinya otomatis membuat file WEB-INF\context.xml)

Apakah Nhu Vy
sumber
0

jika ada yang tidak dapat menyelesaikan masalahnya dengan jawaban yang diterima, maka perhatikan pertimbangan di bawah ini:

  1. tidak perlu disebutkan localhost:<port>dengan <img> srcatribut.
  2. pastikan Anda menjalankan proyek ini di luar eclipse, karena eclipse membuat context docBaseentri sendiri di dalam server.xmlfile lokalnya .
JPG
sumber
0

Baca InputStream file dan tuliskan ServletOutputStreamuntuk mengirim data biner ke klien.

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

Hasil URL langsung ke srcattibute.

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

Jika Anda ingin bekerja dengan JAX-RS (mis. RESTEasy) coba ini:

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

menggunakan javax.ws.rs.core.Responsedancom.google.common.io.ByteStreams

electrobabe
sumber
-1

Saya melakukannya bahkan lebih sederhana. Masalah: File CSS memiliki tautan url ke folder img. Mendapat 404.

Saya melihat url, http: // tomcatfolder: port / img / blablah.png , yang tidak ada. Tapi, itu benar-benar menunjuk ke aplikasi ROOT di Tomcat.

Jadi saya hanya menyalin folder img dari aplikasi web saya ke aplikasi ROOT itu. Bekerja!

Tidak direkomendasikan untuk produksi, tentu saja, tetapi ini untuk aplikasi dev alat internal.

Josef.B
sumber