• SpringMVC之自定义注解


    目录

    前言

    一、自定义注解

    1.Java注解简介

    2. 注解的用处

    3. 为什么要用注解

    4.自定义注解的应用场景

    5. 注解的分类

    6.如何定义并使用自定义注解

    7.自定义注解三种使用案例

    案例一:

    案例二:

    案例三:

    二、Aop自定义注解的应用  

    1 .自定义注解类

    2.切面类

    3.Controller层


    前言

    随着Web开发的发展,越来越多的企业开始使用SpringMVC框架来构建自己的Web应用程序。在开发过程中,为了提高代码的可读性和可维护性,我们经常需要自定义注解。本文将介绍如何编写一个自定义注解,并通过一个简单的例子来演示如何使用它。

    一、自定义注解

    1.Java注解简介

    Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。 注解相关类都包含在java.lang.annotation包中。

    2. 注解的用处

    • 配置和元数据:注解可以用于配置和描述类、方法、字段等元素的特性和行为。例如,我们可以使用注解来指定数据库表的名称、字段的长度、方法的访问权限等。

    • 编译时检查:注解可以用于在编译时对代码进行静态检查,以确保代码的正确性和合规性。例如,我们可以使用注解来标记过时的方法或类,编译器会在编译时给出警告。

    • 运行时处理:注解可以在运行时通过反射机制获取到,并根据注解的定义来执行相应的逻辑。例如,我们可以使用注解来实现自定义的AOP(面向切面编程)逻辑,或者在某些条件下动态地修改方法的行为。

    • 文档生成:注解可以用于生成文档,以便开发者更好地理解代码的含义和使用方式。例如,我们可以使用注解来标记API的使用示例、参数的说明等。

    3. 为什么要用注解

    • 减少样板代码:通过使用注解,我们可以将一些重复性的代码抽象为注解,从而减少冗余的代码量。

    • 提高代码可读性:注解可以用于描述代码的特性和行为,使代码更加易于理解和阅读。

    • 增强代码的可维护性:通过使用注解,我们可以将一些与业务逻辑无关的代码与业务逻辑分离,使代码更加模块化和可维护。

    • 提高开发效率:使用注解可以简化一些繁琐的操作,提高开发效率。

    4.自定义注解的应用场景

    应用场景十分广泛,举例说明几个:

    • 在SpringMVC中,我们可以使用自定义注解来标记Controller中的方法,以实现请求的映射和处理。
    • 在MyBatis中,我们可以使用自定义注解来标记Mapper接口中的方法,以实现SQL语句的映射和执行。
    • 在JUnit中,我们可以使用自定义注解来标记测试方法,以实现自动化测试的执行。

    5. 注解的分类

    • JDK元注解:元注解是用于注解其他注解的注解,它可以用于指定注解的作用范围、生命周期等。常见的元注解有@Target@Retention@Documented等。

    • JDK基本注解:标准注解是Java提供的一些常用注解,例如@Override@Deprecated@SuppressWarnings等。

    • 自定义注解:自定义注解是开发者根据自己的需求定义的注解,用于实现特定的功能或逻辑。

    • 框架注解:框架注解是一些常用框架提供的注解,用于实现框架的特定功能。例如,Spring框架提供的@Autowired@RequestMapping等注解。

    6.如何定义并使用自定义注解

    自定义注解的定义非常简单,只需要使用@interface关键字即可。

    1. package com.ctb.utils;
    2. import java.lang.annotation.ElementType;
    3. import java.lang.annotation.Retention;
    4. import java.lang.annotation.RetentionPolicy;
    5. import java.lang.annotation.Target;
    6. @Target(ElementType.METHOD)
    7. @Retention(RetentionPolicy.RUNTIME)
    8. public @interface CustomAnnotation {
    9. String value() default "";
    10. }

    我们定义了一个名为CustomAnnotation的注解。该注解可以应用于方法上,并且在运行时保留。注解中还定义了一个名为value的属性,默认为空字符串。

    使用自定义注解非常简单,只需要在需要标记的地方使用注解即可。

    1. @CustomAnnotation("这是一个自定义注解示例")
    2. public void doSomething() {
    3. // 执行一些操作
    4. }

    7.自定义注解三种使用案例

    案例一:

    1. 定义一个枚举类:用来表示一组固定的值。

    1. package com.ctb.model;
    2. public enum TranscationModel {
    3. Read, Write, ReadWrite
    4. }

    2. 定义三个不同注解方式的类:

    MyAnnotation1 :  

    1. package com.ctb.annotation;
    2. import java.lang.annotation.*;
    3. /**
    4. * MyAnnotation1注解可以用在类、接口、属性、方法上
    5. * 注解运行期也保留
    6. * 不可继承
    7. */
    8. @Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
    9. @Retention(RetentionPolicy.RUNTIME)
    10. @Documented
    11. public @interface MyAnnotation1 {
    12. String name();
    13. }

    MyAnnotation2 :  

    1. package com.ctb.annotation;
    2. import com.ctb.model.TranscationModel;
    3. import java.lang.annotation.*;
    4. /**
    5. * MyAnnotation2注解可以用在方法上
    6. * 注解运行期也保留
    7. * 不可继承
    8. */
    9. @Target(ElementType.METHOD)
    10. @Retention(RetentionPolicy.RUNTIME)
    11. @Documented
    12. public @interface MyAnnotation2 {
    13. TranscationModel model() default TranscationModel.ReadWrite;
    14. }

    MyAnnotation3 :  

    1. package com.ctb.annotation;
    2. import com.ctb.model.TranscationModel;
    3. import java.lang.annotation.*;
    4. /**
    5. * MyAnnotation3注解可以用在方法上
    6. * 注解运行期也保留
    7. * 可继承
    8. */
    9. @Target(ElementType.METHOD)
    10. @Retention(RetentionPolicy.RUNTIME)
    11. @Inherited
    12. @Documented
    13. public @interface MyAnnotation3 {
    14. TranscationModel[] models() default TranscationModel.ReadWrite;
    15. }

     Demo1测试类 : 获取类与方法上的注解值

    1. package com.ctb.annotation.demo;
    2. import com.ctb.annotation.MyAnnotation1;
    3. import com.ctb.annotation.MyAnnotation2;
    4. import com.ctb.annotation.MyAnnotation3;
    5. import com.ctb.model.TranscationModel;
    6. /**
    7. * 获取类与方法上的注解值
    8. */
    9. @MyAnnotation1(name = "abc")
    10. public class Demo1 {
    11. @MyAnnotation1(name = "xyz")
    12. private Integer age;
    13. @MyAnnotation2(model = TranscationModel.Read)
    14. public void list() {
    15. System.out.println("list");
    16. }
    17. @MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write})
    18. public void edit() {
    19. System.out.println("edit");
    20. }
    21. }

     Demo1Test测试类:

    1. package com.ctb.annotation.demo;
    2. import com.ctb.annotation.MyAnnotation1;
    3. import com.ctb.annotation.MyAnnotation2;
    4. import com.ctb.annotation.MyAnnotation3;
    5. import com.ctb.model.TranscationModel;
    6. import org.junit.Test;
    7. public class Demo1Test {
    8. @Test
    9. public void list() throws Exception {
    10. // 获取类上的注解
    11. MyAnnotation1 annotation1 = Demo1.class.getAnnotation(MyAnnotation1.class);
    12. System.out.println(annotation1.name());//abc
    13. // 获取方法上的注解
    14. MyAnnotation2 myAnnotation2 = Demo1.class.getMethod("list").getAnnotation(MyAnnotation2.class);
    15. System.out.println(myAnnotation2.model());//Read
    16. // 获取属性上的注解
    17. MyAnnotation1 myAnnotation1 = Demo1.class.getDeclaredField("age").getAnnotation(MyAnnotation1.class);
    18. System.out.println(myAnnotation1.name());// xyz
    19. }
    20. @Test
    21. public void edit() throws Exception {
    22. MyAnnotation3 myAnnotation3 = Demo1.class.getMethod("edit").getAnnotation(MyAnnotation3.class);
    23. for (TranscationModel model : myAnnotation3.models()) {
    24. System.out.println(model);//Read,Write
    25. }
    26. }
    27. }

    @Ingerited的使用
    @Inherited注解是Java中的元注解之一,用于控制注解的继承性。当一个类或接口被@Inherited注解修饰时,它的子类将自动获得该注解。但需要注意的是,@Inherited只对类和接口有效,对方法、字段等无效。
    普通的类继承是指子类可以继承父类的所有非private的成员变量和方法,包括构造器。子类可以使用父类中的方法和属性,也可以重写父类的方法,在其基础上进行扩展或修改。

     执行list方法测试结果

    执行edit方法测试结果 

    案例二:

    1. 自定义注解类:

    1. package com.ctb.annotation;
    2. import java.lang.annotation.ElementType;
    3. import java.lang.annotation.Retention;
    4. import java.lang.annotation.RetentionPolicy;
    5. import java.lang.annotation.Target;
    6. //@Retention(RetentionPolicy.SOURCE)
    7. @Retention(RetentionPolicy.RUNTIME)
    8. @Target(ElementType.FIELD)
    9. public @interface TestAnnotation {
    10. String value() default "默认value值";
    11. String what() default "这里是默认的what属性对应的值";
    12. }

    2. 定义测试类:获取类属性上的注解属性值

    1. package com.ctb.annotation.demo2;
    2. import com.ctb.annotation.TestAnnotation;
    3. /**
    4. * 获取类属性上的注解属性值
    5. */
    6. public class Demo2 {
    7. @TestAnnotation(value = "这就是value对应的值_msg1", what = "这就是what对应的值_msg1")
    8. private static String msg1;
    9. @TestAnnotation("这就是value对应的值1")
    10. private static String msg2;
    11. @TestAnnotation(value = "这就是value对应的值2")
    12. private static String msg3;
    13. @TestAnnotation(what = "这就是what对应的值")
    14. private static String msg4;
    15. }

     3. 测试

    1. package com.ctb.annotation.demo2;
    2. import com.ctb.annotation.TestAnnotation;
    3. import org.junit.Test;
    4. public class Demo2Test {
    5. @Test
    6. public void test1() throws Exception {
    7. TestAnnotation msg1 = Demo2.class.getDeclaredField("msg1").getAnnotation(TestAnnotation.class);
    8. System.out.println(msg1.value());
    9. System.out.println(msg1.what());
    10. }
    11. @Test
    12. public void test2() throws Exception{
    13. TestAnnotation msg2 = Demo2.class.getDeclaredField("msg2").getAnnotation(TestAnnotation.class);
    14. System.out.println(msg2.value());
    15. System.out.println(msg2.what());
    16. }
    17. @Test
    18. public void test3() throws Exception{
    19. TestAnnotation msg3 = Demo2.class.getDeclaredField("msg3").getAnnotation(TestAnnotation.class);
    20. System.out.println(msg3.value());
    21. System.out.println(msg3.what());
    22. }
    23. @Test
    24. public void test4() throws Exception{
    25. TestAnnotation msg4 = Demo2.class.getDeclaredField("msg4").getAnnotation(TestAnnotation.class);
    26. System.out.println(msg4.value());
    27. System.out.println(msg4.what());
    28. }
    29. }

    案例三:

    1.创建自定义注解:

    1. package com.ctb.annotation;
    2. import java.lang.annotation.*;
    3. /**
    4. * 非空注解:使用在方法的参数上,false表示此参数可以为空,true不能为空
    5. */
    6. @Documented
    7. @Target({ElementType.PARAMETER})
    8. @Retention(RetentionPolicy.RUNTIME)
    9. public @interface IsNotNull {
    10. boolean value() default false;
    11. }

    2. 创建测试类:

    1. package com.ctb.annotation.demo3;
    2. import com.ctb.annotation.IsNotNull;
    3. /**
    4. * 获取参数修饰注解对应的属性值
    5. */
    6. public class Demo3 {
    7. public void hello1(@IsNotNull(true) String name) {
    8. System.out.println("hello:" + name);
    9. }
    10. public void hello2(@IsNotNull String name) {
    11. System.out.println("hello:" + name);
    12. }
    13. }

    3. 测试

    1. package com.ctb.annotation.demo3;
    2. import com.ctb.annotation.IsNotNull;
    3. import org.junit.Test;
    4. import java.lang.reflect.Method;
    5. import java.lang.reflect.Parameter;
    6. public class Demo3Test {
    7. @Test
    8. public void hello1() throws Exception {
    9. Demo3 demo3 = new Demo3();
    10. for (Parameter parameter : demo3.getClass().getMethod("hello1", String.class).getParameters()) {
    11. IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
    12. if(annotation != null){
    13. System.out.println(annotation.value());//true
    14. }
    15. }
    16. }
    17. @Test
    18. public void hello2() throws Exception {
    19. Demo3 demo3 = new Demo3();
    20. for (Parameter parameter : demo3.getClass().getMethod("hello2", String.class).getParameters()) {
    21. IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
    22. if(annotation != null){
    23. System.out.println(annotation.value());//false
    24. }
    25. }
    26. }
    27. @Test
    28. public void hello3() throws Exception {
    29. // 模拟浏览器传递到后台的参数 解读@requestParam
    30. String name = "zs";
    31. Demo3 demo3 = new Demo3();
    32. Method method = demo3.getClass().getMethod("hello1", String.class);
    33. for (Parameter parameter : method.getParameters()) {
    34. IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
    35. if(annotation != null){
    36. System.out.println(annotation.value());//true
    37. if (annotation.value() && !"".equals(name)){
    38. method.invoke(demo3,name);
    39. }
    40. }
    41. }
    42. }
    43. }

    二、Aop自定义注解的应用  

    1 .自定义注解类

    1. package com.ctb.annotation;
    2. import java.lang.annotation.ElementType;
    3. import java.lang.annotation.Retention;
    4. import java.lang.annotation.RetentionPolicy;
    5. import java.lang.annotation.Target;
    6. @Target(ElementType.METHOD)
    7. @Retention(RetentionPolicy.RUNTIME)
    8. public @interface MyLog {
    9. String desc();
    10. }

    2.切面类

    1. package com.ctb.aspect;
    2. import com.ctb.annotation.MyLog;
    3. import org.aspectj.lang.JoinPoint;
    4. import org.aspectj.lang.annotation.Aspect;
    5. import org.aspectj.lang.annotation.Before;
    6. import org.aspectj.lang.annotation.Pointcut;
    7. import org.aspectj.lang.reflect.MethodSignature;
    8. import org.slf4j.Logger;
    9. import org.slf4j.LoggerFactory;
    10. import org.springframework.stereotype.Component;
    11. @Component
    12. @Aspect
    13. public class MyLogAspect {
    14. private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);
    15. /**
    16. * 只要用到了com.javaxl.p2.annotation.springAop.MyLog这个注解的,就是目标类
    17. */
    18. @Pointcut("@annotation(com.ctb.annotation.MyLog)")
    19. private void MyValid() {
    20. }
    21. @Before("MyValid()")
    22. public void before(JoinPoint joinPoint) {
    23. MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    24. logger.debug("[" + signature.getName() + " : start.....]");
    25. System.out.println("[" + signature.getName() + " : start.....]");
    26. MyLog myLog = signature.getMethod().getAnnotation(MyLog.class);
    27. logger.debug("【目标对象方法被调用时候产生的日志,记录到日志表中】:"+myLog.desc());
    28. System.out.println("【目标对象方法被调用时候产生的日志,记录到日志表中】:" + myLog.desc());
    29. }
    30. }

    3.Controller层

    1. package com.ctb.web;
    2. import com.ctb.annotation.MyLog;
    3. import org.springframework.stereotype.Component;
    4. @Component
    5. public class LogController {
    6. @MyLog(desc = "这是结合spring aop知识,讲解自定义注解应用的一个案例")
    7. public void testLogAspect(){
    8. System.out.println("记录日志...");
    9. }
    10. }
  • 相关阅读:
    【改论文有感】给英语论文写作小白的有用提示!(二)文法章法篇
    【计算机网络】 Nagle算法
    Android 天气APP(三十六)运行到本地AS、更新项目版本依赖、去掉ButterKnife
    CEC2018:动态多目标测试函数DF1~DF5的PS及PF
    .net 微服务 服务保护 自动重试 Polly
    二、GRE(Generic Routing Encapsulation,通用路由封装协议)
    室外光缆的规划与维护
    Tech Lead如何组建你的全明星团队
    计算机毕业设计成品java项目开发实例基于SSM框架图书借阅管理系统开发与设计
    JavaWeb之MySql高级(保姆级教程)
  • 原文地址:https://blog.csdn.net/weixin_74268571/article/details/132914168