java自定义注解的使用

在开始讲如何实现自定义注解之前,我们先唠唠嗑,其实我们刚开始学java的时候,如何创建一个对象,这本身就是一个难题,有的人或许会直接说直接new一个,或者通过反射机制直接创建一个类的实例对象进行对对象实例的操作。

不曾想,每个人都是这样经历过来的,不知你是否还记得在spring的xml配置文件里如何配置对象的场景?或许依然记忆犹新,或许早已抛开在脑后,等等吧。后面spring出现了通过注解的方式去注入一个实例,这或许解放了很多我这样的码农双手,坏笑。

通过上面的故事,我们一步一步走进了注解的视野里面,既然熟知注解的应用,接下来我们还是看下如何实现自己的注解吧。

在看示例程序之前,我们看下是如何自定义一个注解的,我们都知道定义一个类使用class标识符进行修饰,定义一个接口使用interface标识进行修饰,那么同样使用@interface标识进行修饰的就是自定义注解。

public @interface ValidatorString {
}

好了,我们既然知道了如何自定义一个自己的注解,接下来我们看下我们的示例程序吧。

package com.wpw.springboot;

import java.lang.annotation.*;

@Documented
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidatorString {
    /**
     * 判断是否为空
     * @return  boolean值
     */
    boolean isEmpty();
}

上面我们实现了一个对字符串进行判空操作的自定义注解,在看下面的程序之前,我们还是看下上面的各个元注解的含义好了。

什么叫做元注解呢?其实这个词语可以不必深究,因为就算你懂了,对你来说也没什么意思,元注解就是修饰注解的注解,是不是有点绕?坏笑。

@Documented:这个注解的含义就是可以包含在javadoc中的。

@Inherited:这个注解的含义就是允许子类继承父类的注解的。

@Target:这个注解的含义就是说这个注解的作用范围,标识这个注解可以用在什么地方。比如说我们可以作用在类上,接口上,字段上,方法上等等等。

@Retention:这个注解的含义就是说注解的保存策略,比如说注解的生效范围,有的可能在编译器生效,有的可能只存在源码级别生效,但是大部分我们都是设置为运行期生效,毕竟我们就是在程序运行期间进行使用的嘛,不知道这段话,你懂了没有。

好了,下面我们需要定义一个类来验证我们的注解是否可行。

package com.wpw.springboot;

public class User {
    @ValidatorString(isEmpty = false)
    private String username;
    @ValidatorMax(max = 120)
    @ValidatorMin(min = 1)
    private int age;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

在上面的示例程序中,我们使用了我们自己的自定义注解对字符串username进行了限定,同样我们使用了下面的注解进行对age属性进行了最大最小的限定。

package com.wpw.springboot;

import java.lang.annotation.*;

@Documented
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public  @interface ValidatorMax {
    /**
     * 校验最大值
     * @return  最大值
     */
    int max();
}
package com.wpw.springboot;

import java.lang.annotation.*;

@Documented
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidatorMin {
    /**
     * @return  返回最小值
     */
    int min();
}

其实上面的是可以放到一个自定义注解里面的。由于文章都有注释,详细解析就不再说明了,你应该都会明白的。

接下来我们就是要写一个自定义解析器,对我们的自定义注解的内容进行解析。

package com.wpw.springboot;

import java.lang.reflect.Field;
import java.util.Objects;

public class ValidatorResolver {
    public static <T> boolean validator(T t) throws IllegalAccessException {
        Field[] fields = t.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            ValidatorString validatorString = field.getAnnotation(ValidatorString.class);
            ValidatorMax validatorMax = field.getAnnotation(ValidatorMax.class);
            ValidatorMin validatorMin = field.getAnnotation(ValidatorMin.class);
            //判断字符是否为空
            if (Objects.nonNull(validatorString) && field.getType().equals(String.class)) {
                if (Objects.isNull(field.get(t)) || ((String) field.get(t)).length() <= 0) {
                    System.out.println(field.getName() + "不可以为空");
                    return false;
                }
            }
            if ((Objects.nonNull(validatorMax) || Objects.nonNull(validatorMin)) && field.getType().equals(Integer.class) &&
                    Objects.isNull(field.get(t))) {
                System.out.println(field.getName() + "字段不可以为空");
                return false;
            }
            //判断该字段是否为Integer或者int类型
            if (field.getType().equals(Integer.class) || field.getType() == int.class) {
                if (Objects.nonNull(validatorMax) && ((int) field.get(t)) > validatorMax.max()) {
                    System.out.println(field.getName() + "字段大于了最大值");
                    return false;
                }
                if (Objects.nonNull(validatorMin) && ((int) field.get(t) < validatorMin.min())) {
                    System.out.println(field.getName() + "字段小于了最小值");
                    return false;
                }
            }
        }
        return true;
    }
}

好了,上面的自定义注解的解析器就写完了,下面我们开始做个测试了,看下我们的自定义注解是否生效。

 public static void main(String[] args) throws IllegalAccessException {
        User user=new User();
        user.setUsername("backCoder");
        user.setAge(90);
        System.out.println(ValidatorResolver.validator(user));//true
    }

上面我们都是对对象user进行了合理的设置,接下来我们故意写个错误的看下是否可以达到我们想要的效果。

public static void main(String[] args) throws IllegalAccessException {
        User user=new User();
        user.setAge(90);
        System.out.println(ValidatorResolver.validator(user));
    }

当我们不设置username值时,我们看下控制台的输出语句。

username不可以为空
false

这就是我们在解析器里面输出的内容和返回的结果。

本文分享自微信公众号 - 后端Coder(gh_245290c1861a)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Linyb极客之路

SpringBoot注解最全详解(整合超详细版本)

@SpringBootApplication:申明让spring boot自动给程序进行必要的配置,这个配置等同于:@Configuration ,@Enabl...

12510
来自专栏架构之美

大中台模式下如何构建复杂业务核心状态机组件

由此可见,对于复杂状态的管理是一个业务依赖,需求多变的场景。在公司初创期,可以采用硬编码方式,对于每一个操作进行状态判断,每一步操作定制一套逻辑链路。随着业务的...

10730
来自专栏码匠的流水账

聊聊rocketmq的MessageQueueSelector

rocketmq-client-4.5.2-sources.jar!/org/apache/rocketmq/client/producer/MessageQu...

7310
来自专栏chenchenchen

关于Spring的BeanUtils

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

5100
来自专栏Java架构学习路线

2019年Spring核心知识点整理,看看你掌握了多少?

如今做Java尤其是web几乎是避免不了和Spring打交道了,但是Spring是这样的大而全,新鲜名词不断产生,学起来给人一种凌乱的感觉,在这里总结一下,理顺...

9120
来自专栏Java大联盟

Spring Boot+Vue|axios异步请求数据的12种操作(下篇)

上一篇 axios 教程中,我已经为大家详细讲解了 axios 异步请求数据的前 6 种操作方式:Spring Boot+Vue|axios异步请求数据的12种...

12420
来自专栏泰斗贤若如

Java匹马行天下之一顿操作猛如虎,框架作用知多少?

  框架就是开发人员定义好的一套模板,程序员只需要往模板中添加响应的代码即可,填完代码,项目就完成了。所以框架存在的意义以及我们学习框架的目的就是想办法能够让程...

10010
来自专栏码匠的流水账

聊聊rocketmq的ExtProducerResetConfiguration

本文主要研究一下rocketmq的ExtProducerResetConfiguration

4710
来自专栏码匠的流水账

聊聊RocketMQTemplate

rocketmq-spring-boot-2.0.3-sources.jar!/org/apache/rocketmq/spring/core/RocketMQ...

7530
来自专栏须臾之余

SpringBoot源码分析 顶

一:创建SpringApplication对象过程:new SpringApplication(primarySources)

5520

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励