在上一遍利用st_geometry进行图形叠加分析文章的基础上,结合mybatis操做st_geometry,主要简单实现一下三个功能:利用st_geometry两个表之间图形表的叠加分析、WKT与图形表的叠加分析、将WKT存储至数据图形表。html
两个表之间图形表的叠加分析,先来建立一个专门构造sql的类,而后利用mybatis建立构造叠加分析的sql语句的方法java
package com.zifan.st_geometry.mapper; import java.lang.reflect.Field; import org.apache.ibatis.jdbc.SQL; public class STGeomertySqlBuilder { /** * * @param srcTableName 源表表名字 * @param targetTableName 目标表的表名 * @param fields 返回表字段数据,若是两个代表字段都同样,要求添加前缀T或者S,例如T.OBJECTID * @param where 原表数据条件,例如 objectId=100 * @return */ public String buildQueryIntersectByWhere(final String srcTableName, final String targetTableName, final String[] fields, final String where) { return new SQL() { { SELECT("SDE.ST_AREA(SDE.ST_TRANSFORM(S.SHAPE, #{srId})) SAREA"); SELECT("SDE.ST_ASTEXT(SDE.ST_INTERSECTION(SDE.ST_TRANSFORM(T.SHAPE, #{srId}),SDE.ST_TRANSFORM(S.SHAPE, #{srId}))) OVERLAPCOORDS"); SELECT("SDE.ST_AREA(SDE.ST_INTERSECTION(SDE.ST_TRANSFORM(T.SHAPE, #{srId}),SDE.ST_TRANSFORM(S.SHAPE, #{srId}))) OVERLAPAREA"); if (fields != null) { for (String field : fields) { SELECT(field); } } FROM(srcTableName + " S").FROM(targetTableName + " T");//添加表别名 WHERE("SDE.ST_INTERSECTS(T.SHAPE, S.SHAPE) = 1").AND().WHERE(where); } }.toString(); } }
上面buildQueryIntersectByWhere方法返回的是根据一个源表某条或者多条的图形数据与须要叠加分析的表的sql语句。返回的sql语句出了会返回指定的字段数据外,默认会返回源图形面积、叠加面积以及叠加图形的坐标串WKT。git
接下来进行实际叠加分析操做写mybatis的Mapper接口spring
package com.zifan.st_geometry.mapper; import java.util.HashMap; import java.util.List; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.SelectProvider; import org.apache.ibatis.type.ClobTypeHandler; @Mapper public interface STGeometryMapper { @Results({@Result(property = "OVERLAPCOORDS", column = "OVERLAPCOORDS", javaType = String.class, typeHandler = ClobTypeHandler.class) }) @SelectProvider(type = STGeomertySqlBuilder.class, method = "buildQueryIntersectByWhere") List<HashMap<String, Object>> queryIntersectByWhere(String srcTableName, String targetTableName, String[] fields, String where, @Param("srId") int srId); }
这个方法返回的是List的HashMap,经过mybatis的注解SelectProvider定义此方法的查询语句。对于返回数据的处理,利用注解Results将返回的数据中包含叠加的WKT坐标串就涉及到CLOB大字段经过ClobTypeHandler类将转换成String类型。mybatis提供一个TypeHandler接口类,实现该接口处理要插入到数据库或者数据库返回的字段,ClobTypeHandler是mybatis自带的一个clob字段处理类。sql
@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest public class STGeometryTest { @Autowired private STGeometryMapper stGeometryMapper; @Test public void test() { List<HashMap<String, Object>> map = stGeometryMapper.queryIntersectByWhere("TABLE1", "TABLE2", new String[] { "T.DL", "S.MC"}, "S.OBJECTID = 18133", 2); // System.out.println(net.minidev.json.JSONArray.toJSONString(map)); Assert.assertEquals(4, map.size()); } }
测试结果返回4条叠加数据,能够打印出来返回list的JSON数据看看,这里我省略的坐标的显示。数据库
[ { "SAREA": 19562.0006962064, "OVERLAPAREA": 2776.6041580972, "OVERLAPCOORDS": "POLYGON (( ...))", "DL": "4419", "MC": "项目1" }, { "SAREA": 19562.0006962064, "OVERLAPAREA": 14444.0513595036, "OVERLAPCOORDS": "MULTIPOLYGON ((( ...)))", "DL": "4419", "MC": "项目2" }, { "SAREA": 19562.0006962064, "OVERLAPAREA": 0.00205911626740205, "OVERLAPCOORDS": "POLYGON (( ...))", "DL": "4419", "MC": "项目3" }, { "SAREA": 19562.0006962064, "OVERLAPAREA": 2341.34313614271, "OVERLAPCOORDS": "POLYGON (( ...))", "DL": "4419", "MC": "项目4" } ]
一样经过mybatis来构造叠加分析的sql语句apache
/** * * @param targetTableName 叠加图层的表名 * @param fields 返回表字段数据 * @return */ public String buildQueryIntersectByWKT(final String targetTableName, final String[] fields) { return new SQL() { { SELECT("SDE.ST_AREA(SDE.ST_GEOMETRY(#{wkt,typeHandler=com.zifan.st_geometry.handler.STGeometryHandler}, #{srId})) SAREA"); SELECT("SDE.ST_ASTEXT(SDE.ST_INTERSECTION(SDE.ST_TRANSFORM(SHAPE, #{srId}),SDE.ST_GEOMETRY(#{wkt,typeHandler=com.zifan.st_geometry.handler.STGeometryHandler}, #{srId}))) OVERLAPCOORDS"); SELECT("SDE.ST_AREA(SDE.ST_INTERSECTION(SDE.ST_TRANSFORM(SHAPE, #{srId}),SDE.ST_GEOMETRY(#{wkt,typeHandler=com.zifan.st_geometry.handler.STGeometryHandler}, #{srId}))) OVERLAPAREA"); if (fields != null) { for (String field : fields) { SELECT(field); } } FROM(targetTableName); WHERE("SDE.ST_INTERSECTS(SHAPE, SDE.ST_GEOMETRY(#{wkt,typeHandler=com.zifan.st_geometry.handler.STGeometryHandler}, #{srId})) = 1"); } }.toString(); }
上面方法中涉及到一个自定义的TypeHandler类,专门用来处理WKT字符转换成Clob,而后进行数据库操做。代码以下:json
package com.zifan.st_geometry.mapper.handler; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import oracle.sql.CLOB; public class STGeometryHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { // TODO Auto-generated method stub CLOB clob = CLOB.createTemporary(ps.getConnection(), true, CLOB.DURATION_SESSION); clob.setString(1, parameter);//ojdbc14以上支持 ps.setClob(i, clob); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { // TODO Auto-generated method stub return null; } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { // TODO Auto-generated method stub return null; } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { // TODO Auto-generated method stub return null; } }
@Results({@Result(property = "OVERLAPCOORDS", column = "OVERLAPCOORDS", javaType = String.class, typeHandler = ClobTypeHandler.class) }) @SelectProvider(type = STGeomertySqlBuilder.class, method = "buildQueryIntersectByWKT") List<HashMap<String, Object>> queryIntersectByWKT(String targetTableName, String[] fields, @Param("wkt") String wkt, @Param("srId") int srId);
返回结果与第一个功能的结果同样api
@Test public void testIntersectByWKT() { String shortWkt = "POLYGON ((3 3, 4 6, 5 3, 3 3))"; List<HashMap<String, Object>> map = intersect.queryIntersectByWKT("TB2013", new String[] { "DL", "MC"}, shortWkt, 2); // System.out.println(net.minidev.json.JSONArray.toJSONString(map)); Assert.assertEquals(80, map .size()); }
使用这种方法进行叠加分析要注意的是若是WKT坐标串越长这种方法执行的时间就越长,主要是因为这里的sql构造涉及了四个如出一辙CLOB内容的输入。因此在更多状况下仍是建议将这种方法变换成第一种的分析方法为好,具体就是先将WKT存储到临时的图形表中,而后才用表与表之间的分析方法进行叠加产生结果。mybatis
这里咱们先设计一个基础类,全部图形数据表都继承它,类属性有图形表名字、空间参考ID、objectId、wkt、表所在的数据库用户。代码:
package com.zifan.st_geometry.model; public abstract class STGeometry { //主要用于生成OBJECTID private String tableName; //主要用于生成OBJECTID private String owner; private long objectId; private int srId; private String wkt; public int getSrId() { return srId; } public void setSrId(int srId) { this.srId = srId; } public String getWkt() { return wkt; } public void setWkt(String wkt) { this.wkt = wkt; } public long getObjectId() { return objectId; } public void setObjectId(long objectId) { this.objectId = objectId; } public String getTableName() { if (tableName == null) { // 默认获取类名称 tableName = this.getClass().getSimpleName(); } return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
这里有两个字段须要说明一下,tableName、Owner,他们主要是用于产生图形数据中的主键OBJECTID的,查找下一个OBJECTID的sql语句:
SELECT SDE.VERSION_USER_DDL.NEXT_ROW_ID(UPPER('gis') (SELECT REGISTRATION_ID FROM SDE.TABLE_REGISTRY WHERE TABLE_NAME = UPPER('tb') AND OWNER = UPPER('gis'))) AS OBJECTID
public String buildInsertSql(final STGeometry geometry) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { return new SQL() { { INSERT_INTO(geometry.getTableName()); Field[] fieldList = geometry.getClass().getDeclaredFields(); for (Field field : fieldList) { String methodName = "get".concat(field.getName().substring(0, 1).toUpperCase()) .concat(field.getName().substring(1)); Method method = geometry.getClass().getMethod(methodName); if (method.invoke(geometry) != null) { VALUES(field.getName(), "#{" + field.getName() + "}"); } } VALUES("SHAPE", "SDE.ST_GEOMETRY(#{wkt,typeHandler=com.zifan.st_geometry.handler.STGeometryHandler}, #{srId})"); VALUES("OBJECTID", "#{objectId}"); } }.toString(); }
这个方法能够根据继承STGeometry类的类动态返回插入图形数据的sql语句。
final static String GET_NEXT_OBJECTID_SQL = "SELECT SDE.VERSION_USER_DDL.NEXT_ROW_ID(UPPER(#{owner,typeHandler=com.zifan.st_geometry.handler.DBOwnerHandler}),(SELECT REGISTRATION_ID FROM SDE.TABLE_REGISTRY WHERE TABLE_NAME = UPPER(#{tableName}) AND OWNER = UPPER(#{owner,typeHandler=com.zifan.st_geometry.handler.DBOwnerHandler}))) AS OBJECTID FROM DUAL"; @SelectKey(statement = GET_NEXT_OBJECTID_SQL, keyProperty = "objectId", before = true, resultType = long.class) @InsertProvider(type = STGeomertySqlBuilder.class, method = "buildInsertSql") void saveGeometryToTable(STGeometry object);
SelectKey注解主要进行插入数据前先查找下个OBJECTID值。其中上面涉及到一个TypeHandler,主要用户获取表默认所在的数据库用户名
package com.zifan.st_geometry.handler; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; public class DBOwnerHandler implements TypeHandler<String> { public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { // TODO Auto-generated method stub if (parameter == null) { parameter = ps.getConnection().getMetaData().getUserName(); } ps.setString(i, parameter); } public String getResult(ResultSet rs, String columnName) throws SQLException { // TODO Auto-generated method stub return null; } public String getResult(ResultSet rs, int columnIndex) throws SQLException { // TODO Auto-generated method stub return null; } public String getResult(CallableStatement cs, int columnIndex) throws SQLException { // TODO Auto-generated method stub return null; } }
先来建立一个STGeometry子类,这里有两个属性对应的是数据库的字段。
package com.zifan.st_geometry.model; public class SubGeometry extends STGeometry { private String ysdm; private String djth; public String getYsdm() { return ysdm; } public void setYsdm(String ysdm) { this.ysdm = ysdm; } public String getDjth() { return djth; } public void setDjth(String djth) { this.djth = djth; } }
测试方法
@Test public void testInsert() { String shortWkt = "POLYGON ((3 3, 4 6, 5 3, 3 3))"; SubGeometry czdj = new SubGeometry(); czdj.setDjth("长"); czdj.setYsdm("华"); czdj.setWkt(shorWkt); czdj.setSrId(2); czdj.setTableName("CZDJ2"); stGeometryMapper.saveGeometryToTable(czdj); Assert.assertEquals(6, czdj.getObjectId()); }
执行后存储的图形数据djth和ysdm两个属性是存在值的。
至此经过mybatis利用st_geometry就完成了对arcgis图形数据的叠加分析和存储。
以上涉及到的mybatis的使用能够查看其API,此外是经过spring-boot与mybatis结合进行的开发测试。有兴趣能够查看一下关于spring-boot的更多知识。
工程代码见码云经过spring-boot+mybatis+swagger构建。