springboot全局异常捕获,java下载教程

自定义异常

@Valid


全局异常捕获


什么是异常?程序在启动或者运行时没有按照预期的执行,在执行途中发生某种未知的错误,导致程序非正常停止或者报错。

在我们的程序中,肯定会伴随着很多的异常,启动时:空对象、找不到数据库、用户名密码不对等等异常,都会在程序启动时抛出异常信息,运行时:空引用、参数不匹配等等都会在程序运行时抛出异常,启动的时候抛出异常我们可以马上修改,但是程序正在运行的突然报了一个错,如果没有对这个错误做处理,用户可能会看到一堆的代码信息,很不友好,所以今天讲解一下springboot全局异常捕获。

我们先看一个程序没有做异常处理会发生什么事情,下面是一个小小的例子:

private static List list = new ArrayList();

static {

list.add(“小明”);

list.add(“小红”);

list.add(null);

}

/**

  • 测试

  • @return

*/

@GetMapping(value = “/test”)

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异常捕获?这样不仅让代码的可读性变差,还会牵扯到代码的可维护性,以后接手代码的同事心里可能是崩溃的。

![](https://img-blog.csdnimg.cn/20200

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

302150742828.jpg)

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通过指定特定的异常类对象来做出对应的处理,如果没有指定到特定的异常类那么他将找到与这个异常类最接近的类,比如之前的空指针异常,我们并没有针对空指针做一个全局异常处理,所以@ExceptionHandler找到了他的大哥:@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;

log.info(“第一步:删除基础信息。。。。。。。。。。。”);

log.info(“第二步:删除详细信息。。。。。。。。。。。”);

log.info(“第三步:删除图像信息。。。。。。。。。。。,结果返回了0,表示删除失败”);

count = 0;

if(count == 0){

throw new MyException(“delete_excption”,“删除图像信息失败,请过一会在尝试”);

}

return Result.OK();

}

这里就不具体去实现了,主要是看如何调用自定义的异常使用,调用updateUser接口:

程序抛出了异常,这就会导致事务不会提交,是我们的预期结果,我们再来看看返回给用户的信息:

提示消息正是我在删除失败之后调用自定义异常。

@Valid


相信很多人都是用过:@Valid,他是用来校验参数的一个重要工具,他能简化我们很多的if代码语句,下面我们来介绍一下他的使用方法。

需求,添加一个用户,需要添加:用户名、手机、邮箱、年龄,并且字段都不可为空,邮箱格式需要正确,年龄必须在0-120岁之间。

正常的写法是不是需要在controller中添加一堆的if语句,来判断传递的参数是否符合要求,今天我们讲解一种可读性更好,代码更简单的方式:@Valid注解。

用户VO类:

package com.ymy.vo;

import lombok.Getter;

import lombok.Setter;

import javax.validation.constraints.*;

@Getter

@Setter

public class UserVo {

@NotEmpty(message = “用户名不能为空”)

private String userName;

@NotEmpty(message = “手机号不能为空”)

private String phone;

@NotEmpty(message = “邮箱不可为空”)

@Email(message = “邮箱格式不正确”)

private String email;

@Min(0)

@Max(120)

@NotNull(message = “年龄必填”)

private Integer age;

}

controller接口实现:

  • 添加用户

  • @return

*/

@RequestMapping(value = “addUser”, method = RequestMethod.POST)

public Result addUser(@RequestBody @Valid UserVo userVo, BindingResult bindingResult) {

if (bindingResult.hasErrors()) {

return Result.faild(ConstantUtil.ResponeCode.INVALID_PARAMETER,bindingResult.getFieldError().getDefaultMessage());

}

log.info(“添加成功。。。。。。{}”, userVo);

return Result.OK();

}

运行addUser接口:

发现已经实现了参数校验的功能,但是代码看着还是有一点点的不爽,那是为什么呢?因为controller中还是有着一个if的判断条件,如果能把这个if判断也去掉,那整个世界都美好了。

刚刚在讲全局异常捕获的时候提到了一个异常类,:MethodArgumentNotValidException,不知道还记得吗,他就是配合我们的@Valid使用的,具体如何使用呢?

在全局异常捕获类(GlobalExceptionRespone.java)中添加对@Valid注解参数校验失败捕获:

/**

  • 校验错误拦截处理

  • @param exception 错误信息集合

  • @return 错误信息

*/

@ExceptionHandler(MethodArgumentNotValidException.class)

public Object validationBodyException(MethodArgumentNotValidException exception){

BindingResult bindingResult = exception.getBindingResult();

if (bindingResult.hasErrors()) {

return Result.faild(ConstantUtil.ResponeCode.INVALID_PARAMETER,bindingResult.getFieldError().getDefaultMessage());

}

return Result.faild(ConstantUtil.ResponeCode.SYS_ERROR_CODE);

}

就是这么简单,我们现在去掉controller中的if判断:

/**

  • 添加用户

  • @return

*/

@RequestMapping(value = “addUser”, method = RequestMethod.POST)

public Result addUser(@RequestBody @Valid UserVo userVo) {

log.info(“添加成功。。。。。。{}”, userVo);

return Result.OK();

}

运行结果如下:

完美,从一堆的if判断语句到现在的一个注解,代码的可读性以及可维护性都得到了很大的提升,现在的心情就是倍爽

@Valid常用校验注解:

**@Null:**只能为空

**@NotNull:**不能为空

**@Max(value):**最大数字

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 中,可以通过实现一个全局异常处理器来捕获应用程序中的异常,并对异常进行统一处理。 实现一个全局异常处理器的步骤如下: 1. 创建一个异常处理器类,用于处理应用程序中的异常。 ```java @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleException(Exception ex) { ErrorResponse errorResponse = new ErrorResponse("500", ex.getMessage()); return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); } } ``` 2. 在异常处理器类上加上 @ControllerAdvice 注解,表示这是一个全局异常处理器。 3. 在异常处理器类中定义异常处理方法,使用 @ExceptionHandler 注解指定要处理的异常类型。在异常处理方法中,可以处理异常并返回一个自定义的错误响应实体。 4. 在异常处理方法中使用 ResponseEntity 类来封装错误响应实体,并指定 HTTP 状态码。这里示例使用了 500 状态码。 5. 配置 Spring Boot 应用,使其能够扫描到异常处理器类。可以在启动类上加上 @ComponentScan 注解来指定扫描路径。 ```java @SpringBootApplication @ComponentScan(basePackages = "com.example.demo") public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 以上就是在 Spring Boot 中实现全局异常处理的步骤。通过实现全局异常处理器,可以有效地统一处理应用程序中的异常

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值