SpringMVC:参数处理RequestBodyAdvice和返回结果处理ResponseBodyAdvice
目录背景使用场景接口说明RequestBodyAdviceResponseBodyAdvice示例场景说明:参数转换自定义注解User实体对象接口返回对象自定义RequestBodyAdvice参数处理器自定义ResponseBodyAdvice返回值处理器controller接口测试注意事项在SpringBoot项目中,很多时候都需要对Controller层请求参数和响应结果做一些公共操作,这时
目录
RequestBodyAdvice
在执行Controller接口之前,如果Controller参数是被@RequestBody修饰,可以对该参数进行一些特殊处理,比如参数解密,参数转换等。
ResponseBodyAdvice
执行完Controller接口之后,在response返回给客户端之前,如果Controller方法被@ResponseBody修饰,此时可以对response返回的数据做一些特殊处理,比如返回值加密,构造统一返回对象,返回值转换等。
背景
在SpringBoot项目中,很多时候都需要对Controller层请求参数和响应结果做一些公共操作,这时就可以使用RequestBodyAdvice和ResponseBodyAdvice。
使用场景
对接口参数进行前后空格的过滤;
参数转换,比如字段关联字典:将字典显示值转换为保存值;
解密一些关键性字段;
返回参数统一处理;
身份证等特殊字符统一转换为*;
接口说明
RequestBodyAdvice
public interface RequestBodyAdvice {
/**
* 该方法用于判断当前请求,是否要执行beforeBodyRead方法
* methodParameter方法的参数对象
* type方法的参数类型
* aClass 将会使用到的Http消息转换器类类型
* 注意:此判断方法,会在beforeBodyRead 和 afterBodyRead方法前都触发一次。
*
* @return 返回true则会执行beforeBodyRead
*/
boolean supports(MethodParameter methodParameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType);
/**
* 在Http消息转换器执转换,之前执行
* inputMessage 客户端的请求数据
* parameter方法的参数对象
* targetType方法的参数类型
* converterType 将会使用到的Http消息转换器类类型
* @return 返回 一个自定义的HttpInputMessage
*/
HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException;
/**
* 在Http消息转换器执转换,之后执行
* body 转换后的对象
* inputMessage 客户端的请求数据
* parameter 方法的参数类型
* targetType 方法的参数类型
* converterType 使用的Http消息转换器类类型
* @return 返回一个新的对象
*/
Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
/**
* 参数与afterBodyRead相同,body为空时由该方法处理
*/
@Nullable
Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
}
ResponseBodyAdvice
public interface ResponseBodyAdvice<T> {
/**
* 判断当前返回结果,是否要执行beforeBodyWrite方法
* @param returnType
* @param converterType
* @return
*/
boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);
/**
* 对返回对象做一些特殊处理
* @param body 返回给前端的对象
* @param returnType 控制器方法的返回类型
* @param selectedContentType 内容类型
* @param selectedConverterType 选择器类型
* @param request 请求对象
* @param response 返回值对象
* @return
*/
@Nullable
T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response);
}
示例
场景说明:参数转换
自定义一个注解@TransParam,现在需要将Controller接口中,@TransParam注解修饰的参数进行参数转换。
转换关系:controller入参:男->0,女->1,其他值->2;
转换关系:controller出参:0->男1,1->女1,其他值->中性
自定义注解
注解可应用于
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TransParam {
}
User实体对象
User对象中sex字段被@TransParam修饰。
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
private String name;
@TransParam
private int sex;
}
接口返回对象
@Data
@AllArgsConstructor
public class ResponseResult {
private int code;
private Object content;
public static ResponseResult fail(Object content) {
return new ResponseResult(HttpStatus.FOUND.value(), content);
}
public static ResponseResult success(Object content) {
return new ResponseResult(HttpStatus.OK.value(), content);
}
}
自定义RequestBodyAdvice参数处理器
作用:将@TransParam修饰的字段值,进行转换:男->0,女->1,其他值->2;
主要会用到supports和beforeBodyRead两个方法:
supports判断是否对当前接口进行参数转换;
beforeBodyRead执行具体的转换逻辑。
@ControllerAdvice
public class MyRequestBodyAdvice implements RequestBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
if (inputMessage.getBody().available()<=0) {
return inputMessage;
}
// 获取前端入参jsonobj
byte[] requestBodyByte=new byte[inputMessage.getBody().available()];
inputMessage.getBody().read(requestBodyByte);
String requestData = new String(requestBodyByte, StandardCharsets.UTF_8);
JSONObject jsonobj = JSON.parseObject(requestData);
// 参数转换,将@TransParam修饰的字段,男->0,女->1,其他值->2;
jsonobj = transParams(jsonobj, targetType);
// 使用解密后的数据,构造新的读取流
return getNewInputStream(jsonobj, inputMessage);
}
private JSONObject transParams(JSONObject jsonobj, Type targetType) {
try {
Class<?> clazz = Class.forName(targetType.getTypeName());
// 获取接口参数类的所有属性
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
// 如果属性被@TransParam修饰,则执行转换
if (field.getAnnotation(TransParam.class) != null) {
String value = jsonobj.getString(fieldName);
if (value.equals("男")) {
jsonobj.put(fieldName, 0);
} else if (value.equals("女")) {
jsonobj.put(fieldName, 1);
} else {
jsonobj.put(fieldName, 2);
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return jsonobj;
}
private HttpInputMessage getNewInputStream(JSONObject jsonobj, HttpInputMessage inputMessage) {
byte[] newRequestByte = jsonobj.toJSONString().getBytes();
InputStream rawInputStream = new ByteArrayInputStream(newRequestByte);
return new HttpInputMessage() {
@Override
public HttpHeaders getHeaders() {
return inputMessage.getHeaders();
}
@Override
public InputStream getBody() {
return rawInputStream;
}
};
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
}
自定义ResponseBodyAdvice返回值处理器
作用
1、将@TransParam修饰的字段值,进行转换:0->男1,1->女1,其他值->中性;
2、将返回值统一封装成ResponseResult对象返回给前端。
主要会用到supports和beforeBodyWrite两个方法:
supports判断是否对当前返回值进行值转换;
beforeBodyWrite执行具体的转换逻辑。
@ControllerAdvice
public class MyResponseBodyAdvice 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) {
JSONObject jsonObject = null;
try {
Class<?> clazz = Class.forName(returnType.getParameterType().getName());
// 获取返回值对象类的所有属性
Field[] fields = clazz.getDeclaredFields();
jsonObject = JSONObject.parseObject(JSONObject.toJSONString(body));
for (Field field : fields) {
String fieldName = field.getName();
// 如果字段被@TransParam修饰,则进行数据转换:0->男1,1->女1,其他值->中性
if (field.getAnnotation(TransParam.class) != null) {
String value = jsonObject.getString(fieldName);
if (value.equals("0")) {
jsonObject.put(fieldName, "男1");
} else if (value.equals("1")) {
jsonObject.put(fieldName, "女1");
} else {
jsonObject.put(fieldName, "中性");
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
// 将返回结果封装成ResponseResult对象统一返回。
return ResponseResult.success(jsonObject);
}
}
controller接口
@ResponseBody
@PostMapping("/test")
public User test(@RequestBody User user) {
String result = "姓名:" + user.getName() + "; 性别编号:" + user.getSex();
System.out.println(result);
return user;
}
测试

注意事项
自定义的处理对象类上必须得加上@ControllerAdvice注解;
RequestBodyAdvice作用范围为@RequestBody修饰的参数;
ResponseBodyAdvice作用范围为@ResponseBodyAdvice修饰的方法。
以上内容为个人学习理解,如有问题,欢迎在评论区指出。
更多推荐


所有评论(0)