美文网首页Android开发经验谈
那些高端、优雅的注解是怎么实现的<6> --自定义持久层框架-类

那些高端、优雅的注解是怎么实现的<6> --自定义持久层框架-类

作者: ifjgm | 来源:发表于2019-10-12 22:17 被阅读0次

    概述

    上一篇我们用apt,实现了一个自动生成工厂类的实例。这篇我们使用反射的方式去实现一个持久层框架,当然只是核心代码,并不是可以直接拿来使用的商业项目 ,类似于 Hibernate

    自定义注解系列文章

    需求

    • 有一张用户表(user),包括用户id、用户名、昵称、年龄、性别、邮箱、手机号等字段
    • 根据bean 类中包含的信息查询在 user 表中查询出符合条件的 user

    定义实体类并和 user 表形成映射关系

    定义beanCustomer

    @Table("user")
    public class Customer {
        //id
        @Column("id")
        private int id;
    
        //姓名
        @Column("user_name")
        private String userName;
    
        //年龄
        @Column("age")
        private int age;
    
        //城市
        @Column("city")
        private String city;
    
        //邮箱
        @Column("email")
        private String email;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        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;
        }
    
        public String getCity() {
            return city;
        }
    
        public void setCity(String city) {
            this.city = city;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    }
    
    

    我们需要定义@Table注解来让 user 表和 Customer 类之间形成映射关系。需要定义 @Columnuser 表 和 Customer 类的字段之间形成映射关系。

    定义注解

    • 定义 @Table 注解
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Table {
        String value();
    }
    
    • 定义 @Column 注解
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Column {
        String value();
    }
    

    解析注解并生成相应的逻辑代码

    我们最后需要生成sql语句类似如下

    select * from user where 1=1 and user_name='zhangsan' and age=18 and email in('xxx@163.com,xxx@qq.com,xxx@yahoo.com.cn')
    

    下面我们定义query 方法,去解析注解,并拼接完成我们的 sql 语句 。

     public static String query(Object bean) {
    
            //因为最后我们会返回sql语句,所以这里我们需要拼接sql语句
            StringBuilder sb = new StringBuilder();
    
            //首先获取 bean 类的 class,本例就是 Customer
            Class<?> beanClass = bean.getClass();
    
            //判断该 class 上是否有 table 注解
            boolean present = beanClass.isAnnotationPresent(Table.class);
            if (!present) {
                return "";
            }
    
            //获取该 class上 table 注解
            Table table = beanClass.getAnnotation(Table.class);
    
            //获取表名
            String tableName = table.value();
            sb.append("select * from")
                    .append(" ")
                    .append(tableName)
                    .append(" ")
    
                    //防止没有查询条件而报错
                    .append("where 1=1");
    
            //获取类里面的所有字段
            Field[] fields = beanClass.getDeclaredFields();
    
            //遍历所有字段
            for (Field field : fields) {
    
                //判断字段上是否有Colomn 注解
                boolean fieldPresent = field.isAnnotationPresent(Column.class);
    
                //如果不存在,跳过这个字段继续下一个循环
                if (!fieldPresent) {
                    continue;
                }
    
                //获取到 Column
                Column column = field.getAnnotation(Column.class);
    
                //获取 Column 的名称,如(user_name)
                String columnName = column.value();
    
                //获取字段的名称,如 useName
                String fieldName = field.getName();
    
                //通过该字段的get方法名
                String fieldGetName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    
    
                Object value = null;
    
                try {
                    //获取到get方法
                    Method method = beanClass.getMethod(fieldGetName);
    
                    //反射调用该字段的get方法,获取到该字段的值
                    value = method.invoke(bean);
    
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
    
                //如果不为空,则开始添加 and 语句
                if (value == null ||((value instanceof Integer)&& (Integer)value==0)) {
                    continue;
                }
    
                //如果有值则添加 and 语句
                sb.append(" ")
                        .append("and").append(" ")
                        .append(columnName)
    
                ;
    
                //如果这个字段是int类型
                if (value instanceof Integer) {
                    sb.append("=").append(value);
                } else if (value instanceof String) {
    
                    //如果包含逗号,则是in查询
                    if (((String) value).contains(",")) {
                        String[] values = ((String) value).split(",");
    
                        //添加 in 语句
                        sb.append(" ").append("in('");
    
                        //添加查询条件,并用逗号隔开
                        for (String item : values) {
                            sb.append(item).append(",");
                        }
    
                        //去除最后一个逗号
                        sb.deleteCharAt(sb.length() - 1);
    
                        sb.append("')");
    
                    }
    
                    //如果单个查询用 = 即可,但需要加入单引号
                    else {
    
    
                        sb.append("='").append(value).append("'");
                    }
                }
    
    
            }
    
    
            return sb.toString();
        }
    

    调用 query 方法,获取sql语句

        public static void main(String[] args) {
            // new  Customer,并赋值
            Customer customer1 = new Customer();
            customer1.setUserName("zhangsan");
            customer1.setAge(18);
            customer1.setEmail("xxx@163.com,xxx@qq.com,xxx@yahoo.com.cn");
            
            
            //调用 query 方法,获取 sql 语句 
            String sql1 = Query.query(customer1);
            
            
            //打印sql语句
            System.out.println(sql1);
        }
    

    总结

    完整的代码我会上传到 github,如果仅仅上上面的代码片段无法看懂,那clone下来看看吧!

    相关文章

      网友评论

        本文标题:那些高端、优雅的注解是怎么实现的<6> --自定义持久层框架-类

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