SpringBoot实践之(十五)---自定义注解Annotation的使用

首先导入相关包

在build.gradle中添加

dependencies {
    //支持AOP
    compile('org.springframework.boot:spring-boot-starter-aop')
}

然后创建Aspect测试类 TestAspect:

import com.great.annotation.OperateLogAnnotation;
import com.great.annotation.TestAnnotation;
//import javassist.bytecode.SignatureAttribute;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
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.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect // FOR AOP
@Order(-99) // 控制多个Aspect的执行顺序,越小越先执行
@Component
public class TestAspect {

    @Before("@annotation(test)")// 拦截被TestAnnotation注解的方法;如果你需要拦截指定package指定规则名称的方法,可以使用表达式execution(...),具体百度一下资料一大堆
    public void beforeTest(JoinPoint point, TestAnnotation test) throws Throwable {
        System.out.println("beforeTest:" + test.name());
    }

    @After("@annotation(test)")
    public void afterTest(JoinPoint point, TestAnnotation test) {
        System.out.println("afterTest:" + test.name());
    }


/*    @Pointcut("@annotation(com.great.annotation.OperateLogAnnotation)")
    public void annotationPointCut() {
    }

   @Before("annotationPointCut()")
    public void before(JoinPoint joinPoint) {
        MethodSignature sign = (MethodSignature) joinPoint.getSignature();
        Method method = sign.getMethod();
        OperateLogAnnotation annotation = method.getAnnotation(OperateLogAnnotation.class);
        System.out.println("打印:" + annotation.value() + " 前置日志1");
    }

    @After("annotationPointCut()")
    public void afterTTT(JoinPoint point) {
        MethodSignature sign = (MethodSignature) point.getSignature();
        Method method = sign.getMethod();
        OperateLogAnnotation annotation = method.getAnnotation(OperateLogAnnotation.class);
        System.out.println("打印自带参数:" + annotation.value() + " 后置日志1");
    }*/

    @Before("@annotation(operateLogAnnotation)")
    public void before(JoinPoint joinPoint,OperateLogAnnotation operateLogAnnotation) {
        System.out.println("打印:" + operateLogAnnotation.value() + " 前置日志2");
    }

    @After("@annotation(operateLogAnnotation)")
    public void afterTTT(JoinPoint point,OperateLogAnnotation operateLogAnnotation) {
        System.out.println("打印自带参数:" + operateLogAnnotation.value() + " 后置日志2");
    }
}

再添加一个自定义的注解类OperateLogAnnotation:

import java.lang.annotation.*;

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperateLogAnnotation {
    String value();
}

然后创建一个TestAOPController 验证一下:

import com.great.annotation.OperateLogAnnotation;
import com.great.annotation.TestAnnotation;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class TestAOPController {

    @TestAnnotation(name="abc")
    @RequestMapping("/show")
    public String show() {
        return "OK";
    }

    @RequestMapping("/show2")
    public String show2() {
        return "OK2";
    }

    @RequestMapping("/show3")
    @ResponseBody
    @OperateLogAnnotation("测试")
    public String getById() {
        return "hello";
    }

}

此时我们访问请求show3则会触发切面被拦截。
这里写图片描述
这里写图片描述

注解基本概念:

java注解:附在代码中的一些元信息,用于在编译、运行时起到说明、配置的功能。

一、元注解

java提供了4种元注解用于注解其他注解,所有的注解都是基于这四种注解来定义的。

@Target注解:用于描述注解的使用范围,超出范围时编译失败。

取值类型(ElementType):

1.CONSTRUCTOR:用于描述构造器

2.FIELD:用于描述域(成员变量)

3.LOCAL_VARIABLE:用于描述局部变量

4.METHOD:用于描述方法

5.PACKAGE:用于描述包

6.PARAMETER:用于描述参数

7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

例如:

@Target(ElementType.TYPE)  
public @interface MyAnnotation {  
    //类名注解,默认即为当前类名  
    String name() default "className";  
}  
import java.lang.annotation.ElementType;  
import java.lang.annotation.Target;  

//字段注解  
@Target(ElementType.FIELD)  
public @interface MyAnnotation1 {  
    String name() default "fieldName";            
    String getFieldValue() default "getField";    
    String setFieldValue() default "setField";   
} 

@Retention:描述注解的生命周期,即注解的生效范围。

取值范围(RetentionPolicy):

1.SOURCE:在源文件中生效,仅存在java文件中,class文件将会去除注解。

2.CLASS:在class文件中生效,仅保留在class文件中,运行时无法获取注解。

3.RUNTIME:在运行时生效,保留在class文件中且运行时可通过反射机制获取。

例如:

@Target(ElementType.FIELD) //字段注解  
@Retention(RetentionPolicy.RUNTIME) //在运行期保留注解信息  
public @interface MyAnnotation1 {  
    String name() default "fieldName";            
    String getFieldValue() default "getField";    
    String setFieldValue() default "setField";   
}  

@Documented:用于指定javac生成API时显示该注解信息。

例如:

@Target(ElementType.FIELD) //字段注解  
@Retention(RetentionPolicy.RUNTIME) //在运行期保留注解信息  
@Documented     //在生成javac时显示该注解的信息  
public @interface MyAnnotation1 {  
    String name() default "fieldName";            
    String getFieldValue() default "getField";    
    String setFieldValue() default "setField";   
}  

@Inherited:标明该注解可以由子类继承,及子类可以继承父类的注解。而默认情况下,子类是不继承父类注解的。

例如:

@Target(ElementType.FIELD) //字段注解  
@Retention(RetentionPolicy.RUNTIME) //在运行期保留注解信息  
@Documented     //在生成javac时显示该注解的信息  
@Inherited      //标明MyAnnotation1注解可以被使用它的子类继承  
public @interface MyAnnotation1 {  
    String name() default "fieldName";            
    String getFieldValue() default "getField";    
    String setFieldValue() default "setField";   
    public enum FieldValue{MYTEST,MYFIELD,MYVALUE};  
    FieldValue  realVale() default FieldValue.MYFIELD;  
}

读取注解

通过反射机制我们可以读取注解信息
java在java.lang.reflect包下新增了AnnotatedElement接口,该接口定义了可以接受注解的元素
为:Class(类)、Constructor(构造器)、Field(字段)、Method(方法)、Package(包)。

AnnotatedElement是所有注解元素的父接口,所有的注解元素都可以通过某个类反射获取该对象,
该对象有一下4个方法来访问Annotation信息。

(1) T getAnnotation(Class annotationClass)
返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。

(2)Annotation[] getAnnotations():返回该程序元素上存在的所有注解。

(3)boolean isAnnotationPresent(Class

package com.dhcc.iscp.web.annotation;  

import java.lang.annotation.ElementType;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  
import java.lang.annotation.Target;  

@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME) //在运行期保留注解信息  
public @interface MyAnnotation {  
    //类名注解,默认即为当前类名  
    String name() default "className";  
}  
package com.dhcc.iscp.web.annotation;  

import java.lang.annotation.Documented;  
import java.lang.annotation.ElementType;  
import java.lang.annotation.Inherited;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  
import java.lang.annotation.Target;  


@Target(ElementType.FIELD) //字段注解  
@Retention(RetentionPolicy.RUNTIME) //在运行期保留注解信息  
@Documented     //在生成javac时显示该注解的信息  
@Inherited      //标明MyAnnotation1注解可以被使用它的子类继承  
public @interface MyAnnotation1 {  
    String name() default "fieldName";            
    String getFieldValue() default "getField";    
    String setFieldValue() default "setField";   
    public enum FieldValue{MYTEST,MYFIELD,MYVALUE};  
    FieldValue  realValue() default FieldValue.MYFIELD;  
}  

实体类:

package com.dhcc.iscp.web.annotation;  

import com.dhcc.iscp.web.annotation.MyAnnotation1.FieldValue;  

@MyAnnotation(name="myTest")  
public class MyTest {  

    @MyAnnotation1  
    String myTest;  

    @MyAnnotation1(name="test",getFieldValue="1",setFieldValue="2",realValue=FieldValue.MYVALUE)  
    String testValue;  

    public String getMyTest() {  
        return myTest;  
    }  

    public void setMyTest(String myTest) {  
        this.myTest = myTest;  
    }  

    public String getTestValue() {  
        return testValue;  
    }  

    public void setTestValue(String testValue) {  
        this.testValue = testValue;  
    }  

}  

测试类:

package com.dhcc.iscp.web.annotation;  

import java.lang.annotation.Annotation;  
import java.lang.reflect.Field;  
import java.lang.reflect.Method;  

public class TestAnnotation {  
    public static void main(String[] args){  
        MyTest myTest = new MyTest();  

        Annotation[] annotations = myTest.getClass().getAnnotations();  //获取类的所有注解  
        for(Annotation anno:annotations){  
            if(anno instanceof MyAnnotation){  
                MyAnnotation myAnnotation = (MyAnnotation)anno;  
                System.out.println("className:"+myAnnotation.name());  
            }else if(anno instanceof MyAnnotation1){  
                MyAnnotation1 myAnnotation1 = (MyAnnotation1)anno;  
                System.out.println("FiledName:"+myAnnotation1.name());  
                System.out.println("setFieldValue"+myAnnotation1.setFieldValue());  
                System.out.println("getFieldValue"+myAnnotation1.getFieldValue());  
                System.out.println("realValue"+myAnnotation1.realValue());  
            }  
        }  

        Field[] fields = myTest.getClass().getDeclaredFields();//获取所有注解字段  
        for(Field field:fields){  
            if(field.isAnnotationPresent(MyAnnotation1.class)){  
                MyAnnotation1 myAnno = (MyAnnotation1)field.getAnnotation(MyAnnotation1.class);  
                System.out.println(field.getName()+"-name:"+myAnno.name());  
                System.out.println(field.getName()+"-getFieldValue:"+myAnno.getFieldValue());  
                System.out.println(field.getName()+"-setFieldValue:"+myAnno.setFieldValue());  
                System.out.println(field.getName()+"-realValue:"+myAnno.realValue());  
            }  
        }  

        Method[] methods = myTest.getClass().getMethods();//获取所有方法  
        for(Method method:methods){  
            if(method.isAnnotationPresent(MyAnnotation1.class)){  
                MyAnnotation1 myAnno1 = (MyAnnotation1)method.getAnnotation(MyAnnotation1.class);  
                System.out.println(myAnno1.getClass());  
            }  
        }  
    }  
}  

测试结果:

这里写图片描述

自定义注解

自定义注解是通过@interface来声明的,其中的每一个方法实际上是声明了一个配置参数,参数名称即为方法名,参数类型即为返回值类型。

自定义注解的格式:

public @interface 注解名{定义体}

注解参数可支持的类型:

1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
2.String类型
3.Class类型
4.enum类型
5.Annotation类型
6.以上所有类型的数组

注解参数的定义规则:

a.只能使用public或默认2种访问修饰,例如:String getName();这里getName()就是使用了默认访问权限。

b.参数类型只能使用上面提到的6种情况

c.如果只有一个参数成员,最好将参数名定义为:value()。

d.注解元素必须有确定值,要么在定义的时候设置默认值,要么在使用注解的时候设置参数值。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot应用中,如果你想要允许跨域请求并在周末(周六、周日)特定时间开启Access-Control-Allow-Origin策略,你可以创建一个自定义过滤器(Filter),例如使用`@CrossOrigin`注解,并通过`@PreAuthorize`或`@ConditionalOnDate`来控制其生效的时间。 首先,创建一个定制的过滤器,比如`WeekendCorsFilter.java`: ```java import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @Configuration @Component public class WeekendCorsFilter { private final ManagementServerProperties management; public WeekendCorsFilter(ManagementServerProperties management) { this.management = management; } @Bean(name = "weekendCorsFilter") public WebMvcConfigurer corsConfigurer() { return (configurer) -> { configurer.addCorsConfiguration( "/**", // 允许所有的路径 headers -> { if (isWeekend()) { // 检查是否为周末 headers.setAllowCredentials(true); // 设置允许凭证 headers.addAllowedHeader("*"); // 允许所有头信息 headers.addAllowedMethod("*"); // 允许所有HTTP方法 headers.addAllowedOrigin("*"); // 允许来自任何源的请求 } else { // 非周末则按默认设置或你自己的规则处理 configurer.cors().allowCredentials(false); configurer.cors().allowedOrigins("http://your-origin.com"); } }); }; } private boolean isWeekend() { String[] daysOfWeek = {"Saturday", "Sunday"}; for (String day : daysOfWeek) { if (management.getEndpointProperties().getWeb().getDatepatterns().contains(day)) { return true; // 如果找到对应的日期模式,则为周末 } } return false; } } ``` 然后在启动类或Spring Boot Actuator配置中启用这个过滤器: ```java @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Autowired private WeekendCorsFilter weekendCorsFilter; // ... @PostConstruct public void init() { weekendCorsFilter.corsConfigurer(); // 加载配置 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值