SpringBoot全局异常处理

1、为什么要全局异常处理

在实际开发中,如果不处理统一处理异常,那么前端在调用后端提供的接口,就会处理各种的异常结构,对于前端来说那可谓是一场灾难,这对前后端的协作也不友好。比如后端路径:/api/v1/index/user?id=222,如果前端未传入ID,那么SpringBoot就会报如下异常:

{"timestamp":"2021-03-30T15:22:46.139+00:00","status":400,"error":"Bad Request","message":"","path":"/api/v1/index/user"}

或者是我们代码里面自定义异常throw new RuntimeException("用户信息未找到!");,对于Spring Boot来说抛出如下异常:

{"timestamp":"2021-03-30T15:25:55.657+00:00","status":500,"error":"Internal Server Error","message":"","path":"/api/v1/index/users"}

而后端真的异常信息是用户信息未找到!,前端获取到500异常,完全不知后端的具体异常。基于这些就有必要全局统一处理异常。

2、实现全局异常处理

2.1 封装统一结构消息

在实现全局异常处理之前,我们先封装一个统一结构的消息对象。

  • 消息类
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class RestResponse {
    private String code;
    private String message;
    private Object data;
}
  • 异常状态枚举
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum ExceptionStatusEnums {
    OK("0","success"),
    ERROR("1","error");
    private String code;
    private String msg;
}
  • 处理消息的工厂类
import com.tenghu.lf.enums.ExceptionStatusEnums;
import com.tenghu.lf.resp.RestResponse;

public class ResponseFactory {
    private ResponseFactory(){

    }

    public static RestResponse getOkResponse(){
        return new RestResponse(ExceptionStatusEnums.OK.getCode(),ExceptionStatusEnums.OK.getMsg(),null);
    }

    public static RestResponse getOkResponse(String message){
        return new RestResponse(ExceptionStatusEnums.OK.getCode(),message,null);
    }

    public static RestResponse getOkResponse(Object data){
        return new RestResponse(ExceptionStatusEnums.OK.getCode(),ExceptionStatusEnums.OK.getMsg(),data);
    }

    public static RestResponse getOkResponse(String message,Object data){
        return new RestResponse(ExceptionStatusEnums.OK.getCode(),message,data);
    }

    public static RestResponse getErrorMessage(){
        return new RestResponse(ExceptionStatusEnums.ERROR.getCode(),ExceptionStatusEnums.ERROR.getMsg(),null);
    }

    public static RestResponse getErrorMessage(String message){
        return new RestResponse(ExceptionStatusEnums.ERROR.getCode(),message,null);
    }

    public static RestResponse getErrorMessage(String message,Object data){
        return new RestResponse(ExceptionStatusEnums.ERROR.getCode(),message,data);
    }

    public static RestResponse getBuildMessage(String code,String message){
        return new RestResponse(code,message,null);
    }

    public static RestResponse getBuildMessage(String code,String message,Object data){
        return new RestResponse(code,message,data);
    }
}

2.2 实现全局异常

定义一个全局异常处理类,在类上加上@RestControllerAdvice注解,也可以使用@ControllerAdvice注解,只不过使用后者,需要在各个方法上加上@ResponseBody注解

@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理自定义异常
     * @param componentException
     * @return
     */
    @ExceptionHandler(ComponentException.class)
    public RestResponse componentException(ComponentException componentException) {
        componentException.printStackTrace();
        return ResponseFactory.getBuildMessage(componentException.getCode(),componentException.getLocalizedMessage());
    }

    /**
     * 处理请求参数异常
     * @param e
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public RestResponse paramMissingException(MissingServletRequestParameterException e){
        e.printStackTrace();
        return ResponseFactory.getBuildMessage(HttpStatus.INTERNAL_SERVER_ERROR.value()+"",String.format("请求参数:%s不能为空!",e.getParameterName()));
    }

    /**
     * 处理请求体异常
     * @param e
     * @return
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public RestResponse readableException(HttpMessageNotReadableException e){
        e.printStackTrace();
        return ResponseFactory.getBuildMessage(HttpStatus.INTERNAL_SERVER_ERROR.value()+"",String.format("请求参数体不能为空!%s",e.getLocalizedMessage()));
    }

    /**
     * 处理其他未知的运行时异常
     * @param runtimeException
     * @return
     */
    @ExceptionHandler(RuntimeException.class)
    public RestResponse runtimeException(RuntimeException runtimeException) {
        runtimeException.printStackTrace();
        return ResponseFactory.getBuildMessage(HttpStatus.INTERNAL_SERVER_ERROR.value()+"",runtimeException.getLocalizedMessage());
    }

    /**
     * 处理其他异常
     * @param exception
     * @return
     */
    @ExceptionHandler(Exception.class)
    public RestResponse otherException(Exception exception){
        exception.printStackTrace();
        return ResponseFactory.getErrorMessage(exception.getLocalizedMessage());
    }
}

3、测试

  • 访问路径/api/v1/index/user?name=小A,不传name的情况下。
{
    "code": "500",
    "message": "请求参数:name不能为空!",
    "data": null
}
  • 访问路径/api/v1/index/user?name=小A,传name的情况下。
{
    "code": "0",
    "message": "success",
    "data": {
        "id": "1111",
        "name": "小A"
    }
}
  • 访问路径/api/v1/index,不传请求体。
{
    "code": "500",
    "message": "请求参数体不能为空!Required request body is missing: public com.tenghu.lf.resp.RestResponse com.tenghu.lf.controller.IndexController.save(com.tenghu.lf.entity.User)",
    "data": null
}
  • 访问路径/api/v1/index,传请求体。
{
    "code": "0",
    "message": "success",
    "data": null
}

其他就不一一测试了,感兴趣的可以自己尝试下。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小老虎Love

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值