Zurückgeben von Bild- / Mediendaten mit Spring MVC
1. Überblick
In diesem Tutorial wird veranschaulicht, wie Bilder und andere Medien mithilfe des Spring MVC-Frameworks zurückgegeben werden.
Wir werden verschiedene Ansätze diskutieren, angefangen von der direkten Manipulation vonHttpServletResponse bis hin zu Ansätzen, die von der Abstraktion vonMessage Conversion,Content Negotiation und SpringResourceprofitieren. Wir werden uns jeden einzelnen genauer ansehen und ihre Vor- und Nachteile diskutieren.
2. Verwenden SieHttpServletResponse
Der grundlegendste Ansatz des Bilddownloads besteht darin, direkt mit dem Objektresponsezu arbeiten und die Implementierung eines reinenServletnachzuahmen. Dies wird anhand des folgenden Snippets demonstriert:
@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());
}
Wenn Sie die folgende Anforderung absetzen, wird das Bild in einem Browser gerendert:
http://localhost:8080/spring-mvc-xml/image-manual-response.jpg
Die Implementierung ist aufgrund vonIOUtils aus dem Paketorg.apache.commons.io ziemlich einfach und unkompliziert. Der Nachteil des Ansatzes besteht jedoch darin, dass er gegenüber möglichen Änderungen nicht robust ist. Der MIME-Typ ist fest codiert, und die Änderung der Konvertierungslogik oder die Externalisierung des Bildorts erfordert Änderungen am Code.
Der folgende Abschnitt beschreibt einen flexibleren Ansatz.
3. Using the *HttpMessageConverter *
Im vorherigen Abschnitt wurde ein grundlegender Ansatz erläutert, bei dem die FunktionenMessage Conversion undContent Negotiationdes Spring MVC Framework nicht genutzt werden. Um diese Funktion zu booten, müssen wir:
-
Kommentieren Sie die Controller-Methode mit der Annotation@ResponseBody
-
Registrieren Sie einen geeigneten Nachrichtenkonverter basierend auf dem Rückgabetyp der Controller-Methode (ByteArrayHttpMessageConverter, die beispielsweise für die korrekte Konvertierung des Byte-Arrays in eine Bilddatei benötigt wird).
3.1. Aufbau
Zur Darstellung der Konfiguration der Konverter verwenden wir die integriertenByteArrayHttpMessageConverter, die eine Nachricht konvertieren, wenn eine Methode den Typbyte[]zurückgibt.
ByteArrayHttpMessageConverter ist standardmäßig registriert, die Konfiguration ist jedoch für jeden anderen integrierten oder benutzerdefinierten Konverter analog.
Zum Anwenden der Message Converter Bean müssen Sie eine geeigneteMessageConverter Bean im Spring MVC-Kontext registrieren und die Medientypen einrichten, die verarbeitet werden sollen. Sie können es über XML mit dem Tag<mvc:message-converters>definieren.
Dieses Tag sollte wie im folgenden Beispiel innerhalb des Tags von<mvc:annotation-driven>definiert werden:
image/jpeg
image/png
Der oben erwähnte Konfigurationsteil registriertByteArrayHttpMessageConverter fürimage/jpeg undimage/png Antwortinhaltstypen. Wenn<mvc:message-converters> Tag in der MVC-Konfiguration nicht vorhanden ist, wird der Standardsatz von Konvertern registriert.
Sie können auch den Nachrichtenkonverterusing Java configuration registrieren:
@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. Implementierung
Jetzt können wir unsere Methode implementieren, die Anfragen nach Medien behandelt. Wie oben erwähnt, müssen Sie Ihre Controller-Methode mit der Annotation@ResponseBody markieren undbyte[] als Rückgabetyp verwenden:
@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);
}
Geben Sie die folgende Anforderung in Ihrem Browser aus, um die Methode zu testen:
http://localhost:8080/spring-mvc-xml/image-byte-array.jpg
Auf der Vorteilsseite weiß die Methode nichts über dieHttpServletResponse,, für die der Konvertierungsprozess hochgradig konfigurierbar ist. Dies reicht von der Verwendung der verfügbaren Konverter bis zur Angabe eines benutzerdefinierten Konvertierungsprozesses. Der Inhaltstyp der Antwort muss nicht fest codiert sein, sondern beträgtnegotiated basierend auf dem Anforderungspfadsuffix.jpg.
Der Nachteil dieses Ansatzes besteht darin, dass Sie die Logik zum Abrufen von Bildern aus einer Datenquelle (lokale Datei, externer Speicher usw.) explizit implementieren müssen und keine Kontrolle über die Header oder den Statuscode der Antwort haben.
4. Verwenden derResponseEntity-Klasse
Sie können ein Bild alsbyte[] zurückgeben, das inResponse Entity eingeschlossen ist. Spring MVCResponseEntity ermöglicht die Steuerung nicht nur des Hauptteils der HTTP-Antwort, sondern auch des Headers und des Antwortstatuscodes. Nach diesem Ansatz müssen Sie den Rückgabetyp der Methode alsResponseEntity<byte[]> definieren und das zurückgebendeResponseEntity-Objekt im Methodenkörper erstellen.
@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;
}
MitResponseEntity können Sie einen Antwortcode für eine bestimmte Anforderung konfigurieren.
Das explizite Festlegen des Antwortcodes ist insbesondere angesichts eines außergewöhnlichen Ereignisses, z. wenn das Bild nicht gefunden wurde (FileNotFoundException) oder beschädigt ist (IOException). In diesen Fällen ist nur das Einstellen des Antwortcodes erforderlich, z. new ResponseEntity<>(null, headers, HttpStatus.NOT_FOUND), in einem geeigneten Fangblock.
Wenn Sie in Ihrer Antwort bestimmte Header festlegen müssen, ist dieser Ansatz außerdem einfacher als das Festlegen von Headern mithilfe desHttpServletResponse-Objekts, das von der Methode als Parameter akzeptiert wird. Es macht die Methodensignatur klar und fokussiert.
5. Bild mit der KlasseResourcezurückgeben
Schließlich können Sie ein Bild in Form desResource-Objekts zurückgeben.
DieResource-Schnittstelle ist eine Schnittstelle zum Abstrahieren des Zugriffs auf Ressourcen auf niedriger Ebene. Es wird im Frühjahr als leistungsfähigerer Ersatz für die Standardklassejava.net.URLeingeführt. Es ermöglicht einen einfachen Zugriff auf verschiedene Arten von Ressourcen (lokale Dateien, Remotedateien, Klassenpfadressourcen), ohne dass ein Code geschrieben werden muss, der sie explizit abruft.
Um diesen Ansatz zu verwenden, sollte der Rückgabetyp der Methode aufResource festgelegt werden, und Sie müssen die Methode mit der Annotation@ResponseBody versehen.
5.1. Implementierung
@ResponseBody
@RequestMapping(value = "/image-resource", method = RequestMethod.GET)
public Resource getImageAsResource() {
return new ServletContextResource(servletContext, "/WEB-INF/images/image-example.jpg");
}
oder, wenn wir mehr Kontrolle über die Antwortheader haben wollen:
@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);
}
Mit diesem Ansatz behandeln Sie Bilder als Ressourcen, die mithilfe der Schnittstellenimplementierung vonResourceLoadergeladen werden können. In diesem Fall abstrahieren Sie von der genauen Position Ihres Bildes undResourceLoader entscheidet, woher es geladen wird.
Es bietet einen allgemeinen Ansatz, um den Speicherort von Bildern mithilfe der Konfiguration zu steuern und das Schreiben von Code zum Laden von Dateien zu vermeiden.
6. Fazit
Unter den oben genannten Ansätzen gingen wir vom Basisansatz aus und verwendeten den Ansatz, der von der Nachrichtenkonvertierungsfunktion des Frameworks profitiert. Wir haben auch besprochen, wie der Antwortcode und die Antwortheader abgerufen werden können, ohne das Antwortobjekt direkt zu übergeben.
Schließlich haben wir die Flexibilität aus der Sicht der Bildpositionen hinzugefügt, da in der Konfiguration festgelegt ist, wo ein Bild abgerufen werden soll, das im Handumdrehen leichter geändert werden kann.
Der Beispielcode nach dem Tutorial ist unterGitHub verfügbar.