使用Java将shapefile文件转SQL导入Oracle数据库的实现方法之一

前言

ShapeFile文件用于描述空间数据中的矢量数据。例如几何体对象:点,折线与多边形。以及同时存储几何形状与属性信息,这是Shapefile文件最基本的特征。

Shape File (以下简称shp文件)主要有三个主文件,及若干子文件组成的名称相同的文件。
1 . shpname.shp 用于保存元素的几何实体的,即主文件
2 . shpname.shx 图形索引格式 几何体位置索引,记录每一个几何体在shp文件之中的位置,能够加快向前或向后搜索一个几何体的效率
3 . shpname.dbf 属性数据格式,以dBase IV的数据表格式存储每个几何形状的属性数据

还有更多的如:
.prj— 投帧式,用于保存地理坐标系统与投影信息,是一个存储well-known text投影描述符的文本文件。
.sbnand.sbx— 几何体的空间索引
.fbnand.fbx— 只读的Shapefiles的几何体的空间索引
.ainand.aih— 列表中活动字段的属性索引。
.ixs— 可读写Shapefile文件的地理编码索引
.mxs— 可读写Shapefile文件的地理编码索引(ODB格式)
.dbf文件的属性索引,其文件名格式为shapefile.columnname.atx(ArcGIS 8及之后的版本).
shp.xml— 以XML格式保存元数据。
.cpg— 用于描述.dbf文件的代码页,指明其使用的字符编码。

了解更多请移步下方链接: 链接: SHAPEFILE.

在这里插入图片描述

问题分析

shp文件解析入库Oracle数据库的方式有很多种,例如1,后台Java使用GeoTools解析并入库 2,使用Oracle自带插件解析并入库

这里需要说明的是,两种方式我都有尝试,但是第二种方式并不尽如人意,因为oracle自带的解析shp文件的类年代久远,长时间没有更新,使用的人也并不多,所以使用与学习起来不太理想。

这里就采用Geotools解析shp文件入库的方式来作为此demo的示例。

使用Geotools解析shp文件并入库的方式有两种

1,是通过geotoos解析shp文件后将需要的数据转sql,然后插入到Oracle

2,是通过geotoos自带插件直接将shp文件写入Oracle,但是由于此方法并不是很好支持oracle直接写入,所以目前采用第一种。

关于geotools的使用介绍的详细内容,大家可以移步官网,后期我会出一些最想的教程,包括各种接口,类,方法的详细使用方法。

链接: lGeoTools.

在这里插入图片描述

事先准备,引入依赖:

此demo是采用Idea创建的maven QuickStart 项目

<!-- Geotools版本控制-->
   <properties>
        <java.version>1.8</java.version>
        <geotools.version>24-SNAPSHOT</geotools.version>
    </properties>
<!-- Geotools相关-->
    <repositories>
        <repository>
            <id>osgeo</id>
            <name>OSGeo Release Repository</name>
            <url>https://repo.osgeo.org/repository/release/</url>
            <snapshots><enabled>false</enabled></snapshots>
            <releases><enabled>true</enabled></releases>
        </repository>
        <repository>
            <id>osgeo-snapshot</id>
            <name>OSGeo Snapshot Repository</name>
            <url>https://repo.osgeo.org/repository/snapshot/</url>
            <snapshots><enabled>true</enabled></snapshots>
            <releases><enabled>false</enabled></releases>
        </repository>
    </repositories>
    
  <dependencies>
      
        <!--geotools-->
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-shapefile</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-swing</artifactId>
            <version>${geotools.version}</version>
        </dependency>
    </dependencies>

代码实现,(shp文件转sql):

具体插入数据库请查看我的下篇博文

Demo类

package com.lyf.oracle.shape;
import com.lyf.oracle.modo.Fields;
import com.lyf.oracle.untils.ShpUntils;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.locationtech.jts.geom.Geometry;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import java.io.File;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author Unen_
 * @Date 2020-06 10:25
 */

public class Demo{
/**注意以下类导包千万不要导错了,可以看看我上面的包*/

	//用于存储读取到的shp数据源
    private SimpleFeatureSource featureSource = null;
    //用于存储表明 因为表明多次用到
    private String tableName = "";
    //用于存取读取的shp文件属性信息
    private List<Fields> fields = new ArrayList<>();
   
   //读取shp文件,需要一个文件路径, 此方法执行完后,SimpleFeatureSource已获取数据源信息
    public void readShape(String shpfile){
        try {
            File file = new File(shpfile);
            ShapefileDataStore shpDataStore = null;
            shpDataStore = new ShapefileDataStore(file.toURL());
            //设置编码 防止中文属性乱码
            Charset charset = Charset.forName("GBK");
            shpDataStore.setCharset(charset);
            //这里getTypeNames()读取的是多个数据表的名称,默认第一个为表名
            tableName = shpDataStore.getTypeNames()[0];
            featureSource =  shpDataStore.getFeatureSource (tableName);
        }catch (Exception e){
            e.printStackTrace();
        }
    }


	//获取shp文件的属性信息
    public void getShpFields(){
    	//通过featureSource 获取具体的元素信息
        SimpleFeatureType schema = featureSource.getSchema();
        List<AttributeDescriptor> attrs= schema.getAttributeDescriptors();
        for(int i=0;i<attrs.size();i++){
            AttributeDescriptor attr = attrs.get(i);
            //获取属性类型 ,会返回各种类型
            Class<?> cls = attr.getType().getBinding();
            //获取属性最大长度 ,这里的ShpUntils.GetLength()是我定义的一个工具类,下方会贴出,用于创建表时字段长度限制
            String length = ShpUntils.GetLength(attr.getType().getRestrictions());
            //获取属性名称
            String clsName = cls.getName();
            //关怀这个方法的作用,你输出打印前后的结果就知道了
            clsName = clsName.substring(clsName.lastIndexOf(".")+1).toLowerCase();
            //利用构造函数,注入值,因为类型不同所以导致字段长度不同,所以要进行判断
            if (length==null||"".equals(length)){
                Fields field = new Fields(attr.getLocalName(), clsName,0);
                fields.add(field);
            }else{
                Fields field = new Fields(attr.getLocalName(), clsName,Integer.parseInt(length));
                fields.add(field);
            }

        }
    }

	//创建tablesql ,这里是如oracle库,语法结构与mysql数据库一样
    public String createTableSql(){
        StringBuffer sql = new StringBuffer();
        sql.append("CREATE TABLE "+tableName+" (");
        for(int i=0, size = fields.size();i<size;i++){
            Fields field = fields.get(i);
            //Oracle里面名称都是用大写
            String filedname = field.getFieldname().toUpperCase();
            String fieldtype = field.getFieldtype();
            Integer length=field.getMaxLength();
            String judgment = ShpUntils.typeJudgment(fieldtype);
            //进行字段长度拼接
            if (length>0){
                sql.append(filedname+" "+judgment+"("+length+")");
            }else {
                sql.append(filedname+" "+judgment);
            }
            //去除最后一个逗号
            if(i!=size-1) {
                sql.append(", ");
            }
        }
            String reuslt=sql.append(");").toString();
        return reuslt ;
    }

	// 插入sql
    public String  insertValueSql() {
        try {
            SimpleFeatureCollection result = featureSource.getFeatures();
            SimpleFeatureIterator itertor = result.features();
            StringBuffer sql = new StringBuffer();
            while (itertor.hasNext()){
                SimpleFeature feature = itertor.next();
                StringBuffer _sql = new StringBuffer();
                _sql.append("insert into "+tableName+" values(");
                for(int i=0, size = fields.size();i<size;i++){
                    Fields field = fields.get(i);
                    String filedname = field.getFieldname();
       				//这里根据字段名称判断类型 因为下划线不好识别,所以将the——geom替换一下
		          filedname = filedname=="the_geom"?"shapefile":filedname;
                    String fieldtype = field.getFieldtype();
                    
                    if(filedname!="shapefile"){
                        if(fieldtype.equals("string")){
                            _sql.append("'"+feature.getAttribute(filedname)+"'");
                        }else {
                            _sql.append(feature.getAttribute(filedname));
                        }
                    }else{
						//这里很关键,决定了sql能否插入数据库的主要原因,将wkt转几何对象,具体原因请自行百度,后面也会写博客做相关介绍!!!
                        Geometry geom = (Geometry)feature.getAttribute("the_geom");
                        _sql.append("sdo_geometry('"+geom.toString()+"', 4326)");
                    }
                    if(i!=size-1){
                        _sql.append(", ");
                    };
                }
                _sql.append(");\r\n");
                sql.append(_sql);
            }
           return sql.toString();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }


	
	//方法测试与调用
    public static void main(String[] args) {
        Demo s = new Demo();
        
        //读取
        s.readShape("C:/Users/Unen_/Desktop/GisWork/T_SHUIWEI.shp");
        //获取字段名称 类型 长度 
        s.getShpFields();
        //返回创建表sql
        String sql = s.createTableSql();
        
        System.out.println(sql);
          //返回插入表sql
        String sql1 = s.insertValueSql();
        
        System.out.println(sql1 );
    }


}

Demo类

package com.lyf.oracle.modo;

import java.io.Serializable;

/**
 * @Author Unen_
 * @Date 2020-08 10:34
 */
public class Fields  implements Serializable {



    /**
     * 字段名称
     */
    private String Fieldname = "";

    /**
    * 字段类型
    */

    private String Fieldtype = null;


    /**
     * 字段长度
     */
    private Integer  MaxLength = null;


    public Fields(String fieldname, String fieldtype ,Integer  maxLength ) {
        MaxLength = maxLength;
        Fieldname = fieldname;
        Fieldtype = fieldtype;
    }


    public String getFieldname() {
        return Fieldname;
    }

    public void setFieldname(String fieldmame) {
        Fieldname = fieldmame;
    }

    public String getFieldtype() {
        return Fieldtype;
    }

    public void setFieldtype(String fieldtype) {
        Fieldtype = fieldtype;
    }

    public Integer getMaxLength() {
        return MaxLength;
    }

    public void setMaxLength(Integer maxLength) {
        MaxLength = maxLength;
    }
}

ShpUntils 类

package com.lyf.oracle.untils
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @Author Unen_
 * @Date 2020-08 11:25
 */
public class ShpUntils {


    /**
     *传入 filer对象,解析返回长度字符串
     * @param o
     * @return
     */
    public  static  String GetLength(Object o){
        String string = o.toString();
        List<String> lis = Arrays.asList(string.split(""));
        String current="";
        for (int i = 0; i < lis.size(); i++) {
            String s = lis.get(i);
            boolean integer = isInteger(s);
            if (integer){
                current+=s;
            }
        }
        return current;
    }

    /**
     * 过滤1~9的数字
     * @param str
     * @return
     */
    public static boolean isInteger(String str) {
        String rgex="[0-9]*";
        Pattern pattern = Pattern.compile(rgex);
        return pattern.matcher(str).matches();
    }


    /** 功能描述: Java类型与数据库类型转换
     * @param
     * @return:
     * @Author: Unen_
     * @Date: 2020/6/4 15:04
     */

    public static String typeJudgment(String name){
        if (name.equals("point")||name.equals("multiPolygon")||name.equals("multiLineString")){
            return   "\"MDSYS\""+"."+"\"SDO_GEOMETRY\"" ;
        }else if(name.equals("integer")||name.equals("long")){
            return   "NUMBER" ;
        }else if(name.equals("double")){
            return   "FLOAT" ;
        }else if(name.equals("string")){
            return   "VARCHAR2" ;
        }else if(name.equals("date")){
            return   "TIMESTAMP" ;
        }

        return  null;
    }


}

结尾

其实因为着急实现功能,所以很多东西没写全,比如Oracle空间元数据的添加,空间索引的建立,没有做很好的封装,也有很多值得优化的空间,写这个博客只为记录自己当下解决问题的思路。

最后

关于最后入库的问题,我会在下篇博文种贴出,以及优化后的代码我也会贴出。886

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值