统一返回数据格式;保证后端返回前端的数据格式固定不变
介绍
为了保证接口的顺利开发,前端与后端一般都有约定的数据格式。
常见的web项目中,后端都会对返回给前端的数据进行一层封装,比如一个包含code,message,data这样的result对象。
import lombok.Data;
@Data
public class R<T> {
private Integer code;
//状态码:1成功,0失败
private String msg;
//错误信息
private T data;
//数据
public static <T> R<T> success(T object) {
R<T> r = new R<T>();
r.data = object;
r.code = 1;
return r;
}
public static <T> R<T> error(String msg) {
R<T> r = new R<T>();
r.msg = msg;
r.code = 0;
return r;
}
}
然后在controller层返回数据时都使用这个类,如此达到控制返回数据格式的目的。但还是要考虑其他情况(如下)
情况1-程序抛异常
如果你没有做异常捕获的处理的话,那么大概率出异常的时候返回前端的数据格式就不受控制了。这里我介绍我经常使用处理的方式
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author yang
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class)
public R<String> exceptionHandler(Exception e) {
log.error(e.getMessage());
return R.error(e.getMessage(),HttpCode.SERVER_ERROR);
}
}
使用注解@ControllerAdvice或@RestControllerAdvice配合注解@ExceptionHandler来定制要捕获的异常就能达到全局捕获异常的目的。这样的好处是既处理了数据返回格式不一致的问题又能减少很多try…catch代码。
情况2-请求路径找不到(404 error)
这是一种不常见的情况,它甚至不会抛异常,这种情况发送时,数据格式就又不受控制了。它会被springboot捕获并改为/error,然后由springboot返回一个默认的error处理。
{
"timestamp": "2023-04-18T06:14:37.966+00:00",
"status": 404,
"error": "Not Found",
"path": "/test_not_found"
}
很显然,这种数据不是我们想要返回的结果。那么要怎么做呢?
我使用的办法是在application.yml配置文件中添加springMVC的配置
spring:
mvc:
throw-exception-if-no-handler-found: true
web:
resources:
add-mappings: false
开启路径找不到时抛异常NoHandlerFoundException,并关闭静态资源映射。这样就可以被全局异常处理类捕获啦!
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author yang
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 捕获请求路径找不到的异常
* @param e NoHandlerFoundException
* @return Result<String>
*/
@ExceptionHandler(value = NoHandlerFoundException.class)
public R<String> noHandlerFoundException(NoHandlerFoundException e){
log.warn(e.getMessage());
return R.error(e.getMessage(),HttpCode.CLIENT_ERROR);
}
@ExceptionHandler(value = Exception.class)
public R<String> exceptionHandler(Exception e) {
log.error(e.getMessage());
return R.error(e.getMessage(),HttpCode.SERVER_ERROR);
}
}
再次请求不存在的路径:
{
"code": 404,
"msg": "No handler found for GET /test_not_found",
"data": null
}
很完美的解决了问题!
不过这种方法也是有缺点的,就是在前后端不分离的项目里不太友好,毕竟不能映射静态资源了嘛。
其他的方式比如可以在controller层加一个"/error"的Mapping,然后写个方法处理返回。这种方式我没怎么用过,所以具体的细节记不太清了。
其他
等我遇到了再回来更新。。