SpringMVC之自定义注解

2023-09-16 05:36:08

目录

前言

一、自定义注解

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关键字即可。

package com.ctb.utils;
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 CustomAnnotation {
    String value() default "";
}

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

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

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

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

案例一:

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

package com.ctb.model;
 
public enum  TranscationModel {
    Read, Write, ReadWrite
}

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

MyAnnotation1 :  

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

MyAnnotation2 :  

package com.ctb.annotation;
 
import com.ctb.model.TranscationModel;
 
import java.lang.annotation.*;
 
/**
 *  MyAnnotation2注解可以用在方法上
 *  注解运行期也保留
 *  不可继承
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {
    TranscationModel model() default TranscationModel.ReadWrite;
}

MyAnnotation3 :  

package com.ctb.annotation;
 
import com.ctb.model.TranscationModel;
 
import java.lang.annotation.*;
 
 
/**
 * MyAnnotation3注解可以用在方法上
 * 注解运行期也保留
 * 可继承
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation3 {
    TranscationModel[] models() default TranscationModel.ReadWrite;
}

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

package com.ctb.annotation.demo;
 
import com.ctb.annotation.MyAnnotation1;
import com.ctb.annotation.MyAnnotation2;
import com.ctb.annotation.MyAnnotation3;
import com.ctb.model.TranscationModel;
 
/**
 * 获取类与方法上的注解值
 */
@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测试类:

package com.ctb.annotation.demo;
 
import com.ctb.annotation.MyAnnotation1;
import com.ctb.annotation.MyAnnotation2;
import com.ctb.annotation.MyAnnotation3;
import com.ctb.model.TranscationModel;
import org.junit.Test;
 
public class Demo1Test {
    @Test
    public 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
    }
 
    @Test
    public void edit() throws Exception {
        MyAnnotation3 myAnnotation3 = Demo1.class.getMethod("edit").getAnnotation(MyAnnotation3.class);
        for (TranscationModel model : myAnnotation3.models()) {
            System.out.println(model);//Read,Write
        }
    }
}

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

 执行list方法测试结果

执行edit方法测试结果 

案例二:

1. 自定义注解类:

package com.ctb.annotation;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
//@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TestAnnotation {
    String value() default "默认value值";
 
    String what() default "这里是默认的what属性对应的值";
}

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

package com.ctb.annotation.demo2;
 
import com.ctb.annotation.TestAnnotation;
 
/**
 * 获取类属性上的注解属性值
 */
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;
}

 3. 测试

package com.ctb.annotation.demo2;
 
import com.ctb.annotation.TestAnnotation;
import org.junit.Test;
 
public class Demo2Test {
    @Test
    public void test1() throws Exception {
        TestAnnotation msg1 = Demo2.class.getDeclaredField("msg1").getAnnotation(TestAnnotation.class);
        System.out.println(msg1.value());
        System.out.println(msg1.what());
    }
 
    @Test
    public void test2() throws Exception{
        TestAnnotation msg2 = Demo2.class.getDeclaredField("msg2").getAnnotation(TestAnnotation.class);
        System.out.println(msg2.value());
        System.out.println(msg2.what());
    }
 
    @Test
    public void test3() throws Exception{
        TestAnnotation msg3 = Demo2.class.getDeclaredField("msg3").getAnnotation(TestAnnotation.class);
        System.out.println(msg3.value());
        System.out.println(msg3.what());
    }
 
    @Test
    public void test4() throws Exception{
        TestAnnotation msg4 = Demo2.class.getDeclaredField("msg4").getAnnotation(TestAnnotation.class);
        System.out.println(msg4.value());
        System.out.println(msg4.what());
    }
}

案例三:

1.创建自定义注解:

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

2. 创建测试类:

package com.ctb.annotation.demo3;
 
import com.ctb.annotation.IsNotNull;
 
/**
 * 获取参数修饰注解对应的属性值
 */
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);
    }
}

3. 测试

package com.ctb.annotation.demo3;
 
import com.ctb.annotation.IsNotNull;
import org.junit.Test;
 
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
 
public class Demo3Test {
 
    @Test
    public 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
            }
        }
    }
 
    @Test
    public 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
            }
        }
    }
 
    @Test
    public void hello3() throws Exception {
//        模拟浏览器传递到后台的参数 解读@requestParam
        String 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());//true
                if (annotation.value() && !"".equals(name)){
                    method.invoke(demo3,name);
                }
            }
        }
    }
}

二、Aop自定义注解的应用  

1 .自定义注解类

package com.ctb.annotation;
 
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();
}

2.切面类

package com.ctb.aspect;
 
import com.ctb.annotation.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;
 
@Component
@Aspect
public class MyLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);
 
    /**
     * 只要用到了com.javaxl.p2.annotation.springAop.MyLog这个注解的,就是目标类
     */
    @Pointcut("@annotation(com.ctb.annotation.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());
    }
}

3.Controller层

package com.ctb.web;
 
import com.ctb.annotation.MyLog;
import org.springframework.stereotype.Component;
 
@Component
public class LogController {
    @MyLog(desc = "这是结合spring aop知识,讲解自定义注解应用的一个案例")
    public void testLogAspect(){
        System.out.println("记录日志...");
    }
}
更多推荐

职业了解|03师范生的编制教师之路

“初闻不解曲中意,再闻已是曲中人”。每个行业有一个共性在于,外面的人想进去,里面的人想出来。时代变化,不同的行业的细则也在变化。十五年前,有谁会预计计算机会这么火爆呢?估计大概率只会被认为计算机属于不务正业。而现在,宇宙的尽头是编制。但编制是否真的十全十美呢?本文讲述一个小学在编教师的心声。1、为什么想到读师范生我高考

基于CNN-LSTM的时序预测MATLAB实战

一、算法原理1.1CNN原理卷积神经网络具有局部连接、权值共享和空间相关等特性。卷积神经网络结构包含卷积层、激活层和池化层。(a)二维卷积层将滑动卷积滤波器应用于输入。该层通过沿输入垂直和水平方向移动滤波器对输入进行卷积,并计算权重与输入的点积,然后加入一个偏置项。具体表达式为:卷积层的功能是对输入数据进行特征提取。其

基于R语言APSIM模型进阶应用与参数优化、批量模拟实践技术

APSIM(AgriculturalProductionSystemssIMulator)模型是世界知名的作物生长模拟模型之一。APSIM模型有Classic和NextGeneration两个系列模型,能模拟几十种农作物、牧草和树木的土壤-植物-大气过程,被广泛应用于精细农业、水肥管理、气候变化、粮食安全、土壤碳周转、

1、MongoDb综述

1.MongoDb综述1.1.什么是NosqlNoSQL:NotOnlySQL,本质也是一种数据库的技术,相对于传统数据库技术,它不会遵循一些约束,比如:sql标准、ACID属性,表结构等。Nosql优点l满足对数据库的高并发读写l对海量数据的高效存储和访问l对数据库高扩展性和高可用性l灵活的数据结构,满足数据结构不固

zabbix

zabbix是一个基于Web界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。zabbix能监视各种网络参数,保证服务器系统的安全运营;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问题。zabbix由2部分构成,zabbixserver与可选组件zabbixagent。通过C/S模式采集数据

sqlite条件查询语句where

文章目录导入CSV数据where其他运算符sqlite初步导入CSV数据查询是数据库中最频繁的操作,但学习查询指令,最起码要有可供查询的表格。比如现在有下面这些2022排名前20的国家GDP的数据,当然格式是csv的,我们要做的第一步就是将其转为sqilte格式。1,美国,美洲,254600,0.2532042,中国,

Excel_字母数字混合排序(数字不符合预期)的一种解决方法

引ADC_DCAL_DN1[13:0]ADC_DCAL_DN10[13:0]ADC_DCAL_DN11[13:0]ADC_DCAL_DN2[13:0]ADC_DCAL_DN3[13:0]ADC1_EOCADC10_EOCADC11_EOCADC2_EOCADC3_EOCADC4_EOCADC5_EOCADC_CALCB

酷开科技夯实流量基础,构建智慧生活新风尚!

在这个日新月异的时代,智能化趋势加速发展,依托于互联网服务的OTT也越来越贴近消费者的居家生活,并在家用场景下释放出独特的大屏营销价值。成立于2006年的酷开科技,一直是智能电视行业前进道路上的坚实力量,自创建以来便一直为互联网智能电视行业提供技术与运维服务。酷开科技以内容技术服务和数字营销服务为核心,自主研发了一套智

基于springboot+vue的便利店信息管理系统

博主主页:猫头鹰源码博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万+、专注Java技术领域和毕业设计项目实战主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询文末联系获取项目介绍:本系统适合选题:便利店、便利店管理、商店管理等。系统采用springb

C++之operator()和构造函数区别与总结(二百三十)

简介:CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀人生格言:人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.更多原创,欢迎关注:Android系统攻城狮1.前言本篇目的:理解C+

MYSQL--事务

目录一、事物的概念:二、事务的ACID特点:1.原子性:2.一致性:3.隔离性:4.持久性:三、隔离性:1.事务之间的相互影响:(1)脏读:(2)不可重复读:(3)幻读:(4)丢失更新:2.Mysql的隔离级别:3.隔离级别作用范围:四、事务控制语句:1.commit提交事务:2.ROLLBACK回滚:3.使用回滚点:

热文推荐