首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【SpringBoot】拦截器 && 统一数据返回格式 && 统一异常处理

【SpringBoot】拦截器 && 统一数据返回格式 && 统一异常处理

原创
作者头像
lirendada
发布2026-07-14 14:55:06
发布2026-07-14 14:55:06
290
举报
文章被收录于专栏:JavaJava

Ⅰ. 拦截器

一、快速入门

拦截器是 Spring 框架提供的核心功能之一,主要用来拦截用户的请求在指定方法前后,根据业务需要执行预先设定的代码

也就是说,允许开发人员提前预定义一些逻辑,在用户的请求响应前后执行。也可以在用户请求前阻止其执行。 在拦截器当中,开发人员可以在应用程序中做一些通用性的操作,比如通过拦截器来拦截前端发来的请求,判断 Session 中是否有登录用户的信息。如果有就可以放行,如果没有就进行拦截。

比如我们去银行办理业务,在办理业务前后,就可以加一些拦截操作:

  1. 办理业务之前,先取号,如果带身份证了就取号成功;
  2. 业务办理结束,给业务办理人员的服务进行评价。

这些就是"拦截器"做的工作。

拦截器的使用步骤分为两步:

  1. 定义拦截器
  2. 注册配置拦截器

定义拦截器:实现 HandlerInterceptor 接口,并重写其指定方法

代码语言:javascript
复制
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("LoginInterceptor 目标方法执行前执行..");
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("LoginInterceptor 目标方法执行后执行");
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("LoginInterceptor 视图渲染完毕后执行,最后执行");
    }
}

SpringMVC 的拦截器有 三个回调方法

  1. preHandle
    1. 在 Controller 方法执行 之前 调用。
    2. 返回 true → 继续往下走;返回 false → 拦截请求,不会再进入 Controller。
  2. postHandle
    1. 在 Controller 方法执行 之后,但是 视图渲染之前 调用。
    2. 如果 Controller 抛了异常,这里不会执行。
  3. afterCompletion
    1. 在整个请求执行完成以后调用。
    2. 不管 Controller 正常执行还是抛了异常,都会执行(类似 Java 的 finally)。
    3. 可以在这里做收尾清理,比如日志打印、资源释放、ThreadLocal.remove()
    4. 👉 请求已经处理完了,响应也准备好返回客户端了,这时候 Spring 才会触发 afterCompletion

注册配置拦截器:实现 WebMvcConfigurer 接口,并重写 addInterceptors() 方法

代码语言:javascript
复制
@Configuration
public class WebConfig implements WebMvcConfigurer {
    // 注入自定义的拦截器对象
    @Autowired
    private LoginInterceptor loginInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册自定义拦截器对象
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**"); // 设置拦截器拦截的请求路径,其中 /** 表示拦截所有请求
    }
}

启动服务,试试访问任意请求,观察后端日志。

可以看到 preHandle 方法执行之后就放行了,开始执行目标方法,目标方法执行完成之后执行 postHandleafterCompletion 方法。

我们把拦截器中 preHandle 方法的返回值改为 false,再观察运行结果。

可以看到,拦截器拦截了请求,没有进行响应。

二、拦截器详解

拦截器的入门程序完成之后,接下来我们来介绍拦截器的使用细节。拦截器的使用细节我们主要介绍两个部分:

  1. 拦截器的拦截路径配置
  2. 拦截器实现原理

1. 拦截路径

拦截路径是指我们定义的这个拦截器,对哪些请求生效。

在注册配置拦截器的时候,通过 addPathPatterns() 方法指定要拦截哪些请求;也可以通过excludePathPatterns() 指定不拦截哪些请求,而 /** 表示拦截所有的请求。

比如用户登录校验,我们希望可以对除了登录之外所有的路径生效。

代码语言:javascript
复制
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    //自定义的拦截器对象
    @Autowired
    private LoginInterceptor loginInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册自定义拦截器对象
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**") // 设置拦截器拦截的请求路径(/**表示拦截所有请求)
                .excludePathPatterns("/user/login") // 设置拦截器排除拦截的路径
                .excludePathPatterns("/**/*.js")    // 排除前端静态资源
                .excludePathPatterns("/**/*.css")
                .excludePathPatterns("/**/*.png")
                .excludePathPatterns("/**/*.html");
    }
}

下面是常见拦截路径设置:

拦截路径

含义

举例

/*

一级路径

能匹配 /user、/book、/login,但不能匹配二级目录及更深的路径,比如 /user/login 访问不到

/**

任意级路径

能匹配 /user、/user/login、/user/reg 所有路径

/book/*

/book 下的一级路径

能匹配 /book/addBook,不能匹配 /book/addBook/1、/book

/book/**

/book 下的任意级路径

能匹配 /book、/book/addBook、/book/addBook/2,不能匹配 /user/login

以上拦截规则可以拦截此项目中的使用URL,包括静态文件(图片文件,JS 和 CSS 等文件)

2. 拦截器执行流程

有了拦截器之后,会在调用 Controller 之前进行相应的业务处理,执行的流程如下图:

  1. 添加拦截器后,执行 Controller 的方法之前,请求会先被拦截器拦截住。执行 preHandle() 方法,这个方法需要返回一个布尔类型的值。如果返回 true,就表示放行本次操作,继续访问 controller 中的方法。如果返回 false,则不会放行(controller中的方法也不会执行)
  2. controller 当中的方法执行完毕后,再回过来执行 postHandle() 这个方法以及 afterCompletion() 方法,执行完毕之后,最终给浏览器响应数据。

3. DispatcherServlet源码分析(了解)

观察服务启动日志:

Tomcat 启动之后,有一个核心的类 DispatcherServlet,它来控制程序的执行顺序。所有请求都会先进到 DispatcherServlet,执行 doDispatch() 调度方法。

如果有拦截器,会先执行拦截器 preHandle() 方法的代码,如果 preHandle() 返回 true,继续访问 controller 中的方法。controller 当中的方法执行完毕后,再回过来执行 postHandle()afterCompletion(),返回给 DispatcherServlet,最终给浏览器响应数据。

① 初始化(了解)

DispatcherServlet 的初始化方法 init() 在其父类 HttpServletBean 中实现的。

主要作用是加载 web.xmlDispatcherServlet 的配置,并调用子类的初始化

init() 具体代码如下:

代码语言:javascript
复制
@Override
public final void init() throws ServletException {
    try {
        // ServletConfigPropertyValues 是静态内部类,使用 ServletConfig 获取 web.xml 中配置的参数
        PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
        
        // 使用 BeanWrapper 来构造 DispatcherServlet
        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
        ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
        bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
        initBeanWrapper(bw);
        bw.setPropertyValues(pvs, true);
    } catch (BeansException ex) {}
    
    // 让子类实现的方法,这种在父类定义在子类实现的方式叫做模版方法模式
    initServletBean();
}

HttpServletBeaninit() 中调用了 initServletBean(),它是在 FrameworkServlet 类中实现的,主要作用是建立 WebApplicationContext 容器,并加载 SpringMVC 配置文件中定义的 Bean 到该容器中,最后将该容器添加到 ServletContext 中。

下面是 initServletBean() 的具体代码:

代码语言:javascript
复制
/**
 * Overridden method of {@linkHttpServletBean}, invoked after any bean properties
 * have been set. Creates this servlet's WebApplicationContext.
 */
@Override
protected final void initServletBean() throws ServletException {
    getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
    if (logger.isInfoEnabled()) {
        logger.info("Initializing Servlet '" + getServletName() + "'");
    }
    long startTime = System.currentTimeMillis();
    try {
        // 创建ApplicationContext容器
        this.webApplicationContext = initWebApplicationContext();
        initFrameworkServlet();
    }
    catch (ServletException | RuntimeException ex) {
        logger.error("Context initialization failed", ex);
        throw ex;
    }
    if (logger.isDebugEnabled()) {
        String value = this.enableLoggingRequestDetails ?
            "shown which may lead to unsafe logging of potentially sensitive data" :
            "masked to prevent unsafe logging of potentially sensitive data";
        logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
                     "': request parameters and headers will be " + value);
    }
    if (logger.isInfoEnabled()) {
        logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
    }
}

此处打印的日志,也正是控制台打印出来的日志。

初始化 web 容器的过程中,会通过 onRefresh 来初始化 SpringMVC 的容器:

代码语言:javascript
复制
protected WebApplicationContext initWebApplicationContext() {
    //...
    if (!this.refreshEventReceived) {
        //初始化Spring MVC
        synchronized (this.onRefreshMonitor) {
            onRefresh(wac);
        }
    }
    return wac;
}

@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

/**
 * Initialize the strategy objects that this servlet uses.
 * <p>May be overridden in subclasses in order to initialize further strategy objects.
 */
protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}

initStrategies() 中进行九大组件的初始化,如果没有配置相应的组件,就使用默认定义的组件。

  1. 初始化文件上传解析器 MultipartResolver
  2. 初始化区域解析器 LocaleResolver
  3. 初始化主题解析器 ThemeResolver
  4. 初始化处理器映射器 HandlerMappings
    1. 通过处理器映射器找到对应的处理器适配器,将请求交给适配器处理;
    2. 缓存每个请求地址 URL 对应的位置(Controller.xxx方法);如果在 ApplicationContext 发现有 HandlerMappings,则从 ApplicationContext 中获取到所有的 HandlerMappings,并进行排序;如果在 ApplicationContext 中没有发现有处理器映射器,则默认 BeanNameUrlHandlerMapping作为处理器映射器
  5. 初始化处理器适配器 HandlerAdapter:作用是通过调用具体的方法来处理具体的请求;如果在 ApplicationContext 发现有 handlerAdapter,则从 ApplicationContext 中获取到所有的 HandlerAdapter,并进行排序;如果在 ApplicationContext 中没有发现处理器适配器,则默认 SimpleControllerHandlerAdapter 作为处理器适配器
  6. 初始化异常处理器解析器 HandlerExceptionResolver
  7. 初始化 RequestToViewNameTranslator:其作用是从 Request 中获取 viewName
  8. 初始化视图解析器 ViewResolvers
  9. 初始化 FlashMapManager:其作用是用于检索和保存 FlashMap(保存从一个 URL 重定向到另一个 URL时的参数信息)

② 处理请求(核心)

DispatcherServlet 接收到请求后,执行 doDispatch 调度方法,再将请求转给 Controller

下面是 doDispatch 方法的具体实现:

代码语言:javascript
复制
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    try {
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
            try {
                processedRequest = this.checkMultipart(request);
                multipartRequestParsed = processedRequest != request;
                
                // 1. 获取执行链
                // 遍历所有的 HandlerMapping 找到与请求对应的 Handler
                mappedHandler = this.getHandler(processedRequest);
                if (mappedHandler == null) {
                    this.noHandlerFound(processedRequest, response);
                    return;
                }
                
                // 2. 获取适配器
                // 遍历所有的 HandlerAdapter,找到可以处理该 Handler 的 HandlerAdapter
                HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                String method = request.getMethod();
                boolean isGet = HttpMethod.GET.matches(method);
                if (isGet || HttpMethod.HEAD.matches(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                
                // 3. 执行拦截器 preHandle 方法
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                
                // 4. 执行目标方法
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                this.applyDefaultViewName(processedRequest, mv);
                
                // 5. 执行拦截器 postHandle 方法
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            } catch (Exception var20) {
                dispatchException = var20;
            } catch (Throwable var21) {
                dispatchException = new NestedServletException("Handler dispatch failed", var21);
            }
            
            // 6. 处理视图, 处理之后执行拦截器 afterCompletion 方法
            this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
        } catch (Exception var22) {
            // 7. 执行拦截器 afterCompletion 方法
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
        } catch (Throwable var23) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
        }
    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else if (multipartRequestParsed) {
            this.cleanupMultipart(processedRequest);
        }
    }
}

HandlerAdapter 主要用于支持不同类型的处理器,如 ControllerHttpRequestHandler 或者 Servlet 等,让它们能够适配统一的请求处理流程。这样,SpringMVC 可以通过一个统一的接口来处理来自各种处理器的请求。

从上述源码可以看出在开始执行 Controller 之前,会先调用预处理方法 applyPreHandle,而 applyPreHandle 方法的实现源码如下:

代码语言:javascript
复制
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
        // 获取项目中使用的拦截器 HandlerInterceptor
        HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
        if (!interceptor.preHandle(request, response, this.handler)) {
            this.triggerAfterCompletion(request, response, (Exception)null);
            return false;
        }
    }
    return true;
}

applyPreHandle 中会获取所有的拦截器 HandlerInterceptor,并执行拦截器中的 preHandle 方法,这样就会咱们前面定义的拦截器对应上了,如下图所示:

  • 如果拦截器返回 true,整个发放就返回 true,继续执行后续逻辑处理;
  • 如果拦截器返回 fasle,则中断后续操作。

Ⅱ. 统一数据返回格式

统一返回格式:后端接口不论成功或失败,都返回一个结构一致的 JSON 格式响应,让前端不必逐个接口判断数据结构,提升开发效率、减少出错。

统一的数据返回格式使用注解 @ControllerAdvice 和实现 ResponseBodyAdvice 接口的方式实现。

@ControllerAdvice:表示控制器通知类

代码语言:javascript
复制
@Slf4j
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    private static ObjectMapper mapper = new ObjectMapper();
    
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }
    
    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 防止包装两次
        if (body instanceof Result){
            return body;
        }
        // 如果返回结果为String类型, 使用SpringBoot内置提供的Jackson来实现信息的序列化
        if (body instanceof String){
            return mapper.writeValueAsString(Result.success(body));
        }
        return Result.success(body);
    }
}
  • supports():判断是否要执行 beforeBodyWrite() 方法。true 为执行,false 不执行。通过该方法可以选择哪些类或哪些方法的 response 要进行处理,其他的不进行处理。
  • beforeBodyWrite():对 response 方法进行具体操作处理。

需要对 String 特别处理的原因分析:因为 SpringMVC 中返回类型为 String 时,会使用 StringHttpMessageConverter,它不会走对象的 JSON 序列化流程,但是返回类型仍然是 JSON,所以一返回时就会出错。

SpringMVC 默认会注册一些自带的 HttpMessageConverter (从先后顺序排列分别为ByteArrayHttpMessageConverterStringHttpMessageConverterSourceHttpMessageConverterSourceHttpMessageConverterAllEncompassingFormHttpMessageConverter),如下所示:

代码语言:java
复制
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
    //...
    public RequestMappingHandlerAdapter() {
        this.messageConverters = new ArrayList<>(4);
        this.messageConverters.add(new ByteArrayHttpMessageConverter());
        this.messageConverters.add(new StringHttpMessageConverter());
        if (!shouldIgnoreXml) {
            try {
                this.messageConverters.add(new SourceHttpMessageConverter<>());
            }
            catch (Error err) {
                // Ignore when no TransformerFactory implementation is available
            }
        }
        this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
    }
    //...
}

其中 AllEncompassingFormHttpMessageConverter 会根据项目依赖情况添加对应的 HttpMessageConverter:

代码语言:java
复制
public AllEncompassingFormHttpMessageConverter() {
    if (!shouldIgnoreXml) {
        try {
            addPartConverter(new SourceHttpMessageConverter<>());
        }
        catch (Error err) {
            // Ignore when no TransformerFactory implementation is available
        }
        if (jaxb2Present && !jackson2XmlPresent) {
            addPartConverter(new Jaxb2RootElementHttpMessageConverter());
        }
    }
    if (kotlinSerializationJsonPresent) {
        addPartConverter(new KotlinSerializationJsonHttpMessageConverter());
    }
    if (jackson2Present) {
        addPartConverter(new MappingJackson2HttpMessageConverter());
    }
    else if (gsonPresent) {
        addPartConverter(new GsonHttpMessageConverter());
    }
    else if (jsonbPresent) {
        addPartConverter(new JsonbHttpMessageConverter());
    }
    if (jackson2XmlPresent && !shouldIgnoreXml) {
        addPartConverter(new MappingJackson2XmlHttpMessageConverter());
    }
    if (jackson2SmilePresent) {
        addPartConverter(new MappingJackson2SmileHttpMessageConverter());
    }
}

在依赖中引入 jackson 包后,容器会把 MappingJackson2HttpMessageConverter 自动注册到 messageConverters 链的末尾。 Spring 会根据返回的数据类型,从 messageConverters 链选择合适的 HttpMessageConverter。 当返回的数据是非字符串时,使用的 MappingJackson2HttpMessageConverter 写入返回对象。 当返回的数据是字符串时,StringHttpMessageConverter 会先被遍历到,这时会认为StringHttpMessageConverter 可以使用。

代码语言:java
复制
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
        implements HandlerMethodReturnValueHandler {
    //...代码省略
    protected <T> void writeWithMessageConverters(@Nullable T value,
            MethodParameter returnType,
            ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
            throws IOException, HttpMediaTypeNotAcceptableException,
            HttpMessageNotWritableException {
        //...代码省略
        if (selectedMediaType != null) {
            selectedMediaType = selectedMediaType.removeQualityValue();
            for (HttpMessageConverter<?> converter : this.messageConverters) {
                GenericHttpMessageConverter genericConverter = (converter
                        instanceof GenericHttpMessageConverter ?
                        (GenericHttpMessageConverter<?>) converter : null);
                if (genericConverter != null ?
                        ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
                        converter.canWrite(valueType, selectedMediaType)) {
                    //getAdvice().beforeBodyWrite 执行之后, body转换成了Result类型的结果
                    body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
                            (Class<? extends HttpMessageConverter<?>>) converter.getClass(),
                            inputMessage, outputMessage);
                    if (body != null) {
                        Object theBody = body;
                        LogFormatUtils.traceDebug(logger, traceOn ->
                                "Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
                        addContentDispositionHeader(inputMessage, outputMessage);
                        if (genericConverter != null) {
                            genericConverter.write(body, targetType, selectedMediaType, outputMessage);
                        }
                        else {
                            //此时cover为StringHttpMessageConverter
                            ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
                        }
                    }
                    else {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Nothing to write: null body");
                        }
                    }
                    return;
                }
            }
        }
        //...代码省略
    }
    //...代码省略
}

在 ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage) 的处理中,调用父类的 write 方法。 由于 StringHttpMessageConverter 重写了 addDefaultHeaders 方法,所以会执行子类的方法。 然而子类 StringHttpMessageConverter 的 addDefaultHeaders 方法定义接收参数为 String,此时泛型 t 为 Result 类型,所以出现类型不匹配 "Result cannot be cast to java.lang.String" 的异常。

Ⅲ. 统一异常处理

统一异常处理使用的是 @ControllerAdvice + @ExceptionHandler 来实现的。

@ControllerAdvice 表示控制器通知类,@ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执行某个通知,也就是执行某个方法事件。

具体代码如下:

代码语言:javascript
复制
import com.example.demo.model.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ResponseBody
@ControllerAdvice
public class ErrorAdvice {
    @ExceptionHandler
    public Object handler(Exception e) {
        return Result.fail(e.getMessage());
    }
}

类名,方法名和返回值可以自定义,重要的是注解。 接口返回为数据时,需要加 @ResponseBody 注解

我们可以针对不同的异常,返回不同的结果:

代码语言:javascript
复制
import com.example.demo.model.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ResponseBody
@ControllerAdvice
public class ErrorAdvice {
    @ExceptionHandler
    public Object handler(Exception e) {
        return Result.fail(e.getMessage());
    }
    
    @ExceptionHandler
    public Object handler(NullPointerException e) {
        return Result.fail("发生NullPointerException:"+e.getMessage());
    }
    
    @ExceptionHandler
    public Object handler(ArithmeticException e) {
        return Result.fail("发生ArithmeticException:"+e.getMessage());
    }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Ⅰ. 拦截器
    • 一、快速入门
    • 二、拦截器详解
      • 1. 拦截路径
      • 2. 拦截器执行流程
      • 3. DispatcherServlet源码分析(了解)
  • Ⅱ. 统一数据返回格式
  • Ⅲ. 统一异常处理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档