Spring Boot 统一定义Resutful接口输出结构


placeholder image
admin 发布于:2022-05-09 10:12:03
阅读:loading

背景介绍

在前面一篇文章《Spring Boot 定义公共结果集输出对象》时列举了Spring Boot内置的统一错误的JSON结构和阿里编码规范中提供的统一JSON结构,同时也提供了本站系统的统一结果集输出的对象类型和数据结构,本次将使用编码来的形式来接管全局的统一JSON格式输出,达到统一输出的目的,即无论在Controller中使用任何类型的返回值,均会被使用内置的输出类型进行包装输出。

在项目中也有实现HandlerMethodReturnValueHandler接口来统一接管Response响应输出的实现,本次提供本站博客系统的实现ResponseBodyAdvice接口来统一输出JSON结构(建站初期时的实现选型),详细介绍如下:

(1)使用@ControllerAdvice和@RestControllerAdvice处理@RestController和@ResponseBody的响应请求输出拦截;

(2)限制仅继承BaseController的类实现统一输出,不排除一些对外部提供接口时个性化输出定制场景;

参考代码

package cn.chendd.base.handler;

import cn.chendd.base.controller.BaseController;
import cn.chendd.base.result.BaseResult;
import cn.chendd.base.result.SuccessResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
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.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.awt.image.BufferedImage;
import java.lang.annotation.Annotation;

/**
 * Controller响应结果统一封装,也可以使用 @RestControllerAdvice 注解处理
 *
 * @author chendd
 * @date 2019/9/22 18:03
 */
@ControllerAdvice
@RestControllerAdvice
@Slf4j
public class HandlerResponseBodyAdvice implements ResponseBodyAdvice {

    /**
     * 必须规则:约定类继承了BaseController,表示为自定义模块
     * 可选规则:类被标记有@RestController
     * 可选规则:方法被标记有@Response
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        Class<?> containingClass = methodParameter.getContainingClass();
        Annotation restController = containingClass.getAnnotation(RestController.class);
        ResponseBody responseBody = methodParameter.getMethod().getAnnotation(ResponseBody.class);
        boolean rest = restController != null || responseBody != null;
        boolean custom = BaseController.class.isAssignableFrom(containingClass);
        return rest && custom;
    }

    @Override
    public Object beforeBodyWrite(Object value,
                                  MethodParameter methodParameter,
                                  MediaType mediaType,
                                  Class aClass, ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {
        if(value == null){
            return SuccessResult.build();
        }
        if(value instanceof BaseResult){
            return value;
        } else if(value instanceof BufferedImage) {
            return value;
        }
        return SuccessResult.build().data(value);
    }

}

注意事项

仅使用上述代码是满足大多数的响应结果输出,需要注意一些特殊场景的细节问题:

(1)当Controller方法返回String类型时会出现类型转换异常,即无法将String类型转换为系统统一的JSON数据类型BaseResult,解决方式是增加String类型的JSON转换器输出即可;

(2)当Controller方法返回为Object、JavaBean等类型时,若返回值为空时则系统统一的JSON输出不会生成期望的BaseResult数据结构,解决方式是设置默认的JSON组件的属性即可;

所以,上述问题的解决可参见项目代码示例的cn.chendd.base.spring.components.WebMvcRegistrationsConfig类。

源码下载

源码工程下载可转至https://gitee.com/88911006/chendd-blog-examples项目的HandlerResponse分支;


 点赞


 发表评论

当前回复:作者

 评论列表


留言区