SpringMVC自定义注解和使用

一.引言

1.简介:

在Spring MVC中,我们可以使用自定义注解来扩展和定制化我们的应用程序。自定义注解是一种通过Java的注解机制定义的特殊注解,可以应用于控制器类、方法或者方法参数上,以实现不同的功能和行为。(注解相关类都包含在java.lang.annotation包中。)

2、可实现功能

1.路由映射:可以定义一个自定义注解来标注控制器方法,以指定该方法的URL映射路径。

2.权限控制:可以定义一个自定义注解,用于标记需要进行权限验证的方法,从而实现简单的权限控制逻辑。

3.参数验证:可以定义一个自定义注解,用于标记方法参数,然后结合AOP等技术,在方法执行前或后进行参数的验证和校验。

4.日志记录:可以定义一个自定义注解,用于标记需要进行日志记录的方法,从而实现日志的统一处理。

5.缓存控制:可以定义一个自定义注解,用于标记需要进行缓存管理的方法,从而实现缓存的自动化管理。

3、使用自定义注解流程

1.定义注解:使用注解语法,在相关的注解类上定义自定义注解,可以指定注解的目标范围和属性。

2.标记使用:在控制器类、方法或者方法参数上使用自定义注解,标识需要应用自定义逻辑的地方。

3.处理注解:通过Spring的AOP、拦截器等机制,对标记了特定自定义注解的类、方法或者参数进行处理,实现相关的功能。

二.java的分解类

1、JDK基本注解

@Override:重写

应用:一般出现在接口实现类里面

java 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

@SuppressWarnings(value = "unchecked")

应用:压制编辑器警告

java 复制代码
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

2、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工具提取成文档.

3、自定义注解

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

标记Annotation:

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

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

4、如何自定义注解 ?

使用@interface关键字, 其定义过程与定义接口非常类似, 需要注意的是:

Annotation的成员变量在Annotation定义中是以无参的方法形式来声明的, 其方法名和返回值类型定义了该成员变量的名字和类型,

而且我们还可以使用default关键字为这个成员变量设定默认值;

三.使用自定义注解

1.配置pom.XMl

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xzs</groupId>
    <artifactId>spboottest01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spboottest01</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
<!--            <scope>test</scope>-->
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.了解什么是枚举?

枚举类是Java中一种特殊的数据类型,用于定义一组固定的命名常量。枚举类型提供了一种更强大、更安全和更易读的方式来表示一组相关的常量。在Java中,枚举类型是通过关键字enum来定义的。

作用:枚举类的作用是提供一种类型安全的方式来表示一组固定的值,避免使用数字或字符串常量时可能出现的错误。通过使用枚举类型,可以限制变量只能取预定义的值,并且可以在代码中使用这些常量的名称来提高可读性和可维护性。

java 复制代码
package com.xzs.annotation;

public enum  TranscationModel {
    Read, Write, ReadWrite
}

3**、自定义注解类**

1.MyAnnotation1

java 复制代码
package com.xzs.annotation.pi;

import java.lang.annotation.*;

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

    String name();
}

2、MyAnnotation2

java 复制代码
package com.xzs.annotation.pi;

import com.xzs.annotation.TranscationModel;

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

}

.3、MyAnnotation3

java 复制代码
package com.xzs.annotation.pi;

import com.xzs.annotation.TranscationModel;

import java.lang.annotation.*;
 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation3 {
    TranscationModel[] models() default TranscationModel.ReadWrite;


}

.4、TestAnnotation

java 复制代码
package com.xzs.annotation.pi;

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属性对应的值";

}

案例1:

1.创建一个测试类

java 复制代码
package com.xzs.annotation.pi;

import com.xzs.annotation.TranscationModel;

@MyAnnotation1(id = 1, name = "lei")
public class DemoTest {

    @MyAnnotation1(id = 2, name = "sx")
    private Integer age;

    @MyAnnotation2(model = TranscationModel.ReadWrite)
    public void select() {
        System.out.println("select");
    }

    @MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write, TranscationModel.ReadWrite})
    public void up() {
        System.out.println("up");
    }

}

**2、**获取类上的注解

java 复制代码
    @Test
    public void list() throws Exception {
//        获取类上的注解
        MyAnnotation1 annotation1 = DemoTest.class.getAnnotation(MyAnnotation1.class);
        System.out.println(annotation1.name() + "/" + annotation1.id());
}

3.获取方法上的注解

java 复制代码
 @Test
    public void list2() throws Exception {
//        获取方法上的注解
        MyAnnotation2 myAnnotation2 = DemoTest.class.getMethod("select").getAnnotation(MyAnnotation2.class);
        System.out.println(myAnnotation2.model());

    }

4. 获取属性上的注解

java 复制代码
 @Test
    public void list3() throws Exception {
//        获取属性上的注解
        MyAnnotation1 myAnnotation1 = DemoTest.class.getDeclaredField("age").getAnnotation(MyAnnotation1.class);
        System.out.println(myAnnotation1.name() + "/" + myAnnotation1.id());
    }

.5、遍历方法上的注解

java 复制代码
  @Test
    public void edit() throws Exception {
        MyAnnotation3 myAnnotation3 = DemoTest.class.getMethod("up").getAnnotation(MyAnnotation3.class);
        for (TranscationModel model : myAnnotation3.models()
        ) {
            System.out.println(model);
        }
    }

案例2:

1.测试类:

java 复制代码
package com.xzs.annotation.p2;

import com.xzs.annotation.pi.TestAnnotation;

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

    @TestAnnotation("这就是value对应的值1:msg2")
    private static String msg2;

    @TestAnnotation(value = "这就是value对应的值2:msg3")
    private static String msg3;

    @TestAnnotation(what = "这就是what对应的值:msg4")
    private static String msg4;

}
java 复制代码
package com.xzs.annotation.p2;

import com.xzs.annotation.pi.TestAnnotation;
import org.junit.jupiter.api.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());
    }
}

案例3:

自定义注解

java 复制代码
package com.xzs.annotation.p3;

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

}

测试类

java 复制代码
package com.xzs.annotation.p3;

import org.junit.jupiter.api.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("hello1:" + annotation.value());//true
                System.out.println(("-----------hello1----------"));
            }
        }
    }
 
    @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("hello2:" + annotation.value());//false
                System.out.println(("-----------hello2----------"));
            }
        }
    }
 
    @Test
    public void hello3() throws Exception {
//        模拟浏览器传递到后台的参数 解读@requestParam
        String name = "tqg";
        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);
                }
                System.out.println(("-----------hello3----------"));  }
        }
    }}

四、Aop自定义注解应用

1、自定义注解

java 复制代码
package com.xzs.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();
}

2、配置spring-context.xml

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <!--spring框架与mybatis整合配置文夹加载到spring上下文中-->
    <import resource="spring-mybatis.xml"></import>
   <context:annotation-config/>
    <!-- 用注解方式注入bean,并指定查找范围:com.javaxl.ssh2及子子孙孙包-->
    <context:component-scan base-package="com.xzs"/>
    <!--开启动态代理-->
    <aop:aspectj-autoproxy/>
</beans>

3、应用注解

java 复制代码
package com.xzs.annotation.aop;


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);
 
   
    @Pointcut("@annotation(com.xzs.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、Controller层代码

java 复制代码
package com.xzs.web;

import com.xzs.annotation.aop.MyLog;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

@Component
@RequestMapping("/log")
public class LogController {

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

}

结果:

相关推荐
刘鹏3784 分钟前
深入浅出Java中的CAS:原理、源码与实战应用
后端
当归10247 分钟前
微服务与消息队列RabbitMQ
java·微服务
Lx3529 分钟前
《从头开始学java,一天一个知识点》之:循环结构:for与while循环的使用场景
java·后端
fliter9 分钟前
RKE1、K3S、RKE2 三大 Kubernetes 发行版的比较
后端
aloha_10 分钟前
mysql 某个客户端主机在短时间内发起了大量失败的连接请求时
后端
程序员爱钓鱼11 分钟前
Go 语言高效连接 SQL Server(MSSQL)数据库实战指南
后端·go·sql server
xjz184212 分钟前
Java AQS(AbstractQueuedSynchronizer)实现原理详解
后端
Victor35612 分钟前
Zookeeper(97)如何在Zookeeper中实现分布式协调?
后端
至暗时刻darkest12 分钟前
go mod文件 项目版本管理
开发语言·后端·golang
程序员爱钓鱼12 分钟前
Go 语言高效连接 MySQL 数据库:从入门到实战
后端·mysql·go