Exception也是加工中心系统锁机怎么破解的子类之一。相较于Error而言,但是它可是和我们开发者有很大的关系,也经常会遇到他或他的子类,Exception的子类是用来抽象主要都是程序自身出现类问题,我们开发者需要关注和处理这些问题,保证程序业务正常。
Exception拥有大量的子类,但是大致分为两种:
RuntimeException以及他的子类:这类异常都属于不可检查异常(unchecked exceptions)
除去1中的非运行时异常:这类异常属于可检查异常(checked exceptions)
不可检查异常:程序经过编译时,编译器不会要求对此类异常进行处理(throws/try-catch)。RuntimeException以及他的子类和Error都属于不可检查异常,对于RuntimeException的子类我们开发者要特别注意,因为编译器不会提示我们,我们要给与合适的处理(但像空指针、数组下标越界等异常都可以通过代码规避掉,还有些如NumberFormatException等在不确定的情况下要使用异常处理机制哦,举例:在解析JSON字符串形式的数字时,可能存在数字格式错误)。
可检查异常:程序经过编译时,编译器会要求对此类异常进行处理(throws/try-catch)。Exception子类中除去RuntimeException以及他的子类的异常都是可检查异常。处理方式也就是:throws/try-catch,下面会细讲。
二、异常处理
在出现可检查异常和可能出现运行时异常时,需要采用异常处理机制。常见的异常处理机制:
使用throws向方法栈上层抛出:
public void test() thros NumberFormatException{
//TODO
//抛出一个可检查异常或可能抛出运行时异常
}
使用try-catch处理相应的异常:执行记录日志、返回给前端数据等操作(后面也会介绍使用统一异常处理来解决对异异常的处理)。
之前写的关于异常处理的运行流程(https://blog.csdn.net/zll_zll…)在这里既不赘述了。
三、统一异常处理
上面的内容都是偏向于理论,这里我们讨论下,实际项目中对于异常的处理方式。
而且在JavaWeb应用中,一旦发生异常,正常的代码逻辑就不能执行了,而去执行异常处理:
我们想要的:
前后端分离时:我们要返回给用户固定格式的包含错误信息的数据,有好的提示用户。
前后端未分离时:我们要跳转到错误页面(对用户友好),而不是默认情况下的直接把错误信息打印在页面上。
为了实现上面的:
发生可检查异常时:如果发生在非Controller层,我们一般会使用throws来向上抛出异常,知道Controller层,如果前后端分离那就返回固定数据,未分离则跳转到错误页面。但是会写很多的try-catch代码,不仅不美观不易读、而且不规范难维护(很难保证每个开发人员在catch里的处理都很规范)。
对于不可检查异常(运行时异常)来说:要么只能靠祈祷每个开发人员都能写出完美的代码逻辑,保证不发生运行时异常(显然不可能),要么就在每个Controller层方法里都加入try-catch保证万一发生异常能有完成上面的操作(和1中面临的困难一样了)。
那么怎么才能,既能保证实现我们的预期,又能规避上面操作的缺点呢?
那就是做统一异常处理。
实现的方式/思路:
1)AOP方式:
使用Around Advice(环绕通知),在调用原方法的语句上加上try-catch,完成异常的捕获、日志记录等其他操作。
@Around(value = “execution(public * Controller.(…))”)
public BaseResult catchException(ProceedingJoinPoint joinPoint) {
try {
//统一返回数据类型(前后端为分离时直接跳转页面即可)
BaseResult baseResult = new BaseResult(SUCCESS);
baseResult.setData(joinPoint.proceed());
return baseResult;
} catch (Throwable e) {
//捕获异常
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
//打上LOG
logger.error(className + “:” + methodName + “:” + e);
return new BaseResult(FAIL);
}
}
怎么样?够不够惊艳?什么,还嫌太麻烦?
2)@ControllerAdvice/@RestControllerAdvice+@ExceptionHandler
@Slf4j
@ControllerAdvice
@ResponseBody
//或者@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* @valid参数校验异常处理
* @param e
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultData validationException(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
if (bindingResult.hasErrors()) {
List allErrors = bindingResult.getAllErrors();
List messages = new ArrayList<>();
allErrors.forEach(p->{
FieldError fieldError = (FieldError) p;
log.error("参数格式错误:参数对象:{};字段:{};错误原因:{}", fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());
messages.add(fieldError.getDefaultMessage());
});
return ResultData.error(StringUtils.join(messages,","));
}
return ResultData.error("参数格式错误");
}
/**
* 全局异常处理
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
public ResultData globalExceptionHandler(Exception e) {
//MyBaseException自定义异常
if (e instanceof MyBaseException) {
//自定义异常
log.error("自定义异常",e);
return ResultData.error(e.getMessage());
} else {
//其他异常
log.error("未知异常", e);
//给用户有好的提示(不能直接把异常信息传回前端)
return ResultData.error("系统开小差了");
}
}
}
注意 @ExceptionHandler标识的方法的顺序和拦截的顺序一致,加工中心系统锁机怎么破解如果异常背前面的捕获了,那么后面的就能捕获了,所以具体的异常要放在前面。