当前位置: 首页 > news >正文

SpringMVC自定义注解---[详细介绍]

一,对于SpringMVC自定义注解概念

       是一种特殊的 Java 注解,它允许开发者在代码中添加自定义的元数据,并且可以在运行时使用反射机制来获取和处理这些信息。在 Spring MVC 中,自定义注解通常用于定义控制器、请求处理方法、参数或者其他相关组件的行为

创建和使用由开发者自行编写,可以根据具体需求定义注解元素,并编写相应的注解处理器和逻辑来处理注解可用于标记特定的类、方法或参数

1.2 java注解的分类(主三种)

基本注解:

@Override:用于标记一个方法覆盖了父类或接口的方法。

@Deprecated用于标记一个类、方法或字段已经过时,不推荐使用。

@SuppressWarnings(value = "unchecked")用于抑制编译器产生的警告信息

元注解:

@Retention指定注解的生命周期,包括 RetentionPolicy.SOURCERetentionPolicy.CLASS 和 RetentionPolicy.RUNTIME

@Target指定注解的应用目标,包括 ElementType.TYPEElementType.FIELD

ElementType.METHOD 等。

@Documented指示注解是否包含在 Java 文档中。

@Inherited指示注解是否可以被继承。

@Repeatable指示注解可以多次应用于同一元素。

注:可以指定多个位置,例如:
@Target({ElementType.METHOD, ElementType.TYPE}),也就是此注解可以在方法和类上面使用

@Inherited:指定被修饰的Annotation将具有继承性

@Documented:指定被修饰的该Annotation可以被javadoc工具提取成文档.

自定义注解:

注解分类(根据Annotation是否包含成员变量,可以把Annotation分为两类):

标记Annotation:
没有成员变量的Annotation; 这种Annotation仅利用自身的存在与否来提供信息

元数据Annotation:
包含成员变量的Annotation; 它们可以接受(和提供)更多的元数据;

注意:自定义注解只是一种提供元数据的机制,具体的处理逻辑需要通过注解处理器来实现。在使用自定义注解时,需要编写注解处理器来解析注解,并执行相应的行为。

1.3 如何使用自定义注解

使用@interface关键字, 其定义过程与定义接口非常类似, 需要注意的是:
Annotation的成员变量在Annotation定义中是以无参的方法形式来声明的, 其方法名和返回值类型定义了该成员变量的名字和类型。而且我们还可以使用default关键字为这个成员变量设定默认值

二,使用自定义注解

案例一(获取类与方法上的注解值)

定义一个Package名为annotation包定义TranscationModel类

package com.Bingzy.annotation;public enum  TranscationModel {Read, Write, ReadWrite;private Integer id;private String name;public void init1(){Read.id=1;Read.name="zs";}public void init2(){Write.id=2;Write.name="lisi";}public void init3(){ReadWrite.id=3;ReadWrite.name="wangwu";}
}

在annotation包下再创建测试类test01:

package com.Bingzy.annotation;/*** @Name BingBing* @company zking cy* @create 2023-09-14-19:43*/
public class Test01 {public static void main(String[] args) {System.out.println(TranscationModel.Read);System.out.println(TranscationModel.Write);System.out.println(TranscationModel.ReadWrite);}
}

在annotation包下再创建一个Package包Demo01 方便测试案例一:

创建三个注解类:

MyAnnotation1类:

@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation1 {String name();
}

MyAnnotation2类:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {TranscationModel model() default TranscationModel.ReadWrite;
}

MyAnnotation3类:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation3 {TranscationModel[] models() default TranscationModel.ReadWrite;
}

在Demo01包下创建测试类代码

Demo1:

@MyAnnotation1(name = "abc")
public class Demo1 {@MyAnnotation1(name = "xyz")private Integer age;@MyAnnotation2(model = TranscationModel.Read)public void list() {System.out.println("list");}@MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write})public void edit() {System.out.println("edit");}
}

Demo1Test:

public class Demo1Test {@Testpublic void list() throws Exception {
//        获取类上的注解MyAnnotation1 annotation1 = Demo1.class.getAnnotation(MyAnnotation1.class);System.out.println(annotation1.name());//abc//        获取方法上的注解MyAnnotation2 myAnnotation2 = Demo1.class.getMethod("list").getAnnotation(MyAnnotation2.class);System.out.println(myAnnotation2.model());//Read//        获取属性上的注解MyAnnotation1 myAnnotation1 = Demo1.class.getDeclaredField("age").getAnnotation(MyAnnotation1.class);System.out.println(myAnnotation1.name());// xyz}@Testpublic void edit() throws Exception {MyAnnotation3 myAnnotation3 = Demo1.class.getMethod("edit").getAnnotation(MyAnnotation3.class);for (TranscationModel model : myAnnotation3.models()) {System.out.println(model);//Read,Write}}
}

测试结果:

案例二(获取类属性上的注解属性值)

注解类:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TestAnnotation {String value() default "默认value值";String what() default "这里是默认的what属性对应的值";
}

测试类Demo2类

public class Demo2 {@TestAnnotation(value = "这就是value对应的值_msg1", what = "这就是what对应的值_msg1")private static String msg1;@TestAnnotation("这就是value对应的值1")private static String msg2;@TestAnnotation(value = "这就是value对应的值2")private static String msg3;@TestAnnotation(what = "这就是what对应的值")private static String msg4;
}

Demo2Test:

public class Demo2Test {@Testpublic void test1() throws Exception {TestAnnotation msg1 = Demo2.class.getDeclaredField("msg1").getAnnotation(TestAnnotation.class);System.out.println("test1");System.out.println(msg1.value());System.out.println(msg1.what());}@Testpublic void test2() throws Exception{TestAnnotation msg2 = Demo2.class.getDeclaredField("msg2").getAnnotation(TestAnnotation.class);System.out.println("test2");System.out.println(msg2.value());System.out.println(msg2.what());}@Testpublic void test3() throws Exception{TestAnnotation msg3 = Demo2.class.getDeclaredField("msg3").getAnnotation(TestAnnotation.class);System.out.println("test3");System.out.println(msg3.value());System.out.println(msg3.what());}@Testpublic void test4() throws Exception{TestAnnotation msg4 = Demo2.class.getDeclaredField("msg4").getAnnotation(TestAnnotation.class);System.out.println("test4");System.out.println(msg4.value());System.out.println(msg4.what());}
}

总结:如果我们注解上没有指定是value还是what默认就是value,如果只想转递一个参数又不想默认是value那就需要指定what=""即可。 

 案例三(获取参数修饰注解对应的属性值)

注解类:

@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsNotNull {boolean value() default false;
}

测试类Demo3:

public class Demo3 {public void hello1(@IsNotNull(true) String name) {System.out.println("hello:" + name);}public void hello2(@IsNotNull String name) {System.out.println("hello:" + name);}
}

测试类DemoTest3:

public class Demo3Test {@Testpublic void hello1() throws Exception {Demo3 demo3 = new Demo3();for (Parameter parameter : demo3.getClass().getMethod("hello1", String.class).getParameters()) {IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);if(annotation != null){System.out.println(annotation.value());//true}}}@Testpublic void hello2() throws Exception {Demo3 demo3 = new Demo3();for (Parameter parameter : demo3.getClass().getMethod("hello2", String.class).getParameters()) {IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);if(annotation != null){System.out.println(annotation.value());//false}}}@Testpublic void hello3() throws Exception {
//        模拟浏览器传递到后台的参数 解读@requestParamString name = "zs";Demo3 demo3 = new Demo3();Method method = demo3.getClass().getMethod("hello1", String.class);for (Parameter parameter : method.getParameters()) {IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);if(annotation != null){System.out.println(annotation.value());//trueif (annotation.value() && !"".equals(name)){method.invoke(demo3,name);}}}}
}

运行结果: 

 

总结:这个案例像不像我们的注解@RequestParam必须传递参数,除非指定required为false就可与不传参数,我们这个案例也是如此。 

三,Aop自定义注解

定义一个注解类:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {String desc();
}

切面类:

@Component
@Aspect
public class MyLogAspect {private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);/*** 只要用到了com.javaxl.p2.annotation.springAop.MyLog这个注解的,就是目标类*/@Pointcut("@annotation(com.Bingzy.annotation.aop.MyLog)")private void MyValid() {}@Before("MyValid()")public void before(JoinPoint joinPoint) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();logger.debug("[" + signature.getName() + " : start.....]");System.out.println("[" + signature.getName() + " : start.....]");MyLog myLog = signature.getMethod().getAnnotation(MyLog.class);logger.debug("【目标对象方法被调用时候产生的日志,记录到日志表中】:"+myLog.desc());System.out.println("【目标对象方法被调用时候产生的日志,记录到日志表中】:" + myLog.desc());}
}

Controller层:

@Controller
public class LogController {@RequestMapping("/mylog")@MyLog(desc = "这是结合spring aop知识,讲解自定义注解应用的一个案例")public void testLogAspect(){System.out.println("这里随便来点啥");}
}

运行结果:

相关文章:

SpringMVC自定义注解---[详细介绍]

一,对于SpringMVC自定义注解概念 是一种特殊的 Java 注解,它允许开发者在代码中添加自定义的元数据,并且可以在运行时使用反射机制来获取和处理这些信息。在 Spring MVC 中,自定义注解通常用于定义控制器、请求处理方法、参数或者…...

5.4 转换数据

5.4 转换数据 5.4.1 哑变量处理类别型数据5.4.2 离散化连续型数据1、等宽法2、等频法3、聚类分析法 数据集 E:/Input/ptest.csv 5.4.1 哑变量处理类别型数据 数据分析模型中有相当一部分的算法模型都要求输入的特征为数值型,但实际数据中特征的类型不一定只有数值…...

雷池社区WAF:保护您的网站免受黑客攻击 | 开源日报 0918

keras-team/keras Stars: 59.2k License: Apache-2.0 Keras 是一个用 Python 编写的深度学习 API,运行在机器学习平台 TensorFlow 之上。它 简单易用:减少了开发者认知负荷,使其能够更关注问题中真正重要的部分。灵活性强:通过逐…...

链表反转-LeetCode206

**题目:**给你单链表的头结点head,请反转链表,并返回反转后的链表。 示例: 输入:head [1,2,3,4,5] 输出:[5,4,3,2&#x…...

北邮22级信通院数电:Verilog-FPGA(3)实验“跑通第一个例程”modelsim仿真及遇到的问题汇总(持续更新中)

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章,请访问专栏: 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 注意:本篇文章所有绝对路径的展示都来自…...

4G工业路由器,开启智能工厂,这就是关键所在

​提到工业物联网,首先联想到的就是数据传输。要把海量的工业数据从设备端传到控制中心,无线数传终端就发挥着重要作用。今天就跟着小编来看看它的“联”是怎么建立的吧! 原文:https://www.key-iot.com/iotlist/1838.html 一提到无线数传终端,相信大家首先想到的是…...

计组-机器字长、存储字长、指令字长以及和他们有关的机器位数

🌳🌳🌳前言:本文总结了机器字长、存储字长、指令字长的概念以及和它们相关的机器位数。 目录 字长 机器字长 指令字长 存储字长 寄存器的位数 总结 字长 🌟字长一个字中的二进制位数。 🌟字长由微处…...

解决express服务器接收post请求报错:“req.body==> undefined“

现象如下: 解决办法:在代码中加入body-parser解析 const bodyParser require("body-parser"); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); 参考: How to fix "req.body undefined&q…...

5.zigbee的开发,串口putchar重定向(使用print),单播实验,usb抓包实验

一。实验:单播 实验要求: 实现终端定时向协调器发送给“好好学习”字符串,并且从终端打印出来。 要求: 指定端点为 0x0005 指定簇为 0x0003 1.进入应用层SampleApp.c中,串口的重定向 报错&#xff…...

解决AU报“MME无法使用“问题

今天在Adobe Audition(简称AU)软件,打开麦克风时,弹出如下错误:“加载默认的输入和输出设备失败:MME设备内部错误”,如图(1)所示: 图(1) AU报“MME设备内部错误” 继续点击AU菜单栏上的【编辑】–》首选项–》音频硬件&#xff0c…...

Maven 安装配置

Maven 安装配置 文章目录 Maven 安装配置一、下载 Maven二、解压Maven核心程序三、指定本地仓库四、配置阿里云镜像仓库4.1 将原有的例子配置注释掉4.2 加入新的配置 五、配置 Maven 工程的基础 JDK 版本六、配置环境变量6.1 检查 JAVAHOME 配置是否正确6.2 配置 MAVENHOME6.3 …...

vscode 配置网址

首先我的项目是一个面向医院的系统 我是在三个文件里都配置了网址 第一个文件:vue.config.js const path require(path) const webpack require(webpack) const createThemeColorReplacerPlugin require(./config/plugin.config)function resolve (dir) {retu…...

git 本地工作区和仓库区基本使用

(1)git 本地有三个区 工作区和暂存区和 git管理的仓库. (自行动手实践理解,然后就入门了)(2)本地初次使用git做的事情,需要做如下工作 git config --global user.name "xx" git config --global user.email xxxqq.com git config --globa…...

有效的括号(栈的高频面试题)

一、题目描述 题目连接:有效的括号 给定一个只包括 (,),{,},[,] 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺…...

GIS跟踪监管系统电子围栏

GIS跟踪监管系统电子围栏 (1)电子围栏展示。① 显示:② 隐藏:(2)电子围栏修改。① 新增电子围栏。② 修改电子围栏。工具箱(1)测量。① 测量距离:② 测量面积&#xff1a…...

蓝桥杯2023年第十四届省赛真题-买瓜--Java题解

目录 蓝桥杯2023年第十四届省赛真题-买瓜 题目描述 输入格式 输出格式 样例输入 样例输出 提示 【思路解析】 【代码实现】 蓝桥杯2023年第十四届省赛真题-买瓜 时间限制: 3s 内存限制: 320MB 提交: 796 解决: 69 题目描述 小蓝正在一个瓜摊上买瓜。瓜摊上共有 n 个…...

Chatbot到底提供了哪些便利?来看看“中文版Chatbase”

Chatbot的出现可以说是在极大的程度上改变了企业与客户互动的方式。Chatbot凭借其先进的功能和全天候可用性提供了一系列便捷的功能,为企业和客户提供便利和高效。随着自然语言处理和机器学习算法的进步,Chatbot已经发展到可以提供准确和个性化的响应&am…...

2023-09-18 LeetCode每日一题(打家劫舍 III)

2023-09-18每日一题 一、题目编号 337. 打家劫舍 III二、题目链接 点击跳转到题目位置 三、题目描述 小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。 除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦…...

Python一行代码实现文件共享【内网穿透公网访问】

文章目录 1.前言2.本地文件服务器搭建2.1.python的安装和设置2.2.cpolar的安装和注册 3.本地文件服务器的发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 数据共享作为和连接作为互联网的基础应用,不仅在商业和办公场景有广泛的应用&#…...

uni-app 之 下拉刷新,上拉加载,获取网络列表数据

uni-app 之 下拉刷新&#xff0c;上拉加载&#xff0c;获取网络列表数据 image.png <template><view><!-- 车源模块 -->--- uni.request 网络请求API接口 ---<view v-for"(item) in newsArr" :key"item.id" style"display: fle…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

Java后端检查空条件查询

通过抛出运行异常&#xff1a;throw new RuntimeException("请输入查询条件&#xff01;");BranchWarehouseServiceImpl.java // 查询试剂交易&#xff08;入库/出库&#xff09;记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...

2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案

一、延迟敏感行业面临的DDoS攻击新挑战 2025年&#xff0c;金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征&#xff1a; AI驱动的自适应攻击&#xff1a;攻击流量模拟真实用户行为&#xff0c;差异率低至0.5%&#xff0c;传统规则引…...

项目进度管理软件是什么?项目进度管理软件有哪些核心功能?

无论是建筑施工、软件开发&#xff0c;还是市场营销活动&#xff0c;项目往往涉及多个团队、大量资源和严格的时间表。如果没有一个系统化的工具来跟踪和管理这些元素&#xff0c;项目很容易陷入混乱&#xff0c;导致进度延误、成本超支&#xff0c;甚至失败。 项目进度管理软…...

【大厂机试题解法笔记】矩阵匹配

题目 从一个 N * M&#xff08;N ≤ M&#xff09;的矩阵中选出 N 个数&#xff0c;任意两个数字不能在同一行或同一列&#xff0c;求选出来的 N 个数中第 K 大的数字的最小值是多少。 输入描述 输入矩阵要求&#xff1a;1 ≤ K ≤ N ≤ M ≤ 150 输入格式 N M K N*M矩阵 输…...