在SpringMVC框架中统一处理异常及请求参数验证(4)

8. 在SpringMVC框架中统一处理异常


在SpringMVC框架中提供了统一处理异常的机制(当然,在SpringBoot框架中也可以直接使用),使得每种异常只需要被处理1次即可,即使某种异常在多种请求中都会出现,也不需要反复处理!其核心是开发人员调用了可能抛出异常的方法时,在控制器中,直接将异常再次抛出,则SpringMVC在调用控制器的方法时,就会捕获到对应的异常对象,并且,如果开发人员定义了统一处理异常的方法,则SpringMVC框架就会自动调用该方法来处理异常!


关于统一处理异常的方法:


默认情况下,该方法只能作用于当前控制器类中的相关请求,例如,将该方法写在UserController中,只能作用了UserController 中处理的各个请求,如果在其它控制器的方法执行过程中出现了异常,是不会被处理的!关于这个问题,可选择的解决方案有2种:


将处理异常的方法写在控制器类的基类中,各控制器类都继承自该基类即可;

将处理异常的方法定义在任意类中,并在这个类的声明之前添加@ControllerAdvice或@RestControllerAdvice注解,各控制器类不需要继承自该类;

统一处理异常的方法必须添加@ExceptionHandler注解;


应该使用public权限;


返回值的类型,可参考处理请求的方法的返回值的设计原则;


方法名称可以自定义;


方法的参数列表至少需要添加异常类型的参数,用于表示被框架捕获的异常对象,关于参数的异常类型,要求能够表示任何将被处理的异常;方法的参数列表中还可以添加其它参数,但是,只能添加SpringMVC框架允许的几种参数,例如HttpServletRequest、HttpServletResponse等,不能像处理请求的方法那样随意!


可以在项目的cn.tedu.straw.portal.controller包中创建GlobalExceptionHandler类,用于统一处理异常,在类的声明之前添加@RestControllerAdvice,使得该类中处理异常的方法能作用于整个项目,并在这个类中添加方法来处理异常:

package cn.tedu.straw.portal.controller;

import cn.tedu.straw.portal.service.ex.ClassDisabledException;
import cn.tedu.straw.portal.service.ex.InsertException;
import cn.tedu.straw.portal.service.ex.InviteCodeException;
import cn.tedu.straw.portal.service.ex.PhoneDuplicateException;
import cn.tedu.straw.portal.vo.R;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler
    public R handleException(Throwable e) {
        if (e instanceof InviteCodeException) {
            return R.failure(12, e);
        } else if (e instanceof ClassDisabledException) {
            return R.failure(13, e);
        } else if (e instanceof PhoneDuplicateException) {
            return R.failure(14, e);
        } else if (e instanceof InsertException) {
            return R.failure(15, e);
        } else {
            return R.failure(9999, e);
        }
    }

}


为了便于统一管理错误代号,并增加代码的可读性,应该将这些错误代号声明为静态常量,同时,为了便于声明和管理这些静态常量,可以在R类中使用静态内部接口来声明:

package cn.tedu.straw.portal.vo;

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain=true)
public class R {

    private Integer state;
    private String message;

    public static R ok() {
        return new R().setState(State.OK);
    }

    public static R failure(Integer state, String message) {
        return new R().setState(state).setMessage(message);
    }

    public static R failure(Integer state, Throwable e) {
        return failure(state, e.getMessage());
    }

    public static interface State {
        int OK = 0;
        int ERR_INVITE_CODE = 4001;
        int ERR_CLASS_DISABLED = 4002;
        int ERR_PHONE_DUPLICATE = 4003;
        int ERR_INSERT = 4004;
        int ERR_UNKNOWN = 9999;
    }

}


然后,在处理异常时,错误代号就使用这些静态常量:

package cn.tedu.straw.portal.controller;

import cn.tedu.straw.portal.service.ex.ClassDisabledException;
import cn.tedu.straw.portal.service.ex.InsertException;
import cn.tedu.straw.portal.service.ex.InviteCodeException;
import cn.tedu.straw.portal.service.ex.PhoneDuplicateException;
import cn.tedu.straw.portal.vo.R;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler
    public R handleException(Throwable e) {
        if (e instanceof InviteCodeException) {
            return R.failure(R.State.ERR_INVITE_CODE, e);
        } else if (e instanceof ClassDisabledException) {
            return R.failure(R.State.ERR_CLASS_DISABLED, e);
        } else if (e instanceof PhoneDuplicateException) {
            return R.failure(R.State.ERR_PHONE_DUPLICATE, e);
        } else if (e instanceof InsertException) {
            return R.failure(R.State.ERR_INSERT, e);
        } else {
            return R.failure(R.State.ERR_UNKNOWN, e);
        }
    }

}

上一篇:上传网页后遇到网页乱码问题


下一篇:Java、C#双语版配套AES加解密示例