Mengembalikan Data Gambar / Media dengan Spring MVC

1. Ikhtisar

Dalam tutorial ini, kami akan mengilustrasikan cara mengembalikan gambar dan media lain menggunakan framework Spring MVC.

Kami akan membahas beberapa pendekatan, mulai dari memanipulasi HttpServletResponse secara langsung daripada beralih ke pendekatan yang mendapat manfaat dari Konversi Pesan, Negosiasi Konten, dan abstraksi Sumber Daya Spring . Kami akan melihat lebih dekat masing-masing dan mendiskusikan kelebihan dan kekurangannya.

2. Menggunakan HttpServletResponse

Pendekatan paling dasar dari download gambar adalah dengan langsung bekerja pada objek respons dan meniru implementasi Servlet murni , dan didemonstrasikan menggunakan cuplikan berikut:

@RequestMapping(value = "/image-manual-response", method = RequestMethod.GET) public void getImageAsByteArray(HttpServletResponse response) throws IOException { InputStream in = servletContext.getResourceAsStream("/WEB-INF/images/image-example.jpg"); response.setContentType(MediaType.IMAGE_JPEG_VALUE); IOUtils.copy(in, response.getOutputStream()); }

Menerbitkan permintaan berikut akan membuat gambar di browser:

//localhost:8080/spring-mvc-xml/image-manual-response.jpg

Implementasinya cukup mudah dan sederhana berkat IOUtils dari paket org.apache.commons.io . Namun, kelemahan dari pendekatan ini adalah tidak kuat menghadapi potensi perubahan. Jenis pantomim dikodekan keras dan perubahan logika konversi atau eksternalisasi lokasi gambar memerlukan perubahan pada kode.

Bagian berikut membahas pendekatan yang lebih fleksibel.

3. Menggunakan HttpMessageConverter

Bagian sebelumnya membahas pendekatan dasar yang tidak memanfaatkan fitur Konversi Pesan dan Negosiasi Konten dari Kerangka MVC Spring. Untuk mem-bootstrap fitur-fitur ini kita perlu:

  • Beri anotasi pada metode pengontrol dengan anotasi @ResponseBody
  • Daftarkan konverter pesan yang sesuai berdasarkan jenis kembalian dari metode pengontrol ( misalnya ByteArrayHttpMessageConverter diperlukan untuk konversi yang benar dari array byte ke file gambar)

3.1. Konfigurasi

Untuk menampilkan konfigurasi konverter, kita akan menggunakan ByteArrayHttpMessageConverter bawaan yang mengonversi pesan setiap kali metode mengembalikan tipe byte [] .

The ByteArrayHttpMessageConverter terdaftar secara default, tetapi konfigurasi analog untuk setiap lain built-in atau converter kustom.

Menerapkan message converter bean membutuhkan registrasi bean MessageConverter yang sesuai di dalam konteks Spring MVC dan mengatur tipe media yang harus ditangani. Anda dapat mendefinisikannya melalui XML, menggunakanmenandai.

Tag ini harus didefinisikan di dalam tag, seperti pada contoh berikut:

     image/jpeg image/png     

Bagian konfigurasi yang disebutkan akan mendaftarkan ByteArrayHttpMessageConverter untuk jenis konten respons image / jpeg dan image / png . Jika tag tidak ada dalam konfigurasi mvc, maka kumpulan konverter default akan didaftarkan.

Selain itu, Anda dapat mendaftarkan konverter pesan menggunakan konfigurasi Java :

@Override public void configureMessageConverters(List
    
      converters) { converters.add(byteArrayHttpMessageConverter()); } @Bean public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() { ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter(); arrayHttpMessageConverter.setSupportedMediaTypes(getSupportedMediaTypes()); return arrayHttpMessageConverter; } private List getSupportedMediaTypes() { List list = new ArrayList(); list.add(MediaType.IMAGE_JPEG); list.add(MediaType.IMAGE_PNG); list.add(MediaType.APPLICATION_OCTET_STREAM); return list; }
    

3.2. Penerapan

Sekarang kita bisa mengimplementasikan metode kita yang akan menangani permintaan media. Seperti yang disebutkan di atas, Anda perlu menandai metode pengontrol Anda dengan anotasi @ResponseBody dan menggunakan byte [] sebagai tipe yang dikembalikan:

@RequestMapping(value = "/image-byte-array", method = RequestMethod.GET) public @ResponseBody byte[] getImageAsByteArray() throws IOException { InputStream in = servletContext.getResourceAsStream("/WEB-INF/images/image-example.jpg"); return IOUtils.toByteArray(in); }

Untuk menguji metode ini, keluarkan permintaan berikut di browser Anda:

//localhost:8080/spring-mvc-xml/image-byte-array.jpg

Di sisi keuntungan, metode ini tidak tahu apa-apa tentang HttpServletResponse, proses konversi sangat dapat dikonfigurasi, mulai dari menggunakan konverter yang tersedia hingga menentukan konverter khusus. Jenis konten dari respons tidak harus berupa hard code, melainkan akan dinegosiasikan berdasarkan akhiran jalur permintaan .jpg .

Kerugian dari pendekatan ini adalah Anda perlu menerapkan logika secara eksplisit untuk mengambil gambar dari sumber data (file lokal, penyimpanan eksternal, dll.) Dan Anda tidak memiliki kendali atas header atau kode status respons.

4. Menggunakan Kelas ResponseEntity

Anda bisa mengembalikan gambar sebagai byte [] yang dibungkus dalam Entitas Respons . Spring MVC ResponseEntity memungkinkan kontrol tidak hanya atas isi Respon HTTP tetapi juga header dan kode status tanggapan. Dengan mengikuti pendekatan ini, Anda perlu mendefinisikan tipe kembalian metode sebagai ResponseEntity dan membuat objek ResponseEntity yang dikembalikan dalam badan metode.

@RequestMapping(value = "/image-response-entity", method = RequestMethod.GET) public ResponseEntity getImageAsResponseEntity() { HttpHeaders headers = new HttpHeaders(); InputStream in = servletContext.getResourceAsStream("/WEB-INF/images/image-example.jpg"); byte[] media = IOUtils.toByteArray(in); headers.setCacheControl(CacheControl.noCache().getHeaderValue()); ResponseEntity responseEntity = new ResponseEntity(media, headers, HttpStatus.OK); return responseEntity; }

Menggunakan ResponseEntity memungkinkan Anda mengonfigurasi kode respons untuk permintaan tertentu.

Menyetel kode respons secara eksplisit sangat berguna dalam menghadapi peristiwa luar biasa misalnya jika gambar tidak ditemukan ( FileNotFoundException ) atau rusak ( IOException) . Dalam kasus ini, semua yang diperlukan adalah menyetel kode respons misalnya ResponseEntity baru (null, header, HttpStatus.NOT_FOUND), dalam blok catch yang memadai.

Selain itu, jika Anda perlu menyetel beberapa tajuk khusus dalam respons Anda, pendekatan ini lebih mudah daripada menyetel tajuk dengan menggunakan objek HttpServletResponse yang diterima oleh metode sebagai parameter. Itu membuat tanda tangan metode jelas dan fokus.

5. Mengembalikan Gambar Menggunakan Kelas Sumber Daya

Terakhir, Anda dapat mengembalikan gambar dalam bentuk objek Resource .

The Sumber Daya antarmuka adalah sebuah antarmuka untuk abstrak akses ke sumber daya tingkat rendah. Ini diperkenalkan di Spring sebagai pengganti yang lebih mampu untuk kelas java.net.URL standar . Ini memungkinkan akses mudah ke berbagai jenis resource (file lokal, file jarak jauh, resource classpath) tanpa perlu menulis kode yang secara eksplisit mengambilnya.

Untuk menggunakan pendekatan ini, jenis kembalian dari metode ini harus disetel ke Resource dan Anda perlu memberi anotasi pada metode tersebut dengan anotasi @ResponseBody .

5.1. Penerapan

@ResponseBody @RequestMapping(value = "/image-resource", method = RequestMethod.GET) public Resource getImageAsResource() { return new ServletContextResource(servletContext, "/WEB-INF/images/image-example.jpg"); }

atau, jika kita ingin lebih mengontrol header respon:

@RequestMapping(value = "/image-resource", method = RequestMethod.GET) @ResponseBody public ResponseEntity getImageAsResource() { HttpHeaders headers = new HttpHeaders(); Resource resource = new ServletContextResource(servletContext, "/WEB-INF/images/image-example.jpg"); return new ResponseEntity(resource, headers, HttpStatus.OK); }

Dengan menggunakan pendekatan ini, Anda memperlakukan gambar sebagai sumber daya yang dapat dimuat menggunakan implementasi antarmuka ResourceLoader . Dalam kasus seperti itu, Anda mengabstraksi dari lokasi persis gambar Anda dan ResourceLoader memutuskan dari mana gambar tersebut dimuat.

Ini memberikan pendekatan umum untuk mengontrol lokasi gambar menggunakan konfigurasi, dan menghilangkan kebutuhan untuk menulis kode pemuatan file.

6. Kesimpulan

Di antara pendekatan yang disebutkan di atas, kami mulai dari pendekatan dasar, kemudian menggunakan pendekatan yang memanfaatkan fitur konversi pesan dari framework. Kami juga membahas cara mendapatkan set kode respons dan header respons tanpa menyerahkan objek respons secara langsung.

Terakhir, kami menambahkan fleksibilitas dari sudut pandang lokasi gambar, karena dari mana mengambil gambar, ditentukan dalam konfigurasi yang lebih mudah untuk diubah dengan cepat.

Unduh Gambar atau File dengan Spring menjelaskan cara mencapai hal yang sama menggunakan Spring Boot.

Kode contoh setelah tutorial tersedia di GitHub.