本文簡(jiǎn)要介紹如何使用 Spring JDBC 進(jìn)行基本的空間查詢(xún)狐援。
數(shù)據(jù)的準(zhǔn)備
??將空間數(shù)據(jù)存入 Oracle Spatial 的方法有很多種,最基本的一種方法就是直接用 SQL 語(yǔ)句插入數(shù)據(jù)瘩将,但這種方法效率太低,而且極易出錯(cuò)现诀。我個(gè)人較為喜歡也最常使用的一種方法是借助現(xiàn)成的 GIS 軟件導(dǎo)入數(shù)據(jù)阶牍。下面簡(jiǎn)要介紹如何使用 ArcCatalog 將矢量數(shù)據(jù)導(dǎo)入 Oracle Spatial。
連接數(shù)據(jù)庫(kù)
-
在 ArcCatalog 的目錄樹(shù)中偏灿,找到數(shù)據(jù)庫(kù)連接丹诀,展開(kāi)后有一個(gè)添加數(shù)據(jù)庫(kù)連接,雙擊之后就會(huì)打開(kāi)如下的窗口:
數(shù)據(jù)庫(kù)連接窗口 - 按照?qǐng)D中的示范填寫(xiě)相關(guān)屬性菩混,實(shí)例這一項(xiàng)的格式是
主機(jī):端口/數(shù)據(jù)庫(kù)實(shí)例名
忿墅。點(diǎn)擊確定,然后就會(huì)連接到 Oracle沮峡。注意,ArcCatalog 只能連接32位的 Oracle 客戶(hù)端亿柑,我安裝的是32位的 Oracle 11g 客戶(hù)端邢疙。
導(dǎo)入數(shù)據(jù)
-
成功連接到 Oracle 之后在數(shù)據(jù)庫(kù)連接下就會(huì)看到一個(gè)新建的連接,右鍵,導(dǎo)入→要素類(lèi)(單個(gè))疟游,打開(kāi)如下的窗口呼畸。
導(dǎo)入要素窗口 - 介紹幾個(gè)關(guān)鍵字段的含義:
- 輸入要素:就是要導(dǎo)入的矢量數(shù)據(jù),這里選擇的是 .shp 文件(示例數(shù)據(jù)將會(huì)在文末給出)颁虐。注意文件名中不能包含中文蛮原。
- 輸出要素類(lèi):數(shù)據(jù)將會(huì)導(dǎo)入到這個(gè)字段指定的表中。
- 配置關(guān)鍵字:選擇 SDO_GEOMETRY另绩,這是 Oracle Spatial 提供的空間數(shù)據(jù)類(lèi)型儒陨。
- 點(diǎn)擊確定,右鍵連接笋籽,選擇刷新蹦漠,導(dǎo)入成功的話(huà)就會(huì)看到一個(gè)新生成的表,表名就是剛才在輸出要素類(lèi)中給的值车海。
用 Java API 進(jìn)行基本的空間查詢(xún)
實(shí)現(xiàn) Domain 類(lèi)笛园,封裝數(shù)據(jù)
??前面已經(jīng)提過(guò),Oracle Spatial 用 SDO_GEOMETRY 類(lèi)型來(lái)表示空間數(shù)據(jù),Java API 中對(duì)應(yīng)的類(lèi)是 oracle.spatial.geometry.JGeometry窜醉。根據(jù)表中的字段清钥,設(shè)計(jì)如下的 JavaBean 用來(lái)封裝數(shù)據(jù):
// 封裝鐵路信息的類(lèi)
public class RailWay {
private int objectId;
private JGeometry shape;
private double fNode;
private double tNode;
private double lPoly;
private double rPoly;
private int gbCode;
private String name;
private String pinYin;
private double length_m;
public int getObjectId() {
return objectId;
}
public void setObjectId(int objectId) {
this.objectId = objectId;
}
public JGeometry getShape() {
return shape;
}
public void setShape(JGeometry shape) {
this.shape = shape;
}
public double getfNode() {
return fNode;
}
public void setfNode(double fNode) {
this.fNode = fNode;
}
public double gettNode() {
return tNode;
}
public void settNode(double tNode) {
this.tNode = tNode;
}
public double getlPoly() {
return lPoly;
}
public void setlPoly(double lPoly) {
this.lPoly = lPoly;
}
public double getrPoly() {
return rPoly;
}
public void setrPoly(double rPoly) {
this.rPoly = rPoly;
}
public int getGbCode() {
return gbCode;
}
public void setGbCode(int gbCode) {
this.gbCode = gbCode;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPinYin() {
return pinYin;
}
public void setPinYin(String pinYin) {
this.pinYin = pinYin;
}
public double getLength_m() {
return length_m;
}
public void setLength_m(double length_m) {
this.length_m = length_m;
}
@Override
public String toString() {
return this.name + ",編號(hào)" + this.gbCode + ",長(zhǎng)度為" + this.length_m + "m";
}
}
實(shí)現(xiàn) DAO 類(lèi),提供 CRUD 接口
??這里只舉例如何進(jìn)行查詢(xún)蚜印。
// DAO 類(lèi),提供 CRUD 接口
public class RailWayDao {
private static NamedParameterJdbcTemplate namedTempl;
// 建立數(shù)據(jù)連接
static {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:@localhost:1521:orcl");
dataSource.setUsername("");
dataSource.setPassword("");
namedTempl = new NamedParameterJdbcTemplate(dataSource);
}
// 查詢(xún)指定名字的鐵路留量,返回結(jié)果只有一個(gè)
public RailWay getRailWay(String name) {
String sql = "select * from railwayorcl where name = :name";
Map<String,String> param = new HashMap<>();
param.put("name", name);
// 需要自己實(shí)現(xiàn) RowMapper
return this.namedTempl.queryForObject(sql, param, (rs,rowNum) -> {
RailWay r = new RailWay();
r.setObjectId(rs.getInt("objectId"));
r.setShape(JGeometry.load((STRUCT)rs.getObject("shape")));
r.setfNode(rs.getDouble("fNode_"));
r.settNode(rs.getDouble("tNode_"));
r.setlPoly(rs.getDouble("lPoly_"));
r.setrPoly(rs.getDouble("rPoly_"));
r.setGbCode(rs.getInt("gbCode"));
r.setName(rs.getString("name"));
r.setPinYin(rs.getString("pinYin"));
r.setLength_m(rs.getDouble("length_m"));
return r;
});
}
//查詢(xún)指定名字的鐵路窄赋,查詢(xún)結(jié)果不止一個(gè)
public List<RailWay> getRailWays(String name) {
String sql = "select * from railwayorcl where name = :name";
Map<String,String> param = new HashMap<>();
param.put("name", name);
//需要自己實(shí)現(xiàn) RowMapper
return this.namedTempl.query(sql, param, (rs,rowNum) -> {
RailWay r = new RailWay();
r.setObjectId(rs.getInt("objectId"));
r.setShape(JGeometry.load((STRUCT)rs.getObject("shape")));
r.setfNode(rs.getDouble("fNode_"));
r.settNode(rs.getDouble("tNode_"));
r.setlPoly(rs.getDouble("lPoly_"));
r.setrPoly(rs.getDouble("rPoly_"));
r.setGbCode(rs.getInt("gbCode"));
r.setName(rs.getString("name"));
r.setPinYin(rs.getString("pinYin"));
r.setLength_m(rs.getDouble("length_m"));
return r;
});
}
// 查詢(xún)指定名字的鐵路的結(jié)點(diǎn)坐標(biāo)
public double[] getCoords(String name) {
double[] coords = new double[0];
RailWay r = getRailWay(name);
coords = r.getShape().getOrdinatesArray();
return coords;
}
}
??需要注意的是,從數(shù)據(jù)庫(kù)查詢(xún)到的空間數(shù)據(jù)是 oracle.sql.STRUCT 類(lèi)型的楼熄,而在前面設(shè)計(jì)的 RailWay 類(lèi)中忆绰,空間數(shù)據(jù)是 JGeometry 類(lèi)型的,所以這里需要手動(dòng)進(jìn)行轉(zhuǎn)換可岂。因此错敢,必須自己實(shí)現(xiàn)一個(gè) RowMapper :
public RailWay getRailWay(String name) {
String sql = "select * from railwayorcl where name = :name";
Map<String,String> param = new HashMap<>();
param.put("name", name);
// RowMapper 接口只有一個(gè) mapRow 方法,所以使用了 lambda 表達(dá)式
return this.namedTempl.queryForObject(sql, param, (rs,rowNum) -> {
RailWay r = new RailWay();
r.setObjectId(rs.getInt("objectId"));
//將 STRUCT 轉(zhuǎn)換成 JGeometry
r.setShape(JGeometry.load((STRUCT)rs.getObject("shape")));
r.setfNode(rs.getDouble("fNode_"));
r.settNode(rs.getDouble("tNode_"));
r.setlPoly(rs.getDouble("lPoly_"));
r.setrPoly(rs.getDouble("rPoly_"));
r.setGbCode(rs.getInt("gbCode"));
r.setName(rs.getString("name"));
r.setPinYin(rs.getString("pinYin"));
r.setLength_m(rs.getDouble("length_m"));
return r;
});
}
示例數(shù)據(jù) 密碼:9b1u
Oracle Spatial Java API 的各種 jar 包在 %ORACLE_HOME%\md\jlib 目錄下缕粹。