Spring中的@ControllerAdvice和ResponseBodyAdvice详解

 更新时间:2024年01月15日 10:20:20   作者:开源必胜  
这篇文章主要介绍了Spring中的@ControllerAdvice和ResponseBodyAdvice详解,@ControllerAdvice作用于@Controller修饰的类里面的所有方法,ResponseBodyAdvice作用于@ResponseBody注解修饰的方法,它可以对这些方法的返回值进行修改,需要的朋友可以参考下

@ControllerAdvice

@ControllerAdvice作用于@Controller修饰的类里面的所有方法。

它主要有两种作用:

对Controller的入参进行预处理

对Controller中的异常进行全局统一处理

ResponseBodyAdvice

ResponseBodyAdvice作用于@ResponseBody注解修饰的方法,它可以对这些方法的返回值进行修改。

它是一个接口,这个接口有两个函数:

/**
* @param returnType 可以得到方法和参数的相关信息(注解呀,类型呀)
* @param converterType HttpMessageConverter的实现类
* @return 是否对某个接口(被@ResponseBody修饰)的返回值进行修改。如果为true就会调用
*         beforeBodyWrite方法
*/
boolean supports(MethodParameter returnType, 
                Class<? extends HttpMessageConverter<?>> converterType);
/**
* @param body 被@ResponseBody修饰方法的返回值(区别于returnType)
* @param returnType 可以得到方法和参数的相关信息(注解呀,类型呀)
* @param selectedContentType 选中的媒体类型,即以什么格式写出数据(json、xml、text...)
* @param selectedConverterType HttpMessageConverter的实现类的具体类型
* @param request 请求对象
* @param response 响应对象
* @return
*/
T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType,
			Class<? extends HttpMessageConverter<?>> selectedConverterType,
			ServerHttpRequest request, ServerHttpResponse response);

类上注释如下:

Allows customizing the response after the execution of an 
@ResponseBody or a ResponseEntity controller method but
 before the body is written with an HttpMessageConverter.

根据类上的注释可以得知如果满足以下两个条件,则返回值会被ResponseBodyAdvice的beforeBodyWrite方法修改,修改之后的值被HttpMessageConverter写出,返回给前端浏览器。

Controller里的方法被@ResponseBody修饰或者Controller里的方法返回ResponseEntityResponseBodyAdvice的supports方法返回true 注意两者的执行顺序

如果针对异常情况和正常情况我们都做了统一处理,要留意不要重复处理。

示例

新建一个Advice类,它被@ControllerAdvice修饰,又实现了ResponseBodyAdvice接口。我们希望在这个类里面既能实现全局异常处理,又能对后端返回的数据统一封装。

返回结果封装类

在Controller里可以返回任意类型,他们都会被封装到Result的data属性中。

public class Result {
    private int code;
    private String data;
    // getter and seter
}

全局处理异常,全局封装返回值

@ControllerAdvice
public class Advice implements ResponseBodyAdvice {
    //因为这里也加了@ResponseBody注解,所以它的返回值也会被ResponseBodyAdvice 处理一遍
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result he(Exception e) {
        Result res = new Result();
        res.setCode(500);
        res.setData(e.getMessage());
        return res;
    }

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        //返回任意类型都要封装
        return true;
    }

    ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType selectedContentType, Class selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {

        Result res = new Result();
        res.setCode(200);
        //如果返回值是String,直接放到Result里
        if (body instanceof String) {
            res.setData((String) body);
            return res;
        }
        //如果返回值是标准返回格式,就不需要再次封装了
        //如果不加这个判断,异常的结果会被封装两次
        else if (body instanceof Result) {
            return body;
        }
        String dataStr = null;
        try {
            dataStr = objectMapper.writeValueAsString(body);
            res.setData(dataStr);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return res;
    }
}

注意:Advice类加了@ControllerAdvice注解,并实现了ResponseBodyAdvice

接口

简单起见,直接在启动类里面写RESTful接口。一个抛出异常,一个返回一个实体类。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@Controller
public class Demo1Application {

    public static void main(String[] args) {
        SpringApplication.run(Demo1Application.class, args);
    }

    @GetMapping("ex")
    @ResponseBody
    public String ex() throws Exception {
        throw new Exception("异常信息");
    }

    @GetMapping("stu")
    @ResponseBody
    public Stu s() {
        final Stu stu = new Stu();
        stu.setName("zcx");
        stu.setAge(22);
        return stu;
    }
}


class Stu {
    private String name;
    private int age;
    //getter and setter
}

原理

因为被@ResponseBody注解注释的返回值都会被RequestResponseBodyMethodProcessor处理,它里面的 HttpMessageConverter在写出数据时,会先拿到一个RequestResponseBodyAdviceChain,先用RequestResponseBodyAdviceChain里面的responseBodyAdvice对Controller返回值进行处理,再写到浏览器。

拓展

与ResponseBodyAdvice类似的有RequestBodyAdvice,它可以对@RequestBody注释的参数进行额外处理,在使用时注意不要在beforeBodyRead里面把inputMessage的body读出来,否则会有I/O异常。可以使用afterBodyRead对参数进行修改。

到此这篇关于Spring中的@ControllerAdvice和ResponseBodyAdvice详解的文章就介绍到这了,更多相关@ControllerAdvice和ResponseBodyAdvice内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java内存区域与内存溢出异常分析与解决

    Java内存区域与内存溢出异常分析与解决

    在 Java 开发中,内存管理和内存溢出异常是一个至关重要的主题,本文将深入探讨 Java 的内存区域及其对应的内存溢出异常,希望对大家有所帮助
    2025-05-05
  • 详解spring整合hibernate的方法

    详解spring整合hibernate的方法

    这篇文章主要介绍了spring整合hibernate的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-02-02
  • Java编程关于子类重写父类方法问题的理解

    Java编程关于子类重写父类方法问题的理解

    这篇文章主要介绍了Java编程关于子类重写父类方法问题的理解,分享了有关子类重写父类的实例,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Spring Cloud Feign实现动态URL

    Spring Cloud Feign实现动态URL

    本文主要介绍了Spring Cloud Feign实现动态URL,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • Java实现简易学籍管理系统

    Java实现简易学籍管理系统

    这篇文章主要为大家详细介绍了Java实现简易学籍管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • Java使用Spire.Presentation在PowerPoint中添加或删除表格行与列

    Java使用Spire.Presentation在PowerPoint中添加或删除表格行与列

    在日常开发中,Java 开发者常需自动化生成报告PPT,手动编辑PowerPoint 表格行与列效率低下,尤其批量操作时易出错,Spire.Presentation for Java 库提供高效解决方案,本文分享实用代码与步骤,助你快速上手,需要的朋友可以参考下
    2026-02-02
  • 冒泡排序算法原理及JAVA实现代码

    冒泡排序算法原理及JAVA实现代码

    关键字较小的记录好比气泡逐趟上浮,关键字较大的记录好比石块下沉,每趟有一块最大的石块沉底
    2014-01-01
  • java支付宝即时到帐提交订单功能

    java支付宝即时到帐提交订单功能

    这篇文章主要为大家详细介绍了java支付宝即时到帐提交订单功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • 扒一扒 Java 中的枚举类型

    扒一扒 Java 中的枚举类型

    这篇文章主要给大家介绍了Java中枚举类型的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-12-12
  • Druid(新版starter)在SpringBoot下的使用教程

    Druid(新版starter)在SpringBoot下的使用教程

    Druid是Java语言中最好的数据库连接池,Druid能够提供强大的监控和扩展功能,DruidDataSource支持的数据库,这篇文章主要介绍了Druid(新版starter)在SpringBoot下的使用,需要的朋友可以参考下
    2023-05-05

最新评论