SpringBoot全局Controller返回值格式统一

目录
  • 一、返回值格式统一
    • 1.返回值介绍
    • 2.基础类功能
    • 3.基础实现
  • 二、附录说明

一、返回值格式统一

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返回值格式统一内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解SpringBoot如何统一后端返回格式

    目录 为什么要对SpringBoot返回统一的标准格式 第一种:返回 String 第二种:返回自定义对象 第三种:接口异常 定义返回标准格式 高级实现方式 接口异常问题 SpringBoot为什么需要全局异常处理器 体验效果 全局异常接入返回的标准格式 今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常. 首先我们来看看为什么要返回统一的标准格式? 为什么要对SpringBoot返回统一的标准格式 在默认情况下,SpringB

  • SpringBoot全局Controller返回值格式统一

    目录 一.返回值格式统一 1.返回值介绍 2.基础类功能 3.基础实现 二.附录说明 一.返回值格式统一 1.返回值介绍 在使用controller对外提供服务的时候,很多时候都需要统一返回值格式,例如 { "status": true, "message": null, "code": "200", "data": { "name": "json", "d

  • 解析springboot包装controller返回值问题

    1.springboot项目统一包装返回值,通常返回结果包含code.message.data,结构如下 import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class ResponseResult<T> { private int code; private Strin

  • Spring MVC Controller返回值及异常的统一处理方法

    旧的设计方案 开发api的时候,需要先定义好接口的数据响应结果.如下是一个很简单直接的Controller实现方法及响应结果定义. @RestController @RequestMapping("/users") public class UserController { @Inject private UserService userService; @GetRequest("/{userId:\\d+}") public ResponseBean signin

  • 关于springboot的接口返回值统一标准格式

    目录 一.目标 二.为什么要对springboot的接口返回值统一标准格式? 第一种格式:response为String 第二种格式:response为Objct 第三种格式:response为void 第四种格式:response为异常 三.定义response的标准格式 四.初级程序员对response代码封装 步骤1:把标准格式转换为代码 步骤2:把状态码存在枚举类里面 步骤3:加一个体验类 五.高级程序员对response代码封装 步骤1:采用ResponseBodyAdvice技术来实

  • .NetCore Web Api 利用ActionFilterAttribute统一接口返回值格式及问题解析

    .Net Core 同 Asp.Net MVC一样有几种过滤器,这里不再赘述每个过滤器的执行顺序与作用. 在实际项目开发过程中,统一API返回值格式对前端或第三方调用将是非常必要的,在.NetCore中我们可以通过ActionFilterAttribute来进行统一返回值的封装. 在封装之前我们需要考虑下面几个问题: 1,需要对哪些结果进行封装 我目前的做法是,只对ObjectResult进行封装,其他的类型:FileResult,ContentResult,EmptyResult,Redire

  • SpringMVC Controller 返回值的可选类型详解

    spring mvc 支持如下的返回方式:ModelAndView, Model, ModelMap, Map,View, String, void. ModelAndView @RequestMapping("/hello") public ModelAndView helloWorld() { String message = "Hello World, Spring 3.x!"; return new ModelAndView("hello"

  • 详解利用SpringMVC拦截器控制Controller返回值

    背景:需求是在Controller中方法没有实现时,返回模拟结果.主要用于项目初期前台跟后台的交互,Web项目就是在前台发出请求然后后台响应并返回结果.本示例利用拦截器和注解实现跳过执行方法直接返回定义结构的功能. 通过定义一个StringResult注解,在访问方法的时候返回StringResult中的内容.通过Debug注解来定义方法是否要返回StringResult中的内容. Debug默认为TRUE package com.tiamaes.dep.annotation; import j

  • PHP中Restful api 错误提示返回值实现思路

    RESTful架构是一种流行的互联网软件架构,它结构清晰,符合标准,易于理解,扩展方便. REST是Representational State Transfer的缩写,翻译为"表现层状态转化".表现层其实就是资源,因此可以理解为"资源状态转化". 网络应用上的任何实体都可以看作是一种资源,通过一个URI(统一资源定位符)指向它. 序言 不管是微博还是淘宝,他们都有自己的错误返回值格式规范,以及错误代码说明,这样不但手机端用起来方便,给人的感觉也清晰明了,高大上.遇

  • java中有无参数和返回值的方法详解

    目录 java有无参数和返回值 以下的例子要细细查看 方法的返回值和参数 1.返回值 2.参数 java有无参数和返回值 首先,定义一个土豪类(LocalTyrant) 属性:name moeney smoke 行为一:(无参数无返回值): 行为二:(无参数有返回值): 行为三:(有参数有返回值): 行为四:(有参数无返回值): 以下的例子要细细查看 慢慢分析,切不可急于求成 package cm.tr; class LocalTyrant{ String name; int money; St

  • Spring Boot 捕捉全局异常 统一返回值的问题

    在前后端分离的情况下,我们经常会定义一个统一的反回数据格式,通常都会包含状态码,返回信息,返回的数据,是否成功等参数. 1.ResultCode 单独定义了一个ReturnCode枚举类用于存储代码和返回的Message public enum ResultCode { //成功 SUCCESS(200), // 失败 FAIL(400), // 未认证(签名错误) UNAUTHORIZED(401), // 接口不存在 NOT_FOUND(404), // 服务器内部错误 INTERNAL_S

随机推荐