loading...
浅析ResponseBodyAdvice接口的理解和实际应用
Published in:2022-02-15 | category: Spring
Words: 875 | Reading time: 4min | reading:

浅析ResponseBodyAdvice接口的理解和实际应用

一、官方解释

官方对ResponseBodyAdvice接口类,大致描述是这样的

允许执行{@code ResponseBody} 或 {@code ResponseEntity} 控制器方法之后,但在使用{@code HttpMessageConverter}编写主体之前自定义响应。

实现可以直接用{@code RequestMappingHandlerAdapter} 和 {@code ExceptionHandlerExceptionResolver}注释,在这种情况下,它们将被两者自动检测。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* 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.*/
public interface ResponseBodyAdvice<T> {
/**
* 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
*/
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
*/
T beforeBodyWrite(T body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response);

}

二、方法分析

ResponseBodyAdvice接口是在Controller执行return之后,在Response返回给客户端之前,执行的对response的一些处理,可以实现对response数据的一些统一封装或者加密等操作。

该接口一共有两个方法:

  1. supports —— 判断是否需要执行beforeBodyWrite方法,true为执行,false不执行 —— 通过supports方法,我们可以选择哪些类或哪些方法要对response进行处理,其余的则不处理。
  2. beforeBodyWrite —— 对response处理的具体执行方法。

三、在Spring项目开发中的应用场景

对Controller层的返回值进行修改或增强处理。比如返回值5,需要封装成

1
2
3
4
5
{
"code": 0,
"data": 5,
"msg": "success"
}

格式返回给前端。

1. Controller层

1
2
3
4
5
6
7
8
@RestController //此注解包含@ResponseBody注解
@RequestMapping("/mp")
public class ResponseBodyAdviceController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public int hello() {
return 5;
}
}

2. 实现ResponseBodyAdvice接口的切面类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
*此注解针对controller层的类做增强功能,即对加了@RestController注解的类进行处理
*/
@ControllerAdvice(annotations = RestController.class)
public class RestResultWrapper implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}

@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {

//定义一个统一的返回类
RestResult responseResult = new RestResult( "0", body, "success");
//如果handler处理类的返回类型是String(即控制层的返回值类型),为了保证一致性,这里需要将ResponseResult转回去
if(body instanceof String) {
return JSON.toJSONString(responseResult);
}
//封装后的数据返回到前端页面
return JSONObject.toJSON(responseResult);
}
}

3. 返回公共类的创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 统一返回Rest风格的数据结构
public class RestResult<T> implements Serializable {
private String code = "2000";
// 成功时返回的数据,失败时返回具体的异常信息
private T data;
// 请求失败返回的提示信息,给前端进行页面展示的信息
private String message ;

public RestResult() {
}

@Override
public String toString() {
return "RestResult{" +
"code='" + code + '\'' +
", data=" + data +
", message=" + message +
'}';
}

public RestResult(String code, T data, String message) {
this.code = code;
this.data = data;
this.message = message;
}
}
Prev:
FastJson的AutoType
Next:
GitHub:remote:Support for password authentication was removed on August 13, 2021.
catalog
catalog