SpringBoot异常捕获与封装处理

简介

​ 日常开发过程中,难免有的程序会因为某些原因抛出异常,而这些异常一般都是利用try ,catch的方式处理异常或者throw,throws的方式抛出异常不管。这种方法对于程序员来说处理也比较麻烦,对客户来说也不太友好,所以我们希望既能方便程序员编写代码,不用过多的自己去处理各种异常编写重复的代码又能提升用户的体验,这时候全局异常处理就显得很重要也很便捷了,是一种不错的选择。

一、 全局异常捕获与处理

Springboot对于异常的处理做了不错的支持,它提供了两个可用的注解。

@ControllerAdvice用来开启全局的异常捕获。

@ExceptionHandler说明捕获哪些异常,对哪些异常进行处理。

@ControllerAdvice
public class MyExceptionHandler {
    @ExceptionHandler(value =Exception.class)
	public String exceptionHandler(Exception e){
		System.out.println("发生了一个异常"+e);
       	return e.getMessage();
    }
}

上面这段代码的意思是,只要是代码运行过程中有异常就会进行捕获,并输出这个异常。然后我们输入一个不存在的URL,测试出来的异常是这样的。
图片
​ 这对于前后端分离来说并不好,前后端分离之后唯一的交互就是json了,我们也希望将后端的异常变成json返回给前端处理,所以就需要统一结果返回和统一异常处理。

二、统一结果返回与统一异常

Result类:封装返回结果。

public class Result<T> {
    private Integer code;//状态码
    private String message;//提示消息
    private T data;//数据

    public Result() {
    }

    /**
     * @param code 响应码
     * @param message 响应信息
     */
    public Result(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    /**
     * @param code 响应码
     * @param message 响应信息
     * @param data 数据
     */
    public Result(Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    /**
     * @param resultEnum 自定义枚举类,包含 code 和 message
     */
    public Result(ResultEnum resultEnum) {
        this.code = resultEnum.getCode();
        this.message = resultEnum.getMessage();
    }

    /**
     * @param resultEnum 自定义枚举类,包含 code 和 message
     * @param data 数据
     */
    public Result(ResultEnum resultEnum, T data) {
        this.code = resultEnum.getCode();
        this.message = resultEnum.getMessage();
        this.data = data;
    }

    /**
     * 自定义异常返回的结果
     * @param definitionException 自定义异常处理类
     * @return 返回自定义异常
     */
    public static Result<Object> defineError(DefinitionException definitionException) {
        return new Result<>(definitionException.getErrorCode(), definitionException.getErrorMessage());
    }

    /**
     * 其他异常处理方法返回的结果
     * @param resultEnum 自定义枚举类,包含 code 和 message
     * @return 返回其他异常
     */
    public static Result<Object> otherError(ResultEnum resultEnum) {
        return new Result<>(resultEnum);
    }

    //这里写get和set方法
}

注意:其中省略了get,set方法。

ResultEnum:自定义枚举类。

public enum ResultEnum {
    // 数据操作定义
    SUCCESS(200, "成功"),
    TIME_OUT(130, "访问超时"),
    NO_PERMISSION(403, "拒绝访问"),
    NO_AUTH(401, "未经授权访问"),
    NOT_FOUND(404, "无法找到资源"),
    METHOD_NOT_ALLOWED(405, "不支持当前请求方法"),
    SERVER_ERROR(500, " 服务器运行异常"),
    NOT_PARAM(10001, "参数不能为空"),
    NOT_EXIST_USER_OR_ERROR_PASSWORD(10002, "该用户不存在或密码错误"),
    NOT_PARAM_USER_OR_ERROR_PASSWORD(10003, "用户名或密码为空");;
    /**
     * 响应码
     */
    private final Integer code;

    /**
     * 响应信息
     */
    private final String message;

    /**
     * 有参构造
     * @param code  响应码
     * @param message 响应信息
     */
    ResultEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
    
    public Integer getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

注意:枚举类中定义了常见的错误码以及错误的提示信息。这里我们就定义好了统一的结果返回,其中里面的静态方法是用来当程序异常的时候转换成异常返回规定的格式。

DefinitionException:自定义异常处理类。

/*
  自定义异常处理类,继承 RuntimeException
 */
public class DefinitionException extends RuntimeException{
    protected Integer errorCode;//错误码
    protected String errorMessage;//错误消息
    
    //有参,无参,get和set方法
}

注意:其中省略了有参,无参,get和set方法。

我们可以自定义一个全局异常处理类,来处理各种异常,包括自己定义的异常和内部异常。这样可以简化不少代码,不用自己对每个异常都使用try,catch的方式来实现。

GlobalExceptionHandler:全局异常处理类。

//@ControllerAdvice+@ResponseBody,开启全局的异常捕获,返回JSON
@RestControllerAdvice 
public class GlobalExceptionHandler {

    /**
     * 处理自定义异常
     * @return Result
     * @ExceptionHandler 说明捕获哪些异常,对那些异常进行处理。
     */
    @ExceptionHandler(value = DefinitionException.class)
    public Result<Object> customExceptionHandler(DefinitionException e) {
        return Result.defineError(e);
    }

    /**
     * 处理其他异常
     * @return Result
     */
    @ExceptionHandler(value = Exception.class)
    public Result<Object> exceptionHandler(Exception e) {
        return Result.otherError(ErrorEnum.INTERNAL_SERVER_ERROR);
    }
}

说明:将对象解析成json,是为了方便前后端的交互。

三、代码测试与结果

测试类

ResultController:测试的controller类

@RestController
public class ResultController {

    //获取学生信息
    @GetMapping("/student")
    public Result<Student> getStudent() {
        Student student = new Student();
        student.setId(1);
      	student.setAge(18);
        student.setName("XuWwei")
        return new Result<>(ResultEnum.SUCCESS, student);
    }

    //自定义异常处理
    @RequestMapping("/getDeException")
    public Result<Object> DeException() {
        throw new DefinitionException(400, "我出错了");
    }

    //其他异常处理
    @RequestMapping("/getException")
    public Result Exception(){
        Result result = new Result();
        int a=1/0;
        return result;
    }

Student:学生类

public class Student {
    /**
     * 唯一标识id
     */
    private Integer id;
    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private Integer age;
}

注意:其中省略了get,set方法。

测试结果

启动项目,一个一个测试

1. 正常测试

图片

可以看到数据是正常返回json,没有异常。

2. 自定义异常

图片

可以看到这个自定义的异常被捕获到了,并且返回了一个json。

3. 其他异常

图片
可以看到这个异常被捕获到了,并且返回了一个json。

注意:这种方法是不能处理404异常的,捕获不到。

四、404异常特殊处理

1、修改配置文件

​ 默认情况下,SpringBoot是不会抛出404异常的,所以@ControllerAdvice也不能捕获到404异常。我们可以通过配置文件来让这个注解能捕获到404异常,在application.properties中添加以下配置:

#当发现404异常时直接抛出异常
spring.mvc.throw-exception-if-no-handler-found=true
#关闭默认的静态资源路径映射,这样404不会跳转到默认的页面
spring.resources.add-mappings=false

但是关闭默认的静态资源路径映射会让静态资源访问出现问题,也就是不适合前后端一体的情况。

但是我们可以手动配置静态资源路径映射,就能正常访问静态资源了。

@Configuration
public class ResourceConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //可以访问localhost:8080/static/images/image.jpg
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}

2、修改error跳转路径

​ 关闭默认的静态资源路径映射显然不太合理,可能会导致其他的错误发生,所以也可以通过修改默认错误页面的跳转路径来达到我们的目的。

GlobalExceptionHandler类中添加NotFoundExceptionHandler类,这个类继承了ErrorController,可以重写error的跳转路径。

//处理404NotFoundException
@Controller
class NotFoundExceptionHandler implements ErrorController {

    //设置错误页面路径
    @Override
    public String getErrorPath() {
        return "/error";
    }

    //当访问error路径时,返回一个封装的异常的Json
    @RequestMapping("/error")
    @ResponseBody
    public Result<Object> error() {
        return Result.otherError(ResultEnum.NOT_FOUND);
    }
}

五、拓展异常类

GlobalExceptionHandlerexceptionHandler方法将所有的异常统一返回500系统错误,这不符合我们的设想,所以我们可以通过判断异常的类型,来返回不同的值。

exceptionHandler改成以下代码:

/**
  * 处理其他异常
  * @return Result
  */
@ExceptionHandler(value = Exception.class)
public Result<Object> exceptionHandler(Exception e) {
    if (e instanceof NullPointerException){
        //捕获空指针异常
        return Result.otherError(ResultEnum.NOT_PARAM);
    }else if (e instanceof IllegalAccessException){
        //非法访问异常
        return Result.otherError(ResultEnum.NO_PERMISSION);
    } else{
        return Result.otherError(ResultEnum.SERVER_ERROR);
    }
}

注意:更多异常可以通过else if来细分。

六、总结

​ springboot的异常处理,需要通过@ControllerAdvice注解以及 @ExceptionHandler注解,来拦截所有的异常,并通过一个封装返回值返回。但是,这两个注解无法捕获404NotFound异常,因为SpringBoot默认是不会抛出404异常的,所以要通过继承ErrorController来修改404异常的跳转路径,达到捕获404异常的目的。

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
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 中实现全局异常处理的步骤。通过实现全局异常处理器,可以有效地统一处理应用程序中的异常

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值