因为需要知道数据库表、字段和实体类的对应关系,那么下面就介绍下在mybatisext中如何实现的
- 注解定义
表注解@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(); } -
枚举类型定义
package cw.frame.mybatisext.base.entity; public interface BaseExtEnum { public Object getValue(); public String getName(); } -
字段信息类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类(为后续读取、赋值使用)
-
表信息类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记录了所有实体类信息,每个实体类第一次使用的时候更新
其它变量记录了表信息、表字段信息、对应的实体类等 -
关系映射类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; } } -
实体基类
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; } }
整体上都比较简单,就不做过多赘述了,看下代码就应该明白了。源代码下载

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

被折叠的 条评论
为什么被折叠?



