spring boot 四:全局异常捕捉

1 前言

希望定制错误,比如一般springboot的500错误展示如下(trace等可以通过配置application.yml来决定隐藏还是具有):
在这里插入图片描述
application.yml:

server:
  port: 8088
  path: /hello
  error:
    include-stacktrace: never

如果不希望使用springboot封装的这种接口调用异常返回,可以个人定制。

tips:springboot热启动

配置依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>

快捷键热启动springboot:ctrl+F9

2 定制全局错误返回

在这里插入图片描述
GlobalExceptionHandler代码如下:

package com.xiaoxu.Exception;

import com.google.common.collect.ImmutableMap;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

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

/**
 * @author xiaoxu
 * @date 2022-01-27
 * Ymybatis:com.xiaoxu.Exception.excHandler
 */
@ControllerAdvice//该注解其实就类似于一个@Component注解,所以如果自己定制的错误返回希望是一个json形式的,那么就可以加上@ResponseBody注解
public class GlobalExceptionHandler {
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Map<String,Object> handleException(HttpServletRequest h, Exception e){
        System.out.println("自定义异常:");
        e.printStackTrace();
        System.out.println("excHandler.defaultExceptionHandler执行结束");
        return ImmutableMap.<String,Object>builder().put("code",502).put("msg",e.getMessage()).put("isSuccess",false).build();
    }
}

注意:上述异常捕捉类,以及方法名称,均可随便写,主要是要有 @ControllerAdvice注解修饰类
以及 @ExceptionHandler(value = Exception.class)来修饰需要捕捉的异常方法 ,@ControllerAdvice本质上,也是一个@Component注解,所以如果需要捕捉异常后,返回json格式的数据,那么方法加上@ResponseBody注解即可(类似于controller层,加上@Controller修饰类,@ResponseBody修饰请求的方法,返回的就是json格式的数据,两个注解的功能等同于类上加@RestController)。然后因为@ControllerAdvice本质是@Component,所以也是个组件,所以springboot的主程序类(或者说启动类)包扫描必须包含该异常捕捉类的包路径才可:
在这里插入图片描述

@SpringBootApplication(scanBasePackages = {"com.xiaoxu"})

修改controller:

package com.xiaoxu.controller;

import com.google.common.collect.ImmutableMap;
import com.xiaoxu.service.YouHTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * @author xiaoxu
 * @date 2022-01-24
 * Ymybatis:com.xiaoxu.controller.YouHuiQuanController
 */
@RestController
public class YouHuiQuanController {
    @Autowired
    YouHTypeService youHTypeService;

    @PostMapping(value = "/Youh2")
    public Map<String,Object> getYouhuiTypesNew2(@RequestParam("type") String resourceType) throws Exception {
        if(resourceType.equals("你好")){
            throw new Exception("出错了");
        }
        return ImmutableMap.<String,Object>builder()
                .put("1",youHTypeService.getResult(resourceType))
                .build();
    }
}

postman调用接口:
在这里插入图片描述
3 抛出自定义异常

先自定义一个异常类:
在这里插入图片描述

package com.xiaoxu.Exception;

/**
 * @author xiaoxu
 * @date 2022-01-27
 * Ymybatis:com.xiaoxu.Exception.TypeIsNotPresentException
 */
public class TypeIsNotPresentException extends RuntimeException{
    public TypeIsNotPresentException() {
        //调用父类的含有message的构造方法
        super("该类型不存在");
    }
}

修改全局的异常捕捉类GlobalExceptionHandler:

package com.xiaoxu.Exception;

import com.google.common.collect.ImmutableMap;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

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

/**
 * @author xiaoxu
 * @date 2022-01-27
 * Ymybatis:com.xiaoxu.Exception.excHandler
 */
@ControllerAdvice//该注解其实就类似于一个@Component注解,所以如果自己定制的错误返回希望是一个json形式的,那么就可以加上@ResponseBody注解
public class GlobalExceptionHandler {
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Map<String,Object> myhandleException(HttpServletRequest h, Exception e){
        System.out.println("自定义异常:");
        e.printStackTrace();
        System.out.println("excHandler.defaultExceptionHandler执行结束");
        return ImmutableMap.<String,Object>builder().put("code",502).put("msg",e.getMessage()).put("isSuccess",false).build();
    }

    @ResponseBody
    @ExceptionHandler(TypeIsNotPresentException.class)
    public Map<String,Object> typeIsNotPre(TypeIsNotPresentException t){
        return ImmutableMap.<String,Object>builder().put("code",503).put("msg",t.getMessage()).put("isSuccess",false).build();
    }
}

修改controller层:

package com.xiaoxu.controller;

import com.google.common.collect.ImmutableMap;
import com.xiaoxu.Exception.TypeIsNotPresentException;
import com.xiaoxu.service.YouHTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * @author xiaoxu
 * @date 2022-01-24
 * Ymybatis:com.xiaoxu.controller.YouHuiQuanController
 */
@RestController
public class YouHuiQuanController {
    @Autowired
    YouHTypeService youHTypeService;

    @PostMapping(value = "/Youh2")
    public Map<String,Object> getYouhuiTypesNew2(@RequestParam("type") String resourceType) throws Exception {
        if(resourceType.equals("你好")){
//            throw new RuntimeException("出错了");
            throw new TypeIsNotPresentException();
        }
        return ImmutableMap.<String,Object>builder()
                .put("1",youHTypeService.getResult(resourceType))
                .build();
    }
}

调用postman效果如下:
在这里插入图片描述

如果修改controller层抛出RunTimeException,那么调用postman结果如下:
在这里插入图片描述
注意:配置依赖时,不要重复配置版本不匹配的webmvc依赖,因为spring-boot-starter-web依赖,已经添加了spring-web和spring-webmvc的依赖,否则执行全局异常捕捉的时候会抛错:

<!--        <dependency>-->
<!--            <groupId>org.springframework</groupId>-->
<!--            <artifactId>spring-webmvc</artifactId>-->
<!--            <version>5.3.14</version>-->
<!--        </dependency>-->
<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>

<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.5.4</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

在这里插入图片描述

在这里插入图片描述

4 总结

(1)全局异常类定义,必须加上@ControllerAdvice注解修饰,相当于@Component注解,会在springboot包扫描路径下找到并注册为一个组件。

(2)全局异常捕捉中,捕捉的异常类型由@ExceptionHandler(value = Exception.class)注解决定,如果个人定义异常能匹配上,那么就优先执行个人定义的异常返回(即便全局异常捕捉中,同时还存在父类异常Exception的捕捉,也不会调它),比如@ExceptionHandler(TypeIsNotPresentException.class);如果是类似RunTimeException、或者Exception等,因为Exception异常类是所有异常类的父类,那么异常返回就会调用到@ExceptionHandler(value = Exception.class)这里。

(3)如果希望异常方法返回的是json格式,那么类似@Controller+@ResponseBody,为方法增加@ResponseBody注解,异常响应就会返回json格式数据了。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐