SpringBoot统一异常处理(4)

在后端发生异常或者是请求出错时,前端通常显示如下

对于用户来说非常不友好。本文主要讲解如何在SpringBoot应用中使用统一异常处理。

实现方式

第一种:使用@ControllerAdvice和@ExceptionHandler注解

第二种: 使用ErrorController类来实现。

第一种:使用@ControllerAdvice和@ExceptionHandler注解

package com.hanzhenya.learnspringboot.advice;

import com.hanzhenya.learnspringboot.util.ResultInfo;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description: 切面异常处理
 * @author: 韩振亚
 * @date: 2021年03月29日 13:38
 */
@RestControllerAdvice
public class GlobalControllerAdvice{
        private static final String BAD_REQUEST_MSG = "客户端请求参数错误";
        // <1> 处理 form data方式调用接口校验失败抛出的异常 
        @ExceptionHandler(BindException.class)
        public ResultInfo bindExceptionHandler(BindException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        List collect = fieldErrors.stream().map(o ->o.getDefaultMessage()).collect(Collectors.toList());
       return new ResultInfo().success(HttpStatus.BAD_REQUEST.value(), BAD_REQUEST_MSG, collect);
        }
        // <2> 处理 json 请求体调用接口校验失败抛出的异常 
     @ExceptionHandler(MethodArgumentNotValidException.class)
     public ResultInfo methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        List collect = fieldErrors.stream().map(o ->o.getDefaultMessage()).collect(Collectors.toList());
        return new ResultInfo().success(HttpStatus.BAD_REQUEST.value(), BAD_REQUEST_MSG, collect);
        }
        // <3> 处理单个参数校验失败抛出的异常
         @ExceptionHandler(ConstraintViolationException.class)
         public ResultInfo constraintViolationExceptionHandler(ConstraintViolationException e) {
         Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
        List collect = constraintViolations.stream().map(o -> o.getMessage()).collect(Collectors.toList());
        return new ResultInfo().success(HttpStatus.BAD_REQUEST.value(), BAD_REQUEST_MSG, collect);
        }
        }

注解@ControllerAdvice表示这是一个控制器增强类,当控制器发生异常且符合类中定义的拦截异常类,将会被拦截。

可以定义拦截的控制器所在的包路径

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<?>[] assignableTypes() default {};

    Class<? extends Annotation>[] annotations() default {};
}

注解ExceptionHandler定义拦截的异常类

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler {
    Class<? extends Throwable>[] value() default {};
} 

第二种: 使用ErrorController类来实现。

系统默认的错误处理类为BasicErrorController,将会显示如上的错误页面。

这里编写一个自己的错误处理类,上面默认的处理类将不会起作用。

getErrorPath()返回的路径服务器将会重定向到该路径对应的处理类,本例中为error方法。

package com.hanzhenya.learnspringboot.advice;

import com.hanzhenya.learnspringboot.util.ResultInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.jws.WebResult;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Description: TODO
 * @author: 韩振亚
 * @date: 2021年03月31日 14:38
 */
@Slf4j
@RestController
public class HttpErrorController implements ErrorController {

    private final static String ERROR_PATH = "/error";

    @ResponseBody
    @RequestMapping(path  = ERROR_PATH )
    public ResultInfo error(HttpServletRequest request, HttpServletResponse response){
        log.info("访问/error" + "  错误代码:"  + response.getStatus());
        return new ResultInfo().success(response.getStatus(),"请求参数错误","");
    }

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

区别

1.注解@ControllerAdvice方式只能处理控制器抛出的异常。此时请求已经进入控制器中。

2.类ErrorController方式可以处理所有的异常,包括未进入控制器的错误,比如404,401等错误

3.如果应用中两者共同存在,则@ControllerAdvice方式处理控制器抛出的异常,类ErrorController方式处理未进入控制器的异常。

4.@ControllerAdvice方式可以定义多个拦截方法,拦截不同的异常类,并且可以获取抛出的异常信息,自由度更大。

原文地址:https://www.cnblogs.com/h-z-y/p/14600658.html