REST接口定义全局异常码以及异常信息

        在编写REST接口时,常常会抛出各种各样的异常,比如系统错误,请求参数不合法,没有权限,token检验未通过等等,这时如果直接抛出异常,不仅对使用者不友好,而且会暴露程序内部信息,这种做法是不可取的,程序可以对异常进行拦截,并进一步封装。同时,对于程序异常,如果有一整套异常码以及对应的异常信息,那么也非常便于排查异常。下面就来介绍一下基于拦截器实现全局异常拦截。

 

一、定义接口返回包装类BaseResponse

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseResponse implements Serializable {

    private int code;

    private String message;

    private T data;

    public BaseResponse(T data) {
        this.code = 0;
        this.data = data;
        this.message = "OK";
    }

    public BaseResponse(int code, String message) {
        this.code = code;
        this.message = message;
    }
}

 

二、定义全局异常类BizException

@Data
@EqualsAndHashCode(callSuper = true)
public class BizException extends RuntimeException {

    private int code;

    public BizException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public BizException(Integer code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

}

 

 三、定义全局异常码以及异常信息(异常码与异常信息视业务而定,这里只列举几个做示例)

public enum SystemEvent {

    /**
     * 异常类型及异常码定义
     */
    INVALID_PARAM(10000, "接口输入参数不合法"),

    SYSTEM_ERROR(10002, "系统异常,操作失败"),

    NOT_FOUND(10110, "没有找到数据"),

    PASSWORD_ERROR(10111,"用户名或密码错误"),

    INVALID_TOKEN(999999, "token无效");

    private Integer id;

    private String details;

    SystemEvent(Integer id, String details) {
        this.id = id;
        this.details = details;
    }


    public Integer getId() {
        return this.id;
    }


    public String getDetails() {
        return details;
    }

}

 

 四、定义全局异常拦截器

@ResponseBody
@ControllerAdvice(basePackages = "com.shuwei.userprofile.web.controller")
public class ExceptionInterceptor extends ResponseEntityExceptionHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionInterceptor.class);

    /**
     * Hibernate validate 失败的异常.
     */
    @Override
    protected ResponseEntity handleMethodArgumentNotValid(
            MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status,
            WebRequest request) {
        final BindingResult bindingResult = ex.getBindingResult();

        return ResponseEntity.badRequest().body(
                new BaseResponse<>(SystemEvent.INVALID_PARAM.getId(),
                        getErrors(bindingResult).toString()));
    }

    /**
     * Json格式错误异常.
     */
    @Override
    protected ResponseEntity handleHttpMessageNotReadable(
            HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status,
            WebRequest request) {

        String message = ex.getMessage();
        final Throwable cause = ex.getCause();
        if (cause != null) {
            message = message + "; Caused by:" + cause.getMessage();
        }
        return ResponseEntity.badRequest()
                .body(new BaseResponse<>(SystemEvent.INVALID_PARAM.getId(), message));
    }

    @Override
    protected ResponseEntity handleExceptionInternal(Exception exception, Object body,
                                                             HttpHeaders headers, HttpStatus status, WebRequest request) {
        SystemEvent event = SystemEvent.SYSTEM_ERROR;
        LOGGER.error(exception.getMessage(), exception);
        String msg = exception.getMessage() + "; Caused by: " + exception.getCause().getMessage();
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(new BaseResponse<>(event.getId(), msg));
    }

    /**
     * 业务主动失败异常. 所有抛出BizException都会被拦截.
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BizException.class)
    @ResponseBody
    public BaseResponse bizException(BizException exception) {
        return new BaseResponse<>(exception.getCode(), exception.getMessage());
    }


    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public BaseResponse otherException(Exception exception) {
        SystemEvent event = SystemEvent.SYSTEM_ERROR;
        LOGGER.error(exception.getMessage(), event, exception);
        String msg = exception.getMessage();
        if (exception.getCause() != null) {
            msg = msg + "; Caused by: " + exception.getCause().getMessage();
        }

        return new BaseResponse<>(event.getId(), msg);
    }


    private Map getErrors(BindingResult result) {

        return result.getFieldErrors().stream()
                .collect(Collectors.toMap(FieldError::getField,
                        DefaultMessageSourceResolvable::getDefaultMessage, (o1, o2) -> o1));
    }
}
 
  

 这样就实现了全局异常拦截,所有抛出的异常都会被这个拦截器拦截并进一步封装转化为异常码和异常信息,如下图:

REST接口定义全局异常码以及异常信息_第1张图片

 

你可能感兴趣的:(拦截器)