Spring中ResponseBodyAdvice的使用详解

网友投稿 1457 2022-11-27

Spring中ResponseBodyAdvice的使用详解

Spring中ResponseBodyAdvice的使用详解

目录1 ResponseBodyAdvice的简介2 ResponseBodyAdvice的使用1 准备一个SpringBoot项目环境3 添加一个返回包装类4 添加控制类5 接口测试

ResponseBodyAdvice可以在注解@ResponseBody将返回值处理成相应格式之前操作返回值。实现这个接口即可完成相应操作。可用于对response 数据的一些统一封装或者加密等操作

1 ResponseBodyAdvice的简介

ResponseBodyAdvice接口和之前记录的RequestBodyAdvice接口类似, RequestBodyAdvice是请求到Controller之前拦截,做相应的处理操作, 而ResponseBodyAdvice是对Controller返回的{@code @ResponseBody}or a {@code ResponseEntity} 后,{@code HttpMessageConverter} 类型转换之前拦截, 进行相应的处理操作后,再将结果返回给客户端.

ResponseBodyAdvice的源代码:

/** 数据的处理顺序向下

* Allows customizing the response after the execution of an {@code @ResponseBody}

* or a {@code ResponseEntity} controller method but before the body is written

* with an {@code HttpMessageConverter}.

*

*

Implementations may be registered directly with

* {@code RequestMappingHandlerAdapter} and {@code ExceptionHandlerExceptionResolver}

* or more likely annotated with {@code @ControllerAdvice} in which case they

* will be auto-detected by both.

*

* @author Rossen Stoyanchev

* @since 4.1

* @param the body type

*/

public interface ResponseBodyAdvice {

/**

* Whether this component supports the given controller method return type

* and the selected {@code HttpMessageConverter} type.

* @param returnType the return type 方法返回的类型

* @param converterType the selected converter type 参数类型装换

* @return {@code true} if {@link #beforeBodyWrite} should be invoked;

* {@code false} otherwise

* 返回 true 则下面 beforeBodyWrite方法被调用, 否则就不调用下述方法

*/

boolean supports(MethodParameter returnType, Class extends HttpMessageConverter>> converterType);

/**

* Invoked after an {@code HttpMessageConverter} is selected and just before

* its write method is invoked.

* @param body the body to be written

* @param returnType the return type of the controller method

* @param selectedContentType the content type selected through content negotiation

* @param selectedConverterType the converter type selected to write to the response

* @param request the current request

* @param response the current response

* @return the body that was passed in or a modified (possibly new) instance

*/

@Nullable

T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType,

Class extends HttpMessageConverter>> selectedConverterType,

ServerHttpRequest request, ServerHttpResponse response);

}

说明:

supports方法: 判断是否要执行beforeBodyWrite方法,true为执行,false不执行. 通过该方法可以选择哪些类或那些方法的response要进行处理, 其他的不进行处理.

beforeBodyWrite方法: 对response方法进行具体操作处理

{@code @ResponseBody} 返回响应体, 例如List集合

{@code ResponseEntity} 返回响应实体对象,例如User对象

2 ResponseBodyAdvice的使用

1 准备一个SpringBoot项目环境

2 添加一个响应拦截类

@ControllerAdvice

public class BaseResponseBodyAdvice implements ResponseBodyAdvice {

@Override

public boolean supports(MethodParameter returnType, Class converterType) {

return true;

}

@Override

public Object beforeBodyWrite(Object body, MethodParameter returnType,

MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request,

ServerHttpResponse response) {

// 遇到feign接口之类的请求, 不应该再次包装,应该直接返回

// 上述问题的解决方案: 可以在feign-中,给feign请求头中添加一个标识字段, 表示是feign请求

// 在此处拦截到feign标识字段, 则直接放行 返回body.

System.out.println("响应拦截成功");

if (body instanceof BaseResponse) {

return body;

} else if (body == null) {

return BaseResponse.ok();

} else {

return BaseResponse.ok(body);

}

}

}

3 添加一个返回包装类

@Data

@AllArgsConstructor

@NoArgsConstructor

public class BaseResponse {

private T data;

private int status = 200;

private String message;

private long srvTime = System.currentTimeMillis();

public BaseResponse(String message) {

this.message = message;

}

public BaseResponse setData(T data) {

this.data = data;

return this;

}

public static BaseResponse ok() {

return new BaseResponse<>("操作成功");

}

public static BaseResponse ok(T data) {

return new BaseResponse("操作成功").setData(data);

}

}

4 添加控制类

@Controller

@RequestMapping("/hello")

public class HelloWorld {

// 此处数据从数据库中查询, 案例中也可以使用伪数据代替

@Autowired

private UserMapper userMapper;

// {@code ResponseEntity} 案列

@GetMapping("/one")

@ResponseBody

public User one() {

List users = userMapper.selectAll();

System.out.println(users.get(0));

return users.get(0);

}

// {@code @ResponseBody} 案列

@GetMapping("/list")

@ResponseBody

public List list() {

List users = userMapper.selectAll();

System.out.println(users);

return users;

}

}

5 接口测试

浏览器访问: http://localhost:8080/hello/http://one

User(id=1, username=李子柒, phone=77777, icon=李子柒的头像, queryTime=Wed Oct 27 20:47:02 CST 2021)

响应拦截成功

浏览器访问: http://localhost:8080/hello/list

[User(id=1, username=李子柒, phone=77777, icon=李子柒的头像, queryTime=Wed Oct 27 20:46:58 CST 2021)]

响应拦截成功

ps: 如果直接响应字符串返回,则会报类型转换异常.

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:时隔4个月我面试字节又挂了|总结与展望
下一篇:走进 Yarn 资源管理和调度|青训营笔记
相关文章

 发表评论

暂时没有评论,来抢沙发吧~