spring-boot学习:十三、spring-boot统一异常处理

上文讲了如何对返回的数据格式进行统一处理,本文主要是进一步对异常情况的补充。

在后台接口处理的过程中会产生各种各样的异常,比如参数校验异常、系统内部异常、业务逻辑异常等,这些异常产生在各个环节,不能随意抛给调用方,格式不一致会导致调用方无法处理。

实现思路:
1)对后台接口(Controller)中的异常进行处理,使用@ControllerAdvice+@ExceptionHandler的方式进行处理;
2)对于Filter等类产生的异常,上面的方式是无法处理到的,在spring boot中默认将异常统一转发到"/error",所以只需要处理"/error"即可。

  1. 定义统一异常类ServiceException.java
package com.kevin.core.exception;

/**
 * 统一异常
 * @author Kevin Yu
 */
public class ServiceException extends RuntimeException {

	private Integer code = 400;

	public Integer getCode() {
		return code;
	}

	public ServiceException() {
	}

	public ServiceException(Throwable e) {
		super(e);
	}

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

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

	public ServiceException(String message, Throwable e) {
		super(message, e);
	}
}
  1. 定义全局异常处理类
package com.kevin.core.exception;

import com.kevin.core.result.ApiResultEntity;
import com.kevin.core.servlet.ServletHolderFilter;
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;

/**
 * 统一异常处理,仅适用于Controller,无法处理Filter中的异常
 * @author Kevin Yu
 */
@ControllerAdvice
public class GlobalExceptionHandler {

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

	@ExceptionHandler(Exception.class)
    @ResponseBody
    public ApiResultEntity handleException(Exception e){
	    logger.error(String.format("[%s][%s]请求出现异常,URL:%s,异常信息:%s", ServletHolderFilter.getClientIP(),ServletHolderFilter.getUserAgent(),ServletHolderFilter.getServletPath(), msg), e);
     
        return new ApiResultEntity(ApiResultEntity.RESULT_EXCEPTION, e.getMessage());
    }

	@ExceptionHandler(ServiceException.class)
    @ResponseBody
    public ApiResultEntity handleException(ServiceException e){
        logger.warn("[{}][{}]请求出现业务异常,URL:{},异常信息:{}", ServletHolderFilter.getClientIP(),ServletHolderFilter.getUserAgent(),ServletHolderFilter.getServletPath(), e.getMessage());
        return new ApiResultEntity(e.getCode(), e.getMessage());
    }

}
  1. 实现"/error"接口,对异常结果进行统一处理
package com.kevin.core.base;

import com.kevin.core.result.ApiResultEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 自定义Error处理类
 * Spring Boot默认会将异常转发到"/error",交给{@link DefaultErrorAttributes}处理
 * @Author kevin
 * @create 2020/5/26 10:28
 */
@RestController
public class BaseErrorController implements ErrorController {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private ErrorAttributes errorAttributes;

    private static final String ERROR_PATH = "/error";

    @Autowired
    public BaseErrorController(ErrorAttributes errorAttributes) {
        this.errorAttributes = errorAttributes;
    }

    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }

    @RequestMapping(value = ERROR_PATH)
    public Object errorJson(HttpServletRequest request) {
        Map<String, Object> errorInfo = errorAttributes.getErrorAttributes(new ServletWebRequest(request), true);

        logger.error("请求异常:{}", errorInfo.toString());
        return new ApiResultEntity((Integer)errorInfo.get("status"), (String) errorInfo.get("message"));
    }
}

4.测试

package com.kevin.fish.controller.demo;

import com.kevin.core.exception.ServiceException;
import com.kevin.core.result.ApiResult;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author kevin
 * @create 2020/8/7 14:42
 */
@ApiResult
@RestController
public class TestController {

    @GetMapping(value="/test",produces= MediaType.APPLICATION_JSON_VALUE)
    public Object test(){
        throw new ServiceException("I am sorry");
    }
}

调用接口 http://localhost:8081 返回结果:
{“code”:500,“text”:“I am sorry”,“data”:null}

猜你喜欢

转载自blog.csdn.net/guangcaiwudong/article/details/107862609
今日推荐