package com.hollywood.common.exception;
|
|
|
import com.hollywood.common.basic.ApiResult;
|
import com.hollywood.common.swagger.GlobalResultEnum;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.dao.DataIntegrityViolationException;
|
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.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 org.springframework.web.servlet.NoHandlerFoundException;
|
|
import javax.naming.SizeLimitExceededException;
|
import javax.validation.ConstraintViolation;
|
import javax.validation.ConstraintViolationException;
|
import javax.xml.bind.ValidationException;
|
import java.nio.file.AccessDeniedException;
|
import java.text.DecimalFormat;
|
import java.util.Set;
|
|
/**
|
* @author madman
|
* @version 1.0
|
* @date 2019/7/30 16:13
|
* 全局的异常处理
|
*/
|
@RestControllerAdvice
|
@Slf4j
|
public class GlobalExceptionHandler {
|
/**
|
* 请求参数错误
|
*/
|
private final static String BASE_PARAM_ERR_MSG = "参数校验不通过";
|
@Value("${spring.servlet.multipart.max-file-size:10MB}")
|
private String maxFileSize;
|
@Value("${spring.servlet.multipart.max-request-size:10MB}")
|
private String maxRequestSize;
|
|
/**
|
* 文件大小转换
|
*
|
* @param size
|
* @return
|
*/
|
private static String asReadableFileSize(long size) {
|
if (size <= 0) {
|
return "0";
|
}
|
final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
|
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
|
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + "" + units[digitGroups];
|
}
|
|
/**
|
* 顶级的异常处理
|
* 处理所有不可知异常
|
*
|
* @param e
|
* @return
|
*/
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler(Exception.class)
|
public ApiResult handleException(Exception e) {
|
// 打印异常堆栈信息
|
log.error("顶级异常->:" + e.getMessage(), e);
|
if (e instanceof TokenException) {
|
TokenException e1 = (TokenException) e;
|
return ApiResult.failed(e1.getCode(), e.getMessage());
|
}
|
return ApiResult.failed(e.getMessage());
|
}
|
|
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler({MultipartException.class})
|
public ApiResult fileUpLoad2(MaxUploadSizeExceededException e) {
|
log.error("上传文件异常 => : {}", e.getMessage());
|
if (e.getCause().getCause() instanceof FileSizeLimitExceededException) {
|
return ApiResult.failed("文件大小超出限制,允许的大小在" + maxFileSize);
|
} else if (e.getCause().getCause() instanceof SizeLimitExceededException) {
|
return ApiResult.failed("文件单次上传总大小超过限制,允许的大小在" + maxRequestSize);
|
} else {
|
return ApiResult.failed("文件上传失败");
|
}
|
}
|
|
/**
|
* 自定义的异常处理
|
* 业务异常
|
*
|
* @param e
|
* @return
|
*/
|
@ExceptionHandler(ServerException.class)
|
@ResponseStatus(HttpStatus.OK)
|
public ApiResult handleBusinessException(ServerException e) {
|
// 打印异常堆栈信息
|
log.error(" ---> 业务处理异常: {}", e.getMessage());
|
return ApiResult.failed(e.getCode(), e.getMessage(), e.getData());
|
}
|
|
/**
|
* 请求参数类型不匹配异常
|
* 例如本应传递int,却传递了String
|
*
|
* @param e
|
* @return
|
*/
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler({MethodArgumentTypeMismatchException.class})
|
public ApiResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
|
log.warn("方法参数类型不匹配异常: {}", e);
|
return ApiResult.failed("方法请求参数类型不匹配异常");
|
}
|
|
/**
|
* 缺少servlet请求参数抛出的异常
|
*
|
* @param e
|
* @return
|
*/
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler({MissingServletRequestParameterException.class})
|
public ApiResult handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
|
log.warn(" 参数错误: {}", e.getParameterName());
|
return ApiResult.failed(BASE_PARAM_ERR_MSG + ":请求参数");
|
}
|
|
/**
|
* 请求参数不能正确读取解析时,抛出的异常,比如传入和接受的参数类型不一致
|
*
|
* @param e
|
* @return
|
*/
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler({HttpMessageNotReadableException.class})
|
public ApiResult handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
|
log.error("参数解析失败:", e);
|
return ApiResult.failed("传入和接受的参数类型不一致");
|
}
|
|
/**
|
* 请求参数无效抛出的异常
|
* 校验参数抛出的异常
|
*
|
* @param e
|
* @return
|
*/
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler({MethodArgumentNotValidException.class})
|
public ApiResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
BindingResult result = e.getBindingResult();
|
String message = getBindResultMessage(result);
|
log.error("参数验证失败:" + message);
|
return ApiResult.failed(message.split(":")[1]);
|
}
|
|
/**
|
* 构造参数校验错误信息
|
*
|
* @param result
|
* @return
|
*/
|
private String getBindResultMessage(BindingResult result) {
|
// 多个错误随机取值的
|
FieldError error = result.getFieldError();
|
String field = error != null ? error.getField() : "空";
|
String code = error != null ? error.getDefaultMessage() : "空";
|
return String.format("%s:%s", field, code);
|
}
|
|
|
/**
|
* 请求参数绑定到controller请求参数时的异常
|
*
|
* @param e
|
* @return
|
*/
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler({BindException.class})
|
public ApiResult handleHttpMessageNotReadableException(BindException e) {
|
BindingResult result = e.getBindingResult();
|
String message = getBindResultMessage(result);
|
log.error("参数绑定失败:{}", message);
|
return ApiResult.failed("请求参数绑定失败");
|
}
|
|
/**
|
* javax.validation:validation-api 校验参数抛出的异常
|
*
|
* @param e
|
* @return
|
*/
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler({ConstraintViolationException.class})
|
public ApiResult handleServiceException(ConstraintViolationException e) {
|
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
|
ConstraintViolation<?> violation = violations.iterator().next();
|
String message = violation.getMessage();
|
log.warn("参数验证失败:{}", message);
|
return ApiResult.failed("参数验证失败:" + message);
|
}
|
|
/**
|
* javax.validation 下校验参数时抛出的异常
|
* 400 - Bad Request
|
*
|
* @param e
|
* @return
|
*/
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler({ValidationException.class})
|
public ApiResult<String> handleValidationException(ValidationException e) {
|
log.warn("参数验证失败:{}", e);
|
return ApiResult.failed("参数验证失败:" + e.getMessage());
|
}
|
|
/**
|
* 不支持该请求方法时抛出的异常
|
* 例如本应GET,结果却是POST
|
*
|
* @param e
|
* @return
|
*/
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler({HttpRequestMethodNotSupportedException.class})
|
public ApiResult<String> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
|
log.warn("不支持当前请求方法: {}", e);
|
return ApiResult.failed("Request Method 不正确");
|
}
|
|
|
/**
|
* 不支持当前媒体类型抛出的异常
|
*
|
* @param e
|
* @return
|
*/
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler({HttpMediaTypeNotSupportedException.class})
|
public ApiResult<String> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
|
log.warn("不支持当前媒体类型:{} ", e);
|
return ApiResult.failed("不支持当前媒体类型");
|
}
|
|
/**
|
* 操作数据库出现异常:名称重复,外键关联
|
*/
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler(DataIntegrityViolationException.class)
|
public ApiResult<String> handleException(DataIntegrityViolationException e) {
|
log.error("操作数据库出现异常:{}", e);
|
return ApiResult.failed("操作数据库出现异常:" + e.getMessage());
|
}
|
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler(NoHandlerFoundException.class)
|
public ApiResult<String> handlerNoFoundException(Exception e) {
|
log.error("请求路径匹配异常:" + e.getMessage(), e);
|
return ApiResult.failed(GlobalResultEnum.NOT_FOUND.getCode(), "路径不存在,请检查路径是否正确");
|
}
|
|
@ResponseStatus(HttpStatus.OK)
|
@ExceptionHandler(AccessDeniedException.class)
|
public ApiResult<String> handleAuthorizationException(AccessDeniedException e) {
|
log.warn(e.getMessage());
|
return ApiResult.failed(GlobalResultEnum.FORBIDDEN.getCode(), "没有权限,请联系管理员授权");
|
}
|
|
/**
|
* 自定义的异常处理
|
* 业务异常
|
*
|
* @param e
|
* @return
|
*/
|
@ExceptionHandler(ServiceException.class)
|
@ResponseStatus(HttpStatus.OK)
|
public ApiResult handleBusinessException(ServiceException e) {
|
// 打印异常堆栈信息
|
log.error(" ---> 业务处理异常: {}", e.getMessage());
|
return ApiResult.failed(e.getCode(), e.getMessage(), e.getData());
|
}
|
|
}
|