本文分为两种方法,第一种适合于对于小程序这种简单的应用,只需要得到错误消息即可,第二章针对大型规范化的网页项目。

一、简易异常类封装:

1、创建自定义异常类

1、继承RuntimeException。

2、实现get和set方法(lombok工具类实现)

3、创建两个变量,一个用于保存状态码另一个保存错误消息。

4、创建可能使用到的构造方法

super(msg)表示将错误信息以我们平时看见的红色字样打印在控制台

import lombok.Data;
@Data//异常类
public class EmosException extends RuntimeException{
    private int code=500;
    private String msg;

    //对该异常类的构造方法进行补充,不写的化会默认只有一个无参构造
    public EmosException(String msg) {
        super(msg);
        this.msg = msg;
    }

    public EmosException(String msg, int code) {
        super(msg);
        this.msg = msg;
        this.code = code;
    }

    public EmosException(String msg, Throwable e) {
        super(msg, e);
        this.msg = msg;
    }

    public EmosException(String msg, int code, Throwable e) {
        super(msg, e);
        this.msg = msg;
        this.code = code;
    }

}

2、创建异常配置类

1、给这个类+@RestControllerAdvice注解表示是异常处理的配置类。

2、给该类的方法上+@ResponseBody注解表示返回的是JSON类型,@ExceptionHandler表示处理的异常是什么类型的异常。

3、书写异常处理方法,参数就是总异常类Exception。

4、用if else if等进行分支,用instanceof判断是什么类型的。

返回的类型都是字符串类型,保存在requset.data中,前台获取只需要request.data即可得到异常消息。

package com.example.emos.config;
import com.example.emos.exception.EmosException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
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.RestControllerAdvice;

@Slf4j//打印日志信息用
@RestControllerAdvice//让系统知道这是处理异常的类
//步骤:1、将异常转化为对应的类型 2、调用里面的获取消息模块
public class ExceptionAdvice {
    @ResponseBody//将异常的返回格式为json格式
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)//处理哪种异常
    public String exceptionHandler(Exception e){
        log.error("执行异常",e);//将异常打印在控制台
        //处理后端验证失败
        if(e instanceof MethodArgumentNotValidException){
            //将异常强转为验证异常
            MethodArgumentNotValidException exception= (MethodArgumentNotValidException) e;
            //获取异常消息
            return exception.getBindingResult().getFieldError().getDefaultMessage();
        }
        //自定义异常
        else if(e instanceof EmosException){
            EmosException exception= (EmosException) e;
            return exception.getMsg();
        }
        //未授权类型
        else if(e instanceof UnauthorizedException){
            return "你不具备相关权限";
        }
        else{
            return "后端执行异常";
        }
    }
}

二、复杂类型封装:

该封装方法将每一种异常对应的状态码,以及异常返回消息的统一封装

1、新建一个properties文件,用于保存所有的异常消息文本:

lin.codes[0] = ok
lin.codes[999] = 服务器未知异常

lin.codes[10000] = 通用错误
lin.codes[10001] = 通用参数错误
lin.codes[10002] = 资源未找到
lin.codes[10003] = 没有找到合适的登陆处理方法
lin.codes[10004] = 令牌不合法或者过期
lin.codes[10005] = 用户未被授权
lin.codes[10006] = 登陆失败

lin.codes[20000] = 用户类通用错误
lin.codes[20001] = 用户已存在
lin.codes[20002] = 用户不存在
lin.codes[20003] = 用户密码错误
lin.codes[20004] = 获取用户wx openid失败

2、写一个配置文件,将上面写好的各种异常消息在SpringBoot开启时就读取进去。

package com.lin.missyou.core.CodeConfiguration;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;

//指明共有的前缀
@ConfigurationProperties(prefix = "lin")
//指明异常文件的地址
@PropertySource(value = "classpath:config/exception-code.properties",encoding = "UTF-8")
//加入到SpringBoot容器
@Component
//将那个文件的所有内容都读到这个map中
public class ExceptionCodeConfiguration {

    private Map<Integer, String> codes = new HashMap<>();

    public Map<Integer, String> getCodes() {
        return codes;
    }

    public void setCodes(Map<Integer, String> codes) {
        this.codes = codes;
    }


    public String getMessage(int code){
        String message = codes.get(code);
        return message;
    }
}

配置文件的位置如下:

spring boot设置异常处理机制 springboot异常类_spring boot设置异常处理机制

3、此时我们新建一个父类继承RuntimeException,用于让所有的关于http的异常都继承它:

package com.lin.missyou.exception.http;

/**
 * 这是下面所有小错误类的父类。
 * 1、同包的所有类都继承这个类,不同异常的code和状态码不同。code码指的是前面写的异常信息的数组索引
 * 2、根据状态码对异常进行分类。
 * 3、例如商品没找到,或用户没找到,都抛出NotFoundException,状态码来表示是什么没找到
 * */
public class HttpException extends RuntimeException{
    protected Integer code;
    protected Integer httpStatusCode = 500;

    public Integer getCode() {
        return code;
    }

    public Integer getHttpStatusCode() {
        return httpStatusCode;
    }


}

 下面我们以一个NotFoundException为例:

  • 继承HttpException。
  • 编写一个有参构造
package com.lin.missyou.exception.http;

public class NotFoundException extends HttpException{
    public NotFoundException(int code){
        this.httpStatusCode = 404;
        this.code = code;
    }
}

我还创建了一个和它写法一致的异常类,只是httpStatusCode不同:

spring boot设置异常处理机制 springboot异常类_后端_02

 4、此时我们来到最核心的部分,全局异常管理类:

在这里将处理我们前面所写的全部异常,每当新增一个异常类就要在这里写好对应的处理方法。

1、打上@ControllerAdvice注解表示是处理异常类的

2、打上@ResponseBody 防止返回JSON对象出现问题

3、将刚刚写好的处理异常消息的封装类注入今来

4、@ExceptionHandler表示处理什么异常

5、@ResponseStatus表示该异常的http状态码是多少。该部分有两种处理方式:

  1. 通过@ResponseStatus注解直接指明对应的状态码
  2. 对于我们自己写的自定义异常类,由于以及指明了对应的httpStatus所以要通过ResponseEntity来返回。

完整代码:

//当有异常时会进入这个类
@ControllerAdvice //内部包含了Component注解,所以会被SpringBoot发现
@ResponseBody //因为异常返回的也是对象,所以要加这个注解
public class GlobalExceptionAdvice {
    @Autowired //将异常配置文件与这个类相对应
    private ExceptionCodeConfiguration codeConfiguration;

    //一、处理一个已知hpptStatus的异常
    @ExceptionHandler(value=Exception.class)
    /**
     * 设置Http的状态码,不设置的话都是200正常。设置方式有两种:
     * 1、 @ResponseStatus来设置状态码。不灵活,不能动态设置
     * 2、通过ResponseEntity来设置返回的属性
     * */
    @ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
    public UnifyResponse handleException(HttpServletRequest req, Exception e) {
        String requestUrl = req.getRequestURI(); //获取出现异常的地址
        String method = req.getMethod(); //获取是GET还是POST方法
        System.err.println(e);
        return new UnifyResponse(9999, "服务器异常", method + " "+ requestUrl);
    }

    //二、处理自己写的那些httpStatus动态变化HttpException<-自己写的那个父类
    @ExceptionHandler(HttpException.class)
    /**2、通过ResponseEntity来设置返回的属性(状态码等)*/
    public ResponseEntity<UnifyResponse> handleHttpException(HttpServletRequest req, HttpException e){
        //1、获取URL和请求方法
        String requestUrl = req.getRequestURI();
        String method = req.getMethod();
        //2、封装返回对象
        UnifyResponse message =
                new UnifyResponse(
                        e.getCode() //获取自定义的异常状态码
                        ,codeConfiguration.getMessage(e.getCode())  //通过这个自定义状态码来查询对应的消息
                        , method + " " + requestUrl); //封装方法和URL

        //3、因为没用指定状态码,所以需要用ResponseEntity对象。
        //3.1与ResponseBody注解用处相同,不加无法返回对象以及对中文等都无法解析
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        //3.2通过异常来获取http状态码信息
        HttpStatus httpStatus = HttpStatus.resolve(e.getHttpStatusCode());

        //4、返回对象
        return new ResponseEntity<>(message, headers, httpStatus);
    }
}

调用处:

@Override
    public BannerByNameVo findByName(String name) {
        BannerByNameVo bannerItems = bannerDao.selectByNames(name);
        if (bannerItems==null)
            throw new NotFoundException(10005);
        return bannerItems;
    }

返回形式如下:

spring boot设置异常处理机制 springboot异常类_java_03