SpringBoot Web开发-响应体响应数据并统一接口返回格式

1,690 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

前言

本篇文章主要介绍 SpringBoot进行前后端开发时,如何返回json 格式数据以及统一接口的返回格式 。希望观众老爷们多多支持,请在评论区批评指正!

无论是 RestFul风格还是之前 web阶段接触过的异步请求,都需要把数据转换成 json放入到响应体中。

1. 数据放到响应体

我们的 SpringMVC为我们提供了 @ResponseBody注解,@ResponseBody注解标注在类或者方法上:标志在类上,则这个类中的所有请求方法返回的数据都为被 SpringMVC封装为 json格式的数据放到响应体中;标注在方法上,那么该方法返回的数据会被封装为 json格式的数据放到响应体中。

当然如果想要将 Controller层请求方法,默认返回数据都封装 json格式,放到响应体中。那么我们可以使用 @RestController注解,这个注解是 @Controller@ResponseBody注解的结合体,具有相同的作用,该注解只能标志在类上。

2. 数据如何转换为 json

前面的文章提到过,在我们使用 SSM 进行开发的时候,如果想要 SpringMVC帮我们把 json数据转换成我们需要的类型。这时候我们需要进行一些基本配置。SpringMVC默认使用 jackson来进行 json的解析,那么我们就需要导入 jackson的依赖。并且开启注解驱动。

但是我们使用 SpringBoot进行开发时,当我们引入 spring-boot-starter-web场景启动器后,该场景中就包含了 jackson依赖,不需要再额外导入,并且默认开启了注解扫描驱动。

所以说当我们的 Controller层的请求方法,需要将数据放到响应体中进行返回,只需要将数据作为方法的返回值进行返回即可,SpringMVC会自动将数据封装为 json格式放到响应体中。前提是类上或具体的请求方法上标志了 @ResponseBody注解及其相关注解 @RestController

@Controller
@RequestMapping("/user/")
public class HelloController {

    @RequestMapping(value="/hi"})
    @ResponseBody
    public List<String> hello(){
        List<String> list = new ArrayList<>();
        list.add("hi");
        return list;
    }
}

3. 封装统一的接口响应格式

在我们进行前后端分离项目开发的时候,后端服务提供 API,前端发送 http请求,来进行数据交互的。

前面的我们进行返回数据的时候,我们是随意返回的,没有状态码和提示,不利于前后端接口的对接。

那么我们可以创建一个类:用于对返回的数据封装为统一的响应格式。

/**
 * @param <T> T 返回的数据类型泛型
 * @JsonInclude(JsonInclude.Include.NON_NULL) 对象返回的字段中为null(空)的字段不进行序列化,也就是不会显示到响应体中
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseResult<T> {

    /**
     * 状态码
     */
    private Integer code;

    /**
     * 提示信息,如果有错误时,前端可以获取该字段进行提示
     */
    private String msg;

    /**
     * 返回的结果数据
     */
    private T data;

    private ResponseResult() {

    }

    public ResponseResult(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public ResponseResult(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer 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;
    }

}

当然我们也可以对常见的状态进行封装,如成功、失败、参数无效、无权限访问等。我们可以创建一个枚举类来完成:

public enum ResultCode {
    /**
     * 通用状态码
     */
    SUCCESS(1,"OK"),
    FAILED(-1,"FAIL"),
    /*
    参数错误状态码
     */
    PARAM_IS_INVAlID(101,"参数无效"),
    PARAM_IS_BLANK(101,"参数为空"),
    /* 用户错误  201 - 299  */
    USER_NOT_LOGIN(201,"未登录"),
    USER_NOT_EXIST(202,"用户不存在"),
    USER_LOGIN_ERROR(203,"登陆失败,账号或者密码有误"),
    NOT_PERMISSION(204,"无权限访问"),
    /* 业务错误 301 - 399*/
    DATA_NOT_FOUND(301,"没有数据");

    //返回状态码
    private Integer code;

    //返回消息
    private String msg;

    private ResultCode() {
    
    }
    
    ResultCode(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

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

    public String getMsg() {
        return msg;
    }

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

这个时候我们需要在 ResponseResult添加新的方法来完成对常见状态枚举类(ResultCode)的对接。

public static <T> ResponseResult<T> setCommonStatusAndData(ResultCode resultCode, T data){
    return new ResponseResult<>(resultCode.getCode(), resultCode.getMsg(),data);
}

public static ResponseResult setCommonStatusNoData(ResultCode resultCode){
    return new ResponseResult<>(resultCode.getCode(), resultCode.getMsg());
}

下面进行测试:

  1. 使用 ResponseResult类的构造方法返回一个响应格式
@Controller
@RequestMapping("/user/")
public class HelloController {
	
    @GetMapping("/{id}/{username}")
    @ResponseBody
    public ResponseResult<User> getUserOneInfoByIdAndUsername(@PathVariable("id") Integer id, @PathVariable("username") String username){
        User user = new User();
        user.setId(id);
        user.setName(username);
        return new ResponseResult<>(1, "OK", user);
    }

}

然后我们使用 apifox进行测试:

  1. 使用枚举类封装的常用状态快速返回
@GetMapping("/{id}/{username}")
@ResponseBody
public ResponseResult<User> getUserOneInfoByIdAndUsername(@PathVariable("id") Integer id, @PathVariable("username") String username){
    User user = new User();
    user.setId(id);
    user.setName(username);
    return ResponseResult.setCommonStatusAndData(ResultCode.SUCCESS,user);
}

4. 为什么要统一响应格式

当我们前端发送一个请求,后端服务接口返回数据后,有统一的返回格式 code,msg,data;当前端拿到响应数据后 res.data是返回的响应体,先判断 res.data.code状态码是否成功,如果成功进行一些处理,如果失败,就可以通过 msg来获取提示信息再进行处理。

这样做可以指定统一的接口规范,有利于前后端的交互。