说点废话:越来越觉得自己渺小,以前只在前端用些turf做过简单的空间分析了解ogc,后来慢慢接触到geotools,再后来发现geotools也有不顶用的时候,直到又发现了gdal,感觉打开了新世界的大门。
GDAL开源读取arcgis数据(shape,ged,mdb等)的方案,由C++编写,Java可以调用
1.下载GDAL
//下载地址,不会翻墙的话下载很慢 https://www.gisinternals.com/ //懒得下可以用我下好的 链接: https://pan.baidu.com/s/1sjLHrxBKpubO6Uwfvkj6qw 提取码: uijm 复制这段内容后打开百度网盘手机App,操作更方便哦
2.下载下来获取到文件并解压,并配置java调用环境变量
让java能调用dll文件
将解压目录下bin目录下的dll文件全部复制到java安装路径的bin目录下:C:\Program Files\Java\jdk1.8.0_171\bin
并将bin/gdal/java下的dll调用文件同样复制到jdk环境下C:\Program Files\Java\jdk1.8.0_171\bin
配置环境变量
3.maven配置调用的jar
新建lib目录并将\bin\gdal\java\gdal.jar放到里面
配置jar地址
<dependency> <groupId>org.gdal</groupId> <artifactId>gdal</artifactId> <version>1.0</version> <scope>system</scope> <systemPath>${project.basedir}/lib/gdal.jar</systemPath> </dependency>
spring boot配置引入外部jar包打包(请注意我这里的spring boot是打包成war)
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <webResources> <resource> <directory>lib</directory> <targetPath>WEB-INF/lib/</targetPath> <includes> <include>**/gdal.jar</include> </includes> </resource> </webResources> </configuration> </plugin>
至此我们的环境设置已经完成了。
package com.ruoyi; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Console; import cn.hutool.core.util.ReUtil; import cn.hutool.json.JSONUtil; import cn.hutool.poi.excel.ExcelWriter; import com.ruoyi.common.utils.JdbcUtils; import com.ruoyi.common.utils.UnitConverionUtils; import com.ruoyi.project.zrzy.domain.CityCode; import com.ruoyi.project.zrzy.service.IVitUplodFileService; import org.gdal.gdal.gdal; import org.gdal.ogr.*; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.junit4.SpringRunner; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.sql.SQLException; import java.sql.Time; import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @Auther: jhwang * @Date: 2021/4/27 09:23 * @Description: */ @RunWith(SpringRunner.class) //这两个注解是为了让测试类能拥有同等的spring boot上下文环境 @SpringBootTest public class GDBread2 { static { gdal.AllRegister();//设置gdal环境 } // /** // * 从GDB中读取行政区划数据并返回 // * 读不出来,连表查询有问题 // * @return // */ // public void selectGDBCity(String year){ // JdbcTemplate xzqh = JdbcUtils.getJdbcTemplate("xzqh"); // List<CityCode> query = xzqh.query(getCitySql(year), // (rs, rowNum) -> { // CityCode cityCode = new CityCode(); // cityCode.setPac(rs.getString("pac")); // return cityCode; // } // ); // Console.log(); // File[] ls = FileUtil.ls(cityFileFolder); // Map map = new HashMap<>(); // Driver driver = ogr.GetDriverByName("OpenFileGDB"); //设置驱动 // for (int i = 0; i < ls.length; i++) { // String filePath = ls[i].getPath(); // String year = ReUtil.get("\\d+", ls[i].getName(), 0); // List<CityCode> list = new ArrayList<>(); // DataSource dataSource = driver.Open(filePath, 0); // Layer querylayer = dataSource.ExecuteSQL("select DISTINCT f.pac as pac ,f.SHAPE_Area as area ,m.name as name ,m.gb as gb,m.level from (select t.pac,sum(t.SHAPE_Area) as SHAPE_Area from (select name,gb,pac,SHAPE_Area from v_boua2 UNION select name,gb,pac,SHAPE_Area from v_boua4 UNION select name,gb,pac,SHAPE_Area from v_boua5 UNION select name,gb,pac,SHAPE_Area from v_boua6 order by gb) t group by t.pac) f left join (select name,gb,pac,SHAPE_Area,'0' as level from v_boua2 UNION select name,gb,pac,SHAPE_Area,'1' as level from v_boua4 UNION select name,gb,pac,SHAPE_Area,'2' as level from v_boua5 UNION select name,gb,pac,SHAPE_Area,'3' as level from v_boua6 ) m on m.pac = f.pac order by f.pac"); // // //测试是否支持统计查询(测试完全支持统计查询) // //Layer querylayer = dataSource.ExecuteSQL("select sum(SHAPE_Area) as s from v_boua5"); // //好像是不支持关联查询,有点狗了 // // do {//获取图层下的要素 // Feature feature = querylayer.GetNextFeature(); // if (null == feature) {break;} // CityCode cityCode = new CityCode(); // cityCode.setPac(feature.GetFieldAsString("pac")); // cityCode.setArea(new BigDecimal(feature.GetFieldAsString("SHAPE_Area"))); // cityCode.setGb(feature.GetFieldAsString("gb")); // cityCode.setName(feature.GetFieldAsString("name")); // list.add(cityCode); // } while (true); // map.put(year,list); // } // Console.log(map); // } private static Object getProperty(Feature feature, int index) { int type = feature.GetFieldType(index); GDBread2.PropertyGetter propertyGetter; if (type < 0 || type >= propertyGetters.length) { propertyGetter = stringPropertyGetter; } else { propertyGetter = propertyGetters[type]; } try { return propertyGetter.get(feature, index); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 属性获取器 */ @FunctionalInterface private interface PropertyGetter { Object get(Feature feature, int index); } private static final GDBread2.PropertyGetter stringPropertyGetter = (feature, index) -> feature.GetFieldAsString(index); /** * feature.GetFieldType(index)得到一个属性类型的int值,该值对应具体类型 */ private static final GDBread2.PropertyGetter[] propertyGetters = new GDBread2.PropertyGetter[]{ (feature, index) -> feature.GetFieldAsInteger(index),//0 Integer (feature, index) -> feature.GetFieldAsIntegerList(index),//1 IntegerList (feature, index) -> feature.GetFieldAsDouble(index),//2 Real (feature, index) -> feature.GetFieldAsDoubleList(index),//3 RealList stringPropertyGetter,//4 String (feature, index) -> feature.GetFieldAsStringList(index),//5 StringList stringPropertyGetter,//6 (unknown) stringPropertyGetter,//7 (unknown) (feature, index) -> feature.GetFieldAsBinary(index),//8 Binary (feature, index) -> { int[] pnYear = new int[1]; int[] pnMonth = new int[1]; int[] pnDay = new int[1]; int[] pnHour = new int[1]; int[] pnMinute = new int[1]; float[] pfSecond = new float[1]; int[] pnTZFlag = new int[1]; feature.GetFieldAsDateTime(index, pnYear, pnMonth, pnDay, pnHour, pnMinute, pfSecond, pnTZFlag); java.sql.Date date = java.sql.Date.valueOf(LocalDate.of(pnYear[0], pnMonth[0], pnDay[0])); return date; },//9 Date (feature, index) -> { int[] pnYear = new int[1]; int[] pnMonth = new int[1]; int[] pnDay = new int[1]; int[] pnHour = new int[1]; int[] pnMinute = new int[1]; float[] pfSecond = new float[1]; int[] pnTZFlag = new int[1]; feature.GetFieldAsDateTime(index, pnYear, pnMonth, pnDay, pnHour, pnMinute, pfSecond, pnTZFlag); float fSecond = pfSecond[0]; int s = (int) fSecond; int ns = (int) (1000000000 * fSecond - s); Time time = Time.valueOf(LocalTime.of(pnHour[0], pnMinute[0], s, ns)); return time; },// 10 Time (feature, index) -> { int[] pnYear = new int[1]; int[] pnMonth = new int[1]; int[] pnDay = new int[1]; int[] pnHour = new int[1]; int[] pnMinute = new int[1]; float[] pfSecond = new float[1]; int[] pnTZFlag = new int[1]; feature.GetFieldAsDateTime(index, pnYear, pnMonth, pnDay, pnHour, pnMinute, pfSecond, pnTZFlag); float fSecond = pfSecond[0]; int s = (int) fSecond; int ns = (int) (1000000000 * fSecond - s); LocalDateTime localDateTime = LocalDateTime.of( LocalDate.of(pnYear[0], pnMonth[0], pnDay[0]), LocalTime.of(pnHour[0], pnMinute[0], s, ns) ); Timestamp timestamp = Timestamp.valueOf(localDateTime); return timestamp; },//11 DateTime (feature, index) -> feature.GetFieldAsInteger64(index),//12 Integer64 (feature, index) -> feature.GetFieldAsIntegerList(index),//13 Integer64List //>=14 (unknown) }; /** * 不存在则级联创建文件 * @param path */ private static void CreateFile(String path){ File testFile = new File(path); String parent = testFile.getParent(); if(!new File(parent).exists()){ new File(parent).mkdirs(); } if (!testFile.exists()) { try { testFile.createNewFile();// 能创建多级目录 } catch (IOException e) { e.printStackTrace(); } } } }