springboot接口返回封装与异常控制
首先,返回有两个状态,status和code
status标识response的状态,有2个值:0成功,-1服务错误。
code跟业务有关,可以有各种数值,99999服务未知异常,10000参数异常,100001创建订单失败等等。这两个状态用枚举类表示。
ResponseStatus
/** * @Author: ivan * @Description: 服务状态代码 * @Date: 18/11/26 * @Modified By; */ public enum ResponseStatus { OK(0, "成功"), ERROR(-1, "服务错误"); private int value; private String message; ResponseStatus(int value, String message){ this.value = value; this.message = message; } public int getValue() { return value; } public String getMessage() { return message; } }
ResponseCode
/** * @Author: ivan * @Description: 业务状态代码 * @Date: 18/11/26 * @Modified By; */ public enum ResponseCode { FORMAL(0, "业务正常"), INVALID_PARAM(100000, "参数错误"), UNKNOWN_FAILED(999999, "服务器未知错误"), SAVE_FAILED(888888, "保存失败"), UPDATE_FAILED(777777, "保存失败"), DELTE_FAILED(666666, "删除失败"), SEARCH_FLOW_FAILED(555555, "查询任务流的执行详情失败!"); private int value; private String message; ResponseCode(int value, String message){ this.value = value; this.message = message; } public int getValue() { return value; } public String getMessage() { return message; } }
然后,是Response类,简单工厂模式,提供build方法,创建正常返回和错误返回Response。
Response
/** * @Author: ivan * @Description: 返回值封装 * @Date: Created in 17:26 18/11/26 * @Modified By: */ public class Response<T> implements Serializable { private int status; private int code; private String message; private Object data; public Response(ResponseStatus status, ResponseCode code, String message, T data) { this.setStatus(status); this.setCode(code); this.setMessage(message); this.setData(data); } public static <T> Response<T> buildSuccessResponse(T data) { return new Response<T>(ResponseStatus.OK, ResponseCode.FORMAL, null, data); } public static <T> Response<T> buildFailResponse(ResponseStatus responseStatus, ResponseCode responseCode, String message, T data) { return new Response<T>(responseStatus, responseCode, message, data); } public int getStatus() { return status; } public void setStatus(ResponseStatus status) { this.status = status.getValue(); } public int getCode() { return code; } public void setCode(ResponseCode code) { this.code = code.getValue(); } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } }
如果不想在controller里try-catch一般的异常,并且在一定的条件下通过throw控制代码逻辑,我们需要建立ControllerAdvice。
我这个advice会捕捉ApiException(自定义),一般用业务Code码里的错误码和信息,这时候我们可以返回提示性异常。然后就是Exception普通异常,一般提示服务器未知错误。
我这里还处理了一个参数校验异常
/** * @Author: ivan * @Description: 全局异常处理advice * @Date: Created in 20:21 18/11/26 * @Modified By: */ @ControllerAdvice public class GlobalExceptionHandler { private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 处理全局异常handler, ApiException为业务异常, 其他为服务器未知异常 */ @ExceptionHandler(Exception.class) @ResponseBody public Response<String> handle(Exception e) { Response<String> response; if (e instanceof ApiException) { ApiException error = (ApiException) e; response = Response.buildFailResponse(ResponseStatus.ERROR, error.getResponseCode(), error.getResponseCode().getMessage(), null); } else { response = Response.buildFailResponse(ResponseStatus.ERROR, ResponseCode.UNKNOWN_FAILED, ResponseCode.UNKNOWN_FAILED.getMessage(), null); } logger.error("[Exception] message={}", e); return response; } /** * 处理参数校验异常handler */ @ExceptionHandler(ValidationException.class) @ResponseBody public Response<String> handle(ValidationException e) { StringBuilder sb = new StringBuilder(); if(e instanceof ConstraintViolationException){ ConstraintViolationException error = (ConstraintViolationException) e; Set<ConstraintViolation<?>> violations = error.getConstraintViolations(); for (ConstraintViolation<?> item : violations) { sb.append(item.getMessage()); } } logger.error("[Validation] message={}", sb.toString(), e); return Response.buildFailResponse(ResponseStatus.ERROR, ResponseCode.INVALID_PARAM, sb.toString(), null); } }