美文网首页技术干货程序员
我的后端打怪升级之路一:注解

我的后端打怪升级之路一:注解

作者: 秋名山菜车手 | 来源:发表于2018-01-28 16:45 被阅读0次

    原文链接 - Joker's
    欢迎大家访问我的个人博客:)

    大约有一个月没写博啦,中间经历了急性支气管炎、大雪封山、懒癌附身种种,这次想写的是「注解」,一个之前一直很惧怕的东西。

    起因是跟着【手把手】JavaWeb 入门级项目实战 -- 文章发布系统 (第四节)这篇博文在做入门的 jsp 项目,所以接触到了。接触到了,自然就要了解一下。部分内容出自原博客,侵删。

    我是后端新手,以前完全没接触过后端项目,所以做的时候理解上会有问题,同时我也想把自己遇到的这些问题,用浅显易懂的方式说出来,可以供有相同疑惑的朋友参考。如有不足之处,欢迎指正。

    这篇文章可能有点长,但写的应该比较容易看懂,如果你也是新手,希望你能看到最后,不明白的部分可以留言给我讨论。文章整体脉络应该是比较清晰:首先介绍注解是什么,然后再看注解的定义,最后是如何使用,把这些讲完之后我又举了一个完整的实例来讲解。


    目录

    Step 1. 注解是什么

    首先介绍一下,注解到底是个啥?为什么用途这么广泛?

    Step 2. 注解怎么写

    初步了解以后,让我们直接上手写一个!

    Step 3. 注解如何用

    写完注解不会用相当于没有写,那么我们如何使用呢?
    3.1 给谁用?
    3.2 怎么用?
    3.3 几个注意点

    Step 4. 看一个完整的例子:获取数据库表名

    从零开始,展示一个完整的注解用法。
    4.1 第 0-1 步:给谁用?(JavaBean)
    4.2 第 0-2 步:注解怎么写(定义注解)
    4.3 第 1 步:获取类的对象
    4.4 第 2 步:获得相应的方法/域
    4.5 第 3 步:获取注解的实例
    4.6 第 4 步:获取对应的属性

    参考


    正文

    Step 1. 注解是什么

    原博主写了一篇文章非常好,推荐仔细看一遍:用大白话聊聊JavaSE -- 自定义注解入门。我看了三遍,才感觉理解个差不多。

    我简单总结一下原博主的思想:注解就像是写给电脑看的注释,有了注解,我们可以通过代码来获得关于一个方法或者一个类的信息。在平时的开发过程中,我们会给一个类、方法或者域添加注释,比如,我们会在方法前面添加关于入参、返回值、以及方法作用的注释。同样的,我们可以给一个类、方法或者域添加注解。

    同时,你仔细观察的话,会发现注解非常像一个空的接口。

    了解了这些内容,我来介绍一下元注解的概念。典型的元注解有 @Target@Retention ,这是我们在定义一个注解时需要用到的,

    @Target 用来定义你的注解用在什么地方:

    • @Target(ElementType.FIELD) 表示用于一个域
    • @Target(ElementType.METHOD) 表示用于一个方法
    • @Target(ElementType.TYPE) 则表示用于一个类。

    @Retention 用来定义注解在哪一个级别可用:

    • @Retention(RetentionPolicy.SOURCE) 表示在源代码中可用
    • @Retention(RetentionPolicy.CLASS) 表示在类文件中可用
    • @Retention(RetentionPolicy.RUNTIME) 表示在运行时可用,一般用的比较多。

    Step 2. 注解怎么写

    下面让我们来看一下注解的格式,我们参照原作者的方式,来给方法写一个注解:

    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 MethodAnnotation {
        // 方法作用,有默认值
        String description() default "作者很懒,没有写本方法的作用";
        // 方法创建时间
        String createTime();
    }
    

    很显然,我们可以通过这个注解来获取方法的作用和创建时间,当然,我们也可以加上作者,无非是再加这么一行:String author() default "Joker";。此外,在定义注解的过程中,默认值是可选的。

    Step 3. 注解如何用

    好,通过上面两部分,我们已经了解了注解是什么,以及如何写一个简单的注解,接下来看一看注解是怎么用的。这要分为两部分来说。

    3.1 给谁用?

    既然明白了我们刚刚编写的注解时用来写给方法的,那么我们想获得哪个方法的作用和创建时间呢?

    让我们来随便写一个:

    package util;
    
    import java.util.Date;
    import java.text.SimpleDateFormat;
    
    public class DateUtil {
        @MethodAnnotation(createTime = "2018-01-01")
        public static String formatDate(Date date , String formatPattern){
            return new SimpleDateFormat(formatPattern).format(date);
        }
    }
    

    现在目标明确了,我们是想获得 formatDate 这个方法的作用和创建时间,那就先给方法加上我们刚刚创建的注解,也就是@MethodAnnotation()。括号里面要填入注解中对应的参数和值,有默认值的可以不用写。如果参数没有默认值,且在这里没有填写的话(比如在这里只写一个空括号),ide 会报 The annotion @MethodAnnotation must define the attribute createTime错误。

    3.2 怎么用?

    计算机如何在 Java 类中获取我们上面定义的注解信息呢?

    那我们不得不聊聊另外一个名词:反射。我们先来看一个例子(这里我还是使用原作者的例子,侵删),在 DateUtil.java 中创建一个单元测试(main 方法)如下:

    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
        Class classOfDateUtil = DateUtil.class;
        Method formatDate = classOfDateUtil.getMethod("formatDate", Date.class,String.class);
        MethodAnnotation methodNote = formatDate.getAnnotation(MethodAnnotation.class);
    
        System.out.println("方法描述:" + methodNote.description());
        System.out.println("创建日期:" + methodNote.createTime());
    }
    

    首先读一下上面的代码,自己想一想,然后再来看我的总结。

    ---------------------------------------------------分割线---------------------------------------------------

    关于上面的反射过程,我个人总结为四部曲:

    1. 获取类的对象。如果在编译器能够知道名字的话,可以使用上面的方法;如果在编译器不知道类的名字,但是可以在运行期获得到类名字符串的话,可以使用以下方法:
    String className = ... ;//在运行期获取的类名字符串
    Class class = Class.forName(className);
    
    1. 根据类对象获得相应的方法/域,如果注解是加在类上的,可以省略这一步。主要方法有(具体用法可以自己去查询 API 文档):
    • Field getField()
    • Field[] getFields() 返回 Field 数组,包括这个类及其父类的公有域。
    • Field[] getDeclaredFields() 返回 Field 数组,包括这个类的所有域。
    • Method getMethod()
    • Method[] getMethods() 返回所有的公有方法,包括从父类继承来的公有方法。
    • Method[] getDeclaredMethods() 返回所有的方法,但不包括由父类继承来的方法。
    1. 根据获得的域/方法/类对象,结合 getAnnotations() 方法来获取注解的实例。
    2. 根据注解实例,获取对应的信息。结束!

    3.3 几个注意点

    • 不要漏写 default 值。
    • 在第二步时,注意看下用到的方法是否抛出异常。如果有的话,在3中不要忘记抛出。

    Step 4. 看一个完整的例子:获取数据库表名

    这里的情景是,用户在登陆页面上输入了用户名和密码,点登陆的时候,发送请求到我们的 controller 层,此时我们把用户数据封装为一个 JavaBean,再把 JavaBean 转化为建表语句。为了简化过程,最后一步我省略掉,我们只看怎么获取表名即可。

    关于 JavaBean 大家可以看看原博主的这篇文章:用大白话聊聊JavaSE -- 如何理解Java Bean(一),写的非常好。

    我简单解释一下 JavaBean 和数据库的对应关系:写 JavaBean 的过程其实就相当于是数据库的设计过程,对应着属性对应着字段

    4.1 第 0-1 步:给谁用?(JavaBean)

    既然是用户,我们新建一个 User 类,我只抽了一部分。

    public class User {
        private String username;
        private String password;
        ...
        
        public void setUsername(String username) {
            this.username = username;
        }
        
        public String getUsername() {
            return username;
        }
        
        public void setPassword(String password) {
            this.password = password;
        }
        
        public String getPassword() {
            return password;
        }
    }
    

    4.2 第 0-2 步:注解怎么写(定义注解)

    我们新建一个 Annotation 文件,就叫 Table。

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Table {
        public String tableName(); 
    }
    

    这里把导包过程省略了,请大家自行补充。

    这步做完之后,我们给 0-1 中的 User 类加上注解,参数设置为 t_user,即表名:

    @Table(tableName = "t_user")
    public class User {
    }
    

    4.3 第 1 步:获取类的对象

    这里我们封装一个 TableUtils 作为数据库表的工具类,来使用注解,真正的调用过程我们在单元测试中进行。在刚刚讲解的过程中,其实是把这两部分合二为一了。在实际开发过程中,可能要将不同的模块分包处理,比如 annotions 包、util 包、bean 包等等。

    // 作为工具类API使用,直接传入类的对象
    public class TableUtils {
        public static String getCreateTablename(Class<?> clazz) {
            
        }
    }
    
    // 在这里传入类
    public class TestMain {
        public static void main(String[] args) {
            TableUtils.getCreateTablename(User.class);
        }
    }
    

    4.4 第 2 步:获得相应的方法/域

    因为我们的注解是加在类上的,所以这一步可以省略。

    4.5 第 3 步:获取注解的实例

    既然是获取注解的实例,肯定是在直接使用注解的地方,也就是 TableUtils 中进行。

    public static String getCreateTablename(Class<?> clazz) {
        Table table = clazz.getAnnotation(Table.class);        
    }
    

    4.6 第 4 步:获取对应的属性

    这里我们要获取表名,可以控制台打印下,看看是不是我们的 t_user

    public static String getCreateTablename(Class<?> clazz) {
        Table table = clazz.getAnnotation(Table.class); 
        String tableName = table.tableName();
        System.out.println(tableName);
    }
    

    至此,一个完整的注解 demo 完成,感谢大家看到最后~

    参考

    相关文章

      网友评论

        本文标题:我的后端打怪升级之路一:注解

        本文链接:https://www.haomeiwen.com/subject/mskzaxtx.html