springboot学习笔记(三)——全局异常处理之注解方式处理

前言:

        异常是不可避免的,但是我们可以最大限制的去处理异常,让用户体验更好。下面先介绍异常对的几种处理方式。本次先介绍基于@ControllerAdvice注解的Controller层的全局异常统一处理,后面会出一篇用AOP来实现的全局异常处理。

开发环境:

        win10+IntelliJ IDEA +JDK1.8 

         springboot版本:springboot 1.5.14 ——2.0后的springboot增加了挺多新特性,暂时先不做了解


pom.xml具体如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.wen</groupId>
   <artifactId>demo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>demo</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.14.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
   </properties>

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

      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <optional>true</optional>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>


</project>


项目结构:

                        


开始开发:

        开发前先提醒,小编用了lombok插件,该插件让代码极其精简。如果你看到

@Slf4j

        @Slf4j相当于:

Logger logger= LoggerFactory.getLogger(this.getClass());

       而@Data注解

@Data       //相当于帮你写完了get-set还有toString方法
    Ok,废话说完,我们先准备个数据返回的实体(主要用于API数据返回格式)   

package com.wen.springboot_test.ResultResponse;

import lombok.Data;

import java.io.Serializable;

/**
 * 返回对象包装类(带泛型)
 */
@Data
public class ResultBean<T> implements Serializable {

   private static final long serialVersionUID = 1L;

   public static final int NO_LOGIN = -1;

   public static final int SUCCESS = 0;

   public static final int CHECK_FAIL = 1;

   public static final int NO_PERMISSION = 2;

   public static final int UNKNOWN_EXCEPTION = -99;

   /**
    * 返回的信息(主要出错的时候使用)
    */
   private String msg = "success";

   /**
    * 接口返回码, 0表示成功, 其他看对应的定义
    * 0   : 成功
    * >0 : 表示已知的异常(例如提示错误等, 需要调用地方单独处理) 
    * <0 : 表示未知的异常(不需要单独处理, 调用方统一处理)
    */
   private int code = SUCCESS;

   /**
    * 返回的数据
    */
   private T data;

   public ResultBean() {
      super();
   }

   public ResultBean(T data) {
      super();
      this.data = data;
   }

   public ResultBean(Throwable e) {
      super();
      this.msg = e.toString();
      this.code = UNKNOWN_EXCEPTION;
   }
}

        既然是异常处理,我们总得需要一个自定义异常吧,自定义异常也很简单,就写了个CheckException来做测试

package com.wen.springboot_test.exception;


import lombok.Data;

/**
 * 自定义异常,主要用于校验错误异常
 *
 */
public class CheckException extends RuntimeException {

   private static final long serialVersionUID = 1L;

   public CheckException() {
   }

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

   public CheckException(Throwable cause) {
      super(cause);
   }

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

   public CheckException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
      super(message, cause, enableSuppression, writableStackTrace);
   }

}
        这两个写完,还少了控制器和异常处理器吧。。Go

package com.wen.springboot_test.controller;

import com.wen.springboot_test.ResultResponse.ResultBean;
import com.wen.springboot_test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 随便写一个Controller,为了简单点,
 * 方法就一个,传id来判断要抛什么异常
 */
@RestController
public class HelloController {

    @Autowired
    UserService userService;

    /**
     * 传id来判断抛什么异常
     * @param id
     * @return
     */
    @RequestMapping(value="test")
    public ResultBean hello(Integer id ){

        return new ResultBean(userService.throwException(id));
    }


}
        异常处理器如下:

package com.wen.springboot_test.HandlerException;

import com.wen.springboot_test.ResultResponse.ResultBean;
import com.wen.springboot_test.exception.CheckException;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 异常处理器
 */
@ControllerAdvice
@Slf4j
public class HandlerException {
    /**
     * 处理未知异常
     * @param e
     * @return
     */

    @ExceptionHandler(value=Exception.class)
    @ResponseBody
    public ResultBean unknowException(Exception e){
        e.printStackTrace();
        ResultBean resultBean =new ResultBean();
        resultBean.setCode(ResultBean.UNKNOWN_EXCEPTION);
        resultBean.setMsg("系统出现未知异常,请于管理员联系");
        /**
         * 未知异常的话,这里写逻辑,发邮件,发短信都可以、、
         */
        return resultBean;
    }

    /**
     * 处理已知异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = CheckException.class)
    @ResponseBody
    public ResultBean handlerCheckException(CheckException e){
        log.info("发生了已知错误:"+e.getMessage());
        ResultBean resultBean =new ResultBean();
        resultBean.setCode(ResultBean.CHECK_FAIL);
        resultBean.setMsg(e.getMessage());
        return resultBean;
    }
}
        下面就是service,逻辑处理层了。

package com.wen.springboot_test.service;

public interface UserService {

    String throwException(Integer id);
}
          实现类  
package com.wen.springboot_test.service.Impl;

import com.wen.springboot_test.exception.CheckException;
import com.wen.springboot_test.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Override
    public String throwException(Integer id)   {
        if (id==0) {
            throw new CheckException("已知异常啦");
        }else if (id==1){
            /**
             * 这里出个除以0异常 ,当做一个未知异常
             */
            Integer e=id/0;
        }

        return "这里不出异常";
    }
}

        

    到这里,代码基本编写完成了。是不是很简单。写完要测试,这是个好习惯。运行main方法。访问来试着访问以下。

    带个id参数主要是为了测试不同异常,懒得写多个Controller了。。

       已知异常:     

            

       未知异常:

            

       正常通过:

            


完整项目案例:

    https://github.com/LuckToMeet-Dian-N/springboot_Learn_3


总结:

        springboot的全局异常处理的方式还是挺多的。每种都有自己的优缺点。本次案例的主要演示的是自定义异常。也是我们比较常用的异常处理吧。后面将出一篇用AOP来实现异常处理的博文。最后祝大家学习进步,步步高升。


程序人生,与君共勉~


猜你喜欢

转载自blog.csdn.net/weixin_41622183/article/details/81030758