springboot 优雅的实现统一返回处理
前言:随着前后端分离这种模式的趋势下,后端开发人员更注重后端方面的代码,但是对后端人员在代码编写的过程当中需要越来越规范,这样不仅可以提高开发效率,更可以让代码后期维护起来更加的方便。
这篇文章主要是当接口返回的统一处理,能够让前端人员有个统一的接收后台的接口返回。
1、自定义常用的状态码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
public enum ResultCode {
RC200(200, "操作成功"),
RC900(900, "操作失败"),
RC500(500, "系统异常,请稍后重试");
private final int code;
private final String message;
ResultCode(int code, String message) { this.code = code; this.message = message; }
public int getCode() { return code; }
public String getMessage() { return message; } }
|
当然可以定义定义一些其他状态码,可以让前端根据不同的状态码进行不同的处理,这里只定义部分常用状态码。
2、统一结果返回包装类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| package com.example.spring.response.constant;
import lombok.Data;
@Data public class ResultData<T> {
private int status;
private String message;
private T data;
public static <T> ResultData<T> success(T data) { ResultData<T> resultData = new ResultData<>(); resultData.setStatus(ResultCode.RC200.getCode()); resultData.setMessage(ResultCode.RC200.getMessage()); resultData.setData(data); return resultData; }
public static <T> ResultData<T> success() { ResultData<T> resultData = new ResultData<>(); resultData.setStatus(ResultCode.RC200.getCode()); resultData.setMessage(ResultCode.RC200.getMessage()); return resultData; }
public static <T> ResultData<T> fail(int code, String message) { ResultData<T> resultData = new ResultData<>(); resultData.setStatus(code); resultData.setMessage(message); return resultData; }
public static <T> ResultData<T> fail( String message) { ResultData<T> resultData = new ResultData<>(); resultData.setStatus(ResultCode.RC999.getCode()); resultData.setMessage(message); return resultData; }
}
|
这里只封装的部分方法,可以根据自己的实际需求封装不同方法。
写一个简单的请求demo
1 2 3 4
| @GetMapping("/getHi") public ResultData<String> getHi(){ return ResultData.success("hi"); }
|
返回结果
模拟一个服务器的异常
1 2 3 4 5
| @GetMapping("/getHi") public ResultData<String> getHi(){ int a = 1/0; return ResultData.success("hi"); }
|
结果
这种返回结果肯定不是前端开发人员想处理的,所以我们还要对服务端如果出现一个异常,也需要处理统一的返回格式。
3、自定义异常类,以及全局异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package com.example.spring.response.exception;
import com.example.spring.response.constant.ResultCode;
public class BizException extends RuntimeException {
public ResultCode resultCode;
public BizException(String message) { super(message); }
public BizException(ResultCode resultCode) { super(resultCode.getMessage()); this.resultCode = resultCode; }
@Override public String getMessage() { return super.getMessage(); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.example.spring.response.handler;
import com.example.spring.response.constant.ResultCode; import com.example.spring.response.constant.ResultData; import com.example.spring.response.exception.BizException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice;
@Slf4j @RestControllerAdvice public class RestExceptionHandler {
@ExceptionHandler(BizException.class) @ResponseStatus(HttpStatus.EXPECTATION_FAILED) public ResultData<String> exception(BizException e) { log.error("全局异常信息 e={}", e.getMessage(), e); return ResultData.fail(e.getMessage()); }
@ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ResultData<String> exception(Exception e) { log.error("全局异常信息 e={}", e.getMessage(), e); return ResultData.fail(ResultCode.RC500.getCode(),e.getMessage()); }
}
|
运行结果
能够正确的返回。
当时回头一想,统一处理但是每次返回结果的时候自己都得重复手动包装一下自定义的类,这样可以用代码来处理,所以下面实现自动包装返回的结果。
4、自定义自动包装统一返回类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package com.example.spring.response.handler;
import com.example.spring.response.constant.ResultData; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.SneakyThrows; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.MethodParameter; import org.springframework.core.io.Resource; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice<Object> { @Autowired private ObjectMapper objectMapper;
@Override public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) { return true; }
@SneakyThrows @Override public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { if (o instanceof String) { return objectMapper.writeValueAsString(ResultData.success(o)); } if (o instanceof ResultData || o instanceof Resource ) { return o; } return ResultData.success(o); } }
|
写个demo测试一下
1 2 3 4 5 6 7 8 9
| @GetMapping("getWorld") public Order getWorld(){ return new Order(1L,"购物车"); }
@GetMapping("/getError") public Order getError(){ throw new BizException("失败了"); }
|
返回结果:
这样就可以优雅的实现统一返回值的处理。
注意:
特别注意这个类的判断!!!