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());
    }
posted @ 2019-03-26 20:45  喜欢日向雏田一样的女子啊  阅读(5448)  评论(0编辑  收藏  举报