Java解析图形mdb矢量mdb
背景:项目中需要解析图形mdb,同事积累下的代码无法读取复杂图形;终于在某位大佬的博客下发现新的
解析方法,特此整理记录下。
原理:jackcess(assess提供解析mdb属性)、esri-geometry-api(esri提供解析二进制图形数据)
Maven依赖
<dependency><groupId>com.healthmarketscience.jackcess</groupId><artifactId>jackcess</artifactId><version>4.0.5</version>
</dependency>
<dependency><groupId>com.esri.geometry</groupId><artifactId>esri-geometry-api</artifactId><version>1.2.1</version>
</dependency>
读取测试代码
public static void main(String[] args) {// 设置mdb文件路径String mdbFilePath = "C:\\XXX.mdb";File file = new File(mdbFilePath);MDBReaderUtils readerUtils = new MDBReaderUtils();MDBMsg mdbMsg = readerUtils.read(file, "DATA_TEMPLATE");// mdb中数据表名称String epsg = mdbMsg.getEpsg();List<Map<String, Object>> data = mdbMsg.getData();System.out.println("epsg : " + epsg); // 坐标系System.out.println("data : " + data.size()); // mdb数据for (Map<String, Object> map : data) {String objectid = MDBReaderUtils.getString(map.get("objectid")); // objectidString wkt = MDBReaderUtils.getString(map.get("wkt")); // mdb中图形wktSystem.out.println(objectid + " -> " + wkt);}
}
读取结果
MDBMsg
@Data
public class MDBMsg {private String epsg; // 坐标系private List<Map<String, Object>> data; // mdb数据
}
MDBReaderUtils
@Slf4j
public class MDBReaderUtils {private final static Map<String, String> ESRI_EPSG_MAPPING = new HashMap<>();static {ESRI_EPSG_MAPPING.put("GCS_China_Geodetic_Coordinate_System_2000", "4490");ESRI_EPSG_MAPPING.put("CGCS2000_3_Degree_GK_Zone_40", "4528");ESRI_EPSG_MAPPING.put("CGCS2000_3_Degree_GK_Zone_39", "4527");ESRI_EPSG_MAPPING.put("CGCS2000_3_Degree_GK_Zone_41", "4529");ESRI_EPSG_MAPPING.put("GCS_WGS_1984", "4326");}public MDBMsg read(MultipartFile multipartFile, String tableName) {File file = null;try {String originalFilename = multipartFile.getOriginalFilename();String[] filename = originalFilename.split("\\.");file = File.createTempFile(filename[0], filename[1] + ".");multipartFile.transferTo(file);file.deleteOnExit();} catch (IOException e) {e.printStackTrace();}return read(file, tableName);}public MDBMsg read(File file, String tableName) {MDBMsg mdbMsg = new MDBMsg();try (Database db = DatabaseBuilder.open(file)) {String epsg = getEpsg(db, tableName);mdbMsg.setEpsg(epsg);Map<String, Integer> tableFieldShapeTypeMap = getShapeFieldMap(db);// 打开表Table table = db.getTable(tableName);List<? extends Column> columns = table.getColumns();List<Map<String, Object>> data = new ArrayList<>();// 读取所有行for (Row row : table) {Map<String, Object> map = new HashMap<>();for (Column column : columns) {String name = column.getName();Object value = row.get(name);//DataType.OLE 类型代表几何类型if (value instanceof byte[] && DataType.OLE.toString().equals(column.getType().toString())) {try {// 如果是字节数组,尝试解析为几何对象byte[] shapeBytes = (byte[]) value;// 使用 Esri Geometry API 解析二进制数据ByteBuffer buffer = ByteBuffer.wrap(shapeBytes).order(java.nio.ByteOrder.LITTLE_ENDIAN);buffer.rewind(); // 确保从头开始读取// 使用 OperatorImportFromESRIShape 解析 Shape 数据OperatorImportFromESRIShape opImportFromESRIShape = OperatorImportFromESRIShape.local();Geometry.Type geometryTypeFromShapeType = getGeometryTypeFromShapeType(tableName, column.getName(), tableFieldShapeTypeMap);Geometry esriGeometry = opImportFromESRIShape.execute(0, geometryTypeFromShapeType ,buffer);// 将 Esri 几何对象转换为 OGC 几何对象OGCGeometry ogcGeometry = OGCGeometry.createFromEsriGeometry(esriGeometry, null);// 输出 WKT 格式的几何数据String wkt = ogcGeometry.asText();map.put("wkt", wkt);} catch (Exception e) {System.err.println("无法解析几何数据: " + e.getMessage());continue;}} else {map.put(name, value);}}data.add(map);}mdbMsg.setData(data);} catch (Exception e) {mdbMsg.setData(new ArrayList<>());System.err.println(e.getMessage());}return mdbMsg;}/*** 获取mdb某个矢量表的几何类型* @param tableName* @param fieldName* @param tableFieldShapeTypeMap* @return*/private Geometry.Type getGeometryTypeFromShapeType(String tableName, String fieldName, Map<String, Integer> tableFieldShapeTypeMap) {if (!tableFieldShapeTypeMap.containsKey(tableName + "." + fieldName)) {return null;}Integer type = tableFieldShapeTypeMap.get(tableName + "." + fieldName);//暂时只支持点、折线、面,也大致通过真实数据推断GDB_GeomColumns表中记录的几何类型if (type == 1) {return Geometry.Type.Point;}if (type == 3) {return Geometry.Type.Polyline;}if (type == 4) {return Geometry.Type.Polygon;}return null;}private Map<String, Integer> getShapeFieldMap(Database db) {try {// 获取 GDB_GeomColumns 表Table table = db.getTable("GDB_GeomColumns");// 创建一个映射,用于存储每个几何字段的几何类型Map<String, Integer> geometryTypeMap = new HashMap<>();// 读取 GDB_GeomColumns 表中的所有行for (Row row : table) {String tableName = row.get("TableName").toString();String fieldName = row.get("FieldName").toString();int shapeType = ((Number) row.get("ShapeType")).intValue();// 将几何字段和几何类型存储在映射中geometryTypeMap.put(tableName + "." + fieldName, shapeType);}return geometryTypeMap;} catch (Exception e) {log.error(e.getMessage());return new HashMap<>();}}private String getEpsg(Database db, String tName) {String epsg = "";try {// 获取 GDB_GeomColumns 表Table colTable = db.getTable("GDB_GeomColumns");int srid = -1;// 读取 GDB_GeomColumns 表中的所有行for (Row row : colTable) {String tableName = row.get("TableName").toString();if (tName.equals(tableName)) {srid = ((Number) row.get("SRID")).intValue();break;}}// 获取 GDB_SpatialRefs 表Table refTable = db.getTable("GDB_SpatialRefs");// 读取 GDB_SpatialRefs 表中的所有行for (Row row : refTable) {if (srid == ((Number) row.get("SRID")).intValue()) {epsg = row.get("SRTEXT").toString().split(",")[0];break;}}for (Map.Entry<String, String> entry : ESRI_EPSG_MAPPING.entrySet()) {if (epsg.contains(entry.getKey())) {epsg = entry.getValue();break;}}return epsg;} catch (Exception e) {log.error(e.getMessage());return epsg;}}public static String getString(Object o) {return Objects.isNull(o) ? null : o.toString();}public static Double getDouble(Object o) {Double v = null;try {v = Double.valueOf(getString(o));} catch (Exception var4) {;}return v;}public static Integer getInteger(Object o) {Integer v = null;try {v = Integer.valueOf(getString(o));} catch (Exception var4) {;}return v;}public static Long getLong(Object o) {Long v = null;try {v = Long.valueOf(getString(o));} catch (Exception var4) {;}return v;}public static BigDecimal getBigDecimal(Object o) {BigDecimal v = null;try {v = new BigDecimal(getString(o));} catch (Exception var4) {;}return v;}}
参考博文:https://blog.csdn.net/qq_41613913/article/details/142488569