优秀的编程知识分享平台

网站首页 > 技术文章 正文

SpringBoot技术实践-全局接口(Controller)返回值格式统一

nanyue 2024-12-25 14:41:34 技术文章 3 ℃

一、返回值格式统一

1.1 返回值介绍

  1. 在使用controller对外提供服务的时候,很多时候都需要统一返回值格式,例如
{
    "status": true,
    "message": null,
    "code": "200",
    "data": {
        "name": "json",
        "desc": "json返回值"
    }
}
  1. 如果不使用全局统一返回,就需要写一个工具类,然后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();
}
  1. 除了上述方法,可以对返回值进行统一处理,不需要对所有controller都使用一个返回值,controller只需要返回原始值,处理器会对返回值进行封装
  2. 同时也可以添加自定义注解,此注解用于忽略返回值封装,按照controller原始值返回

1.2 基础类功能

  1. org.springframework.web.method.support.HandlerMethodReturnValueHandler使用不同策略处理从调用处理程序方法的返回值策略处理顶层接口,自定义返回值格式需要实现此接口supportsReturnType:设置支持返回值类型handleReturnValue:处理返回值基础参数
  1. org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter请求映射处理适配,包含了参数、返回值处理器等信息HandlerMethodReturnValueHandlerComposite内部维护了HandlerMethodReturnValueHandler列表

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

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreResponseWrapper {
}
  1. org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor属于HandlerMethodReturnValueHandler子类主要功能是对请求和响应体的做处理的方法所有属于RequestResponseBodyMethodProcessor的子类都需要替换为自定义返回值处理
  2. 实现原理就是,在bean初始化的时候,获取到所有处理器数组,然后将所有是RequestResponseBodyMethodProcessor处理器子类对返回值处理的过程替换为自定义处理器处理
  3. 这样当调用对应返回值处理器时,将会使用到自定义的返回值处理器,也就是所有返回值都会按照规定的进行处理

1.3 基础实现

  1. 创建普通springboot项目,项目创建在此不做说明
  2. 创建类实现HandlerMethodReturnValueHandler接口,主要用于实现自定义返回值内容,不需要注入容器
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreResponseWrapper {
}
  1. 创建类实现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;
            }
        }
    }
}
  1. 创建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;
    }
}

1.4 测试信息

  1. 测试json(有封装)
{
    "status": true,
    "message": null,
    "code": "200",
    "data": {
        "name": "json",
        "desc": "json返回值"
    }
}
  1. 测试map(无封装)
{
    "name": "map",
    "desc": "map返回值"
}
  1. 别的方法测试一样

二、附录说明

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

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



最近发表
标签列表