HandlerMethodReturnValueHandler 实现api返回统一格式

1. 场景

在springmvc 的controller需要统一的返回接口,比如:需要在后台所有接口返回统一的json字符串。可以通过自定义注解,通过 HandlerMethodReturnValueHandler 对返回值的处理,该接口会在返回值之前,执行该接口的内部逻辑。

假设现在想返回一个接送字符串。格式:

{

status: 200

code : success

data :{

 age: 100,

 name : 小明

}

}

1. 创建返回结果类


public class ResponseResult<T> {

public Integer status;

    public String code;

    public   T data;

//  构造 setter...

}

1. 创建一个返回结果的自定义注解包装类:


public @Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface ResponseJson{

    public String className() default "ResponseResult"; // 全路径名

}

2. 定义controller 逻辑,假设有如下一个接口,我们需要对返回值进行包装成ResponseResulltJson结构,加上自定义注解。


@ResponseResulltJson

@GetMapping(“/test”)

public Student test(@RequestParam(value="name") String name){

      // 处理逻辑
     Student  student  = new Student();

    student.setName(name);

   return student;

}
  1. 创建HandlerMethodReturnValueHandler接口实现类,下面的o就是上面test接口的返回值。

public class ExampleHandler implements HandlerMethodReturnValueHandler {

    @Override

    publicboolean supportsReturnType(MethodParameter methodParameter) {

        return methodParameter.hasMethodAnnotation(ResponseJson.class);

    }

    @Override

    public void  handleReturnValue(Object o, MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,

NativeWebRequest nativeWebRequest)throws Exception {

    HttpServletResponse response = 
        nativeWebRequest.getNativeResponse(HttpServletResponse.class);

    response.setConentTpye(MediaType.APPLICATION_JSON_VALUE);

    response.setCharactrer("UTF-8");

    ResponseJson json = methodParameter.getAnnation(ResponseJson .class);

// 得到需要反射类对象,即结果类

    Class responseResult= json.className();

// 通过反射从构造放入注入,需要注意,通过构造器注入的参数和newInstance传入的必须一致。 

    Object rp = Class.forName(responseResult).getConstrtor(Object.class).newInstance(o);

// 通过guava中Gson来json化,或者FastJson

    Gson gson = new GSon();

    response.getWriter().write(gson.toJson(rp));

}

}

4. 把上面的的handler添加进RequestMappingHandlerAdapter适配器中

public class   RequestMappingHandlerAdapterWrapper{

    @Autowired

    private RequestMappingHandlerAdapter handlerAdapter;

    @PostConstruct

    public void register(){

                handlerAdapter.setReturnValueHandlers(new ArrayList<RequestMappingHandlerAdapter >({{

                this.add(new ExampleHandler ());

                this.addAll(RequestMappingHandlerAdapterWrapper.this.handlerAdapter.[getReturnValueHandlers](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.html#getReturnValueHandlers--)());

    }}))

}

}

为什么上面这样写就可以在Controller中的返回结果调用到这个处理器。
在RequestMappingHandlerAdapter中实现了InitializingBean这个接口,该接口具有唯一的函数AfterPropertiesSet(),意思是在容器启动时,会调用这个方法,该方法主要设置了一些默认的handlers,在初始化方法中主要有三种,@PostContruct、xml的init-method,实现InitalizingBean接口。这三种的执行顺序时@PostContruct、InitalizingBean、init-method,因此上面的register会先于AfterPropertiesSet方法执行,自然可以在设置默认的handler时起作用。

Data:2019/3/10

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容