Spring: @ControllerAdvice & @ResponseBodyAdvice

 

Config:

复制代码
package io.jot.memento;


import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@Configuration
public class Config{
  @ControllerAdvice
  static class MyControllerAdvice implements ResponseBodyAdvice{
    @Override
    public boolean supports(MethodParameter returnType, Class converterType){
      if(returnType.getMethodAnnotation(ResponseBody.class) != null ||
        AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null
        /*returnType.getContainingClass().isAnnotationPresent(ResponseBody.class)*/){
        return true;
      }
      return false;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response){
      if(body instanceof Result)
        return body;
      return Result.ok(body);
    }
  }

  // @Controller
  // @ResponseBody
  @RestController
  public static class MyController{
    public User user(){
      return new User("bbbbbbbbbb", 55);
    }
  }

  public static class User{
    private String name;
    private int age;

    public User(String name, int age){
      this.name = name;
      this.age = age;
    }

    public String getName(){
      return name;
    }

    public void setName(String name){
      this.name = name;
    }

    public int getAge(){
      return age;
    }

    public void setAge(int age){
      this.age = age;
    }
  }
}
复制代码

 

Result:

复制代码
package io.jot.memento;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Result{
    private int code;
    private String msg;
    private Object data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    @JsonCreator
    private Result(@JsonProperty("code") int code, @JsonProperty("data") Object data) {
        this.code = code;
        this.data = data;
    }

    private Result(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public static Result ok() {
        return new Result(200, null);
    }

    public static Result ok(Object data) {
        return new Result(200, data);
    }

    public static Result error(String msg) {
        return new Result(500, "服务器内部错误:" + msg);
    }
}
复制代码

 

复制代码
package io.jot.memento;


import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.ControllerAdviceBean;
import org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver;
import org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver;
import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.*;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class Venal{
  public static void main(String[] args) throws Exception{
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
    ServletInvocableHandlerMethod handlerMethod = new ServletInvocableHandlerMethod(context.getBean(Config.MyController.class), Config.MyController.class.getMethod("user"));
    handlerMethod.setDataBinderFactory(new ServletRequestDataBinderFactory(Collections.emptyList(), null));
    handlerMethod.setHandlerMethodArgumentResolvers(getArgumentResolvers(context));
    handlerMethod.setHandlerMethodReturnValueHandlers(getReturnValueHandlers(context));
    handlerMethod.setParameterNameDiscoverer(new DefaultParameterNameDiscoverer());

    MockHttpServletRequest request = new MockHttpServletRequest();
    MockHttpServletResponse response = new MockHttpServletResponse();

    handlerMethod.invokeAndHandle(new ServletWebRequest(request, response), new ModelAndViewContainer());

    System.out.println("\033[37;7m>>>>>> " + new String(response.getContentAsByteArray(), StandardCharsets.UTF_8) + " <<<<<<\033[0m");
    context.close();

  }

  public static HandlerMethodArgumentResolverComposite getArgumentResolvers(AnnotationConfigApplicationContext context){
    HandlerMethodArgumentResolverComposite composite = new HandlerMethodArgumentResolverComposite();
    composite.addResolvers(
      new RequestParamMethodArgumentResolver(context.getDefaultListableBeanFactory(), false),
      new PathVariableMethodArgumentResolver(),
      new RequestHeaderMethodArgumentResolver(context.getDefaultListableBeanFactory()),
      new ServletCookieValueMethodArgumentResolver(context.getDefaultListableBeanFactory()),
      new ExpressionValueMethodArgumentResolver(context.getDefaultListableBeanFactory()),
      new ServletRequestMethodArgumentResolver(),
      new ServletModelAttributeMethodProcessor(false),
      new RequestResponseBodyMethodProcessor(List.of(new MappingJackson2HttpMessageConverter())),
      new ServletModelAttributeMethodProcessor(true),
      new RequestParamMethodArgumentResolver(context.getDefaultListableBeanFactory(), true)
    );
    return composite;
  }

  public static HandlerMethodReturnValueHandlerComposite getReturnValueHandlers(AnnotationConfigApplicationContext context){
    // 添加 advice
    List<ControllerAdviceBean> annotatedBeans = ControllerAdviceBean.findAnnotatedBeans(context);
    List<Object> collect = annotatedBeans.stream().filter(b -> ResponseBodyAdvice.class.isAssignableFrom(b.getBeanType()))
      .collect(Collectors.toList());

    HandlerMethodReturnValueHandlerComposite composite = new HandlerMethodReturnValueHandlerComposite();
    composite.addHandler(new ModelAndViewMethodReturnValueHandler());
    composite.addHandler(new ViewNameMethodReturnValueHandler());
    composite.addHandler(new ServletModelAttributeMethodProcessor(false));
    composite.addHandler(new HttpEntityMethodProcessor(List.of(new MappingJackson2HttpMessageConverter())));
    composite.addHandler(new HttpHeadersReturnValueHandler());
    composite.addHandler(new RequestResponseBodyMethodProcessor(List.of(new MappingJackson2HttpMessageConverter()), collect));
    composite.addHandler(new ServletModelAttributeMethodProcessor(true));
    return composite;
  }
}
复制代码

 

posted @   ascertain  阅读(149)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
历史上的今天:
2020-06-01 miscellanea
点击右上角即可分享
微信分享提示