基于geotools24.0的创建自动增长主键id字段的方法
原始引入的包中有bug,一直返回fid主键的问题
protected String findPrimaryKeyColumnName(SimpleFeatureType featureType) {
String[] suffix = new String[] {
"", "_1", "_2"};
String[] base = new String[] {
"fid", "id", "gt_id", "ogc_fid"};
for (String b : base) {
//O:
for (String s : suffix) {
String name = b + s;
for (AttributeDescriptor ad : featureType.getAttributeDescriptors()) {
if (ad.getLocalName().equalsIgnoreCase(name)) {
return name; //continue O;
}
}
//return name;
}
}
// practically should never get here, but just fall back and fail later
return "fid";
}
下面为修改后创建自动增长主键id字段的方法
主要修改两处:
一、findPrimaryKeyColumnName方法的修改
二、createTableSQL方法有主键id字段,不能重复添加字段
修改后代码
//
private DataStore m_pgDatastore = null;
public boolean initPgDatastore(String dbtype, String host, Integer port, String database, String userName, String password) {
boolean success =false;
if(m_pgDatastore==null) {
try {
if(m_pgDatastore==null) {
Map<String, Object> params = new HashMap<String, Object>();
params.put(PostgisNGDataStoreFactory.DBTYPE.key, "postgis"); //需要连接何种数据库,postgis or mysql
params.put(PostgisNGDataStoreFactory.HOST.key, host);//ip地址
params.put(PostgisNGDataStoreFactory.PORT.key, port);//端口号
params.put(PostgisNGDataStoreFactory.DATABASE.key, database);//需要连接的数据库
params.put(PostgisNGDataStoreFactory.SCHEMA.key, "public");//架构
params.put(PostgisNGDataStoreFactory.USER.key, userName);//需要连接数据库的名称
params.put(PostgisNGDataStoreFactory.PASSWD.key, password);//数据库的密码
//获取存储空间
m_pgDatastore= DataStoreFinder.getDataStore(params);
}
success = true;
} catch (IOException e) {
e.printStackTrace();
this.logger.error(e.getMessage());
} finally {
}
}
return success;
}
public boolean initPgDatastore(DbConfig sdeCfg)
{
return this.initPgDatastore(sdeCfg.getDbType(),sdeCfg.getHost(),sdeCfg.getPort(),sdeCfg.getDatabase(),sdeCfg.getUsername(),sdeCfg.getPassword());
}
public JDBCDataStore getJDBCDataStore() {
return (JDBCDataStore) this.m_pgDatastore;
}
public boolean close()
{
if(m_pgDatastore!=null)
{
m_pgDatastore.dispose();
m_pgDatastore=null;
}
return true;
}
//创建表结构
public void createSchema(final SimpleFeatureType featureType) throws IOException {
/*
if (entry(featureType.getName()) != null) {
String msg = "Schema '" + featureType.getName() + "' already exists";
throw new IllegalArgumentException(msg);
}*/
// execute the create table statement
// TODO: create a primary key and a spatial index
Connection cx = this.createConnection();
try {
String sql = createTableSQL(featureType, cx);
//LOGGER.log(Level.FINE, "Create schema: {0}", sql);
Statement st = cx.createStatement();
try {
st.execute(sql);
} finally {
this.closeSafe(st);
}
this.getJDBCDataStore().dialect.postCreateTable(this.getJDBCDataStore().getDatabaseSchema(), featureType, cx);
} catch (Exception e) {
String msg = "Error occurred creating table";
throw (IOException) new IOException(msg).initCause(e);
} finally {
this.closeSafe(cx);
}
}
protected String createTableSQL(SimpleFeatureType featureType,Connection cx) throws Exception {
// figure out the names and types of the columns
String[] columnNames = new String[featureType.getAttributeCount()];
String[] sqlTypeNames = null;
Class[] classes = new Class[featureType.getAttributeCount()];
// figure out which columns can not be null
boolean[] nillable = new boolean[featureType.getAttributeCount()];
for (int i = 0; i < featureType.getAttributeCount(); i++) {
AttributeDescriptor attributeType = featureType.getDescriptor(i);
// column name
columnNames[i] = attributeType.getLocalName();
// column type
classes[i] = attributeType.getType().getBinding();
// can be null?
nillable[i] = attributeType.getMinOccurs() <= 0 || attributeType.isNillable();
// eventual options
}
sqlTypeNames = getSQLTypeNames(featureType.getAttributeDescriptors(), cx);
for (int i = 0; i < sqlTypeNames.length; i++) {
if (sqlTypeNames[i] == null) {
String msg = "Unable to map " + columnNames[i] + "( " + classes[i].getName() + ")";
throw new RuntimeException(msg);
}
}
return createTableSQL(
featureType.getTypeName(),
columnNames,
sqlTypeNames,
nillable,
findPrimaryKeyColumnName(featureType),
featureType);
}
private String createTableSQL(
String tableName,
String[] columnNames,
String[] sqlTypeNames,
boolean[] nillable,
String pkeyColumn,
SimpleFeatureType featureType)
throws SQLException {
// build the create table sql
StringBuffer sql = new StringBuffer();
this.getJDBCDataStore().dialect.encodeCreateTable(sql);
this.getJDBCDataStore().encodeTableName(tableName, sql, null);
sql.append(" ( ");
// primary key column
if (pkeyColumn != null) {
this.getJDBCDataStore().dialect.encodePrimaryKey(pkeyColumn, sql);
sql.append(", ");
}
// normal attributes
for (int i = 0; i < columnNames.length; i++) {
if(pkeyColumn!=null && columnNames[i].equals(pkeyColumn)==true)
{
//跳过主键字段,上面已添加主键字段
continue;
}
// the column name
this.getJDBCDataStore().dialect.encodeColumnName(null, columnNames[i], sql);
sql.append(" ");
// some sql dialects require varchars to have an
// associated size with them
int length = -1;
if (sqlTypeNames[i].toUpperCase().startsWith("VARCHAR")) {
if (featureType != null) {
AttributeDescriptor att = featureType.getDescriptor(columnNames[i]);
length = this.findVarcharColumnLength(att);
}
}
// only apply a length if one exists (i.e. to applicable varchars)
if (length == -1) {
this.getJDBCDataStore().dialect.encodeColumnType(sqlTypeNames[i], sql);
} else {
this.getJDBCDataStore().dialect.encodeColumnType(sqlTypeNames[i] + "(" + length + ")", sql);
}
// nullable
if (nillable != null && !nillable[i]) {
sql.append(" NOT NULL ");
}
// delegate to dialect to encode column postamble
if (featureType != null) {
AttributeDescriptor att = featureType.getDescriptor(columnNames[i]);
this.getJDBCDataStore().dialect.encodePostColumnCreateTable(att, sql);
}
// sql.append(sqlTypeNames[i]);
if (i < (sqlTypeNames.length - 1)) {
sql.append(", ");
}
}
sql.append(" ) ");
// encode anything post create table
this.getJDBCDataStore().dialect.encodePostCreateTable(tableName, sql);
return sql.toString();
}
private Integer findVarcharColumnLength(AttributeDescriptor att) {
for (Filter r : att.getType().getRestrictions()) {
if (r instanceof PropertyIsLessThanOrEqualTo) {
PropertyIsLessThanOrEqualTo c = (PropertyIsLessThanOrEqualTo) r;
if (c.getExpression1() instanceof Function
&& ((Function) c.getExpression1())
.getName()
.toLowerCase()
.endsWith("length")) {
if (c.getExpression2() instanceof Literal) {
Integer length = c.getExpression2().evaluate(null, Integer.class);
if (length != null) {
return length;
}
}
}
}
}
return this.getJDBCDataStore().dialect.getDefaultVarcharSize();
}
private String[] getSQLTypeNames(List<AttributeDescriptor> descriptors, Connection cx)
throws SQLException {
// figure out what the sql types are corresponding to the feature type
// attributes
int[] sqlTypes = new int[descriptors.size()];
String[] sqlTypeNames = new String[sqlTypes.length];
for (int i = 0; i < descriptors.size(); i++) {
AttributeDescriptor ad = descriptors.get(i);
Class clazz = ad.getType().getBinding();
Integer sqlType = this.getJDBCDataStore().dialect.getSQLType(ad);
if (sqlType == null) {
sqlType = this.getJDBCDataStore().getMapping(clazz);
}
if (sqlType == null) {
sqlType = Types.OTHER;
}
sqlTypes[i] = sqlType;
// if this a geometric type, get the name from teh dialect
// if ( attributeType instanceof GeometryDescriptor ) {
if (Geometry.class.isAssignableFrom(clazz)) {
String sqlTypeName = this.getJDBCDataStore().dialect.getGeometryTypeName(sqlType);
if (sqlTypeName != null) {
sqlTypeNames[i] = sqlTypeName;
}
}
// check types previously read from DB
String sqlTypeDBName = this.getJDBCDataStore().getDBsqlTypesCache().get(sqlType);
if (sqlTypeDBName != null) {
sqlTypeNames[i] = sqlTypeDBName;
}
}
// GEOT-6347 if all sql type names have been found in dialect dont
// go to database
boolean allTypesFound = !ArrayUtils.contains(sqlTypeNames, null);
if (!allTypesFound) {
//LOGGER.log(Level.WARNING, "Fetching fields from Database");
// figure out the type names that correspond to the sql types from
// the database metadata
DatabaseMetaData metaData = cx.getMetaData();
ResultSet types = metaData.getTypeInfo();
try {
while (types.next()) {
int sqlType = types.getInt("DATA_TYPE");
String sqlTypeName = types.getString("TYPE_NAME");
for (int i = 0; i < sqlTypes.length; i++) {
// check if we already have the type name from the dialect
if (sqlTypeNames[i] != null) {
continue;
}
if (sqlType == sqlTypes[i]) {
sqlTypeNames[i] = sqlTypeName;
// GEOT-6347
// cache the sqlType which required going to database for sql types
this.getJDBCDataStore().getDBsqlTypesCache().putIfAbsent(sqlType, sqlTypeName);
}
}
}
} finally {
this.getJDBCDataStore().closeSafe(types);
}
}
// apply the overrides specified by the dialect
Map<Integer, String> overrides = getSqlTypeToSqlTypeNameOverrides();
for (int i = 0; i < sqlTypes.length; i++) {
String override = overrides.get(sqlTypes[i]);
if (override != null) sqlTypeNames[i] = override;
}
return sqlTypeNames;
}
protected final Connection createConnection() {
try {
//LOGGER.fine("CREATE CONNECTION");
Connection cx = this.getJDBCDataStore().getDataSource().getConnection();
// isolation level is not set in the datastore, see
// http://jira.codehaus.org/browse/GEOT-2021
// call dialect callback to initialize the connection
this.getJDBCDataStore().dialect.initializeConnection(cx);
// if there is any lifecycle listener use it
if (connectionLifecycleListeners.size() > 0) {
List<ConnectionLifecycleListener> locals =
new ArrayList<ConnectionLifecycleListener>(connectionLifecycleListeners);
cx = new LifecycleConnection(this.getJDBCDataStore(), cx, locals);
}
return cx;
} catch (SQLException e) {
throw new RuntimeException("Unable to obtain connection: " + e.getMessage(), e);
}
}
protected List<ConnectionLifecycleListener> connectionLifecycleListeners =
new CopyOnWriteArrayList<ConnectionLifecycleListener>();
/*
* search feature type looking for suitable unique column for primary key.
*/
protected String findPrimaryKeyColumnName(SimpleFeatureType featureType) {
String[] suffix = new String[] {
"", "_1", "_2"};
String[] base = new String[] {
"fid", "id", "gt_id", "ogc_fid"};
for (String b : base) {
//O:
for (String s : suffix) {
String name = b + s;
for (AttributeDescriptor ad : featureType.getAttributeDescriptors()) {
if (ad.getLocalName().equalsIgnoreCase(name)) {
return name; //continue O;
}
}
//return name;
}
}
// practically should never get here, but just fall back and fail later
return "fid";
}
protected HashMap<Integer, String> sqlTypeToSqlTypeNameOverrides;
public Map<Integer, String> getSqlTypeToSqlTypeNameOverrides() {
if (sqlTypeToSqlTypeNameOverrides == null) {
sqlTypeToSqlTypeNameOverrides = new HashMap<Integer, String>();
((JDBCDataStore)this.m_pgDatastore).dialect.registerSqlTypeToSqlTypeNameOverrides(sqlTypeToSqlTypeNameOverrides);
}
return sqlTypeToSqlTypeNameOverrides;
}
public void closeSafe(Statement st) {
if (st == null) {
return;
}
try {
st.close();
} catch (SQLException e) {
String msg = "Error occurred closing statement";
/*
//LOGGER.warning(msg);
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.log(Level.FINER, msg, e);
}*/
}
}
/**
* Utility method for closing a connection.
*
* <p>This method closed the connection "safely" in that it never throws an exception. Any
* exceptions that do occur are logged at {@link Level#FINER}.
*
* @param cx The connection to close.
*/
public void closeSafe(Connection cx) {
if (cx == null) {
return;
}
try {
// System.out.println("Closing connection " + System.identityHashCode(cx));
cx.close();
//LOGGER.fine("CLOSE CONNECTION");
} catch (SQLException e) {
String msg = "Error occurred closing connection";
/*
LOGGER.warning(msg);
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.log(Level.FINER, msg, e);
}*/
}
}