matrix.boot.based.config.ResultControllerExceptionAutoConfiguration Maven / Gradle / Ivy
package matrix.boot.based.config;
import lombok.extern.slf4j.Slf4j;
import matrix.boot.based.properties.ResultControllerExceptionProperties;
import matrix.boot.based.utils.I18nMessageUtil;
import matrix.boot.common.dto.Result;
import matrix.boot.common.exception.*;
import matrix.boot.common.utils.StringUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.PriorityOrdered;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Result Controller异常捕捉器
*
* @author wangcheng
*/
@EnableConfigurationProperties(ResultControllerExceptionProperties.class)
@ConditionalOnProperty(value = {"matrix.exception.enabled"}, matchIfMissing = true)
@RestControllerAdvice
@Slf4j
public class ResultControllerExceptionAutoConfiguration {
/**
* 全局异常配置
*/
private final ResultControllerExceptionProperties resultControllerExceptionProperties;
public ResultControllerExceptionAutoConfiguration(ResultControllerExceptionProperties resultControllerExceptionProperties) {
this.resultControllerExceptionProperties = resultControllerExceptionProperties;
}
/**
* 捕捉ResultControllerException
*
* @param req 请求体
* @param resp 返回体
* @param e 异常信息
* @return Result包装信息
*/
@ExceptionHandler({ResultControllerException.class})
@ResponseStatus(code = HttpStatus.OK)
@ResponseBody
public Result> defaultHandler(HttpServletRequest req, HttpServletResponse resp, Exception e) {
Throwable throwable = e.getCause();
//默认的错误编码
Integer defaultErrorCode = resultControllerExceptionProperties.getDefaultErrorCode();
if (throwable == null) {
return Result.fail("forbidden throw ResultControllerException!", defaultErrorCode);
}
while (throwable instanceof ResultControllerException && throwable.getCause() != null) {
throwable = throwable.getCause();
}
if (throwable instanceof ConstraintViolationException) {
//内部异常校验
ConstraintViolationException ex = (ConstraintViolationException) throwable;
log.error(ex.getConstraintViolations().stream().map(item -> item.getRootBeanClass().getName() + "." + item.getPropertyPath().toString() + ":" + item.getMessage()).collect(Collectors.joining("|")));
return Result.fail("params error").setErrorCode(resultControllerExceptionProperties.getDefaultErrorCode());
}
if (throwable instanceof BusinessException) {
//business异常不打印堆栈信息
BusinessException businessException = (BusinessException) throwable;
log.error("business exception: message: {}", businessException.getMessage());
return Result.fail(throwable.getMessage()).setErrorCode(businessException.getErrorCode() == null ? defaultErrorCode : businessException.getErrorCode());
}
if (throwable instanceof I18nBusinessException) {
//国际化business 异常不打印堆栈信息
I18nBusinessException businessException = (I18nBusinessException) throwable;
//获取国际化的消息
String message = I18nMessageUtil.get(businessException.getMessageCode());
log.error("i18n business exception message code: {}, value: {}, message: {}", businessException.getMessageCode(), message, businessException.getMessage());
String resultMessage = StringUtil.isEmpty(message) ? businessException.getMessage() : message;
return Result.fail(resultMessage).setErrorCode(businessException.getErrorCode() == null ? defaultErrorCode : businessException.getErrorCode());
}
if (throwable instanceof ServiceException) {
//service异常
log.error(throwable.getMessage(), throwable);
ServiceException serviceException = (ServiceException) throwable;
return Result.fail(throwable.getMessage()).setErrorCode(serviceException.getErrorCode() == null ? defaultErrorCode : serviceException.getErrorCode());
}
if (throwable instanceof I18nServiceException) {
//国际化service异常
log.error(throwable.getMessage(), throwable);
I18nServiceException serviceException = (I18nServiceException) throwable;
//获取国际化的消息
String message = I18nMessageUtil.get(serviceException.getMessageCode());
String resultMessage = StringUtil.isEmpty(message) ? throwable.getMessage() : message;
return Result.fail(resultMessage).setErrorCode(serviceException.getErrorCode() == null ? defaultErrorCode : serviceException.getErrorCode());
}
//其他异常
log.error(throwable.getMessage(), throwable);
return Result.fail(throwable.getMessage()).setErrorCode(resultControllerExceptionProperties.getDefaultErrorCode());
}
/**
* 捕捉校验参数的异常
*
* @param ex 异常数据
* @return 校验参数的异常
*/
@ExceptionHandler(BindException.class)
@ResponseStatus(code = HttpStatus.OK)
@ResponseBody
public Result> defaultHandler(BindException ex) {
String result = parseErrorMessage(ex.getBindingResult().getAllErrors());
log.error(result);
return Result.fail("params error").setErrorCode(resultControllerExceptionProperties.getDefaultErrorCode());
}
/**
* 切面,针对所有返回为result的controller的错误包装为ResultControllerException抛出
*/
@EnableConfigurationProperties(ResultControllerExceptionProperties.class)
@ConditionalOnProperty(value = {"matrix.exception.enabled"}, matchIfMissing = true)
@Aspect
public static class ResultControllerAspect implements PriorityOrdered {
@Pointcut("execution(matrix.boot.common.dto.Result||reactor.core.publisher.Mono||reactor.core.publisher.Flux *(..))")
public void result() {
}
@Around("result()")
public Object resultAround(ProceedingJoinPoint joinPoint) {
try {
return joinPoint.proceed(joinPoint.getArgs());
} catch (Throwable e) {
throw new ResultControllerException(e);
}
}
@Override
public int getOrder() {
return 0;
}
}
/**
* 解析错误信息
*
* @param objectErrors 对象错误信息
* @return 错误信息
*/
private static String parseErrorMessage(List objectErrors) {
List errorMessages = new ArrayList<>();
for (ObjectError objectError : objectErrors) {
if (objectError instanceof FieldError) {
FieldError fieldError = (FieldError) objectError;
errorMessages.add(fieldError.getObjectName() + "." + fieldError.getField() + ":" + fieldError.getDefaultMessage());
} else {
errorMessages.add(objectError.getObjectName() + ":" + objectError.getDefaultMessage());
}
}
return String.join("|", errorMessages);
}
}