参考网上其他教程,使用AOP统一记录日志和异常处理。
先定义一个切面类。
@Aspect
@Component
@Slf4j
public class ExceptionAspect {
@Autowired
private ExceptionHandle exceptionHandle;
@Pointcut("execution(public * com.sky.controller.*.*(..))")
public void log(){
}
@Before("log()")
public void doBefore(JoinPoint joinPoint){
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//url
log.info("url={}",request.getRequestURL());
//method
log.info("method={}",request.getMethod());
//ip
log.info("id={}",request.getRemoteAddr());
//class_method
log.info("class_method={}",joinPoint.getSignature().getDeclaringTypeName() + "," + joinPoint.getSignature().getName());
//args[]
log.info("args={}",joinPoint.getArgs());
}
@Around("log()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
try {
return proceedingJoinPoint.proceed();
} catch (Exception e) {
return exceptionHandle.exceptionGet(e);
}
}
@AfterReturning(pointcut = "log()",returning = "object")//打印输出结果
public void doAfterReturing(Object object){
log.info("response={}",object.toString());
}
}
给controller下面所有的类里的方法都调用AOP记录日志(方法执行前控制台输出请求的url,方法名,id,方法执行后输出返回值)以及处理异常,省去了每个方法调用记录日志以及try...catch的麻烦。Service层直接抛异常就行了。
自定义异常处理类
@Getter
public class BaseException extends RuntimeException {
private ExceptionEnum exceptionEnum;
public BaseException() {
}
public BaseException(ExceptionEnum exceptionEnum) {
this.exceptionEnum = exceptionEnum;
}
}
里面记录了枚举值,可以细化异常的处理。
同时写了一个ExceptionHandle用来区分自定义的异常和未知异常。
@Slf4j
@ControllerAdvice
public class ExceptionHandle {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result<T> exceptionGet(Exception e){
if(e instanceof BaseException){
log.info("自定义异常{}",e);
BaseException MyException = (BaseException) e;
return Result.error(MyException.getExceptionEnum());
}
log.error("系统未知异常{}",e);
return Result.error(ExceptionEnum.UNKNOW_ERROR);
}
}
最后自定义一个枚举类记录状态码和报错信息。
@Getter
public enum ExceptionEnum {
UNKNOW_ERROR(500,"未知错误"),
USER_NOT_FIND(400,"用户不存在"),
PASSWORD_ERROR(401,"密码错误"),
Success(200,"成功")
.......
;
private Integer code;
private String msg;
ExceptionEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
直接向上抛异常
if (!password.equals(employee.getPassword())) {
//密码错误
throw new PasswordErrorException(ExceptionEnum.PASSWORD_ERROR);
}
通过AOP统一记录日志以及异常处理可以减少重复代码的编写,可以快速找到发生异常的接口,还有一种方法是用@RestControllerAdvice(@ResponseBody+@ControllerAdvice)和@ExceptionHandler进行全局异常捕获。