@ControllerAdvice 的介绍及三种用法

@ControllerAdvice 的介绍及三种用法

浅析@ControllerAdvice

首先,ControllerAdvice本质上是一个Component,因此也会被当成组建扫描,一视同仁,扫扫扫。

ControllerAdvice.class

然后,我们来看一下此类的注释:

这个类是为那些声明了(@ExceptionHandler@InitBinder 或 @ModelAttribute注解修饰的)方法的类而提供的专业化的@Component , 以供多个 Controller类所共享。

说白了,就是aop思想的一种实现,你告诉我需要拦截规则,我帮你把他们拦下来,具体你想做更细致的拦截筛选和拦截之后的处理,你自己通过@ExceptionHandler@InitBinder 或 @ModelAttribute这三个注解以及被其注解的方法来自定义。

在这里插入图片描述

初定义拦截规则:

ControllerAdvice 提供了多种指定Advice规则的定义方式,默认什么都不写,则是Advice所有Controller,当然你也可以通过下列的方式指定规则
比如对于 String[] value() default {} , 写成@ControllerAdvice("org.my.pkg") 或者 @ControllerAdvice(basePackages="org.my.pkg"), 则匹配org.my.pkg包及其子包下的所有Controller,当然也可以用数组的形式指定,如:@ControllerAdvice(basePackages={"org.my.pkg", "org.my.other.pkg"}), 也可以通过指定注解来匹配,比如我自定了一个 @CustomAnnotation 注解,我想匹配所有被这个注解修饰的 Controller, 可以这么写:@ControllerAdvice(annotations={CustomAnnotation.class})

还有很多用法,这里就不全部罗列了。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {@AliasFor("basePackages")String[] value() default {};@AliasFor("value")String[] basePackages() default {};Class<?>[] basePackageClasses() default {};Class<?>[] assignableTypes() default {};Class<? extends Annotation>[] annotations() default {};}

1.处理全局异常

@ControllerAdvice 配合 @ExceptionHandler 实现全局异常处理

在这里插入图片描述

用于在特定的处理器类、方法中处理异常的注解

在这里插入图片描述

接收Throwable类作为参数,我们知道Throwable是所有异常的父类,所以说,可以自行指定所有异常

比如在方法上加:@ExceptionHandler(IllegalArgumentException.class),则表明此方法处理

IllegalArgumentException 类型的异常,如果参数为空,将默认为方法参数列表中列出的任何异常(方法抛出什么异常都接得住)。

下面的例子:处理所有IllegalArgumentException异常,域中加入错误信息errorMessage 并返回错误页面error

@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(IllegalArgumentException.class)public ModelAndView handleException(IllegalArgumentException e){ModelAndView modelAndView = new ModelAndView("error");modelAndView.addObject("errorMessage", "参数不符合规范!");return modelAndView;}
}

2.预设全局数据

@ControllerAdvice 配合 @ModelAttribute 预设全局数据

我们先来看看 ModelAttribute注解类的源码

/*** Annotation that binds a method parameter or method return value* to a named model attribute, exposed to a web view. Supported* for controller classes with {@link RequestMapping @RequestMapping}* methods.* 此注解用于绑定一个方法参数或者返回值到一个被命名的model属性中,暴露给web视图。支持在* 在Controller类中注有@RequestMapping的方法使用(这里有点拗口,不过结合下面的使用介绍* 你就会明白的)*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ModelAttribute {@AliasFor("name")String value() default "";@AliasFor("value")String name() default "";boolean binding() default true;}

实际上这个注解的作用就是,允许你往 Model 中注入全局属性(可以供所有Controller中注有@Request Mapping的方法使用),value 和 name 用于指定 属性的 key ,binding 表示是否绑定,默认为 true

具体使用方法如下:

  • 全局参数绑定

    • 方式一:
    @ControllerAdvice
    public class MyGlobalHandler {@ModelAttributepublic void presetParam(Model model){model.addAttribute("globalAttr","this is a global attribute");}
    }
    

    这种方式比较灵活,需要什么自己加就行了,加多少属性自己控制

    • 方式二:
    @ControllerAdvice
    public class MyGlobalHandler {@ModelAttribute()public Map<String, String> presetParam(){Map<String, String> map = new HashMap<String, String>();map.put("key1", "value1");map.put("key2", "value2");map.put("key3", "value3");return map;}}
    

    这种方式对于加单个属性比较方便。默认会把返回值(如上面的map)作为属性的value,而对于key有两种指定方式:

    1. 当 @ModelAttribute() 不传任何参数的时候,默认会把返回值的字符串值作为key,如上例的 key 则是 ”map"(值得注意的是,不支持字符串的返回值作为key)。
    2. 当 @ModelAttribute("myMap") 传参数的时候,则以参数值作为key,这里 key 则是 ”myMap“。
  • 全局参数使用

    @RestController
    public class AdviceController {@GetMapping("methodOne")public String methodOne(Model model){ Map<String, Object> modelMap = model.asMap();return (String)modelMap.get("globalAttr");}@GetMapping("methodTwo")public String methodTwo(@ModelAttribute("globalAttr") String globalAttr){return globalAttr;}@GetMapping("methodThree")public String methodThree(ModelMap modelMap) {return (String) modelMap.get("globalAttr");}}
    

    这三种方式大同小异,其实都是都是从Model 中存储属性的 Map里取数据。

3.请求参数预处理

@ControllerAdvice 配合 @InitBinder 实现对请求参数的预处理

再次之前我们先来了解一下 @IniiBinder,先看一下源码,我会提取一些重要的注释进行浅析

/*** Annotation that identifies methods which initialize the* {@link org.springframework.web.bind.WebDataBinder} which* will be used for populating command and form object arguments* of annotated handler methods.* 粗略翻译:此注解用于标记那些 (初始化[用于组装命令和表单对象参数的]WebDataBinder)的方法。* 原谅我的英语水平,翻译起来太拗口了,从句太多就用‘()、[]’分割一下便于阅读** Init-binder methods must not have a return value; they are usually* declared as {@code void}.* 粗略翻译:初始化绑定的方法禁止有返回值,他们通常声明为 'void'** <p>Typical arguments are {@link org.springframework.web.bind.WebDataBinder}* in combination with {@link org.springframework.web.context.request.WebRequest}* or {@link java.util.Locale}, allowing to register context-specific editors.* 粗略翻译:典型的参数是`WebDataBinder`,结合`WebRequest`或`Locale`使用,允许注册特定于上下文的编辑 * 器。* * 总结如下:*  1. @InitBinder 标识的方法的参数通常是 WebDataBinder。*  2. @InitBinder 标识的方法,可以对 WebDataBinder 进行初始化。WebDataBinder 是 DataBinder 的一* 		           个子类,用于完成由表单字段到 JavaBean 属性的绑定。*  3. @InitBinder 标识的方法不能有返回值,必须声明为void。*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InitBinder {/*** The names of command/form attributes and/or request parameters* that this init-binder method is supposed to apply to.* <p>Default is to apply to all command/form attributes and all request parameters* processed by the annotated handler class. Specifying model attribute names or* request parameter names here restricts the init-binder method to those specific* attributes/parameters, with different init-binder methods typically applying to* different groups of attributes or parameters.* 粗略翻译:此init-binder方法应该应用于的命令/表单属性和/或请求参数的名称。默认是应用于所有命	   		* 令/表单属性和所有由带注释的处理类处理的请求参数。这里指定模型属性名或请求参数名将init-binder		 * 方法限制为那些特定的属性/参数,不同的init-binder方法通常应用于不同的属性或参数组。* 我至己都理解不太理解这说的是啥呀,我们还是看例子吧*/String[] value() default {};
}

我们来看看具体用途,其实这些用途在 Controller里也可以定义,但是作用范围就只限当前Controller,因此下面的例子我们将结合 ControllerAdvice 作全局处理。

  • 参数处理

    @ControllerAdvice
    public class MyGlobalHandler {@InitBinderpublic void processParam(WebDataBinder dataBinder){/** 创建一个字符串微调编辑器* 参数{boolean emptyAsNull}: 是否把空字符串("")视为 null*/StringTrimmerEditor trimmerEditor = new StringTrimmerEditor(true);/** 注册自定义编辑器* 接受两个参数{Class<?> requiredType, PropertyEditor propertyEditor}* requiredType:所需处理的类型* propertyEditor:属性编辑器,StringTrimmerEditor就是 propertyEditor的一个子类*/dataBinder.registerCustomEditor(String.class, trimmerEditor);//同上,这里就不再一步一步讲解了binder.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false));}
    }
    

    这样之后呢,就可以实现全局的实现对 Controller 中RequestMapping标识的方法中的所有 String 和Date类型的参数都会被作相应的处理。

    Controller:

    @RestController
    public class BinderTestController {@GetMapping("processParam")public Map<String, Object> test(String str, Date date) throws Exception {Map<String, Object> map = new HashMap<String, Object>();map.put("str", str);map.put("data", date);return  map;}
    }
    

    测试结果:

在这里插入图片描述
我们可以看出,str 和 date 这两个参数在进入 Controller 的test的方法之前已经被处理了,str 被去掉了两边的空格(%20 在Http url 中是空格的意思),String类型的 1997-1-10被转换成了Date类型。

  • 参数绑定

    参数绑定可以解决特定问题,那么我们先来看看我们面临的问题

    class Person {private String name;private Integer age;// omitted getters and setters.
    }class Book {private String name;private Double price;// omitted getters and setters.
    }@RestController
    public class BinderTestController {@PostMapping("bindParam")public void test(Person person, Book book) throws Exception {System.out.println(person);System.out.println(book);}
    }
    

    我们会发现 Person类和 Book 类都有 name属性,那么这个时候就会出先问题,它可没有那么只能区分哪个name是哪个类的。因此 @InitBinder就派上用场了:

    @ControllerAdvice
    public class MyGlobalHandler {/** @InitBinder("person") 对应找到@RequstMapping标识的方法参数中* 找参数名为person的参数。* 在进行参数绑定的时候,以‘p.’开头的都绑定到名为person的参数中。*/@InitBinder("person")public void BindPerson(WebDataBinder dataBinder){dataBinder.setFieldDefaultPrefix("p.");}@InitBinder("book")public void BindBook(WebDataBinder dataBinder){dataBinder.setFieldDefaultPrefix("b.");}
    }
    

    因此,传入的同名信息就能对应绑定到相应的实体类中:

    p.name -> Person.name b.name -> Book.name

    还有一点注意的是如果 @InitBinder("value") 中的 value 值和 Controller 中 @RequestMapping() 标识的方法的参数名不匹配,则就会产生绑定失败的后果,如:

    @InitBinder(“p”)、@InitBinder(“b”)

    public void test(Person person, Book book)

    上述情况就会出现绑定失败,有两种解决办法

    第一中:统一名称,要么全叫p,要么全叫person,只要相同就行。

    第二种:方法参数加 @ModelAttribute,有点类似@RequestParam

    @InitBinder(“p”)、@InitBinder(“b”)

    public void test(@ModelAttribute(“p”) Person person, @ModelAttribute(“b”) Book book)

如果有不足之处,欢迎在评论区评论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/686844.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

订餐|网上订餐系统|基于springboot的网上订餐系统设计与实现(源码+数据库+文档)

网上订餐系统目录 目录 基于springboot的网上订餐系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户功能模块的实现 &#xff08;1&#xff09;用户注册界面 &#xff08;2&#xff09;用户登录界面 &#xff08;3&#xff09;菜品详情界面 &#xff08…

Codeforces Round 486 (Div. 3)

目录 A. Diverse Team B. Substrings Sort C. Equal Sums D. Points and Powers of Two E. Divisibility by 25 F. Rain and Umbrellas A. Diverse Team 找出不重复的同时存下下标即可&#xff0c;依次遍历map判断重复最后判断数量即可 void solve(){cin>>n>>…

AI专题:5G-A扬帆风正劲,踏AI增长新浪潮

今天分享的是AI系列深度研究报告&#xff1a;《AI专题&#xff1a;5G-A扬帆风正劲&#xff0c;踏AI增长新浪潮》。 &#xff08;报告出品方&#xff1a;开源证券&#xff09; 报告共计&#xff1a;22页 足立连接&#xff0c;拓展算力&#xff0c;双曲线稳步发力 中兴通讯拥…

【论文精读】DALL·E

摘要 本文利用从互联网上收集的2.5亿个图像/文本对数据&#xff0c;训练了一个120亿参数的自回归transformer&#xff0c;进而得到一个可以通过自然语言/图像控制生成的高保真图像生成模型。在大多数数据集上的表现超越以往的方法。 框架 本文的目标为通过训练一个自回归trans…

java+SSM+mysql 开放式实验管理系统78512-计算机毕业设计项目选题推荐(免费领源码)

摘 要 我国高校开放式实验管理普遍存在实验设备使用率较低、管理制度不完善,实验设备共享程度不高等诸多问题。要在更大范围推行开放式实验管理,就必须在开放式实验教学管理流程中,通过引入信息化管理加大信息技术在其中的应用,才能真正发挥这种教学模式的开放性优势。 本系统…

文生视频:Sora模型报告总结

作为世界模拟器的视频生成模型 我们探索视频数据生成模型的大规模训练。具体来说&#xff0c;我们在可变持续时间、分辨率和宽高比的视频和图像上联合训练文本条件扩散模型。我们利用对视频和图像潜在代码的时空补丁进行操作的变压器架构。我们最大的模型 Sora 能够生成一分钟…

小苯的数组切分 ---- 牛客月赛

题目描述 qionghuaqionghuaqionghua 给了小苯一个长度为 n 的数组 a&#xff0c;希望小苯将数组 aaa 分为恰好非空的三段。即&#xff1a;[1,l−1],[l,r],[r1,n]这三段&#xff0c;其中 1< l≤r<n。接着&#xff1a; ∙ 第一段的所有数字做 ⊕&#xff08;按位异或&…

【C语言相关问题】C语言中关于大小写字母转换的问题

大家好&#xff0c;这里是争做图书馆扫地僧的小白。非常感谢各位的支持&#xff0c;也期待着您的关注。 目前博主有着C语言、C、linux以及数据结构的专栏&#xff0c;内容正在逐步的更新。 希望对各位朋友有所帮助同时也期望可以得到各位的支持&#xff0c;有任何问题欢迎私信与…

每日OJ题_算法_递归④力扣24. 两两交换链表中的节点

目录 ④力扣24. 两两交换链表中的节点 解析代码 ④力扣24. 两两交换链表中的节点 24. 两两交换链表中的节点 难度 中等 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即…

【大厂AI课学习笔记】【2.1 人工智能项目开发规划与目标】(2)项目开发周期

我们来学习项目开发的周期。 再次声明&#xff0c;本文来自腾讯AI课的学习笔记&#xff0c;图片和文字&#xff0c;仅用于大家学习&#xff0c;想了解更多知识&#xff0c;请访问腾讯云相关章节。如果争议&#xff0c;请联系作者。 今天&#xff0c;我们来学习AI项目的周期。 主…

17-k8s控制器资源-job控制

job控制器&#xff1a;就是一次性任务的pod控制器&#xff0c;pod完成作业后不会重启&#xff0c;其重启策略是&#xff1a;Never 1&#xff0c;job控制器案例描述 启动一个pod&#xff0c;执行完成一个事件&#xff0c;然后pod关闭&#xff1b; 事件&#xff1a;计算π的值&a…

AI大模型学习笔记之五:监督学习--数据如何驱动决策

监督学习&#xff0c;又称为监督式机器学习&#xff0c;是机器学习和人工智能领域的一个重要分支。 其基本原理是利用带有标签的数据集来训练算法&#xff0c;以实现精确分类数据或预测结果的目标。 在监督学习中&#xff0c;通过将数据输入模型&#xff0c;并不断调整数据权…

软件工程师,为什么不喜欢关电脑

概述 你是否注意到&#xff0c;软件工程师们似乎从不关电脑&#xff0c;也不喜欢关电脑&#xff1f;别以为他们是电脑“上瘾”&#xff0c;或是沉迷于电脑&#xff0c;这一现象背后蕴含着多种实际原因。 1、代码保存与恢复。 在编写代码过程中&#xff0c;遇到问题时可能会暂时…

【JavaScript】面试手写题精讲之数组(下)

引入 这章主要讲的是数组的排序篇&#xff0c;我们知道面试的时候&#xff0c;数组的排序是经常出现的题目。所以这块还是有必要进行一下讲解的。笔者观察了下前端这块的常用算法排序题&#xff0c;大概可以分为如下 冒泡排–> 稳定排序插入排序–> 稳定排序选择排序–…

Swing程序设计(10)列表框,文本框,文本域,密码框

文章目录 前言一、列表框二、文本框&#xff08;域&#xff09; 1.文本框2.文本域三、密码框总结 前言 该篇文章简单介绍了Java中Swing组件里的列表框、文本框、密码框。 一、列表框 列表框&#xff08;JList&#xff09;相比下拉框&#xff0c;自身只是在窗体上占据固定的大小…

【探索Linux】—— 强大的命令行工具 P.22(POSIX信号量)

阅读导航 引言一、POSIX信号量的基本概念二、信号量的相关操作1 . 初始化信号量sem_init ( )&#xff08;1&#xff09;原型&#xff08;2&#xff09;参数&#xff08;3&#xff09;返回值&#xff08;4&#xff09;示例代码 2 . 等待信号量&#xff08;1&#xff09;sem_wait…

高程 | 类与对象(c++)

文章目录 &#x1f4da;面向对象程序设计的基本特点&#x1f407;抽象——概括问题&#xff0c;抽出公共性质并加以描述。&#x1f407;封装——将抽象所得数据和行为相结合&#xff0c;形成一个有机的整体&#xff0c;形成“类”。&#x1f407;继承——在原有类特性的基础上&…

Python爬虫学习

1.1搭建爬虫程序开发环境 爬取未来七天天气预报 from bs4 import BeautifulSoup from bs4 import UnicodeDammit import urllib.request url"http://www.weather.com.cn/weather/101120901.shtml" try:headers{"User-Agent":"Mozilla/5.0 (Windows …

51_蓝桥杯_蜂鸣器与继电器

一 电路 二 蜂鸣器与继电器工作原理 2.1蜂鸣器与继电器 2.2 十六进制与二进制 二进制 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 十六进制 0 1 2 3 4 5 6 7 8 9 A B C D E F 2.3非门 二 代码 …

Java Lambda表达式:简化编程,提高效率

Java Lambda表达式&#xff1a;简化编程&#xff0c;提高效率 1. 使用Lambda表达式进行集合遍历1.1 未使用Lambda表达式&#xff1a;1.2 使用Lambda表达式&#xff1a; 2. 使用Lambda表达式进行排序2.1 未使用Lambda表达式&#xff1a;2.2 使用Lambda表达式&#xff1a; 3. 使用…