千家信息网

SpringMVC中如何利用@ControllerAdvice和ResponseBodyAdvice接口统一处理返回值

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,SpringMVC中如何利用@ControllerAdvice和ResponseBodyAdvice接口统一处理返回值,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这
千家信息网最后更新 2026年11月03日SpringMVC中如何利用@ControllerAdvice和ResponseBodyAdvice接口统一处理返回值

SpringMVC中如何利用@ControllerAdvice和ResponseBodyAdvice接口统一处理返回值,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

在我们进行Java的Web应用开发时,如何写更少的代码,做更多的事情。如何让开发更容易上手,更专注于业务层面,不需要太关心底层的实现。这里就分享一些我平时在搭建基础框架时候的一些心得体验。

统一处理返回值

在web应用中,通常前后端会定义一个统一的对象来封装返回值,一般除了业务数据之外,可能会包含一些请求相关的数据

例如以下这个对象

  • code来标识整个请求的结果

  • msg用于返回错误信息

  • data用于返回实际的业务数据。

{        "code": 0,        "msg": "success",        "data": {}}

统一封装的好处就是前端可以使用统一的逻辑进行请求处理,能够编写通用代码来处理返回值。

当然这也需要后端做一定的开发。通常我们都是直接写在代码里面,手动去创建一个封装对象,然后将数据set进去,或者是封装类添加一些静态方法之类的。 在大部分情况下,这些工作都是重复的。

ResponseBodyAdvice 的执行流程

今天介绍的这个接口, ResponseBodyAdvice, 这是由SpringMvc提供的一个接口,在消息转换前处理返回值,源码如下:

public interface ResponseBodyAdvice{        boolean supports(MethodParameter returnType, Class> converterType);        T beforeBodyWrite(T body, MethodParameter returnType, MediaType selectedContentType,                        Class> selectedConverterType,                        ServerHttpRequest request, ServerHttpResponse response);}

这个接口在返回值被消息转换器写回前端之前进行处理, 大致处理流程如下:

我们实现这个接口的代码主要在这个方法里被调用 RequestResponseBodyAdviceChain.processBody, 可以看到这一段逻辑很简单

先执行ResponseBodyAdvice.supports看当前切面类是否支持,如果支持再调用ResponseBodyAdvice.beforeBodyWrite方法并返回

返回值会被 HttpMessageConverter.write 接口在进行最终的转换(例如转JSON),然后写回前端

private  Object processBody(@Nullable Object body, MethodParameter returnType, MediaType contentType,                Class> converterType,                ServerHttpRequest request, ServerHttpResponse response) {        for (ResponseBodyAdvice advice : getMatchingAdvice(returnType, ResponseBodyAdvice.class)) {                if (advice.supports(returnType, converterType)) {                        body = ((ResponseBodyAdvice) advice).beforeBodyWrite((T) body, returnType,                                        contentType, converterType, request, response);                }        }        return body;}

ResponseBodyAdvice 的初始化

SpringMVC在初始化的时候, 会调用RequestMappingHandlerAdapter.initControllerAdviceCache,将ResponseBodyAdvice初始化到容器中

里面会调用ControllerAdviceBean.findAnnotatedBeans ,获取所有带有 @ControllerAdvice 注解的类

将所有实现了 ResponseBodyAdvice 接口的Bean放入requestResponseBodyAdviceBeans中, 在之前介绍到的 getAdvice() 方法取得就是该对象。

//代码片段public static List findAnnotatedBeans(ApplicationContext context) {        return Arrays.stream(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, Object.class))                        .filter(name -> context.findAnnotationOnBean(name, ControllerAdvice.class) != null)                        .map(name -> new ControllerAdviceBean(name, context))                        .collect(Collectors.toList());}// 代码片段for (ControllerAdviceBean adviceBean : adviceBeans) {        Class beanType = adviceBean.getBeanType();        if (beanType == null) {                throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);        }        Set attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);        if (!attrMethods.isEmpty()) {                this.modelAttributeAdviceCache.put(adviceBean, attrMethods);        }        Set binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);        if (!binderMethods.isEmpty()) {                this.initBinderAdviceCache.put(adviceBean, binderMethods);        }        if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {                requestResponseBodyAdviceBeans.add(adviceBean);        }        if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {                requestResponseBodyAdviceBeans.add(adviceBean);        }}

了解到这些,我们实现一个通用的返回值处理就很简单了, 只需要实现 ResponseBodyAdvice 接口,并且加上 @ControllerAdvice 注解就可以了

这是我实现的一个,统一封装返回值的实现, 大家可以参考一下,根据自己的业务需求来进行修改

package com.diamondfsd.fast.mvc.advice;import com.diamondfsd.fast.mvc.annotations.IgnoreAware;import com.diamondfsd.fast.mvc.entity.FastResult;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.core.MethodParameter;import org.springframework.http.MediaType;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import java.lang.reflect.Method;import java.util.Map;import java.util.WeakHashMap;/** * 统一返回数据封装 * @author Diamond */@ControllerAdvicepublic class FastMvcResponseBodyAwareAdvice implements ResponseBodyAdvice {    private final Map supportsCache = new WeakHashMap<>();    private final String [] basePackages;    private ObjectMapper objectMapper = new ObjectMapper();    public FastMvcResponseBodyAwareAdvice(String [] basePackages) {        this.basePackages = basePackages;    }    @Override    public boolean supports(MethodParameter returnType, Class> converterType) {        if (supportsCache.containsKey(returnType.getMethod())) {            return supportsCache.get(returnType.getMethod());        }        boolean isSupport = getIsSupport(returnType);        supportsCache.put(returnType.getMethod(), isSupport);        return isSupport;    }    private boolean getIsSupport(MethodParameter returnType) {        Class declaringClass = returnType.getMember().getDeclaringClass();        IgnoreAware classIgnore = declaringClass.getAnnotation(IgnoreAware.class);        IgnoreAware methodIgnore = returnType.getMethod().getAnnotation(IgnoreAware.class);        if (classIgnore != null || methodIgnore != null || FastResult.class.equals(returnType.getGenericParameterType())) {            return false;        }        for (int i = 0; i < basePackages.length; i++) {            if (declaringClass.getPackage().getName().startsWith(basePackages[i])) {                return true;            }        }        return false;    }    @Override    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,                                  Class> selectedConverterType, ServerHttpRequest request,                                  ServerHttpResponse response) {        FastResult result = new FastResult<>();        result.setData(body);        if (returnType.getGenericParameterType().equals(String.class)) {            try {                response.getHeaders().set("Content-Type", "application/json;charset=utf-8");                return objectMapper.writeValueAsString(result);            } catch (JsonProcessingException e) {                e.printStackTrace();            }        }        return result;    }}

看完上述内容,你们掌握SpringMVC中如何利用@ControllerAdvice和ResponseBodyAdvice接口统一处理返回值的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!

接口 处理 统一 代码 方法 封装 数据 业务 对象 前端 更多 开发 内容 就是 时候 注解 流程 消息 片段 逻辑 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 上海喔噻互联网科技有限公司 互联网科技垄断 盈实互联网科技 上海致骋互联网科技 亿账通互联网科技 天扬科技互联网广告 联恩商钥互联网科技有限公司 哈尔滨新华互联网科技 济南和联互联网科技有限公司 哈尔滨新华互联网科技学院 崇明区互联网教育科技诚信经营 链环科技传统企业怎么转型互联网 晋城互联网科技 长沙互联网科技 广州千川互联网科技有限公司 下一代互联网重大应用科技园 半导体行业属于互联网高科技类吗 郑州欣桑互联网科技有限公司 上海万顺科技互联网有限公司招聘 互联网高科技绘画 山东特亿宝互联网科技有限公司 互联网 科技公司 卓越科技互联网 招聘 汉立互联网科技有限公司联系电话 互联网大会黑科技排名 华夏互联网科技业 卡尔迅互联网科技有限公司 互联网领先科技活动 互联网领先科技成果宣传视频 互联网科技创业计划的风险分析
0