手写 Hibernate ORM 框架 02-实体 Bean 定义,建表语句自动生成

手写 Hibernate 系列

手写 Hibernate ORM 框架 00-hibernate 简介

手写 Hibernate ORM 框架 00-环境准备

手写 Hibernate ORM 框架 01-注解常量定义

手写 Hibernate ORM 框架 02-实体 Bean 定义,建表语句自动生成

手写 Hibernate ORM 框架 03-配置文件读取, 数据库连接构建

手写 Hibernate ORM 框架 04-持久化实现

手写 Hibernate ORM 框架 05-整体效果测试验证

从零手写组件系列

java 从零手写 spring ioc 控制反转

java 从零手写 spring mvc

java 从零手写 jdbc-pool 数据库连接池

java 从零手写 mybatis

java 从零手写 hibernate

java 从零手写 rpc 远程调用

java 从零手写 mq 消息组件

java 从零手写 cache 缓存

java 从零手写 nginx4j

java 从零手写 tomcat

本节内容

实体 Bean 的定义。

根据实体 Bean 生成对应的建表语句。

定义实体 Bean

简单的用户实体信息定义

java 复制代码
package com.ryo.hibernate.simulator.model;


import com.ryo.hibernate.simulator.hibernate.annotations.Column;
import com.ryo.hibernate.simulator.hibernate.annotations.Entity;
import com.ryo.hibernate.simulator.hibernate.annotations.GenerateValue;
import com.ryo.hibernate.simulator.hibernate.annotations.Id;

import java.util.Date;

/**
 * 用户实体类
 * Created by houbinbin on 16/6/5.
 */
@Entity("t_user")
public class User {
    @Id
    @GenerateValue
    private Long id;
    private String name;
    private String password;
    @Column("myAge")
    private Integer age;
    private Date createOn;
    private Date modifiedOn;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

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

    public Date getCreateOn() {
        return createOn;
    }

    public void setCreateOn(Date createOn) {
        this.createOn = createOn;
    }

    public Date getModifiedOn() {
        return modifiedOn;
    }

    public void setModifiedOn(Date modifiedOn) {
        this.modifiedOn = modifiedOn;
    }
}

Table

实现

Table 核心类的实现

java 复制代码
package com.ryo.hibernate.simulator.hibernate;


import com.ryo.hibernate.simulator.hibernate.annotations.Column;
import com.ryo.hibernate.simulator.hibernate.constants.HibernateConstant;
import com.ryo.hibernate.simulator.hibernate.util.FieldUtil;
import com.ryo.hibernate.simulator.hibernate.util.TableUtil;
import com.ryo.hibernate.simulator.util.ReflectionUtil;
import com.ryo.hibernate.simulator.util.StringBuilderUtil;

import java.lang.reflect.Field;

/**
 * 表
 * @author houbinbin
 * Created by houbinbin on 16/6/5.
 */
public class Table {
    /**
     * 构建创建表的 SQL
     * @param t 泛型入参
     * @param <T> 泛型
     * @return sql
     */
    public <T> String buildCreateTableSQL(T t) {
        String tableName = TableUtil.getTableName(t);
        StringBuilder stringBuilder = new StringBuilder("create table ");
        stringBuilder.append(tableName).append(" (");

        for(Field field : ReflectionUtil.getFieldList(t)) {
            stringBuilder.append(buildFieldSQL(t, field));
        }

        String result = StringBuilderUtil.removeLastStr(stringBuilder, ", ");
        result = buildPrimaryKey(t, result);

        return String.format("%s );", result);
    }

    /**
     * 构建主键SQL
     * @param t 入参
     * @param result 结果
     * @param <T> 泛型
     * @return SQL
     */
    private <T> String buildPrimaryKey(T t, String result) {
        Field field = FieldUtil.getIdField(t);

        if(field != null) {
            String idFieldName = FieldUtil.getFieldName(field);
            result = String.format("%s , PRIMARY KEY  (`%s`)", result, idFieldName);
        }

        return result;
    }

    private <T> String buildFieldSQL(T t, Field field) {
        String result;
        String fieldName = FieldUtil.getFieldName(field);
        String sqlType = FieldUtil.getSqlType(field);

        result = String.format("%s %s", fieldName, sqlType);
        Column column = FieldUtil.getFieldColumnAnnotation(field);

        if(ReflectionUtil.isType(field, String.class)) {
            int length = column != null ? column.length() : HibernateConstant.DEFAULT_STRING_SIZE;
            result = String.format("%s(%d)", result, length);
        }

        if(column != null) {
            result = String.format("%s %s", result, getNullAbleInfo(column));
        }

        if(FieldUtil.isGenerateValueField(t, field)) {
            result = String.format("%s AUTO_INCREMENT", result);
        }

        return String.format("%s, ", result);
    }

    /**
     * 获取是否可以为空的信息
     * @param column 列信息
     * @return 是否可以为空的结果
     */
    private String getNullAbleInfo(Column column) {
        return column.nullable() ? "" : "NOT NULL";
    }

}

测试

  • TableTest.java
java 复制代码
/**
 * 建表语句测试
 */
@Test
public void createTableSQLTest() {
    Table table = new Table();
    User user = new User();
    System.out.println(table.buildCreateTableSQL(user));
}

测试结果:

sql 复制代码
create table t_user (id BIGINT AUTO_INCREMENT, name VARCHAR(255), password VARCHAR(255), myAge INTEGER , createOn DATETIME, modifiedOn DATETIME , PRIMARY KEY  (`id`) );

Table 中涉及到的工具类

后面如有重复,将不再赘述

FieldUtil

java 复制代码
package com.ryo.hibernate.simulator.hibernate.util;


import com.ryo.hibernate.simulator.hibernate.annotations.Column;
import com.ryo.hibernate.simulator.hibernate.annotations.GenerateValue;
import com.ryo.hibernate.simulator.hibernate.annotations.Id;
import com.ryo.hibernate.simulator.hibernate.constants.TypeMap;
import com.ryo.hibernate.simulator.util.CollectionUtil;
import com.ryo.hibernate.simulator.util.StringUtil;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import static com.ryo.hibernate.simulator.util.ReflectionUtil.getAnnotation;
import static com.ryo.hibernate.simulator.util.ReflectionUtil.getFieldList;
import static com.ryo.hibernate.simulator.util.ReflectionUtil.getFieldValueForce;
import static com.ryo.hibernate.simulator.util.ReflectionUtil.isType;

/**
 *
 * 字段工具类
 * @author houbinbin
 * @date 16/6/5
 */
public class FieldUtil {
    /**
     * 获取对应SQL字段类型
     * @param field
     * @return
     */
    public static String getSqlType(Field field) {
        return TypeMap.getTypeMap().get(field.getType().getTypeName());
    }

    /**
     * 获取字段名称
     * @param field
     * @return
     */
    public static String getFieldName(Field field) {
        String fieldName = field.getName();
        Annotation annotation = getAnnotation(field, Column.class);

        Column column = getFieldColumnAnnotation(field);
        if(column != null) {
            String columnValue = column.value();
            fieldName = StringUtil.isEmpty(columnValue) ? fieldName : columnValue;
        }

        return fieldName;
    }

    /**
     * 获取子弹注解信息
     * @param field
     * @return
     */
    public static Column getFieldColumnAnnotation(Field field) {
        Annotation annotation = getAnnotation(field, Column.class);

        if(annotation != null) {
            return (Column) annotation;
        }

        return null;
    }

    /**
     * 获取ID字段
     * - 不存在则返回null
     * @param t
     * @param <T>
     * @return
     */
    public static <T> Field getIdField(T t) {
        for (Field field : getFieldList(t)) {
            Annotation annotation = getAnnotation(field, Id.class);
            if(annotation != null) {
                return field;
            }
        }

        return null;
    }

    /**
     * 获取自增长字段。
     * @param <T>
     * @return
     */
    public static <T> Field getGenerateValueField(T t) {
        for(Field field : getFieldList(t)) {
            Annotation annotation = getAnnotation(field, GenerateValue.class);
            if(annotation != null) {
                return field;
            }
        }

        return null;
    }

    /**
     * 是否为 GenerateValue 字段
     * @param t
     * @param field
     * @param <T>
     * @return
     */
    public static <T> boolean isGenerateValueField(T t, Field field) {
        Field generateValueField = getGenerateValueField(t);
        return generateValueField != null && field.equals(generateValueField);
    }

    /**
     * 获取字段名称列表
     * @param t
     * @param <T>
     * @return
     */
    public static <T> List<String> getFieldNameList(T t) {
        List<String> fieldNameList = new LinkedList<>();

        for(Field field : getFieldList(t)) {
            fieldNameList.add(getFieldName(field));
        }

        return fieldNameList;
    }

    /**
     * 获取字段名称字符串形式
     * @param t
     * @param <T>
     * @return
     */
    public static <T> String getFieldNameString(T t) {
        return CollectionUtil.concatCollection2Str(FieldUtil.getFieldNameList(t));
    }

    /**
     * 获取字段值字符串形式
     * @param t
     * @param <T>
     * @return
     */
    public static <T> String getFieldValueString(T t) {
        List<String> valueStrList = new LinkedList<>();
        for(Field field : getFieldList(t)) {
            valueStrList.add(String.format("'%s'", getValueString(t, field)));
        }

        return CollectionUtil.concatCollection2Str(valueStrList);
    }

    /**
     * 获取指定字段值字符串
     * @param t
     * @param field
     * @param <T>
     * @return
     */
    private static <T> String getValueString(T t, Field field) {
        Object value = getFieldValueForce(t, field.getName());

        String result = value.toString();

        if(isType(field, Date.class)) {
            result = dateToString((Date) value);
        }

        return result;
    }

    /**
     * 日期转字符串
     * @param dateTime 日期
     * @return 字符串
     */
    private static String dateToString(Date dateTime) {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(dateTime);
    }

}

TableUtil

java 复制代码
package com.ryo.hibernate.simulator.hibernate.util;


import com.ryo.hibernate.simulator.hibernate.annotations.Entity;
import com.ryo.hibernate.simulator.util.ReflectionUtil;
import com.ryo.hibernate.simulator.util.StringUtil;

import java.lang.annotation.Annotation;

/**
 * 列表工具类
 *
 * @author houbinbin
 * @date 16/6/5
 */
public class TableUtil {
    private TableUtil() {
    }

    /**
     * 获取表名称
     *
     * @param t
     * @param <T>
     * @return 表名称
     */
    public static <T> String getTableName(T t) {
        Annotation annotation = ReflectionUtil.getAnnotation(t, Entity.class);

        String tableName = ReflectionUtil.getClassName(t);

        if (annotation != null) {
            Entity entity = (Entity) annotation;
            String tableValue = entity.value();
            tableName = StringUtil.isEmpty(tableValue) ? tableName : tableValue;
        }

        return tableName;
    }
}

ReflectionUtil

java 复制代码
package com.ryo.hibernate.simulator.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;


/**
 *
 * 反射工具类
 * @author houbinbin
 * @date 16/6/5
 */
public class ReflectionUtil {

    /**
     * 是否为某一类型
     * @param field
     * @param clazz
     * @return
     */
    public static Boolean isType(Field field, Class clazz) {
        return field.getType().equals(clazz);
    }

    /**
     * 获取类名
     * @param t
     * @param <T>
     * @return
     */
    public static <T> String getClassName(T t) {
        Class clazz = t.getClass();
        return clazz.getSimpleName();
    }

    /**
     * 获取子弹列表
     * @param t
     * @param <T>
     * @return
     */
    public static <T> Field[] getFieldList(T t) {
        Class clazz = t.getClass();

        return clazz.getDeclaredFields();
    }


    /**
     * 强制获取字段值
     * @param t
     * @param fieldName
     * @param <T>
     * @return
     */
    public static <T> Object getFieldValueForce(T t, String fieldName) {
        Class clazz = t.getClass();
        Object value = null;
        try {
            Field field = clazz.getDeclaredField(fieldName);
            value = getFieldValue(t, field);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        return value;
    }

    /**
     * 获取字段值
     * @param t
     * @param field
     * @param <T>
     * @return
     */
    private static <T> Object getFieldValue(T t, Field field) {
        Object value = null;
        field.setAccessible(true);
        try {
            value = field.get(t);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return value;
    }

    /**
     * 获取注解信息
     * @param t
     * @param annotationClass
     * @param <T>
     * @return
     */
    public static <T> Annotation getAnnotation(T t, Class annotationClass) {
        Class clazz = t.getClass();

        return clazz.getAnnotation(annotationClass);
    }

    /**
     * 获取注解信息
     * @param field
     * @param annotationClass
     * @return
     */
    public static Annotation getAnnotation(Field field, Class annotationClass) {
        return field.getAnnotation(annotationClass);
    }
}

StringBuilderUtil

java 复制代码
package com.ryo.hibernate.simulator.util;

/**
 * 字符串Builder-工具类
 *
 * @author houbinbin
 * @date 16/6/5
 */
public class StringBuilderUtil {

    /**
     * 移除最后一饿字符
     *
     * @param stringBuilder stringBuilder
     * @param subStr        需要字符串
     * @return 新的结果
     */
    public static String removeLastStr(StringBuilder stringBuilder, String subStr) {
        int lastIndex = stringBuilder.lastIndexOf(subStr);
        return stringBuilder.substring(0, lastIndex);
    }
    
}

StringUtil

java 复制代码
package com.ryo.hibernate.simulator.util;

/**
 * 字符串-工具类
 * @author houbinbin
 * @date 16/6/5
 */
public class StringUtil {

    /**
     * 空字符串
     */
    public static final String EMPTY_STRING = "";

    /**
     * 是否为空
     * @param string
     * @return
     */
    public static Boolean isEmpty(String string) {
        return string == null || EMPTY_STRING.equals(string.trim());
    }

}

CollectionUtil

java 复制代码
package com.ryo.hibernate.simulator.util;

import java.util.Collection;

/**
 * 集合工具类
 * @author houbinbin
 * @date 16/6/5
 */
public class CollectionUtil {
    /**
     * 默认连接符
     */
    public static final String CONNECTER = ",";

    /**
     * 是否为空
     *
     * @param array
     * @return
     */
    public static boolean isEmpty(Object[] array) {
        return (array == null) || (array.length <= 0);
    }


    /**
     * Collection<String>,根据连接符转成字符串.
     * 注意:如set 是无序的。。。
     *
     * @param collection
     * @param connector  //连接符默认为","
     * @return
     */
    public static String concatCollection2Str(Collection<String> collection, String... connector) {
        String conn = isEmpty(connector) ? CollectionUtil.CONNECTER : connector[0];
        StringBuilder stringBuilder = new StringBuilder();

        for (String str : collection) {
            if (stringBuilder.length() > 0) {
                stringBuilder.append(conn);
            }
            stringBuilder.append(str);
        }

        return stringBuilder.toString();
    }
}
相关推荐
试行3 分钟前
Android实现自定义下拉列表绑定数据
android·java
茜茜西西CeCe9 分钟前
移动技术开发:简单计算器界面
java·gitee·安卓·android-studio·移动技术开发·原生安卓开发
救救孩子把13 分钟前
Java基础之IO流
java·开发语言
小菜yh15 分钟前
关于Redis
java·数据库·spring boot·redis·spring·缓存
宇卿.21 分钟前
Java键盘输入语句
java·开发语言
浅念同学21 分钟前
算法.图论-并查集上
java·算法·图论
立志成为coding大牛的菜鸟.34 分钟前
力扣1143-最长公共子序列(Java详细题解)
java·算法·leetcode
鱼跃鹰飞35 分钟前
Leetcode面试经典150题-130.被围绕的区域
java·算法·leetcode·面试·职场和发展·深度优先
爱上语文2 小时前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
serve the people2 小时前
springboot 单独新建一个文件实时写数据,当文件大于100M时按照日期时间做文件名进行归档
java·spring boot·后端