spring的@ControllerAdvice注解

@ControllerAdvice注解是Spring3.2中新增的注解,学名是Controller增强器,作用是给Controller控制器添加统一的操作或处理。

对于@ControllerAdvice,我们比较熟知的用法是结合@ExceptionHandler用于全局异常的处理,但其作用不止于此。ControllerAdvice拆开来就是Controller Advice,关于Advice,在Spring的AOP中,是用来封装一个切面所有属性的,包括切入点和需要织入的切面逻辑。这里ControllerAdvice也可以这么理解,其抽象级别应该是用于对Controller进行切面环绕的,而具体的业务织入方式则是通过结合其他的注解来实现的。@ControllerAdvice是在类上声明的注解,其用法主要有三点

1.结合方法型注解@ExceptionHandler,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的。

2.结合方法型注解@InitBinder,用于request中自定义参数解析方式进行注册,从而达到自定义指定格式参数的目的。

3.结合方法型注解@ModelAttribute,表示其注解的方法将会在目标Controller方法执行之前执行。

从上面的讲解可以看出,@ControllerAdvice的用法基本是将其声明在某个bean上,然后在该bean的方法上使用其他的注解来指定不同的织入逻辑。不过这里@ControllerAdvice并不是使用AOP的方式来织入业务逻辑的,而是Spring内置对其各个逻辑的织入方式进行了内置支持。

@ControllerAdvice注解的使用

@ControllerAdvice
public class SpringControllerAdvice {/*** 应用到所有被@RequestMapping注解的方法,在其执行之前初始化数据绑定器* @param binder*/@InitBinderpublic void initBinder(WebDataBinder binder) {}/*** 把值绑定到Model中,使全局@RequestMapping可以获取到该值* @param model*/@ModelAttributepublic void addAttributes(Model model) {model.addAttribute("words", "hello world");}/*** 全局异常捕捉处理* @param ex* @return*/@ResponseBody@ExceptionHandler(value = Exception.class)public Map errorHandler(Exception ex) {Map map = new HashMap();map.put("code", 100);map.put("msg", ex.getMessage());return map;}}

在启动应用之后,被@ExceptionHandler、@InitBinder和@ModelAttribute注解的方法都会作用在被@RequestMappping注解的方法上。比如上面的@ModelAttribute注解的方法参数model上设置的值,所有被@RequestMapping注解的方法中都可以通过ModelMap获取。

@RequestMapping("/index")
public String index(ModelMap modelMap) {System.out.println(modelMap.get("words"));
}// 也可以通过@ModelAttribute获取
@RequestMapping("/index")
public String index(@ModelAttribute("words") String words) {System.out.println(words);
}

下面对@ControllerAdvice三种使用方式进行分别讲解。

@ExceptionHandler拦截异常并统一处理

@ExceptionHandler的作用主要在于声明一个或多个类型的异常,当符合条件的Controller抛出这些异常之后将会对这些异常进行捕获,然后按照其标注的方法的逻辑进行处理,从而改变返回的视图信息。

@ExceptionHandler的属性结构

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler {// 指定需要捕获的异常的Class类型Class<? extends Throwable>[] value() default {};
}

使用@ExceptionHandler捕获RuntimeException异常的例子

@ControllerAdvice
public class SpringControllerAdvice {@ExceptionHandler(RuntimeException.class)public ModelAndView runtimeExceptionHandler(RuntimeException e) {e.printStackTrace();return new ModelAndView("error");}
}
@Controller
public class UserController {@RequestMapping(value = "/users", method = RequestMethod.GET)public void users() {throw new RuntimeException("没有任何用户。");}
}

这样,当访问/users的时候,因为在该方法中抛出了RuntimeException,那么理论上这里的异常捕获器就会捕获该异常,然后返回我们定义的异常视图(默认的error视图)。

使用@InitBinder绑定一些自定义参数

对于@InitBinder,该注解的主要作用是绑定一些自定义的参数。一般情况下我们使用的参数通过@RequestParam,@RequestBody或者@ModelAttribute等注解就可以进行绑定了,但对于一些特殊类型参数,比如Date,它们的绑定Spring是没有提供直接的支持的,我们只能为其声明一个转换器,将request中字符串类型的参数通过转换器转换为Date类型的参数,从而供给@RequestMapping标注的方法使用。

@InitBinder的属性结构

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InitBinder {// 这里value参数用于指定需要绑定的参数名称,如果不指定,则会对所有的参数进行适配,// 只有是其指定的类型的参数才会被转换String[] value() default {};
}

使用@InitBinder注册Date类型参数转换器的实现

@ControllerAdvice
public class SpringControllerAdvice {@InitBinderpublic void globalInitBinder(WebDataBinder binder) {binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));}
}
@Controller
public class UserController {@RequestMapping(value = "/users", method = RequestMethod.GET)public void users(Date date) {System.out.println(date); // Tue May 02 00:00:00 CST 2019}
}

这里@InitBinder标注的方法注册的Formatter在每次request请求进行参数转换时都会调用,用于判断指定的参数是否为其可以转换的参数。可以看到当访问/users的时候,对request参数进行了转换,并且在接口方法中成功接收了该参数,并在控制台打印出日期格式的结果。

使用@ModelAttribute在方法执行前进行一些操作

关于@ModelAttribute的用法,除了用于方法参数时可以用于转换对象类型的属性之外,其还可以用来进行方法的声明。如果声明在方法上,并且结合@ControllerAdvice,该方法将会在@ControllerAdvice所指定的范围内的所有接口方法执行之前执行,并且@ModelAttribute标注的方法的返回值还可以供给后续会调用的接口方法使用。

@ModelAttribute的属性结构

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ModelAttribute {// 该属性与name属性的作用一致,用于指定目标参数的名称@AliasFor("name")String value() default "";@AliasFor("value")String name() default "";// 与name属性一起使用,如果指定了binding为false,那么name属性指定名称的属性将不会被处理boolean binding() default true;
}

这里@ModelAttribute的各个属性值主要是用于其在接口方法参数上进行标注时使用的,如果是作为方法注解,其name或value属性则指定的是返回值的名称。

使用@ModelAttribute注解进行方法标注的一个例子

@ControllerAdvice
public class SpringControllerAdvice {@ModelAttribute(value = "message")public String globalModelAttribute() {System.out.println("添加了message全局属性。");return "输出了message全局属性。";}
}
@Controller
public class UserController {@RequestMapping(value = "/users", method = RequestMethod.GET)public void users(@ModelAttribute("message") String message) {System.out.println(message);}
}

这里@ModelAttribute注解的方法提供了一个String类型的返回值,而@ModelAttribute注解中指定了该属性的名称是message,这样在Controller层就可以通过@ModelAttribute注解接收名称为message的参数,从而获取到前面绑定的参数了。

添加了message全局属性。
输出了message全局属性。

从输出结果上看,使用@ModelAttribute注解标注的方法确实在目标方法执行之前执行了。需要说明的是,@ModelAttribute标注的方法的执行是在所有的拦截器的preHandle()方法执行之后才会执行。

小结

关于@ControllerAdvice注解的三种使用方式对应的注解,这三种注解如果应用于@ControllerAdvice注解所标注的类中,那么它们表示会对@ControllerAdvice所指定的范围内的方法都有效;如果单纯地将这三种注解应用于某个Controller中,那么它们将只会对该Controller类中的所有接口有效,并且此时是不需要在该Controller上标注@ControllerAdvice注解的。

另外的还有@RestControllerAdvice注解,用法和@ControllerAdvice注解类似,只是当需要返回值到响应头的时候就不用在方法上添加@ResponseBody注解了。

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

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

相关文章

mysql游标的用法及作用_Mysql 游标的用法及其作用

mysql 游标的用法和作用&#xff0c;话不多说&#xff0c;这个是网上看到的例子&#xff0c;简答粗暴。例子&#xff1a;当前有三张表a、b、c其中a和b是一对多关系&#xff0c;b和c是一对多关系&#xff0c;现在需要将b中a表的主键存到c中&#xff1b;常规思路就是将b中查询出来…

@ControllerAdvice实现优雅地处理异常

ControllerAdvice&#xff0c;是Spring3.2提供的新注解,它是一个Controller增强器,可对controller中被 RequestMapping注解的方法加一些逻辑处理。最常用的就是异常处理 统一异常处理 需要配合ExceptionHandler使用。 当将异常抛到controller时,可以对异常进行统一处理,规定返…

python django图书管理系统_Python框架:Django写图书管理系统(LMS)

Django模版文件配置文件路径 test_site -- test_site -- settings.pyTEMPLATES [ { BACKEND: django.template.backends.django.DjangoTemplates, DIRS: [os.path.join(BASE_DIR, "template")], # template文件夹位置 APP_DIRS: True, OPTIONS: { context_processor…

springsecurity中session失效后怎样处理_结合Spring Security进行web应用会话安全管理

结合Spring Security进行web应用会话安全管理在本文中&#xff0c;将为大家说明如何结合Spring Security 管理web应用的会话。如果您阅读后觉得本文对您有帮助&#xff0c;期待您能关注、转发&#xff01;您的支持是我不竭的创作动力&#xff01;一、Spring Security创建使用se…

如何把数据库从sql变成mysql_如何将数据库从SQL Server迁移到MySQL

一、迁移Database Schema。首先使用Sybase Powerdesigner的逆向工程功能&#xff0c;逆向出SQL Server数据库的物理模型。具体操作是在Powerdesigner中选择“File”&#xff0c;“Reverse Engine”再选择Database&#xff0c;将DBMS选择为SQL Server&#xff0c;如图&#xff1…

mysql查询单词出现的位置_在MySQL中从左侧获取一些单词

为此&#xff0c;请在MySQL中使用LEFT。让我们首先创建一个表-mysql> create table DemoTable-> (-> Title text-> );使用插入命令在表中插入一些记录-mysql> insert into DemoTable values(Java database connectivity to MySQL database);mysql> insert in…

linux转mysql_[转] linux下安装mysql服务器

[转自&#xff1a;http://www.extmail.org/forum/archive/2/0510/563.html]安装MySQL服务器你可以根据服务器的CPU类型&#xff0c;下载适合你所用CPU和操作系统的MySQL发行包。从下面的URL下载MySQL 4.1.16以tar.gz形式发布的二进制发行包&#xff1a;http://www.mysql.com增加…

mysql数据库开发要求_MYSQL数据库开发规范

MYSQL数据库开发规范(一) 建表规约1.【推荐】表达是与否概念的字段&#xff0c;必须使用 is_xxx 的方式命名&#xff0c;数据类型是 unsigned tinyint ( 1 表示是&#xff0c;0 表示否)。说明&#xff1a;任何字段如果为非负数&#xff0c;必须是 unsigned。正例&#xff1a;表…

HTTP 学习,程序员不懂网络怎么行,一篇HTTP入门 不收藏都可惜

文章目录&#x1f4e2;前言HTTP 必备干货学习&#xff0c;程序员不懂网络怎么行HTTP 协议五个特点&#xff1a;网络结构图解HTTP概述&#x1f3f3;️‍&#x1f308;基于 HTTP 的系统的组件客户端&#xff1a;用户代理网络服务器代理HTTP 的基本方面HTTP 很简单HTTP 是可扩展的…

docker mysql5.7 主从_docker-compose mysql5.7.30 主从

一、安装mysql5.7.30主库1.准备docker和docker-compose环境2.创建yml目录&#xff0c;相关数据挂载#yml存放的目录mkdir -p /root/docker-compse/mysql#主库的/var/lib/mysql 数据的挂载目录mkdir -p /data/mysql5matser#不用slave 了&#xff0c;用replication的缩写replic , …

Java面试——Redis系列总结

文章目录&#xff1a; 1.什么是Redis&#xff1f; 2.为什么要用 Redis / 为什么要用缓存&#xff1f; 3.Redis为什么这么快&#xff1f; 4.Redis都有哪些数据类型&#xff1f; 5.什么是Redis持久化&#xff1f;Redis 的持久化有哪些实现方式&#xff1f; 6.什么是Redis事…

使用ping时遇到 Time to live exceeded

环境&#xff1a;Ubuntu服务器&#xff0c;带有两块物理网卡&#xff0c;分别连接两个局域网&#xff0c;所处网络环境复杂。 网卡1地址为192.168.5.100 网卡2地址为10.172.172.100 网卡1的路由为默认路由&#xff0c;网关为192.168.5.254 网卡2路由到网关10.172.150.254&a…

python 手机编程termux_如何优雅的在手机上进行Python编程?

其实谈不上优雅&#xff0c;编程还是老老实实在电脑编程更实用&#xff0c;手机只是某种程度上做一些便捷性的操作。回到主题&#xff0c;下面介绍两个常用的Python编程工具。第一款&#xff1a;TermuxTermux是一个安卓手机的 Linux 模拟器&#xff0c;可以在手机上模拟 Linux …

python打飞机源码_python 飞机大战 游戏源码(pygame入门级)

l文件 35644 2018-09-21 12:27 飞机大战03\.idea\workspace.xml文件 398 2018-09-19 09:42 飞机大战03\.idea\飞机大战.iml文件 5082 2018-09-21 11:23 飞机大战03\bin\planefight.py文件 0 2018-09-19 09:34 飞机大战03\bin\__init__.py文…

java运行环境_Windows系统java运行环境配置 | 吴文辉博客

在进行java开发之前&#xff0c;我们最重要的步骤就是如何获取JDK版本及正确的安装、配置java环境。只有正确的安装了java运行环境&#xff0c;才能继续java的学习和实践。一、下载JDK安装1、我系统是win7 64位&#xff0c;所以我下载了jdk-8u74-windows-x64&#xff1b;下载地…

鉴权必须了解的5个知识点:cookie,session,token,jwt,单点登录

从状态说起 [HTTP 无状态] 我们知道&#xff0c;HTTP是无状态的&#xff0c;也就是说&#xff0c;HTTP请求方和响应方间无法维护状态&#xff0c;都是一次性的&#xff0c;它不知道前后的请求都发生了什么 但有的场景下&#xff0c;我们需要维护状态&#xff0c;最常见的&am…

一个java类可以有_一个.java文件中可以有几个同级类?

1、在一个.java文件中可以有多个同级类(和public一样的位置&#xff0c;注意不是内部类).其修饰符只可以public&#xff0f;abstract&#xff0f;final&#xff0f;和无修饰符&#xff0c;不能是其他的protected/private等修饰符。所以protected类虽然可以在包内访问&#xff0…

java中的关键字有哪些_Java关键字有哪些?

Abstract 抽象的一个Java语言中的关键字&#xff0c;用在类的声明中来指明一个类是不能被实例化的&#xff0c;但是可以被其它类继承。一个抽象类可以使用抽象方法&#xff0c;抽象方法不需要实现&#xff0c;但是需要在子类中被实现break一个Java的关键字&#xff0c;用来改变…

如何实现session共享的几种解决方案?

先了解一下为什么会出现这种session共享的解决方案&#xff1f; 随着互联网公司的项目在微服务和分布式的环境下进行的搭建&#xff0c;导致一个项目可能分别部署在几个甚至很多的服务器集群下&#xff0c;此时就会出现一个问题当用户进行一个session会话的时候&#xff0c;比…

java类继承语法_java类的继承(基础)

---恢复内容开始---这篇随笔和大家讲讲java中类的继承是什么&#xff1f;希望对你们有所帮助。目录一、java继承是什么&#xff1f;二、为什么使用java继承三、java继承的实现1.1 java继承的基本语法1.2 super的用法一、Java继承是什么&#xff1f;简单来讲&#xff0c;Java中…