目录
Spring ResponseEntity对象详细及其源码分析
ResponseEntity
代表返回的数据是一个对象,在Spring MVC中,请求数据到对象和对象到响应数据的转换是通过消息转换器来完成的。
@RequestBody
用于读取Request请求的body部分数据。使系统默认的HttpMessageConverter进行解析,然后把相应的数据绑定要返回的对象上,再把HttpMessageConverter返回的对象数据绑定到Controller方法的参数上。
自动将前台传入的JSON字符串转换成对应的类对象。只能接收POST请求,GET是不行的。
@ResponseBody
只是作为一个响应体,注解标记请求处理方法。把方法返回值直接写到HTTP response body(响应体)
@RestController = Controller + ResponseBody
也就在每个方法上面都加上了@ResponseBody
@ResponseBody一般与@Controller组合使用,用来返回JSON字符串;自动将后端响应的类对象转换成对应的JSON字符串
一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@ResponseBody后返回结果不会被解析为跳转路径,其将方法的返回值通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来给客户端返回JSON数据、XML数据。
比如:异步获取JSON数据,加上@ResponseBody后,会直接返回JSON数据;能够处理方法结果值作为http响应体;在典型的Spring MVC应用中,请求点通常返回html页面;有时仅需要实际数据,如使用AJAX请求。
(1)无@ResponseBody时,底层会将方法的返回值封装为ModelAndView对象,也就是走视图解析器
如果有@ResponseBody这个注解,return “/ssyer/index”,返回数据就是字符/ssyer/index,没有经过视图处理器直接返回
(2)使用此注解之后不会再走视图解析器,而是直接将数据写入到输入流中,等同于通过response对象输出指定格式的数据
如果没有这个注解,那么返回的就是/ssyer/index这个地址所指的内容,也就是经过经过视图处理器处理后的视图,返回的是视图
@ResponseStatus:状态码
@ResponseStatus:标记一个方法或异常类在返回时响应的http状态。
@ResponseStatus一般与RestController组合使用。@ResponseStatus无法设置标题,也无法设置HttpServletResponse或HttpHeaders参数,但是很简单方便
ResponseEntity
ResponseEntity是在org.springframework.http.HttpEntity的基础上添加http status code(http状态码),用于RestTemplate以及@Controller的HandlerMethod。它在Controoler中或者用于服务端响应时,作用和@ResponseStatus与@ResponseBody结合起来的功能一样的。用于RestTemplate时,它是接收服务端返回的http status code和reason的。
ResponseEntity标识整个HTTP响应:状态码、头部信息、响应体内容。因此可以使用其对http响应实现完整配置,它是一个对象。
(1)标识整个http,可以使用任意类型作为响应体,可以通过编程方式指明响应状态,根据不同场景返回不同状态,并设置http响应头
(2)提供了两个内嵌的构建器接口:HeadersBuilder和其子接口BodyBuilder。因此能通过ResponseEntity的静态方法直接访问。也可以自定义头信息
http 请求包含什么?
请求头、请求行、请求体;响应头、响应体、响应行(状态码)
HttpMessageConverter
HTTP请求和响应是基于文本的,意味着浏览器和服务器通过交换原始文本进行通信。但是,使用Spring,Controller类中的方法返回纯String类型和域模型(或其他Java内建对象)
HttpMessageConverter是消息转换器的顶层接口,所有的消息转换器都必须实现这个接口
策略接口,它指定了一个转换器,可以将请求和响应转换为HTTP请求和响应
针对不同的类型,实现了具体消息转换器
@since 3.0
public interface HttpMessageConverter<T> {
/**
* 指示此转换器是否可以读取给定的类
* @param clazz 要测试可读性的类
* @param mediaType 要读取的媒体类型,如果没有指定,可以是{@code null});通常是{@code Content-Type}头的值
* @return true为可读,false反之
* /
boolean canRead(Class<?> clazz, MediaType mediaType);
/**
* 指示给定的类是否可以由此转换器写入
* @param clazz 要测试可写性的类
* @param 要写入的媒体类型(如果没有指定,可以是{@code null});通常是{@code Accept}报头的值
* @return {@code true}可写,false反之
* /
boolean canWrite(Class<?> clazz, MediaType mediaType);
/**
* 返回此转换器支持的{@link MediaType}对象列表
* @return 支持的媒体类型列表
* /
List<MediaType> getSupportedMediaTypes();
/**
* 从给定的输入消息中读取给定类型的对象,并返回它
* @param clazz 要返回的对象的类型。此类型以前必须已传递给这个接口的{@link #canRead canRead}方法,它必须返回{@code true}
* @param inputMessage 要从中读取的HTTP输入消息
* @return 转换对象
* @throws I/O错误时的IOException
* @throws 转换错误时的HttpMessageNotReadableException
* /
T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException;
/**
* 将给定的对象写入给定的输出消息
* @param t 要写入输出消息的对象。此对象的类型以前必须是传递给该接口的{@link canWrite}方法,必须是返回{@code true}
* @param contentType 编写时使用的内容类型。可能是{@code null}来表示必须使用转换器的默认内容类型。如果不是{@code null},则此媒体类型必须具有以前被传递给这个接口的{@link canWrite}方法,它必须有返回{@code true}
* @param outputMessage 要写的消息
* @throws I/O错误时的IOException
* @throws 转换错误时的HttpMessageNotReadableException
* /
void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;
}
ResponseEntity使用
ResponseEntity继承了HttpEntity,是HttpEntity的子类且可以添加HttpStatus状态码,被用于 RestTemplate和Controller层方法。
@GetMapping("list")
public ResponseEntity<List<User>> queryUserListById(@RequestParam("id") Long id) {
return ResponseEntity.ok(userService.queryCategoryListByPid(id));
}
ResponseEntity ,泛型T表示要设置的返回的响应体,而ResponseEntity.ok()表示设置的状态码 200,而ResponseEntity.ok()其实是一种快捷的写法。
@GetMapping("list")
public ResponseEntity<List<User>> queryUserListById(@RequestParam("id") Long id) {
// return ResponseEntity.status(200)
// .body(mCategoryService.queryUserListById(id));
return ResponseEntity.status(HttpStatus.OK).body(userService.queryCategoryListByPid(id));
}
ResponseEntity和@ResponseStatus一起使用是无效的,ResponseEntity的设置会覆盖@ResponseStatus
ResponseEntity源码分析
属性
package org.springframework.http;
public class ResponseEntity<T> extends HttpEntity<T> {
private final Object status; // 属性
}
构造方法
/**
* 使用给定的状态码创建一个新的{@code ResponseEntity},没有正文和标题
* @param status 状态码
* /
public ResponseEntity(HttpStatus status) {
this(null, null, status); // 调用自己的私有构造
}
/**
* 使用给定的正文和状态代码创建一个新的{@code ResponseEntity},没有标题
* @param body 实体类
* @param status 状态码
* /
public ResponseEntity(T body, HttpStatus status) {
this(body, null, status);
}
/**
* 创建一个新的{@code HttpEntity},包含给定的头信息和状态码,没有正文
* @param headers 实体标头
* @param status 状态码
* /
public ResponseEntity(MultiValueMap<String, String> headers, HttpStatus status) {
this(null, headers, status);
}
/**
* 使用给定的正文、标题和状态代码创建一个新的{@code HttpEntity}
* @param body 实体
* @param headers 实体标头
* @param status 状态码
* /
public ResponseEntity(T body, MultiValueMap<String, String> headers, HttpStatus status) {
super(body, headers);
Assert.notNull(status, "HttpStatus must not be null");
this.status = status;
}
/**
* 使用给定的正文、标题和状态代码创建一个新的{@code HttpEntity}
* 只是在嵌套的builder API后面使用
* @param body 实体
* @param headers 实体头
* @param status 状态码(为{@code HttpStatus}或{@code Integer}值)
* /
private ResponseEntity(T body, MultiValueMap<String, String> headers, Object status) {
super(body, headers);
this.status = status;
}
@RequestMapping(value="/response/entity/headers", method=RequestMethod.GET)
public ResponseEntity<String> responseEntityCustomHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
return new ResponseEntity<String>("The String ResponseBody with
custom header Content-Type=text/plain",
headers, //指定content-type
HttpStatus.OK);
}
成员方法
(1)HttpStatus getStatusCode()
返回响应的HTTP状态码。HttpStatus enum条目的HTTP作为状态
(2)getStatusCodeValue()
返回响应的HTTP状态码。int值的HTTP作为状态(@since 4.3)
静态生成器方法(都是静态的,4.1版本以后)
静态builder方法 | 描述 |
---|---|
BodyBuilder status(HttpStatus status) | status 响应状态码(HttpStatus)。返回具有给定状态的生成器。return new DefaultBuilder(status);也就是说也可调用DefaultBuilder下的方法 |
BodyBuilder status(int status) | status 响应状态码(int)。返回具有给定状态的生成器。return new DefaultBuilder(status);也就是说也可调用DefaultBuilder下的方法 |
BodyBuilder ok() | 返回创建一个状态设置为{@linkplain HttpStatus.OK}的生成器 |
ResponseEntity ok(T body) | 创建具有给定主体和的{@code ResponseEntity}的快捷方式状态设置为{@linkplain HttpStatus.OK OK} |
BodyBuilder created(URI location) | location URI的位置。使用{@linkplain HttpStatus.CREATED}创建一个新的生成器和设置为给定URI的位置标头 |
BodyBuilder accepted() | 创建一个具有{@linkplain HttpStatus.ACCEPTED}状态的生成器 |
HeadersBuilder<?> noContent() | 使用{@linkplain HttpStatus.NO_CONTENT}状态创建一个生成器 |
BodyBuilder badRequest() | 创建一个带有{@linkplain HttpStatus.BAD_REQUEST}状态的生成器 |
HeadersBuilder<?> notFound() | 创建一个具有{@linkplain HttpStatus.NOT_FOUND}状态的生成器 |
BodyBuilder unprocessableEntity() | 创建一个生成器{@linkplain HttpStatus.UNPROCESSABLE_ENTITY}状态 |
HeadersBuilder接口
定义一个向响应实体添加标头的生成器
/**
* @since 4.1
* @param <B> 建造者子类
* /
public interface HeadersBuilder<B extends HeadersBuilder<B>> {}
/**
* 在给定名称下添加给定的单一标题值,返回这个构造器
* headerName 标题名称
* headerValues 头的值(s)
* /
B header(String headerName, String... headerValues)
/**
* 将给定的标头复制到实体的标头映射中,返回这个构造器
* headers 要复制的现有httpheader
* /
B headers(HttpHeaders headers)
/**
* 根据指定设置允许的{@link HttpMethod HTTP方法}通过{@code Allow}头,返回这个构造器
* allowedMethods 允许的方法
* /
B allow(HttpMethod... allowedMethods)
/**
* 设置主体的实体标记,由{@code ETag}头指定
* etag 新的实体标签
* /
B eTag(String etag)
/**
* 属性所指定的,设置上次更改资源的时间{@code last - modified}头。日期应该指定为此后的毫秒数1970年1月1日,返回这个构造器
* lastModified 最后修改日期
* /
B lastModified(long lastModified)
/**
* 设置资源的位置,由{@code location}头指定,返回这个构造器
* location 位置
* /
B location(URI location)
/**
* 设置资源的缓存指令,如HTTP 1.1所指定的{@code cache-control}头。
* <p>一个{@code CacheControl}实例可以这样构建{@code CacheControl.maxAge (3600) .cachePublic () .noTransform ()}
* cacheControl 一个缓存相关的HTTP响应头的生成器
* /
B cacheControl(CacheControl cacheControl)
/**
* 配置一个或多个请求头名称(例如。“接收语言”),添加到“变化”响应标头,通知客户响应是以内容协商和基于值的差异为准,给定请求头。只添加配置的请求头名称,如果还没有出现在响应的“Vary”标题中
* requestHeaders 请求头名称
* /
B varyBy(String... requestHeaders)
/**
* 构建没有主体的响应实体,返回响应实体
* /
ResponseEntity<T> build()
BodyBuilder接口
定义将主体添加到响应实体的生成器
@since 4.1
public interface BodyBuilder extends HeadersBuilder<BodyBuilder> {}
/**
* 方法指定的,以字节为单位设置主体的长度{@code Content-Length}报头,返回这个构建器
* contentLength 内容长度
* /
BodyBuilder contentLength(long contentLength)
/**
* 属性所指定的,设置主体的{@linkplain MediaType媒体类型}{@code Content-Type}报头,返回这个构建器
* contentType 内容类型
* /
BodyBuilder contentType(MediaType contentType)
/**
* 设置响应实体的主体并返回它,返回构建的响应实体
* <T> body的类型
* body 响应实体的主体
* /
ResponseEntity<T> body(T body)
DefaultBuilder静态内部类
private static class DefaultBuilder implements BodyBuilder {
private final Object statusCode;
private final HttpHeaders headers = new HttpHeaders();
}
构造方法
DefaultBuilder(Object statusCode)
方法
header(String headerName, String... headerValues)
headers(HttpHeaders headers)
allow(HttpMethod... allowedMethods)
contentLength(long contentLength)
contentType(MediaType contentType)
eTag(String etag)
lastModified(long date)
location(URI location)
cacheControl(CacheControl cacheControl)
BodyBuilder varyBy(String... requestHeaders)
ResponseEntity<T> build(){ return body(null) }
ResponseEntity<T> body(T body){
return new ResponseEntity<T>(body, this.headers, this.statusCode); }
没有写返回值的都是返回this,也就是返回DefaultBuilder的实例,方法的返回类型都是BodyBuilder