|
@@ -6,6 +6,8 @@ import com.siwei.apply.common.Constant;
|
|
|
import com.siwei.apply.domain.*;
|
|
import com.siwei.apply.domain.*;
|
|
|
import com.siwei.apply.domain.res.*;
|
|
import com.siwei.apply.domain.res.*;
|
|
|
import com.siwei.apply.domain.vo.NodeVo;
|
|
import com.siwei.apply.domain.vo.NodeVo;
|
|
|
|
|
+import com.siwei.apply.domain.vo.ProjectCycleCurrentShpVo;
|
|
|
|
|
+import com.siwei.apply.domain.vo.ProjectCycleProjectVo;
|
|
|
import com.siwei.apply.domain.vo.ProjectFilterVo;
|
|
import com.siwei.apply.domain.vo.ProjectFilterVo;
|
|
|
import com.siwei.apply.domain.vo.ProjectUpdateVo;
|
|
import com.siwei.apply.domain.vo.ProjectUpdateVo;
|
|
|
import com.siwei.apply.domain.vo.ProjectVo;
|
|
import com.siwei.apply.domain.vo.ProjectVo;
|
|
@@ -14,7 +16,22 @@ import com.siwei.apply.mapper.*;
|
|
|
import com.siwei.apply.service.NodeAttachmentService;
|
|
import com.siwei.apply.service.NodeAttachmentService;
|
|
|
import com.siwei.apply.service.NodeLandService;
|
|
import com.siwei.apply.service.NodeLandService;
|
|
|
import com.siwei.apply.service.ProjectService;
|
|
import com.siwei.apply.service.ProjectService;
|
|
|
|
|
+import com.siwei.apply.utils.ServiceFileUtil;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.geotools.data.DefaultTransaction;
|
|
|
|
|
+import org.geotools.data.FeatureWriter;
|
|
|
|
|
+import org.geotools.data.Transaction;
|
|
|
|
|
+import org.geotools.data.shapefile.ShapefileDataStore;
|
|
|
|
|
+import org.geotools.data.shapefile.ShapefileDataStoreFactory;
|
|
|
|
|
+import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
|
|
|
|
|
+import org.geotools.referencing.CRS;
|
|
|
|
|
+import org.locationtech.jts.geom.Geometry;
|
|
|
|
|
+import org.locationtech.jts.geom.MultiPolygon;
|
|
|
|
|
+import org.locationtech.jts.geom.Polygon;
|
|
|
|
|
+import org.locationtech.jts.io.WKTReader;
|
|
|
|
|
+import org.opengis.feature.simple.SimpleFeature;
|
|
|
|
|
+import org.opengis.feature.simple.SimpleFeatureType;
|
|
|
|
|
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
|
import org.apache.commons.io.FileUtils;
|
|
import org.apache.commons.io.FileUtils;
|
|
|
import org.apache.commons.lang3.ArrayUtils;
|
|
import org.apache.commons.lang3.ArrayUtils;
|
|
@@ -23,8 +40,14 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
|
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
import java.io.File;
|
|
import java.io.File;
|
|
|
|
|
+import java.io.FileInputStream;
|
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
|
|
|
+import java.io.PrintWriter;
|
|
|
|
|
+import java.io.Serializable;
|
|
|
|
|
+import java.net.URLEncoder;
|
|
|
|
|
+import java.nio.charset.Charset;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.charset.StandardCharsets;
|
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Files;
|
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Path;
|
|
@@ -43,6 +66,36 @@ import static com.siwei.apply.common.Common.UserId;
|
|
|
@Slf4j
|
|
@Slf4j
|
|
|
@Service
|
|
@Service
|
|
|
public class ProjectImpl implements ProjectService {
|
|
public class ProjectImpl implements ProjectService {
|
|
|
|
|
+ private static final Map<String, String> CYCLE_TABLE_WORKTYPE_MAP;
|
|
|
|
|
+ private static final Map<String, String> CYCLE_RESOURCE_TABLE_MAP;
|
|
|
|
|
+
|
|
|
|
|
+ static {
|
|
|
|
|
+ Map<String, String> tableWorktypeMap = new HashMap<>();
|
|
|
|
|
+ tableWorktypeMap.put("t_ydysyxz", "ydysyxz");
|
|
|
|
|
+ tableWorktypeMap.put("t_ydbp", "ydbp");
|
|
|
|
|
+ tableWorktypeMap.put("t_ydbp_data", "ydbpData");
|
|
|
|
|
+ tableWorktypeMap.put("t_tjyydhx", "tjyydhx");
|
|
|
|
|
+ tableWorktypeMap.put("t_tdgy", "tdgy");
|
|
|
|
|
+ tableWorktypeMap.put("t_gyjsydscdj", "gyjsydscdj");
|
|
|
|
|
+ tableWorktypeMap.put("t_jsydghxk", "jsydghxk");
|
|
|
|
|
+ tableWorktypeMap.put("t_jsgcghxk", "jsgcghxk");
|
|
|
|
|
+ tableWorktypeMap.put("t_tdhyhs", "tdhyhs");
|
|
|
|
|
+ tableWorktypeMap.put("t_gyjsydjfwscdj", "gyjsydjfwscdj");
|
|
|
|
|
+ CYCLE_TABLE_WORKTYPE_MAP = Collections.unmodifiableMap(tableWorktypeMap);
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, String> resourceTableMap = new HashMap<>();
|
|
|
|
|
+ resourceTableMap.put("1", "t_ydysyxz");
|
|
|
|
|
+ resourceTableMap.put("2", "t_ydbp");
|
|
|
|
|
+ resourceTableMap.put("3", "t_tjyydhx");
|
|
|
|
|
+ resourceTableMap.put("4", "t_tdgy");
|
|
|
|
|
+ resourceTableMap.put("5", "t_gyjsydscdj");
|
|
|
|
|
+ resourceTableMap.put("6", "t_jsydghxk");
|
|
|
|
|
+ resourceTableMap.put("7", "t_jsgcghxk");
|
|
|
|
|
+ resourceTableMap.put("8", "t_tdhyhs");
|
|
|
|
|
+ resourceTableMap.put("9", "t_gyjsydjfwscdj");
|
|
|
|
|
+ CYCLE_RESOURCE_TABLE_MAP = Collections.unmodifiableMap(resourceTableMap);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private ProjectMapper projectMapper;
|
|
private ProjectMapper projectMapper;
|
|
|
@Autowired
|
|
@Autowired
|
|
@@ -135,6 +188,51 @@ public class ProjectImpl implements ProjectService {
|
|
|
return map;
|
|
return map;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Map<String, Object> getCurrentCycleProjects(ProjectCycleProjectVo projectCycleProjectVo) {
|
|
|
|
|
+ if (projectCycleProjectVo == null || StringUtils.isBlank(projectCycleProjectVo.getNodeTableName())) {
|
|
|
|
|
+ throw new IllegalArgumentException("阶段表名不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ projectCycleProjectVo.validatePageParams();
|
|
|
|
|
+ String nodeTableName = projectCycleProjectVo.getNodeTableName().trim();
|
|
|
|
|
+ String worktype = CYCLE_TABLE_WORKTYPE_MAP.get(nodeTableName);
|
|
|
|
|
+ if (StringUtils.isBlank(worktype)) {
|
|
|
|
|
+ throw new IllegalArgumentException("不支持的阶段表名:" + nodeTableName);
|
|
|
|
|
+ }
|
|
|
|
|
+ projectCycleProjectVo.setNodeTableName(nodeTableName);
|
|
|
|
|
+ projectCycleProjectVo.setWorktype(worktype);
|
|
|
|
|
+ projectCycleProjectVo.setIsOnchain(true);
|
|
|
|
|
+
|
|
|
|
|
+ List<Project> candidates = projectMapper.getListWithoutPage(projectCycleProjectVo);
|
|
|
|
|
+ List<Map<String, Object>> rows = new ArrayList<>();
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(candidates)) {
|
|
|
|
|
+ for (Project project : candidates) {
|
|
|
|
|
+ ProjectWorkflow currentProjectWorkflow = getCurrentNode(project.getId());
|
|
|
|
|
+ if (currentProjectWorkflow == null
|
|
|
|
|
+ || !nodeTableName.equals(currentProjectWorkflow.getNodeTableName())) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ Map<String, Object> nodeData = projectWorkflowMapper.getCurrentNode(
|
|
|
|
|
+ currentProjectWorkflow.getNodeId(),
|
|
|
|
|
+ project.getId(),
|
|
|
|
|
+ currentProjectWorkflow.getNodeTableName());
|
|
|
|
|
+ rows.addAll(buildCycleProjectRows(project, currentProjectWorkflow, nodeData, worktype));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int count = rows.size();
|
|
|
|
|
+ int fromIndex = Math.min(projectCycleProjectVo.getOffset(), count);
|
|
|
|
|
+ int toIndex = Math.min(fromIndex + projectCycleProjectVo.getPageSize(), count);
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> map = new LinkedHashMap<>();
|
|
|
|
|
+ map.put("projects", rows.subList(fromIndex, toIndex));
|
|
|
|
|
+ map.put("count", count);
|
|
|
|
|
+ map.put("nodeTableName", nodeTableName);
|
|
|
|
|
+ map.put("worktype", worktype);
|
|
|
|
|
+ return map;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Override
|
|
@Override
|
|
|
public void update(ProjectUpdateVo projectUpdateVo) {
|
|
public void update(ProjectUpdateVo projectUpdateVo) {
|
|
|
projectMapper.update(projectUpdateVo);
|
|
projectMapper.update(projectUpdateVo);
|
|
@@ -322,6 +420,716 @@ public class ProjectImpl implements ProjectService {
|
|
|
return workflows;
|
|
return workflows;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void exportCycleShp(String projectId, HttpServletResponse response) {
|
|
|
|
|
+ exportCycleShp(Collections.singletonList(projectId), response);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void exportCycleShp(List<String> projectIds, HttpServletResponse response) {
|
|
|
|
|
+ File tempDir = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (CollectionUtils.isEmpty(projectIds)) {
|
|
|
|
|
+ throw new RuntimeException("项目ID列表不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ List<CycleShpRow> rows = new ArrayList<>();
|
|
|
|
|
+ List<String> projectNames = new ArrayList<>();
|
|
|
|
|
+ for (String projectId : projectIds) {
|
|
|
|
|
+ if (StringUtils.isBlank(projectId)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ Project project = projectMapper.get(projectId);
|
|
|
|
|
+ if (Objects.isNull(project)) {
|
|
|
|
|
+ log.warn("批量导出项目全生命周期SHP时项目不存在,projectId={}", projectId);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ List<ProjectCycleExportNode> exportNodes = buildCycleExportNodes(project);
|
|
|
|
|
+ if (CollectionUtils.isEmpty(exportNodes)) {
|
|
|
|
|
+ log.warn("批量导出项目全生命周期SHP时项目无已上链生命周期数据,projectId={}", projectId);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ List<CycleShpRow> projectRows = buildCycleShpRows(project, exportNodes);
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(projectRows)) {
|
|
|
|
|
+ rows.addAll(projectRows);
|
|
|
|
|
+ projectNames.add(project.getName());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (CollectionUtils.isEmpty(rows)) {
|
|
|
|
|
+ throw new RuntimeException("所选项目无可导出的地块图形");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String shpName = "project_cycle_" + System.currentTimeMillis();
|
|
|
|
|
+ tempDir = Files.createTempDirectory("project-cycle-shp-").toFile();
|
|
|
|
|
+ File shpFile = new File(tempDir, shpName + ".shp");
|
|
|
|
|
+ writeCycleShapefile(shpFile, rows);
|
|
|
|
|
+
|
|
|
|
|
+ File cpgFile = new File(tempDir, shpName + ".cpg");
|
|
|
|
|
+ try (PrintWriter writer = new PrintWriter(cpgFile, "UTF-8")) {
|
|
|
|
|
+ writer.print("UTF-8");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ File zipFile = new File(tempDir, shpName + ".zip");
|
|
|
|
|
+ ServiceFileUtil.zipFiles(Arrays.asList(
|
|
|
|
|
+ new File(tempDir, shpName + ".shp"),
|
|
|
|
|
+ new File(tempDir, shpName + ".shx"),
|
|
|
|
|
+ new File(tempDir, shpName + ".dbf"),
|
|
|
|
|
+ new File(tempDir, shpName + ".prj"),
|
|
|
|
|
+ cpgFile
|
|
|
|
|
+ ), zipFile);
|
|
|
|
|
+
|
|
|
|
|
+ String downloadName = projectNames.size() == 1
|
|
|
|
|
+ ? safeFileName(projectNames.get(0)) + "_全生命周期.zip"
|
|
|
|
|
+ : "项目全生命周期_" + projectNames.size() + "个项目.zip";
|
|
|
|
|
+ String encodedName = URLEncoder.encode(downloadName, StandardCharsets.UTF_8.name())
|
|
|
|
|
+ .replaceAll("\\+", "%20");
|
|
|
|
|
+ response.reset();
|
|
|
|
|
+ response.setContentType("application/zip");
|
|
|
|
|
+ response.setCharacterEncoding("utf-8");
|
|
|
|
|
+ response.setHeader("Content-Disposition", "attachment;filename=" + encodedName
|
|
|
|
|
+ + ";filename*=UTF-8''" + encodedName);
|
|
|
|
|
+ response.setContentLengthLong(zipFile.length());
|
|
|
|
|
+
|
|
|
|
|
+ try (FileInputStream fis = new FileInputStream(zipFile)) {
|
|
|
|
|
+ byte[] buffer = new byte[4096];
|
|
|
|
|
+ int len;
|
|
|
|
|
+ while ((len = fis.read(buffer)) > 0) {
|
|
|
|
|
+ response.getOutputStream().write(buffer, 0, len);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ response.getOutputStream().flush();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("导出项目全生命周期SHP失败,projectIds={}", projectIds, e);
|
|
|
|
|
+ throw new RuntimeException("导出项目全生命周期SHP失败: " + e.getMessage());
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if (tempDir != null && tempDir.exists()) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ FileUtils.deleteDirectory(tempDir);
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ log.warn("清理生命周期SHP临时目录失败: {}", tempDir.getAbsolutePath(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void exportCurrentCycleShp(ProjectCycleCurrentShpVo projectCycleCurrentShpVo, HttpServletResponse response) {
|
|
|
|
|
+ File tempDir = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (projectCycleCurrentShpVo == null || StringUtils.isBlank(projectCycleCurrentShpVo.getNodeTableName())) {
|
|
|
|
|
+ throw new IllegalArgumentException("阶段表名不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ String nodeTableName = projectCycleCurrentShpVo.getNodeTableName().trim();
|
|
|
|
|
+ if (!CYCLE_TABLE_WORKTYPE_MAP.containsKey(nodeTableName)) {
|
|
|
|
|
+ throw new IllegalArgumentException("不支持的阶段表名:" + nodeTableName);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (CollectionUtils.isEmpty(projectCycleCurrentShpVo.getRows())) {
|
|
|
|
|
+ throw new IllegalArgumentException("请选择要导出的当前阶段数据");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, String> currentFieldMap = buildCurrentCycleFieldMap(nodeTableName);
|
|
|
|
|
+ List<CycleShpRow> rows = new ArrayList<>();
|
|
|
|
|
+ Set<String> projectNames = new LinkedHashSet<>();
|
|
|
|
|
+ for (ProjectCycleCurrentShpVo.Item item : projectCycleCurrentShpVo.getRows()) {
|
|
|
|
|
+ if (item == null || StringUtils.isBlank(item.getProjectId())) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ Project project = projectMapper.get(item.getProjectId());
|
|
|
|
|
+ if (project == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ ProjectWorkflow workflow = findExportWorkflow(item, nodeTableName);
|
|
|
|
|
+ if (workflow == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ Map<String, Object> nodeData = projectWorkflowMapper.getCurrentNode(
|
|
|
|
|
+ workflow.getNodeId(), project.getId(), nodeTableName);
|
|
|
|
|
+ if (nodeData == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ List<Map<String, String>> geomDetails = getSelectedGeomDetails(project.getId(), nodeTableName, workflow, item);
|
|
|
|
|
+ for (Map<String, String> geomDetail : geomDetails) {
|
|
|
|
|
+ String geom = geomDetail.get("geom");
|
|
|
|
|
+ if (StringUtils.isBlank(geom)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ CycleShpRow row = new CycleShpRow();
|
|
|
|
|
+ row.geom = geom;
|
|
|
|
|
+ row.attributes.put("id", project.getId());
|
|
|
|
|
+ row.attributes.put("xmmc", project.getName());
|
|
|
|
|
+ row.attributes.put("xmbm", project.getCode());
|
|
|
|
|
+ row.attributes.put("jsdw", project.getCompany());
|
|
|
|
|
+ row.attributes.put("dkid", geomDetail.get("id"));
|
|
|
|
|
+ for (Map.Entry<String, Object> entry : nodeData.entrySet()) {
|
|
|
|
|
+ String columnName = entry.getKey();
|
|
|
|
|
+ if (shouldSkipExportColumn(columnName) || entry.getValue() == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ String fieldName = currentFieldMap.get(columnName);
|
|
|
|
|
+ if (StringUtils.isNotBlank(fieldName)) {
|
|
|
|
|
+ row.attributes.put(fieldName, entry.getValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ rows.add(row);
|
|
|
|
|
+ projectNames.add(project.getName());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (CollectionUtils.isEmpty(rows)) {
|
|
|
|
|
+ throw new RuntimeException("所选当前阶段数据无可导出的地块图形");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String shpName = "project_cycle_current_" + System.currentTimeMillis();
|
|
|
|
|
+ tempDir = Files.createTempDirectory("project-cycle-current-shp-").toFile();
|
|
|
|
|
+ File shpFile = new File(tempDir, shpName + ".shp");
|
|
|
|
|
+ writeCycleShapefile(shpFile, rows);
|
|
|
|
|
+
|
|
|
|
|
+ File cpgFile = new File(tempDir, shpName + ".cpg");
|
|
|
|
|
+ try (PrintWriter writer = new PrintWriter(cpgFile, "UTF-8")) {
|
|
|
|
|
+ writer.print("UTF-8");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ File zipFile = new File(tempDir, shpName + ".zip");
|
|
|
|
|
+ ServiceFileUtil.zipFiles(Arrays.asList(
|
|
|
|
|
+ new File(tempDir, shpName + ".shp"),
|
|
|
|
|
+ new File(tempDir, shpName + ".shx"),
|
|
|
|
|
+ new File(tempDir, shpName + ".dbf"),
|
|
|
|
|
+ new File(tempDir, shpName + ".prj"),
|
|
|
|
|
+ cpgFile
|
|
|
|
|
+ ), zipFile);
|
|
|
|
|
+
|
|
|
|
|
+ String downloadName = projectNames.size() == 1
|
|
|
|
|
+ ? safeFileName(projectNames.iterator().next()) + "_当前阶段.zip"
|
|
|
|
|
+ : "当前阶段_" + projectNames.size() + "个项目.zip";
|
|
|
|
|
+ writeZipToResponse(zipFile, downloadName, response);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("导出当前生命周期阶段SHP失败,param={}", projectCycleCurrentShpVo, e);
|
|
|
|
|
+ throw new RuntimeException("导出当前生命周期阶段SHP失败: " + e.getMessage());
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if (tempDir != null && tempDir.exists()) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ FileUtils.deleteDirectory(tempDir);
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ log.warn("清理当前阶段SHP临时目录失败: {}", tempDir.getAbsolutePath(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private List<ProjectCycleExportNode> buildCycleExportNodes(Project project) {
|
|
|
|
|
+ Integer projectType = project.getProjectType();
|
|
|
|
|
+ List<ProjectCycleRes> workflows = workflowMapper.selectByProjectTypeOrderByIndex(projectType);
|
|
|
|
|
+ List<String> allowTables = workflows.stream().map(ProjectCycleRes::getTableName).collect(Collectors.toList());
|
|
|
|
|
+ Map<String, Integer> levelMap = new HashMap<>();
|
|
|
|
|
+ for (int i = 0; i < workflows.size(); i++) {
|
|
|
|
|
+ levelMap.put(workflows.get(i).getId(), i + 1);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ List<ProjectWorkflowRes> projectWorkflows = projectWorkflowMapper.selectCycleByProjectId(project.getId());
|
|
|
|
|
+ List<ProjectCycleExportNode> exportNodes = new ArrayList<>();
|
|
|
|
|
+ for (ProjectWorkflowRes workflowRes : projectWorkflows) {
|
|
|
|
|
+ String tableName = workflowRes.getNodeTableName();
|
|
|
|
|
+ if (!allowTables.contains(tableName)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ Boolean hasOnchain = projectWorkflowMapper.isOnchain(workflowRes.getNodeId(), project.getId(), tableName);
|
|
|
|
|
+ if (!Boolean.TRUE.equals(hasOnchain)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> currentNode = projectWorkflowMapper.getCurrentNode(workflowRes.getNodeId(),
|
|
|
|
|
+ project.getId(), tableName);
|
|
|
|
|
+ if (Objects.isNull(currentNode)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, String> geomInfo = nodeLandMapper.selectUnionGeomByNodeId(workflowRes.getNodeId());
|
|
|
|
|
+ if ((geomInfo == null || StringUtils.isBlank(geomInfo.get("geom")))
|
|
|
|
|
+ && shouldUseGyjsydscdjGeom(tableName)) {
|
|
|
|
|
+ geomInfo = nodeLandMapper.selectUnionGeomByNodeId(findProjectNodeId(project.getId(), "t_gyjsydscdj"));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (geomInfo == null || StringUtils.isBlank(geomInfo.get("geom"))) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int level = levelMap.getOrDefault(workflowRes.getWorkflowId(), exportNodes.size() + 1);
|
|
|
|
|
+ ProjectCycleExportNode node = new ProjectCycleExportNode();
|
|
|
|
|
+ node.level = level;
|
|
|
|
|
+ node.tableName = tableName;
|
|
|
|
|
+ node.node = currentNode;
|
|
|
|
|
+ node.geom = geomInfo.get("geom");
|
|
|
|
|
+ node.geomKey = StringUtils.defaultIfBlank(geomInfo.get("geomDbId"), normalizeGeomKey(node.geom));
|
|
|
|
|
+ exportNodes.add(node);
|
|
|
|
|
+ }
|
|
|
|
|
+ exportNodes.sort(Comparator.comparingInt(o -> o.level));
|
|
|
|
|
+ return exportNodes;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private ProjectWorkflow findExportWorkflow(ProjectCycleCurrentShpVo.Item item, String nodeTableName) {
|
|
|
|
|
+ if (StringUtils.isNotBlank(item.getNodeId())) {
|
|
|
|
|
+ List<ProjectWorkflow> workflows = projectWorkflowMapper.selectByNodeId(item.getNodeId(), item.getProjectId());
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(workflows)) {
|
|
|
|
|
+ for (ProjectWorkflow workflow : workflows) {
|
|
|
|
|
+ if (nodeTableName.equals(workflow.getNodeTableName())) {
|
|
|
|
|
+ return workflow;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ List<ProjectWorkflow> workflows = projectWorkflowMapper.selectByProjectIdAndNodeTableName(
|
|
|
|
|
+ item.getProjectId(), nodeTableName);
|
|
|
|
|
+ return CollectionUtils.isEmpty(workflows) ? null : workflows.get(0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private List<Map<String, String>> getSelectedGeomDetails(String projectId, String nodeTableName,
|
|
|
|
|
+ ProjectWorkflow workflow,
|
|
|
|
|
+ ProjectCycleCurrentShpVo.Item item) {
|
|
|
|
|
+ String geomNodeId = StringUtils.defaultIfBlank(item.getGeomNodeId(), workflow.getNodeId());
|
|
|
|
|
+ List<Map<String, String>> details = copyGeomDetails(geomNodeId,
|
|
|
|
|
+ nodeLandMapper.selectGeomDbDetailsByNodeId(geomNodeId, item.getGeomId()));
|
|
|
|
|
+ if (CollectionUtils.isEmpty(details) && shouldUseGyjsydscdjGeom(nodeTableName)) {
|
|
|
|
|
+ String fallbackNodeId = findProjectNodeId(projectId, "t_gyjsydscdj");
|
|
|
|
|
+ if (StringUtils.isNotBlank(fallbackNodeId)) {
|
|
|
|
|
+ details = copyGeomDetails(fallbackNodeId,
|
|
|
|
|
+ nodeLandMapper.selectGeomDbDetailsByNodeId(fallbackNodeId, item.getGeomId()));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return details;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private List<Map<String, String>> getCycleProjectGeomDetails(String projectId, String nodeTableName,
|
|
|
|
|
+ ProjectWorkflow workflow) {
|
|
|
|
|
+ List<Map<String, String>> details = copyGeomDetails(workflow.getNodeId(),
|
|
|
|
|
+ nodeLandMapper.selectGeomDbDetailsByNodeId(workflow.getNodeId(), null));
|
|
|
|
|
+ if (CollectionUtils.isEmpty(details) && shouldUseGyjsydscdjGeom(nodeTableName)) {
|
|
|
|
|
+ String fallbackNodeId = findProjectNodeId(projectId, "t_gyjsydscdj");
|
|
|
|
|
+ if (StringUtils.isNotBlank(fallbackNodeId)) {
|
|
|
|
|
+ details = copyGeomDetails(fallbackNodeId,
|
|
|
|
|
+ nodeLandMapper.selectGeomDbDetailsByNodeId(fallbackNodeId, null));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return details;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private List<Map<String, String>> copyGeomDetails(String geomNodeId, List<Map<String, String>> details) {
|
|
|
|
|
+ if (CollectionUtils.isEmpty(details)) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+ List<Map<String, String>> result = new ArrayList<>();
|
|
|
|
|
+ for (Map<String, String> detail : details) {
|
|
|
|
|
+ Map<String, String> copy = new LinkedHashMap<>(detail);
|
|
|
|
|
+ copy.put("geomNodeId", geomNodeId);
|
|
|
|
|
+ result.add(copy);
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private List<CycleShpRow> buildCycleShpRows(Project project, List<ProjectCycleExportNode> exportNodes) {
|
|
|
|
|
+ List<CycleShpRow> rows = new ArrayList<>();
|
|
|
|
|
+ Map<String, CycleShpRow> rowMap = new LinkedHashMap<>();
|
|
|
|
|
+ Map<String, Map<String, String>> tableColumnMap = new HashMap<>();
|
|
|
|
|
+ Map<String, Map<String, String>> cycleFieldMap = buildCycleFieldMap(project.getProjectType(), tableColumnMap);
|
|
|
|
|
+
|
|
|
|
|
+ for (ProjectCycleExportNode node : exportNodes) {
|
|
|
|
|
+ CycleShpRow row = rowMap.computeIfAbsent(node.geomKey, key -> {
|
|
|
|
|
+ CycleShpRow newRow = new CycleShpRow();
|
|
|
|
|
+ newRow.geom = node.geom;
|
|
|
|
|
+ newRow.attributes.put("id", project.getId());
|
|
|
|
|
+ newRow.attributes.put("xmmc", project.getName());
|
|
|
|
|
+ newRow.attributes.put("xmbm", project.getCode());
|
|
|
|
|
+ newRow.attributes.put("jsdw", project.getCompany());
|
|
|
|
|
+ for (Map<String, String> fieldMap : cycleFieldMap.values()) {
|
|
|
|
|
+ for (String fieldName : fieldMap.values()) {
|
|
|
|
|
+ newRow.attributes.put(fieldName, "");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ rows.add(newRow);
|
|
|
|
|
+ return newRow;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, String> fieldMap = cycleFieldMap.getOrDefault(node.tableName, new LinkedHashMap<>());
|
|
|
|
|
+ for (Map.Entry<String, Object> entry : node.node.entrySet()) {
|
|
|
|
|
+ String columnName = entry.getKey();
|
|
|
|
|
+ if (shouldSkipExportColumn(columnName) || entry.getValue() == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ String fieldName = fieldMap.get(columnName);
|
|
|
|
|
+ if (StringUtils.isNotBlank(fieldName)) {
|
|
|
|
|
+ row.attributes.put(fieldName, entry.getValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return rows;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Map<String, String> buildCurrentCycleFieldMap(String tableName) {
|
|
|
|
|
+ Map<String, String> columnCommentMap = getColumnCommentMap(tableName);
|
|
|
|
|
+ Map<String, String> fieldMap = new LinkedHashMap<>();
|
|
|
|
|
+ Set<String> usedFieldNames = new HashSet<>(Arrays.asList("id", "xmmc", "xmbm", "jsdw", "dkid"));
|
|
|
|
|
+ for (Map.Entry<String, String> entry : columnCommentMap.entrySet()) {
|
|
|
|
|
+ String columnName = entry.getKey();
|
|
|
|
|
+ if (shouldSkipExportColumn(columnName)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ fieldMap.put(columnName, buildShpFieldName("D", entry.getValue(), columnName, usedFieldNames));
|
|
|
|
|
+ }
|
|
|
|
|
+ return fieldMap;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Map<String, Map<String, String>> buildCycleFieldMap(Integer projectType, Map<String, Map<String, String>> tableColumnMap) {
|
|
|
|
|
+ Map<String, Map<String, String>> result = new LinkedHashMap<>();
|
|
|
|
|
+ Set<String> usedFieldNames = new HashSet<>();
|
|
|
|
|
+ List<ProjectCycleRes> workflows = workflowMapper.selectByProjectTypeOrderByIndex(projectType);
|
|
|
|
|
+ for (int i = 0; i < workflows.size(); i++) {
|
|
|
|
|
+ ProjectCycleRes workflow = workflows.get(i);
|
|
|
|
|
+ String tableName = workflow.getTableName();
|
|
|
|
|
+ Map<String, String> columnCommentMap = tableColumnMap.computeIfAbsent(tableName, this::getColumnCommentMap);
|
|
|
|
|
+ Map<String, String> fieldMap = new LinkedHashMap<>();
|
|
|
|
|
+ for (Map.Entry<String, String> entry : columnCommentMap.entrySet()) {
|
|
|
|
|
+ String columnName = entry.getKey();
|
|
|
|
|
+ if (shouldSkipExportColumn(columnName)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ String fieldName = buildShpFieldName("L" + (i + 1), entry.getValue(), columnName, usedFieldNames);
|
|
|
|
|
+ fieldMap.put(columnName, fieldName);
|
|
|
|
|
+ }
|
|
|
|
|
+ result.put(tableName, fieldMap);
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Map<String, String> getColumnCommentMap(String tableName) {
|
|
|
|
|
+ List<Map<String, String>> columnComments = projectWorkflowMapper.selectTableColumnComments(tableName);
|
|
|
|
|
+ Map<String, String> result = new HashMap<>();
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(columnComments)) {
|
|
|
|
|
+ for (Map<String, String> columnComment : columnComments) {
|
|
|
|
|
+ result.put(columnComment.get("columnName"), columnComment.get("columnComment"));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void writeCycleShapefile(File shpFile, List<CycleShpRow> rows) throws Exception {
|
|
|
|
|
+ SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
|
|
|
|
|
+ typeBuilder.setName("project_cycle");
|
|
|
|
|
+ CoordinateReferenceSystem crs = CRS.decode("EPSG:4490");
|
|
|
|
|
+ typeBuilder.setCRS(crs);
|
|
|
|
|
+ typeBuilder.add("the_geom", MultiPolygon.class);
|
|
|
|
|
+
|
|
|
|
|
+ List<String> fields = rows.stream()
|
|
|
|
|
+ .flatMap(row -> row.attributes.keySet().stream())
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .sorted(this::compareCycleField)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ for (String field : fields) {
|
|
|
|
|
+ typeBuilder.length(254).add(field, String.class);
|
|
|
|
|
+ }
|
|
|
|
|
+ SimpleFeatureType featureType = typeBuilder.buildFeatureType();
|
|
|
|
|
+
|
|
|
|
|
+ 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);
|
|
|
|
|
+
|
|
|
|
|
+ WKTReader wktReader = new WKTReader();
|
|
|
|
|
+ Transaction transaction = new DefaultTransaction("create");
|
|
|
|
|
+ try (FeatureWriter<SimpleFeatureType, SimpleFeature> writer = dataStore.getFeatureWriterAppend(transaction)) {
|
|
|
|
|
+ for (CycleShpRow row : rows) {
|
|
|
|
|
+ Geometry geometry = parseEwkt(row.geom, wktReader);
|
|
|
|
|
+ if (geometry == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (geometry instanceof Polygon) {
|
|
|
|
|
+ geometry = geometry.getFactory().createMultiPolygon(new Polygon[]{(Polygon) geometry});
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ SimpleFeature feature = writer.next();
|
|
|
|
|
+ feature.setAttribute("the_geom", geometry);
|
|
|
|
|
+ for (String field : fields) {
|
|
|
|
|
+ Object value = row.attributes.get(field);
|
|
|
|
|
+ feature.setAttribute(field, value == null ? "" : trimDbfValue(String.valueOf(value)));
|
|
|
|
|
+ }
|
|
|
|
|
+ writer.write();
|
|
|
|
|
+ }
|
|
|
|
|
+ transaction.commit();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ transaction.rollback();
|
|
|
|
|
+ throw e;
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ transaction.close();
|
|
|
|
|
+ dataStore.dispose();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Geometry parseEwkt(String ewkt, WKTReader reader) {
|
|
|
|
|
+ if (StringUtils.isBlank(ewkt)) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ String wkt = ewkt.contains(";") ? ewkt.substring(ewkt.indexOf(";") + 1) : ewkt;
|
|
|
|
|
+ return reader.read(wkt);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("生命周期SHP几何解析失败: {}", e.getMessage());
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean shouldUseGyjsydscdjGeom(String tableName) {
|
|
|
|
|
+ return AloneWorkFlowEnum.NODE_4.getTableName().equalsIgnoreCase(tableName)
|
|
|
|
|
+ || AloneWorkFlowEnum.NODE_5.getTableName().equalsIgnoreCase(tableName)
|
|
|
|
|
+ || AloneWorkFlowEnum.NODE_6.getTableName().equalsIgnoreCase(tableName)
|
|
|
|
|
+ || AloneWorkFlowEnum.NODE_7.getTableName().equalsIgnoreCase(tableName);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String findProjectNodeId(String projectId, String tableName) {
|
|
|
|
|
+ List<ProjectWorkflow> workflows = projectWorkflowMapper.selectByProjectIdAndNodeTableName(projectId, tableName);
|
|
|
|
|
+ if (CollectionUtils.isEmpty(workflows)) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ return workflows.get(0).getNodeId();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean shouldSkipExportColumn(String columnName) {
|
|
|
|
|
+ if (StringUtils.isBlank(columnName)) {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ String column = columnName.toLowerCase();
|
|
|
|
|
+ return Arrays.asList("id", "project_id", "has_onchain", "created_at", "updated_at", "creator_id",
|
|
|
|
|
+ "geom", "shape", "shp", "shppath", "file_path", "file_name").contains(column);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String buildShpFieldName(String level, String comment, String columnName, Set<String> usedFieldNames) {
|
|
|
|
|
+ String initials = toInitials(StringUtils.defaultIfBlank(comment, columnName));
|
|
|
|
|
+ if (StringUtils.isBlank(initials)) {
|
|
|
|
|
+ initials = columnName.replaceAll("[^A-Za-z0-9]", "");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (StringUtils.isBlank(initials)) {
|
|
|
|
|
+ initials = "field";
|
|
|
|
|
+ }
|
|
|
|
|
+ String prefix = level + "_";
|
|
|
|
|
+ String base = prefix.toUpperCase(Locale.ROOT) + initials.toLowerCase(Locale.ROOT);
|
|
|
|
|
+ if (base.length() > 10) {
|
|
|
|
|
+ base = base.substring(0, 10);
|
|
|
|
|
+ }
|
|
|
|
|
+ String fieldName = base;
|
|
|
|
|
+ int index = 1;
|
|
|
|
|
+ while (usedFieldNames.contains(fieldName)) {
|
|
|
|
|
+ String suffix = String.valueOf(index++);
|
|
|
|
|
+ int maxBaseLength = Math.max(1, 10 - suffix.length());
|
|
|
|
|
+ fieldName = base.substring(0, Math.min(base.length(), maxBaseLength)) + suffix;
|
|
|
|
|
+ }
|
|
|
|
|
+ usedFieldNames.add(fieldName);
|
|
|
|
|
+ return fieldName;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private int compareCycleField(String field1, String field2) {
|
|
|
|
|
+ List<String> baseFields = Arrays.asList("id", "xmmc", "xmbm", "jsdw");
|
|
|
|
|
+ int baseIndex1 = baseFields.indexOf(field1);
|
|
|
|
|
+ int baseIndex2 = baseFields.indexOf(field2);
|
|
|
|
|
+ if (baseIndex1 >= 0 || baseIndex2 >= 0) {
|
|
|
|
|
+ if (baseIndex1 < 0) {
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (baseIndex2 < 0) {
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ return Integer.compare(baseIndex1, baseIndex2);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int level1 = getCycleFieldLevel(field1);
|
|
|
|
|
+ int level2 = getCycleFieldLevel(field2);
|
|
|
|
|
+ if (level1 != level2) {
|
|
|
|
|
+ return Integer.compare(level1, level2);
|
|
|
|
|
+ }
|
|
|
|
|
+ return field1.compareToIgnoreCase(field2);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private int getCycleFieldLevel(String field) {
|
|
|
|
|
+ if (StringUtils.isBlank(field) || !field.startsWith("L")) {
|
|
|
|
|
+ return Integer.MAX_VALUE;
|
|
|
|
|
+ }
|
|
|
|
|
+ int end = field.indexOf('_');
|
|
|
|
|
+ if (end <= 1) {
|
|
|
|
|
+ return Integer.MAX_VALUE;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ return Integer.parseInt(field.substring(1, end));
|
|
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
|
|
+ return Integer.MAX_VALUE;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String toInitials(String text) {
|
|
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
|
|
+ for (int i = 0; i < text.length(); i++) {
|
|
|
|
|
+ char ch = text.charAt(i);
|
|
|
|
|
+ if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')) {
|
|
|
|
|
+ sb.append(Character.toLowerCase(ch));
|
|
|
|
|
+ } else if (isChinese(ch)) {
|
|
|
|
|
+ sb.append(getChineseFirstLetter(ch));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return sb.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean isChinese(char ch) {
|
|
|
|
|
+ return Character.UnicodeScript.of(ch) == Character.UnicodeScript.HAN;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private char getChineseFirstLetter(char ch) {
|
|
|
|
|
+ String letters = "ABCDEFGHJKLMNOPQRSTWXYZ";
|
|
|
|
|
+ int[] areas = {45217, 45253, 45761, 46318, 46826, 47010, 47297, 47614, 48119, 49062, 49324, 49896,
|
|
|
|
|
+ 50371, 50614, 50622, 50906, 51387, 51446, 52218, 52698, 52980, 53689, 54481};
|
|
|
|
|
+ try {
|
|
|
|
|
+ byte[] bytes = String.valueOf(ch).getBytes("GBK");
|
|
|
|
|
+ if (bytes.length < 2) {
|
|
|
|
|
+ return Character.toLowerCase(ch);
|
|
|
|
|
+ }
|
|
|
|
|
+ int code = (bytes[0] & 0xff) * 256 + (bytes[1] & 0xff);
|
|
|
|
|
+ for (int i = areas.length - 1; i >= 0; i--) {
|
|
|
|
|
+ if (code >= areas[i]) {
|
|
|
|
|
+ return Character.toLowerCase(letters.charAt(i));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception ignored) {
|
|
|
|
|
+ }
|
|
|
|
|
+ return 'x';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String normalizeGeomKey(String ewkt) {
|
|
|
|
|
+ if (StringUtils.isBlank(ewkt)) {
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ return ewkt.replaceAll("\\s+", "").toUpperCase(Locale.ROOT);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String trimDbfValue(String value) {
|
|
|
|
|
+ if (value == null) {
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ return value.length() > 80 ? value.substring(0, 80) : value;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String safeFileName(String name) {
|
|
|
|
|
+ if (StringUtils.isBlank(name)) {
|
|
|
|
|
+ return "项目";
|
|
|
|
|
+ }
|
|
|
|
|
+ return name.replaceAll("[\\\\/:*?\"<>|]", "_");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void writeZipToResponse(File zipFile, String downloadName, HttpServletResponse response) throws IOException {
|
|
|
|
|
+ String encodedName = URLEncoder.encode(downloadName, StandardCharsets.UTF_8.name())
|
|
|
|
|
+ .replaceAll("\\+", "%20");
|
|
|
|
|
+ response.reset();
|
|
|
|
|
+ response.setContentType("application/zip");
|
|
|
|
|
+ response.setCharacterEncoding("utf-8");
|
|
|
|
|
+ response.setHeader("Content-Disposition", "attachment;filename=" + encodedName
|
|
|
|
|
+ + ";filename*=UTF-8''" + encodedName);
|
|
|
|
|
+ response.setContentLengthLong(zipFile.length());
|
|
|
|
|
+
|
|
|
|
|
+ try (FileInputStream fis = new FileInputStream(zipFile)) {
|
|
|
|
|
+ byte[] buffer = new byte[4096];
|
|
|
|
|
+ int len;
|
|
|
|
|
+ while ((len = fis.read(buffer)) > 0) {
|
|
|
|
|
+ response.getOutputStream().write(buffer, 0, len);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ response.getOutputStream().flush();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static class ProjectCycleExportNode {
|
|
|
|
|
+ private int level;
|
|
|
|
|
+ private String tableName;
|
|
|
|
|
+ private Map<String, Object> node;
|
|
|
|
|
+ private String geom;
|
|
|
|
|
+ private String geomKey;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static class CycleShpRow {
|
|
|
|
|
+ private String geom;
|
|
|
|
|
+ private final Map<String, Object> attributes = new LinkedHashMap<>();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private List<Map<String, Object>> buildCycleProjectRows(Project project, ProjectWorkflow workflow,
|
|
|
|
|
+ Map<String, Object> nodeData, String worktype) {
|
|
|
|
|
+ List<Map<String, String>> geomDetails = getCycleProjectGeomDetails(
|
|
|
|
|
+ project.getId(), workflow.getNodeTableName(), workflow);
|
|
|
|
|
+ if (CollectionUtils.isEmpty(geomDetails)) {
|
|
|
|
|
+ return Collections.singletonList(buildCycleProjectRow(project, workflow, nodeData, worktype, null));
|
|
|
|
|
+ }
|
|
|
|
|
+ List<Map<String, Object>> rows = new ArrayList<>();
|
|
|
|
|
+ for (Map<String, String> geomDetail : geomDetails) {
|
|
|
|
|
+ rows.add(buildCycleProjectRow(project, workflow, nodeData, worktype, geomDetail));
|
|
|
|
|
+ }
|
|
|
|
|
+ return rows;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Map<String, Object> buildCycleProjectRow(Project project, ProjectWorkflow workflow,
|
|
|
|
|
+ Map<String, Object> nodeData, String worktype,
|
|
|
|
|
+ Map<String, String> geomDetail) {
|
|
|
|
|
+ Map<String, Object> row = new LinkedHashMap<>();
|
|
|
|
|
+ if (nodeData != null) {
|
|
|
|
|
+ for (Map.Entry<String, Object> entry : nodeData.entrySet()) {
|
|
|
|
|
+ String key = toCamelCase(entry.getKey());
|
|
|
|
|
+ if ("id".equals(key)) {
|
|
|
|
|
+ row.put("businessId", entry.getValue());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ row.put(key, entry.getValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ row.put("id", project.getId());
|
|
|
|
|
+ row.put("projectId", project.getId());
|
|
|
|
|
+ row.put("projectName", project.getName());
|
|
|
|
|
+ row.put("projectCode", project.getCode());
|
|
|
|
|
+ row.put("projectCompany", project.getCompany());
|
|
|
|
|
+ row.put("name", project.getName());
|
|
|
|
|
+ row.put("code", project.getCode());
|
|
|
|
|
+ row.put("company", project.getCompany());
|
|
|
|
|
+ row.put("projectType", project.getProjectType());
|
|
|
|
|
+ row.put("onChainNum", project.getOnChainNum());
|
|
|
|
|
+ row.put("nodeId", workflow.getNodeId());
|
|
|
|
|
+ row.put("workflowId", workflow.getWorkflowId());
|
|
|
|
|
+ row.put("workflowName", workflow.getWorkflowName());
|
|
|
|
|
+ row.put("nodeTableName", workflow.getNodeTableName());
|
|
|
|
|
+ row.put("tableName", workflow.getNodeTableName());
|
|
|
|
|
+ row.put("worktype", worktype);
|
|
|
|
|
+ row.put("sjly", workflow.getNodeTableName());
|
|
|
|
|
+ if (geomDetail != null) {
|
|
|
|
|
+ row.put("geomId", geomDetail.get("id"));
|
|
|
|
|
+ row.put("geomNodeId", geomDetail.get("geomNodeId"));
|
|
|
|
|
+ row.put("geom", geomDetail.get("geom"));
|
|
|
|
|
+ row.put("geomArea", geomDetail.get("geom_area"));
|
|
|
|
|
+ row.put("landRowKey", project.getId() + "_" + workflow.getNodeId() + "_" + geomDetail.get("id"));
|
|
|
|
|
+ }
|
|
|
|
|
+ return row;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String toCamelCase(String value) {
|
|
|
|
|
+ if (StringUtils.isBlank(value) || !value.contains("_")) {
|
|
|
|
|
+ return value;
|
|
|
|
|
+ }
|
|
|
|
|
+ StringBuilder builder = new StringBuilder();
|
|
|
|
|
+ boolean upperNext = false;
|
|
|
|
|
+ for (char ch : value.toCharArray()) {
|
|
|
|
|
+ if (ch == '_') {
|
|
|
|
|
+ upperNext = true;
|
|
|
|
|
+ } else if (upperNext) {
|
|
|
|
|
+ builder.append(Character.toUpperCase(ch));
|
|
|
|
|
+ upperNext = false;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ builder.append(ch);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return builder.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 1.查询出所有的节点。
|
|
* 1.查询出所有的节点。
|
|
|
* 2.根据节点表名和项目id,查询出该节点表中该项目的上链数量。
|
|
* 2.根据节点表名和项目id,查询出该节点表中该项目的上链数量。
|
|
@@ -485,11 +1293,36 @@ public class ProjectImpl implements ProjectService {
|
|
|
String fileName = fileURL.getPath();
|
|
String fileName = fileURL.getPath();
|
|
|
String configStr = FileUtils.readFileToString(new File(fileName), StandardCharsets.UTF_8);
|
|
String configStr = FileUtils.readFileToString(new File(fileName), StandardCharsets.UTF_8);
|
|
|
JSONArray aa = JSON.parseArray(configStr);
|
|
JSONArray aa = JSON.parseArray(configStr);
|
|
|
- configStr = aa.toJSONString();
|
|
|
|
|
- log.info("------------" + configStr);
|
|
|
|
|
|
|
+ enrichCycleResourceData(aa);
|
|
|
|
|
+ log.info("------------" + aa.toJSONString());
|
|
|
return aa;
|
|
return aa;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private void enrichCycleResourceData(JSONArray nodes) {
|
|
|
|
|
+ if (nodes == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ for (Object item : nodes) {
|
|
|
|
|
+ if (!(item instanceof JSONObject)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ JSONObject node = (JSONObject) item;
|
|
|
|
|
+ String tableName = CYCLE_RESOURCE_TABLE_MAP.get(node.getString("id"));
|
|
|
|
|
+ if (StringUtils.isNotBlank(tableName)) {
|
|
|
|
|
+ String worktype = CYCLE_TABLE_WORKTYPE_MAP.get(tableName);
|
|
|
|
|
+ node.put("source", tableName);
|
|
|
|
|
+ node.put("nodeTableName", tableName);
|
|
|
|
|
+ node.put("tableName", tableName);
|
|
|
|
|
+ node.put("sjly", tableName);
|
|
|
|
|
+ node.put("worktype", worktype);
|
|
|
|
|
+ }
|
|
|
|
|
+ Object children = node.get("children");
|
|
|
|
|
+ if (children instanceof JSONArray) {
|
|
|
|
|
+ enrichCycleResourceData((JSONArray) children);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Override
|
|
@Override
|
|
|
public void testData() {
|
|
public void testData() {
|
|
|
// String nodeId = null;
|
|
// String nodeId = null;
|