Mybatis(拦截器实现)通用mapper及全ORM实现(三)

本文详细介绍了在MybatisEXT中如何利用注解实现数据库表、字段与实体类的对应关系。包括@Table、@Column、@OneOne和@OneToMany等注解的用法,以及定义的ColumnInfo、TableInfo和RelationshipInfo等关键类的作用,旨在提供一种全ORM的解决方案。通过实体基类和静态变量tableMap来管理和存储元数据信息。

因为需要知道数据库表、字段和实体类的对应关系,那么下面就介绍下在mybatisext中如何实现的

  1. 注解定义

    表注解@Table
     
    package cw.frame.mybatisext.annotation;
    
    import java.lang.annotation.*;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Table {
        String value() default "";
    }
    

    列注解@Column

    package cw.frame.mybatisext.annotation;
    
    import java.lang.annotation.*;
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Column {
        String value() default "";
        boolean primaryKey() default false;
        boolean generatedKey() default true;
    }
    

    一对一注解@OneOne

    package cw.frame.mybatisext.annotation;
    
    import cw.frame.mybatisext.base.entity.BaseExtEntity;
    
    import java.lang.annotation.*;
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface OneOne {
    
        Class<? extends BaseExtEntity> type();
    
        String foreignKey();
    
        String propertyKey();
    }
    

    一对多注解@OneMany

    package cw.frame.mybatisext.annotation;
    
    import cw.frame.mybatisext.base.entity.BaseExtEntity;
    
    import java.lang.annotation.*;
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface OneMany {
        Class<? extends BaseExtEntity> type();
    
        String foreignKey();
    
        String propertyKey();
    }
    

     

  2. 枚举类型定义

    package cw.frame.mybatisext.base.entity;
    
    public interface BaseExtEnum {
    
        public Object getValue();
    
        public String getName();
    
    }

     

  3. 字段信息类ColumnInfo
     

    package cw.frame.mybatisext.base.entity;
    
    import java.lang.reflect.Field;
    
    public class ColumnInfo {
        private TableInfo table;
        private String propertyName;
        private String columnName;
        private boolean isPrimaryKey = false;
        private boolean isGeneratedKey = true;
        private boolean isDbColumn = true;
        private Field field;
    
        public static ColumnInfo createDbColumn(TableInfo table, String propertyName, String columnName, boolean isPrimaryKey, boolean isGeneratedKey, Field field){
            return new ColumnInfo(table, propertyName, columnName, isPrimaryKey, isGeneratedKey, field);
        }
    
        public static ColumnInfo createNormalColumn(TableInfo table, String propertyName, Field field){
            return new ColumnInfo(table, propertyName, field);
        }
    
        private ColumnInfo(TableInfo table, String propertyName, String columnName, boolean isPrimaryKey, boolean isGeneratedKey, Field field){
            this.table = table;
            this.propertyName = propertyName;
            this.columnName = columnName;
            this.isPrimaryKey = isPrimaryKey;
            this.isGeneratedKey = isGeneratedKey;
            this.isDbColumn = true;
            this.field = field;
        }
    
        private ColumnInfo(TableInfo table, String propertyName, Field field){
            this.table = table;
            this.propertyName = propertyName;
            this.isDbColumn = false;
            this.field = field;
        }
    
        public TableInfo getTable() {
            return table;
        }
    
        public void setTable(TableInfo table) {
            this.table = table;
        }
    
        public String getColumnName() {
            return columnName;
        }
    
        public String getPropertyName() {
            return propertyName;
        }
    
        public boolean getIsPrimaryKey(){
            return this.isPrimaryKey;
        }
    
        public boolean isGeneratedKey(){
            return this.isGeneratedKey;
        }
    
        public boolean isDbColumn(){
            return this.isDbColumn;
        }
    
        public Field getField() {
            return field;
        }
    
        public void setField(Field field) {
            this.field = field;
        }
    
    }
    

    记录了实体类与数据库字段的信息:字段属性名、数据库列名、是否主键、是否自增、是否是数据库字段、对应Field类(为后续读取、赋值使用)

  4. 表信息类TableInfo

    package cw.frame.mybatisext.base.entity;
    
    import cw.frame.mybatisext.annotation.Column;
    import cw.frame.mybatisext.annotation.OneMany;
    import cw.frame.mybatisext.annotation.OneOne;
    import cw.frame.mybatisext.annotation.Table;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Type;
    import java.util.*;
    
    public class TableInfo {
        private static Map<String, TableInfo> tableMap = new Hashtable<String, TableInfo>();
    
        private String tableName;
        private String entityFullName;
        private Class<? extends BaseExtEntity> entityClass;
        private ColumnInfo primaryKeyColumnInfo;
    
        private Map<String, ColumnInfo> propertyMap = new HashMap<String, ColumnInfo>();
        private Map<String, ColumnInfo> columnNameMap = new HashMap<String, ColumnInfo>();
        private Map<String, RelationshipInfo> oneOneMap = new HashMap<String, RelationshipInfo>();
        private Map<String, RelationshipInfo> oneManyMap = new HashMap<String, RelationshipInfo>();
    
        private TableInfo(Class<? extends BaseExtEntity> entityClass){
            this.entityClass = entityClass;
            this.tableName = this.getTableName(entityClass);
            this.entityFullName = entityClass.getName();
    
            this.initTableInfo();
    
            tableMap.put(this.entityFullName, this);
        }
    
        public static TableInfo getTableInfo(Class<? extends BaseExtEntity> entityClass){
            return getTableInfo(entityClass.getName());
        }
    
        public static TableInfo getTableInfo(String className){
            if (!tableMap.containsKey(className)){
                try{
                    Class entityClass = Class.forName(className);
                    if (BaseExtEntity.class.isAssignableFrom(entityClass)){
                        tableMap.put(className, new TableInfo(entityClass));
                    } else {
                        return null;
                    }
                } catch (ClassNotFoundException ex){
                    return null;
                }
            }
    
            return tableMap.get(className);
        }
    
        public static void setFieldValue(Object entity, String propertyName, Object value) throws Throwable{
            TableInfo tableInfo = TableInfo.getTableInfo(entity.getClass().getName());
            Field field = tableInfo.getColumnByPropertyName(propertyName).getField();
    
            setFieldValue(entity, field, value);
        }
    
        public static void setFieldValue(Object entity, Field field, Object value) throws Throwable{
            field.setAccessible(true);
            String type = field.getGenericType().toString();
    
            if (type.equals("class java.lang.String")){
                field.set(entity, value.toString());
            } else if (type.equals("class java.lang.Integer")){
                field.set(entity, Integer.valueOf(value.toString()));
            } else if (type.equals("int")){
                field.set(entity, Integer.valueOf(value.toString()));
            } else if (type.equals("boolean")){
                field.set(entity, (boolean)value);
            } else if (type.equals("class java.lang.Boolean")){
                field.set(entity, (Boolean)value);
            } else if (type.equals("class java.util.Date")){
                field.set(entity, (Date)value);
            } else if (type.equals("class java.lang.Long")){
                field.set(entity, (Long)value);
            } else if (type.equals("class java.lang.Short")){
                field.set(entity, (Short)value);
            } else if (type.equals("class java.lang.Byte")){
                field.set(entity, (Byte)value);
            } else if (type.equals("class java.lang.Float")){
                field.set(entity, (Float)value);
            } else if (type.equals("class java.lang.Double")){
                field.set(entity, (Double)value);
            } else {
                Class clazz = Class.forName(field.getGenericType().getTypeName());
                if (clazz.isEnum() && BaseExtEnum.class.isAssignableFrom(clazz)){
                    BaseExtEnum baseExtEnums[] = (BaseExtEnum[]) clazz.getMethod("values").invoke(null, null);
                    String val = value.toString();
                    for (BaseExtEnum baseExtEnum : baseExtEnums){
                        if (baseExtEnum.getValue().toString().equals(val)){
                            field.set(entity, baseExtEnum);
                            break;
                        }
                    }
                }
            }
    
            field.setAccessible(false);
        }
    
        public static Object getFieldValue(Object entity, Field field) throws Throwable{
            field.setAccessible(true);
            Object val = field.get(entity);
            field.setAccessible(false);
    
            return val;
        }
    
        public static Object getFieldValue(Object entity, String propertyName) throws Throwable{
            TableInfo tableInfo = TableInfo.getTableInfo(entity.getClass().getName());
            Field field = tableInfo.getColumnByPropertyName(propertyName).getField();
    
            return getFieldValue(entity, field);
        }
    
        public String getTableName() {
            return tableName;
        }
    
        public Class<? extends BaseExtEntity> getTableEntityClass(){
            return this.entityClass;
        }
    
        public ColumnInfo getPrimaryKeyColumn(){
            return this.primaryKeyColumnInfo;
        }
    
        /**
         * 根据属性字段获取ColumnnInfo对象,包括非数据库字段
         * @param propertyName  属性字段名
         * @return  ColumnInfo
         */
        public ColumnInfo getColumnByPropertyName(String propertyName){
            return this.propertyMap.getOrDefault(propertyName, null);
        }
    
        public ColumnInfo getColumnByColumnName(String columnName){
            return this.columnNameMap.getOrDefault(columnName, null);
        }
    
        /**
         * 根据属性字段获取ColumnnInfo对象,包括非数据库字段
         * @param propertyNames 多个属性字段名
         * @return
         */
        public Collection<ColumnInfo> getColumnnsByPropertyNames(String[] propertyNames){
            return this.getColumnnsNames(propertyNames, this.propertyMap);
        }
    
        public Collection<ColumnInfo> getColumnnsByColumnyNames(String[] columnNames){
            return this.getColumnnsNames(columnNames, this.columnNameMap);
        }
    
        public Collection<ColumnInfo> getColumnns(){
            return this.propertyMap.values();
        }
    
        public Collection<String> getPropertyNames(){
            return this.propertyMap.keySet();
        }
    
        public Collection<String> getColumnNames(){
            return this.columnNameMap.keySet();
        }
    
        public Map<String, RelationshipInfo> getOneManyMap() {
            return oneManyMap;
        }
    
        public Map<String, RelationshipInfo> getOneOneMap() {
            return oneOneMap;
        }
    
        public boolean isOneOne(String propertyName){
            return this.oneOneMap.containsKey(propertyName);
        }
    
        public boolean isOneMany(String propertyName){
            return this.oneManyMap.containsKey(propertyName);
        }
    
        public RelationshipInfo getRelationshipInfo(String propertyName) {
            if (this.isOneOne(propertyName)){
                return this.getOneOneMap().get(propertyName);
            } else if (this.isOneMany(propertyName)){
                return this.getOneManyMap().get(propertyName);
            } else {
                throw new IllegalArgumentException("propertyName error: " + propertyName);
            }
        }
    
        private Collection<ColumnInfo> getColumnnsNames(String[] names, Map<String, ColumnInfo> map){
            if (names == null || names.length == 0){
                return this.getColumnns();
            }
    
            List<ColumnInfo> columnInfoList = new ArrayList<ColumnInfo>();
            for (String name : names){
                columnInfoList.add(map.get(name));
            }
    
            return columnInfoList;
        }
    
        private void initTableInfo(){
            this.propertyMap = new HashMap<String, ColumnInfo>();
            this.columnNameMap = new HashMap<String, ColumnInfo>();
    
            Class<?> classType = this.entityClass;
            while (true){
                for (Field field : classType.getDeclaredFields()){
                    ColumnInfo columnInfo = null;
    
                    if (!this.isEntityColumn(field)){
                        Type type = field.getGenericType();
                        String typeName = type.getTypeName();
                        if (typeName.equals("class java.lang.String")
                                || typeName.equals("class java.lang.Integer")
                                || typeName.equals("int")
                                || typeName.equals("boolean")
                                || typeName.equals("class java.lang.Boolean")
                                || typeName.equals("class java.util.Date")
                                || typeName.equals("class java.lang.Long")
                                || typeName.equals("class java.lang.Short")
                                || typeName.equals("class java.lang.Byte")
                                || typeName.equals("class java.lang.Float")
                                || typeName.equals("class java.lang.Double")
                                ) {
                            columnInfo = ColumnInfo.createNormalColumn(this, field.getName(), field);
                        } else {
                            OneOne oneOne = field.getAnnotation(OneOne.class);
                            OneMany oneMany = field.getAnnotation(OneMany.class);
                            if (oneOne != null){
                                RelationshipInfo relationshipInfo = RelationshipInfo.createOneOneRelationship(this, field, oneOne.type(), oneOne.propertyKey(), oneOne.foreignKey());
                                this.oneOneMap.put(field.getName(), relationshipInfo);
                            } else if (oneMany != null){
                                RelationshipInfo relationshipInfo = RelationshipInfo.createOneManyRelationship(this, field, oneMany.type(), oneMany.propertyKey(), oneMany.foreignKey());
                                this.oneManyMap.put(field.getName(), relationshipInfo);
                            }
    
                        }
                    } else {
                        columnInfo = this.buildColumnInfo(field);
                        if (columnInfo.getIsPrimaryKey()){
                            this.primaryKeyColumnInfo = columnInfo;
                            this.columnNameMap.put(columnInfo.getColumnName(), columnInfo);
                        }
                    }
    
                    if (columnInfo != null){
                        this.propertyMap.put(columnInfo.getPropertyName(), columnInfo);
                    }
    
                }
    
                if (classType.equals(BaseExtEntity.class)){
                    break;
                }
    
                classType = classType.getSuperclass();
            }
        }
    
        private boolean isEntityColumn(Field field){
            boolean isColumn = true;
    
            Column column = field.getAnnotation(Column.class);
            if (column == null){
                isColumn = false;
            }
    
            return isColumn;
        }
    
        private ColumnInfo buildColumnInfo(Field field){
            Column column = field.getAnnotation(Column.class);
    
            String columnName = column.value();
            boolean isPrimaryKey = column.primaryKey();
            boolean isGeneratedKey = isPrimaryKey && column.generatedKey();
            String propertyName = field.getName();
    
            if (columnName == null || columnName.isEmpty()){
                columnName = propertyName;
            }
    
            return ColumnInfo.createDbColumn(this, propertyName, columnName, isPrimaryKey, isGeneratedKey, field);
        }
    
        private String getTableName(Class<?> entityClass){
            String tableName = entityClass.getSimpleName();
    
            Table table = entityClass.getAnnotation(Table.class);
    
            if (table != null){
                tableName = table.value();
                if (tableName == null || tableName.isEmpty()){
                    tableName = entityClass.getSimpleName();
                }
            }
    
            return tableName;
        }
    }
    

    静态变量tableMap记录了所有实体类信息,每个实体类第一次使用的时候更新
    其它变量记录了表信息、表字段信息、对应的实体类等

  5. 关系映射类RelationshipInfo

    package cw.frame.mybatisext.base.entity;
    
    import java.lang.reflect.Field;
    
    public class RelationshipInfo {
        private TableInfo primaryTable;
        private Field field;
        private String foreignKey;
        private String propertyKey;
        private boolean oneOne;
        private Class<? extends BaseExtEntity> relationTableEntityClass;
    
        public static RelationshipInfo createOneOneRelationship(TableInfo primaryTable, Field field, Class<? extends BaseExtEntity> relationTableEntityClass, String propertyKey, String foreignKey){
            return new RelationshipInfo(primaryTable, field, relationTableEntityClass, propertyKey, foreignKey, true);
        }
    
        public static RelationshipInfo createOneManyRelationship(TableInfo primaryTable, Field field, Class<? extends BaseExtEntity> relationTableEntityClass, String propertyKey, String foreignKey){
            return new RelationshipInfo(primaryTable, field, relationTableEntityClass, propertyKey, foreignKey, false);
        }
    
        private RelationshipInfo(TableInfo primaryTable, Field field, Class<? extends BaseExtEntity> relationTableEntityClass, String propertyKey, String foreignKey, boolean oneOne){
            this.primaryTable = primaryTable;
            this.field = field;
            this.relationTableEntityClass = relationTableEntityClass;
            this.foreignKey = foreignKey;
            this.propertyKey = propertyKey;
            this.oneOne = oneOne;
        }
    
        public String getForeignKey() {
            return foreignKey;
        }
    
        public String getPropertyKey() {
            return propertyKey;
        }
    
        public TableInfo getPrimaryTable() {
            return primaryTable;
        }
    
        public Field getField() {
            return field;
        }
    
        public TableInfo getSubTable() {
            return TableInfo.getTableInfo(this.relationTableEntityClass);
        }
    
        public boolean isOneOne() {
            return oneOne;
        }
    
        public boolean isOneMay(){
            return !oneOne;
        }
    }
    

     

  6. 实体基类
     

    package cw.frame.mybatisext.base.entity;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.lang.reflect.Field;
    import java.util.List;
    
    public abstract class BaseExtEntity {
    
        private Logger logger= LoggerFactory.getLogger(getClass());
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
    
            TableInfo tableInfo = TableInfo.getTableInfo(this.getClass());
            for (ColumnInfo columnInfo : tableInfo.getColumnns()){
                if (sb.length() > 0){
                    sb.append(", ");
                }
                Field field = columnInfo.getField();
                sb.append(columnInfo.getPropertyName()).append("=");
                sb.append(this.getFieldValue(field));
            }
    
            int i = 0;
            for (RelationshipInfo relationshipInfo : tableInfo.getOneOneMap().values()){
                if (i > 0){
                    sb.append(", ");
                }
                sb.append(relationshipInfo.getPropertyKey()).append("=");
                sb.append(this.getFieldValue(relationshipInfo.getField()));
            }
    
            i = 0;
            for (RelationshipInfo relationshipInfo : tableInfo.getOneManyMap().values()){
                if (i > 0){
                    sb.append(",");
                }
                sb.append(relationshipInfo.getPropertyKey()).append("=");
                sb.append("[");
    
                Object obj = this.getFieldValue(relationshipInfo.getField());
                if (obj != null){
                    List values = (List)obj;
                    for (int j=0; j<values.size(); j++){
                        if (j > 0){
                            sb.append(", ");
                        }
                        sb.append(values.get(j));
                    }
                }
    
                sb.append("]");
            }
    
            sb.insert(0, "{").append("}");
    
            return sb.toString();
        }
    
        private Object getFieldValue(Field field){
            Object val = null;
            field.setAccessible(true);
            try{
                val = field.get(this);
            }
            catch (Exception ex){
                this.logger.error(ex.getMessage());
            }
    
            return val;
        }
    }
    

     

整体上都比较简单,就不做过多赘述了,看下代码就应该明白了。源代码下载

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值