对于的编程艺术家来说,我们要将优雅进行到底,像上一节介绍的情况,我们不可能只是单纯的返回一个错误字符串的,我们应该要告诉前端这次请求是否成功了,成功了才能够获取到真正的信息,错误了就显示我们提示的信息。
再开讲前,为了让我们能懒到底,这里介绍一个插件lombok。
Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法。
官网传送门
首先在pom.xml加入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
一般idea的最新版本都已经安装好了插件,如果没有安装只要搜索一下安装即可。
打开 preferences - Plugins
这样我们就安装好了这个插件,那么怎么配合一起用呢?
我们要养成一个习惯,就是对于不同的分层代码,我们最好能够创建一个新的包路径。
这里我们创建一个response包路径,并创建三个类文件,如下图。
Result类
package org.liurb.springboot.demo.response;
import lombok.Data;
/**
* 统一结果返回实体
*/
@Data
public class Result<T> {
//返回码
private Integer code;
//返回消息,一般是错误提示信息
private String msg;
//标记请求是否成功
private Boolean success;
//泛型数据
private T data;
}
这个类定义了统一结果返回的结构,一般由返回码、返回信息、成功与否标记、数据体组成。
数据体使用的是泛型的方式返回,即它可以支持任何的数据对象类型。如果大家对于泛型不太了解,可以看看 Java 泛型
相信大家也看到类上面的@Data注解,这个就是 lombok 插件提供的注解,加上这个注解,我们就可以偷懒不需要写成员变量的get/set方法,是不是很方便呢。
@Data 是 @Getter、 @Setter、 @ToString、 @EqualsAndHashCode 和 @RequiredArgsConstructor 的快捷方式。
其他的一些注解使用,可以到上面的官网查阅相关的资料。
ResultEnum类
package org.liurb.springboot.demo.response;
/**
* 统一返回信息枚举
*/
public enum ResultEnum {
/**
* 默认失败
*/
DEFAULT_FAIL(-99, "失败"),
/**
* 参数校验错误返回
*
*/
VALIDATION_ERROR(-2,"参数校验错误"),
/**
* 系统错误返回
*
*/
SYS_ERROR(-1,"系统错误"),
/**
* 成功返回
*/
SUCCESS(0,"成功"),
;
private Integer code;
private String msg;
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
这是一个枚举类,定义了不同场景下的返回码和错误信息。
ResultUtil类
package org.liurb.springboot.demo.response;
/**
* 统一结果返回帮助类
*/
public class ResultUtil {
/**
* 成功返回
*
* @param object
* @return
*/
public static Result success(Object object){
Result result = new Result();
result.setSuccess(true);
result.setCode(ResultEnum.SUCCESS.getCode());
result.setMsg(ResultEnum.SUCCESS.getMsg());
result.setData(object);
return result;
}
/**
* 成功但不带数据
*
* @return
*/
public static Result success(){
return success(null);
}
/**
* 默认失败返回
*
* @param msg
* @return
*/
public static Result fail(String msg) {
Result result = new Result();
result.setSuccess(false);
result.setCode(ResultEnum.DEFAULT_FAIL.getCode());
result.setMsg(msg);
return result;
}
/**
* 失败返回
*
* @param code
* @param msg
* @return
*/
public static Result fail(Integer code, String msg){
Result result = new Result();
result.setSuccess(false);
if (null == code) {
code = ResultEnum.DEFAULT_FAIL.getCode();
}
result.setCode(code);
result.setMsg(msg);
return result;
}
}
这里是一个工具类,主要是对统一结果结构的字段进行赋值。
接下来,我们看看怎么对之前的接口进行调整使用。
/**
* 提交学生信息
*
* @param studentDto
* @return
*/
@PutMapping("/student")
public Result student(@RequestBody @Valid StudentDto studentDto) {
//返回成功
return ResultUtil.success(studentDto);
}
我们将返回统一改为了Result类,返回的信息我们通过ResultUtil工具类进行了包装,传入的是一个泛型数据(StudentDto)
使用postman工具请求一下这个接口,看看返回的是什么。
可以看到,返回的结构发生了变化,而且比之前的规范多了,层级也比较清晰。这时候,前端开发人员就可以根据"success"判断,如果是"true",就能够获取data数据进行页面渲染了。
到这里,大家有没有发现,其实有一个地方,我们是不是漏了也需要调整的呢?
对的,就是统一异常处理类里面的返回。
package org.liurb.springboot.demo.exception;
import org.liurb.springboot.demo.response.Result;
import org.liurb.springboot.demo.response.ResultEnum;
import org.liurb.springboot.demo.response.ResultUtil;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
@RestControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result methodArgumentNotValidExceptionHandler(HttpServletRequest httpServletRequest, MethodArgumentNotValidException e) {
//打印第一条错误信息
String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
return ResultUtil.fail(ResultEnum.VALIDATION_ERROR.getCode(), message);
}
@ExceptionHandler(Exception.class)
public Result globalException(HttpServletRequest request, Exception e) {
String message = e.getMessage();
System.out.println("exception异常:" + message);
return ResultUtil.fail(ResultEnum.SYS_ERROR.getCode(), ResultEnum.SYS_ERROR.getMsg());
}
}
这里还使用到了ResultEnum统一返回信息枚举,并将一些错误信息返回给前端。
我们再使用postman模拟一下异常情况,将姓名字段设置为空。
这样是不是更加的规范了。前端开发人员判断到"success"字段返回的是false,则代表接口调用不成功,而且我们也使用了校验注解,同时接口也会带上我们标注的错误信息。
写在最后
接口的返回规则没有一个统一的标准,但是这个规范最好能够大家商议确定下来一个规范,那么大家就按照这个标准规范去返回相关的数据信息,就不要每个人都有自己的一套返回风格写法,要不然这样对于前端开发人员或者是后端的其他开发人员,都会带来很多磨合或者代码上的调整。