Spring的统一异常处理基于AOP(面向切面编程)和Spring MVC框架的拦截器机制。
-
ControllerAdvice注解:通过@ControllerAdvice注解的类,Spring会将其识别为全局异常处理器。这个类中的方法被用来处理在控制器中抛出的异常。
-
@ExceptionHandler注解:在全局异常处理器中,使用@ExceptionHandler注解标注的方法用于处理特定类型的异常。当控制器中抛出对应的异常时,Spring会调用匹配的异常处理方法。
-
AOP:Spring利用AOP在运行时动态地将异常处理逻辑织入到控制器方法的执行流程中。当控制器方法抛出异常时,AOP会捕获到异常并将其传递给全局异常处理器。
-
拦截器:Spring MVC框架的拦截器也起到了关键作用。它们可以在请求到达控制器之前或者之后执行预处理或者后处理操作。全局异常处理器可以被注册为一个拦截器,使得它可以捕获并处理控制器中抛出的异常。
总的来说,Spring的统一异常处理利用AOP和Spring MVC框架的拦截器机制,通过@ControllerAdvice注解和@ExceptionHandler注解来实现。这种机制使得异常处理逻辑可以被集中管理,提高了代码的可维护性和可读性。
定义不同的异常处理方法来处理不同类型的异常,使你的应用程序在出现异常时能够更加友好地响应客户端。
package com.sjtu.aiportal.common.exception;
import com.sjtu.aiportal.domian.ResultModel;
import com.sjtu.aiportal.utils.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
*
* 统一异常处理
*/
@Slf4j
@ControllerAdvice
public class PortalExceptionHandler {
@Autowired
private HttpServletRequest request;
@Autowired
private HttpServletResponse response;
/**
* 业务异常类统一处理
*
* @param exception
* @return
*/
@ExceptionHandler(PortalException.class)
public ResponseEntity<ResultModel> handleException(PortalException exception) {
String requestId = ThreadUtil.getThreadRequestId();
String code = exception.getCode();
String message = exception.getMessage();
String errorMessage = exception.getErrorMsg();
log.warn("requestId:[{}],PartnerException description:[{}]," +
"PartnerException code:[{}], PartnerException handled:[{}] ",
requestId, errorMessage, code, message);
ResultModel error = ResultModel.builder()
.success(false)
.code(code)
.message(message)
.errorMsg(errorMessage)
.requestId(requestId)
.build();
return new ResponseEntity<>(error, HttpStatus.OK);
}
/**
* 异常最终处理
*
* @param exception
* @return
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<ResultModel> handleError(Exception exception) {
String requestId = ThreadUtil.getThreadRequestId();
ResultModel error = ResultModel.builder()
.success(false)
.requestId(requestId)
.code(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()))
.errorMsg("系统异常,请联系管理员")
.message(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())
.build();
log.error("exception handled", exception);
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ResultModel> handleError(MethodArgumentNotValidException exception) {
List<ObjectError> allErrors = exception.getBindingResult().getAllErrors();
StringBuilder errorMessage = new StringBuilder("");
for( ObjectError error : allErrors ) {
errorMessage.append(error.getDefaultMessage()).append(";");
}
ResultModel error = ResultModel.builder()
.success(false)
.code(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()))
.errorMsg(errorMessage.toString())
.build();
log.error("exception handled", exception);
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
/**
* 参数转换错误
*
* @param req
* @param response
* @param exception
* @return
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<ResultModel> handleMessageNotReadable(
HttpServletRequest req, HttpServletResponse response, Exception exception) {
log.warn("exception handled", exception);
String requestId = ThreadUtil.getThreadRequestId();
ResultModel error = ResultModel.builder()
.success(false)
.requestId(requestId)
.code(String.valueOf(HttpStatus.BAD_REQUEST.value()))
.errorMsg(exception.getMessage())
.message(HttpStatus.BAD_REQUEST.getReasonPhrase())
.build();
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
}