SpringMvc决战-【SpringMVC之自定义注解】

目录

一、前言

1.1.什么是注解

1.2.注解的用处

1.3.注解的原理

二.注解父类

1.注解包括那些

2.JDK基本注解

3. JDK元注解

4.自定义注解

  5.如何使用自定义注解(包括:注解标记【没有任何东西】,元数据注解)?

三.实例展示

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

1.1导入一个类用于创造实例

1.2导入三个注解

1.3导入测试类

1.4测试结果】

1.测试list方法

2.测试ledit方法 

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

2.1导入方法的类

2.导入测试类

3.测试

3.1test测试结果

3.2test4测试结果 

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

 1.导入方法类

2.导入测试类

3.测试结果

三. Aop自定义注解的应用

1.导入pom.xml中的依赖

2.导入自定义注解

3.编写切面类()

4.编写web类用于测试

5.打印输出的结果(web类  )

​编辑​


前言:

讲述的为JSON返回&异常处理机制,json返回就不用多说,毕竟大部分数据都是通过Json来传递数据的,异常返回的作用小编也就不多说了反正很重要!

前台小编带来的是:Spring MVC中,我们可以通过自定义注解来增强和定制化我们的控制器和请求处理逻辑。自定义注解可以通过反射机制在运行时扫描并提取相关信息,从而实现特定的功能和行为。

一、前言

1.1.什么是注解

Annontation是Java5开始引入的新特征,中文名称叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观、更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。

Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。

1.2.注解的用处

 生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等
跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2 依赖注入,未来java 开发,将大量注解配置,具有很大用处;
在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

1.3.注解的原理

注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler 的invoke 方法。该方法会从memberValues 这个Map 中索引出对应的值。而memberValues 的来源是Java 常量池
 

二.注解父类

1.注解包括那些

JDK基本注解 JDK元注解 自定义注解

2.JDK基本注解

比如:@Override 重写 ​ @SuppressWarnings(value = "unchecked") 压制编辑器警告

3. JDK元注解

例子:

@Retention:定义注解的保留策略 @Retention(RetentionPolicy.SOURCE)             //注解仅存在于源码中,在class字节码文件中不包含 @Retention(RetentionPolicy.CLASS)             //默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得, @Retention(RetentionPolicy.RUNTIME)           //注解会在class字节码文件中存在,在运行时可以通过反射获取到 ​ @Target:指定被修饰的Annotation可以放置的位置(被修饰的目标) @Target(ElementType.TYPE)                     //接口、类 @Target(ElementType.FIELD)                     //属性 @Target(ElementType.METHOD)                   //方法 @Target(ElementType.PARAMETER)                 //方法参数 @Target(ElementType.CONSTRUCTOR)               //构造函数 @Target(ElementType.LOCAL_VARIABLE)           //局部变量 @Target(ElementType.ANNOTATION_TYPE)           //注解 @Target(ElementType.PACKAGE)                   //包 注:可以指定多个位置,例如: @Target({ElementType.METHOD, ElementType.TYPE}),也就是此注解可以在方法和类上面使用 ​ @Inherited:指定被修饰的Annotation将具有继承性 ​ @Documented:指定被修饰的该Annotation可以被javadoc工具提取成文档.

4.自定义注解

注解分类(根据Annotation是否包含成员变量,可以把Annotation分为两类): ​ 标记Annotation: 没有成员变量的Annotation; 这种Annotation仅利用自身的存在与否来提供信息 ​ 元数据Annotation: 包含成员变量的Annotation; 它们可以接受(和提供)更多的元数据;

  5.如何使用自定义注解(包括:注解标记【没有任何东西】,元数据注解)?

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

三.实例展示

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

1.1导入一个类用于创造实例

package com.lz.annotation;public enum  TranscationModel {Read, Write, ReadWrite
}

1.2导入三个注解

package com.lz.annotation;import java.lang.annotation.*;/*** MyAnnotation1注解可以用在类、接口、属性、方法上* 注解运行期也保留* 不可继承*/
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation1 {String name();
}
package com.lz.annotation;import java.lang.annotation.*;/***  MyAnnotation2注解可以用在方法上*  注解运行期也保留*  不可继承*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {TranscationModel model() default TranscationModel.ReadWrite;
}
package com.lz.annotation;import java.lang.annotation.*;/*** lz*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited(可以被继承
)
@Documented
public @interface MyAnnotation3 {TranscationModel[] models() default TranscationModel.ReadWrite;
}

1.3导入测试类

package com.lz.annotation;/*** @author lz* @create 2023-09-14 19:04*/@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");}
}
package com.lz.annotation;import org.junit.Test;/*** @author LZ* @site www.javaxl.com*/
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}}
}

1.4测试结果】

1.测试list方法

2.测试ledit方法 

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

2.1导入方法的类

package com.lz.annotation.demo2;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author 小李飞刀* @site www.javaxl.com*/
//@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TestAnnotation {String value() default "默认value值";String what() default "这里是默认的what属性对应的值";
}

2.导入测试类

package com.lz.annotation.demo2;/*** @author  lz** 获取类属性上的注解属性值*/
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;
}
package com.lz.annotation.demo2;import org.junit.Test;/*** @author lz**/
public class Demo2Test {@Testpublic void test1() throws Exception {TestAnnotation msg1 = Demo2.class.getDeclaredField("msg1").getAnnotation(TestAnnotation.class);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(msg2.value());System.out.println(msg2.what());}@Testpublic void test3() throws Exception{TestAnnotation msg3 = Demo2.class.getDeclaredField("msg3").getAnnotation(TestAnnotation.class);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(msg4.value());System.out.println(msg4.what());}
}

3.测试

3.1test测试结果

3.2test4测试结果 

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

通过模拟requestparam来进行操作:默认情况,传递为空。不会调用方法,不为空,不调用方法 

 1.导入方法类

package com.lz.annotation.demo3;import java.lang.annotation.*;/*** @author  lz** 非空注解:使用在方法的参数上,false表示此参数可以为空,true不能为空*/
@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsNotNull {boolean value() default false;
}

2.导入测试类

package com.lz.annotation.demo3;/**@author  lz* 获取参数修饰注解对应的属性值*/
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);}
}
package com.lz.annotation.p3;import com.lz.annotation.demo3.Demo3;
import com.lz.annotation.demo3.IsNotNull;
import org.junit.Test;import java.lang.reflect.Method;
import java.lang.reflect.Parameter;/**@author  lz*/
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);}}}}
}

3.测试结果

三. Aop自定义注解的应用

1.导入pom.xml中的依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>

2.导入自定义注解

package com.lz.annotation.aop;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 导入自定义注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {String desc();
}

3.编写切面类()

package com.lz.acpect;import com.lz.annotation.aop.MyLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;/*** LZ*/
@Component
@Aspect
public class MyLogAspect {private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);/*** 只要用到了com.javaxl.p2.annotation.springAop.MyLog这个注解的,就是目标类*/@Pointcut("@annotation(com.lz.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());}
}

4.编写web类用于测试

package com.lz.controller;import com.lz.annotation.aop.MyLog;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;/*** LZ*/
@Controller
public class LogController {@RequestMapping("/mylog")@MyLog(desc = "这是结合spring aop知识,讲解自定义注解应用的一个案例")public void testLogAspect(){System.out.println("这里随便来点啥");}
}

5.打印输出的结果(web类  )

四.总结

注解是Java语言中的一种元数据标记机制,用于为程序中的代码、类、方法、变量等元素添加附加信息。在Java中,注解主要分为JDK基本注解和JDK元注解两类,同时也支持自定义注解。

JDK基本注解包括 @Override、@Deprecated、@SuppressWarnings,JDK元注解包括 @Retention、@Target、@Documented、@Inherited。自定义注解需要使用 @interface 关键字进行定义,并可以指定元注解和注解属性。

注解在Java中的使用是通过反射机制实现的,可以被用于实现各种功能,如配置文件的自动读取、代码的自动生成、数据校验、接口的实现等。

在实际应用中,可以将注解标记在类、方法、字段等元素上,并在运行时通过反射获取注解的信息来实现相应的功能,或者结合AOP技术实现对代码的增强。

        到这里我的分享就结束了,欢迎到评论区探讨交流!!

💖如果觉得有用的话还请点个赞吧 💖

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

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

相关文章

[JAVAee]SpringBoot配置文件

配置文件的介绍 配置文件当中记录了许多重要的配置信息,例如: 数据库的连接信息(用户的账户与密码)项目的启动端口第三方系统的调用密匙用于记录问题产生的日志 在spring框架中一些特定的框架会自动调用配置文件中的配置信息来运用. 配置文件中的属性也起到了类似全局变量的…

vue2-x6-dag自定义vue组件节点

效果如图 官方案例 人工智能建模 DAG 图 vue2中自定义节点 代码 1.dag.json [{"id": "1","shape": "dag-node","x": 290,"y": 110,"data": {"label": "读数据","status&q…

爬虫 — 验证码反爬

目录 一、超级鹰二、图片验证模拟登录1、页面分析1.1、模拟用户正常登录流程1.2、识别图片里面的文字 2、代码实现 三、滑块模拟登录1、页面分析2、代码实现&#xff08;通过对比像素获取缺口位置&#xff09; 四、openCV1、简介2、代码3、案例 五、selenium 反爬六、百度智能云…

力扣刷题19-删除链表的倒数第N个节点

题目来源 题目描述&#xff1a; class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {//为了删除的格式一样&#xff0c;引入虚拟头节点ListNode dummyNodenew ListNode(1);dummyNode.nexthead;ListNode slowdummyNode;ListNode fastdummyNode;for(int…

【Linux网络编程】Socket-TCP实例

该代码利用socket套接字建立Tcp连接&#xff0c;包含服务器和客户端。当服务器和客户端启动时需要把端口号或ip地址以命令行参数的形式传入。服务器启动如果接受到客户端发来的请求连接&#xff0c;accept函数会返回一个打开的socket文件描述符&#xff0c;区别于监听连接的lis…

Stable Diffusion - 采样器 DPM++ 3M SDE Karras 与 SDXL Refiner 测试

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132978866 Paper: DPM-Solver: Fast Solver for Guided Sampling of Diffusion Probabilistic Models 扩散概率模型&#xff08;DPMs&#xff09;…

Linux集群时间同步方法

参考&#xff1a;https://www.cnblogs.com/felixzh/p/10638399.html

Qt(day1)

思维导图 Qt实现第一个web的基础页面 #include "mywnd.h" #include "ui_mywnd.h" #include<QLabel> #include<QLineEdit> #include<qpushbutton.h>MyWnd::MyWnd(QWidget *parent): QMainWindow(parent), ui(new Ui::MyWnd) {ui->set…

C语言的文件操作(炒详解)

⭐回顾回顾文件操作的相关细节⭐ 欢迎大家指正错误 &#x1f4dd;在之前的学习中&#xff0c;不管增加数据&#xff0c;减少数据&#xff0c;当程序退出时&#xff0c;所有的数据都会销毁&#xff0c;等下次运行程序时&#xff0c;又要重新输入相关数据&#xff0c;如果一直像这…

现在做抖音小店还来得及吗?新手正确入局抖店的流程,醒醒团队

我是王路飞。 现在很多入局抖音的&#xff0c;都意识到了一件事&#xff0c;那就是做店要比做账号容易。 做账号&#xff0c;意味着你选择了成为抖音网红-卖货的路线&#xff0c;看似光鲜亮丽&#xff0c;实则都是团队内容运气等多重因素结合得到的结果。 但是&#xff0c;做…

mysql MVCC多版本并发控制

mvcc的概念 mvcc 的实现依赖于&#xff1a; 隐藏字段 行格式&#xff08;row_id,trx_id,roll_ponter&#xff09;UndologRead view innodb 存储引擎的表来说&#xff0c;聚集索引记录中都包含两个必要的隐藏字段&#xff0c;row_id(如果没有聚集索引&#xff0c;才会创建的) …

【JDK 8-函数式编程】4.6 方法引用与构造函数引用

一、 方法引用与构造函数引用 1. 说明 2. 语法: 二、静态方法 三、实例方法 四、构造函数 4.1 单个参数 4.2 2个参数 五、执行结果 一、 方法引用与构造函数引用 以前调用&#xff1a;对象.方法名、类名.方法名 jdk1.8提供了另外一种调用方式 :: 1. 说明 用来直接访…