SpringBoot中异常的全局处理
背景:
开发过程中碰到的异常不进行处理,默认返回500错误,这样不太符合业务要求,而且会泄露程序代码中一些隐蔽信息,但是一个一个的
try...catch
又会显得过于臃肿
1、Controller层异常统一处理
@ControllerAdvice
是spring提供的一个注解,用于定义全局的异常处理,数据绑定和模型属性的增强。它的主要作用就是集中管理控制器的全局逻辑,例如异常处理,而不需要在每个控制器中重复编写相同的代码。
@ControllerAdvice
作用于类上,可以通过value
或者basePackages
属性指定统一处理的包或者通过basePackageClasses
指定需要统一的类数组,增强注解为@RestControllerAdvice
于@RestController
同理
主要功能(作用于方法上):
- 全局异常处理:通过
@ExceptionHandler
注解,捕获并处理控制器中的抛出的异常,有且仅有一个属性用于指定需要拦截的异常类 - 全局数据绑定:通过
@initBinder
注解,对请求参数进行预处理。 - 全局模型属性:通过
@ModelAttribute
注解为所有控制器提供公共的模型数据
注意:
1、方法返回对象,需要在方法上加上@ResponseBody
注解。
2、这个注解在未指定的情况下,并不能捕获到过滤器中的异常
3、这里捕获的是整个servlet业务层的异常,不仅限于@controller
注解的类,@Service
注解的类同样可以
import cn.zhang.domain.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** @ClassName GlobalExceptionHandler* @Description* @Date 2025/7/31 15:18* @Version 1.0*/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)@ResponseBodypublic CommonResult exceptionHandler(Exception e){log.error("统一全局异常处理:{}",e.getMessage());e.printStackTrace();return CommonResult.error(e.getMessage());}
}
过滤器无法被@ControllerAdvince
捕获的情况
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/*** @ClassName GlobalFilter* @Description* @Date 2025/7/31 15:45* @Version 1.0*/
@Slf4j
@WebFilter(urlPatterns = "/*")
@Component
public class GlobalFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {log.info("这里是过滤器打印的日志");int a= 1/0;filterChain.doFilter(servletRequest, servletResponse);}
}
@Service
注解修饰的类抛出异常
2、Filter过滤器中异常统一处理的三种方式
方式1:在filter中使用try...catch
捕获所有异常
方式2:在过滤器中注入HandlerExceptionResolver
进行异常的抛出,这样就可以在上面的全局异常处理类中处理
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @ClassName GlobalFilter* @Description* @Date 2025/7/31 15:45* @Version 1.0*/
@Slf4j
@WebFilter(urlPatterns = "/*")
@Component
public class GlobalFilter implements Filter {/** 在Filter中注入HandlerExceptionResolver,用于处理异常 **/@Autowired@Qualifier("handlerExceptionResolver")private HandlerExceptionResolver resolver;@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;log.info("这里是过滤器打印的日志");try {int a= 1/0;} catch (Exception e) {//这里捕获之后,使用HandlerExceptionResolver处理异常,可以被全局异常处理类处理。resolver.resolveException(request,response,null,new RuntimeException("这是过滤器异常"));return ;}filterChain.doFilter(servletRequest, servletResponse);}
}
方式3:用到Springboot内置的对异常进行统一处理的Controller–BasicErrorController
import com.alibaba.fastjson.JSONObject;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;
import java.util.Map;/*** @ClassName ErrorController* @Description* @Date 2025/7/31 16:24* @Version 1.0*/
@RestController
public class ErrorController extends BasicErrorController {public ErrorController(ErrorAttributes errorAttributes) {super(errorAttributes,new ErrorProperties());}@Overridepublic ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));HttpStatus httpStatus = getStatus(request);Object errorCode = body.get("status");JSONObject result = new JSONObject();result.put("code", errorCode);result.put("msg",body.get("message"));return new ResponseEntity(result.toString(), httpStatus);}
}
这个父类
BasicErrorController
不仅可以捕获过滤器中的异常,整个SpringBoot中的异常都会被捕获,所以建议不要和@ControllerAdvince
全局异常处理,一起使用,避免处理混乱。