SpringMVC之全局异常处理 ——统一返回格式(自定义异常)

版权声明:本文为博主原创文章,转载请注明出处。谢谢! https://blog.csdn.net/zhibo_lv/article/details/83146347

SpringMVC之全局异常处理

老规矩开篇咱们先介绍一下背景
因当前APP越来越流行,或是提供的第三方接口等等都需要你来统一返回格式。这个时候问题就来了 ,很多时候系统的异常以及为了代码的可读性我们必然会抽出很多的间接层(例如数据格式校验、数据有效性校验等),一层层的return是否让你烦不胜烦?其实只需要抛出异常就像断言那样即可阻止程序继续执行后续业务代码。

Dennis Debruler 说过 “计算机是这样一门科学:它相信所有的问题都可以通过增加一个间接层来解决。”

首先定义好我们的返回对象

package com.xxx.response.common;


import java.io.Serializable;

public class Response<T> implements Serializable {
	private static final long serialVersionUID = 1L;
	private Integer code;
	private String message;
	private T result;

	public static boolean isSuccess(Response<?> response) {
		return response == null ? false : ResponsCodeTypeEnum.SUCCESS.getCode().equals(response.getCode());
	}

	public Response() {
		this.code = ResponsCodeTypeEnum.SUCCESS.getCode();
		this.message = ResponsCodeTypeEnum.SUCCESS.getMessage();
	}

	public Response(Integer code, String message) {
		this.code = code;
		this.message = message;
	}

	public Response(T result) {
		this.code = ResponsCodeTypeEnum.SUCCESS.code;
		this.message = ResponsCodeTypeEnum.SUCCESS.message;
		this.result = result;
	}

	public Integer getCode() {
		return this.code;
	}

	public String getMessage() {
		return this.message;
	}

	public T getResult() {
		return this.result;
	}

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

	public void setMessage(String message) {
		this.message = message;
	}

	public void setResult(T result) {
		this.result = result;
	}

	public String toString() {
		return "Response(code=" + this.getCode() + ", message=" + this.getMessage() + ", result=" + this.getResult() + ")";
	}
	
	//为了方便将枚举类整合至一起了可以单独建一个
	public enum ResponsCodeTypeEnum {
		SUCCESS(0, "请求成功"),
		SYSTEM_BUSY(100, "系统繁忙"),
		REQUEST_TIME_OUT(300, "请求超时"),
		PARAMETER_ERROR(400, "参数错误"),
		NETWORK_ERROR(404, "网络异常"),
		DATA_NOT_EXISTS(600, "数据不存在"),
		FAILURE(999, "未知错误");

		private Integer code;
		private String message;

		private ResponsCodeTypeEnum(Integer code, String message) {
			this.code = code;
			this.message = message;
		}

		public Integer getCode() {
			return this.code;
		}

		public String getMessage() {
			return this.message;
		}
	}
}

接下来自定义异常

我这些写的复杂些可以去除掉你们不需要的

定义接口

package com.xxx.common.exception;

import java.util.Date;

public interface BaseException {
    Integer getCode();

    String[] getArgs();

    void setTime(Date var1);

    Date getTime();

    void setClassName(String var1);

    String getClassName();

    void setMethodName(String var1);

    String getMethodName();

    void setParameters(String[] var1);

    String[] getParameters();

    void setHandled(boolean var1);

    boolean isHandled();

    String getMessage();

    void setI18nMessage(String var1);

    String getI18nMessage();
}

异常工具类

package com.xxx.common.exception.util;

import java.io.PrintWriter;
import java.io.StringWriter;

public class ExceptionUtils extends org.apache.commons.lang3.exception.ExceptionUtils {
    public ExceptionUtils() {
    }

    public static String[] convertArgsToString(Object[] args) {
        String[] argsStrs = new String[args.length];

        for(int i = 0; i < args.length; ++i) {
            argsStrs[i] = String.valueOf(args[i]);
        }

        return argsStrs;
    }

    public static String toString(Throwable e) {
        return toString("", e);
    }

    public static String toString(String msg, Throwable e) {
        StringWriter w = new StringWriter();
        w.write(msg);
        PrintWriter p = new PrintWriter(w);
        p.println();

        String var4;
        try {
            e.printStackTrace(p);
            var4 = w.toString();
        } finally {
            p.close();
        }

        return var4;
    }
}

超类

package com.xxx.common.exception;

import com.xxx.common.exception.util.ExceptionUtils;
import org.springframework.core.NestedRuntimeException;

import java.util.Date;

public class BaseRuntimeException extends NestedRuntimeException implements BaseException {
    private static final long serialVersionUID = 1L;
    private Integer code;
    private Date time;
    private String[] args;
    private String className;
    private String methodName;
    private String[] parameters;
    private boolean handled;
    private String i18nMessage;

    public BaseRuntimeException(Integer code, String defaultMessage, Object[] args) {
        super(defaultMessage);
        this.code = code;
        this.args = ExceptionUtils.convertArgsToString(args);
    }

    public BaseRuntimeException(Integer code, String defaultMessage, Throwable cause, Object[] args) {
        super(defaultMessage, cause);
        this.code = code;
        this.args = ExceptionUtils.convertArgsToString(args);
    }

    public BaseRuntimeException(String defaultMessage, Throwable cause) {
        super(defaultMessage, cause);
    }

    public BaseRuntimeException(String defaultMessage) {
        super(defaultMessage);
    }

    public Integer getCode() {
        return this.code;
    }

    public Date getTime() {
        return this.time;
    }

    public void setTime(Date time) {
        this.time = time;
    }

    public String getClassName() {
        return this.className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getMethodName() {
        return this.methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public String[] getParameters() {
        return this.parameters;
    }

    public void setParameters(String[] parameters) {
        this.parameters = parameters;
    }

    public void setHandled(boolean handled) {
        this.handled = handled;
    }

    public boolean isHandled() {
        return this.handled;
    }

    public void setI18nMessage(String i18nMessage) {
        this.i18nMessage = i18nMessage;
    }

    public String getI18nMessage() {
        return this.i18nMessage;
    }

    public String[] getArgs() {
        return this.args;
    }
}

异常类

package com.xxx.common.exception;

public class FastRuntimeException extends BaseRuntimeException {
    private static final long serialVersionUID = -4954118251735823026L;

    public FastRuntimeException(String msg) {
        super(msg);
    }

    public FastRuntimeException(Integer code, String defaultMsg, Object[] args) {
        super(code, defaultMsg, args);
    }

    public FastRuntimeException(Integer code, String msg) {
        super(code, msg, new Object[0]);
    }

    public FastRuntimeException(String msg, Throwable cause) {
        super(msg, cause);
    }

    public FastRuntimeException(Integer code, String msg, Throwable cause) {
        super(code, msg, cause, new Object[0]);
    }

    public Throwable fillInStackTrace() {
        return this;
    }
}

异常定义完成,可直接使用FastRuntimeException 不过我建议各个系统模块去继承FastRuntimeException 定义自己的异常

全局异常捕获

package com.xxx.common.exception;

import com.alibaba.dubbo.rpc.RpcException;
import com.xxx.common.response.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ValidationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    public GlobalExceptionHandler() {
    }

    @ExceptionHandler({Exception.class})
    public Response<Map<String, String>> MethodArgumentNotValidHandler(Exception exception) throws Exception {
        Response<Map<String, String>> response = new Response();
        HashMap fieldAndMessage;
        Iterator var5;
        FieldError fieldError;
        if (exception instanceof MethodArgumentNotValidException) {
            fieldAndMessage = new HashMap();
            MethodArgumentNotValidException methodArgumentNotValidException = (MethodArgumentNotValidException)exception;
            var5 = methodArgumentNotValidException.getBindingResult().getFieldErrors().iterator();

            while(var5.hasNext()) {
                fieldError = (FieldError)var5.next();
                fieldAndMessage.put(fieldError.getField(), fieldError.getDefaultMessage());
            }

            response.setCode(Response.ResponsCodeTypeEnum.PARAMETER_ERROR.getCode());
            response.setMessage(Response.ResponsCodeTypeEnum.PARAMETER_ERROR.getMessage());
            response.setResult(fieldAndMessage);
        } else if (exception instanceof BindException) {
            fieldAndMessage = new HashMap();
            BindException bindException = (BindException)exception;
            var5 = bindException.getBindingResult().getFieldErrors().iterator();

            while(var5.hasNext()) {
                fieldError = (FieldError)var5.next();
                fieldAndMessage.put(fieldError.getField(), fieldError.getDefaultMessage());
            }

            response.setCode(Response.ResponsCodeTypeEnum.PARAMETER_ERROR.getCode());
            response.setMessage(Response.ResponsCodeTypeEnum.PARAMETER_ERROR.getMessage());
            response.setResult(fieldAndMessage);
        } else if (exception instanceof ValidationException) {
            response.setCode(Response.ResponsCodeTypeEnum.PARAMETER_ERROR.getCode());
            response.setMessage(Response.ResponsCodeTypeEnum.PARAMETER_ERROR.getMessage());
        } else if (exception instanceof RpcException) {
            response.setCode(Response.ResponsCodeTypeEnum.PARAMETER_ERROR.getCode());
            response.setMessage(Response.ResponsCodeTypeEnum.PARAMETER_ERROR.getMessage());
        } else if (exception instanceof BaseRuntimeException) {
        	//取出我们放入异常中的code 和message 返回前端
            response.setCode(((BaseRuntimeException) exception).getCode());
            response.setMessage(exception.getMessage());
        }else {
            response.setCode(Response.ResponsCodeTypeEnum.FAILURE.getCode());
            response.setMessage(Response.ResponsCodeTypeEnum.FAILURE.getMessage());
        }
        this.log.error(exception.getMessage(), exception);
        return response;
    }
}

打完收工,一切的代码都是可以不做任何修改直接拿去使用的。大大的方便了我们的业务开发。接下来请让你的校验工作变成间接层吧。

我的简化版登录校验工厂
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zhibo_lv/article/details/83146347