Spring中的@ControllerAdvice和ResponseBodyAdvice详解
@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多态和实现接口的类的对象赋值给接口引用的方法(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧2017-02-02bug解决Failed_to_execute_goal_org.springframework
这篇文章主要为大家介绍了bug解决Failed_to_execute_goal_org.springframework,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-09-09SpringBoot+SpringCloud用户信息微服务传递实现解析
这篇文章主要介绍了SpringBoot+SpringCloud实现登录用户信息在微服务之间的传递,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2019-11-11Java利用openoffice将doc、docx转为pdf实例代码
这篇文章主要介绍了Java利用openoffice将doc、docx转为pdf实例代码,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下2018-01-01java 中HashMap、HashSet、TreeMap、TreeSet判断元素相同的几种方法比较
这篇文章主要介绍了从源码的角度浅析HashMap、TreeMap元素的存储和获取元素的逻辑;从Map与Set之间的关系浅析常用的Set中元素的存储和判断是否重复的逻辑,需要的朋友可以参考下2017-01-01解决微服务下Mybatis xml无效绑定问题及分析Invalid bound statement
这篇文章主要介绍了解决微服务下Mybatis xml无效绑定问题及分析Invalid bound statement,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2023-11-11Spring中@EnableScheduling实现定时任务代码实例
这篇文章主要介绍了Spring中@EnableScheduling实现定时任务代码实例,@EnableScheduling 注解开启定时任务功能,可以将多个方法写在一个类,也可以分多个类写,当然也可以将方法直接写在上面ScheddulConfig类中,需要的朋友可以参考下2024-01-01
最新评论