SpringBoot Web开发-响应体响应数据并统一接口返回格式
前言
本篇文章主要介绍 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());
}
下面进行测试:
- 使用
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
进行测试:
- 使用枚举类封装的常用状态快速返回
@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
来获取提示信息再进行处理。
这样做可以指定统一的接口规范,有利于前后端的交互。
转载自:https://juejin.cn/post/7151721289848193032