SpringBoot全局统一异常处理

一、maven相关依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

二、响应码枚举类 StatusCode

package com.lgq.demo.common.constant;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 状态码
 *
 * @Author: guanqin_li
 * @Date: 2020-08-06 10:23
 */
@Getter
@AllArgsConstructor
public enum StatusCode {
    /**
     * 成功
     */
    SUCCESS(200, "SUCCESS"),
    /**
     * 系统繁忙,请稍后重试
     */
    SYS_ERROR(-1, "系统繁忙,请稍后重试"),

    /**
     * 参数错误
     */
    PARAM_ERROR(101, "参数错误"),

    /**
     * 缺少必填参数
     */
    PARAM_MISSING(102, "缺少必填参数"),

    /**
     * 操作失败
     */
    OPERATE_FAILED(302, "操作失败");

    private final int code;
    private final String desc;
}

三、统一响应实体类 Response

package com.lgq.demo.common.pojo;

import com.lgq.demo.common.constant.StatusCode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 响应结果
 *
 * @Author: guanqin_li
 * @Date: 2020-08-06 10:21
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Response {
    /**
     * 响应码
     */
    private int code;
    /**
     * 响应信息
     */
    private String message;
    /**
     * 响应数据
     */
    private Object data;

    public Response setCode(int code) {
        this.code = code;
        return this;
    }

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

    public Response setData(Object data) {
        this.data = data;
        return this;
    }

    public static Response warn(int code, String message, Object data) {
        return Response.builder().code(code).message(message).data(data).build();
    }

    public static Response warn(StatusCode statusCode, Object data) {
        return Response.builder().code(statusCode.getCode()).message(statusCode.getDesc()).data(data).build();
    }

    public static Response warn(int code, String message) {
        return Response.builder().code(code).message(message).build();
    }

    public static Response warn(StatusCode statusCode) {
        return Response.builder().code(statusCode.getCode()).message(statusCode.getDesc()).build();
    }

    public static Response success() {
        return warn(StatusCode.SUCCESS);
    }

    public static Response success(Object data) {
        return warn(StatusCode.SUCCESS.getCode(), StatusCode.SUCCESS.getDesc(), data);
    }

    /**
     * 系统繁忙,请稍后重试
     */
    public static Response error() {
        return warn(StatusCode.SYS_ERROR);
    }

    /**
     * 系统繁忙,请稍后重试
     */
    public static Response error(Object data) {
        return warn(StatusCode.SYS_ERROR, data);
    }
}

四、Http响应结果封装类 HttpResult 和 HttpClientUtil

HttpResult 和 HttpClientUtil 请参考 HttpClient工具类

五、异常处理

  • 业务异常类
package com.lgq.demo.common.exception;

import com.lgq.demo.common.constant.StatusCode;
import lombok.Data;

/**
 * 业务异常
 *
 * @Author: guanqin_li
 * @Date: 2020-09-28 15:30
 */
@Data
public class BizException extends RuntimeException {
    /**
     * 返回给用户的错误码
     */
    private int code;
    /**
     * 返回给用户的错误信息
     */
    private String message;
    /**
     * 日志记录的具体异常信息
     */
    private String error;

    public BizException(StatusCode statusCode) {
        super();
        this.code = statusCode.getCode();
        this.message = statusCode.getDesc();
        this.error = statusCode.getDesc();
    }

    public BizException(StatusCode statusCode, String message) {
        super();
        this.code = statusCode.getCode();
        this.message = message;
        this.error = message;
    }

    public BizException(StatusCode statusCode, String message, String error) {
        super();
        this.code = statusCode.getCode();
        this.message = message;
        this.error = error;
    }
}

  • 全局统一异常处理
package com.lgq.demo.common.exception;

import com.lgq.demo.common.constant.StatusCode;
import com.lgq.demo.common.pojo.Response;
import com.lgq.demo.common.util.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.stream.Collectors;

/**
 * 全局异常处理
 *
 * @Author: guanqin_li
 * @Date: 2020-04-09 9:59
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 校验字段失败的处理
     */
    @ExceptionHandler(BindException.class)
    public Response bindExceptionHandler(HttpServletRequest request, BindException e) {
        FieldError fieldError = e.getBindingResult().getFieldError();
        if (null != fieldError) {
            String message = String.format("[%s]%s", fieldError.getField(), fieldError.getDefaultMessage());
            log.warn("CHECK_PARAM|{}|BindException|{}|{}", null != request ? request.getRequestURI() : "", message, null != request ? HttpClientUtil.getIpAddress(request) : "");
            return Response.warn(StatusCode.PARAM_ERROR).setMessage(message);
        }
        log.warn("CHECK_PARAM|{}|BindException|{}", null != request ? request.getRequestURI() : "", null != request ? HttpClientUtil.getIpAddress(request) : "");
        return Response.warn(StatusCode.PARAM_ERROR);
    }

    /**
     * 校验对象字段失败
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Response constraintViolationExceptionHandler(HttpServletRequest request, ConstraintViolationException e) {
        String message = e.getConstraintViolations().stream().map(constraintViolation -> {
            Path path = constraintViolation.getPropertyPath();
            String fieldName = null;
            for (Path.Node node : path) {
                fieldName = node.getName();
            }
            if (StringUtils.isNotBlank(fieldName)) {
                return String.format("[%s]%s", fieldName, constraintViolation.getMessage());
            } else {
                return null;
            }
        }).collect(Collectors.joining());
        if (StringUtils.isNotBlank(message)) {
            log.warn("CHECK_PARAM|{}|ConstraintViolationException|{}|{}", null != request ? request.getRequestURI() : "", message, null != request ? HttpClientUtil.getIpAddress(request) : "");
            return Response.warn(StatusCode.PARAM_ERROR).setMessage(message);
        }
        log.warn("CHECK_PARAM|{}|ConstraintViolationException|{}", null != request ? request.getRequestURI() : "", null != request ? HttpClientUtil.getIpAddress(request) : "");
        return Response.warn(StatusCode.PARAM_ERROR);
    }

    /**
     * 请求字段参数缺失的处理
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Response constraintViolationExceptionHandler(HttpServletRequest request, MissingServletRequestParameterException e) {
        String message = String.format("[%s]%s", e.getParameterName(), StatusCode.PARAM_MISSING.getDesc());
        log.warn("CHECK_PARAM|{}|MissingServletRequestParameterException|{}{}", null != request ? request.getRequestURI() : "", message, null != request ? HttpClientUtil.getIpAddress(request) : "");
        return Response.warn(StatusCode.PARAM_MISSING).setMessage(message);
    }


    /**
     * json 字段校验失败
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Response methodArgumentNotValidExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException e) {
        FieldError fieldError = e.getBindingResult().getFieldError();
        if (null != fieldError) {
            String message = String.format("[%s]%s", fieldError.getField(), fieldError.getDefaultMessage());
            log.warn("CHECK_PARAM|{}|MethodArgumentNotValidException|{}|{}", null != request ? request.getRequestURI() : "", message, null != request ? HttpClientUtil.getIpAddress(request) : "");
            return Response.warn(StatusCode.PARAM_ERROR).setMessage(message);
        }
        log.warn("CHECK_PARAM|{}|MethodArgumentNotValidException|{}|{}", null != request ? request.getRequestURI() : "", e.getMessage(), null != request ? HttpClientUtil.getIpAddress(request) : "");
        return Response.warn(StatusCode.PARAM_ERROR);
    }

    /**
     * 业务异常处理
     */
    @ExceptionHandler(BizException.class)
    public Response exceptionHandler(HttpServletRequest request, BizException e) {
        log.error("BUSINESS_ERROR|{}|{}|{}|{}", null != request ? request.getRequestURI() : "", e.getMessage(), e.getError(), null != request ? HttpClientUtil.getIpAddress(request) : "", e);
        return Response.warn(e.getCode(), e.getMessage());
    }

    /**
     * 异常处理
     */
    @ExceptionHandler(Exception.class)
    public Response exceptionHandler(HttpServletRequest request, Exception e) {
        log.error("SYS_ERROR|{}|{}: {}|{}", null != request ? request.getRequestURI() : "", e.getClass().getSimpleName(), e.getMessage(), null != request ? HttpClientUtil.getIpAddress(request) : "", e);
        return Response.warn(StatusCode.SYS_ERROR);
    }
}

上一篇:php判断远程资源是否存在


下一篇:JQuery 极致ajax局部和整体刷新