簡單記錄下 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()); }