GeXiangDong

精通Java、SQL、Spring的拼写,擅长Linux、Windows的开关机

0%

捕获spring restcontroller中的异常,并记录日志

在使用spring的时候,如果Controller中抛出异常,会被spring显示在客户端界面,而日志中一般没有记录。
客户端对异常的显示也是经spring处理后的信息,没有堆栈,这不方便找错和改错。

可以通过RestControllerAdvice注解定义一个异常处理类来解决这个问题。代码如下

注:也可以不继承ResponseEntityExceptionHandler类,此处继承只是省了一些通用异常的处理。
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
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;


/**
*
* RestController执行过程中发生异常会被此处捕获处理
*
*/
@RestControllerAdvice
public class ControllerExceptionHandler extends ResponseEntityExceptionHandler {
private static final Log log = LogFactory.getLog(ControllerExceptionHandler.class);

/**
* 通过ExceptionHandler来设置待捕获的异常,Throwable可捕获任何异常,但优先级最低,因此
* HttpRequestMethodNotSupportedException HttpMediaTypeNotSupportedException
* HttpMediaTypeNotAcceptableException MissingPathVariableException
* MissingServletRequestParameterException ServletRequestBindingException
* ConversionNotSupportedException TypeMismatchException
* HttpMessageNotReadableException HttpMessageNotWritableException
* MethodArgumentNotValidException MissingServletRequestPartException
* BindException NoHandlerFoundException AsyncRequestTimeoutException
* 等已经在父类声明捕获的异常不会被此方法处理。
*/
@ExceptionHandler(Throwable.class)
@ResponseBody
ResponseEntity<Object> handleControllerException(Throwable ex, WebRequest request) {
Map<String,String> responseBody = new HashMap<>();
// 这里控制返回给客户端的信息
responseBody.put("message","internal server error. " + ex.getMessage());

Exception e;
if(ex instanceof Exception) {
e = (Exception) ex;
}else {
e = new Exception(ex);
}
return handleExceptionInternal(e, responseBody, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
}

/**
* 需要覆盖这个方法,并且在此方法里记录日志;查看ResponseEntityExceptionHandler源码可知,
* 有些异常被父类捕获,不会进入此类的handleControllerException,因此如果在handleControllerException
* 记录异常日志,会导致部分异常无日志
*/
@Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body,
HttpHeaders headers, HttpStatus status, WebRequest request) {
if(log.isErrorEnabled()) {
log.error("内部错误", ex);
}
return super.handleExceptionInternal(ex, body, headers, status, request);
}
}