前面说过SQLDialect被用于屏蔽各种数据库SQL的差异,可以理解为策略模式。凡是涉及到sql的,均由该类来处理。
SQLDialect是一个抽象类,该类继承结构相对就很简单了:
选择直接从BasicSQLDialect派生自己的Dialect。派生后有4个必须实现的函数,如下:
l encodeGeometryValue (Geometry value, int srid, StringBuffer sql)
根据Geometry对象,生成sql语句。
由于只是为GeoServer增加自定义数据源,并不涉及到空间数据的修改,因此可以不为用encodeGeometryValue函数写代码。
l decodeGeometryEnvelope(ResultSet rs, int column,Connection cx)
从rs中获取Geometry的包围盒大小,生成Envelope对象并返回。
l decodeGeometryValue(ResultSet rs, int column,Connection cx)
从rs中获取Geometry数据,构造Geometry对象并返回。
l encodeGeometryEnvelope(String tableName, String geometryColumn,StringBuffer sql)
该函数是用于构造获取指定表的Envelope的sql语句,
代码如下:
public void encodeGeometryEnvelope(String tableName, String geometryColumn, StringBuffer sql) {
sql.append(FeatureClassInfo.XMIN_FIELD_NAME + "," + FeatureClassInfo.XMAX_FIELD_NAME + "," +
FeatureClassInfo.YMIN_FIELD_NAME + "," + FeatureClassInfo.YMAX_FIELD_NAME );
}
但是在一般情况下,仅仅这4个函数并不能满足需求。
l includeTable(String schemaName, String tableName, Connection cx)
该函数用于判断指定的表名是否是空间数据表。
l getGeometrySRID(String schemaName, String tableName,String columnName, Connection cx)
该函数用于返回指定表的SRID(整型)。
l encodeColumnAlias(String raw, StringBuffer sql)
l getMapping(ResultSet columnMetaData, Connection cx)
该函数用来说明当前表保存的是哪种类型的空间数据。如果点状要素,则返回Point.Class(com.vividsolutions.jts.geom),以此类推。如果不确定则返回Geometry.class或者null。
代码如下:
public Class<?> getMapping(ResultSet columnMetaData, Connection cx)
throws SQLException {
String name = columnMetaData.getString("TYPE_NAME");
if ( name.equalsIgnoreCase("image") == false ) {
return null;
}
String tableName = columnMetaData.getString("TABLE_NAME");
AccessHelper helper = new AccessHelper(cx);
GisDBHelper gisdb = new GisDBHelper();
FeatureClassInfo fci = gisdb.getFeatureClassInfo(helper, tableName);
if ( fci.getShapeType() == GisGeometryType.gisGeoTypePoint )
return Point.class;
else if ( fci.getShapeType() == GisGeometryType.gisGeoTypePolyline )
return MultiLineString.class;
else if ( fci.getShapeType() == GisGeometryType.gisGeoTypePolygon )
return MultiPolygon.class;
return null;
}
另外,值得说的是主键查找器。这里为了得到主键,gt里定义了一个抽象类PrimaryKeyFinder,并且有相应的实现类。不过由于自定义数据源,因此并不能直接使用gt中现有的类。为此,从PrimaryKeyFinder派生了一个子类负责返回主键,代码如下:
public class GisPrimaryKeyFinder extends PrimaryKeyFinder {
@Override
public PrimaryKey getPrimaryKey(JDBCDataStore store, String schema,
String table, Connection cx) throws SQLException {
// TODO Auto-generated method stub
AccessHelper helper = new AccessHelper(cx);
FeatureClassInfo fci = GisDBHelper.getFeatureClassInfo(helper, table);
PrimaryKey pk = null;
if ( fci != null )
{
List<PrimaryKeyColumn> keys = new ArrayList<PrimaryKeyColumn>();
keys.add(new NonIncrementingPrimaryKeyColumn(fci.getOidFieldName(),
Integer.class));
pk = new PrimaryKey(table, keys);
}
helper.closeStatement();
return pk;
}
}
那么这个类在什么地方和JDBCDataStore关联起来?
就在数据源工厂类的createSQLDialect方法中,代码如下:
protected SQLDialect createSQLDialect(JDBCDataStore dataStore)
{
dataStore.setPrimaryKeyFinder(new GisPrimaryKeyFinder());
return new KqGisSqlServerSQLDialect(dataStore);
}
通过以上代码就可以实现自定义的空间数据源(数据库型)。
PS:实现自定义的数据源其实并不复杂,大量的时间花在了研究GeoServer和GeoTools中。