1. 概述
在本教程中,我們將演示如何使用 Spring MVC 框架返回圖像和其他媒體。
我們將討論多種方法,從直接操作 HttpServletResponse開始,然後轉向受益於消息轉換、內容協商和 Spring 的 Resource抽象的方法。 我們將更詳細地研究每種方法,並討論它們的優缺點。
使用 HttpServletResponse 對象
最基本的方式是直接操作 response 對象,並模擬一個純粹的 Servlet 實現。 這種方法通過以下代碼片段進行演示:
@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());
}發出以下請求將會在瀏覽器中渲染圖像:
http://localhost:8080/spring-mvc-xml/image-manual-response.jpg該實現相當簡單直接,得益於 IOUtils 及其來自 org.apache.commons.io 包中的功能。然而,這種方法的缺點在於它對潛在變化不夠健壯。 MIME 類型是硬編碼的,轉換邏輯的更改或外部化圖像位置都需要修改代碼。
以下部分討論了一種更靈活的方法。
3. 使用 <em>HttpMessageConverter</em>
前一節討論了一種基本方法,它沒有利用 Spring MVC 框架的消息轉換和內容協商功能。為了啓動這些功能,我們需要:
- 使用 `@ResponseBody` 註解標註控制器方法
- 根據控制器方法的返回類型註冊適當的消息轉換器(例如,使用 `ByteArrayHttpMessageConverter` 以正確地將字節數組轉換為圖像文件)
3.1. 配置
為了展示轉換器的配置,我們將使用內置的 <em >ByteArrayHttpMessageConverter</em>,該轉換器在方法返回 <em >byte[]</em> 類型時,將消息進行轉換。
<em >ByteArrayHttpMessageConverter</em> 默認已註冊,但配置方式與任何其他內置或自定義轉換器類似。
應用消息轉換器 Bean 需要在 Spring MVC 上下文中註冊適當的 <em >MessageConverter</em> Bean,並設置其應處理的媒體類型。 您可以通過 XML 中的 <em >mvc:message-converters</em> 標籤進行定義。
此標籤應定義在 <em >mvc:annotation-driven</em> 標籤內,如以下示例所示:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>image/jpeg</value>
<value>image/png</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>上述配置部分將註冊 ByteArrayHttpMessageConverter 以處理 image/jpeg 和 image/png 響應內容類型。如果 mvc 配置中未包含 <mvc:message-converters> 標籤,則將註冊默認的轉換器集。
此外,您可以使用 Java 配置註冊消息轉換器:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(byteArrayHttpMessageConverter());
}
@Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
arrayHttpMessageConverter.setSupportedMediaTypes(getSupportedMediaTypes());
return arrayHttpMessageConverter;
}
private List<MediaType> getSupportedMediaTypes() {
List<MediaType> list = new ArrayList<MediaType>();
list.add(MediaType.IMAGE_JPEG);
list.add(MediaType.IMAGE_PNG);
list.add(MediaType.APPLICATION_OCTET_STREAM);
return list;
}3.2. 實現
現在我們可以實現該方法,用於處理媒體請求。正如上面提到的,您需要使用 @ResponseBody</em/> 標註您的控制器方法,並使用 byte[]</em/> 作為返回類型:
@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);
}要測試該方法,請在您的瀏覽器中發出以下請求:
http://localhost:8080/spring-mvc-xml/image-byte-array.jpg從優勢方面來看,該方法不涉及對 HttpServletResponse 的任何知識,轉換過程高度可配置,範圍從使用可用的轉換器到指定自定義轉換器。響應的內容類型無需硬編碼,而是會根據請求路徑後綴 .jpg 進行協商。
這種方法的缺點是,您需要顯式地實現從數據源(本地文件、外部存儲等)獲取圖像的邏輯,並且您無法控制響應的頭信息或狀態碼。
4. 使用 ResponseEntity 類
你可以將圖像作為包裝在 byte[] 中的 ResponseEntity 返回。 Spring MVC 的 ResponseEntity 允許你不僅對 HTTP 響應體進行控制,還允許你控制響應頭和響應狀態碼。 採用這種方法,你需要將方法的返回類型定義為 ResponseEntity<byte[]>,並在方法體中創建返回 ResponseEntity 對象的代碼。
@RequestMapping(value = "/image-response-entity", method = RequestMethod.GET)
public ResponseEntity<byte[]> 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<byte[]> responseEntity = new ResponseEntity<>(media, headers, HttpStatus.OK);
return responseEntity;
}使用 ResponseEntity 允許您為給定請求配置響應碼。
明確設置響應碼在處理異常事件時尤其有用,例如圖像未找到 (FileNotFoundException) 或已損壞 (IOException)。 在這些情況下,只需要設置響應碼,例如在適當的捕獲塊中設置 new ResponseEntity<>(null, headers, HttpStatus.NOT_FOUND),。
此外,如果您需要在響應中設置一些特定的頭部,這種方法比通過接受方法參數的 HttpServletResponse 對象設置頭部更直接。 這使方法簽名清晰且專注於目標。
5. 使用 Resource 類返回圖像
最後,你可以通過 Resource 對象的形式返回圖像。
Resource 接口是用於抽象對低級資源的訪問的接口。它作為更強大的替代方案,在 Spring 中引入,取代了標準 java.net.URL 類。它允許在無需編寫顯式檢索代碼的情況下,輕鬆訪問不同類型的資源(本地文件、遠程文件、類路徑資源)。
要使用這種方法,應將方法的返回類型設置為 Resource,並且需要使用 @ResponseBody 註解標記該方法。
5.1. 實施
@ResponseBody
@RequestMapping(value = "/image-resource", method = RequestMethod.GET)
public Resource getImageAsResource() {
return new ServletContextResource(servletContext, "/WEB-INF/images/image-example.jpg");
}或者,如果我們想要對響應頭控制更精細:
@RequestMapping(value = "/image-resource", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<Resource> getImageAsResource() {
HttpHeaders headers = new HttpHeaders();
Resource resource =
new ServletContextResource(servletContext, "/WEB-INF/images/image-example.jpg");
return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}採用這種方法,您將圖像視為可使用 ResourceLoader 接口實現的資源。在這種情況下,您無需關注圖像的確切位置,ResourceLoader 會決定從何處加載它。
它提供了一種通用的方法,通過配置來控制圖像的位置,從而消除編寫文件加載代碼的需求。
6. 結論
在上述方法中,我們首先從基本方法開始,然後利用框架的消息轉換功能進行改進。我們還討論瞭如何在不直接傳遞響應對象的情況下設置響應代碼和響應頭。
最後,我們從圖像位置方面增加了靈活性,因為圖像的獲取位置由配置項定義,便於隨時更改。
使用 Spring 下載圖像或文件解釋瞭如何使用 Spring Boot 實現相同的功能。