簡單記錄下 ResponseEntity 的使用方式
@RequestMapping(value="/demo1" )
public ResponseEntity demo1(){
// 使用方式一.
// ResponseEntity responseEntity = new ResponseEntity(new User("lvbb",24),HttpStatus.OK);
// 使用方式二.
return ResponseEntity.ok(new User("lvbb",24));
}
效果: 在引入jackson的jar包,以及開啟<mvc:annotation-driven/>之后,訪問請求可以看到 界面上顯示出 User 的json格式。
說明. ResponseEntity可以理解為 @ResponseBody + @ResponseStatus 的組合.
ResponseEntity類介紹:
ResponseEntity類繼承自HttpEntity,有三個關鍵屬性 httpStatus 、body、httpHeader,分別代表響應狀態碼、響應體、響應頭信息;
原理簡單記錄:
Spring對於@RequestMapping方法返回值有個接口,專門用來處理返回值類型HandlerMethodReturnValueHandler,接口兩個聲明方法:supportsReturnType判斷是否支持對當前返回值類型,如果是支持解析該種返回值,就調用接口第二個方法handleReturnValue,解析@RequestMapping返回值。
Spring4.3.0 <mvc:annotation-driven/>一共會為我們注冊15個HandlerMethodReturnValueHandler的實現類. 其中 RequestResponseBodyMethodProcessor用來處理@ResponseBody,而HttpEntityMethodProcessor是用來處理 ReponseEntity類型的返回值. 這里也可以發現一點:HttpEntityMethodProcessor在arrayList中的位置要比RequestResponseBodyMethodProcessor靠前,所以 使用了 ResponseEntity 就沒有@ResponseBody出場的機會了.

從HandlerMethodReturnValueHandler接口的第一個方法分析使用滿足條件:
代碼片段位於:org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor#supportsReturnType
只要@RequestMapping的方法返回值為 HttpEntity的實現類 且不是 RequestEntity類或其子類 就會使用HttpEntityMethodProcessor來處理 請求返回值,簡單來說ResponseEntity類就行.

從HandlerMethodReturnValueHandler接口的第二個方法分析使用如何將ResponseEntity返回給瀏覽器?
代碼片段位於:org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor#handleReturnValue
對比@ResponseEntity解析器RequestResponseBodyMethodProcessor,很多地方相似,這兩個解析器都繼承自AbstractMessageConverterMethodProcessor。
記錄下與@ResponseBody不同的地方:1. 可以設置HttpHeaders響應頭消息,並通過Response寫回;通過這種方式 ResponseEntity可以實現下載文件
2. 可以設置HttpStatus,設置響應狀態碼.
代碼具體地方都和ResponseEntity一樣,可以看下我這篇解析:
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
mavContainer.setRequestHandled(true);
if (returnValue == null) {
return;
}
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
Assert.isInstanceOf(HttpEntity.class, returnValue);
HttpEntity<?> responseEntity = (HttpEntity<?>) returnValue;
HttpHeaders outputHeaders = outputMessage.getHeaders();
HttpHeaders entityHeaders = responseEntity.getHeaders();
if (outputHeaders.containsKey(HttpHeaders.VARY) && entityHeaders.containsKey(HttpHeaders.VARY)) {
List<String> values = getVaryRequestHeadersToAdd(outputHeaders, entityHeaders);
if (!values.isEmpty()) {
outputHeaders.setVary(values);
}
}
if (!entityHeaders.isEmpty()) {
for (Map.Entry<String, List<String>> entry : entityHeaders.entrySet()) {
if (!outputHeaders.containsKey(entry.getKey())) {
outputHeaders.put(entry.getKey(), entry.getValue());
}
}
}
if (responseEntity instanceof ResponseEntity) {
outputMessage.getServletResponse().setStatus(((ResponseEntity<?>) responseEntity).getStatusCodeValue());
HttpMethod method = inputMessage.getMethod();
boolean isGetOrHead = (HttpMethod.GET == method || HttpMethod.HEAD == method);
if (isGetOrHead && isResourceNotModified(inputMessage, outputMessage)) {
outputMessage.setStatusCode(HttpStatus.NOT_MODIFIED);
// Ensure headers are flushed, no body should be written.
outputMessage.flush();
// Skip call to converters, as they may update the body.
return;
}
}
// Try even with null body. ResponseBodyAdvice could get involved.
writeWithMessageConverters(responseEntity.getBody(), returnType, inputMessage, outputMessage);
// Ensure headers are flushed even if no body was written.
outputMessage.flush();
}
簡單記錄下:ResponseEntity小文件下載的方式
@RequestMapping(value="/demo2")
public ResponseEntity demo2() throws IOException {
ClassPathResource resource = new ClassPathResource("download/note.txt");
InputStream in = resource.getInputStream();
byte[] bytes = new byte[in.available()];
in.read(bytes);
HttpHeaders headers=new HttpHeaders();
headers.add("Content-Disposition","attachment;filename="+resource.getFilename());
HttpStatus statusCode=HttpStatus.OK;
return new ResponseEntity(bytes,headers,statusCode);
}
效果等同於:利用@ResponseEntity返回byte數組
//通過 ResponseBody返回文件 二進制文件
@RequestMapping(value="/demo11")
@ResponseBody
public byte[] demo11(HttpServletResponse response) throws IOException {
ClassPathResource resource = new ClassPathResource("download/note.txt");
InputStream in = resource.getInputStream();
byte[] bytes = new byte[in.available()];
in.read(bytes);
response.addHeader("Content-Disposition","attachment;filename="+resource.getFilename());
return bytes;
}
最原始的方式:
@RequestMapping(value="/demo3")
public void demo3(HttpServletResponse response) throws IOException {
ClassPathResource resource = new ClassPathResource("download/note.txt");
InputStream in = resource.getInputStream();
response.addHeader("Content-Disposition","attachment;filename="+resource.getFilename());
FileCopyUtils.copy(in,response.getOutputStream());
}
