0%

springboot中异常全局统一处理

日常后端业务开发中,在提供接口服务时会遇到各种异常处理,通常涉及到参数校验异常、自定义异常以及一些不可预知的异常等等。下面就来说一下在springboot中如何在接口层进行全局性的异常处理。

全局异常处理

全局异常处理借用springmvc中的@ControllerAdvice注解来实现,当然在springboot中我们就用@RestControllerAdvice(内部包含@ControllerAdvice和@ResponseBody的特性)。此注解用来监听controller层抛出的异常,以至于让我们能进一步对异常做处理。

下面给出一个全局异常处理案例代码,涉及的有validaton注解校验的异常处理,自定义异常的处理,未知异常的处理。

注意:异常的handler域是由小至大的,所以有先后顺序。

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
package com.lazycece.sbac.exception.controller;

import com.lazycece.sbac.exception.exception.AbstractGlobalException;
import com.lazycece.sbac.exception.response.ResCode;
import com.lazycece.sbac.exception.response.ResMsg;
import com.lazycece.sbac.exception.response.ResponseData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.ServletException;


/**
* @author lazycece
* @date 2019/02/23
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

/**
* 参数校验错误异常
*
* @param e MethodArgumentNotValidException|BindException
* @return ResponseData
*/
@ExceptionHandler(value = {BindException.class, MethodArgumentNotValidException.class})
public ResponseData bindExceptionHandler(Exception e) {
BindingResult bindingResult;
if (e instanceof BindException) {
bindingResult = ((BindException) e).getBindingResult();
} else {
bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
}
StringBuilder stringBuilder = new StringBuilder();
bindingResult.getAllErrors().forEach(
objectError ->
stringBuilder.append(",").append(objectError.getDefaultMessage())
);
String errorMessage = stringBuilder.toString();
errorMessage = errorMessage.substring(1, errorMessage.length());
return ResponseData.builder().code(ResCode.FAIL).message(errorMessage).build();
}

/**
* 捕获自定义的统一全局异常
*
* @param e AbstractGlobalException
* @return ResponseData
*/
@ExceptionHandler(value = AbstractGlobalException.class)
public ResponseData customExceptionHandler(AbstractGlobalException e) {
return ResponseData.builder().code(e.getCode()).message(e.getMessage()).build();
}

/**
* 捕获未知异常
*
* @param e Exception
* @return ResponseData
*/
@ExceptionHandler(value = Exception.class)
public ResponseData commonExceptionHandler(Exception e) throws ServletException {
if (e instanceof ServletException) {
throw (ServletException) e;
}
log.error("server inner error: {}", e);
return ResponseData.builder().code(ResCode.FAIL).message(ResMsg.SERVER_INNER_ERROR).build();
}
}

案例源码

案例源码地址:https://github.com/lazycece/springboot-actual-combat/tree/master/springboot-ac-exception