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 线程池的相关资料,并符实例代码,帮助大家学习参考,需要的朋友可以参考下
    2016-09-09
  • MyBatis之foreach标签的用法及多种循环问题

    MyBatis之foreach标签的用法及多种循环问题

    这篇文章主要介绍了MyBatis之foreach标签的用法及多种循环问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Java集合排序规则接口Comparator用法解析

    Java集合排序规则接口Comparator用法解析

    这篇文章主要介绍了Java集合排序规则接口Comparator用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • 解决idea中maven新增的配置文件xx.xml没生效问题

    解决idea中maven新增的配置文件xx.xml没生效问题

    这篇文章主要介绍了如何解决idea中maven新增的配置文件xx.xml没生效问题,公司项目有用自己的`私服,Maven正常去私服下载jar包是没问题的,但阿里云镜像找不到相关的jar包报错,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2024-06-06
  • mybatis-plus自带QueryWrapper自定义sql实现复杂查询实例详解

    mybatis-plus自带QueryWrapper自定义sql实现复杂查询实例详解

    MyBatis-Plus是一个MyBatis(opens new window)的增强工具,在 MyBatis的基础上只做增强不做改变,MyBatis可以无损升级为MyBatis-Plus,这篇文章主要给大家介绍了关于mybatis-plus自带QueryWrapper自定义sql实现复杂查询的相关资料,需要的朋友可以参考下
    2022-10-10
  • Spring异常捕获且回滚事务解决方案

    Spring异常捕获且回滚事务解决方案

    这篇文章主要介绍了Spring异常捕获且回滚事务解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • java两个List的交集,并集方式

    java两个List的交集,并集方式

    文章主要介绍了Java中两个List的交集和并集的处理方法,推荐使用Apache的CollectionUtils工具类,因为它简单且不会改变原有集合,同时,文章还讨论了Arrays.asList的局限性和JDK1.8中Stream新特性的使用
    2025-03-03
  • Java中的原生post请求方式

    Java中的原生post请求方式

    这篇文章主要介绍了Java中的原生post请求方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • 在AOP中Spring生成代理类的两种方式

    在AOP中Spring生成代理类的两种方式

    今天小编就为大家分享一篇关于在AOP中Spring生成代理类的两种方式,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • Java 手动解析不带引号的JSON字符串的操作

    Java 手动解析不带引号的JSON字符串的操作

    这篇文章主要介绍了Java 手动解析不带引号的JSON字符串的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10

最新评论