From 10d76bee557414829712f1d747044ff25275184c Mon Sep 17 00:00:00 2001 From: Zhao Date: Fri, 12 Sep 2025 17:28:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=87=BA=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/TTaskExportController.java | 49 ++- .../business/TTaskImportController.java | 6 +- .../src/main/resources/application.yml | 6 + ruoyi-admin/src/test/java/GeoTest.java | 56 +++- .../business/mapper/TTaskExportMapper.java | 4 + .../ruoyi/geo/config/GeoExportTaskConfig.java | 22 ++ .../com/ruoyi/geo/constants/GeoSysDir.java | 32 +- .../geo/framework/GeoCjqyExportTask.java | 62 ++++ ...eoCjqyTask.java => GeoCjqyImportTask.java} | 36 +- .../framework/GeoDBExportTaskInterface.java | 11 + ...ace.java => GeoDBImportTaskInterface.java} | 2 +- .../ruoyi/geo/framework/GeoExportTask.java | 315 ++++++++++++++++++ .../ruoyi/geo/framework/GeoImportTask.java | 18 +- .../geo/framework/GeoJtzyExportTask.java | 79 +++++ ...eoJtzyTask.java => GeoJtzyImportTask.java} | 35 +- .../geo/framework/GeoZyhycgExportTask.java | 74 ++++ ...hycgTask.java => GeoZyhycgImportTask.java} | 36 +- .../geo/service/GeoExportHandlerService.java | 268 +++++++++++++++ .../geo/service/GeoImportHandlerService.java | 66 +--- .../ruoyi/geo/service/GeoMapperService.java | 92 +++++ .../mapper/business/TTaskExportMapper.xml | 11 + .../common/core/domain/entity/SysDept.java | 6 + .../java/com/ruoyi/common/geo/GeoCreator.java | 160 +++++++++ .../java/com/ruoyi/common/geo/GeoWriter.java | 278 ++++++++++++++++ .../resources/mapper/system/SysDeptMapper.xml | 1 + 25 files changed, 1604 insertions(+), 121 deletions(-) create mode 100644 ruoyi-business/src/main/java/com/ruoyi/geo/config/GeoExportTaskConfig.java create mode 100644 ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoCjqyExportTask.java rename ruoyi-business/src/main/java/com/ruoyi/geo/framework/{GeoCjqyTask.java => GeoCjqyImportTask.java} (82%) create mode 100644 ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoDBExportTaskInterface.java rename ruoyi-business/src/main/java/com/ruoyi/geo/framework/{GeoDBTaskInterface.java => GeoDBImportTaskInterface.java} (74%) create mode 100644 ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoExportTask.java create mode 100644 ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoJtzyExportTask.java rename ruoyi-business/src/main/java/com/ruoyi/geo/framework/{GeoJtzyTask.java => GeoJtzyImportTask.java} (84%) create mode 100644 ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoZyhycgExportTask.java rename ruoyi-business/src/main/java/com/ruoyi/geo/framework/{GeoZyhycgTask.java => GeoZyhycgImportTask.java} (84%) create mode 100644 ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoExportHandlerService.java create mode 100644 ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoMapperService.java create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/geo/GeoCreator.java create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/geo/GeoWriter.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/business/TTaskExportController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/business/TTaskExportController.java index 10ffda7..49414a8 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/business/TTaskExportController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/business/TTaskExportController.java @@ -14,6 +14,8 @@ import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.pdf.PdfUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.utils.translation.TranslateUtils; +import com.ruoyi.geo.service.GeoExportHandlerService; +import com.ruoyi.geo.service.GeoImportHandlerService; import com.ruoyi.system.service.ISysDeptService; import org.apache.commons.compress.utils.Lists; import org.springframework.beans.factory.annotation.Autowired; @@ -38,7 +40,9 @@ public class TTaskExportController extends BaseController private ITTaskExportService tTaskExportService; @Autowired - private ISysDeptService deptService; + private ISysDeptService deptService; + @Autowired + private GeoExportHandlerService exportHandlerService; /** * 查询导出任务列表 @@ -198,4 +202,47 @@ public class TTaskExportController extends BaseController PdfUtils.initPdf(response, pdf); } + + /** + * 开始导出任务 + */ + @PreAuthorize("@ss.hasPermi('business:export:do')") + @Log(title = "开始导入任务", businessType = BusinessType.UPDATE) + @PostMapping("/start/{taskId}") + public AjaxResult start(@PathVariable Long taskId) + { + return AjaxResult.success(exportHandlerService.startTask(taskId)); + } + + /** + * 获取导出任务日志 + */ + @PreAuthorize("@ss.hasPermi('business:export:do')") + @GetMapping("/log/{taskId}") + public AjaxResult log(@PathVariable Long taskId, Integer offset) + { + if(null == offset) + offset = 0; + return AjaxResult.success(exportHandlerService.loadExportLog(taskId, offset)); + } + + /** + * 下载导出任务日志 + */ + @PreAuthorize("@ss.hasPermi('business:export:do')") + @GetMapping("/downloadLog/{taskId}") + public void downloadLog(@PathVariable Long taskId, HttpServletResponse response) + { + exportHandlerService.downloadLog(taskId, response); + } + + /** + * 下载导出任务文件 + */ + @PreAuthorize("@ss.hasPermi('business:export:down')") + @GetMapping("/downloadFile/{taskId}") + public void downloadFile(@PathVariable Long taskId, HttpServletResponse response) + { + exportHandlerService.downloadFile(taskId, response); + } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/business/TTaskImportController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/business/TTaskImportController.java index db1a138..5fdcaa5 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/business/TTaskImportController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/business/TTaskImportController.java @@ -214,7 +214,7 @@ public class TTaskImportController extends BaseController @PostMapping("/start/{taskId}") public AjaxResult start(@PathVariable Long taskId) { - return AjaxResult.success(importHandlerService.StartTask(taskId)); + return AjaxResult.success(importHandlerService.startTask(taskId)); } /** @@ -226,7 +226,7 @@ public class TTaskImportController extends BaseController { if(null == offset) offset = 0; - return AjaxResult.success(importHandlerService.GetImportLog(taskId, offset)); + return AjaxResult.success(importHandlerService.loadImportLog(taskId, offset)); } /** @@ -236,6 +236,6 @@ public class TTaskImportController extends BaseController @GetMapping("/downloadLog/{taskId}") public void downloadLog(@PathVariable Long taskId, HttpServletResponse response) { - importHandlerService.DownloadLog(taskId, response); + importHandlerService.downloadLog(taskId, response); } } diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 920f76b..8ace2ed 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -135,6 +135,12 @@ xss: urlPatterns: /system/*,/monitor/*,/tool/* importTask: + # 是否启动时执行等待中的任务 + startOnBoot: false + # 下次建议读取日志的间隔(毫秒) + logNextPoll: 2000 + +exportTask: # 是否启动时执行等待中的任务 startOnBoot: false # 下次建议读取日志的间隔(毫秒) diff --git a/ruoyi-admin/src/test/java/GeoTest.java b/ruoyi-admin/src/test/java/GeoTest.java index 6b6cdf0..3f3969a 100644 --- a/ruoyi-admin/src/test/java/GeoTest.java +++ b/ruoyi-admin/src/test/java/GeoTest.java @@ -1,15 +1,21 @@ +import cn.hutool.core.io.FileUtil; import cn.hutool.core.thread.ThreadUtil; import com.alibaba.fastjson2.JSON; import com.ruoyi.RuoYiApplication; import com.ruoyi.common.geo.GeoParser; +import com.ruoyi.common.geo.GeoWriter; +import com.ruoyi.geo.service.GeoExportHandlerService; import com.ruoyi.geo.service.GeoImportHandlerService; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.locationtech.jts.geom.MultiPolygon; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit.jupiter.SpringExtension; import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -19,13 +25,16 @@ import java.util.Map; public final class GeoTest { @Resource - private GeoImportHandlerService service; + private GeoImportHandlerService importer; + @Resource + private GeoExportHandlerService exporter; @Test public void test() { - service.StartTask(4L); + //service.startTask(4L); //new Scanner(System.in).next(); + exporter.startTask(3L); ThreadUtil.sleep(5000); } @@ -36,18 +45,39 @@ public final class GeoTest PATH = "D:/m/胜利村_shp_3857/dk.shp"; // dk PATH = "D:/m/胜利村_shp_3857/zyhycg.shp"; // zyhycg PATH = "D:/m/胜利村_shp_3857/jtzy.shp"; // jtzy - try(GeoParser geo = new GeoParser()) + + String OUT; + OUT = "D:/m/output_胜利村_shp_3857/jtzyxx.shp"; + + FileUtil.mkParentDirs(OUT); + + try(GeoParser parser = new GeoParser()) { - geo.Open(PATH, "UTF-8"); - System.err.println(geo.GetTypeNames()); - geo.SetSource(0); - List> cjqies = geo.GetMapList(); - //List cjqies = geo.GetList(GeoCJQY.class); - //List cjqies = geo.GetList(GeoJTZY.class); - //List cjqies = geo.GetList(GeoZYHYCG.class); - //List cjqies = geo.GetList(GeoDK.class); - - System.err.println(JSON.toJSONString(cjqies)); + parser.Open(PATH, "UTF-8"); + System.out.println(parser.GetTypeNames()); + parser.SetSource(0); + List> cjqies = parser.GetMapList(); + //List cjqies = parser.GetList(GeoCJQY.class); + //List cjqies = parser.GetList(GeoJTZY.class); + //List cjqies = parser.GetList(GeoZYHYCG.class); + //List cjqies = parser.GetList(GeoDK.class); + + System.out.println(JSON.toJSONString(cjqies)); + System.out.println("-------------------------"); + + try(GeoWriter writer = new GeoWriter()) + { + writer.Open(OUT, "UTF-8"); + Map> classes = new LinkedHashMap<>(); + classes.put("QSDWDM", String.class); + classes.put("QSDWMC", String.class); + classes.put("Shape_Area", BigDecimal.class); + classes.put("the_geom", MultiPolygon.class); + writer.AddSchema("test123", classes); + System.out.println(writer.GetTypeNames()); + writer.SetSource(0, false); + writer.WriteMapList(cjqies); + } } } } diff --git a/ruoyi-business/src/main/java/com/ruoyi/business/mapper/TTaskExportMapper.java b/ruoyi-business/src/main/java/com/ruoyi/business/mapper/TTaskExportMapper.java index b636110..dd518b1 100644 --- a/ruoyi-business/src/main/java/com/ruoyi/business/mapper/TTaskExportMapper.java +++ b/ruoyi-business/src/main/java/com/ruoyi/business/mapper/TTaskExportMapper.java @@ -2,6 +2,7 @@ package com.ruoyi.business.mapper; import java.util.List; import com.ruoyi.business.domain.TTaskExport; +import com.ruoyi.business.domain.TTaskImport; /** * 导出任务Mapper接口 @@ -74,4 +75,7 @@ public interface TTaskExportMapper * @return 结果 */ public int deleteTTaskExportByIds(Long[] ids); + + public int terminateRunningTask(); + public TTaskExport getForUpdate(Long id); } diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/config/GeoExportTaskConfig.java b/ruoyi-business/src/main/java/com/ruoyi/geo/config/GeoExportTaskConfig.java new file mode 100644 index 0000000..6e96c74 --- /dev/null +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/config/GeoExportTaskConfig.java @@ -0,0 +1,22 @@ +package com.ruoyi.geo.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "export-task") +public class GeoExportTaskConfig +{ + public static boolean startOnBoot = false; // 是否启动时执行等待中的任务 + public static long logNextPoll = 2000; // 下次建议读取日志的间隔(毫秒) + + public void setStartOnBoot(boolean startOnBoot) + { + GeoExportTaskConfig.startOnBoot = startOnBoot; + } + + public void setLogNextPoll(long logNextPoll) + { + GeoExportTaskConfig.logNextPoll = logNextPoll; + } +} diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/constants/GeoSysDir.java b/ruoyi-business/src/main/java/com/ruoyi/geo/constants/GeoSysDir.java index 1bb7920..c276bda 100644 --- a/ruoyi-business/src/main/java/com/ruoyi/geo/constants/GeoSysDir.java +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/constants/GeoSysDir.java @@ -6,9 +6,25 @@ import com.ruoyi.common.utils.StringUtils; public final class GeoSysDir { // 导入日志路径 - public static final String LOG = "/log"; + public static final String LOG = "/log"; // 导入zip临时解压路径 - public static final String ZIP_EXTRACT_TEMP = "/unzip"; + public static final String UNZIP_DECOMPRESS_TEMP = "/unzip"; + // 导出zip临时生成路径 + public static final String ZIP_COMPRESS_TEMP = "/zip"; + // 导出zip临时生成路径 + public static final String ZIP_FILE_TEMP = "/zip_temp"; + // 导出zip临时生成路径 + public static final String ZIP_DOWNLOAD = "/zip"; + + public static String TrimProfile(String path) + { + if(StringUtils.isEmpty(path)) + return ""; + else if(path.startsWith("/profile")) + return path.substring("/profile".length()); + else + return path; + } public static String GetDir(String path) { @@ -68,5 +84,17 @@ public final class GeoSysDir return "" + fpath.substring(fprofile.length()); } + public static String TrimNormalized(String path) + { + if(StringUtils.isEmpty(path)) + return path; + + String fpath = path.replaceAll("\\\\", "/"); + String fprofile = RuoYiConfig.getProfile().replaceAll("\\\\", "/"); + if(!fpath.startsWith(fprofile)) + return path; + return fpath.substring(fprofile.length()); + } + private GeoSysDir() {} } diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoCjqyExportTask.java b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoCjqyExportTask.java new file mode 100644 index 0000000..2773a08 --- /dev/null +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoCjqyExportTask.java @@ -0,0 +1,62 @@ +package com.ruoyi.geo.framework; + +import com.ruoyi.business.domain.TGisCjqy; +import com.ruoyi.common.geo.GeoCreator; +import com.ruoyi.geo.service.GeoMapperService; +import com.ruoyi.geo.structs.GeoCJQY; +import org.locationtech.jts.geom.MultiPolygon; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class GeoCjqyExportTask implements GeoDBExportTaskInterface +{ + private final static String TYPE_NAME = "村级区域"; + + private final GeoExportTask exportTask; + private List list; + + public GeoCjqyExportTask(GeoExportTask exportTask) + { + this.exportTask = exportTask; + } + + public int LoadDataList() + { + TGisCjqy cond = new TGisCjqy(); + cond.setImportCode(exportTask.dept.getImportCode()); + list = GeoMapperService.GisCjqyMapper().selectTGisCjqyList(cond); + exportTask.logFile.WriteLine(TYPE_NAME + "读取系统数据条数: 区划代码={}, 条数={}", exportTask.dept.getImportCode(), list.size()); + + return list.size(); + } + + private GeoCJQY ConvertData(TGisCjqy src, GeoCJQY dst) + { + if(null == dst) + dst = new GeoCJQY(); + dst.the_geom = src.getTheGeom(); + dst.BSM = src.getBsm().intValue(); + dst.YSDM = src.getYsdm(); + dst.CJQYDM = src.getCjqydm(); + dst.CJQYMC = src.getCjqymc(); + return dst; + } + + public void SaveData() + { + exportTask.logFile.WriteLine(TYPE_NAME + "开始导出数据: 区划代码={}, 条数={}", exportTask.dept.getDeptName(), list.size()); + + List dataList = list.stream().map((x) -> ConvertData(x, null)).collect(Collectors.toList()); + + exportTask.writer.WriteList(dataList); + } + + public Map> GetTypes() + { + Map> types = GeoCreator.GetClassTypes(GeoCJQY.class); + types.put("the_geom", MultiPolygon.class); + return types; + } +} diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoCjqyTask.java b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoCjqyImportTask.java similarity index 82% rename from ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoCjqyTask.java rename to ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoCjqyImportTask.java index 40211a9..e52e638 100644 --- a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoCjqyTask.java +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoCjqyImportTask.java @@ -6,7 +6,9 @@ import com.ruoyi.business.mapper.TGisCjqyMapper; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.geo.service.GeoImportHandlerService; +import com.ruoyi.geo.service.GeoMapperService; import com.ruoyi.geo.structs.GeoCJQY; + import static com.ruoyi.business.constants.TaskEnums.ImportType; import java.util.ArrayList; @@ -14,14 +16,14 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -public class GeoCjqyTask implements GeoDBTaskInterface +public class GeoCjqyImportTask implements GeoDBImportTaskInterface { private final static String TYPE_NAME = "村级区域"; private final GeoImportTask importTask; private List list; - public GeoCjqyTask(GeoImportTask importTask) + public GeoCjqyImportTask(GeoImportTask importTask) { this.importTask = importTask; } @@ -64,7 +66,7 @@ public class GeoCjqyTask implements GeoDBTaskInterface { TGisCjqy cond = new TGisCjqy(); cond.setCjqydm(qydm); - List cjqies = GeoImportHandlerService.GisCjqyMapper().selectTGisCjqyList(cond); + List cjqies = GeoMapperService.GisCjqyMapper().selectTGisCjqyList(cond); importTask.logFile.WriteLine(TYPE_NAME + "读取系统已存在的条数: 区划代码={}, 条数={}", qydm, cjqies.size()); return cjqies; } @@ -87,7 +89,7 @@ public class GeoCjqyTask implements GeoDBTaskInterface if(ImportType.IT_OVERRIDE.equals(importTask.taskImport.getImportType())) { importTask.logFile.WriteLine(TYPE_NAME + "覆盖导入, 需清空现有数据, 然后再插入, 区划代码={}", importCode); - int ret = GeoImportHandlerService.GisCjqyMapper().deleteByCode(importCode); + int ret = GeoMapperService.GisCjqyMapper().deleteByCode(importCode); importTask.logFile.WriteLine(TYPE_NAME + "清空现有数据: {}, 区划代码={}", ret, importCode); return ret; } @@ -100,7 +102,7 @@ public class GeoCjqyTask implements GeoDBTaskInterface private int WriteData(List insertList, List updateList, SysDept dept) { - TGisCjqyMapper gisCjqyMapper = GeoImportHandlerService.GisCjqyMapper(); + TGisCjqyMapper gisCjqyMapper = GeoMapperService.GisCjqyMapper(); int i = ListUtil.split(insertList, 50).stream().map(gisCjqyMapper::insertTGisCjqyBatch).reduce(0, Integer::sum); importTask.logFile.WriteLine(TYPE_NAME + "新增数据: 区划代码={}, 条数={}", dept.getDeptName(), i); int u = ListUtil.split(updateList, 50).stream().map(gisCjqyMapper::updateTGisCjqyBatch).reduce(0, Integer::sum); @@ -111,21 +113,29 @@ public class GeoCjqyTask implements GeoDBTaskInterface private int SaveDeptData(SysDept dept, List datas) { importTask.logFile.WriteLine(TYPE_NAME + "开始处理数据: 区划代码={}, 条数={}", dept.getDeptName(), datas.size()); - List databases = LoadDatabase(dept.getImportCode()); - Map exists = databases.stream().collect(Collectors.toMap(TGisCjqy::getCjqydm, x->x)); + boolean needCheck = !ImportType.IT_OVERRIDE.equals(importTask.taskImport.getImportType()); + Map exists = null; + if(needCheck) + { + List databases = LoadDatabase(dept.getImportCode()); + exists = databases.stream().collect(Collectors.toMap(TGisCjqy::getCjqydm, x->x)); + } List insertList = new ArrayList<>(); List updateList = new ArrayList<>(); for(GeoCJQY data : datas) { - TGisCjqy db = exists.get(data.CJQYDM); - boolean has = null == db; - db = ConvertData(data, db, dept); - if(has) - insertList.add(db); + TGisCjqy db = null; + if(needCheck) + { + db = exists.get(data.CJQYDM); + } + TGisCjqy item = ConvertData(data, db, dept); + if(null == db) + insertList.add(item); else - updateList.add(db); + updateList.add(item); } CleanDatabase(dept.getImportCode()); diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoDBExportTaskInterface.java b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoDBExportTaskInterface.java new file mode 100644 index 0000000..4942e88 --- /dev/null +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoDBExportTaskInterface.java @@ -0,0 +1,11 @@ +package com.ruoyi.geo.framework; + +import java.util.List; +import java.util.Map; + +public interface GeoDBExportTaskInterface +{ + public Map> GetTypes(); + public int LoadDataList(); + public void SaveData(); +} diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoDBTaskInterface.java b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoDBImportTaskInterface.java similarity index 74% rename from ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoDBTaskInterface.java rename to ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoDBImportTaskInterface.java index 8c0b438..6d0d861 100644 --- a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoDBTaskInterface.java +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoDBImportTaskInterface.java @@ -1,6 +1,6 @@ package com.ruoyi.geo.framework; -public interface GeoDBTaskInterface +public interface GeoDBImportTaskInterface { public int LoadDataList(); public void CheckData(); diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoExportTask.java b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoExportTask.java new file mode 100644 index 0000000..12907f1 --- /dev/null +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoExportTask.java @@ -0,0 +1,315 @@ +package com.ruoyi.geo.framework; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.ZipUtil; +import com.ruoyi.business.domain.TTaskExport; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.core.domain.entity.SysDept; +import com.ruoyi.common.geo.GeoWriter; +import com.ruoyi.common.utils.ExceptionUtil; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.common.utils.sql.DB; +import com.ruoyi.geo.constants.GeoShpType; +import com.ruoyi.geo.constants.GeoSysDir; +import com.ruoyi.geo.service.GeoExportHandlerService; +import com.ruoyi.geo.service.GeoMapperService; +import com.ruoyi.system.mapper.SysDeptMapper; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.ruoyi.business.constants.TaskEnums.TaskStatus; + +@Slf4j +public class GeoExportTask implements Runnable +{ + private final Long taskId; + TTaskExport taskExport; + GeoTaskLog logFile; + GeoWriter writer; + private final List typeNames = Arrays.asList( + GeoShpType.CJQY, + GeoShpType.JTZY, + GeoShpType.ZYHYCG + ); + private Map> typeClasses; + private String shpFile; + private String type; + String username; + Date now; + SysDept dept; + + private GeoDBExportTaskInterface task; + + public GeoExportTask(Long taskId) + { + this.taskId = taskId; + } + + public void Init() + { + now = new Date(); + username = "admin"; //SecurityUtils.getUsername(); + String path = LogPath(); + log.info("任务{}日志文件: {}", taskId, path); + logFile = new GeoTaskLog(path); + logFile.Open(); + logFile.WriteLine("任务初始化: {} - {}", taskId, DateUtil.format(now, "yyyy-MM-dd HH:mm:ss.SSS")); + } + + public void Shutdown() + { + //CleanTempFiles(); + + logFile.WriteLine("任务结束: {} - {}", taskId, DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")); + if(null != logFile) + { + logFile.close(); + } + log.info("任务{}日志文件: {}", taskId, GeoSysDir.DesensitizedNormalized(LogPath())); + } + + private String ZipCachePath() + { + return GeoSysDir.CacheDir(GeoSysDir.ZIP_COMPRESS_TEMP + "/" + taskId); + } + + private String ZipTempFilePath() + { + return GeoSysDir.CacheDir(GeoSysDir.ZIP_FILE_TEMP + "/" + taskId + ".zip.temp"); + } + + private String ZipFilePath() + { + return GeoSysDir.ExportDir(GeoSysDir.ZIP_DOWNLOAD + "/" + taskId + ".zip"); + } + + public String LogPath() + { + return GeoSysDir.ExportDir(GeoSysDir.LOG) + "/" + taskId + ".log"; + } + + private void Ready() + { + // 先清空源临时解压文件 + CleanTempFiles(); + + String toDir = ZipCachePath(); + FileUtil.mkdir(toDir); + + FileUtil.mkParentDirs(ZipFilePath()); + } + + private void CleanTempFiles() + { + String toDir = ZipCachePath(); + logFile.WriteLine("清理临时文件: " + GeoSysDir.DesensitizedNormalized(toDir)); + FileUtil.del(toDir); + } + + private void Compress() + { + String cacheDir = ZipCachePath(); + logFile.WriteLine("开始压缩临时shp文件: " + GeoSysDir.DesensitizedNormalized(cacheDir)); + String zipTempFile = ZipTempFilePath(); + FileUtil.mkParentDirs(zipTempFile); + logFile.WriteLine("生成临时zip文件: " + GeoSysDir.DesensitizedNormalized(zipTempFile)); + ZipUtil.zip(cacheDir, ZipTempFilePath()); + String zipFile = ZipFilePath(); + FileUtil.mkParentDirs(zipFile); + + if(StringUtils.isNotEmpty(taskExport.getFileUrl())) + { + File file = new File(RuoYiConfig.getProfile() + "/" + GeoSysDir.TrimProfile(taskExport.getFileUrl())); + if(file.isFile()) + { + logFile.WriteLine("删除之前的zip文件: " + GeoSysDir.DesensitizedNormalized(file.getAbsolutePath())); + file.delete(); + } + } + + logFile.WriteLine("复制zip到下载目录: " + GeoSysDir.DesensitizedNormalized(zipFile)); + FileUtil.move(new File(zipTempFile), new File(zipFile), true); + + taskExport.setFileUrl("/profile" + GeoSysDir.TrimNormalized(zipFile)); + } + + private void CreateShp() + { + writer = new GeoWriter(); + + if(!writer.Open(shpFile, "UTF-8")) + { + logFile.ErrorLine("打开shp文件错误: " + shpFile); + } + + try + { + writer.AddSchema(type, typeClasses); + + System.out.println(writer.GetTypeNames()); + if(!writer.SetSource(type, false)) + { + logFile.ErrorLine("shp文件未找到支持源: " + type); + return; + } + + task.SaveData(); + } + catch(Exception e) + { + e.printStackTrace(); + } + finally + { + writer.close(); + writer = null; + } + } + + private void LoadDept() + { + dept = GeoMapperService.DeptMapper().selectDeptByOrgCode(taskExport.getOrgCode()); + } + + private void LoadTask() + { + TTaskExport task = GeoMapperService.TaskExportMapper().getForUpdate(taskId); + if(null == task) + { + logFile.ErrorLine("任务配置不存在: " + taskId); + return; + } + if(!TaskStatus.ST_WAIT.equals(task.getTaskStatus())) + { + logFile.ErrorLine("任务非等待状态: " + taskId); + return; + } + taskExport = task; + } + + private void SaveTask(String st) + { + if(null != taskExport) + { + taskExport.setTaskStatus(st); + GeoMapperService.TaskExportMapper().updateTTaskExport(taskExport); + } + } + + private void HandleShpTypes() + { + for(String shpType : typeNames) + { + type = shpType; + // 2. 分发任务 + DispatchTask(); + } + } + + private void DispatchTask() + { + // 1. 选择任务类型 + switch(type.toLowerCase()) + { + case GeoShpType.CJQY: + task = new GeoCjqyExportTask(this); + break; + case GeoShpType.JTZY: + task = new GeoJtzyExportTask(this); + break; + case GeoShpType.ZYHYCG: + task = new GeoZyhycgExportTask(this); + break; + default: + logFile.WriteLine("数据类型不支持: " + type); + return; + } + // 2. 处理导入任务 + DoTask(); + } + + private void CreateShpFile() + { + shpFile = ZipCachePath() + "/"/* + group + "/"*/ + type.toLowerCase() + ".shp"; + FileUtil.mkParentDirs(shpFile); + } + + private void DoTask() + { + typeClasses = task.GetTypes(); + + int num = task.LoadDataList(); + if(num == 0) + { + logFile.WriteLine("数据库支持源未读取到数据: " + type); + return; + } + + CreateShpFile(); + CreateShp(); + } + + private void Handle() + { + // 0. 初始化任务: 打开日志系统 + Init(); + + // 1. 加载任务配置, 并检查 + LoadTask(); + + // 2. 读取文件, 解压文件到工作目录 + Ready(); + + // 3. 加载部门数据 + LoadDept(); + + // 4. 依次处理所有shp文件 + HandleShpTypes(); + + // 5. 压缩 + Compress(); + } + + @Override + public void run() + { + Object handle = null; + try + { + handle = DB.BeginTransaction(); + + Handle(); + + // 更改任务状态为已完成 + SaveTask(TaskStatus.ST_FINISH); + } + catch(Exception e) + { + e.printStackTrace(); + logFile.WriteLine(ExceptionUtil.getExceptionMessage(e)); + SaveTask(TaskStatus.ST_FAIL); + } + finally + { + DB.EndTransaction(handle); + // -1: 终止任务, 关闭日志系统 + Shutdown(); + } + } + + public Long GetTaskId() + { + return taskId; + } +} diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoImportTask.java b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoImportTask.java index c97ea47..798aee3 100644 --- a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoImportTask.java +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoImportTask.java @@ -14,6 +14,7 @@ import com.ruoyi.common.utils.sql.DB; import com.ruoyi.geo.constants.GeoShpType; import com.ruoyi.geo.constants.GeoSysDir; import com.ruoyi.geo.service.GeoImportHandlerService; +import com.ruoyi.geo.service.GeoMapperService; import com.ruoyi.system.mapper.SysDeptMapper; import lombok.extern.slf4j.Slf4j; import static com.ruoyi.business.constants.TaskEnums.TaskStatus; @@ -40,7 +41,7 @@ public class GeoImportTask implements Runnable String username; Date now; - private GeoDBTaskInterface task; + private GeoDBImportTaskInterface task; public GeoImportTask(Long taskId) { @@ -72,7 +73,7 @@ public class GeoImportTask implements Runnable private String UnzipCachePath() { - return GeoSysDir.CacheDir(GeoSysDir.ZIP_EXTRACT_TEMP + "/" + taskId); + return GeoSysDir.CacheDir(GeoSysDir.UNZIP_DECOMPRESS_TEMP + "/" + taskId); } public String LogPath() @@ -157,15 +158,14 @@ public class GeoImportTask implements Runnable private void LoadDept() { SysDept cond = new SysDept(); - SysDeptMapper deptMapper = SpringUtils.getBean(SysDeptMapper.class); - List sysDepts = deptMapper.selectDeptList(cond); + List sysDepts = GeoMapperService.DeptMapper().selectDeptList(cond); importDeptMap = sysDepts.stream().collect(Collectors.toMap(SysDept::getImportCode, x -> x)); sysDeptMap = sysDepts.stream().collect(Collectors.toMap(SysDept::getOrgCode, x -> x)); } private void LoadTask() { - TTaskImport task = GeoImportHandlerService.TaskImportMapper().getForUpdate(taskId); + TTaskImport task = GeoMapperService.TaskImportMapper().getForUpdate(taskId); if(null == task) { logFile.ErrorLine("任务配置不存在: " + taskId); @@ -184,7 +184,7 @@ public class GeoImportTask implements Runnable if(null != taskImport) { taskImport.setTaskStatus(st); - GeoImportHandlerService.TaskImportMapper().updateTTaskImport(taskImport); + GeoMapperService.TaskImportMapper().updateTTaskImport(taskImport); } } @@ -215,13 +215,13 @@ public class GeoImportTask implements Runnable switch(type.toLowerCase()) { case GeoShpType.CJQY: - task = new GeoCjqyTask(this); + task = new GeoCjqyImportTask(this); break; case GeoShpType.JTZY: - task = new GeoJtzyTask(this); + task = new GeoJtzyImportTask(this); break; case GeoShpType.ZYHYCG: - task = new GeoZyhycgTask(this); + task = new GeoZyhycgImportTask(this); break; default: logFile.WriteLine("数据类型不支持: " + type); diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoJtzyExportTask.java b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoJtzyExportTask.java new file mode 100644 index 0000000..82d5ac0 --- /dev/null +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoJtzyExportTask.java @@ -0,0 +1,79 @@ +package com.ruoyi.geo.framework; + +import com.ruoyi.common.geo.GeoCreator; +import com.ruoyi.geo.service.GeoExportHandlerService; +import com.ruoyi.geo.service.GeoMapperService; +import com.ruoyi.geo.structs.GeoJTZY; +import com.ruoyi.resource.domain.TResourceLand; +import org.locationtech.jts.geom.MultiPolygon; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class GeoJtzyExportTask implements GeoDBExportTaskInterface +{ + private final static String TYPE_NAME = "地块属性"; + + private final GeoExportTask exportTask; + private List list; + + public GeoJtzyExportTask(GeoExportTask exportTask) + { + this.exportTask = exportTask; + } + + public int LoadDataList() + { + TResourceLand cond = new TResourceLand(); + cond.setImportCode(exportTask.dept.getImportCode()); + list = GeoMapperService.ResourceLandMapper().selectTResourceLandList(cond); + exportTask.logFile.WriteLine(TYPE_NAME + "读取系统数据条数: 区划代码={}, 条数={}", exportTask.dept.getImportCode(), list.size()); + + return list.size(); + } + + private GeoJTZY ConvertData(TResourceLand src, GeoJTZY dst) + { + if(null == dst) + dst = new GeoJTZY(); + dst.the_geom = src.getTheGeom(); + dst.BSM = src.getBsm(); + dst.YSDM = src.getYsdm(); + dst.DKBM = src.getDkbm(); + dst.DKMC = src.getDkmc(); + dst.SYQXZ = src.getSyqxz(); + dst.DKLB = src.getDklb(); + dst.DLDJ = src.getDldj(); + dst.TDYT = src.getTdyt(); + dst.SFJBNT = src.getSfjbnt(); + dst.DKDZ = src.getDkdz(); + dst.DKXZ = src.getDkxz(); + dst.DKNZ = src.getDknz(); + dst.DKBZ = src.getDkbz(); + dst.ZJRXM = src.getZjrxm(); + dst.DKBZXX = src.getDkbzxx(); + dst.TXMJ = src.getTxmj(); + dst.QSDWDM = src.getQsdwdm(); + dst.QSDWMC = src.getQsdwmc(); + dst.SFZWD = src.getSfzwd(); + dst.SCMJM = src.getScmjm(); + return dst; + } + + public void SaveData() + { + exportTask.logFile.WriteLine(TYPE_NAME + "开始导出数据: 区划代码={}, 条数={}", exportTask.dept.getDeptName(), list.size()); + + List dataList = list.stream().map((x) -> ConvertData(x, null)).collect(Collectors.toList()); + + exportTask.writer.WriteList(dataList); + } + + public Map> GetTypes() + { + Map> types = GeoCreator.GetClassTypes(GeoJTZY.class); + types.put("the_geom", MultiPolygon.class); + return types; + } +} diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoJtzyTask.java b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoJtzyImportTask.java similarity index 84% rename from ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoJtzyTask.java rename to ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoJtzyImportTask.java index cd94ff8..ab3a271 100644 --- a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoJtzyTask.java +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoJtzyImportTask.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.ListUtil; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.geo.service.GeoImportHandlerService; +import com.ruoyi.geo.service.GeoMapperService; import com.ruoyi.geo.structs.GeoJTZY; import com.ruoyi.resource.domain.TResourceLand; import com.ruoyi.resource.mapper.TResourceLandMapper; @@ -15,14 +16,14 @@ import java.util.stream.Collectors; import static com.ruoyi.business.constants.TaskEnums.ImportType; -public class GeoJtzyTask implements GeoDBTaskInterface +public class GeoJtzyImportTask implements GeoDBImportTaskInterface { private final static String TYPE_NAME = "地块属性"; private final GeoImportTask importTask; private List list; - public GeoJtzyTask(GeoImportTask importTask) + public GeoJtzyImportTask(GeoImportTask importTask) { this.importTask = importTask; } @@ -65,7 +66,7 @@ public class GeoJtzyTask implements GeoDBTaskInterface { TResourceLand cond = new TResourceLand(); cond.setImportCode(qydm); - List cjqies = GeoImportHandlerService.ResourceLandMapper().selectTResourceLandList(cond); + List cjqies = GeoMapperService.ResourceLandMapper().selectTResourceLandList(cond); importTask.logFile.WriteLine(TYPE_NAME + "读取系统已存在的条数: 区划代码={}, 条数={}", qydm, cjqies.size()); return cjqies; } @@ -117,7 +118,7 @@ public class GeoJtzyTask implements GeoDBTaskInterface if(ImportType.IT_OVERRIDE.equals(importTask.taskImport.getImportType())) { importTask.logFile.WriteLine(TYPE_NAME + "覆盖导入, 需清空现有数据, 然后再插入, 区划代码={}", importCode); - int ret = GeoImportHandlerService.ResourceLandMapper().deleteByCode(importCode); + int ret = GeoMapperService.ResourceLandMapper().deleteByCode(importCode); importTask.logFile.WriteLine(TYPE_NAME + "清空现有数据: {}, 区划代码={}", ret, importCode); return ret; } @@ -130,7 +131,7 @@ public class GeoJtzyTask implements GeoDBTaskInterface private int WriteData(List insertList, List updateList, SysDept dept) { - TResourceLandMapper gisCjqyMapper = GeoImportHandlerService.ResourceLandMapper(); + TResourceLandMapper gisCjqyMapper = GeoMapperService.ResourceLandMapper(); int i = ListUtil.split(insertList, 30).stream().map(gisCjqyMapper::insertTResourceLandBatch).reduce(0, Integer::sum); importTask.logFile.WriteLine(TYPE_NAME + "新增数据: 区划代码={}, 条数={}", dept.getDeptName(), i); int u = ListUtil.split(updateList, 1).stream().map(gisCjqyMapper::updateTResourceLandBatch).reduce(0, Integer::sum); @@ -141,21 +142,29 @@ public class GeoJtzyTask implements GeoDBTaskInterface private int SaveDeptData(SysDept dept, List datas) { importTask.logFile.WriteLine(TYPE_NAME + "开始处理数据: 区划代码={}, 条数={}", dept.getDeptName(), datas.size()); - List databases = LoadDatabase(dept.getImportCode()); - Map exists = databases.stream().collect(Collectors.toMap(TResourceLand::getDkbm, x->x)); + boolean needCheck = !ImportType.IT_OVERRIDE.equals(importTask.taskImport.getImportType()); + Map exists = null; + if(needCheck) + { + List databases = LoadDatabase(dept.getImportCode()); + exists = databases.stream().collect(Collectors.toMap(TResourceLand::getDkbm, x->x)); + } List insertList = new ArrayList<>(); List updateList = new ArrayList<>(); for(GeoJTZY data : datas) { - TResourceLand db = exists.get(data.DKBM); - boolean notExists = null == db; - db = ConvertData(data, db, dept); - if(notExists) - insertList.add(db); + TResourceLand db = null; + if(needCheck) + { + db = exists.get(data.DKBM); + } + TResourceLand item = ConvertData(data, db, dept); + if(null == db) + insertList.add(item); else - updateList.add(db); + updateList.add(item); } CleanDatabase(dept.getImportCode()); diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoZyhycgExportTask.java b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoZyhycgExportTask.java new file mode 100644 index 0000000..3a0af17 --- /dev/null +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoZyhycgExportTask.java @@ -0,0 +1,74 @@ +package com.ruoyi.geo.framework; + +import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.geo.GeoCreator; +import com.ruoyi.common.utils.DecimalUtils; +import com.ruoyi.geo.service.GeoMapperService; +import com.ruoyi.geo.structs.GeoZYHYCG; +import com.ruoyi.resource.domain.TResourceOperation; +import org.locationtech.jts.geom.MultiPolygon; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class GeoZyhycgExportTask implements GeoDBExportTaskInterface +{ + private final static String TYPE_NAME = "地块经营"; + + private final GeoExportTask exportTask; + private List list; + + public GeoZyhycgExportTask(GeoExportTask exportTask) + { + this.exportTask = exportTask; + } + + public int LoadDataList() + { + TResourceOperation cond = new TResourceOperation(); + cond.setImportCode(exportTask.dept.getImportCode()); + list = GeoMapperService.ResourceOperationMapper().selectTResourceOperationList(cond); + exportTask.logFile.WriteLine(TYPE_NAME + "读取系统数据条数: 区划代码={}, 条数={}", exportTask.dept.getImportCode(), list.size()); + + return list.size(); + } + + private GeoZYHYCG ConvertData(TResourceOperation src, GeoZYHYCG dst) + { + if(null == dst) + dst = new GeoZYHYCG(); + dst.DKBM = src.getDkbm(); + dst.DKMC = src.getDkmc(); + dst.SYQXZ = src.getDkdz(); + dst.JYMJ = src.getJymj(); + dst.JYDXLX = src.getJydxlx(); + dst.JYDXMC = src.getJydxmc(); + dst.JYDXZJLX = src.getJydxzjlx(); + dst.JYDXZJHM = src.getJydxzjhm(); + dst.SFQDHT = src.getSfqdht(); + dst.JYKSSJ = src.getJykssj(); + dst.JYJSSJ = src.getJyjssj(); + dst.CBJE = src.getCbje(); + dst.DXJE = src.getDxje(); + dst.SQJE = src.getSqje(); + dst.NSY = src.getNsy(); + dst.BZXX = src.getBzxx(); + dst.JYFS = src.getJyfs(); + return dst; + } + + public void SaveData() + { + exportTask.logFile.WriteLine(TYPE_NAME + "开始导出数据: 区划代码={}, 条数={}", exportTask.dept.getDeptName(), list.size()); + + List dataList = list.stream().map((x) -> ConvertData(x, null)).collect(Collectors.toList()); + + exportTask.writer.WriteList(dataList); + } + + public Map> GetTypes() + { + return GeoCreator.GetClassTypes(GeoZYHYCG.class); + } +} diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoZyhycgTask.java b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoZyhycgImportTask.java similarity index 84% rename from ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoZyhycgTask.java rename to ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoZyhycgImportTask.java index 4741c2b..1724b8e 100644 --- a/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoZyhycgTask.java +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/framework/GeoZyhycgImportTask.java @@ -5,7 +5,7 @@ import cn.hutool.core.util.StrUtil; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.utils.DecimalUtils; import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.geo.service.GeoImportHandlerService; +import com.ruoyi.geo.service.GeoMapperService; import com.ruoyi.geo.structs.GeoZYHYCG; import com.ruoyi.resource.domain.TResourceOperation; import com.ruoyi.resource.mapper.TResourceOperationMapper; @@ -17,14 +17,14 @@ import java.util.stream.Collectors; import static com.ruoyi.business.constants.TaskEnums.ImportType; -public class GeoZyhycgTask implements GeoDBTaskInterface +public class GeoZyhycgImportTask implements GeoDBImportTaskInterface { private final static String TYPE_NAME = "地块经营"; private final GeoImportTask importTask; private List list; - public GeoZyhycgTask(GeoImportTask importTask) + public GeoZyhycgImportTask(GeoImportTask importTask) { this.importTask = importTask; } @@ -67,7 +67,7 @@ public class GeoZyhycgTask implements GeoDBTaskInterface { TResourceOperation cond = new TResourceOperation(); cond.setImportCode(qydm); - List cjqies = GeoImportHandlerService.ResourceOperationMapper().selectTResourceOperationList(cond); + List cjqies = GeoMapperService.ResourceOperationMapper().selectTResourceOperationList(cond); importTask.logFile.WriteLine(TYPE_NAME + "读取系统已存在的条数: 区划代码={}, 条数={}", qydm, cjqies.size()); return cjqies; } @@ -115,7 +115,7 @@ public class GeoZyhycgTask implements GeoDBTaskInterface if(ImportType.IT_OVERRIDE.equals(importTask.taskImport.getImportType())) { importTask.logFile.WriteLine(TYPE_NAME + "覆盖导入, 需清空现有数据, 然后再插入, 区划代码={}", importCode); - int ret = GeoImportHandlerService.ResourceOperationMapper().deleteByCode(importCode); + int ret = GeoMapperService.ResourceOperationMapper().deleteByCode(importCode); importTask.logFile.WriteLine(TYPE_NAME + "清空现有数据: {}, 区划代码={}", ret, importCode); return ret; } @@ -128,7 +128,7 @@ public class GeoZyhycgTask implements GeoDBTaskInterface private int WriteData(List insertList, List updateList, SysDept dept) { - TResourceOperationMapper gisCjqyMapper = GeoImportHandlerService.ResourceOperationMapper(); + TResourceOperationMapper gisCjqyMapper = GeoMapperService.ResourceOperationMapper(); int i = ListUtil.split(insertList, 30).stream().map(gisCjqyMapper::insertTResourceOperationBatch).reduce(0, Integer::sum); importTask.logFile.WriteLine(TYPE_NAME + "新增数据: 区划代码={}, 条数={}", dept.getDeptName(), i); int u = ListUtil.split(updateList, 1).stream().map(gisCjqyMapper::updateTResourceOperationBatch).reduce(0, Integer::sum); @@ -139,21 +139,29 @@ public class GeoZyhycgTask implements GeoDBTaskInterface private int SaveDeptData(SysDept dept, List datas) { importTask.logFile.WriteLine(TYPE_NAME + "开始处理数据: 区划代码={}, 条数={}", dept.getDeptName(), datas.size()); - List databases = LoadDatabase(dept.getImportCode()); - Map exists = databases.stream().collect(Collectors.toMap(TResourceOperation::getDkbm, x->x)); + boolean needCheck = !ImportType.IT_OVERRIDE.equals(importTask.taskImport.getImportType()); + Map exists = null; + if(needCheck) + { + List databases = LoadDatabase(dept.getImportCode()); + exists = databases.stream().collect(Collectors.toMap(TResourceOperation::getDkbm, x->x)); + } List insertList = new ArrayList<>(); List updateList = new ArrayList<>(); for(GeoZYHYCG data : datas) { - TResourceOperation db = exists.get(data.DKBM); - boolean notExists = null == db; - db = ConvertData(data, db, dept); - if(notExists) - insertList.add(db); + TResourceOperation db = null; + if(needCheck) + { + db = exists.get(data.DKBM); + } + TResourceOperation item = ConvertData(data, db, dept); + if(null == db) + insertList.add(item); else - updateList.add(db); + updateList.add(item); } CleanDatabase(dept.getImportCode()); diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoExportHandlerService.java b/ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoExportHandlerService.java new file mode 100644 index 0000000..dba3905 --- /dev/null +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoExportHandlerService.java @@ -0,0 +1,268 @@ +package com.ruoyi.geo.service; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.file.FileNameUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.extra.servlet.ServletUtil; +import com.ruoyi.business.domain.TTaskExport; +import com.ruoyi.business.mapper.TTaskExportMapper; +import com.ruoyi.common.constant.HttpStatus; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.sql.DB; +import com.ruoyi.geo.config.GeoExportTaskConfig; +import com.ruoyi.geo.constants.GeoSysDir; +import com.ruoyi.geo.framework.GeoExportTask; +import com.ruoyi.geo.framework.GeoTaskQueue; +import com.ruoyi.geo.object.GeoLogInfo; +import com.ruoyi.system.mapper.SysDeptMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.stream.Collectors; + +import static com.ruoyi.business.constants.TaskEnums.TaskStatus; + +@Service +@Slf4j +public class GeoExportHandlerService +{ + @Resource + private SysDeptMapper deptMapper; + @Resource + private TTaskExportMapper taskExportMapper; + + private GeoTaskQueue taskQueue; + + private synchronized GeoTaskQueue TaskQueue() + { + if(null == taskQueue) + taskQueue = new GeoTaskQueue(true); + return taskQueue; + } + + @PostConstruct + public synchronized void Init() + { + SyncTask(); + LoadTask(); + } + + @PreDestroy + public synchronized void Shutdown() + { + if(null != taskQueue) + taskQueue.Quit(); + } + + private void SyncTask() + { + log.info("更改运行中的任务状态为中止......"); + // 更改运行中的任务状态为中止 + int i = taskExportMapper.terminateRunningTask(); + log.info("已设置运行中的任务状态为中止: " + i); + } + + private void LoadTask() + { + if(!GeoExportTaskConfig.startOnBoot) + return; + + log.info("拉取排队中的任务......"); + TTaskExport cond = new TTaskExport(); + cond.setTaskStatus(TaskStatus.ST_WAIT); + List taskExports = taskExportMapper.selectTTaskExportList(cond); + log.info("拉取到排队中的任务: " + taskExports.size()); + List tasks = taskExports.stream().map((x) -> new GeoExportTask(x.getId())).collect(Collectors.toList()); + if(!tasks.isEmpty()) + TaskQueue().StartTask(tasks); + } + + public GeoLogInfo loadExportLog(Long taskId, int offset) + { + GeoLogInfo info = new GeoLogInfo(); + info.setNextPollDelay(GeoExportTaskConfig.logNextPoll); + TTaskExport taskExport = taskExportMapper.selectTTaskExportById(taskId); + Assert.notNull(taskExport, "导出任务不存在"); + info.setTaskStatus(taskExport.getTaskStatus()); + if(TaskStatus.ST_READY.equals(taskExport.getTaskStatus())/* || TaskStatus.ST_WAIT.equals(taskExport.getTaskStatus())*/) + { + info.setEof(true); + info.setLength(-1); + return info; + } + + String path = GeoSysDir.ExportDir(GeoSysDir.LOG) + "/" + taskId + ".log"; + if(!FileUtil.isFile(path)) + { + info.setEof(true); + info.setLength(-1); + return info; + } + + info.setEof(!TaskStatus.ST_RUNNING.equals(info.getTaskStatus()) && !TaskStatus.ST_WAIT.equals(info.getTaskStatus())); + String str = FileUtil.readUtf8String(path); + info.setLength(str.length()); + String text; + if(offset >= str.length() - 1) + text = ""; + else if(offset > 0) + text = str.substring(offset); + else + text = str; + info.setText(text); + + return info; + } + + public synchronized int startTask(Long id) + { + if(null != taskQueue) + { + GeoExportTask task = (GeoExportTask)taskQueue.GetCurrentTask(); + Assert.isFalse(null != task && task.GetTaskId().equals(id), "任务正在执行"); + + boolean exists = null != taskQueue.FindTask((x) -> { + GeoExportTask t = (GeoExportTask) x; + return(t.GetTaskId().equals(id)); + }); + Assert.isFalse(exists, "任务已在队列中"); + } + + Object handler = DB.BeginTransaction(); + try + { + TTaskExport taskExport = taskExportMapper.getForUpdate(id); + Assert.notNull(taskExport, "任务不存在"); + Assert.isTrue(TaskStatus.ST_READY.equals(taskExport.getTaskStatus()), "任务非准备状态"); + taskExport.setTaskStatus(TaskStatus.ST_WAIT); + taskExportMapper.updateTTaskExport(taskExport); + DB.CommitTransaction(handler); + } + catch(Exception e) + { + e.printStackTrace(); + DB.RollbackTransaction(handler); + return 0; + } + int ret = null != taskQueue && taskQueue.HasTask() ? 1 : 2; + TaskQueue().StartTask(new GeoExportTask(id)); + return ret; + } + + public void downloadLog(Long taskId, HttpServletResponse response) + { + String path = GeoSysDir.ExportDir(GeoSysDir.LOG) + "/" + taskId + ".log"; + String dlFileName; + try + { + dlFileName = URLEncoder.encode(FileNameUtil.getName(path), "UTF-8"); + } + catch(UnsupportedEncodingException e) + { + e.printStackTrace(); + dlFileName = ""; + } + + int bytes = 0; + + response.reset(); + response.addHeader("Access-Control-Allow-Origin", "*"); + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); + response.setHeader("Content-Disposition", "attachment; filename=\"" + dlFileName + "\""); + response.setContentType("application/octet-stream; charset=UTF-8"); + + TTaskExport taskExport = taskExportMapper.selectTTaskExportById(taskId); + if(null == taskExport) + { + response.setStatus(HttpStatus.NOT_FOUND); + ServletUtil.write(response, "导出任务不存在", "application/octet-stream; charset=UTF-8"); + bytes = "导出任务不存在".getBytes(StandardCharsets.UTF_8).length; + response.addHeader("Content-Length", "" + bytes); + return; + } + + File file = new File(path); + if(!file.isFile()) + { + response.setStatus(HttpStatus.NOT_FOUND); + ServletUtil.write(response, "日志文件不存在", "application/octet-stream; charset=UTF-8"); + bytes = "日志文件不存在".getBytes(StandardCharsets.UTF_8).length; + response.addHeader("Content-Length", "" + bytes); + return; + } + + ServletUtil.write(response, file); + response.addHeader("Content-Length", "" + file.length()); + } + + public void downloadFile(Long taskId, HttpServletResponse response) + { + int bytes = 0; + + response.reset(); + response.addHeader("Access-Control-Allow-Origin", "*"); + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); + response.setHeader("Content-Disposition", "attachment; filename=\"" + taskId + ".zip\""); + response.setContentType("application/octet-stream; charset=UTF-8"); + + TTaskExport taskExport = taskExportMapper.selectTTaskExportById(taskId); + if(null == taskExport) + { + response.setStatus(HttpStatus.NOT_FOUND); + ServletUtil.write(response, "导出任务不存在", "application/octet-stream; charset=UTF-8"); + bytes = "导出任务不存在".getBytes(StandardCharsets.UTF_8).length; + response.addHeader("Content-Length", "" + bytes); + return; + } + if(!TaskStatus.ST_FINISH.equals(taskExport.getTaskStatus())) + { + response.setStatus(HttpStatus.FORBIDDEN); + ServletUtil.write(response, "导出任务未完成", "application/octet-stream; charset=UTF-8"); + bytes = "导出任务未完成".getBytes(StandardCharsets.UTF_8).length; + response.addHeader("Content-Length", "" + bytes); + return; + } + if(StringUtils.isEmpty(taskExport.getFileUrl())) + { + response.setStatus(HttpStatus.NOT_FOUND); + ServletUtil.write(response, "导出文件未生成", "application/octet-stream; charset=UTF-8"); + bytes = "导出文件未生成".getBytes(StandardCharsets.UTF_8).length; + response.addHeader("Content-Length", "" + bytes); + return; + } + + String path = GeoSysDir.GetDir(GeoSysDir.TrimProfile(taskExport.getFileUrl())); + String dlFileName; + try + { + dlFileName = URLEncoder.encode(FileNameUtil.getName(path), "UTF-8"); + } + catch(UnsupportedEncodingException e) + { + e.printStackTrace(); + dlFileName = ""; + } + response.setHeader("Content-Disposition", "attachment; filename=\"" + dlFileName + "\""); + + File file = new File(path); + if(!file.isFile()) + { + ServletUtil.write(response, "导出文件不存在", "application/octet-stream; charset=UTF-8"); + bytes = "导出文件不存在".getBytes(StandardCharsets.UTF_8).length; + response.addHeader("Content-Length", "" + bytes); + return; + } + + ServletUtil.write(response, file); + response.addHeader("Content-Length", "" + file.length()); + } +} diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoImportHandlerService.java b/ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoImportHandlerService.java index be01e20..dd4eb54 100644 --- a/ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoImportHandlerService.java +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoImportHandlerService.java @@ -6,7 +6,9 @@ import cn.hutool.core.lang.Assert; import cn.hutool.extra.servlet.ServletUtil; import com.ruoyi.business.domain.TTaskImport; import com.ruoyi.business.mapper.TGisCjqyMapper; +import com.ruoyi.business.mapper.TTaskExportMapper; import com.ruoyi.business.mapper.TTaskImportMapper; +import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.utils.sql.DB; import com.ruoyi.geo.config.GeoImportTaskConfig; import com.ruoyi.geo.constants.GeoSysDir; @@ -38,57 +40,11 @@ public class GeoImportHandlerService { @Resource private SysDeptMapper deptMapper; - private static TTaskImportMapper taskImportMapper; - private static TGisCjqyMapper gisCjqyMapper; - private static TResourceLandMapper resourceLandMapper; - private static TResourceOperationMapper resourceOperationMapper; + @Resource + private TTaskImportMapper taskImportMapper; private GeoTaskQueue taskQueue; - @Autowired - public void setTaskImportMapper(TTaskImportMapper taskImportMapper) - { - GeoImportHandlerService.taskImportMapper = taskImportMapper; - } - - @Autowired - public void setGisCjqyMapper(TGisCjqyMapper gisCjqyMapper) - { - GeoImportHandlerService.gisCjqyMapper = gisCjqyMapper; - } - - @Autowired - public void setResourceLandMapper(TResourceLandMapper resourceLandMapper) - { - GeoImportHandlerService.resourceLandMapper = resourceLandMapper; - } - - @Autowired - public void setResourceOperationMapper(TResourceOperationMapper resourceOperationMapper) - { - GeoImportHandlerService.resourceOperationMapper = resourceOperationMapper; - } - - public static TTaskImportMapper TaskImportMapper() - { - return taskImportMapper; - } - - public static TGisCjqyMapper GisCjqyMapper() - { - return gisCjqyMapper; - } - - public static TResourceLandMapper ResourceLandMapper() - { - return resourceLandMapper; - } - - public static TResourceOperationMapper ResourceOperationMapper() - { - return resourceOperationMapper; - } - private synchronized GeoTaskQueue TaskQueue() { if(null == taskQueue) @@ -133,7 +89,7 @@ public class GeoImportHandlerService TaskQueue().StartTask(tasks); } - public GeoLogInfo GetImportLog(Long taskId, int offset) + public GeoLogInfo loadImportLog(Long taskId, int offset) { GeoLogInfo info = new GeoLogInfo(); info.setNextPollDelay(GeoImportTaskConfig.logNextPoll); @@ -170,7 +126,7 @@ public class GeoImportHandlerService return info; } - public synchronized int StartTask(Long id) + public synchronized int startTask(Long id) { if(null != taskQueue) { @@ -205,7 +161,7 @@ public class GeoImportHandlerService return ret; } - public void DownloadLog(Long taskId, HttpServletResponse response) + public void downloadLog(Long taskId, HttpServletResponse response) { String path = GeoSysDir.ImportDir(GeoSysDir.LOG) + "/" + taskId + ".log"; String dlFileName; @@ -230,18 +186,24 @@ public class GeoImportHandlerService TTaskImport taskImport = taskImportMapper.selectTTaskImportById(taskId); if(null == taskImport) { + response.setStatus(HttpStatus.NOT_FOUND); ServletUtil.write(response, "导入任务不存在", "application/octet-stream; charset=UTF-8"); bytes = "导入任务不存在".getBytes(StandardCharsets.UTF_8).length; + response.addHeader("Content-Length", "" + bytes); + return; } File file = new File(path); if(!file.isFile()) { + response.setStatus(HttpStatus.NOT_FOUND); ServletUtil.write(response, "日志文件不存在", "application/octet-stream; charset=UTF-8"); bytes = "日志文件不存在".getBytes(StandardCharsets.UTF_8).length; + response.addHeader("Content-Length", "" + bytes); + return; } ServletUtil.write(response, file); - response.addHeader("Content-Length", "" + bytes); + response.addHeader("Content-Length", "" + file.length()); } } diff --git a/ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoMapperService.java b/ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoMapperService.java new file mode 100644 index 0000000..1753125 --- /dev/null +++ b/ruoyi-business/src/main/java/com/ruoyi/geo/service/GeoMapperService.java @@ -0,0 +1,92 @@ +package com.ruoyi.geo.service; + +import com.ruoyi.business.mapper.TGisCjqyMapper; +import com.ruoyi.business.mapper.TTaskExportMapper; +import com.ruoyi.business.mapper.TTaskImportMapper; +import com.ruoyi.resource.mapper.TResourceLandMapper; +import com.ruoyi.resource.mapper.TResourceOperationMapper; +import com.ruoyi.system.mapper.SysDeptMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +@Service +@Slf4j +public class GeoMapperService +{ + private static SysDeptMapper deptMapper; + private static TTaskImportMapper taskImportMapper; + private static TTaskExportMapper taskExportMapper; + private static TGisCjqyMapper gisCjqyMapper; + private static TResourceLandMapper resourceLandMapper; + private static TResourceOperationMapper resourceOperationMapper; + + @Autowired + public void setTaskImportMapper(TTaskImportMapper taskImportMapper) + { + GeoMapperService.taskImportMapper = taskImportMapper; + } + + @Autowired + public void setTaskExportMapper(TTaskExportMapper taskExportMapper) + { + GeoMapperService.taskExportMapper = taskExportMapper; + } + + @Autowired + public void setGisCjqyMapper(TGisCjqyMapper gisCjqyMapper) + { + GeoMapperService.gisCjqyMapper = gisCjqyMapper; + } + + @Autowired + public void setResourceLandMapper(TResourceLandMapper resourceLandMapper) + { + GeoMapperService.resourceLandMapper = resourceLandMapper; + } + + @Autowired + public void setResourceOperationMapper(TResourceOperationMapper resourceOperationMapper) + { + GeoMapperService.resourceOperationMapper = resourceOperationMapper; + } + + @Autowired + public void setSysDeptMapper(SysDeptMapper deptMapper) + { + GeoMapperService.deptMapper = deptMapper; + } + + public static TTaskImportMapper TaskImportMapper() + { + return taskImportMapper; + } + + public static TTaskExportMapper TaskExportMapper() + { + return taskExportMapper; + } + + public static TGisCjqyMapper GisCjqyMapper() + { + return gisCjqyMapper; + } + + public static TResourceLandMapper ResourceLandMapper() + { + return resourceLandMapper; + } + + public static TResourceOperationMapper ResourceOperationMapper() + { + return resourceOperationMapper; + } + + public static SysDeptMapper DeptMapper() + { + return deptMapper; + } + +} diff --git a/ruoyi-business/src/main/resources/mapper/business/TTaskExportMapper.xml b/ruoyi-business/src/main/resources/mapper/business/TTaskExportMapper.xml index 2b969a8..c31762a 100644 --- a/ruoyi-business/src/main/resources/mapper/business/TTaskExportMapper.xml +++ b/ruoyi-business/src/main/resources/mapper/business/TTaskExportMapper.xml @@ -153,4 +153,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{id} + + + update t_task_export + set task_status = '5' + where task_status = '2' + + + diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java index f34b42c..771df2c 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java @@ -2,6 +2,7 @@ package com.ruoyi.common.core.domain.entity; import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -17,6 +18,7 @@ import java.util.List; * * @author ruoyi */ +@Data public class SysDept extends BaseEntity { private static final long serialVersionUID = 1L; @@ -74,6 +76,10 @@ public class SysDept extends BaseEntity private List children = new ArrayList(); + /** 祖先ID */ + private Long rootId; + + public Long getDeptId() { diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/geo/GeoCreator.java b/ruoyi-common/src/main/java/com/ruoyi/common/geo/GeoCreator.java new file mode 100644 index 0000000..c2d1cb1 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/geo/GeoCreator.java @@ -0,0 +1,160 @@ +package com.ruoyi.common.geo; + +import cn.hutool.core.util.ClassUtil; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.LinearRing; +import org.locationtech.jts.geom.MultiLineString; +import org.locationtech.jts.geom.MultiPoint; +import org.locationtech.jts.geom.MultiPolygon; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.Polygon; +import org.locationtech.jts.io.ParseException; +import org.locationtech.jts.io.WKTReader; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; + +public final class GeoCreator +{ + private static GeoCreator geometryCreator = null; + private static GeometryFactory geometryFactory = new GeometryFactory(); + + private GeoCreator() { + } + + /** + * 1.2根据几何对象的WKT描述【String】创建几何对象: 点 【Point】 + * @return + * @throws ParseException + */ + public static Point PointByWKT(String PointWKT) { + WKTReader reader = new WKTReader(geometryFactory); + try + { + return (Point) reader.read(PointWKT); + } + catch(ParseException e) + { + throw new RuntimeException(e); + } + } + + /** + * 1.3根据几何对象的WKT描述【String】创建几何对象:多点 【MultiPoint】 + * @return + * @throws ParseException + */ + public static MultiPoint MultiPointByWKT(String MPointWKT) { + WKTReader reader = new WKTReader( geometryFactory ); + try + { + return (MultiPoint) reader.read(MPointWKT); + } + catch(ParseException e) + { + throw new RuntimeException(e); + } + } + + public static LineString LineStringByWKT(String LineStringWKT) { + WKTReader reader = new WKTReader( geometryFactory ); + try + { + return (LineString) reader.read(LineStringWKT); + } + catch(ParseException e) + { + throw new RuntimeException(e); + } + } + + /** + * 2.4根据几何对象的WKT描述【String】创建几何对象 : 多线【MultiLineString】 + * @param MLineStringWKT + * @return + * @throws ParseException + */ + public static MultiLineString MultiLineByWKT(String MLineStringWKT) { + WKTReader reader = new WKTReader( geometryFactory ); + try + { + return (MultiLineString) reader.read(MLineStringWKT); + } + catch(ParseException e) + { + throw new RuntimeException(e); + } + } + + + /** + * 3.1 根据几何对象的WKT描述【String】创建几何对象:多边形 【Polygon】 + * @param PolygonWKT + * @return + * @throws ParseException + */ + public static Polygon PolygonByWKT(String PolygonWKT) { + WKTReader reader = new WKTReader( geometryFactory ); + try + { + return (Polygon) reader.read(PolygonWKT); + } + catch(ParseException e) + { + throw new RuntimeException(e); + } + } + + /** + * 3.2 根据几何对象的WKT描述【String】创建几何对象: 多多边形 【MultiPolygon】 + * @param MPolygonWKT + * @return + * @throws ParseException + */ + public static MultiPolygon MultiPolygonByWKT(String MPolygonWKT) { + WKTReader reader = new WKTReader( geometryFactory ); + try + { + return (MultiPolygon) reader.read(MPolygonWKT); + } + catch(ParseException e) + { + throw new RuntimeException(e); + } + } + + /** + * 6.1 根据WKT创建环 + * @param ringWKT + * @return + * @throws ParseException + */ + public static LinearRing LinearRingByWKT(String ringWKT) { + WKTReader reader = new WKTReader( geometryFactory ); + try + { + return (LinearRing) reader.read(ringWKT); + } + catch(ParseException e) + { + throw new RuntimeException(e); + } + } + + public static Map> GetClassTypes(Class clazz) + { + Field[] fields = clazz.getDeclaredFields(); + Map> ret = new HashMap<>(); + for(Field field : fields) + { + int modifiers = field.getModifiers(); + if(Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers) || !Modifier.isPublic(modifiers)) + continue; + ret.put(field.getName(), field.getType()); + } + return ret; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/geo/GeoWriter.java b/ruoyi-common/src/main/java/com/ruoyi/common/geo/GeoWriter.java new file mode 100644 index 0000000..64d21b7 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/geo/GeoWriter.java @@ -0,0 +1,278 @@ +package com.ruoyi.common.geo; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.lang.Assert; +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.data.simple.SimpleFeatureIterator; +import org.geotools.data.simple.SimpleFeatureSource; +import org.geotools.feature.simple.SimpleFeatureTypeBuilder; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.LinearRing; +import org.locationtech.jts.geom.MultiLineString; +import org.locationtech.jts.geom.MultiPoint; +import org.locationtech.jts.geom.MultiPolygon; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.Polygon; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; +import org.opengis.feature.type.AttributeDescriptor; + +import java.io.Closeable; +import java.io.File; +import java.io.Serializable; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public final class GeoWriter implements Closeable +{ + private ShapefileDataStore dataStore; + private FeatureWriter writer; + private SimpleFeatureSource source; + private Map> columnMap; + + public GeoWriter() + { + } + + public void Init() + { + } + + @Override + public void close() + { + CloseSource(); + if(null != dataStore) + { + dataStore.dispose(); + dataStore = null; + } + } + + public boolean Open(String path, String charsetName) + { + return Open(new File(path), charsetName); + } + + public boolean Open(File file, String charsetName) + { + close(); + + try { + Map params = new HashMap<>(); + + // 2、用于捕获参数需求的数据类 URLP:url to the .shp file. + params.put(ShapefileDataStoreFactory.URLP.key, file.toURI().toURL()); + + dataStore = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params); + + Charset charset = Charset.forName(charsetName); + dataStore.setCharset(charset); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + private void CheckDataStore() + { + Assert.notNull(dataStore, "请先打开"); + } + + private void CheckWriter() + { + Assert.notNull(writer, "请先打开写入"); + } + + public void AddSchema(String name, Map> parms) + { + CheckDataStore(); + + try { + SimpleFeatureTypeBuilder tBuilder = new SimpleFeatureTypeBuilder(); + + // 5、设置 -- WGS84:一个二维地理坐标参考系统,使用WGS84数据 + tBuilder.setCRS(DefaultGeographicCRS.WGS84); + tBuilder.setName(name); + + parms.forEach(tBuilder::add); + + dataStore.createSchema(tBuilder.buildFeatureType()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public boolean SetSource(String typeName, boolean append) + { + CloseSource(); + + CheckDataStore(); + + try { + if(append) + writer = dataStore.getFeatureWriterAppend(typeName, Transaction.AUTO_COMMIT); + else + writer = dataStore.getFeatureWriter(typeName, Transaction.AUTO_COMMIT); + source = dataStore.getFeatureSource(typeName); + return InitSource(); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public List GetTypeNames() + { + CheckDataStore(); + + try { + return Arrays.stream(dataStore.getTypeNames()).collect(Collectors.toList()); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public boolean SetSource(int index, boolean append) + { + CloseSource(); + if(index < 0) + return true; + CheckDataStore(); + return SetSource(GetTypeNames().get(index), append); + } + + private void CloseSource() + { + columnMap = null; + if(null != writer) + { + IoUtil.close(writer); + writer = null; + } + } + + private boolean InitSource() + { + if(null == writer) + return false; + + try { + if(null == columnMap) + columnMap = new LinkedHashMap<>(); + else + columnMap.clear(); + SimpleFeatureType schema = source.getSchema(); + for(int i = 0; i < schema.getAttributeCount(); i++) + { + AttributeDescriptor descriptor = schema.getDescriptor(i); + columnMap.put(descriptor.getLocalName(), descriptor.getType().getBinding()); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public Object ConvertValue(Class clazz, Object value) + { + if(Point.class.isAssignableFrom(clazz)) + { + if(value instanceof Point) + return value; + else + return GeoCreator.PointByWKT(value.toString()); + } + else if(MultiPoint.class.isAssignableFrom(clazz)) + { + if(value instanceof MultiPoint) + return value; + else + return GeoCreator.MultiPointByWKT(value.toString()); + } + else if(LineString.class.isAssignableFrom(clazz)) + { + if(value instanceof LineString) + return value; + else + return GeoCreator.LineStringByWKT(value.toString()); + } + else if(MultiLineString.class.isAssignableFrom(clazz)) + { + if(value instanceof MultiLineString) + return value; + else + return GeoCreator.MultiLineByWKT(value.toString()); + } + else if(Polygon.class.isAssignableFrom(clazz)) + { + if(value instanceof Polygon) + return value; + else + return GeoCreator.PolygonByWKT(value.toString()); + } + else if(MultiPolygon.class.isAssignableFrom(clazz)) + { + if(value instanceof MultiPolygon) + return value; + else + return GeoCreator.MultiPolygonByWKT(value.toString()); + } + else if(LinearRing.class.isAssignableFrom(clazz)) + { + if(value instanceof LinearRing) + return value; + else + return GeoCreator.LinearRingByWKT(value.toString()); + } + else + return value; + } + + public void WriteMapList(List> list) + { + CheckWriter(); + + try { + Set headers = columnMap.keySet(); + for(Map map : list) + { + SimpleFeature feature = writer.next(); + for(String header : headers) + { + Object value = map.get(header); + if(null == value) + continue; + Class clazz = columnMap.get(header); + feature.setAttribute(header, ConvertValue(clazz, value)); + } + } + writer.write(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void WriteList(List list) + { + List> mapList = list.stream().map((x) -> BeanUtil.beanToMap(x, false, true)).collect(Collectors.toList()); + WriteMapList(mapList); + } +} diff --git a/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml index ab00394..98e6ae9 100644 --- a/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml @@ -54,6 +54,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND status = #{status} + and (dept_id = #{rootId} OR dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{rootId}, ancestors) )) ${params.dataScope}