forked from p81075629/datagear
[meta]完善模块功能
This commit is contained in:
parent
b8e10f7f87
commit
f85e1e7792
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.datagear</groupId>
|
||||
<artifactId>datagear</artifactId>
|
||||
<version>1.7.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>datagear-meta</artifactId>
|
||||
<name>datagear-meta</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.datagear</groupId>
|
||||
<artifactId>datagear-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.datagear</groupId>
|
||||
<artifactId>datagear-connection</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>${maven-antrun-plugin.version}</version>
|
||||
<executions>
|
||||
<!-- 拷贝LICENSE文件 -->
|
||||
<execution>
|
||||
<id>copyLICENSE</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<copy file="../LICENSE" todir="${project.build.outputDirectory}" />
|
||||
</tasks>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 表键。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractKey implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 列名 */
|
||||
private String[] columnNames;
|
||||
|
||||
/** 键名 */
|
||||
private String keyName;
|
||||
|
||||
public AbstractKey()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public AbstractKey(String[] columnNames)
|
||||
{
|
||||
super();
|
||||
this.columnNames = columnNames;
|
||||
}
|
||||
|
||||
public String[] getColumnNames()
|
||||
{
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
public void setColumnNames(String[] columnNames)
|
||||
{
|
||||
this.columnNames = columnNames;
|
||||
}
|
||||
|
||||
public boolean hasKeyName()
|
||||
{
|
||||
return (this.keyName != null && !this.keyName.isEmpty());
|
||||
}
|
||||
|
||||
public String getKeyName()
|
||||
{
|
||||
return keyName;
|
||||
}
|
||||
|
||||
public void setKeyName(String keyName)
|
||||
{
|
||||
this.keyName = keyName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getSimpleName() + " [columnNames=" + Arrays.toString(columnNames) + ", keyName=" + keyName
|
||||
+ "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 抽象表元信息。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class AbstractTable implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 名称 */
|
||||
private String name;
|
||||
|
||||
/** 类型 */
|
||||
private TableType type;
|
||||
|
||||
/** 描述 */
|
||||
private String comment;
|
||||
|
||||
public AbstractTable()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public AbstractTable(String name, TableType type)
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public TableType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(TableType type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getComment()
|
||||
{
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void setComment(String comment)
|
||||
{
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getSimpleName() + " [name=" + name + ", type=" + type + ", comment=" + comment + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 列。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class Column implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 名称 */
|
||||
private String name;
|
||||
|
||||
/** JDBC类型,对应java.sql.Types中的值 */
|
||||
private int type;
|
||||
|
||||
/** 数据源依赖的类型名称,参考"TYPE_NAME"说明 */
|
||||
private String typeName;
|
||||
|
||||
/** 列大小,字符串长度或者数值总长度 */
|
||||
private int size = 0;
|
||||
|
||||
/** 小数部分的位数,如果不是小数,值为0 */
|
||||
private int decimalDigits = 0;
|
||||
|
||||
/** 是否允许为null */
|
||||
private boolean nullable = false;
|
||||
|
||||
/** 描述 */
|
||||
private String comment;
|
||||
|
||||
/** 默认值 */
|
||||
private String defaultValue = null;
|
||||
|
||||
/** 是否自增长 */
|
||||
private boolean autoincrement = false;
|
||||
|
||||
/** 可搜索类型 */
|
||||
private SearchableType searchableType;
|
||||
|
||||
public Column()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public Column(String name, int type)
|
||||
{
|
||||
super();
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public boolean hasTypeName()
|
||||
{
|
||||
return (this.typeName != null && !this.typeName.isEmpty());
|
||||
}
|
||||
|
||||
public String getTypeName()
|
||||
{
|
||||
return typeName;
|
||||
}
|
||||
|
||||
public void setTypeName(String typeName)
|
||||
{
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(int size)
|
||||
{
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public int getDecimalDigits()
|
||||
{
|
||||
return decimalDigits;
|
||||
}
|
||||
|
||||
public void setDecimalDigits(int decimalDigits)
|
||||
{
|
||||
this.decimalDigits = decimalDigits;
|
||||
}
|
||||
|
||||
public boolean isNullable()
|
||||
{
|
||||
return nullable;
|
||||
}
|
||||
|
||||
public void setNullable(boolean nullable)
|
||||
{
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
public boolean hasComment()
|
||||
{
|
||||
return (this.comment != null && !this.comment.isEmpty());
|
||||
}
|
||||
|
||||
public String getComment()
|
||||
{
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void setComment(String comment)
|
||||
{
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public boolean hasDefaultValue()
|
||||
{
|
||||
return (this.defaultValue != null && !this.defaultValue.isEmpty());
|
||||
}
|
||||
|
||||
public String getDefaultValue()
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void setDefaultValue(String defaultValue)
|
||||
{
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public boolean isAutoincrement()
|
||||
{
|
||||
return autoincrement;
|
||||
}
|
||||
|
||||
public void setAutoincrement(boolean autoincrement)
|
||||
{
|
||||
this.autoincrement = autoincrement;
|
||||
}
|
||||
|
||||
public boolean hasSearchableType()
|
||||
{
|
||||
return (this.searchableType != null);
|
||||
}
|
||||
|
||||
public SearchableType getSearchableType()
|
||||
{
|
||||
return searchableType;
|
||||
}
|
||||
|
||||
public void setSearchableType(SearchableType searchableType)
|
||||
{
|
||||
this.searchableType = searchableType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getSimpleName() + " [name=" + name + ", type=" + type + ", typeName=" + typeName + ", size="
|
||||
+ size
|
||||
+ ", decimalDigits=" + decimalDigits + ", nullable=" + nullable + ", comment=" + comment
|
||||
+ ", defaultValue=" + defaultValue + ", autoincrement=" + autoincrement + ", searchableType="
|
||||
+ searchableType + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 导入外键。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class ImportKey extends AbstractKey
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主表名 */
|
||||
private String primaryTableName;
|
||||
|
||||
/** 主表键列名 */
|
||||
private String[] primaryColumnNames;
|
||||
|
||||
public ImportKey()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public ImportKey(String[] columnNames, String primaryTableName, String[] primaryColumnNames)
|
||||
{
|
||||
super(columnNames);
|
||||
this.primaryTableName = primaryTableName;
|
||||
this.primaryColumnNames = primaryColumnNames;
|
||||
}
|
||||
|
||||
public String getPrimaryTableName()
|
||||
{
|
||||
return primaryTableName;
|
||||
}
|
||||
|
||||
public void setPrimaryTableName(String primaryTableName)
|
||||
{
|
||||
this.primaryTableName = primaryTableName;
|
||||
}
|
||||
|
||||
public String[] getPrimaryColumnNames()
|
||||
{
|
||||
return primaryColumnNames;
|
||||
}
|
||||
|
||||
public void setPrimaryColumnNames(String[] primaryColumnNames)
|
||||
{
|
||||
this.primaryColumnNames = primaryColumnNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getSimpleName() + " [columnNames=" + Arrays.toString(getColumnNames())
|
||||
+ ", primaryTableName=" + primaryTableName + ", primaryColumnNames="
|
||||
+ Arrays.toString(primaryColumnNames) + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta;
|
||||
|
||||
/**
|
||||
* 主键。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class PrimaryKey extends AbstractKey
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public PrimaryKey()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public PrimaryKey(String[] columnNames)
|
||||
{
|
||||
super(columnNames);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
|
||||
/**
|
||||
* 可搜索类型(WHERE条件类型)。
|
||||
* <p>
|
||||
* 参考{@linkplain DatabaseMetaData#getTypeInfo()}结果集{@code SEARCHABLE}列说明。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public enum SearchableType
|
||||
{
|
||||
/** 不可用于WHERE */
|
||||
NO,
|
||||
|
||||
/** 仅可用于WHERE中的LIKE */
|
||||
ONLY_LIKE,
|
||||
|
||||
/** 仅不可用于WHERE中的LIKE */
|
||||
EXPCEPT_LIKE,
|
||||
|
||||
/** 可用于WHERE中的任何情况 */
|
||||
ALL
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta;
|
||||
|
||||
/**
|
||||
* 简单表元信息。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class SimpleTable extends AbstractTable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SimpleTable()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public SimpleTable(String name, TableType type)
|
||||
{
|
||||
super(name, type);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 表。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class Table extends AbstractTable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 列集 */
|
||||
private Column[] columns;
|
||||
|
||||
/** 主键 */
|
||||
private PrimaryKey primaryKey;
|
||||
|
||||
/** 唯一键 */
|
||||
private UniqueKey[] uniqueKeys;
|
||||
|
||||
/** 导入外键 */
|
||||
private ImportKey[] importKeys;
|
||||
|
||||
public Table()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public Table(String name, TableType type, Column[] columns)
|
||||
{
|
||||
super(name, type);
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public Column[] getColumns()
|
||||
{
|
||||
return columns;
|
||||
}
|
||||
|
||||
public void setColumns(Column[] columns)
|
||||
{
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public boolean hasPrimaryKey()
|
||||
{
|
||||
return (this.primaryKey != null);
|
||||
}
|
||||
|
||||
public PrimaryKey getPrimaryKey()
|
||||
{
|
||||
return primaryKey;
|
||||
}
|
||||
|
||||
public void setPrimaryKey(PrimaryKey primaryKey)
|
||||
{
|
||||
this.primaryKey = primaryKey;
|
||||
}
|
||||
|
||||
public boolean hasUniqueKey()
|
||||
{
|
||||
return (this.uniqueKeys != null && this.uniqueKeys.length > 0);
|
||||
}
|
||||
|
||||
public UniqueKey[] getUniqueKeys()
|
||||
{
|
||||
return uniqueKeys;
|
||||
}
|
||||
|
||||
public void setUniqueKeys(UniqueKey[] uniqueKeys)
|
||||
{
|
||||
this.uniqueKeys = uniqueKeys;
|
||||
}
|
||||
|
||||
public boolean hasImportKey()
|
||||
{
|
||||
return (this.importKeys != null && this.importKeys.length > 0);
|
||||
}
|
||||
|
||||
public ImportKey[] getImportKeys()
|
||||
{
|
||||
return importKeys;
|
||||
}
|
||||
|
||||
public void setImportKeys(ImportKey[] importKeys)
|
||||
{
|
||||
this.importKeys = importKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getSimpleName() + " [name=" + getName() + ", type=" + getType() + ", comment=" + getComment()
|
||||
+ ", columns=" + Arrays.toString(columns) + ", primaryKey=" + primaryKey + ", uniqueKeys="
|
||||
+ Arrays.toString(uniqueKeys) + ", importKeys=" + Arrays.toString(importKeys) + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta;
|
||||
|
||||
/**
|
||||
* 表类型。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public enum TableType
|
||||
{
|
||||
/** 实体表 */
|
||||
TABLE,
|
||||
|
||||
/** 视图 */
|
||||
VIEW
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta;
|
||||
|
||||
/**
|
||||
* 唯一键。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class UniqueKey extends AbstractKey
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UniqueKey()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public UniqueKey(String[] columnNames)
|
||||
{
|
||||
super(columnNames);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta.resolver;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
import org.datagear.connection.ConnectionSensor;
|
||||
|
||||
/**
|
||||
* 抽象数据库连接敏感的{@linkplain DevotedDBMetaResolver}。
|
||||
* <p>
|
||||
* 此类可以作为特定数据库{@linkplain DevotedDBMetaResolver}实现类的父类。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractConnectionDevotedDBMetaResolver extends AbstractDevotedDBMetaResolver
|
||||
{
|
||||
private ConnectionSensor connectionSensor;
|
||||
|
||||
public AbstractConnectionDevotedDBMetaResolver()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public AbstractConnectionDevotedDBMetaResolver(ConnectionSensor connectionSensor)
|
||||
{
|
||||
super();
|
||||
this.connectionSensor = connectionSensor;
|
||||
}
|
||||
|
||||
public ConnectionSensor getConnectionSensor()
|
||||
{
|
||||
return connectionSensor;
|
||||
}
|
||||
|
||||
public void setConnectionSensor(ConnectionSensor connectionSensor)
|
||||
{
|
||||
this.connectionSensor = connectionSensor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Connection cn)
|
||||
{
|
||||
return this.connectionSensor.supports(cn);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,714 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta.resolver;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLNonTransientException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.datagear.meta.Column;
|
||||
import org.datagear.meta.ImportKey;
|
||||
import org.datagear.meta.PrimaryKey;
|
||||
import org.datagear.meta.SimpleTable;
|
||||
import org.datagear.meta.Table;
|
||||
import org.datagear.meta.TableType;
|
||||
import org.datagear.meta.UniqueKey;
|
||||
import org.datagear.util.JDBCCompatiblity;
|
||||
import org.datagear.util.JdbcUtil;
|
||||
import org.datagear.util.StringUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 抽象{@linkplain DevotedDBMetaResolver}。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractDevotedDBMetaResolver implements DevotedDBMetaResolver
|
||||
{
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDevotedDBMetaResolver.class);
|
||||
|
||||
public static final String TABLE_TYPE_TABLE = "TABLE";
|
||||
|
||||
public static final String TABLE_TYPE_VIEW = "VIEW";
|
||||
|
||||
protected static final String[] TABLE_TYPES = { TABLE_TYPE_TABLE, TABLE_TYPE_VIEW };
|
||||
|
||||
protected static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
|
||||
public AbstractDevotedDBMetaResolver()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SimpleTable> getSimpleTables(Connection cn) throws DBMetaResolverException
|
||||
{
|
||||
DatabaseMetaData metaData = getDatabaseMetaData(cn);
|
||||
String schema = getSchema(cn, metaData);
|
||||
|
||||
return getSimpleTables(cn, metaData, schema, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleTable getRandomSimpleTable(Connection cn) throws DBMetaResolverException
|
||||
{
|
||||
DatabaseMetaData metaData = getDatabaseMetaData(cn);
|
||||
String schema = getSchema(cn, metaData);
|
||||
|
||||
return getRandomSimpleTable(cn, metaData, schema);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table getTable(Connection cn, String tableName) throws DBMetaResolverException
|
||||
{
|
||||
DatabaseMetaData metaData = getDatabaseMetaData(cn);
|
||||
String schema = getSchema(cn, metaData);
|
||||
|
||||
return getTable(cn, metaData, schema, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Column getRandomColumn(Connection cn, String tableName) throws DBMetaResolverException
|
||||
{
|
||||
DatabaseMetaData metaData = getDatabaseMetaData(cn);
|
||||
String schema = getSchema(cn, metaData);
|
||||
|
||||
Column[] columns = getColumns(cn, metaData, schema, tableName, 1);
|
||||
|
||||
return (columns == null || columns.length < 1 ? null : columns[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Column[] getColumns(Connection cn, ResultSetMetaData resultSetMetaData) throws DBMetaResolverException
|
||||
{
|
||||
try
|
||||
{
|
||||
int columnCount = resultSetMetaData.getColumnCount();
|
||||
|
||||
Column[] columnInfos = new Column[columnCount];
|
||||
|
||||
for (int i = 1; i <= columnCount; i++)
|
||||
{
|
||||
Column column = new Column();
|
||||
|
||||
String columnName = resultSetMetaData.getColumnLabel(i);
|
||||
if (columnName == null || columnName.isEmpty())
|
||||
columnName = resultSetMetaData.getColumnName(i);
|
||||
|
||||
column.setName(columnName);
|
||||
column.setType(resultSetMetaData.getColumnType(i));
|
||||
column.setTypeName(resultSetMetaData.getColumnTypeName(i));
|
||||
column.setSize(resultSetMetaData.getPrecision(i));
|
||||
column.setDecimalDigits(resultSetMetaData.getScale(i));
|
||||
column.setNullable(DatabaseMetaData.columnNoNulls == resultSetMetaData.isNullable(i));
|
||||
column.setAutoincrement(resultSetMetaData.isAutoIncrement(i));
|
||||
|
||||
columnInfos[i - 1] = column;
|
||||
}
|
||||
|
||||
return columnInfos;
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
throw new DBMetaResolverException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Table getTable(Connection cn, DatabaseMetaData metaData, String schema, String tableName)
|
||||
throws DBMetaResolverException
|
||||
{
|
||||
List<SimpleTable> simpleTables = getSimpleTables(cn, metaData, schema, tableName);
|
||||
|
||||
if (simpleTables == null || simpleTables.isEmpty())
|
||||
throw new TableNotFoundException(tableName);
|
||||
|
||||
SimpleTable simpleTable = simpleTables.get(0);
|
||||
|
||||
Table table = new Table();
|
||||
table.setName(simpleTable.getName());
|
||||
table.setType(simpleTable.getType());
|
||||
table.setComment(simpleTable.getComment());
|
||||
table.setColumns(getColumns(cn, metaData, schema, tableName, null));
|
||||
table.setPrimaryKey(getPrimaryKey(cn, metaData, schema, tableName));
|
||||
table.setUniqueKeys(getUniqueKeys(cn, metaData, schema, tableName));
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param cn
|
||||
* @param metaData
|
||||
* @param schema
|
||||
* @param tableName
|
||||
* @return 返回{@code null}表示无主键。
|
||||
* @throws DBMetaResolverException
|
||||
*/
|
||||
protected PrimaryKey getPrimaryKey(Connection cn, DatabaseMetaData metaData, String schema, String tableName)
|
||||
throws DBMetaResolverException
|
||||
{
|
||||
PrimaryKey primaryKey = null;
|
||||
|
||||
ResultSet rs = null;
|
||||
try
|
||||
{
|
||||
rs = getPrimaryKeyResulSet(cn, metaData, schema, tableName);
|
||||
|
||||
List<String> columnNames = new ArrayList<String>();
|
||||
String keyName = null;
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
String columnName = rs.getString("COLUMN_NAME");
|
||||
if (StringUtil.isEmpty(keyName))
|
||||
keyName = rs.getString("PK_NAME");
|
||||
|
||||
addName(columnNames, columnName);
|
||||
}
|
||||
|
||||
if (!columnNames.isEmpty())
|
||||
{
|
||||
primaryKey = new PrimaryKey(columnNames.toArray(new String[columnNames.size()]));
|
||||
primaryKey.setKeyName(keyName);
|
||||
}
|
||||
|
||||
return primaryKey;
|
||||
}
|
||||
catch(SQLNonTransientException e)
|
||||
{
|
||||
@JDBCCompatiblity("当tableName是视图时,某些驱动(比如Oracle)可能会抛出SQLSyntaxErrorException异常")
|
||||
SQLNonTransientException e1 = e;
|
||||
|
||||
LOGGER.warn("return null primary key object for exception", e1);
|
||||
|
||||
return null;
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
throw new DBMetaResolverException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JdbcUtil.closeResultSet(rs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param cn
|
||||
* @param metaData
|
||||
* @param schema
|
||||
* @param tableName
|
||||
* @param count 为{@code null}获取全部,否则获取指定数目
|
||||
* @return
|
||||
* @throws DBMetaResolverException
|
||||
*/
|
||||
protected Column[] getColumns(Connection cn, DatabaseMetaData metaData, String schema, String tableName,
|
||||
Integer count)
|
||||
throws DBMetaResolverException
|
||||
{
|
||||
ResultSet rs = null;
|
||||
|
||||
try
|
||||
{
|
||||
rs = getColumnResulSet(cn, metaData, schema, tableName);
|
||||
|
||||
List<Column> columns = new ArrayList<Column>();
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
Column column = readColumn(rs);
|
||||
addColumn(columns, column);
|
||||
|
||||
if (count != null && columns.size() == count)
|
||||
break;
|
||||
}
|
||||
|
||||
columns = postProcessColumns(columns);
|
||||
|
||||
return columns.toArray(new Column[columns.size()]);
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
throw new DBMetaResolverException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JdbcUtil.closeResultSet(rs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cn
|
||||
* @param metaData
|
||||
* @param schema
|
||||
* @param tableName
|
||||
* @return 返回{@code null}表示无唯一键
|
||||
* @throws DBMetaResolverException
|
||||
*/
|
||||
protected UniqueKey[] getUniqueKeys(Connection cn, DatabaseMetaData metaData, String schema,
|
||||
String tableName) throws DBMetaResolverException
|
||||
{
|
||||
UniqueKey[] uniqueKeys = null;
|
||||
|
||||
ResultSet rs = null;
|
||||
|
||||
List<String> keyNames = new ArrayList<String>();
|
||||
List<List<String>> keyColumnNamess = new ArrayList<List<String>>();
|
||||
|
||||
try
|
||||
{
|
||||
rs = getUniqueKeyResulSet(cn, metaData, schema, tableName);
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
String keyName = rs.getString("INDEX_NAME");
|
||||
if (keyName == null)
|
||||
keyName = "";
|
||||
String columnName = rs.getString("COLUMN_NAME");
|
||||
|
||||
int myIndex = keyNames.indexOf(keyName);
|
||||
List<String> keyColumnNames = null;
|
||||
|
||||
if (myIndex < 0)
|
||||
{
|
||||
keyNames.add(keyName);
|
||||
keyColumnNames = new ArrayList<String>();
|
||||
keyColumnNamess.add(keyColumnNames);
|
||||
}
|
||||
else
|
||||
keyColumnNames = keyColumnNamess.get(myIndex);
|
||||
|
||||
addName(keyColumnNames, columnName);
|
||||
}
|
||||
}
|
||||
catch(SQLNonTransientException e)
|
||||
{
|
||||
@JDBCCompatiblity("当tableName是视图时,某些驱动(比如Oracle)可能会抛出SQLSyntaxErrorException异常")
|
||||
SQLNonTransientException e1 = e;
|
||||
|
||||
LOGGER.warn("return null primary key object for exception", e1);
|
||||
|
||||
return null;
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
throw new DBMetaResolverException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JdbcUtil.closeResultSet(rs);
|
||||
}
|
||||
|
||||
if (!keyNames.isEmpty())
|
||||
{
|
||||
uniqueKeys = new UniqueKey[keyNames.size()];
|
||||
|
||||
for (int i = 0; i < uniqueKeys.length; i++)
|
||||
{
|
||||
List<String> keyColumnNames = keyColumnNamess.get(i);
|
||||
uniqueKeys[i] = new UniqueKey(keyColumnNames.toArray(new String[keyColumnNames.size()]));
|
||||
uniqueKeys[i].setKeyName(keyNames.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
return uniqueKeys;
|
||||
}
|
||||
|
||||
protected ImportKey[] getImportedKeys(Connection cn, DatabaseMetaData metaData, String schema,
|
||||
String tableName) throws DBMetaResolverException
|
||||
{
|
||||
ImportKey[] importKeys = null;
|
||||
|
||||
ResultSet rs = null;
|
||||
|
||||
List<String> keyNames = new ArrayList<String>();
|
||||
List<List<String>> columnNamess = new ArrayList<List<String>>();
|
||||
List<String> primaryTableNames = new ArrayList<String>();
|
||||
List<List<String>> primaryColumnNamess = new ArrayList<List<String>>();
|
||||
|
||||
try
|
||||
{
|
||||
rs = getImportKeyResulSet(cn, metaData, schema, tableName);
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
String keyName = rs.getString("FK_NAME");
|
||||
if (keyName == null)
|
||||
keyName = "";
|
||||
|
||||
String columnName = rs.getString("FKCOLUMN_NAME");
|
||||
String primaryColumnName = rs.getString("PKCOLUMN_NAME");
|
||||
|
||||
int myIndex = keyNames.indexOf(keyName);
|
||||
List<String> columnNames = null;
|
||||
List<String> primaryColumnNames = null;
|
||||
|
||||
if (myIndex < 0)
|
||||
{
|
||||
keyNames.add(keyName);
|
||||
primaryTableNames.add(rs.getString("PKTABLE_NAME"));
|
||||
|
||||
columnNames = new ArrayList<String>();
|
||||
columnNamess.add(columnNames);
|
||||
|
||||
primaryColumnNames = new ArrayList<String>();
|
||||
primaryColumnNamess.add(primaryColumnNames);
|
||||
}
|
||||
else
|
||||
{
|
||||
columnNames = columnNamess.get(myIndex);
|
||||
primaryColumnNames = primaryColumnNamess.get(myIndex);
|
||||
}
|
||||
|
||||
addName(columnNames, columnName);
|
||||
addName(primaryColumnNames, primaryColumnName);
|
||||
}
|
||||
}
|
||||
catch(SQLNonTransientException e)
|
||||
{
|
||||
@JDBCCompatiblity("当tableName是视图时,某些驱动(比如Oracle)可能会抛出SQLSyntaxErrorException异常")
|
||||
SQLNonTransientException e1 = e;
|
||||
|
||||
LOGGER.warn("return null import key object for exception", e1);
|
||||
|
||||
return null;
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
throw new DBMetaResolverException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JdbcUtil.closeResultSet(rs);
|
||||
}
|
||||
|
||||
if (!keyNames.isEmpty())
|
||||
{
|
||||
importKeys = new ImportKey[keyNames.size()];
|
||||
|
||||
for (int i = 0; i < importKeys.length; i++)
|
||||
{
|
||||
ImportKey importKey = new ImportKey();
|
||||
|
||||
List<String> columnNames = columnNamess.get(i);
|
||||
List<String> primaryColumnNames = primaryColumnNamess.get(i);
|
||||
|
||||
importKey.setColumnNames(columnNames.toArray(new String[columnNames.size()]));
|
||||
importKey.setPrimaryTableName(primaryTableNames.get(i));
|
||||
importKey.setPrimaryColumnNames(primaryColumnNames.toArray(new String[primaryColumnNames.size()]));
|
||||
importKey.setKeyName(keyNames.get(i));
|
||||
|
||||
importKeys[i] = importKey;
|
||||
}
|
||||
}
|
||||
|
||||
return importKeys;
|
||||
}
|
||||
|
||||
@JDBCCompatiblity("避免某些驱动程序的结果集出现非法或者重复项")
|
||||
protected boolean addName(List<String> names, String name)
|
||||
{
|
||||
if (StringUtil.isEmpty(name) || names.indexOf(name) > -1)
|
||||
return false;
|
||||
|
||||
names.add(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
@JDBCCompatiblity("避免某些驱动程序的结果集出现非法或者重复项")
|
||||
protected boolean addColumn(List<Column> columns, Column column)
|
||||
{
|
||||
if (column == null || containsColumn(columns, column.getName()))
|
||||
return false;
|
||||
|
||||
columns.add(column);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean containsColumn(List<Column> columns, String name)
|
||||
{
|
||||
for (Column column : columns)
|
||||
{
|
||||
if (column.getName().equals(name))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rs
|
||||
* @return 返回{@code null}表示未读取到
|
||||
*/
|
||||
protected Column readColumn(ResultSet rs)
|
||||
{
|
||||
try
|
||||
{
|
||||
String name = rs.getString("COLUMN_NAME");
|
||||
|
||||
if (StringUtil.isEmpty(name))
|
||||
{
|
||||
LOGGER.warn("Invalid column row : name={}", name);
|
||||
return null;
|
||||
}
|
||||
|
||||
Column column = new Column(name, rs.getInt("DATA_TYPE"));
|
||||
|
||||
column.setTypeName(rs.getString("TYPE_NAME"));
|
||||
column.setSize(rs.getInt("COLUMN_SIZE"));
|
||||
column.setDecimalDigits(rs.getInt("DECIMAL_DIGITS"));
|
||||
column.setNullable(DatabaseMetaData.columnNoNulls == rs.getInt("NULLABLE"));
|
||||
column.setComment(rs.getString("REMARKS"));
|
||||
column.setDefaultValue(rs.getString("COLUMN_DEF"));
|
||||
column.setAutoincrement("yes".equalsIgnoreCase(rs.getString("IS_AUTOINCREMENT")));
|
||||
|
||||
return column;
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Column> postProcessColumns(List<Column> columns)
|
||||
{
|
||||
return columns;
|
||||
}
|
||||
|
||||
protected ResultSet getPrimaryKeyResulSet(Connection cn, DatabaseMetaData databaseMetaData, String schema,
|
||||
String tableName) throws SQLException
|
||||
{
|
||||
return databaseMetaData.getPrimaryKeys(cn.getCatalog(), schema, tableName);
|
||||
}
|
||||
|
||||
protected ResultSet getColumnResulSet(Connection cn, DatabaseMetaData databaseMetaData, String schema,
|
||||
String tableName) throws SQLException
|
||||
{
|
||||
return databaseMetaData.getColumns(cn.getCatalog(), schema, tableName, "%");
|
||||
}
|
||||
|
||||
protected ResultSet getUniqueKeyResulSet(Connection cn, DatabaseMetaData databaseMetaData, String schema,
|
||||
String tableName) throws SQLException
|
||||
{
|
||||
return databaseMetaData.getIndexInfo(cn.getCatalog(), getSchema(cn, databaseMetaData), tableName, true, false);
|
||||
}
|
||||
|
||||
protected ResultSet getImportKeyResulSet(Connection cn, DatabaseMetaData databaseMetaData, String schema,
|
||||
String tableName) throws SQLException
|
||||
{
|
||||
return databaseMetaData.getImportedKeys(cn.getCatalog(), schema, tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cn
|
||||
* @param metaData
|
||||
* @param schema
|
||||
* @param tableNamePattern 允许为{@code null}
|
||||
* @return
|
||||
* @throws DBMetaResolverException
|
||||
*/
|
||||
protected List<SimpleTable> getSimpleTables(Connection cn, DatabaseMetaData metaData, String schema,
|
||||
String tableNamePattern)
|
||||
throws DBMetaResolverException
|
||||
{
|
||||
ResultSet rs = null;
|
||||
|
||||
try
|
||||
{
|
||||
rs = getTableResulSet(cn, metaData, schema, tableNamePattern, TABLE_TYPES);
|
||||
|
||||
List<SimpleTable> simpleTables = new ArrayList<SimpleTable>();
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
SimpleTable simpleTable = readSimpleTable(rs);
|
||||
|
||||
if (simpleTable != null)
|
||||
simpleTables.add(simpleTable);
|
||||
}
|
||||
|
||||
simpleTables = postProcessSimpleTables(simpleTables);
|
||||
|
||||
return simpleTables;
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
throw new DBMetaResolverException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JdbcUtil.closeResultSet(rs);
|
||||
}
|
||||
}
|
||||
|
||||
protected SimpleTable getRandomSimpleTable(Connection cn, DatabaseMetaData metaData, String schema)
|
||||
throws DBMetaResolverException
|
||||
{
|
||||
SimpleTable simpleTable = null;
|
||||
|
||||
ResultSet rs = null;
|
||||
|
||||
try
|
||||
{
|
||||
rs = getTableResulSet(cn, metaData, schema, null, TABLE_TYPES);
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
simpleTable = readSimpleTable(rs);
|
||||
|
||||
if (simpleTable != null)
|
||||
return simpleTable;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
throw new DBMetaResolverException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JdbcUtil.closeResultSet(rs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rs
|
||||
* @return 返回{@code null}表示未读取到
|
||||
*/
|
||||
protected SimpleTable readSimpleTable(ResultSet rs)
|
||||
{
|
||||
try
|
||||
{
|
||||
String name = rs.getString("TABLE_NAME");
|
||||
TableType type = toTableType(rs.getString("TABLE_TYPE"));
|
||||
|
||||
if (StringUtil.isEmpty(name) || StringUtil.isEmpty(type))
|
||||
{
|
||||
LOGGER.warn("Invalid table row : name={}, type={}", name, type);
|
||||
return null;
|
||||
}
|
||||
|
||||
SimpleTable simpleTable = new SimpleTable(name, type);
|
||||
simpleTable.setComment(rs.getString("REMARKS"));
|
||||
|
||||
return simpleTable;
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected TableType toTableType(String type)
|
||||
{
|
||||
if (TABLE_TYPE_TABLE.equalsIgnoreCase(type))
|
||||
return TableType.TABLE;
|
||||
else if (TABLE_TYPE_VIEW.equalsIgnoreCase(type))
|
||||
return TableType.VIEW;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
protected List<SimpleTable> postProcessSimpleTables(List<SimpleTable> simpleTables)
|
||||
{
|
||||
return simpleTables;
|
||||
}
|
||||
|
||||
protected ResultSet getTableResulSet(Connection cn, DatabaseMetaData databaseMetaData, String schema,
|
||||
String tableNamePattern, String[] tableTypes) throws SQLException
|
||||
{
|
||||
if (tableNamePattern == null || tableNamePattern.isEmpty())
|
||||
tableNamePattern = "%";
|
||||
|
||||
return databaseMetaData.getTables(cn.getCatalog(), schema, tableNamePattern, tableTypes);
|
||||
}
|
||||
|
||||
protected DatabaseMetaData getDatabaseMetaData(Connection cn) throws DBMetaResolverException
|
||||
{
|
||||
try
|
||||
{
|
||||
return cn.getMetaData();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
throw new DBMetaResolverException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected String getSchema(Connection cn, DatabaseMetaData databaseMetaData) throws DBMetaResolverException
|
||||
{
|
||||
// 在JDBC4.0(JDK1.6)中需要将其设置为null,才符合DatabaseMetaData.getTables(...)等接口的参数要求
|
||||
String schema = null;
|
||||
|
||||
// JDBC4.1(JDK1.7)才有Connection.getSchema()接口,为了兼容性,本应用采用了JDBC4.0(JDK1.6)
|
||||
// 这里为了能支持JDBC4.1的的驱动,先采用反射方式获取
|
||||
if (GET_SCHEMA_METHOD_JDBC41 != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
schema = (String) GET_SCHEMA_METHOD_JDBC41.invoke(cn, new Object[0]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
// 测试使用连接用户名是否可行
|
||||
if (schema == null)
|
||||
{
|
||||
ResultSet rs = null;
|
||||
|
||||
try
|
||||
{
|
||||
String dbUserName = databaseMetaData.getUserName();
|
||||
rs = getTableResulSet(cn, databaseMetaData, dbUserName, null, TABLE_TYPES);
|
||||
|
||||
if (rs.next())
|
||||
schema = dbUserName;
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
JdbcUtil.closeResultSet(rs);
|
||||
}
|
||||
}
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
protected static Method GET_SCHEMA_METHOD_JDBC41 = null;
|
||||
static
|
||||
{
|
||||
Method[] methods = Connection.class.getMethods();
|
||||
|
||||
for (Method method : methods)
|
||||
{
|
||||
if ("getSchema".equals(method.getName()))
|
||||
{
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
|
||||
if (parameterTypes == null || parameterTypes.length == 0)
|
||||
{
|
||||
GET_SCHEMA_METHOD_JDBC41 = method;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta.resolver;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.util.List;
|
||||
|
||||
import org.datagear.meta.Column;
|
||||
import org.datagear.meta.SimpleTable;
|
||||
import org.datagear.meta.Table;
|
||||
|
||||
/**
|
||||
* 数据库元信息解析类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public interface DBMetaResolver
|
||||
{
|
||||
/**
|
||||
* 获取所有{@linkplain SimpleTable}。
|
||||
*
|
||||
* @param cn
|
||||
* @return
|
||||
* @throws DBMetaResolverException
|
||||
*/
|
||||
List<SimpleTable> getSimpleTables(Connection cn) throws DBMetaResolverException;
|
||||
|
||||
/**
|
||||
* 随机获取一个{@linkplain SimpleTable}。
|
||||
*
|
||||
* @param cn
|
||||
* @return 可能返回{@code null}
|
||||
* @throws DBMetaResolverException
|
||||
*/
|
||||
SimpleTable getRandomSimpleTable(Connection cn) throws DBMetaResolverException;
|
||||
|
||||
/**
|
||||
* 获取指定名称的{@linkplain Table}。
|
||||
*
|
||||
* @param cn
|
||||
* @param tableName
|
||||
* @return
|
||||
* @throws DBMetaResolverException
|
||||
*/
|
||||
Table getTable(Connection cn, String tableName) throws DBMetaResolverException;
|
||||
|
||||
/**
|
||||
* 获取指定表的一个随机{@linkplain Column}。
|
||||
*
|
||||
* @param cn
|
||||
* @param tableName
|
||||
* @return 返回{@code null}表示没找到任何字段
|
||||
* @throws DBMetaResolverException
|
||||
*/
|
||||
Column getRandomColumn(Connection cn, String tableName) throws DBMetaResolverException;
|
||||
|
||||
/**
|
||||
* 获取指定{@linkplain ResultSetMetaData}的{@linkplain Column}。
|
||||
*
|
||||
* @param cn
|
||||
* @param resultSetMetaData
|
||||
* @return
|
||||
* @throws DBMetaResolverException
|
||||
*/
|
||||
Column[] getColumns(Connection cn, ResultSetMetaData resultSetMetaData) throws DBMetaResolverException;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta.resolver;
|
||||
|
||||
/**
|
||||
* 数据库元信息解析异常。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class DBMetaResolverException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public DBMetaResolverException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public DBMetaResolverException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DBMetaResolverException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public DBMetaResolverException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta.resolver;
|
||||
|
||||
import org.datagear.connection.ConnectionSensor;
|
||||
|
||||
/**
|
||||
* 专职{@linkplain DBMetaResolver}。
|
||||
* <p>
|
||||
* 此类继承自{@linkplain DBMetaResolver}的所有方法仅在{@linkplain #supports(java.sql.Connection)}返回{@code true}时可用。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public interface DevotedDBMetaResolver extends DBMetaResolver, ConnectionSensor
|
||||
{
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta.resolver;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.util.List;
|
||||
|
||||
import org.datagear.connection.ConnectionOption;
|
||||
import org.datagear.meta.Column;
|
||||
import org.datagear.meta.SimpleTable;
|
||||
import org.datagear.meta.Table;
|
||||
|
||||
/**
|
||||
* 通用{@linkplain DBMetaResolver}。
|
||||
* <p>
|
||||
* 它从其包含的{@linkplain DevotedDBMetaResolver}中(
|
||||
* {@linkplain #getDevotedDBMetaResolvers()},越靠前越优先使用)查找能够处理给定{@link Connection}
|
||||
* 的那一个,并使用其API。
|
||||
* </p>
|
||||
* <p>
|
||||
* 如果没有查找到能处理给定{@link Connection}的{@linkplain DevotedDBMetaResolver},此类将抛出
|
||||
* {@linkplain UnsupportedDBMetaResolverException}异常。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class GenericDBMetaResolver implements DBMetaResolver
|
||||
{
|
||||
private List<DevotedDBMetaResolver> devotedDBMetaResolvers = null;
|
||||
|
||||
public GenericDBMetaResolver()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public GenericDBMetaResolver(List<DevotedDBMetaResolver> devotedDBMetaResolvers)
|
||||
{
|
||||
super();
|
||||
this.devotedDBMetaResolvers = devotedDBMetaResolvers;
|
||||
}
|
||||
|
||||
public List<DevotedDBMetaResolver> getDevotedDBMetaResolvers()
|
||||
{
|
||||
return devotedDBMetaResolvers;
|
||||
}
|
||||
|
||||
public void setDevotedDBMetaResolvers(List<DevotedDBMetaResolver> devotedDBMetaResolvers)
|
||||
{
|
||||
this.devotedDBMetaResolvers = devotedDBMetaResolvers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SimpleTable> getSimpleTables(Connection cn) throws DBMetaResolverException
|
||||
{
|
||||
DevotedDBMetaResolver resolver = doGetDevotedDBMetaResolverNotNull(cn);
|
||||
return resolver.getSimpleTables(cn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleTable getRandomSimpleTable(Connection cn) throws DBMetaResolverException
|
||||
{
|
||||
DevotedDBMetaResolver resolver = doGetDevotedDBMetaResolverNotNull(cn);
|
||||
return resolver.getRandomSimpleTable(cn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table getTable(Connection cn, String tableName) throws DBMetaResolverException
|
||||
{
|
||||
DevotedDBMetaResolver resolver = doGetDevotedDBMetaResolverNotNull(cn);
|
||||
return resolver.getTable(cn, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Column getRandomColumn(Connection cn, String tableName) throws DBMetaResolverException
|
||||
{
|
||||
DevotedDBMetaResolver resolver = doGetDevotedDBMetaResolverNotNull(cn);
|
||||
return resolver.getRandomColumn(cn, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Column[] getColumns(Connection cn, ResultSetMetaData resultSetMetaData) throws DBMetaResolverException
|
||||
{
|
||||
DevotedDBMetaResolver resolver = doGetDevotedDBMetaResolverNotNull(cn);
|
||||
return resolver.getColumns(cn, resultSetMetaData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支持指定{@linkplain Connection}的{@linkplain DevotedDBMetaResolver}。
|
||||
*
|
||||
* @param cn
|
||||
* @return
|
||||
* @throws UnsupportedDBMetaResolverException
|
||||
*/
|
||||
protected DevotedDBMetaResolver doGetDevotedDBMetaResolverNotNull(Connection cn)
|
||||
throws UnsupportedDBMetaResolverException
|
||||
{
|
||||
DevotedDBMetaResolver resolver = doGetDevotedDBMetaResolver(cn);
|
||||
|
||||
if (resolver == null)
|
||||
throw new UnsupportedDBMetaResolverException(ConnectionOption.valueOf(cn));
|
||||
|
||||
return resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cn
|
||||
* @return 返回{@code null}表示没有
|
||||
*/
|
||||
protected DevotedDBMetaResolver doGetDevotedDBMetaResolver(Connection cn)
|
||||
{
|
||||
if (this.devotedDBMetaResolvers == null)
|
||||
return null;
|
||||
|
||||
for (DevotedDBMetaResolver resolver : this.devotedDBMetaResolvers)
|
||||
{
|
||||
if (resolver.supports(cn))
|
||||
return resolver;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta.resolver;
|
||||
|
||||
/**
|
||||
* 表未找到异常。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class TableNotFoundException extends DBMetaResolverException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String tableName;
|
||||
|
||||
public TableNotFoundException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public TableNotFoundException(String tableName)
|
||||
{
|
||||
super("Table [" + tableName + "] not found");
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public TableNotFoundException(String tableName, Throwable cause)
|
||||
{
|
||||
this(tableName);
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
protected void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta.resolver;
|
||||
|
||||
import org.datagear.connection.ConnectionOption;
|
||||
|
||||
/**
|
||||
* 不支持数据库信息解析异常。
|
||||
* <p>
|
||||
* {@linkplain GenericDBMetaResolver}在未找到支持{@linkplain DevotedDBMetaResolver}时抛出此异常。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class UnsupportedDBMetaResolverException extends DBMetaResolverException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ConnectionOption connectionOption;
|
||||
|
||||
public UnsupportedDBMetaResolverException(ConnectionOption connectionOption)
|
||||
{
|
||||
super("Resolving database info for [" + connectionOption + "] is not supported");
|
||||
this.connectionOption = connectionOption;
|
||||
}
|
||||
|
||||
public ConnectionOption getConnectionOption()
|
||||
{
|
||||
return connectionOption;
|
||||
}
|
||||
|
||||
protected void setConnectionOption(ConnectionOption connectionOption)
|
||||
{
|
||||
this.connectionOption = connectionOption;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta.resolver;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* 通配{@linkplain DevotedDBMetaResolver}。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class WildcardDevotedDBMetaResolver extends AbstractDevotedDBMetaResolver
|
||||
{
|
||||
public WildcardDevotedDBMetaResolver()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Connection cn)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta.resolver.support;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.datagear.connection.ConnectionSensor;
|
||||
import org.datagear.connection.URLConnectionSensor;
|
||||
import org.datagear.connection.support.MySqlURLSensor;
|
||||
import org.datagear.meta.SimpleTable;
|
||||
import org.datagear.meta.resolver.AbstractConnectionDevotedDBMetaResolver;
|
||||
import org.datagear.meta.resolver.DevotedDBMetaResolver;
|
||||
import org.datagear.util.StringUtil;
|
||||
|
||||
/**
|
||||
* MySQL {@linkplain DevotedDBMetaResolver}。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class MySqlDevotedDBMetaResolver extends AbstractConnectionDevotedDBMetaResolver
|
||||
{
|
||||
public MySqlDevotedDBMetaResolver()
|
||||
{
|
||||
super(new URLConnectionSensor(new MySqlURLSensor()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConnectionSensor(ConnectionSensor connectionSensor)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<SimpleTable> postProcessSimpleTables(List<SimpleTable> simpleTables)
|
||||
{
|
||||
if (simpleTables != null)
|
||||
{
|
||||
for (SimpleTable st : simpleTables)
|
||||
resolveTableComment(st);
|
||||
}
|
||||
|
||||
return simpleTables;
|
||||
}
|
||||
|
||||
protected void resolveTableComment(SimpleTable st)
|
||||
{
|
||||
String comment = st.getComment();
|
||||
|
||||
if (StringUtil.isEmpty(comment))
|
||||
return;
|
||||
|
||||
int colonIdx = comment.indexOf(';');
|
||||
|
||||
if (colonIdx > -1)
|
||||
{
|
||||
comment = comment.substring(0, colonIdx);
|
||||
st.setComment(comment);
|
||||
}
|
||||
else
|
||||
st.setComment("");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.meta;
|
||||
|
||||
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
|
||||
import static org.hamcrest.collection.ArrayMatching.hasItemInArray;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
import static org.hamcrest.core.IsIterableContaining.hasItem;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.datagear.meta.resolver.DevotedDBMetaResolver;
|
||||
import org.datagear.meta.resolver.GenericDBMetaResolver;
|
||||
import org.datagear.meta.resolver.WildcardDevotedDBMetaResolver;
|
||||
import org.datagear.meta.resolver.support.MySqlDevotedDBMetaResolver;
|
||||
import org.datagear.util.JdbcUtil;
|
||||
import org.datagear.util.test.DBTestSupport;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@linkplain GenericDBMetaResolver}单元测试类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class GenericDBMetaResolverTest extends DBTestSupport
|
||||
{
|
||||
private GenericDBMetaResolver genericDBMetaResolver;
|
||||
|
||||
public GenericDBMetaResolverTest()
|
||||
{
|
||||
super();
|
||||
|
||||
List<DevotedDBMetaResolver> devotedDBMetaResolvers = new ArrayList<DevotedDBMetaResolver>();
|
||||
devotedDBMetaResolvers.add(new MySqlDevotedDBMetaResolver());
|
||||
devotedDBMetaResolvers.add(new WildcardDevotedDBMetaResolver());
|
||||
|
||||
this.genericDBMetaResolver = new GenericDBMetaResolver(devotedDBMetaResolvers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSimpleTablesTest() throws Exception
|
||||
{
|
||||
Connection cn = null;
|
||||
|
||||
List<SimpleTable> simpleTables = null;
|
||||
|
||||
try
|
||||
{
|
||||
cn = getConnection();
|
||||
|
||||
simpleTables = this.genericDBMetaResolver.getSimpleTables(cn);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JdbcUtil.closeConnection(cn);
|
||||
}
|
||||
|
||||
assertThat(simpleTables, hasItem(hasProperty("name", equalTo("T_ACCOUNT"))));
|
||||
assertThat(simpleTables, hasItem(hasProperty("name", equalTo("T_ADDRESS"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTableTest() throws Exception
|
||||
{
|
||||
Connection cn = null;
|
||||
|
||||
Table table0 = null;
|
||||
Table table1 = null;
|
||||
|
||||
try
|
||||
{
|
||||
cn = getConnection();
|
||||
|
||||
table0 = this.genericDBMetaResolver.getTable(cn, "T_ACCOUNT");
|
||||
table1 = this.genericDBMetaResolver.getTable(cn, "T_ADDRESS");
|
||||
}
|
||||
finally
|
||||
{
|
||||
JdbcUtil.closeConnection(cn);
|
||||
}
|
||||
|
||||
assertThat(table0, hasProperty("name", equalTo("T_ACCOUNT")));
|
||||
assertThat(table0, hasProperty("columns", hasItemInArray(hasProperty("name", equalTo("ID")))));
|
||||
assertThat(table0, hasProperty("primaryKey", hasProperty("columnNames", hasItemInArray(equalTo("ID")))));
|
||||
|
||||
assertThat(table1, hasProperty("name", equalTo("T_ADDRESS")));
|
||||
assertThat(table1, hasProperty("columns", hasItemInArray(hasProperty("name", equalTo("ACCOUNT_ID")))));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package org.datagear.util.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.Reader;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 数据库测试支持类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class DBTestSupport
|
||||
{
|
||||
private static final Properties JDBC_PROPERTIES = new Properties();
|
||||
|
||||
static
|
||||
{
|
||||
File jdbcConfigFile = new File("test/config/jdbc.properties");
|
||||
if (!jdbcConfigFile.exists())
|
||||
jdbcConfigFile = new File("../test/config/jdbc.properties");
|
||||
|
||||
try
|
||||
{
|
||||
Reader reader = new FileReader(jdbcConfigFile);
|
||||
JDBC_PROPERTIES.load(reader);
|
||||
reader.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException) e;
|
||||
else
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Connection getConnection() throws Exception
|
||||
{
|
||||
return DriverManager.getConnection(JDBC_PROPERTIES.getProperty("jdbc.url"),
|
||||
JDBC_PROPERTIES.getProperty("jdbc.user"), JDBC_PROPERTIES.getProperty("jdbc.password"));
|
||||
}
|
||||
|
||||
protected Connection getConnection(Properties properties) throws Exception
|
||||
{
|
||||
properties.setProperty("user", JDBC_PROPERTIES.getProperty("jdbc.user"));
|
||||
properties.setProperty("password", JDBC_PROPERTIES.getProperty("jdbc.password"));
|
||||
|
||||
return DriverManager.getConnection(JDBC_PROPERTIES.getProperty("jdbc.url"), properties);
|
||||
}
|
||||
|
||||
protected void println()
|
||||
{
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
protected void println(Object o)
|
||||
{
|
||||
System.out.println((o == null ? "null" : o.toString()));
|
||||
}
|
||||
|
||||
protected void print(Object o)
|
||||
{
|
||||
System.out.print((o == null ? "null" : o.toString()));
|
||||
}
|
||||
}
|
10
pom.xml
10
pom.xml
|
@ -15,6 +15,7 @@
|
|||
<maven.compile.source>1.8</maven.compile.source>
|
||||
<maven.compile.target>1.8</maven.compile.target>
|
||||
<junit.version>4.11</junit.version>
|
||||
<hamcrest.version>2.2</hamcrest.version>
|
||||
<spring.version>4.3.26.RELEASE</spring.version>
|
||||
<spring.security.version>3.2.10.RELEASE</spring.security.version>
|
||||
<DBCP.version>1.4</DBCP.version><!-- 更高版本的不兼容JDBC 4.0 -->
|
||||
|
@ -41,7 +42,8 @@
|
|||
<module>datagear-web</module>
|
||||
<module>datagear-webapp</module>
|
||||
<module>datagear-webappembd</module>
|
||||
</modules>
|
||||
<module>datagear-meta</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@ -49,6 +51,12 @@
|
|||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest</artifactId>
|
||||
<version>${hamcrest.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
|
Loading…
Reference in New Issue