Skip to content

#8.16shp与geojson互转

在线转换工具:https://mapshaper.org/

桌面工具idesktop

/*
     * 数据结构:
     *   FeatureCollection对象下:
     *   --   List<feature>
     *   --   --Feature :id,type,Properties,Geometry
     *   --   --    --Geometry : type ,coordinates
     *   --   --    --Properties : 自定义属性,
     * */
json

 * 数据结构:
 * {
 * 	"type": "FeatureCollection",
 * 	"features": [
 * 	   {
 * 		"geometry": {
 * 			"coordinates": [
 * 				[
 * 					[
 * 						[114.2563, 22.1603],
 * 						[114.2544, 22.1639],
 * 						[114.251, 22.1662],
 * 						[114.2478, 22.1702],
 * 						[114.2501, 22.1738],
 * 						[114.2639, 22.1834],
 * 						[114.2686, 22.1834],
 * 						[114.2714, 22.1725],
 * 						[114.275, 22.166],
 * 						[114.2754, 22.1639],
 * 						[114.2669, 22.1612],
 * 						[114.2563, 22.1603]
 * 					]
 * 				]
 * 			],
 * 			"type": "MultiPolygon"
 * 		},
 * 		"id": "map.923",
 * 		"type": "Feature",
 * 		"properties": {
 * 			"ADCODE99": 810000,
 * 			"AREA": 0.0,
 * 			"BOU2_4M_": 925,
 * 			"ADCODE93": 810000,
 * 			"BOU2_4M_ID": 3114,
 * 			"PERIMETER": 0.079,
 * 			"NAME": "香港特别行政区"
 * 		}
 * 	},
 * 	  {
 * 	  "geometry": {
 * 			"coordinates": [
 * 				[
 * 					[
 * 						[114.2989, 22.1781],
 * 						[114.3006, 22.1789],
 * 						[114.3021, 22.179],
 * 						[114.3024, 22.178],
 * 						[114.302, 22.1763],
 * 						[114.3009, 22.1755],
 * 						[114.2995, 22.1762],
 * 						[114.299, 22.1774],
 * 						[114.2989, 22.1781]
 * 					]
 * 				]
 * 			],
 * 			"type": "MultiPolygon"
 * 		},
 * 		"id": "map.924",
 * 		"type": "Feature",
 * 		"properties": {
 * 			"ADCODE99": 810000,
 * 			"AREA": 0.0,
 * 			"BOU2_4M_": 926,
 * 			"ADCODE93": 810000,
 * 			"BOU2_4M_ID": 3115,
 * 			"PERIMETER": 0.011,
 * 			"NAME": "香港特别行政区"
 * 		}
 * 	}]
 * }v

##一、项目

###1.pom依赖

xml
 <!--geotools,最新版不行21.2-->
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-geojson</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-shapefile</artifactId>
            <version>${geotools.version}</version>
        </dependency>

        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.28</version>
        </dependency>

###2.详细代码

####1.shp转geojson

java
public static String shpToGeojson(String infilePath,String outfilePath){
    return readshp(infilePath,outfilePath);
}

public static String shpToGeojson(String infilePath){
    return readshp(infilePath,null);
}

/**
     * 读取shp文件转为json字符串
     * @param infilePath
     * @param outfilePath
     * @return
     */
private static String readshp(String infilePath,String outfilePath){
    //最外面一层
    JSONObject geojson=new JSONObject();
    geojson.put("type","FeatureCollection");
    JSONArray array = new JSONArray();
    //featureJson专门转json,精确到小数15位,一定要注意
    FeatureJSON fjson = new FeatureJSON(new GeometryJSON(15));
    //1.得到SimpleFeatureCollection
    SimpleFeatureCollection featureCollection = getFeatureCollection(infilePath);
    //2.得到所有的features
    SimpleFeatureIterator features = featureCollection.features();
    //3.遍历每个features
    while (features.hasNext()){
        SimpleFeature feature = features.next();
        StringWriter writer = new StringWriter();
        try {
            //4.feature对象转json字符串
            fjson.writeFeature(feature, writer);
            String feartureStr=writer.toString();
            //5.json字符串转json对象
            JSONObject geojsonObject = JSON.parseObject(feartureStr);
            //6.套入fearture数组
            array.add(geojsonObject);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    geojson.put("features",array);
    features.close();
    //7.最终的json转字符串
    String geojsonStr = geojson.toJSONString();
    //8.可选 输出到文件
    if(StringUtils.isNotBlank(outfilePath)){
        writeFile(outfilePath,geojsonStr);
    }
    return geojsonStr;
}

/**
     * 读取shp文件第一步
     * @param path
     * @return
     */
private static SimpleFeatureSource readStoreByShp(String path) {
    //1.传入文件路径
    File file = new File(path);
    //2.根据文件的url获得FileDataStore对象
    FileDataStore store = null;
    try {
        //*******************可以获取url****************
        //            store  = FileDataStoreFinder.getDataStore(file);

        //            URL url = new URL("https://gitee.com/liuchenyun/JavaSe/tree/master/map/map.shp");
        //            URLConnection urlconn = url.openConnection(); // 试图连接并取得返回状态码
        //            urlconn.connect();
        store  = FileDataStoreFinder.getDataStore(file);
        //转码
        ((ShapefileDataStore) store).setCharset(Charset.forName("GBK"));
        //3.得到SimpleFeatureSource
        return store.getFeatureSource();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;

}

/**
     * 读取shp第一步第二种方式
     * @param path
     * @return
     */
private static SimpleFeatureSource readStoreByShp2(String path){
    //1.传入文件路径
    File file = new File(path);
    //2.根据文件的url得到ShapefileDataStore,这是FileDataStore子类实现
    ShapefileDataStore shpDataStore = null;
    try {
        shpDataStore = new ShapefileDataStore(file.toURL());
        shpDataStore.setCharset(Charset.forName("UTF-8"));
        String typeName = shpDataStore.getTypeNames()[0];
        //3.得到SimpleFeatureSource
        return shpDataStore.getFeatureSource(typeName);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

/**
     * 读取shp第二部
     * @param path
     * @return
     */
private static SimpleFeatureCollection getFeatureCollection(String path){
    try {
        //1.得到SimpleFeatureSource
        SimpleFeatureSource source = readStoreByShp(path);
        if(source==null){
            return null;
        }
        //2.返回SimpleFeatureCollection对象
        return source.getFeatures();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

2.geojson转shp

java
/**
     * geojson转shp,shx,dbf
     * @param geojson
     * @param shpPath
     * @throws IOException
     */
    public static void geojsonToShp(String geojson, String shpPath) {
        GeometryJSON gjson = new GeometryJSON();
        //1.创建shp输出文件
        File file = new File(shpPath);
        //2.得到ShapefileDataStore对象  一个空的store
        Map<String, Serializable> params = new HashMap<>();
        try {
            params.put(ShapefileDataStoreFactory.URLP.key, file.toURI().toURL());
            ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
            //3.定义图形信息和属性信息。。。
            SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
//        tb.setCRS(DefaultGeographicCRS.WGS84);
            tb.setName("shapefile");
            //feature的type
            Class<?> geoType = getFutrueType(geojson);
            tb.add("the_geom", geoType);
            //动态获取properties属性
            JSONObject json = JSON.parseObject(geojson);
            JSONArray features = (JSONArray) json.get("features");
            JSONObject featureStr1 = (JSONObject) features.get(0);
            JSONObject properties1 = (JSONObject)featureStr1.get("properties");
            Set<String> strings1 = properties1.keySet();
            for (String key : strings1) {
                //这有问题,固定死了string,如何获取value的类型?
                Object o = properties1.get(key);
                tb.add(key, String.class);
            }
            ds.createSchema(tb.buildFeatureType());
            ds.setCharset(Charset.forName("UTF-8"));
            //4.从空仓库里得到FeatureWriter对像
            FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
            for(int i=0,len=features.size();i<len;i++){
                JSONObject featureStr = (JSONObject) features.get(i);
                JSONObject properties = (JSONObject)featureStr.get("properties");
                Set<String> strings = properties.keySet();
                //空的feature
                SimpleFeature feature = writer.next();
                //得到每个feature,并读取
                String strFeature = features.get(i).toString();
                Reader reader = new StringReader(strFeature);
                //设置属性,从geojson中取出properties对象的值
                feature.setAttribute("the_geom",gjson.readMultiPolygon(reader));
                for (String key : strings) {
                    feature.setAttribute(key,properties.get(key).toString());
                }
                //往仓库里输出feature
                writer.write();
            }

            writer.close();
            ds.dispose();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据geojson字符串中的feature中的type
     * @param geojson
     * @return
     */
    public static Class<?> getFutrueType(String geojson){
        //每个feature的type都是一样的
        JSONObject json = JSON.parseObject(geojson);
        JSONArray features = (JSONArray) json.get("features");
        JSONObject feature0 = JSON.parseObject(features.get(0).toString());
        String strType = ((JSONObject)feature0.get("geometry")).getString("type").toString();

        Class<?> geoType = null;
        switch(strType){
            case "Point":
                geoType = Point.class;
            case "MultiPoint":
                geoType = MultiPoint.class;
            case "LineString":
                geoType = LineString.class;
            case "MultiLineString":
                geoType = MultiLineString.class;
            case "Polygon":
                geoType = Polygon.class;
            case "MultiPolygon":
                geoType = MultiPolygon.class;
        }

        return geoType;
    }

3.输出文件

 /**
     * 输出到文件
     * @param filePath
     * @param geojsonStr
     */
    private static void writeFile(String filePath,String geojsonStr){
        OutputStreamWriter outputStreamWriter = null;
        try {
            File outputfile=new File(filePath);
            FileOutputStream fileOutputStream=new FileOutputStream(outputfile);
            outputStreamWriter=new OutputStreamWriter(fileOutputStream,"utf-8");
            outputStreamWriter.write(geojsonStr);
            outputStreamWriter.flush();
            outputStreamWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

二、总结

1.问题

1.shp转geojson

type:是固定的

2.geojson转shp

dbf文件变大

三、精确代码

java
package cn.lcy.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.vividsolutions.jts.geom.*;
import org.apache.commons.lang3.StringUtils;
import org.geotools.data.FeatureWriter;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import java.io.*;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * @author 刘琛运
 * @date 2019/8/15 14:17
 *
 */
public class GeoTools2 {


    public static String shpToGeojson(String infilePath,String outfilePath){
        return readshp(infilePath,outfilePath);
    }

    public static String shpToGeojson(String infilePath){
        return readshp(infilePath,null);
    }

    /**
     * 读取shp文件转为json字符串
     * @param infilePath
     * @param outfilePath
     * @return
     */
    private static String readshp(String infilePath,String outfilePath){
        //最外面一层
        JSONObject geojson=new JSONObject();
        geojson.put("type","FeatureCollection");
        JSONArray array = new JSONArray();
        //featureJson专门转json,精确到小数15位,一定要注意
        FeatureJSON fjson = new FeatureJSON(new GeometryJSON(15));
        //1.得到SimpleFeatureCollection
        SimpleFeatureCollection featureCollection = getFeatureCollection(infilePath);
        //2.得到所有的features
        SimpleFeatureIterator features = featureCollection.features();
        //3.遍历每个features
        while (features.hasNext()){
            SimpleFeature feature = features.next();
            StringWriter writer = new StringWriter();
            try {
                //4.feature对象转json字符串
                fjson.writeFeature(feature, writer);
                String feartureStr=writer.toString();
                //5.json字符串转json对象
                JSONObject geojsonObject = JSON.parseObject(feartureStr);
                //6.套入fearture数组
                array.add(geojsonObject);

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        geojson.put("features",array);
        features.close();
        //7.最终的json转字符串
        String geojsonStr = geojson.toJSONString();
        //8.可选 输出到文件
        if(StringUtils.isNotBlank(outfilePath)){
            writeFile(outfilePath,geojsonStr);
        }
        return geojsonStr;
    }

    /**
     * 读取shp文件第一步
     * @param path
     * @return
     */
    private static SimpleFeatureSource readStoreByShp(String path) {
        //1.传入文件路径
        File file = new File(path);
        //2.根据文件的url获得FileDataStore对象
        FileDataStore store = null;
        try {
            //*******************可以获取url****************
//            store  = FileDataStoreFinder.getDataStore(file);

//            URL url = new URL("https://gitee.com/liuchenyun/JavaSe/tree/master/map/map.shp");
//            URLConnection urlconn = url.openConnection(); // 试图连接并取得返回状态码
//            urlconn.connect();
            store  = FileDataStoreFinder.getDataStore(file);
            //转码
            ((ShapefileDataStore) store).setCharset(Charset.forName("GBK"));
            //3.得到SimpleFeatureSource
            return store.getFeatureSource();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;

    }

    /**
     * 读取shp第一步第二种方式
     * @param path
     * @return
     */
    private static SimpleFeatureSource readStoreByShp2(String path){
        //1.传入文件路径
        File file = new File(path);
        //2.根据文件的url得到ShapefileDataStore,这是FileDataStore子类实现
        ShapefileDataStore shpDataStore = null;
        try {
            shpDataStore = new ShapefileDataStore(file.toURL());
            shpDataStore.setCharset(Charset.forName("UTF-8"));
            String typeName = shpDataStore.getTypeNames()[0];
            //3.得到SimpleFeatureSource
            return shpDataStore.getFeatureSource(typeName);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 读取shp第二部
     * @param path
     * @return
     */
    private static SimpleFeatureCollection getFeatureCollection(String path){
        try {
            //1.得到SimpleFeatureSource
            SimpleFeatureSource source = readStoreByShp(path);
            if(source==null){
                return null;
            }
            //2.返回SimpleFeatureCollection对象
            return source.getFeatures();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * geojson转shp,shx,dbf
     * @param geojson
     * @param shpPath
     * @throws IOException
     */
    public static void geojsonToShp(String geojson, String shpPath) {
        GeometryJSON gjson = new GeometryJSON();
        //1.创建shp输出文件
        File file = new File(shpPath);
        //2.得到ShapefileDataStore对象  一个空的store
        Map<String, Serializable> params = new HashMap<>();
        try {
            params.put(ShapefileDataStoreFactory.URLP.key, file.toURI().toURL());
            ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
            //3.定义图形信息和属性信息。。。
            SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
            tb.setCRS(DefaultGeographicCRS.WGS84);
            tb.setName("shapefile");
            //feature的type
            Class<?> geoType = getFutrueType(geojson);
            tb.add("the_geom", geoType);
            //动态获取properties属性
            JSONObject json = JSON.parseObject(geojson);
            JSONArray features = (JSONArray) json.get("features");
            JSONObject featureStr1 = (JSONObject) features.get(0);
            JSONObject properties1 = (JSONObject)featureStr1.get("properties");
            Set<String> strings1 = properties1.keySet();
            for (String key : strings1) {
                //需要先给属性设置类型
                Object value = properties1.get(key);
                Class<?> type = getType(value);
                tb.add(key, type);
            }
            ds.createSchema(tb.buildFeatureType());
            ds.setCharset(Charset.forName("GBK"));
            //4.从空仓库里得到FeatureWriter对像
            FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
            for(int i=0,len=features.size();i<len;i++){
                JSONObject featureStr = (JSONObject) features.get(i);
                JSONObject properties = (JSONObject)featureStr.get("properties");
                Set<String> strings = properties.keySet();
                //空的feature
                SimpleFeature feature = writer.next();
                //得到每个feature,并读取
                String strFeature = features.get(i).toString();
                Reader reader = new StringReader(strFeature);
                //设置属性,从geojson中取出properties对象的值
                feature.setAttribute("the_geom",gjson.readMultiPolygon(reader));
                for (String key : strings) {
                    feature.setAttribute(key,properties.get(key).toString());
                }
                //往仓库里输出feature
                writer.write();
            }

            writer.close();
            ds.dispose();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据geojson字符串中的feature中的type
     * @param geojson
     * @return
     */
    private static Class<?> getFutrueType(String geojson){
        //每个feature的type都是一样的
        JSONObject json = JSON.parseObject(geojson);
        JSONArray features = (JSONArray) json.get("features");
        JSONObject feature0 = JSON.parseObject(features.get(0).toString());
        String strType = ((JSONObject)feature0.get("geometry")).getString("type").toString();

        Class<?> geoType = null;
        switch(strType){
            case "Point":
                geoType = Point.class;
            case "MultiPoint":
                geoType = MultiPoint.class;
            case "LineString":
                geoType = LineString.class;
            case "MultiLineString":
                geoType = MultiLineString.class;
            case "Polygon":
                geoType = Polygon.class;
            case "MultiPolygon":
                geoType = MultiPolygon.class;
        }

        return geoType;
    }

    /**
     * 判断类型
     * @param param
     * @return
     */
    private static Class<?> getType(Object param){
        Class<?> geoType = null;
        if (param instanceof String) {
            //可能是个字符串的数值
            String params = (String)param;
            if(Pattern.compile("^[-\\+]?[\\d]*$").matcher(params).matches()){
                return Integer.class;
            }
            //可能是个字符串的数值
            if(Pattern.compile("^[+-]?[0-9.]+$").matcher(params).find()){
                return Double.class;
            }
            return String.class;
        }else if (param instanceof Integer) {
            return Integer.class;
        } else if (param instanceof Double) {
            return Double.class;
        }else if(param instanceof BigDecimal){
            return Integer.class;
        }
        else {
            return String.class;
        }

    }

    /**
     * 输出到文件
     * @param filePath
     * @param geojsonStr
     */
    private static void writeFile(String filePath,String geojsonStr){
        OutputStreamWriter outputStreamWriter = null;
        try {
            File outputfile=new File(filePath);
            FileOutputStream fileOutputStream=new FileOutputStream(outputfile);
            outputStreamWriter=new OutputStreamWriter(fileOutputStream,"utf-8");
            outputStreamWriter.write(geojsonStr);
            outputStreamWriter.flush();
            outputStreamWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        String in = "D:\\map\\map.shp";
        String out = "D:\\map\\map.json";

//        String in = "D:\\map\\map\\map.shp";
//        String out = "D:\\map\\map\\map.json";

//        String in = "D:\\vector\\北京.shp";
//        String out = "D:\\vector\\北京.json";
        String geojson = shpToGeojson(in,out);


        String s = "D:\\map\\map\\map.shp";
        geojsonToShp(geojson,s);
//        System.out.println(geojson);
    }

    /*
     * 数据结构:
     *   FeatureCollection对象下:
     *   --   List<feature>
     *   --   --Feature :id,type,Properties,Geometry
     *   --   --    --Geometry : type ,coordinates
     *   --   --    --Properties : 自定义属性,
     * */
}