为什么要统一返回值
在我们做前后端应用的时候 , 前后端分离的情况下 , 我们经常会定义一个数据格式,通常会包含code , message, data 这三个不可少的信息来方便我们的交流
创建Result 来包装我的数据
@Data
public class Result {
private Integer code;
private String message;
private Object data;
}
创建测试Controller
@RestController
public class TestController {
@GetMapping("test")
public Result test(){
Map<String, Object> map = new HashMap<>();
map.put("test",2 );
Result result = new Result();
result.setCode(200);
result.setMessage("成功");
result.setData(map);
return result;
}
}
请求 /test 返回结果如下
{
"code": 200,
"message": "成功",
"data": {
"test": 2
}
}
这样写没什么问题 , 但是我们需要在每个方法中都这样写、这样比较繁琐,我们把Result 类重构下
@Data
public class Result {
private Integer code;
private String message;
private Object data;
public Result(Integer code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}
public static Result success() {
return new Result(200,"成功",null);
}
public static Result success(Object data) {
return new Result(200,"成功",data);
}
public static Result error() {
return new Result(201,"失败");
}
}
重构Controller
@RestController
public class TestController {
@GetMapping("test")
public Result test(){
Map<String, Object> map = new HashMap<>();
map.put("test",2 );
return Result.success(map);
}
}
访问
{
"code": 200,
"message": "成功",
"data": {
"test": 2
}
}
结果是一样的,但是controller中的代码量变少了 ,到这里我们发现 code都是直接定义的没有一个统一管理的地方
我们新建一个 ResultCode 来管理所有结果码和对应的信息
@Getter
public enum ResultCode {
//成功返回结果
SERVICE_OK(200,"成功!"),
//返回失败结果
SERVICE_ERR(201,"失败");
private String msg;
private int code;
ResultCode(int code, String msg){
this.code = code;
this.msg = msg;
}
}
在重构下Result
@Data
public class Result {
private Integer code;
private String message;
private Object data;
public Result() {
}
public Result(ResultCode apiCode, Object data) {
this.code = apiCode.getCode();
this.message = apiCode.getMsg();
this.data = data;
}
public Result(ResultCode apiCode) {
this.code = apiCode.getCode();
this.message = apiCode.getMsg();
}
public static Result success() {
return new Result(ResultCode.SERVICE_OK);
}
public static Result success(Object data) {
return new Result(ResultCode.SERVICE_OK, data);
}
public static Result error(ResultCode apiCode) {
return new Result(apiCode);
}
}
重构Controller
@RestController
public class TestController {
@GetMapping("test")
public Result test(){
Map<String, Object> map = new HashMap<>();
map.put("test",2 );
return Result.success(map);
}
@GetMapping("test2")
public Result test2(){
return Result.error(ResultCode.SERVICE_ERR);
}
}
访问 /test
{
"code": 200,
"message": "成功!",
"data": {
"test": 2
}
}
访问/test2
{
"code": 201,
"message": "失败",
"data": null
}
到这里感觉大功告成了 , 其实不然,请看如下代码
@RestController
public class TestController {
@GetMapping("test")
public Result test(){
Map<String, Object> map = new HashMap<>();
map.put("test",2 );
return Result.success(map);
}
@GetMapping("test2")
public Result test2(){
Integer.parseInt("sdf1");
return Result.error(ResultCode.SERVICE_ERR);
}
}
访问/test2
我们用 Integer.parseInt("sdf1"); 来模拟开发中service 的异常。 当然我们可以使用try{}catch 来把异常拦截掉。每个Controller的方法都需要 try catch 代码重复率其实很高的,也不方便后期维护。
要解决这个问题就需要使用我们今天的主角了@ControllerAdvice
首先新建 ResultException 自定义异常
@ControllerAdvice
public class ExceptionHandle {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e) {
if (e instanceof ResultException) {
ResultException resultException = (ResultException) e;
return Result.error(resultException.getResultCode());
}else {
return Result.error(ResultCode.SERVICE_ERR);
}
}
}
新建 ExceptionHandle
@ControllerAdvice
public class ExceptionHandle {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e) {
if (e instanceof ResultException) {
ResultException resultException = (ResultException) e;
return Result.error(resultException.getResultCode());
}else {
return Result.error(ResultCode.SERVICE_ERR);
}
}
}
我们在把Controller 重构下
@GetMapping("test2")
public Result test2(){
Integer.parseInt("sdf1");
return null;
}
请求/test2
{
"code": 201,
"message": "失败",
"data": null
}
我们看到结果 统一异常拦截器把我们的异常拦截返回了我们统一封装类信息
我们在把Controller 重构下
@RestController
public class TestController {
@GetMapping("test2")
public Result test2(){
throw new ResultException(ResultCode.SERVICE_ERR);
}
}
这次我们主动把异常抛出,指定我们的状态码
{
"code": 201,
"message": "失败",
"data": null
}