一、前言

在Web开发中,我们常常需要对API接口的返回结果进行统一的包装,以方便客户端对数据和异常情况的统一处理。我们可以自定义返回接口结果包装类。

二、创建返回结果枚举类

package com.example.hellodemo.enums;

/**
 * @author qx
 * @date 2023/11/30
 * @des 返回结果枚举类
 */
public enum ResultTypeEnum {
    SUCCESS(0, "成功"), FAILURE(1, "失败");

    private final int code;
    private final String msg;

    ResultTypeEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

三、定义统一返回结果类

package com.example.hellodemo.bean;

import com.example.hellodemo.enums.ResultTypeEnum;

import java.io.Serializable;

/**
 * @author qx
 * @date 2023/11/30
 * @des 统一返回结果类
 */
public class ResultResponse<T> implements Serializable {


    private int code;

    private String msg;

    private T data;

    public ResultResponse(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public static <T> ResultResponse success() {
        return new ResultResponse(ResultTypeEnum.SUCCESS.getCode(), ResultTypeEnum.SUCCESS.getMsg(), null);
    }

    public static <T> ResultResponse success(T data) {
        return new ResultResponse(ResultTypeEnum.SUCCESS.getCode(), ResultTypeEnum.SUCCESS.getMsg(), data);
    }

    public static <T> ResultResponse success(String msg, T data) {
        return new ResultResponse(ResultTypeEnum.SUCCESS.getCode(), msg, data);
    }

    public static ResultResponse failure() {
        return new ResultResponse(ResultTypeEnum.FAILURE.getCode(), ResultTypeEnum.FAILURE.getMsg(), null);
    }

    public static ResultResponse failure(String msg) {
        return new ResultResponse(ResultTypeEnum.FAILURE.getCode(), msg, null);
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

四、创建控制器

package com.example.hellodemo.controller;

import com.example.hellodemo.bean.ResultResponse;
import com.example.hellodemo.bean.one.DbOneEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;


/**
 * @author qx
 * @date 2023/11/30
 * @des
 */
@RestController
public class DbController {

    @PostMapping("/test")
    public ResultResponse<Map<String, Object>> testDemo(@RequestParam String name, @RequestParam Integer id) {
        Map<String, Object> hashMap = new HashMap<>();
        hashMap.put("name", name);
        hashMap.put("id", id);
        return ResultResponse.success(hashMap);
    }
}

测试:

SpringBoot返回结果统一处理_返回结果

我们也可以返回自定义的msg。

package com.example.hellodemo.controller;

import com.example.hellodemo.bean.ResultResponse;
import com.example.hellodemo.bean.one.DbOneEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;


/**
 * @author qx
 * @date 2023/11/30
 * @des
 */
@RestController
public class DbController {

    @PostMapping("/test")
    public ResultResponse<Map<String, Object>> testDemo(@RequestParam String name, @RequestParam Integer id) {
        Map<String, Object> hashMap = new HashMap<>();
        hashMap.put("name", name);
        hashMap.put("id", id);
        return ResultResponse.success("获取数据成功",hashMap);
    }
}

测试:

SpringBoot返回结果统一处理_全局返回结果_02

五、全局异常统一返回类

package com.example.hellodemo.exception;

import com.example.hellodemo.bean.ResultResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @author qx
 * @date 2023/11/30
 * @des 全局异常统一返回处理类
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 捕获Exceptino异常类型
     *
     * @param e
     * @return 返回异常统一返回处理结果
     */
    @ExceptionHandler(value = {Exception.class})
    public ResultResponse exceptionHandler(Exception e) {
        return ResultResponse.failure(e.getMessage());
    }
}

我们在控制器中自己创建一个异常,然后请求接口,看看返回什么?

package com.example.hellodemo.controller;

import com.example.hellodemo.bean.ResultResponse;
import com.example.hellodemo.bean.one.DbOneEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;


/**
 * @author qx
 * @date 2023/11/30
 * @des
 */
@RestController
public class DbController {

    @PostMapping("/test")
    public ResultResponse<Map<String, Object>> testDemo(@RequestParam String name, @RequestParam Integer id) {
        Map<String, Object> hashMap = new HashMap<>();
        hashMap.put("name", name);
        hashMap.put("id", id);
        // 自己写一个异常
        int i = 1 / 0;
        return ResultResponse.success("获取数据成功", hashMap);
    }
}

测试:

SpringBoot返回结果统一处理_全局返回结果_03

我们看到msg已经返回了异常的相关信息。

六、Spring切面实现自动返回统一结果

package com.example.hellodemo.config;

import com.example.hellodemo.bean.ResultResponse;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * @author qx
 * @date 2023/11/30
 * @des 全局统一返回结果
 */
@RestControllerAdvice
public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // 要排除的api,里面的接口不需要统一包装
        String[] excludePath = {};
        for (String path : excludePath) {
            if (serverHttpRequest.getURI().getPath().startsWith(path)) {
                return body;
            }
        }
        if (body instanceof ResultResponse) {
            return body;
        }
        return ResultResponse.success(body);
    }
}

我们定义一个不带返回格式的控制器。

package com.example.hellodemo.controller;

import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;


/**
 * @author qx
 * @date 2023/11/30
 * @des
 */
@RestController
public class DbController {

    @PostMapping("/test")
    public Map<String, Object> testDemo(@RequestParam String name, @RequestParam Integer id) {
        Map<String, Object> hashMap = new HashMap<>();
        hashMap.put("name", name);
        hashMap.put("id", id);
        return hashMap;
    }
}

我们进行测试:

SpringBoot返回结果统一处理_返回结果_04

我们发现我们使用切面设置统一返回结果的封装成功了,这样就统一了返回格式,对代码没有侵入。

我们注意全局异常统一返回和切面使用统一返回结果都使用了一个注解@RestControllerAdvice。