package cn.palmte.work.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.http.HttpStatus; import org.springframework.util.ObjectUtils; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.transaction.TransactionSystemException; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.validation.ObjectError; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import org.springframework.web.multipart.MaxUploadSizeExceededException; import org.springframework.web.multipart.MultipartException; import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; import cn.palmte.work.ErrorMessage; import cn.palmte.work.ErrorMessageException; import cn.palmte.work.Json; import cn.palmte.work.Result; import cn.palmte.work.ValidationError; /** * 异常处理 * * @author Harry Yang * @since 2.0 2022/12/30 15:24 */ @RestControllerAdvice public class ApplicationExceptionHandler { private static final Logger log = LoggerFactory.getLogger(ApplicationExceptionHandler.class); public static final ErrorMessage argsErrorMessage = ErrorMessage.failed("参数错误"); public static final ErrorMessage sizeExceeded = ErrorMessage.failed("上传文件大小超出限制"); public static final ErrorMessage methodNotSupported = ErrorMessage.failed("请求方式不支持"); public static final ErrorMessage internalServerError = ErrorMessage.failed("服务器内部异常"); public static final ErrorMessage notWritableError = ErrorMessage.failed("数据无法正常返回到客户端"); @ExceptionHandler(ErrorMessageException.class) public ResponseEntity errorMessage(ErrorMessageException errorMessage) { HttpStatus httpStatus = errorMessage.getStatus(); return ResponseEntity.status(httpStatus) .body(ErrorMessage.failed(errorMessage.getMessage())); } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(IllegalArgumentException.class) public ErrorMessage badRequest(IllegalArgumentException exception) { return ErrorMessage.failed(exception.getMessage()); } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler({ MaxUploadSizeExceededException.class }) public ErrorMessage badRequest() { return sizeExceeded; } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public ErrorMessage methodNotSupported() { return methodNotSupported; } @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorMessage error(Exception exception) { log.error("An Exception occurred", exception); if (exception instanceof SQLException) { return internalServerError; } if (exception instanceof HttpMessageNotWritableException) { return notWritableError; } if (exception instanceof TransactionSystemException) { return ErrorMessage.failed("数据库出错"); } return ErrorMessage.failed(exception.getMessage()); } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MethodArgumentTypeMismatchException.class) public ErrorMessage typeMismatch(MethodArgumentTypeMismatchException mismatch) { return ErrorMessage.failed("参数'" + mismatch.getName() + "'不能转换到对应类型"); } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MissingServletRequestParameterException.class) public ErrorMessage parameterError(MissingServletRequestParameterException e) { return ErrorMessage.failed("缺少参数'" + e.getParameterName() + "'"); } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler({ MultipartException.class, HttpMessageNotReadableException.class, HttpMediaTypeNotSupportedException.class }) public ErrorMessage messageNotReadable() { return argsErrorMessage; } @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler({ BindException.class, MethodArgumentNotValidException.class }) public Result validExceptionHandler(Exception e) { BindingResult result; if (e instanceof MethodArgumentNotValidException) { result = ((MethodArgumentNotValidException) e).getBindingResult(); } else if (e instanceof BindException) { result = (BindingResult) e; } else { return ErrorMessage.failed(); } List allErrors = result.getAllErrors(); Map model = new HashMap<>(16); for (ObjectError error : allErrors) { if (error instanceof FieldError) { FieldError fieldError = (FieldError) error; String field = fieldError.getField(); String defaultMessage = error.getDefaultMessage(); model.put(field, defaultMessage); // log.error("[{}] -> [{}]", field, defaultMessage); } } return ValidationError.failed(model); } @ExceptionHandler(NullPointerException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Json nullPointer(NullPointerException exception) { log.error("An Exception occurred", exception); final StackTraceElement[] stackTrace = exception.getStackTrace(); if (ObjectUtils.isEmpty(stackTrace)) { return Json.failed("空指针", "暂无堆栈信息"); } return Json.failed("空指针", stackTrace[0]); } @ExceptionHandler(DataAccessException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorMessage dataAccessException(DataAccessException accessException) { String message = getDataAccessMessage(accessException.getCause()); log.error(message, accessException); return ErrorMessage.failed(message); } String getDataAccessMessage(Throwable cause) { return "数据库出错"; } @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(DataAccessResourceFailureException.class) public ErrorMessage dataAccessException(DataAccessResourceFailureException accessException) { log.error("数据库连接出错", accessException); return ErrorMessage.failed("数据库连接出错"); } }