全局异常拦截器

使用场景

异常兜底方案,及时捕获发生的异常并作出相应的处理,避免将问题抛到服务端然后造成服务出问题的情况

异常体系

在代码中使用(搭配已经定义好的全局异常码一起使用)

1️⃣在src/main/java/.../common/convention/exception路径下新建异常体系相关的类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 抽象项目中三类异常体系,客户端异常、服务端异常以及远程服务调用异常
*
* @see ClientException
* @see ServiceException
* @see RemoteException
*/
@Getter
public abstract class AbstractException extends RuntimeException {

public final String errorCode;

public final String errorMessage;

public AbstractException(String message, Throwable throwable, IErrorCode errorCode) {
super(message, throwable);
this.errorCode = errorCode.code();
this.errorMessage = Optional.ofNullable(StringUtils.hasLength(message) ? message : null).orElse(errorCode.message());
}
}
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
/**
* 客户端异常
*/
public class ClientException extends AbstractException {

public ClientException(IErrorCode errorCode) {
this(null, null, errorCode);
}

public ClientException(String message) {
this(message, null, BaseErrorCode.CLIENT_ERROR);
}

public ClientException(String message, IErrorCode errorCode) {
this(message, null, errorCode);
}

public ClientException(String message, Throwable throwable, IErrorCode errorCode) {
super(message, throwable, errorCode);
}

@Override
public String toString() {
return "ClientException{" +
"code='" + errorCode + "'," +
"message='" + errorMessage + "'" +
'}';
}
}
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
/**
* 远程服务调用异常
*/
public class RemoteException extends AbstractException {

public RemoteException(String message) {
this(message, null, BaseErrorCode.REMOTE_ERROR);
}

public RemoteException(String message, IErrorCode errorCode) {
this(message, null, errorCode);
}

public RemoteException(String message, Throwable throwable, IErrorCode errorCode) {
super(message, throwable, errorCode);
}

@Override
public String toString() {
return "RemoteException{" +
"code='" + errorCode + "'," +
"message='" + errorMessage + "'" +
'}';
}
}
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
/**
* 服务端异常
*/
public class ServiceException extends AbstractException {

public ServiceException(String message) {
this(message, null, BaseErrorCode.SERVICE_ERROR);
}

public ServiceException(IErrorCode errorCode) {
this(null, errorCode);
}

public ServiceException(String message, IErrorCode errorCode) {
this(message, null, errorCode);
}

public ServiceException(String message, Throwable throwable, IErrorCode errorCode) {
super(Optional.ofNullable(message).orElse(errorCode.message()), throwable, errorCode);
}

@Override
public String toString() {
return "ServiceException{" +
"code='" + errorCode + "'," +
"message='" + errorMessage + "'" +
'}';
}
}

2️⃣在src/main/java/…/common/web路径下新建全局异常拦截器类GlobalExceptionHandler,同时为项目引入Hutool依赖

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
/**
* 全局异常处理器
*
*/
@Component
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

/**
* 拦截参数验证异常
*/
@SneakyThrows
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Result validExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
FieldError firstFieldError = CollectionUtil.getFirst(bindingResult.getFieldErrors());
String exceptionStr = Optional.ofNullable(firstFieldError)
.map(FieldError::getDefaultMessage)
.orElse(StrUtil.EMPTY);
log.error("[{}] {} [ex] {}", request.getMethod(), getUrl(request), exceptionStr);
return Results.failure(BaseErrorCode.CLIENT_ERROR.code(), exceptionStr);
}

/**
* 拦截应用内抛出的异常
*/
@ExceptionHandler(value = {AbstractException.class})
public Result abstractException(HttpServletRequest request, AbstractException ex) {
if (ex.getCause() != null) {
log.error("[{}] {} [ex] {}", request.getMethod(), request.getRequestURL().toString(), ex.toString(), ex.getCause());
return Results.failure(ex);
}
log.error("[{}] {} [ex] {}", request.getMethod(), request.getRequestURL().toString(), ex.toString());
return Results.failure(ex);
}

/**
* 拦截未捕获异常
*/
@ExceptionHandler(value = Throwable.class)
public Result defaultErrorHandler(HttpServletRequest request, Throwable throwable) {
log.error("[{}] {} ", request.getMethod(), getUrl(request), throwable);
return Results.failure();
}

private String getUrl(HttpServletRequest request) {
if (StringUtils.isEmpty(request.getQueryString())) {
return request.getRequestURL().toString();
}
return request.getRequestURL().toString() + "?" + request.getQueryString();
}
}

3️⃣在代码中使用
🔥在service的实现类中使用

1
throw new ClientException(UserErrorCodeEnum.USER_NULL);