diff --git a/src/main/java/im/zhaojun/zfile/core/exception/handler/GlobalExceptionHandler.java b/src/main/java/im/zhaojun/zfile/core/exception/handler/GlobalExceptionHandler.java index 94ebd21..189cdac 100644 --- a/src/main/java/im/zhaojun/zfile/core/exception/handler/GlobalExceptionHandler.java +++ b/src/main/java/im/zhaojun/zfile/core/exception/handler/GlobalExceptionHandler.java @@ -1 +1 @@ -package im.zhaojun.zfile.core.exception.handler; import cn.dev33.satoken.exception.NotLoginException; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import im.zhaojun.zfile.core.exception.PasswordVerifyException; import im.zhaojun.zfile.core.exception.StorageSourceException; import im.zhaojun.zfile.core.exception.file.init.InitializeStorageSourceException; import im.zhaojun.zfile.core.exception.file.operator.DisableProxyDownloadException; import im.zhaojun.zfile.core.exception.file.operator.StorageSourceFileOperatorException; import im.zhaojun.zfile.core.exception.IllegalDownloadLinkException; import im.zhaojun.zfile.core.exception.InvalidShortLinkException; import im.zhaojun.zfile.core.exception.LoginVerifyException; import im.zhaojun.zfile.core.exception.StorageSourceAutoConfigCorsException; import im.zhaojun.zfile.core.exception.StorageSourceNotSupportProxyUploadException; import im.zhaojun.zfile.core.exception.ZFileRuntimeException; import im.zhaojun.zfile.core.util.AjaxJson; import im.zhaojun.zfile.core.util.RequestHolder; import im.zhaojun.zfile.core.util.StringUtils; import im.zhaojun.zfile.module.config.service.SystemConfigService; import lombok.extern.slf4j.Slf4j; import org.apache.catalina.connector.ClientAbortException; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Optional; /** * 全局异常处理 * * @author zhaojun */ @ControllerAdvice @Slf4j @Order(1) public class GlobalExceptionHandler { @Resource private SystemConfigService systemConfigService; /** * 存储源文件操作相关异常处理 */ @ExceptionHandler(value = StorageSourceException.class) @ResponseBody @ResponseStatus public AjaxJson storageSourceException(StorageSourceException e) { log.error("存储源 {} 出现异常", e.getStorageId(), e); return AjaxJson.getError(e.getResultMessage()); } /** * 存储源初始化相关异常处理 */ @ExceptionHandler(value = InitializeStorageSourceException.class) @ResponseBody @ResponseStatus public AjaxJson initializeException(InitializeStorageSourceException e) { log.error("初始化存储源 {} 失败", e.getStorageId(), e); return AjaxJson.getError(e.getResultMessage()); } /** * 存储源文件操作相关异常处理 */ @ExceptionHandler(value = StorageSourceFileOperatorException.class) @ResponseBody @ResponseStatus public AjaxJson storageSourceFileOperatorException(StorageSourceFileOperatorException e) { log.error("存储源 {} 文件操作异常", e.getStorageId(), e); return AjaxJson.getError(e.getResultMessage()); } @ExceptionHandler({ZFileRuntimeException.class}) @ResponseBody @ResponseStatus public AjaxJson getFileInfoException(ZFileRuntimeException e) { if (e.getCause() != null) { log.error("ZFileRuntimeException", e); } return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({InvalidShortLinkException.class}) @ResponseBody @ResponseStatus(HttpStatus.NOT_FOUND) public AjaxJson getFileInfoException(InvalidShortLinkException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({IllegalDownloadLinkException.class}) @ResponseBody @ResponseStatus(HttpStatus.FORBIDDEN) public AjaxJson getFileInfoException(IllegalDownloadLinkException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({LoginVerifyException.class}) @ResponseBody @ResponseStatus(HttpStatus.FORBIDDEN) public AjaxJson loginVerifyException(LoginVerifyException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class}) @ResponseBody public AjaxJson> handleValidException(Exception e) { BindingResult bindingResult = null; if (e instanceof MethodArgumentNotValidException) { bindingResult = ((MethodArgumentNotValidException) e).getBindingResult(); } else if (e instanceof BindException) { bindingResult = ((BindException) e).getBindingResult(); } Map errorMap = new HashMap<>(16); Optional.ofNullable(bindingResult) .map(BindingResult::getFieldErrors) .ifPresent(fieldErrors -> { for (FieldError fieldError : fieldErrors) { errorMap.put(fieldError.getField(), fieldError.getDefaultMessage()); } }); return new AjaxJson<>(400, "非法参数 !", errorMap); } @ExceptionHandler({FileNotFoundException.class}) @ResponseBody @ResponseStatus(HttpStatus.NOT_FOUND) public AjaxJson fileNotFound() { return AjaxJson.getError("文件不存在"); } /** * 密码校验异常 */ @ExceptionHandler({PasswordVerifyException.class}) @ResponseBody @ResponseStatus public AjaxJson passwordVerifyException(PasswordVerifyException ex) { return AjaxJson.get(ex.getCode(), ex.getMessage()); } /** * 初始化时自动设置 cors 异常 */ @ExceptionHandler({StorageSourceAutoConfigCorsException.class}) @ResponseBody @ResponseStatus public AjaxJson autoConfigCorsException(StorageSourceAutoConfigCorsException ex) { log.error("跨域配置失败, 存储源初始化信息 {}, 异常信息: ", JSON.toJSON(ex.getIStorageParam()), ex); return AjaxJson.getError(ex.getMessage()); } @ExceptionHandler({StorageSourceNotSupportProxyUploadException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson storageSourceNotSupportProxyUploadException(StorageSourceNotSupportProxyUploadException e) { return AjaxJson.getError("非法操作, 当前存储源不支持此方式上传."); } @ExceptionHandler(value = DisableProxyDownloadException.class) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson disableProxyDownloadException(DisableProxyDownloadException e) { return AjaxJson.getError(e.getResultMessage()); } @ExceptionHandler({HttpMessageNotReadableException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson handlerHttpMessageNotReadableException(HttpMessageNotReadableException e) { return AjaxJson.getBadRequestError("请求参数不合法"); } /** * 捕获 ClientAbortException 异常, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能. */ @ExceptionHandler({HttpMediaTypeNotAcceptableException.class, ClientAbortException.class}) @ResponseBody @ResponseStatus public void clientAbortException() { // if (log.isDebugEnabled()) { // log.debug("出现了断开异常:", ex); // } } @ExceptionHandler @ResponseBody @ResponseStatus public AjaxJson extraExceptionHandler(Exception e) { log.error(e.getMessage(), e); if (e.getClass() == Exception.class) { return AjaxJson.getError("系统异常, 请联系管理员"); } else { return AjaxJson.getError(e.getMessage()); } } /** * 登录异常拦截器 */ @ExceptionHandler(NotLoginException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) @ResponseBody public AjaxJson handlerNotLoginException(NotLoginException e) { HttpServletRequest request = RequestHolder.getRequest(); String axiosRequest = request.getHeader("axios-request"); if (StrUtil.isNotEmpty(axiosRequest)){ return AjaxJson.getNotLogin(); } try { String domain = systemConfigService.getRealFrontDomain(); String loginUrl = StringUtils.removeDuplicateSlashes(domain + "/login"); RequestHolder.getResponse().sendRedirect(loginUrl); } catch (IOException ex) { throw new RuntimeException(ex); } return null; } } \ No newline at end of file +package im.zhaojun.zfile.core.exception.handler; import cn.dev33.satoken.exception.NotLoginException; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import im.zhaojun.zfile.core.exception.*; import im.zhaojun.zfile.core.exception.file.init.InitializeStorageSourceException; import im.zhaojun.zfile.core.exception.file.operator.DisableProxyDownloadException; import im.zhaojun.zfile.core.exception.file.operator.StorageSourceFileOperatorException; import im.zhaojun.zfile.core.util.AjaxJson; import im.zhaojun.zfile.core.util.RequestHolder; import im.zhaojun.zfile.core.util.StringUtils; import im.zhaojun.zfile.module.config.service.SystemConfigService; import lombok.extern.slf4j.Slf4j; import org.apache.catalina.connector.ClientAbortException; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Optional; /** * 全局异常处理 * * @author zhaojun */ @ControllerAdvice @Slf4j @Order(1) public class GlobalExceptionHandler { @Resource private SystemConfigService systemConfigService; /** * 存储源文件操作相关异常处理 */ @ExceptionHandler(value = StorageSourceException.class) @ResponseBody @ResponseStatus public AjaxJson storageSourceException(StorageSourceException e) { log.error("存储源 {} 出现异常", e.getStorageId(), e); return AjaxJson.getError(e.getResultMessage()); } /** * 存储源初始化相关异常处理 */ @ExceptionHandler(value = InitializeStorageSourceException.class) @ResponseBody @ResponseStatus public AjaxJson initializeException(InitializeStorageSourceException e) { log.error("初始化存储源 {} 失败", e.getStorageId(), e); return AjaxJson.getError(e.getResultMessage()); } /** * 存储源文件操作相关异常处理 */ @ExceptionHandler(value = StorageSourceFileOperatorException.class) @ResponseBody @ResponseStatus public AjaxJson storageSourceFileOperatorException(StorageSourceFileOperatorException e) { log.error("存储源 {} 文件操作异常", e.getStorageId(), e); return AjaxJson.getError(e.getResultMessage()); } @ExceptionHandler({ZFileRuntimeException.class}) @ResponseBody @ResponseStatus public AjaxJson getFileInfoException(ZFileRuntimeException e) { if (e.getCause() != null) { log.error("ZFileRuntimeException", e); } return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({InvalidShortLinkException.class}) @ResponseBody @ResponseStatus(HttpStatus.NOT_FOUND) public AjaxJson getFileInfoException(InvalidShortLinkException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({IllegalDownloadLinkException.class}) @ResponseBody @ResponseStatus(HttpStatus.FORBIDDEN) public AjaxJson getFileInfoException(IllegalDownloadLinkException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler({LoginVerifyException.class}) @ResponseBody @ResponseStatus(HttpStatus.FORBIDDEN) public AjaxJson loginVerifyException(LoginVerifyException e) { return AjaxJson.getError(e.getMessage()); } @ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class}) @ResponseBody public AjaxJson> handleValidException(Exception e) { BindingResult bindingResult = null; if (e instanceof MethodArgumentNotValidException) { bindingResult = ((MethodArgumentNotValidException) e).getBindingResult(); } else if (e instanceof BindException) { bindingResult = ((BindException) e).getBindingResult(); } Map errorMap = new HashMap<>(16); Optional.ofNullable(bindingResult) .map(BindingResult::getFieldErrors) .ifPresent(fieldErrors -> { for (FieldError fieldError : fieldErrors) { errorMap.put(fieldError.getField(), fieldError.getDefaultMessage()); } }); return new AjaxJson<>(400, "非法参数 !", errorMap); } @ExceptionHandler({FileNotFoundException.class}) @ResponseBody @ResponseStatus(HttpStatus.NOT_FOUND) public AjaxJson fileNotFound() { return AjaxJson.getError("文件不存在"); } /** * 密码校验异常 */ @ExceptionHandler({PasswordVerifyException.class}) @ResponseBody @ResponseStatus public AjaxJson passwordVerifyException(PasswordVerifyException ex) { return AjaxJson.get(ex.getCode(), ex.getMessage()); } /** * 初始化时自动设置 cors 异常 */ @ExceptionHandler({StorageSourceAutoConfigCorsException.class}) @ResponseBody @ResponseStatus public AjaxJson autoConfigCorsException(StorageSourceAutoConfigCorsException ex) { log.error("跨域配置失败, 存储源初始化信息 {}, 异常信息: ", JSON.toJSON(ex.getIStorageParam()), ex); return AjaxJson.getError(ex.getMessage()); } @ExceptionHandler({StorageSourceNotSupportProxyUploadException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson storageSourceNotSupportProxyUploadException(StorageSourceNotSupportProxyUploadException e) { return AjaxJson.getError("非法操作, 当前存储源不支持此方式上传."); } @ExceptionHandler(value = DisableProxyDownloadException.class) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson disableProxyDownloadException(DisableProxyDownloadException e) { return AjaxJson.getError(e.getResultMessage()); } @ExceptionHandler({HttpMessageNotReadableException.class}) @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public AjaxJson handlerHttpMessageNotReadableException(HttpMessageNotReadableException e) { return AjaxJson.getBadRequestError("请求参数不合法"); } /** * 捕获 ClientAbortException 异常, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能. */ @ExceptionHandler({HttpMediaTypeNotAcceptableException.class, ClientAbortException.class}) @ResponseBody @ResponseStatus public void clientAbortException() { // if (log.isDebugEnabled()) { // log.debug("出现了断开异常:", ex); // } } /** * 捕获 IORuntimeException 异常, 如果 cause 是 ClientAbortException, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能. */ @ExceptionHandler({ IORuntimeException.class }) @ResponseBody @ResponseStatus public void ioRuntimeException(IORuntimeException e) { if (e.getCause() instanceof ClientAbortException) { // log.info("捕获 ClientAbortException 异常, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能."); return; } log.error(e.getMessage(), e); } @ExceptionHandler @ResponseBody @ResponseStatus public AjaxJson extraExceptionHandler(Exception e) { log.error(e.getMessage(), e); if (e.getClass() == Exception.class) { return AjaxJson.getError("系统异常, 请联系管理员"); } else { return AjaxJson.getError(e.getMessage()); } } /** * 登录异常拦截器 */ @ExceptionHandler(NotLoginException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) @ResponseBody public AjaxJson handlerNotLoginException(NotLoginException e) { HttpServletRequest request = RequestHolder.getRequest(); String axiosRequest = request.getHeader("axios-request"); if (StrUtil.isNotEmpty(axiosRequest)){ return AjaxJson.getNotLogin(); } try { String domain = systemConfigService.getRealFrontDomain(); String loginUrl = StringUtils.removeDuplicateSlashes(domain + "/login"); RequestHolder.getResponse().sendRedirect(loginUrl); } catch (IOException ex) { throw new RuntimeException(ex); } return null; } } \ No newline at end of file diff --git a/src/main/java/im/zhaojun/zfile/module/storage/aspect/FileOperatorExceptionWrapperAspect.java b/src/main/java/im/zhaojun/zfile/module/storage/aspect/FileOperatorExceptionWrapperAspect.java index 14f48ea..c2de37b 100644 --- a/src/main/java/im/zhaojun/zfile/module/storage/aspect/FileOperatorExceptionWrapperAspect.java +++ b/src/main/java/im/zhaojun/zfile/module/storage/aspect/FileOperatorExceptionWrapperAspect.java @@ -7,6 +7,7 @@ import im.zhaojun.zfile.core.exception.file.operator.StorageSourceFileOperatorEx import im.zhaojun.zfile.core.util.CodeMsg; import im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService; import lombok.extern.slf4j.Slf4j; +import org.apache.catalina.connector.ClientAbortException; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; @@ -23,8 +24,8 @@ import org.springframework.stereotype.Component; @Slf4j @Order(2) public class FileOperatorExceptionWrapperAspect { - - + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.newFolder(..))") public void newExceptionWrapper(JoinPoint point, Throwable error) { Integer storageId = getStorageId(point); @@ -42,8 +43,8 @@ public class FileOperatorExceptionWrapperAspect { String errMsg = StrUtil.format("删除文件/文件夹失败, 文件路径: {}, 文件名: {}", path, name); throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_DELETE_FAIL, storageId, errMsg, error); } - - + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.rename*(..))") public void renameExceptionWrapper(JoinPoint point, Throwable error) { Integer storageId = getStorageId(point); @@ -53,8 +54,8 @@ public class FileOperatorExceptionWrapperAspect { String errMsg = StrUtil.format("重命名文件/文件夹失败, 文件路径: {}, 原文件名: {}, 修改为: {}", path, name, newName); throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_RENAME_FAIL, storageId, errMsg, error); } - - + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.getDownloadUrl(..))") public void getDownloadUrl(JoinPoint point, Throwable error) { Integer storageId = getStorageId(point); @@ -62,7 +63,7 @@ public class FileOperatorExceptionWrapperAspect { String errMsg = StrUtil.format("获取下载链接失败, 文件路径: {}", pathAndName); throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_GET_UPLOAD_FAIL, storageId, errMsg, error); } - + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.getUploadUrl(..))") public void getUploadUrlExceptionWrapper(JoinPoint point, Throwable error) { Integer storageId = getStorageId(point); @@ -72,8 +73,8 @@ public class FileOperatorExceptionWrapperAspect { String errMsg = StrUtil.format("获取文件上传链接失败, 文件路径: {}, 文件名: {}, 文件大小: {}", path, name, size); throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_GET_UPLOAD_FAIL, storageId, errMsg, error); } - - + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractProxyTransferService.uploadFile(..))") public void proxyUploadExceptionWrapper(JoinPoint point, Throwable error) { Integer storageId = getStorageId(point); @@ -81,17 +82,20 @@ public class FileOperatorExceptionWrapperAspect { String errMsg = StrUtil.format("文件代理上传失败, 文件路径: {}", pathAndName); throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_PROXY_UPLOAD_FAIL, storageId, errMsg, error); } - - + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractProxyTransferService.downloadToStream(..))") public void proxyDownloadExceptionWrapper(JoinPoint point, Throwable error) { + if (error instanceof ClientAbortException || error.getCause() instanceof ClientAbortException) { + return; + } Integer storageId = getStorageId(point); String pathAndName = getArgStr(point, 0); String errMsg = StrUtil.format("文件代理下载失败, 文件路径: {}", pathAndName); throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_PROXY_DOWNLOAD_FAIL, storageId, errMsg, error); } - - + + @AfterThrowing(throwing = "error", value = "execution(public * im.zhaojun.zfile.module.storage.service.base.AbstractBaseFileService.getFileItem(..))") public void getFileItemExceptionWrapper(JoinPoint point, Throwable error) { Integer storageId = getStorageId(point); @@ -99,8 +103,8 @@ public class FileOperatorExceptionWrapperAspect { String errMsg = StrUtil.format("文件代理下载失败, 文件路径: {}", pathAndName); throw new StorageSourceFileOperatorException(CodeMsg.STORAGE_SOURCE_FILE_DISABLE_PROXY_DOWNLOAD, storageId, errMsg, error); } - - + + /** * 获取存储源 id * @@ -113,7 +117,7 @@ public class FileOperatorExceptionWrapperAspect { AbstractBaseFileService targetService = (AbstractBaseFileService) point.getTarget(); return targetService.getStorageId(); } - + /** * 获取切入点方法第 n 个参数 * @@ -129,11 +133,11 @@ public class FileOperatorExceptionWrapperAspect { Object[] args = point.getArgs(); return ArrayUtil.get(args, index); } - - + + private String getArgStr(JoinPoint point, int index) { Object arg = getArg(point, index); return Convert.toStr(arg); } - + } \ No newline at end of file