Spring ResponseEntity


簡單記錄下 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出場的機會了.

image

 

從HandlerMethodReturnValueHandler接口的第一個方法分析使用滿足條件:

代碼片段位於:org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor#supportsReturnType

只要@RequestMapping的方法返回值為 HttpEntity的實現類 且不是 RequestEntity類或其子類  就會使用HttpEntityMethodProcessor來處理 請求返回值,簡單來說ResponseEntity類就行.

image

 

從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());
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM