public String test(){
for(String s: list){
if(s.equals(“小红”)){
log.info(“听说点赞的都发财了!!!”);
}else{
log.info(“没点赞的好像也发财了!!!”);
}
}
return “success”;
}
这是一个典型的空指针异常,真正写代码的时候是不会这么干的,这里为了展示效果才这样写的,我们请求/test接口,看看会发生什么?
我靠?这是什么玩意?这要是让用户/甲方爸爸看到,那还不得被骂死?那如何解决这个问题呢?
我们将for循环这段代码加try/catch异常捕获处理。
改造后的代码:
/**
-
测试
-
@return
*/
@GetMapping(value = “/test”)
public String test(){
try{
for(String s: list){
if(s.equals(“小红”)){
log.info(“听说点赞的都发财了!!!”);
}else{
log.info(“没点赞的好像也发财了!!!”);
}
}
}catch (Exception e){
return “网络繁忙,请稍后再试”;
}
return “success”;
}
再次访问:
发现已经不是提示代码信息了,而是提示了比较友好的网络繁忙,那这个时候,你可能就会有问题了,那我岂不是需要在每个接口请求中添加一个try/catch异常捕获?这样不仅让代码的可读性变差,还会牵扯到代码的可维护性,以后接手代码的同事心里可能是崩溃的。
![](()
java有没有一种统一的处理方式呢?让特定的错误返回特定的提示,java这么强大,怎么可能没有?下面我们来讲讲如何实现springboot的全局异常捕获。
我们先定义一个全局异常捕获类:GlobalExceptionRespone,由于Exception是大部分异常的大哥大,所以我们针对Exception做一个异常处理
package com.ymy.exceptions;
import com.ymy.utils.ConstantUtil;
import com.ymy.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionRespone {
/**
-
全局异常捕获
-
@param e
-
@return
*/
@ExceptionHandler(value = Exception.class)
public Object errorHandler( Exception e) {
log.error(“网络繁忙,请稍后再试 ->”,e);
return Result.faild(ConstantUtil.ResponeCode.SYS_ERROR_CODE,ConstantUtil.ResponeCode.SYS_ERROR);
}
}
这个时候我们去掉业务代码中的try/catch:
@GetMapping(value = “/test”)
public String test() {
for (String s : list) {
if (s.equals(“小红”)) {
log.info(“听说点赞的都发财了!!!”);
} else {
log.info(“没点赞的好像也发财了!!!”);
}
}
return “success”;
}
重启,运行,结果如下:
发现了什么?程序发现了空指针,但是并没有像最开始那样抛出乱信息,而是经过我们处理过的信息,这感觉是不是不要太爽,就增加一个类,就解决了程序中需要假如try/catch的苦恼。
细心的你可能发现我在全局异常捕获类中添加了一个注解:@RestControllerAdvice,这个注解有着怎样的魅力呢?
@RestControllerAdvice是一个组合注解:@ControllerAdvice+@ResponseBody
spring4.3之后被引入的一个注解,它可以被使用到HandlerMapping中,通过@ExceptionHandler来处理HandlerMapping中的异常信息。
@ExceptionHandler通过指定特定的异常类对象来做出对应的处理,如果没有指定到特定的异常类那么他将找到与这个异常类最接近的类,比如之前的空指针异常,我们并没有针对空指针做一个全局异常处理,所以@Ex 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 ceptionHandler找到了他的大哥:@Exception,如果我们配置一下空指针的异常捕获,会出现什么样的结果呢?
在全局异常捕获类中加入:
/**
-
全局异常捕获
-
@param e
-
@return
*/
@ExceptionHandler(value = NullPointerException.class)
public Object nullPointerException( Exception e) {
log.error(“程序中出现空引用,请检查! ->”,e);
return Result.faild(ConstantUtil.ResponeCode.NULL_POINTER_EXCEPTION_CODE,ConstantUtil.ResponeCode.NULL_POINTER_EXCEPTION);
}
启动程序:
是不是像我刚刚说所的那样,@ExceptionHandler会优先寻找报错的异常对象,找到了直接返回,没有找到,继续往后找。
在这里我展示几种常见的异常类:
1.MissingServletRequestParameterException:缺少参数子类。
2.HttpMessageNotReadableException:参数解析失败。
3.MethodArgumentNotValidException:当对用@Valid注释的参数进行验证失败时,将引发异常。
4.BindException:参数绑定错误并且是致命错误的时候。
5.ConstraintViolationException:违反约束条件。
6.ValidationException:基础异常中所有bean验证异常的问题。
7.NoHandlerFoundException:默认情况下,当DispatcherServlet找不到请求的处理程序时,它将发送404响应。但是,如果将其属性“ throwExceptionIfNoHandlerFound” *设置为 true,则会引发此异常,并且可以使用配置的HandlerExceptionResolver进行处理。
8.HttpRequestMethodNotSupportedException:不支持的请求方式
9.HttpMediaTypeNotSupportedException:当客户端发布、放置或请求处理程序不支持的类型。
10.DuplicateKeyException:当试图插入或更新数据导致违反主键或惟一约束时引发异常。
自定义异常
需求:删除用户信息,包含三张表:用户基础信息、用户详细信息、用户图像表。
假设删除用户基础信息返回1(成功)、删除详细信息返回1(成功)、删除图像信息返回0(失败)。
如果我们将这三个放到一个事物里面,事务肯定是会提交的,因为程序没有发生异常,只是再删除的时候没有返回1而已,所以这时候我们就需要自己创建一个异常,让程序抛出。
现在我们就用一个自定义的异常来解决这个问题。
第一步:创建一个自定义的异常类继承RuntimeException(运行时异常)。
package com.ymy.exceptions;
import lombok.Getter;
@Getter
public class MyException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
- 状态码
*/
private String code;
/**
- 提示消息
*/
private String msg;
public MyException(String code,String msg) {
this.code = code;
this.msg = msg;
}
}
第二步:在全局异常类(GlobalExceptionRespone.java)中加入自定义的异常捕获:
/**
- 业务层需要自己声明异常的情况
*/
@ExceptionHandler(MyException.class)
public Object handleMyTokenExcption(MyException e) {
log.error(“->”,e);
return Result.faild(e.getCode(),e.getMsg());
}
第三步,再返回0的时候调用自定义的异常:
/**
-
修啊给i用户信息
-
@return
*/
@RequestMapping(value = “/updateUser”, method = RequestMethod.POST)
public Result addUser() {
int count = 1;