利用st_geometry進行圖形疊加分析--結合mybatis

在上一遍利用st_geometry進行圖形疊加分析文章的基礎上,結合mybatis操做st_geometry,主要簡單實現一下三個功能:利用st_geometry兩個表之間圖形表的疊加分析、WKT與圖形表的疊加分析、將WKT存儲至數據圖形表。html

兩個表之間圖形表的疊加分析

構造sql

兩個表之間圖形表的疊加分析,先來建立一個專門構造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

mapper接口類

接下來進行實際疊加分析操做寫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"
    }
]

WKT與圖形表的疊加分析

構造sql

一樣經過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處理CLOB類型的WKT

上面方法中涉及到一個自定義的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;
	}

}

mybatis的Mapper接口方法實現

@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

將WKT存儲至數據圖形表

建立圖形數據基礎類

這裏咱們先設計一個基礎類,全部圖形數據表都繼承它,類屬性有圖形表名字、空間參考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

構造sql

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語句。

mybatis的Mapper接口方法實現

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構建。

相關文章
相關標籤/搜索