zoukankan      html  css  js  c++  java
  • 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());
        }
  • 相关阅读:
    C# BackgroundWorker使用总结
    C#如何优雅的结束一个线程
    C#线程中安全访问控件(重用委托,避免繁复的delegate,Invoke)总结
    C#异步方法调用(四大方法详解)
    C# Winform 跨线程更新UI控件常用方法汇总
    走进异步编程的世界
    走进异步编程的世界
    走进异步编程的世界
    Unity-Redis数据存储
    untiy
  • 原文地址:https://www.cnblogs.com/lvbinbin2yujie/p/10602586.html
Copyright © 2011-2022 走看看