package com.monkeylessey.framework.exception; import com.aliyun.oss.OSSException; import com.auth0.jwt.exceptions.JWTVerificationException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.monkeylessey.exception.CaptchaErrorException; import com.monkeylessey.exception.FileFormatNotSupport; import com.monkeylessey.exception.JobException; import com.monkeylessey.exception.ServiceException; import com.monkeylessey.response.Result; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.security.access.AccessDeniedException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.servlet.http.HttpServletRequest; import java.util.List; import java.util.stream.Collectors; /** * @author 29443 * @date 2022/4/9 */ @RestControllerAdvice public class GlobalExceptionHandler { public static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** 公司项目的包结构,用于缩短错误日志的长度 */ private final static String COMPANY_PACKAGE = "com.monkeylessey."; /** * 处理业务逻辑抛出的异常 * * @param e * @param request * @return */ @ExceptionHandler(ServiceException.class) public Result serviceExceptionHandle(ServiceException e, HttpServletRequest request) { this.printExceptionLocation(e, request, e.getMsg()); Integer code = e.getCode(); return code == null ? Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMsg()) : Result.error(e.getCode(), e.getMsg()); } /** * token异常 * * @param e * @param request * @return */ @ExceptionHandler(JWTVerificationException.class) public Result JWTVerificationExceptionHandler(JWTVerificationException e, HttpServletRequest request) { this.printExceptionLocation(e, request, "身份凭证错误"); return Result.error(HttpStatus.FORBIDDEN.value(), "身份凭证错误"); } /** * 验证码异常处理 * * @param e * @param request * @return */ @ExceptionHandler(CaptchaErrorException.class) public Result captchaErrorExceptionHandler(CaptchaErrorException e, HttpServletRequest request) { this.printExceptionLocation(e, request, e.getMsg()); return Result.error(e.getCode(), e.getMsg()); } /** * 处理非手动抛出的运行时异常 * * @param e * @param request * @return */ @ExceptionHandler(Exception.class) public Result runtimeExceptionHandle(Exception e, HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',发生未知异常:{}", requestURI, e); this.printExceptionLocation(e, request, e.getMessage()); return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()); } /** * 认证失败或没有权限,拒绝访问异常 * * @param e * @param request * @return */ @ExceptionHandler(AccessDeniedException.class) public Result handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) { this.printExceptionLocation(e, request, "没有权限,请联系管理员授权"); return Result.error(HttpStatus.FORBIDDEN.value(), "没有权限,请联系管理员授权"); } /** * 请求方式不支持异常 * * @param e * @param request * @return */ @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public Result handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request) { String errMSg = String.format("不支持%s请求", e.getMethod()); this.printExceptionLocation(e, request, errMSg); return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()); } /** * 文件格式不支持异常 * * @param e * @param request * @return */ @ExceptionHandler(FileFormatNotSupport.class) public Result handleFileFormatNotSupported(FileFormatNotSupport e, HttpServletRequest request) { this.printExceptionLocation(e, request, "文件格式不支持" + e.getSuffix()); return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMsg()); } /** * JSON传参数据校验异常 * * @param e * @param request * @return * @throws JsonProcessingException */ @ExceptionHandler(MethodArgumentNotValidException.class) public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) throws JsonProcessingException { List err = e.getBindingResult().getAllErrors().stream().map(error -> error.getDefaultMessage()).collect(Collectors.toList()); String s = new ObjectMapper().writeValueAsString(err); String errMsg = String.format("参数校验失败-%s", s); this.printExceptionLocation(e, request, errMsg); return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), s); } /** * Spring 的断言异常--参数异常 * * @param e * @param request * @return */ @ExceptionHandler(IllegalArgumentException.class) public Result handleIllegalArgumentException(IllegalArgumentException e, HttpServletRequest request) throws JsonProcessingException { String s = new ObjectMapper().writeValueAsString(e.getMessage()); String errMsg = String.format("参数校验失败-%s", s); this.printExceptionLocation(e, request, errMsg); return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), s); } /** * 阿里OSS 文件上传 * * @param e * @param request * @return */ @ExceptionHandler(OSSException.class) public Result handleOSSException(OSSException e, HttpServletRequest request) throws JsonProcessingException { String s = new ObjectMapper().writeValueAsString(e.getMessage()); this.printExceptionLocation(e, request, "文件上传异常"); log.error("Error Message:" + e.getErrorMessage()); log.error("Error Code:" + e.getErrorCode()); log.error("Request ID:" + e.getRequestId()); log.error("Host ID:" + e.getHostId()); return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), s); } /** * 定时任务异常 * * @param e * @param request * @return */ @ExceptionHandler(JobException.class) public Result handleJobException(JobException e, HttpServletRequest request) throws JsonProcessingException { this.printExceptionLocation(e, request, e.getMsg()); return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMsg()); } /** * 打印异常出现位置 * @param e */ private void printExceptionLocation(Throwable e, HttpServletRequest request, String errMsg) { StackTraceElement stackTraceElement = e.getStackTrace()[0]; String className = stackTraceElement.getClassName().contains(COMPANY_PACKAGE) ? stackTraceElement.getClassName().split(COMPANY_PACKAGE)[1] : stackTraceElement.getClassName(); log.error("接口:【{}】, 异常类:【{}】,方法:【{}】,所在行:【{}】, 错误信息:【{}】", request.getRequestURI(), className, stackTraceElement.getMethodName(), stackTraceElement.getLineNumber(), errMsg); } }