|
|
@@ -1,25 +1,54 @@
|
|
|
package com.siwei.apply.service.impl;
|
|
|
|
|
|
import com.siwei.apply.domain.Converge;
|
|
|
+import com.siwei.apply.domain.res.ConvergeRes;
|
|
|
import com.siwei.apply.domain.vo.ConvergeFilterVo;
|
|
|
import com.siwei.apply.domain.vo.ConvergeUpdateVo;
|
|
|
+import com.siwei.apply.enums.ConvergeTableEnum;
|
|
|
+import com.siwei.apply.mapper.CadastreFileMapper;
|
|
|
import com.siwei.apply.mapper.ConvergeMapper;
|
|
|
import com.siwei.apply.service.ConvergeService;
|
|
|
import com.siwei.apply.service.cadastre.impl.FzssFxrwrzHandleService;
|
|
|
import com.siwei.apply.utils.ServiceFileUtil;
|
|
|
+import com.siwei.common.core.exception.ServiceException;
|
|
|
import com.siwei.common.core.utils.uuid.IdUtils;
|
|
|
+import com.vividsolutions.jts.geom.Geometry;
|
|
|
+import com.vividsolutions.jts.geom.MultiPolygon;
|
|
|
+import com.vividsolutions.jts.geom.Polygon;
|
|
|
+import com.vividsolutions.jts.io.ParseException;
|
|
|
+import com.vividsolutions.jts.io.WKBReader;
|
|
|
+import com.vividsolutions.jts.io.WKTReader;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.collections4.CollectionUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.geotools.data.DefaultTransaction;
|
|
|
+import org.geotools.data.Transaction;
|
|
|
+import org.geotools.data.collection.ListFeatureCollection;
|
|
|
+import org.geotools.data.shapefile.ShapefileDataStore;
|
|
|
+import org.geotools.data.shapefile.ShapefileDataStoreFactory;
|
|
|
+import org.geotools.data.simple.SimpleFeatureCollection;
|
|
|
+import org.geotools.data.simple.SimpleFeatureSource;
|
|
|
+import org.geotools.data.simple.SimpleFeatureStore;
|
|
|
+import org.geotools.feature.simple.SimpleFeatureBuilder;
|
|
|
+import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
|
|
|
+import org.geotools.referencing.CRS;
|
|
|
+
|
|
|
+import org.opengis.feature.simple.SimpleFeature;
|
|
|
+import org.opengis.feature.simple.SimpleFeatureType;
|
|
|
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
import java.io.File;
|
|
|
import java.io.FileInputStream;
|
|
|
-import java.util.Arrays;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
+import java.io.PrintWriter;
|
|
|
+import java.io.Serializable;
|
|
|
+import java.nio.charset.Charset;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* 汇交服务实现
|
|
|
@@ -28,6 +57,10 @@ import java.util.Map;
|
|
|
@Service
|
|
|
public class ConvergeServiceImpl implements ConvergeService {
|
|
|
|
|
|
+ ///home/siwei/uploadPath/converge/
|
|
|
+ @Value("${converge_dir}")
|
|
|
+ private String convergedir;
|
|
|
+
|
|
|
@Autowired
|
|
|
private ConvergeMapper convergeMapper;
|
|
|
|
|
|
@@ -35,6 +68,8 @@ public class ConvergeServiceImpl implements ConvergeService {
|
|
|
private FzssFxrwrzHandleService fzssFxrwrzHandleService;
|
|
|
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private CadastreFileMapper cadastreFileMapper;
|
|
|
|
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
@@ -113,38 +148,287 @@ public class ConvergeServiceImpl implements ConvergeService {
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
@Transactional
|
|
|
@Override
|
|
|
public void operationConverge(String batch,String type) {
|
|
|
- try {
|
|
|
- Converge converge = new Converge();
|
|
|
- converge.generateId();
|
|
|
- String convergeId = converge.getId();
|
|
|
- fzssFxrwrzHandleService.insertFxrwrz(convergeId, "地籍库管理", "操作汇交开始", "info");
|
|
|
- converge.setName("赣江新区"+batch+"数据");
|
|
|
- converge.setBatchName(batch);
|
|
|
- converge.setFilePath("");
|
|
|
- converge.setStatus("0");
|
|
|
- converge.setType(type);
|
|
|
- converge.setReadMessage("正在生成。。");
|
|
|
- converge.setFileCostTime("0");
|
|
|
- convergeMapper.add(converge);
|
|
|
- log.info("==========="+convergeId);
|
|
|
- fzssFxrwrzHandleService.insertFxrwrz(convergeId, "地籍库管理", "汇交任务创建", "info");
|
|
|
- fzssFxrwrzHandleService.insertFxrwrz(convergeId, "地籍库管理", "汇交数据执行开始。。。", "info");
|
|
|
+ if (StringUtils.isBlank(type) || (!"1".equals(type) && !"2".equals(type))) {
|
|
|
+ log.warn("类型错误:"+type);
|
|
|
+ throw new ServiceException("汇交入参,类型错误"+type);
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(batch)) {
|
|
|
+ batch = "123";
|
|
|
+ }
|
|
|
|
|
|
+ Converge converge = new Converge();
|
|
|
+ converge.generateId();
|
|
|
+ String convergeId = converge.getId();
|
|
|
+ fzssFxrwrzHandleService.insertFxrwrz(convergeId, "地籍库管理", "操作汇交开始", "info");
|
|
|
+ converge.setName("赣江新区"+batch+"数据");
|
|
|
+ converge.setBatchName(batch);
|
|
|
+ converge.setFilePath("");
|
|
|
+ converge.setStatus("0");
|
|
|
+ converge.setType(type);
|
|
|
+ converge.setReadMessage("正在生成。。");
|
|
|
+ converge.setFileCostTime("0");
|
|
|
+ convergeMapper.add(converge);
|
|
|
+ log.info("==========="+convergeId);
|
|
|
+ fzssFxrwrzHandleService.insertFxrwrz(convergeId, "地籍库管理", "汇交任务创建", "info");
|
|
|
+ fzssFxrwrzHandleService.insertFxrwrz(convergeId, "地籍库管理", "汇交数据执行开始。。。", "info");
|
|
|
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("导出SHP文件失败", e);
|
|
|
- throw new RuntimeException("导出SHP文件失败: " + e.getMessage());
|
|
|
+ //todo 1.做一个vo类型的javabean 2.查询所有的表数据,进行判断去除空表数据。3.区分是否矢量。4.把当前文件处理成其它。
|
|
|
+ List<ConvergeRes> convergeTableList = new ArrayList<>();
|
|
|
+ Arrays.stream(ConvergeTableEnum.values()).forEach(e -> {
|
|
|
+ String tableName = e.getTableName();
|
|
|
+ List<Map<String,Object>> tableDataList = cadastreFileMapper.selectTableData("",tableName);
|
|
|
+ if(CollectionUtils.isNotEmpty(tableDataList)){
|
|
|
+ List<Map<String,String>> tableFieldList = cadastreFileMapper.selectTableCollumAndType(tableName);
|
|
|
+ int convergeType = 2;
|
|
|
+ //如果当前表存在geom 字段,视同为矢量
|
|
|
+ if(tableFieldList.stream().anyMatch(s->s.get("column_name").equals("geom"))){
|
|
|
+ convergeType = 1;
|
|
|
+ }
|
|
|
+ ConvergeRes res = new ConvergeRes();
|
|
|
+ res.setTableName(tableName);
|
|
|
+ res.setType(convergeType);
|
|
|
+ res.setDataList(tableDataList);
|
|
|
+ res.setColumnsList(tableFieldList);
|
|
|
+ convergeTableList.add(res);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ String basePath = convergedir + "/" + converge.getName()+"/"+"012345赣江新区"+"/";
|
|
|
+ List<ConvergeRes> subConvergeTableList = new ArrayList<>();//衍生出的数据
|
|
|
+
|
|
|
+ //如果有汇交数据,针对每张表,计算生成路径
|
|
|
+ if(!convergeTableList.isEmpty()){
|
|
|
+ for(ConvergeRes convergeRes : convergeTableList){
|
|
|
+ // 行政区
|
|
|
+ if(convergeRes.getTableName().equals(ConvergeTableEnum.TABLE_0.getTableName())){
|
|
|
+ convergeRes.setFilePath(basePath+"矢量空间数据/统一坐标");
|
|
|
+ convergeRes.setFileName("01"+ConvergeTableEnum.TABLE_0.getTableName());
|
|
|
+ }else if(ConvergeTableEnum.TABLE_1.getTableName().equals(convergeRes.getTableName())){
|
|
|
+ //地籍区
|
|
|
+ convergeRes.setFilePath(basePath+"矢量空间数据/统一坐标");
|
|
|
+ convergeRes.setFileName("02"+ConvergeTableEnum.TABLE_1.getTableName());
|
|
|
+ } else if(ConvergeTableEnum.TABLE_2.getTableName().equals(convergeRes.getTableName())){
|
|
|
+ //地籍子区
|
|
|
+ convergeRes.setFilePath(basePath+"矢量空间数据/统一坐标");
|
|
|
+ convergeRes.setFileName("03"+ConvergeTableEnum.TABLE_2.getTableName());
|
|
|
+ } else if(ConvergeTableEnum.TABLE_3.getTableName().equals(convergeRes.getTableName())){
|
|
|
+ //宗地
|
|
|
+ convergeRes.setFilePath(basePath+"矢量空间数据/统一坐标");
|
|
|
+ convergeRes.setFileName("03"+ConvergeTableEnum.TABLE_3.getTableName());
|
|
|
+ //todo 这里需要对宗地,根据情况进行拆分,出来一个新的List
|
|
|
+ convergeRes.setValid(-1);
|
|
|
+ subConvergeTableList.add(convergeRes);
|
|
|
+ } else if(ConvergeTableEnum.TABLE_4.getTableName().equals(convergeRes.getTableName())){
|
|
|
+ //房屋
|
|
|
+ convergeRes.setFilePath(basePath+"矢量空间数据/统一坐标");
|
|
|
+ convergeRes.setFileName("04"+ConvergeTableEnum.TABLE_4.getTableName());
|
|
|
+ }else {
|
|
|
+ convergeRes.setFilePath(basePath+"矢量空间数据/统一坐标");
|
|
|
+ convergeRes.setFileName("00"+convergeRes.getTableName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(!subConvergeTableList.isEmpty()){
|
|
|
+ convergeTableList.addAll(subConvergeTableList);
|
|
|
+ }
|
|
|
+
|
|
|
+ //这里进行数据汇交
|
|
|
+ try {
|
|
|
+ operationFileStrategy(convergeTableList);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new ServiceException("汇交失败,数据错误"+e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 这里分成两种文件生成
|
|
|
+ * @param convergeTableList
|
|
|
+ */
|
|
|
+ private void operationFileStrategy(List<ConvergeRes> convergeTableList) throws Exception {
|
|
|
+ if(CollectionUtils.isNotEmpty(convergeTableList)){
|
|
|
+ convergeTableList = convergeTableList.stream().filter(s->s.getValid()==1).collect(Collectors.toList());
|
|
|
+ for(ConvergeRes convergeRes : convergeTableList){
|
|
|
+ if(convergeRes.getType()==1){
|
|
|
+ writeShapefileByTable(convergeRes.getTableName(),convergeRes.getFilePath(),convergeRes.getFileName(),convergeRes.getColumnsList(),convergeRes.getDataList());
|
|
|
+ } else if (convergeRes.getType()==2) {
|
|
|
+ //todo 222
|
|
|
+ log.info("----------------属性数据暂无处理。。。。。");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
+ * 动态传入表名称,根据表结构生成 SHP 文件
|
|
|
+ * @param tableName 表名
|
|
|
+ * @param filePath 生成路径
|
|
|
+ * @param fileName 文件名
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public void writeShapefileByTable(String tableName, String filePath, String fileName,List<Map<String, String>> columns,List<Map<String, Object>> dataList) throws Exception {
|
|
|
+
|
|
|
+ // 3. 定义要素类型 (SimpleFeatureType)
|
|
|
+ SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
|
|
|
+ typeBuilder.setName(tableName);
|
|
|
+
|
|
|
+ // 设置坐标系 CGCS2000 (EPSG:4490)
|
|
|
+ CoordinateReferenceSystem crs = null;
|
|
|
+ try {
|
|
|
+ crs = CRS.decode("EPSG:4490");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("无法从 EPSG 数据库加载 4490,尝试使用 WKT 解析: {}", e.getMessage());
|
|
|
+ // Fallback to WKT definition for CGCS2000
|
|
|
+ String wkt = "GEOGCS[\"China Geodetic Coordinate System 2000\",\n" +
|
|
|
+ " DATUM[\"China_2000\",\n" +
|
|
|
+ " SPHEROID[\"CGCS2000\",6378137,298.257222101,\n" +
|
|
|
+ " AUTHORITY[\"EPSG\",\"1024\"]],\n" +
|
|
|
+ " AUTHORITY[\"EPSG\",\"1043\"]],\n" +
|
|
|
+ " PRIMEM[\"Greenwich\",0,\n" +
|
|
|
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n" +
|
|
|
+ " UNIT[\"degree\",0.0174532925199433,\n" +
|
|
|
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n" +
|
|
|
+ " AUTHORITY[\"EPSG\",\"4490\"]]";
|
|
|
+ crs = CRS.parseWKT(wkt);
|
|
|
+ }
|
|
|
+ typeBuilder.setCRS(crs);
|
|
|
+
|
|
|
+ // 存储字段名和对应的类型,用于后续数据读取
|
|
|
+ Map<String, String> columnTypeMap = new LinkedHashMap<>();
|
|
|
|
|
|
+ // 添加几何字段 (固定为 the_geom)
|
|
|
+ typeBuilder.add("the_geom", MultiPolygon.class);
|
|
|
|
|
|
+ for (Map<String, String> col : columns) {
|
|
|
+ String colName = (String) col.get("column_name");
|
|
|
+ String dataType = (String) col.get("data_type");
|
|
|
+
|
|
|
+ if ("geom".equalsIgnoreCase(colName)) {
|
|
|
+ continue; // 已经处理过几何字段
|
|
|
+ }
|
|
|
+
|
|
|
+ // SHP 字段名长度限制为 10 字符
|
|
|
+ String shpColName = colName.length() > 10 ? colName.substring(0, 10) : colName;
|
|
|
+ Class<?> javaType = mapDatabaseTypeToJavaClass(dataType);
|
|
|
+ typeBuilder.add(shpColName, javaType);
|
|
|
+ columnTypeMap.put(colName, shpColName);
|
|
|
+ }
|
|
|
+
|
|
|
+ SimpleFeatureType featureType = typeBuilder.buildFeatureType();
|
|
|
+
|
|
|
+ // 4. 创建要素集合
|
|
|
+ List<SimpleFeature> features = new ArrayList<>();
|
|
|
+ SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
|
|
|
+ WKTReader wktReader = new WKTReader();
|
|
|
+ WKBReader wkbReader = new WKBReader();
|
|
|
+
|
|
|
+ for (Map<String, Object> data : dataList) {
|
|
|
+ // 获取几何数据,优先从 geom2 (EWKT) 获取
|
|
|
+ Object geomObj = data.get("geom2");
|
|
|
+ if (geomObj == null) {
|
|
|
+ geomObj = data.get("geom");
|
|
|
+ }
|
|
|
+ if (geomObj == null) continue;
|
|
|
+
|
|
|
+ Geometry geometry = null;
|
|
|
+ if (geomObj instanceof Geometry) {
|
|
|
+ geometry = (Geometry) geomObj;
|
|
|
+ } else {
|
|
|
+ String geomStr = geomObj.toString();
|
|
|
+ if (com.siwei.common.core.utils.StringUtils.isEmpty(geomStr)) continue;
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (geomStr.startsWith("01") || geomStr.startsWith("00")) {
|
|
|
+ geometry = wkbReader.read(WKBReader.hexToBytes(geomStr));
|
|
|
+ } else {
|
|
|
+ String wkt = geomStr;
|
|
|
+ if (wkt.contains(";")) {
|
|
|
+ wkt = wkt.split(";")[1];
|
|
|
+ }
|
|
|
+ geometry = wktReader.read(wkt);
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.warn("无法解析几何数据: {}, 错误: {}", geomStr, e.getMessage());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (geometry != null) {
|
|
|
+ // 强制转为 MultiPolygon
|
|
|
+ if (geometry instanceof Polygon) {
|
|
|
+ geometry = geometry.getFactory().createMultiPolygon(new Polygon[]{(Polygon) geometry});
|
|
|
+ }
|
|
|
+
|
|
|
+ featureBuilder.add(geometry);
|
|
|
+
|
|
|
+ // 添加属性字段
|
|
|
+ for (String originColName : columnTypeMap.keySet()) {
|
|
|
+ featureBuilder.add(data.get(originColName));
|
|
|
+ }
|
|
|
+
|
|
|
+ features.add(featureBuilder.buildFeature(null));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 写入文件
|
|
|
+ File shpFile = new File(filePath + File.separator + fileName + ".shp");
|
|
|
+ ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
|
|
|
+ Map<String, Serializable> params = new HashMap<>();
|
|
|
+ params.put("url", shpFile.toURI().toURL());
|
|
|
+ params.put("create spatial index", Boolean.TRUE);
|
|
|
+
|
|
|
+ ShapefileDataStore dataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
|
|
|
+ dataStore.setCharset(Charset.forName("UTF-8"));
|
|
|
+ dataStore.createSchema(featureType);
|
|
|
+
|
|
|
+ Transaction transaction = new DefaultTransaction("create");
|
|
|
+ String typeName = dataStore.getTypeNames()[0];
|
|
|
+ SimpleFeatureSource featureSource = dataStore.getFeatureSource(typeName);
|
|
|
+
|
|
|
+ if (featureSource instanceof SimpleFeatureStore) {
|
|
|
+ SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
|
|
|
+ SimpleFeatureCollection collection = new ListFeatureCollection(featureType, features);
|
|
|
+ featureStore.setTransaction(transaction);
|
|
|
+ try {
|
|
|
+ featureStore.addFeatures(collection);
|
|
|
+ transaction.commit();
|
|
|
+ } catch (Exception e) {
|
|
|
+ transaction.rollback();
|
|
|
+ throw e;
|
|
|
+ } finally {
|
|
|
+ transaction.close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ dataStore.dispose();
|
|
|
+
|
|
|
+ // 6. 生成 .cpg 文件
|
|
|
+ File cpgFile = new File(filePath + File.separator + fileName + ".cpg");
|
|
|
+ try (PrintWriter writer = new PrintWriter(cpgFile)) {
|
|
|
+ writer.print("UTF-8");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Class<?> mapDatabaseTypeToJavaClass(String dataType) {
|
|
|
+ if (dataType == null) return String.class;
|
|
|
+ dataType = dataType.toLowerCase();
|
|
|
+ if (dataType.contains("char") || dataType.contains("text")) {
|
|
|
+ return String.class;
|
|
|
+ } else if (dataType.contains("int")) {
|
|
|
+ return Integer.class;
|
|
|
+ } else if (dataType.contains("numeric") || dataType.contains("decimal") || dataType.contains("double") || dataType.contains("float") || dataType.contains("real")) {
|
|
|
+ return Double.class;
|
|
|
+ } else if (dataType.contains("date") || dataType.contains("time")) {
|
|
|
+ return java.util.Date.class;
|
|
|
+ } else if (dataType.contains("boolean")) {
|
|
|
+ return Boolean.class;
|
|
|
+ }
|
|
|
+ return String.class;
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|