优秀的编程知识分享平台

网站首页 > 技术文章 正文

33-Spring MVC的REST控制器建言(spring restcontroller)

nanyue 2024-09-03 16:18:25 技术文章 7 ℃

上篇我们学习了《32-Spring MVC的控制器建言@ControllerAdvice》,本篇我们学习REST控制器建言@RestControllerAdvice。

@RestControllerAdvice是组合注解,它组合了@ControllerAdvice@ResponseBody,它的功能和@ControllerAdvice一致,主要使用于对RESTful的请求体和返回体进行定制处理。

2.4.1 先处理请求体与后处理返回体

对请求体定制处理实现RequestBodyAdvice接口,它会在请求体进入控制器方法之前对请求体进行先处理;对返回体进行定制处理ResponseBodyAdvice,它会在控制器方法返回值确定之后对返回值进行后处理。他们和@RestControllerAdvice一起使用。

我们定义个注解,这个注解作为使用我们的定制功能的标记。

@Target({ElementType.PARAMETER, ElementType.METHOD}) //支持注解在方法参数和方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ProcessTag {
}

定制请求体的建言:

@RestControllerAdvice
public class CustomRequestBodyAdvice implements RequestBodyAdvice {
    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
       return methodParameter.getParameterAnnotation(ProcessTag.class) != null; //1

    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        return inputMessage; //2
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        if (body instanceof Person) {
            Person person = (Person) body;
            String upperCaseName = person.getName().toUpperCase();
            return new Person(person.getId(), upperCaseName, person.getAge());
        }
        return body; //3
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        if(Person.class.isAssignableFrom((Class<?>) targetType)){
            return new Person(new Random().nextLong(),"Nobody",-1);
        }
        return body; //4
    }
}
  1. 该请求体建言起效的条件,本例是请求体参数是否标记了@ProcessTag注解;
  2. 在请求体读取前,未做任何处理;
  3. 在请求体读取后,如果请求体类型是Person,将name转为大写;若不是Person保持不变;
  4. 在处理请求体为空时,如果请求体类型是Person,建一个对象,否则保持不变。

定制的返回体处理建言:

@RestControllerAdvice
public class CustomResponseBodyAdvice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return returnType.hasMethodAnnotation(ProcessTag.class); //1
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof Person){
            Map<String, Object> map = new HashMap<>();
            map.put("person", body);
            map.put("extra-response-body", "demo-body");
            return map;
        }
        return body; //2
    }
}
  1. 该返回体建言起效的条件,本例是控制器方法上标记了@ProcessTag注解;
  2. 在写返回体前,我们将额外的信息和body封装到map里返回;若不是Person类型则保持不变。

我们在控制里验证这两个建言:

@GetMapping("/modifyBodies")
@ProcessTag //标记定制返回体
public Person modifyRequestBody(@ProcessTag @RequestBody Person person){ //标记定制请求体
    return person;
}

我们请求体不为空时请求:


我们请求体为空时请求:

最近发表
标签列表