SpringBoot系列(7)——统一异常处理

1. 固定格式

1.1 由于返回的格式比较乱,所以先对返回格式进行统一,返回消息格式参照如下模板:

{
    "code":1,
    "msg":"年龄不小于10岁",
    "data":null
}

{
    "code":0,
    "msg":"成功"
    "data":{
        "id":20,
        "age":18,
        "name":"hahaha"
    }
}
  • code,代表状态码,0为成功,1为异常
  • msg,提示信息,成功时返回"成功",异常时返回异常信息
  • data,返回数据,异常时data为null,成功时包含返回的数据

1.2 按照如上的消息格式,在domain下新建Result类,该类是Http请求返回的最外层对象(code,msg,data):

package com.example.demo.domain;

/**
 * Http请求返回的最外层对象
 * Created by xzf on 2017/9/19.
 */
public class Result<T> {
    //错误码
    private Integer code;

    //提示信息
    private String msg;

    //具体的内容,用泛型表示
    private T data;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

1.3 把设置返回结果的方法抽象成 ResultUtil 工具类(这样可复用,避免代码冗余),在具体业务场景中,调用 ResultUtil 工具类中的对应方法,如下图:

094640_uTqb_3381212.png

当发生错误时,调用ResultUtil中的error方法;当执行“添加一个学生”成功时,则调用 ResultUtil 的success方法。

那么,ResultUtil工具类中的success和error具体是怎么定义的的?其代码如下:

package com.example.demo.utils;

import com.example.demo.domain.Result;

/**
 * Created by xzf on 2017/9/19.
 */
public class ResultUtil {
    public static Result success(Object object){
        Result result=new Result();
        result.setCode(0);
        result.setMsg("成功");
        result.setData(object);
        return result;
    }

    //成功的情况下也可能不含object(即成功也可能没有返回数据)
    public static Result success(){
        //此处调用上面定义的success方法,传入null值
        return success(null);
    }

    public static Result error(Integer code,String msg){
        Result result=new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }
}

 

2. 引入异常,采用异常处理

下面这个方法通过传入一个id,获得该id对应的学生的年龄。在该方法中,对获得的学生年龄进行了判断,并根据判断结果抛出异常

//studentService中的getAge方法
public void getAge (Integer id)throws Exception{
        Student student= studentRepository.findOne(id);
        Integer age=student.getAge();
        if (age<10){
            //返回"你可能在上小学"  code=100
            throw new StudentException(ResultEnum.PRIMARY_SCHOOL);
        }else if (age>10 && age<16){
            //返回"你可能在上初中"  code=101
            throw new StudentException(ResultEnum.MIDDLE_SCHOOL);
        }
    }

不难看出,这里使用了自定义的异常类StudentException

 

2.1 自定义异常

因为原生的Exception异常类,其构造方法只能传入一个String 类型的message,而我们定义的返回json的模板需要传入的除了错误提示消息,还有错误码,因此此处自定义一个异常类——StudentException

package com.example.demo.exception;

import com.example.demo.enums.ResultEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.plugin2.message.Message;

/**
 * Created by xzf on 2017/9/19.
 */
//Spring框架只对RuntimeException抛出的异常进行回滚,因此此处不用Exception
public class StudentException extends RuntimeException{

    private Integer code;

    public StudentException(ResultEnum resultEnum) {
        super(resultEnum.getMsg());//父类构造方法中本身会传一个message进去
        this.code = resultEnum.getCode();
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
}

在上面的代码中我们看到,在抛StudentException异常时,该异常的构造方法中传入的参数是“ResultEnum.PRIMARY_SCHOOL ”,他们是什么呢?不是说需要传入“错误码+返回消息”吗?其实,这里的“ResultEnum.PRIMARY_SCHOOL ”就包含了这两个信息。

 

2.2 code和message设成枚举,统一管理

原来,为了方便对错误码(状态码)进行统一管理,使得错误码和其相应的返回消息能够一一对应,也方便程序员查看和修改,这里把错误码和返回消息设置成一个枚举类:

package com.example.demo.enums;

/**
 * 将code和message对应起来
 * Created by xzf on 2017/9/19.
 */
public enum ResultEnum {
    UNKNOW_ERROR(-1,"未知错误"),
    SUCCESS(0,"成功"),
    PRIMARY_SCHOOL(100,"你可能在上小学"),
    MIDDLE_SCHOOL(101,"你可能在上初中"),
    ;
    private Integer code;
    private String msg;

    ResultEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    /**
     * 枚举类中给getter方法就可以了,枚举的使用都是使用构造方法来创建,不会再set它的值
     * @return
     */
    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

这样一来,错误码和它所对应的返回消息就一目了然了。

在这里拗了半天,下面来捋一捋关系:

简单说来,就是把原来的抛异常,改成了抛一个自定义的异常;把原来要传入的两个参数(code和msg),改成了传入一个枚举类参数(枚举类中包含了这两个信息)

 

2.3 捕获异常

既然是抛出了异常,那么就需要捕获异常,并采取相应的操作。这里我们在handle下新建一个ExceptionHandle类,用于捕获并处理上面的异常:

package com.example.demo.handle;

import com.example.demo.domain.Result;
import com.example.demo.exception.StudentException;
import com.example.demo.utils.ResultUtil;
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;

/**
 * Created by xzf on 2017/9/19.
 */
@ControllerAdvice
public class ExceptionHandle {

    private static final Logger logger= LoggerFactory.getLogger(ExceptionHandle.class);

    @ExceptionHandler(value = Exception.class)  //声明捕获的异常类
    @ResponseBody       //返回的是json数据,然而类前使用的不是@RestController注解,因此需要加上@ResponseBody
    public Result handle(Exception e){
        //判断捕获的异常是否是自定义的StudentException
        if (e instanceof StudentException){
            StudentException exception=(StudentException) e;
            return ResultUtil.error(exception.getCode(),exception.getMessage());
        }else {
            logger.error("【系统异常】",e);//控制台输出异常信息
            //前台返回“-1,未知错误”,并且该异常被捕获处理了,控制台不显示,所以这里借助日志来排查错误
            return ResultUtil.error(-1,"未知错误!");//返回json信息为"未知错误",
        }

    }

}

从上面代码可以看到,在处理异常的时候,传过来的 StudentException 类中的值就可以用来设置进Result中了

转载于:https://my.oschina.net/u/3381212/blog/1543386

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值