栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot--全局异常处理--方法/实例

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot--全局异常处理--方法/实例

原文网址:SpringBoot--全局异常处理--方法/实例_IT利刃出鞘的博客-CSDN博客

简介

说明

        本文用实例介绍SpringBoot如何进行全局异常处理。

方案简述

         全局异常处理可以用两个注解来实现:@ControllerAdvice+@ExceptionHandler。这样可以捕获 Controller中抛出的指定类型异常,可对不同类型的异常单独进行处理。

系列文章

SpringBoot全局处理我写了一个系列:

  1. SpringBoot--全局异常处理--方法/实例_IT利刃出鞘的博客-CSDN博客
  2. SpringBoot--全局响应处理--方法/实例_IT利刃出鞘的博客-CSDN博客
  3. SpringBoot--全局请求处理--方法/实例_IT利刃出鞘的博客-CSDN博客
  4. SpringBoot--全局格式处理--方法/实例_IT利刃出鞘的博客-CSDN博客
@ControllerAdvice介绍

说明

        @ControllerAdvice里边有@Component,用于类,可包含@ExceptionHandler,@InitBinder和@ModelAttribute方法,适用于所有使用@RequestMapping方法。(因此是全局的处理方法)。

        可以在多个类上使用@ControllerAdvice,可通过@Order来控制顺序。不能通过实现Order接口来控制顺序,因为这部分源码里只支持@Order这种方式。见:调整多个ControllerAdvice的执行顺序_felixu的博客-CSDN博客。

        在Spring4及之后, @ControllerAdvice支持配置控制器的子集,可通过annotations(), basePackageClasses(), basePackages()方法选择控制器子集。

官网网址

springmvc 注解总结 - SpringMVC中文官网

使用场景

  1. @ControllerAdvice+@ExceptionHandler:全局异常处理
    1. 捕获Controller中抛出的指定类型异常,可对不同类型的异常区别处理
  2. @ControllerAdvice+ 实现ResponseBodyAdvice接口:全局响应处理(返回值)
    1. 其标注的方法将会在目标Controller方法执行之后执行。
  3. @ControllerAdvice+@ModelAttribute:全局请求处理
    1. 其标注的方法将会在目标Controller方法执行之前执行。
    2. 使用场景示例:鉴权/授权、全局处理格式
  4. @ControllerAdvice+@InitBinder:全局请求处理
    1. 其标注的方法将会在目标Controller方法执行之前执行。
    2. request中自定义参数解析方式进行注册
    3. 使用场景示例:全局处理格式
      SpringBoot--LocalDateTime--全局格式转换/前后端/前端入参/响应给前端_IT利刃出鞘的博客-CSDN博客
实例:简单测试 代码

返回值用任何类型都可以,类似Controller的返回值。

package com.example.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;

@Slf4j
@ControllerAdvice
public class GlobalExceptionAdvice {
    @ExceptionHandler({Exception.class})
    @ResponseBody
    public Object handleException(HttpServletRequest request, Exception e) throws Exception {
        log.error(e.getMessage(), e);
        // 如果某个自定义异常有@ResponseStatus注解,就继续抛出
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }
        HashMap map = new HashMap<>();
        map.put("message", "全局异常处理" + e.getMessage());
        return map;
    }
}

controller

package com.example.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/advice")
    public String test() {
        int i = 1 / 0;
        return "test success";
    }
}
测试

访问:http://localhost:8080/advice

前端结果:

{
    "message": "全局异常处理/ by zero"
}

后端结果:

2021-08-18 00:39:20.240 ERROR 31064 --- [nio-8080-exec-1] c.example.config.GlobalExceptionAdvice   : / by zero

java.lang.ArithmeticException: / by zero
	at com.example.controller.HelloController.test(HelloController.java:11) ~[classes/:na]
	...
实例:项目实战 代码

异常处理类

package com.example.common;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestControllerAdvice
// 也可以:类上加@ControllerAdvice + 方法上加@ResponseBody
public class GlobalExceptionAdvice {
    // 处理其他所有异常
    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e) throws Exception {
        log.info("这是异常处理");
        log.error(e.getMessage(), e);
 
        // 如果某个自定义异常有@ResponseStatus注解,就继续抛出
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }
 
        // 实际项目中应该这样写,防止用户看到详细的异常信息
        // return new Result().failure().message.message("操作失败");
        return new Result<>().failure().message(e.getMessage());
    }
 
    // 处理自定义异常
    @ExceptionHandler(BusinessException.class)
    public Result handleBusinessException(Exception e) throws Exception {
        log.error(e.getMessage(), e);
 
        // 如果某个自定义异常有@ResponseStatus注解,就继续抛出
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }
 
        // 实际项目中应该这样写,防止用户看到详细的异常信息
        // return new Result<>().failure().message("操作失败");
        return new Result<>().failure().message(e.getMessage());
    }
} 
 

或者这么写

​import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
// 也可以:类上加@ControllerAdvice + 方法上加@ResponseBody
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e){
        log.error(e.getMessage(), e);

        // 如果某个自定义异常有@ResponseStatus注解,就继续抛出
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }
        
        // 处理所有业务异常
        if (e instanceOf BusinessException.class){
            return Result.failure().message(e.getMessage());
        }

        // 防止用户看到详细的异常信息
        return Result.failure().message("操作失败");
    }
}

Controller(无需处理异常了)

package com.example.business.controller;

import com.example.business.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("user")
public class UserController {

    @GetMapping("fault")
    public void fault() {
        int i = 1 / 0;
    }

}
测试

postman访问:http://localhost:8080/user/fault

postman结果

​​

后端结果

​​

公共代码

下边这两个类好几处都用到了,单独把它提出来。

 User实体类

package com.example.business.entity;
 
import lombok.AllArgsConstructor;
import lombok.Data;
 
@Data
@AllArgsConstructor
public class User {
    private Long id;
    private String userName;
    private Integer age;
}

响应的包装

package com.example.demo.common.entity;

import lombok.Data;

@Data
public class Result {
    private boolean success = true;

    private int code = 1000;

    private String message;

    private T data;

    public Result() {
    }

    public Result(boolean success) {
        this.success = success;
    }

    public Result success(boolean success) {
        Result result = new Result<>(success);
        if (success) {
            result.code = 1000;
        } else {
            result.code = 1001;
        }
        return result;
    }

    public Result success() {
        return success(true);
    }

    public Result failure() {
        return success(false);
    }

    
    public Result code(int code) {
        this.code = code;
        return this;
    }

    public Result message(String message) {
        this.message = message;
        return this;
    }

    public Result data(T data) {
        this.data = data;
        return this;
    }
}

自定义异常

package com.example.common.exception;

public class BusinessException extends RuntimeException{
    public BusinessException() {
        super();
    }

    public BusinessException(String message) {
        super(message);
    }

    public BusinessException(String message, Throwable cause) {
        super(message, cause);
    }
}

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号