SpringBoot全局Controller返回值格式统一

 更新时间:2021年7月30日 10:00  点击:1490

一、返回值格式统一

1.返回值介绍

在使用controller对外提供服务的时候,很多时候都需要统一返回值格式,例如

{
	"status": true,
	"message": null,
	"code": "200",
	"data": {
		"name": "json",
		"desc": "json返回值"
	}
}

如果不使用全局统一返回,就需要写一个工具类,然后controller返回对应的对象

@Data
public class ResponseData {
    private boolean status;
    private String message;
    private String code;
    private Object data;
}

@RequestMapping("/foo")
public ResponseData foo() {
    // 或者使用工具类返回,根据业务设置值
    return new ResponseData();
}

除了上述方法,可以对返回值进行统一处理,不需要对所有controller都使用一个返回值,controller只需要返回原始值,处理器会对返回值进行封装

同时也可以添加自定义注解,此注解用于忽略返回值封装,按照controller原始值返回

2.基础类功能

org.springframework.web.method.support.HandlerMethodReturnValueHandler

  • 使用不同策略处理从调用处理程序方法的返回值
  • 策略处理顶层接口,自定义返回值格式需要实现此接口
  • supportsReturnType:设置支持返回值类型
  • handleReturnValue:处理返回值基础参数

在这里插入图片描述

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

  • 请求映射处理适配,包含了参数、返回值处理器等信息
  • HandlerMethodReturnValueHandlerComposite内部维护了HandlerMethodReturnValueHandler列表

在这里插入图片描述在这里插入图片描述

可以自定义注解,用于类或者方法级别忽略返回值封装

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreResponseWrapper {

}

org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor

  • 属于HandlerMethodReturnValueHandler子类
  • 主要功能是对请求和响应体的做处理的方法
  • 所有属于RequestResponseBodyMethodProcessor的子类都需要替换为自定义返回值处理

实现原理就是,在bean初始化的时候,获取到所有处理器数组,然后将所有是RequestResponseBodyMethodProcessor处理器子类对返回值处理的过程替换为自定义处理器

处理这样当调用对应返回值处理器时,将会使用到自定义的返回值处理器,也就是所有返回值都会按照规定的进行处理

3.基础实现

创建普通springboot项目,项目创建在此不做说明

创建类实现HandlerMethodReturnValueHandler接口,主要用于实现自定义返回值内容,不需要注入容器

import com.codecoord.unifyreturn.annotation.IgnoreResponseWrapper;
import com.codecoord.unifyreturn.domain.ResponseBase;
import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;

public class ResponseBodyWrapHandler implements HandlerMethodReturnValueHandler {
    private final HandlerMethodReturnValueHandler delegate;

    public ResponseBodyWrapHandler(HandlerMethodReturnValueHandler delegate) {
        this.delegate = delegate;
    }

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return delegate.supportsReturnType(returnType);
    }

    @Override
    public void handleReturnValue(Object returnValue,
                                  MethodParameter returnType,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest) throws Exception {
        // 如果类或者方法含有不包装注解则忽略包装
        IgnoreResponseWrapper wrapper = returnType.getDeclaringClass().getAnnotation(IgnoreResponseWrapper.class);
        if (wrapper != null) {
            delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
            return;
        }
        wrapper = returnType.getMethodAnnotation(IgnoreResponseWrapper.class);
        if (wrapper != null) {
            delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
            return;
        }
        
        // 自定义返回格式
        ResponseBase responseBase = new ResponseBase();
        responseBase.setStatus(true);
        responseBase.setCode("200");
        responseBase.setData(returnValue);
        delegate.handleReturnValue(responseBase, returnType, mavContainer, webRequest);
    }
}

创建类实现InitializingBean,在初始化时调用,需要注入到容器中,否则Spring无法管理

import java.util.ArrayList;
import java.util.List;

@Component
public class ResponseBodyWrapFactoryBean implements InitializingBean {
    private final RequestMappingHandlerAdapter adapter;

    @Autowired
    public ResponseBodyWrapFactoryBean(RequestMappingHandlerAdapter adapter) {
        this.adapter = adapter;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        List<HandlerMethodReturnValueHandler> returnValueHandlers = adapter.getReturnValueHandlers();
        if (returnValueHandlers.size() > 0) {
        	// 将内置的返回值处理器进行替换
            List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(returnValueHandlers);
            decorateHandlers(handlers);
            adapter.setReturnValueHandlers(handlers);
        }
    }

    /** 
     * 将所有RequestResponseBodyMethodProcessor返回值处理器替换为自定义的返回值处理器
     *
     * @author tianxincode@163.com
     * @since 2020/10/12
     */
    private void decorateHandlers(List<HandlerMethodReturnValueHandler> handlers) {
        for (HandlerMethodReturnValueHandler handler : handlers) {
            if (handler instanceof RequestResponseBodyMethodProcessor) {
            	// 替换为自定义返回值处理器
                ResponseBodyWrapHandler decorator = new ResponseBodyWrapHandler(handler);
                int index = handlers.indexOf(handler);
                handlers.set(index, decorator);
                break;
            }
        }
    }
}

创建controller信息,例如此处map不需要封装,按照原来格式响应

@RestController
@RequestMapping("/unify")
public class UnifyReturnValueController {

    @RequestMapping("string")
    public String stringHandler(){
        return "接收成功了";
    }

    @RequestMapping("/json")
    public JSONObject jsonHandler(){
        JSONObject object = new JSONObject();
        object.put("name", "json");
        object.put("desc", "json返回值");
        return object;
    }

    @RequestMapping("/map")
    @IgnoreResponseWrapper
    public Map<String, Object> mapHandler(){
        Map<String, Object> map = new HashMap<>(10);
        map.put("name", "map");
        map.put("desc", "map返回值");
        return map;
    }

    @RequestMapping("/list")
    public List<Object> listHandler(){
        List<Object> data = new ArrayList<>();
        data.add(100);
        data.add(95);
        data.add(99);
        return data;
    }
}

4.测试信息 测试json(有封装)

{
	"status": true,
	"message": null,
	"code": "200",
	"data": {
		"name": "json",
		"desc": "json返回值"
	}
}

测试map(无封装)

{
	"name": "map",
	"desc": "map返回值"
}

别的方法测试一样

二、附录说明

项目结构参考红框部分,别的忽略

在这里插入图片描述

除了对返回值进行全局统一,也可以对异常进行全局处理和按照统一格式返回

到此这篇关于SpringBoot全局Controller返回值格式统一的文章就介绍到这了,更多相关SpringBoot返回值格式统一内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • 解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题

    这篇文章主要介绍了解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-28
  • mybatis-plus 返回部分字段的解决方式

    这篇文章主要介绍了mybatis-plus 返回部分字段的解决方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-02
  • Json格式详解

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。JSON采用完全独立于语言的文本格式,这些特性使JSON成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成...2021-11-05
  • SpringBoot实现excel文件生成和下载

    这篇文章主要为大家详细介绍了SpringBoot实现excel文件生成和下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-09
  • 详解springBoot启动时找不到或无法加载主类解决办法

    这篇文章主要介绍了详解springBoot启动时找不到或无法加载主类解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-16
  • SpringBoot集成Redis实现消息队列的方法

    这篇文章主要介绍了SpringBoot集成Redis实现消息队列的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-10
  • 解决Springboot get请求是参数过长的情况

    这篇文章主要介绍了解决Springboot get请求是参数过长的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17
  • SQLMAP结合Meterpreter实现注入渗透返回shell

    sqlmap 是一个自动SQL 射入工具。它是可胜任执行一个广泛的数据库管理系统后端指印, 检索遥远的DBMS 数据库等,下面我们来看一个学习例子。 自己搭建一个PHP+MYSQ...2016-11-25
  • Spring Boot项目@RestController使用重定向redirect方式

    这篇文章主要介绍了Spring Boot项目@RestController使用重定向redirect方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-02
  • Springboot+TCP监听服务器搭建过程图解

    这篇文章主要介绍了Springboot+TCP监听服务器搭建过程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-10-28
  • springBoot 项目排除数据库启动方式

    这篇文章主要介绍了springBoot 项目排除数据库启动方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-10
  • php实例分享之html转为rtf格式

    核心代码: 复制代码 代码如下:<!--?php$html2RTFCom = new COM("HTML2RTF.Converter");$html2RTFCom--->PreserveImages = true;$html2RTFCom->PageNumbers = 1;$html2RTFCom->PageNumbersAlignH = 1;$html2RTFCom->Pa...2014-06-07
  • springboot中使用@Transactional注解事物不生效的坑

    这篇文章主要介绍了springboot中使用@Transactional注解事物不生效的原因,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-26
  • 详解SpringBoot之访问静态资源(webapp...)

    这篇文章主要介绍了详解SpringBoot之访问静态资源(webapp...),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-14
  • SpringBoot接口接收json参数解析

    这篇文章主要介绍了SpringBoot接口接收json参数解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-19
  • Pycharm 设置默认解释器路径和编码格式的操作

    这篇文章主要介绍了Pycharm 设置默认解释器路径和编码格式的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
  • springboot多模块包扫描问题的解决方法

    这篇文章主要介绍了springboot多模块包扫描问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-16
  • Springboot mybatis plus druid多数据源解决方案 dynamic-datasource的使用详解

    这篇文章主要介绍了Springboot mybatis plus druid多数据源解决方案 dynamic-datasource的使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-11-18
  • nestjs返回给前端数据格式的封装实现

    这篇文章主要介绍了nestjs返回给前端数据格式的封装实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-22
  • Springboot实现多线程注入bean的工具类操作

    这篇文章主要介绍了Springboot实现多线程注入bean的工具类操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-27