| @@ -40,6 +40,7 @@ | |||||
| <de.odysseus.juel.version>2.1.3</de.odysseus.juel.version> | <de.odysseus.juel.version>2.1.3</de.odysseus.juel.version> | ||||
| <httpclient.version>4.5.13</httpclient.version> | <httpclient.version>4.5.13</httpclient.version> | ||||
| <net.coobird.version>0.4.8</net.coobird.version> | <net.coobird.version>0.4.8</net.coobird.version> | ||||
| <geotools.version>20.0</geotools.version> | |||||
| </properties> | </properties> | ||||
| <!-- 依赖声明 --> | <!-- 依赖声明 --> | ||||
| @@ -230,6 +231,33 @@ | |||||
| <version>${net.coobird.version}</version> | <version>${net.coobird.version}</version> | ||||
| </dependency> | </dependency> | ||||
| <dependency> | |||||
| <groupId>org.springframework.boot</groupId> | |||||
| <artifactId>spring-boot-starter-test</artifactId> | |||||
| <scope>test</scope> | |||||
| <version>${spring-boot.version}</version> | |||||
| </dependency> | |||||
| <!-- 添加GeoTools依赖 --> | |||||
| <dependency> | |||||
| <groupId>org.geotools</groupId> | |||||
| <artifactId>gt-shapefile</artifactId> | |||||
| <version>${geotools.version}</version> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>org.geotools</groupId> | |||||
| <artifactId>gt-swing</artifactId> | |||||
| <version>${geotools.version}</version> | |||||
| </dependency> | |||||
| <!-- wkt转geojson --> | |||||
| <dependency> | |||||
| <groupId>org.geotools</groupId> | |||||
| <artifactId>gt-geojson</artifactId> | |||||
| <version>${geotools.version}</version> | |||||
| </dependency> | |||||
| <!-- 定时任务--> | <!-- 定时任务--> | ||||
| @@ -312,6 +340,17 @@ | |||||
| <enabled>true</enabled> | <enabled>true</enabled> | ||||
| </releases> | </releases> | ||||
| </repository> | </repository> | ||||
| <repository> | |||||
| <id>osgeo</id> | |||||
| <name>OSGeo Release Repository</name> | |||||
| <url>https://repo.osgeo.org/repository/release/</url> | |||||
| <snapshots> | |||||
| <enabled>false</enabled> | |||||
| </snapshots> | |||||
| <releases> | |||||
| <enabled>true</enabled> | |||||
| </releases> | |||||
| </repository> | |||||
| </repositories> | </repositories> | ||||
| <pluginRepositories> | <pluginRepositories> | ||||
| @@ -67,6 +67,11 @@ | |||||
| <artifactId>ruoyi-business</artifactId> | <artifactId>ruoyi-business</artifactId> | ||||
| </dependency> | </dependency> | ||||
| <dependency> | |||||
| <groupId>org.springframework.boot</groupId> | |||||
| <artifactId>spring-boot-starter-test</artifactId> | |||||
| </dependency> | |||||
| </dependencies> | </dependencies> | ||||
| <build> | <build> | ||||
| @@ -81,16 +81,16 @@ public class ResourceBigController extends BaseController { | |||||
| @GetMapping("/homepageStatistics") | @GetMapping("/homepageStatistics") | ||||
| public AjaxResult homepageStatistics() { | public AjaxResult homepageStatistics() { | ||||
| LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); | LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); | ||||
| Object statisticVOMap = redisCache.getCacheObject(CacheConstants.BIG_DATA_RESOURCE_KEY+"homepageStatistics" + loginUser.getUser().getUserName()); | |||||
| if (Objects.nonNull(statisticVOMap)) { | |||||
| return AjaxResult.success(statisticVOMap); | |||||
| } | |||||
| // Object statisticVOMap = redisCache.getCacheObject(CacheConstants.BIG_DATA_RESOURCE_KEY+"homepageStatistics" + loginUser.getUser().getUserName()); | |||||
| // if (Objects.nonNull(statisticVOMap)) { | |||||
| // return AjaxResult.success(statisticVOMap); | |||||
| // } | |||||
| List<TBigDataScreen> list = tResourceLandService.progressResourceInvestigationStatistics(loginUser.getUser().getDeptId());//资源调查进度统计 | List<TBigDataScreen> list = tResourceLandService.progressResourceInvestigationStatistics(loginUser.getUser().getDeptId());//资源调查进度统计 | ||||
| TBigDataScreen tBigDataScreen = tResourceLandService.homepageDownStatistics(loginUser.getUser().getDeptId());//首页下面统计 | TBigDataScreen tBigDataScreen = tResourceLandService.homepageDownStatistics(loginUser.getUser().getDeptId());//首页下面统计 | ||||
| Map map = new HashMap(); | Map map = new HashMap(); | ||||
| map.put("progressResourceInvestigation",list); | map.put("progressResourceInvestigation",list); | ||||
| map.put("homepageStatistics",tBigDataScreen); | map.put("homepageStatistics",tBigDataScreen); | ||||
| redisCache.setCacheObject(CacheConstants.BIG_DATA_RESOURCE_KEY+"homepageStatistics" + loginUser.getUser().getUserName(), map, expireTime, TimeUnit.MINUTES); | |||||
| // redisCache.setCacheObject(CacheConstants.BIG_DATA_RESOURCE_KEY+"homepageStatistics" + loginUser.getUser().getUserName(), map, expireTime, TimeUnit.MINUTES); | |||||
| return AjaxResult.success(map); | return AjaxResult.success(map); | ||||
| } | } | ||||
| @@ -14,6 +14,7 @@ import com.ruoyi.common.enums.BusinessType; | |||||
| import com.ruoyi.common.utils.pdf.PdfUtils; | import com.ruoyi.common.utils.pdf.PdfUtils; | ||||
| import com.ruoyi.common.utils.poi.ExcelUtil; | import com.ruoyi.common.utils.poi.ExcelUtil; | ||||
| import com.ruoyi.common.utils.translation.TranslateUtils; | import com.ruoyi.common.utils.translation.TranslateUtils; | ||||
| import com.ruoyi.geo.service.GeoImportHandlerService; | |||||
| import com.ruoyi.system.service.ISysDeptService; | import com.ruoyi.system.service.ISysDeptService; | ||||
| import org.apache.commons.compress.utils.Lists; | import org.apache.commons.compress.utils.Lists; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
| @@ -38,7 +39,9 @@ public class TTaskImportController extends BaseController | |||||
| private ITTaskImportService tTaskImportService; | private ITTaskImportService tTaskImportService; | ||||
| @Autowired | @Autowired | ||||
| private ISysDeptService deptService; | |||||
| private ISysDeptService deptService; | |||||
| @Autowired | |||||
| private GeoImportHandlerService importHandlerService; | |||||
| /** | /** | ||||
| * 查询导入任务列表 | * 查询导入任务列表 | ||||
| @@ -202,4 +205,37 @@ public class TTaskImportController extends BaseController | |||||
| PdfUtils.initPdf(response, pdf); | PdfUtils.initPdf(response, pdf); | ||||
| } | } | ||||
| /** | |||||
| * 开始导入任务 | |||||
| */ | |||||
| @PreAuthorize("@ss.hasPermi('business:import:do')") | |||||
| @Log(title = "开始导入任务", businessType = BusinessType.UPDATE) | |||||
| @PostMapping("/start/{taskId}") | |||||
| public AjaxResult start(@PathVariable Long taskId) | |||||
| { | |||||
| return AjaxResult.success(importHandlerService.StartTask(taskId)); | |||||
| } | |||||
| /** | |||||
| * 获取导入任务日志 | |||||
| */ | |||||
| @PreAuthorize("@ss.hasPermi('business:import:do')") | |||||
| @GetMapping("/log/{taskId}") | |||||
| public AjaxResult log(@PathVariable Long taskId, Integer offset) | |||||
| { | |||||
| if(null == offset) | |||||
| offset = 0; | |||||
| return AjaxResult.success(importHandlerService.GetImportLog(taskId, offset)); | |||||
| } | |||||
| /** | |||||
| * 下载导入任务日志 | |||||
| */ | |||||
| @PreAuthorize("@ss.hasPermi('business:import:do')") | |||||
| @GetMapping("/downloadLog/{taskId}") | |||||
| public void downloadLog(@PathVariable Long taskId, HttpServletResponse response) | |||||
| { | |||||
| importHandlerService.DownloadLog(taskId, response); | |||||
| } | |||||
| } | } | ||||
| @@ -66,7 +66,7 @@ spring: | |||||
| devtools: | devtools: | ||||
| restart: | restart: | ||||
| # 热部署开关 | # 热部署开关 | ||||
| enabled: true | |||||
| enabled: false | |||||
| # redis 配置 | # redis 配置 | ||||
| redis: | redis: | ||||
| # 地址 | # 地址 | ||||
| @@ -133,3 +133,9 @@ xss: | |||||
| excludes: /system/notice | excludes: /system/notice | ||||
| # 匹配链接 | # 匹配链接 | ||||
| urlPatterns: /system/*,/monitor/*,/tool/* | urlPatterns: /system/*,/monitor/*,/tool/* | ||||
| importTask: | |||||
| # 是否启动时执行等待中的任务 | |||||
| startOnBoot: false | |||||
| # 下次建议读取日志的间隔(毫秒) | |||||
| logNextPoll: 2000 | |||||
| @@ -0,0 +1,53 @@ | |||||
| import cn.hutool.core.thread.ThreadUtil; | |||||
| import com.alibaba.fastjson2.JSON; | |||||
| import com.ruoyi.RuoYiApplication; | |||||
| import com.ruoyi.common.geo.GeoParser; | |||||
| 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.springframework.boot.test.context.SpringBootTest; | |||||
| import org.springframework.test.context.junit.jupiter.SpringExtension; | |||||
| import javax.annotation.Resource; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| @Slf4j | |||||
| @ExtendWith(SpringExtension.class) | |||||
| @SpringBootTest(classes = RuoYiApplication.class) | |||||
| public final class GeoTest | |||||
| { | |||||
| @Resource | |||||
| private GeoImportHandlerService service; | |||||
| @Test | |||||
| public void test() | |||||
| { | |||||
| service.StartTask(4L); | |||||
| //new Scanner(System.in).next(); | |||||
| ThreadUtil.sleep(5000); | |||||
| } | |||||
| public static void main(String[] args) | |||||
| { | |||||
| String PATH; | |||||
| PATH = "D:/m/胜利村_shp_3857/cjqy.shp"; // cjqy | |||||
| 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()) | |||||
| { | |||||
| geo.Open(PATH, "UTF-8"); | |||||
| System.err.println(geo.GetTypeNames()); | |||||
| geo.SetSource(0); | |||||
| List<Map<String, Object>> cjqies = geo.GetMapList(); | |||||
| //List<GeoCJQY> cjqies = geo.GetList(GeoCJQY.class); | |||||
| //List<GeoJTZY> cjqies = geo.GetList(GeoJTZY.class); | |||||
| //List<GeoZYHYCG> cjqies = geo.GetList(GeoZYHYCG.class); | |||||
| //List<GeoDK> cjqies = geo.GetList(GeoDK.class); | |||||
| System.err.println(JSON.toJSONString(cjqies)); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| package com.ruoyi.business.constants; | |||||
| public final class TaskEnums | |||||
| { | |||||
| public static final class TaskStatus | |||||
| { | |||||
| public static final String ST_READY = "0"; // 已准备 | |||||
| public static final String ST_WAIT = "1"; // 排队中 | |||||
| public static final String ST_RUNNING = "2"; // 运行中 | |||||
| public static final String ST_FINISH = "3"; // 已完成 | |||||
| public static final String ST_FAIL = "4"; // 失败 | |||||
| public static final String ST_TERMINATED = "5"; // 被终止 | |||||
| private TaskStatus() {} | |||||
| } | |||||
| public static final class ImportType | |||||
| { | |||||
| public static final String IT_OVERRIDE = "1"; // 覆盖导入 | |||||
| public static final String IT_APPEND = "2"; // 增量导入 | |||||
| private ImportType() {} | |||||
| } | |||||
| private TaskEnums() {} | |||||
| } | |||||
| @@ -74,4 +74,6 @@ public interface TGisCjqyMapper | |||||
| * @return 结果 | * @return 结果 | ||||
| */ | */ | ||||
| public int deleteTGisCjqyByFids(Long[] fids); | public int deleteTGisCjqyByFids(Long[] fids); | ||||
| public int deleteByCode(String importCode); | |||||
| } | } | ||||
| @@ -74,4 +74,7 @@ public interface TTaskImportMapper | |||||
| * @return 结果 | * @return 结果 | ||||
| */ | */ | ||||
| public int deleteTTaskImportByIds(Long[] ids); | public int deleteTTaskImportByIds(Long[] ids); | ||||
| public int terminateRunningTask(); | |||||
| public TTaskImport getForUpdate(Long id); | |||||
| } | } | ||||
| @@ -0,0 +1,22 @@ | |||||
| package com.ruoyi.geo.config; | |||||
| import org.springframework.boot.context.properties.ConfigurationProperties; | |||||
| import org.springframework.stereotype.Component; | |||||
| @Component | |||||
| @ConfigurationProperties(prefix = "import-task") | |||||
| public class GeoImportTaskConfig | |||||
| { | |||||
| public static boolean startOnBoot = false; // 是否启动时执行等待中的任务 | |||||
| public static long logNextPoll = 2000; // 下次建议读取日志的间隔(毫秒) | |||||
| public void setStartOnBoot(boolean startOnBoot) | |||||
| { | |||||
| GeoImportTaskConfig.startOnBoot = startOnBoot; | |||||
| } | |||||
| public void setLogNextPoll(long logNextPoll) | |||||
| { | |||||
| GeoImportTaskConfig.logNextPoll = logNextPoll; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| package com.ruoyi.geo.constants; | |||||
| public final class GeoShpType | |||||
| { | |||||
| public static final String CJQY = "cjqy"; | |||||
| public static final String JTZY = "jtzy"; | |||||
| public static final String ZYHYCG = "zyhycg"; | |||||
| public static final String DK = "dk"; | |||||
| private GeoShpType() {} | |||||
| } | |||||
| @@ -0,0 +1,72 @@ | |||||
| package com.ruoyi.geo.constants; | |||||
| import com.ruoyi.common.config.RuoYiConfig; | |||||
| import com.ruoyi.common.utils.StringUtils; | |||||
| public final class GeoSysDir | |||||
| { | |||||
| // 导入日志路径 | |||||
| public static final String LOG = "/log"; | |||||
| // 导入zip临时解压路径 | |||||
| public static final String ZIP_EXTRACT_TEMP = "/unzip"; | |||||
| public static String GetDir(String path) | |||||
| { | |||||
| if(StringUtils.isEmpty(path)) | |||||
| path = ""; | |||||
| else if(!path.startsWith("/")) | |||||
| path = "/" + path; | |||||
| String str = ""; | |||||
| if(!path.startsWith(RuoYiConfig.getProfile())) | |||||
| str += RuoYiConfig.getProfile(); | |||||
| str += path; | |||||
| return str; | |||||
| } | |||||
| public static String CacheDir(String dir) | |||||
| { | |||||
| if(null == dir) | |||||
| dir = ""; | |||||
| return GetDir("/cache" + dir); | |||||
| } | |||||
| public static String ImportDir(String dir) | |||||
| { | |||||
| if(null == dir) | |||||
| dir = ""; | |||||
| return GetDir("/import" + dir); | |||||
| } | |||||
| public static String ExportDir(String dir) | |||||
| { | |||||
| if(null == dir) | |||||
| dir = ""; | |||||
| return GetDir("/export" + dir); | |||||
| } | |||||
| public static String Desensitized(String path) | |||||
| { | |||||
| if(StringUtils.isEmpty(path)) | |||||
| return path; | |||||
| String fpath = path.replaceAll("\\\\", "/"); | |||||
| String fprofile = RuoYiConfig.getProfile().replaceAll("\\\\", "/"); | |||||
| if(!fpath.startsWith(fprofile)) | |||||
| return path; | |||||
| return "<profile directory>" + path.substring(RuoYiConfig.getProfile().length()); | |||||
| } | |||||
| public static String DesensitizedNormalized(String path) | |||||
| { | |||||
| if(StringUtils.isEmpty(path)) | |||||
| return path; | |||||
| String fpath = path.replaceAll("\\\\", "/"); | |||||
| String fprofile = RuoYiConfig.getProfile().replaceAll("\\\\", "/"); | |||||
| if(!fpath.startsWith(fprofile)) | |||||
| return path; | |||||
| return "<profile directory>" + fpath.substring(fprofile.length()); | |||||
| } | |||||
| private GeoSysDir() {} | |||||
| } | |||||
| @@ -0,0 +1,149 @@ | |||||
| package com.ruoyi.geo.framework; | |||||
| import cn.hutool.core.collection.ListUtil; | |||||
| import com.ruoyi.business.domain.TGisCjqy; | |||||
| 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.structs.GeoCJQY; | |||||
| import static com.ruoyi.business.constants.TaskEnums.ImportType; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import java.util.stream.Collectors; | |||||
| public class GeoCjqyTask implements GeoDBTaskInterface | |||||
| { | |||||
| private final static String TYPE_NAME = "村级区域"; | |||||
| private final GeoImportTask importTask; | |||||
| private List<GeoCJQY> list; | |||||
| public GeoCjqyTask(GeoImportTask importTask) | |||||
| { | |||||
| this.importTask = importTask; | |||||
| } | |||||
| public int LoadDataList() | |||||
| { | |||||
| list = importTask.parser.GetList(GeoCJQY.class); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "shp读取数据条数: " + list.size()); | |||||
| return list.size(); | |||||
| } | |||||
| public void CheckData() | |||||
| { | |||||
| boolean hasEmpty = list.stream().anyMatch((x) -> StringUtils.isEmpty(x.CJQYDM)); | |||||
| if(hasEmpty) | |||||
| { | |||||
| importTask.logFile.ErrorLine("shp文件支持源中的行政区划代码缺失"); | |||||
| return; | |||||
| } | |||||
| List<String> collect = list.stream().map((x) -> x.CJQYDM).distinct().collect(Collectors.toList()); | |||||
| for(String importCode : collect) | |||||
| { | |||||
| SysDept dept = importTask.importDeptMap.get(importCode); | |||||
| if(null == dept) | |||||
| { | |||||
| importTask.logFile.ErrorLine("shp文件支持源中的行政区划代码在系统不存在: " + importCode); | |||||
| return; | |||||
| } | |||||
| if(!dept.getOrgCode().startsWith(importTask.taskImport.getOrgCode())) | |||||
| { | |||||
| importTask.logFile.ErrorLine(TYPE_NAME + "shp文件支持源中的行政区划代码与系统不匹配: 文件({}) != 系统({})", dept.getOrgCode(), importTask.taskImport.getOrgCode()); | |||||
| } | |||||
| } | |||||
| } | |||||
| private List<TGisCjqy> LoadDatabase(String qydm) | |||||
| { | |||||
| TGisCjqy cond = new TGisCjqy(); | |||||
| cond.setCjqydm(qydm); | |||||
| List<TGisCjqy> cjqies = GeoImportHandlerService.GisCjqyMapper().selectTGisCjqyList(cond); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "读取系统已存在的条数: 区划代码={}, 条数={}", qydm, cjqies.size()); | |||||
| return cjqies; | |||||
| } | |||||
| private TGisCjqy ConvertData(GeoCJQY src, TGisCjqy dst, SysDept dept) | |||||
| { | |||||
| if(null == dst) | |||||
| dst = new TGisCjqy(); | |||||
| dst.setTheGeom(src.the_geom); | |||||
| dst.setImportCode(dept.getImportCode()); | |||||
| dst.setCjqydm(src.CJQYDM); | |||||
| dst.setBsm(src.BSM.longValue()); | |||||
| dst.setCjqymc(src.CJQYMC); | |||||
| dst.setYsdm(src.YSDM); | |||||
| return dst; | |||||
| } | |||||
| private int CleanDatabase(String importCode) | |||||
| { | |||||
| if(ImportType.IT_OVERRIDE.equals(importTask.taskImport.getImportType())) | |||||
| { | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "覆盖导入, 需清空现有数据, 然后再插入, 区划代码={}", importCode); | |||||
| int ret = GeoImportHandlerService.GisCjqyMapper().deleteByCode(importCode); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "清空现有数据: {}, 区划代码={}", ret, importCode); | |||||
| return ret; | |||||
| } | |||||
| else | |||||
| { | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "增量导入, 无需清空现有数据, 仅执行插入或更新, 区划代码={}", importCode); | |||||
| return -1; | |||||
| } | |||||
| } | |||||
| private int WriteData(List<TGisCjqy> insertList, List<TGisCjqy> updateList, SysDept dept) | |||||
| { | |||||
| TGisCjqyMapper gisCjqyMapper = GeoImportHandlerService.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); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "更新数据: 区划代码={}, 条数={}", dept.getDeptName(), u); | |||||
| return i + u; | |||||
| } | |||||
| private int SaveDeptData(SysDept dept, List<GeoCJQY> datas) | |||||
| { | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "开始处理数据: 区划代码={}, 条数={}", dept.getDeptName(), datas.size()); | |||||
| List<TGisCjqy> databases = LoadDatabase(dept.getImportCode()); | |||||
| Map<String, TGisCjqy> exists = databases.stream().collect(Collectors.toMap(TGisCjqy::getCjqydm, x->x)); | |||||
| List<TGisCjqy> insertList = new ArrayList<>(); | |||||
| List<TGisCjqy> 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); | |||||
| else | |||||
| updateList.add(db); | |||||
| } | |||||
| CleanDatabase(dept.getImportCode()); | |||||
| int ret = WriteData(insertList, updateList, dept); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "总写入数据: 区划代码={}, 条数={}", dept.getDeptName(), ret); | |||||
| return ret; | |||||
| } | |||||
| public int SaveData() | |||||
| { | |||||
| int ret = 0; | |||||
| Map<String, List<GeoCJQY>> group = list.stream().collect(Collectors.groupingBy((x) -> x.CJQYDM)); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "shp数据: 区划代码类型数={}", group.size()); | |||||
| for(String dm : group.keySet()) | |||||
| { | |||||
| SysDept dept = importTask.importDeptMap.get(dm); | |||||
| ret = SaveDeptData(dept, group.get(dm)); | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,8 @@ | |||||
| package com.ruoyi.geo.framework; | |||||
| public interface GeoDBTaskInterface | |||||
| { | |||||
| public int LoadDataList(); | |||||
| public void CheckData(); | |||||
| public int SaveData(); | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| package com.ruoyi.geo.framework; | |||||
| public class GeoException extends RuntimeException | |||||
| { | |||||
| public GeoException(String msg) | |||||
| { | |||||
| super(msg); | |||||
| } | |||||
| public GeoException(Throwable e) | |||||
| { | |||||
| super(e); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,46 @@ | |||||
| package com.ruoyi.geo.framework; | |||||
| import cn.hutool.core.io.FileUtil; | |||||
| import com.ruoyi.common.utils.StringUtils; | |||||
| import java.io.File; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| public final class GeoFileSystem | |||||
| { | |||||
| public static List<String> FindFiles(File dir, String suffix) | |||||
| { | |||||
| return FindFiles_r(new ArrayList<>(), dir, suffix); | |||||
| } | |||||
| public static List<String> FindFiles_r(List<String> list, File dir, String suffix) | |||||
| { | |||||
| File[] files; | |||||
| if(StringUtils.isEmpty(suffix)) | |||||
| files = dir.listFiles(); | |||||
| else | |||||
| { | |||||
| String ext = suffix.toLowerCase(); | |||||
| files = dir.listFiles((d, f) -> { | |||||
| if(FileUtil.isDirectory(d.getAbsolutePath() + File.separatorChar + f)) | |||||
| return true; | |||||
| return f.toLowerCase().endsWith(ext); | |||||
| }); | |||||
| } | |||||
| if(null != files) | |||||
| { | |||||
| for(File file : files) | |||||
| { | |||||
| if(file.isDirectory()) | |||||
| FindFiles_r(list, file, suffix); | |||||
| else | |||||
| list.add(file.getAbsolutePath()); | |||||
| } | |||||
| } | |||||
| return list; | |||||
| } | |||||
| private GeoFileSystem() {} | |||||
| } | |||||
| @@ -0,0 +1,293 @@ | |||||
| 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.TTaskImport; | |||||
| import com.ruoyi.common.config.RuoYiConfig; | |||||
| import com.ruoyi.common.core.domain.entity.SysDept; | |||||
| import com.ruoyi.common.geo.GeoParser; | |||||
| import com.ruoyi.common.utils.ExceptionUtil; | |||||
| 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.GeoImportHandlerService; | |||||
| import com.ruoyi.system.mapper.SysDeptMapper; | |||||
| import lombok.extern.slf4j.Slf4j; | |||||
| import static com.ruoyi.business.constants.TaskEnums.TaskStatus; | |||||
| import java.io.File; | |||||
| import java.util.Date; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import java.util.stream.Collectors; | |||||
| @Slf4j | |||||
| public class GeoImportTask implements Runnable | |||||
| { | |||||
| private final Long taskId; | |||||
| TTaskImport taskImport; | |||||
| GeoTaskLog logFile; | |||||
| GeoParser parser; | |||||
| Map<String, SysDept> importDeptMap; | |||||
| private Map<String, SysDept> sysDeptMap; | |||||
| private List<String> shpFiles; | |||||
| private List<String> typeNames; | |||||
| private String shpPath; | |||||
| private String type; | |||||
| String username; | |||||
| Date now; | |||||
| private GeoDBTaskInterface task; | |||||
| public GeoImportTask(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 UnzipCachePath() | |||||
| { | |||||
| return GeoSysDir.CacheDir(GeoSysDir.ZIP_EXTRACT_TEMP + "/" + taskId); | |||||
| } | |||||
| public String LogPath() | |||||
| { | |||||
| return GeoSysDir.ImportDir(GeoSysDir.LOG) + "/" + taskId + ".log"; | |||||
| } | |||||
| private void ExtractZip() | |||||
| { | |||||
| // 先清空源临时解压文件 | |||||
| CleanTempFiles(); | |||||
| File file = new File(RuoYiConfig.getProfile() + "/" + taskImport.getFileUrl()); | |||||
| logFile.WriteLine("正在打开zip文件: " + GeoSysDir.DesensitizedNormalized(file.getAbsolutePath())); | |||||
| if(!file.isFile()) | |||||
| { | |||||
| logFile.ErrorLine("zip文件不存在: " + GeoSysDir.DesensitizedNormalized(file.getAbsolutePath())); | |||||
| } | |||||
| String toDir = UnzipCachePath(); | |||||
| File dir = ZipUtil.unzip(file, new File(toDir)); | |||||
| shpFiles = GeoFileSystem.FindFiles(dir, ".shp"); | |||||
| logFile.WriteLine("zip文件中发现shp文件: " + shpFiles.size()); | |||||
| if(shpFiles.isEmpty()) | |||||
| { | |||||
| logFile.ErrorLine("zip文件中未找到shp文件: " + GeoSysDir.DesensitizedNormalized(file.getAbsolutePath())); | |||||
| } | |||||
| int i = 0; | |||||
| for(String shpFile : shpFiles) | |||||
| { | |||||
| logFile.WriteLine("{}: {}", ++i, GeoSysDir.DesensitizedNormalized(shpFile)); | |||||
| } | |||||
| } | |||||
| private void CleanTempFiles() | |||||
| { | |||||
| String toDir = UnzipCachePath(); | |||||
| logFile.WriteLine("清理临时文件: " + GeoSysDir.DesensitizedNormalized(toDir)); | |||||
| FileUtil.del(toDir); | |||||
| } | |||||
| private void ParseShp() | |||||
| { | |||||
| if(null == parser) | |||||
| parser = new GeoParser(); | |||||
| parser.close(); | |||||
| if(!parser.Open(shpPath, "UTF-8")) | |||||
| { | |||||
| logFile.ErrorLine("打开shp文件错误: " + shpPath); | |||||
| } | |||||
| typeNames = parser.GetTypeNames(); | |||||
| if(CollectionUtil.isEmpty(typeNames)) | |||||
| { | |||||
| logFile.ErrorLine("shp文件支持源未读取到任何数据类型: " + shpPath); | |||||
| } | |||||
| } | |||||
| private boolean LoadDataList() | |||||
| { | |||||
| if(!parser.SetSource(type)) | |||||
| { | |||||
| logFile.ErrorLine("shp文件未找到支持源: " + type); | |||||
| return false; | |||||
| } | |||||
| int num = task.LoadDataList(); | |||||
| if(num == 0) | |||||
| { | |||||
| logFile.WriteLine("shp文件支持源未读取到数据: " + type); | |||||
| return false; | |||||
| } | |||||
| task.CheckData(); | |||||
| return true; | |||||
| } | |||||
| private void LoadDept() | |||||
| { | |||||
| SysDept cond = new SysDept(); | |||||
| SysDeptMapper deptMapper = SpringUtils.getBean(SysDeptMapper.class); | |||||
| List<SysDept> sysDepts = 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); | |||||
| if(null == task) | |||||
| { | |||||
| logFile.ErrorLine("任务配置不存在: " + taskId); | |||||
| return; | |||||
| } | |||||
| if(!TaskStatus.ST_WAIT.equals(task.getTaskStatus())) | |||||
| { | |||||
| logFile.ErrorLine("任务非等待状态: " + taskId); | |||||
| return; | |||||
| } | |||||
| taskImport = task; | |||||
| } | |||||
| private void SaveTask(String st) | |||||
| { | |||||
| if(null != taskImport) | |||||
| { | |||||
| taskImport.setTaskStatus(st); | |||||
| GeoImportHandlerService.TaskImportMapper().updateTTaskImport(taskImport); | |||||
| } | |||||
| } | |||||
| private void HandleShpFiles() | |||||
| { | |||||
| for(String shpFile : shpFiles) | |||||
| { | |||||
| shpPath = shpFile; | |||||
| HandleShpFile(); | |||||
| } | |||||
| } | |||||
| private void HandleShpFile() | |||||
| { | |||||
| // 1. 读取当前shp文件中的所有类型 | |||||
| ParseShp(); | |||||
| for(String typeName : typeNames) | |||||
| { | |||||
| type = typeName; | |||||
| // 2. 分发任务 | |||||
| DispatchTask(); | |||||
| } | |||||
| } | |||||
| private void DispatchTask() | |||||
| { | |||||
| // 1. 选择任务类型 | |||||
| switch(type.toLowerCase()) | |||||
| { | |||||
| case GeoShpType.CJQY: | |||||
| task = new GeoCjqyTask(this); | |||||
| break; | |||||
| case GeoShpType.JTZY: | |||||
| task = new GeoJtzyTask(this); | |||||
| break; | |||||
| case GeoShpType.ZYHYCG: | |||||
| task = new GeoZyhycgTask(this); | |||||
| break; | |||||
| default: | |||||
| logFile.WriteLine("数据类型不支持: " + type); | |||||
| return; | |||||
| } | |||||
| // 2. 处理导入任务 | |||||
| DoTask(); | |||||
| } | |||||
| private void DoTask() | |||||
| { | |||||
| // 1. 读取数据列表 | |||||
| if(!LoadDataList()) | |||||
| return; | |||||
| // 2. 保存数据列表 | |||||
| task.SaveData(); | |||||
| } | |||||
| private void Handle() | |||||
| { | |||||
| // 0. 初始化任务: 打开日志系统 | |||||
| Init(); | |||||
| // 1. 加载任务配置, 并检查 | |||||
| LoadTask(); | |||||
| // 2. 读取文件, 解压文件到工作目录 | |||||
| ExtractZip(); | |||||
| // 3. 加载部门数据 | |||||
| LoadDept(); | |||||
| // 4. 依次处理所有shp文件 | |||||
| HandleShpFiles(); | |||||
| } | |||||
| @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; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,181 @@ | |||||
| package com.ruoyi.geo.framework; | |||||
| 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.structs.GeoJTZY; | |||||
| import com.ruoyi.resource.domain.TResourceLand; | |||||
| import com.ruoyi.resource.mapper.TResourceLandMapper; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import java.util.stream.Collectors; | |||||
| import static com.ruoyi.business.constants.TaskEnums.ImportType; | |||||
| public class GeoJtzyTask implements GeoDBTaskInterface | |||||
| { | |||||
| private final static String TYPE_NAME = "地块属性"; | |||||
| private final GeoImportTask importTask; | |||||
| private List<GeoJTZY> list; | |||||
| public GeoJtzyTask(GeoImportTask importTask) | |||||
| { | |||||
| this.importTask = importTask; | |||||
| } | |||||
| public int LoadDataList() | |||||
| { | |||||
| list = importTask.parser.GetList(GeoJTZY.class); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "shp读取数据条数: " + list.size()); | |||||
| return list.size(); | |||||
| } | |||||
| public void CheckData() | |||||
| { | |||||
| boolean hasEmpty = list.stream().anyMatch((x) -> (StringUtils.isEmpty(x.DKBM) && StringUtils.isEmpty(x.QSDWDM)) || (x.DKBM.length() < 12 && x.QSDWDM.length() < 12)); | |||||
| if(hasEmpty) | |||||
| { | |||||
| importTask.logFile.ErrorLine("shp文件支持源中的行政区划代码缺失或不完整"); | |||||
| return; | |||||
| } | |||||
| List<String> collect = list.stream().map(GeoJTZY::Code).distinct().collect(Collectors.toList()); | |||||
| for(String importCode : collect) | |||||
| { | |||||
| SysDept dept = importTask.importDeptMap.get(importCode); | |||||
| if(null == dept) | |||||
| { | |||||
| importTask.logFile.WriteLine("shp文件支持源中的行政区划代码在系统不存在: " + importCode); | |||||
| continue; | |||||
| } | |||||
| if(!dept.getOrgCode().startsWith(importTask.taskImport.getOrgCode())) | |||||
| { | |||||
| importTask.logFile.ErrorLine(TYPE_NAME + "shp文件支持源中的行政区划代码与系统不匹配: 文件({}) != 系统({})", dept.getOrgCode(), importTask.taskImport.getOrgCode()); | |||||
| } | |||||
| } | |||||
| } | |||||
| private List<TResourceLand> LoadDatabase(String qydm) | |||||
| { | |||||
| TResourceLand cond = new TResourceLand(); | |||||
| cond.setImportCode(qydm); | |||||
| List<TResourceLand> cjqies = GeoImportHandlerService.ResourceLandMapper().selectTResourceLandList(cond); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "读取系统已存在的条数: 区划代码={}, 条数={}", qydm, cjqies.size()); | |||||
| return cjqies; | |||||
| } | |||||
| private TResourceLand ConvertData(GeoJTZY src, TResourceLand dst, SysDept dept) | |||||
| { | |||||
| boolean notExists = null == dst; | |||||
| if(notExists) | |||||
| dst = new TResourceLand(); | |||||
| dst.setTheGeom(src.the_geom); | |||||
| dst.setImportCode(dept.getImportCode()); | |||||
| dst.setBsm(src.BSM); | |||||
| dst.setYsdm(src.YSDM); | |||||
| dst.setDkbm(src.DKBM); | |||||
| dst.setDkmc(src.DKMC); | |||||
| dst.setSyqxz(src.SYQXZ); | |||||
| dst.setDklb(src.DKLB); | |||||
| dst.setDldj(src.DLDJ); | |||||
| dst.setTdyt(src.TDYT); | |||||
| dst.setSfjbnt(src.SFJBNT); | |||||
| dst.setDkdz(src.DKDZ); | |||||
| dst.setDkxz(src.DKXZ); | |||||
| dst.setDknz(src.DKNZ); | |||||
| dst.setDkbz(src.DKBZ); | |||||
| dst.setZjrxm(src.ZJRXM); | |||||
| dst.setDkbzxx(src.DKBZXX); | |||||
| dst.setTxmj(src.TXMJ); | |||||
| dst.setQsdwdm(src.QSDWDM); | |||||
| dst.setQsdwmc(src.QSDWMC); | |||||
| dst.setSfzwd(src.SFZWD); | |||||
| dst.setScmjm(src.SCMJM); | |||||
| dst.setDeptName(dept.getDeptName()); | |||||
| if(notExists) | |||||
| { | |||||
| dst.setSurveyStatus("1"); | |||||
| dst.setCreateBy(importTask.username); | |||||
| dst.setCreateTime(importTask.now); | |||||
| } | |||||
| else | |||||
| { | |||||
| dst.setUpdateBy(importTask.username); | |||||
| dst.setUpdateTime(importTask.now); | |||||
| } | |||||
| return dst; | |||||
| } | |||||
| private int CleanDatabase(String importCode) | |||||
| { | |||||
| if(ImportType.IT_OVERRIDE.equals(importTask.taskImport.getImportType())) | |||||
| { | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "覆盖导入, 需清空现有数据, 然后再插入, 区划代码={}", importCode); | |||||
| int ret = GeoImportHandlerService.ResourceLandMapper().deleteByCode(importCode); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "清空现有数据: {}, 区划代码={}", ret, importCode); | |||||
| return ret; | |||||
| } | |||||
| else | |||||
| { | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "增量导入, 无需清空现有数据, 仅执行插入或更新, 区划代码={}", importCode); | |||||
| return -1; | |||||
| } | |||||
| } | |||||
| private int WriteData(List<TResourceLand> insertList, List<TResourceLand> updateList, SysDept dept) | |||||
| { | |||||
| TResourceLandMapper gisCjqyMapper = GeoImportHandlerService.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); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "更新数据: 区划代码={}, 条数={}", dept.getDeptName(), u); | |||||
| return i + u; | |||||
| } | |||||
| private int SaveDeptData(SysDept dept, List<GeoJTZY> datas) | |||||
| { | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "开始处理数据: 区划代码={}, 条数={}", dept.getDeptName(), datas.size()); | |||||
| List<TResourceLand> databases = LoadDatabase(dept.getImportCode()); | |||||
| Map<String, TResourceLand> exists = databases.stream().collect(Collectors.toMap(TResourceLand::getDkbm, x->x)); | |||||
| List<TResourceLand> insertList = new ArrayList<>(); | |||||
| List<TResourceLand> 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); | |||||
| else | |||||
| updateList.add(db); | |||||
| } | |||||
| CleanDatabase(dept.getImportCode()); | |||||
| int ret = WriteData(insertList, updateList, dept); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "总写入数据: 区划代码={}, 条数={}", dept.getDeptName(), ret); | |||||
| return ret; | |||||
| } | |||||
| public int SaveData() | |||||
| { | |||||
| int ret = 0; | |||||
| Map<String, List<GeoJTZY>> group = list.stream().collect(Collectors.groupingBy(GeoJTZY::Code)); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "shp数据: 区划代码类型数={}", group.size()); | |||||
| for(String dm : group.keySet()) | |||||
| { | |||||
| SysDept dept = importTask.importDeptMap.get(dm); | |||||
| if(null == dept) | |||||
| continue; | |||||
| ret = SaveDeptData(dept, group.get(dm)); | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,174 @@ | |||||
| package com.ruoyi.geo.framework; | |||||
| import cn.hutool.core.io.FileUtil; | |||||
| import cn.hutool.core.lang.Assert; | |||||
| import cn.hutool.core.thread.ThreadUtil; | |||||
| import cn.hutool.core.util.StrUtil; | |||||
| import lombok.extern.slf4j.Slf4j; | |||||
| import java.io.BufferedWriter; | |||||
| import java.io.Closeable; | |||||
| import java.io.File; | |||||
| import java.io.FileWriter; | |||||
| import java.io.IOException; | |||||
| @Slf4j | |||||
| public class GeoTaskLog implements Closeable | |||||
| { | |||||
| private BufferedWriter writer; | |||||
| private String path; | |||||
| private boolean autoFlush; | |||||
| public GeoTaskLog(String path) | |||||
| { | |||||
| this(path, true); | |||||
| } | |||||
| public GeoTaskLog(String path, boolean autoFlush) | |||||
| { | |||||
| this.path = path; | |||||
| this.autoFlush = autoFlush; | |||||
| } | |||||
| public boolean IsOpened() | |||||
| { | |||||
| return null != writer; | |||||
| } | |||||
| public boolean Open() | |||||
| { | |||||
| Assert.isNull(writer, "日志文件已经打开"); | |||||
| File file = CreateFile(); | |||||
| if(null == file) | |||||
| return false; | |||||
| try | |||||
| { | |||||
| FileWriter fos = new FileWriter(file); | |||||
| writer = new BufferedWriter(fos); | |||||
| log.info("打开日志文件: " + path); | |||||
| return true; | |||||
| } | |||||
| catch(Exception e) | |||||
| { | |||||
| e.printStackTrace(); | |||||
| return false; | |||||
| } | |||||
| } | |||||
| @Override | |||||
| public void close() | |||||
| { | |||||
| if(null != writer) | |||||
| { | |||||
| try | |||||
| { | |||||
| log.info("关闭日志文件: " + path); | |||||
| writer.flush(); | |||||
| writer.close(); | |||||
| writer = null; | |||||
| } | |||||
| catch(IOException e) | |||||
| { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| } | |||||
| private void AfterWrite() | |||||
| { | |||||
| if(autoFlush) | |||||
| { | |||||
| try | |||||
| { | |||||
| writer.flush(); | |||||
| } | |||||
| catch(IOException e) | |||||
| { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| } | |||||
| private void CheckWriter() | |||||
| { | |||||
| Assert.notNull(writer, "文件未打开"); | |||||
| } | |||||
| public void Error(String str, Object...args) | |||||
| { | |||||
| String text = StrUtil.format(str, args); | |||||
| Write(text); | |||||
| throw new GeoException(text); | |||||
| } | |||||
| public void ErrorLine(String str, Object...args) | |||||
| { | |||||
| String text = StrUtil.format(str, args); | |||||
| WriteLine(text); | |||||
| throw new GeoException(text); | |||||
| } | |||||
| public void Write(String str, Object...args) | |||||
| { | |||||
| String text = StrUtil.format(str, args); | |||||
| log.info(text); | |||||
| //ThreadUtil.sleep(5000); | |||||
| CheckWriter(); | |||||
| try | |||||
| { | |||||
| writer.write(text); | |||||
| AfterWrite(); | |||||
| } | |||||
| catch(IOException e) | |||||
| { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| public String GetString() | |||||
| { | |||||
| File file = new File(path); | |||||
| if(!file.isFile()) | |||||
| return null; | |||||
| return FileUtil.readUtf8String(file); | |||||
| } | |||||
| public void WriteLine(String str, Object...args) | |||||
| { | |||||
| Write(str, args); | |||||
| try | |||||
| { | |||||
| writer.newLine(); | |||||
| AfterWrite(); | |||||
| } | |||||
| catch(IOException e) | |||||
| { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| private File CreateFile() | |||||
| { | |||||
| File file = new File(path); | |||||
| if(file.exists()) | |||||
| { | |||||
| log.error("日志文件已存在: " + path); | |||||
| log.warn("覆盖日志文件: " + path); | |||||
| return file; | |||||
| } | |||||
| FileUtil.mkParentDirs(path); | |||||
| return file; | |||||
| } | |||||
| public String Path() | |||||
| { | |||||
| return path; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,261 @@ | |||||
| package com.ruoyi.geo.framework; | |||||
| import cn.hutool.core.thread.ThreadUtil; | |||||
| import lombok.extern.slf4j.Slf4j; | |||||
| import java.util.LinkedList; | |||||
| import java.util.List; | |||||
| import java.util.concurrent.atomic.AtomicInteger; | |||||
| import java.util.concurrent.atomic.AtomicReference; | |||||
| import java.util.function.Predicate; | |||||
| /** | |||||
| * 队列式任务线程 | |||||
| */ | |||||
| @Slf4j | |||||
| public class GeoTaskQueue implements Runnable | |||||
| { | |||||
| private static final int ST_DILE = 0; | |||||
| private static final int ST_READY = 1; | |||||
| private static final int ST_RUNNING = 2; | |||||
| private static final int ST_WORKING = 3; | |||||
| private static final int ST_WAITING = 4; | |||||
| private static final int ST_END = 5; | |||||
| private static final int ST_TERMINATED = 6; | |||||
| private volatile Thread thread; | |||||
| private final List<Runnable> queue = new LinkedList<>(); | |||||
| private final AtomicInteger state = new AtomicInteger(ST_DILE); | |||||
| private final Object lock = new Object(); | |||||
| private volatile boolean reqQuit = false; | |||||
| private final boolean quitOnNoTask; | |||||
| private Runnable currentTask = null; | |||||
| // 计数器 | |||||
| private volatile int c_loop = 0; | |||||
| private volatile int c_wait = 0; | |||||
| private volatile int c_work = 0; | |||||
| private volatile int c_error = 0; | |||||
| private volatile int c_run = 0; | |||||
| public GeoTaskQueue(boolean quitOnNoTask) { | |||||
| this.quitOnNoTask = quitOnNoTask; | |||||
| } | |||||
| @Override | |||||
| public void run() | |||||
| { | |||||
| Runnable task; | |||||
| log.info("[任务队列线程]: {}开始执行 -> {}", Thread.currentThread().getName(), Thread.currentThread().getId()); | |||||
| state.set(ST_RUNNING); | |||||
| for(;;) | |||||
| { | |||||
| c_loop++; | |||||
| synchronized(this) { | |||||
| if(reqQuit) | |||||
| { | |||||
| reqQuit = false; | |||||
| boolean hasTask = HasTask(); | |||||
| log.info("[退出任务队列线程]: 退出状态 -> " + (hasTask ? "中断" : "完成")); | |||||
| state.set(hasTask ? ST_TERMINATED : ST_END); | |||||
| break; | |||||
| } | |||||
| } | |||||
| task = TakeTask(); | |||||
| if(null == task) | |||||
| { | |||||
| if(quitOnNoTask) | |||||
| { | |||||
| log.info("[任务队列线程循环]: 当前无任务, 退出"); | |||||
| break; | |||||
| } | |||||
| // 如果没有任务, 则暂停线程 | |||||
| synchronized(lock) { | |||||
| try | |||||
| { | |||||
| c_wait++; | |||||
| log.info("[任务队列线程循环]: 当前无任务, 进入等待状态"); | |||||
| state.set(ST_WAITING); | |||||
| lock.wait(); | |||||
| log.info("[任务队列线程循环]: 有新任务添加, 继续执行"); | |||||
| } | |||||
| catch(InterruptedException e) | |||||
| { | |||||
| e.printStackTrace(); | |||||
| ThreadUtil.sleep(30000); // 强制等待30秒 | |||||
| } | |||||
| } | |||||
| continue; | |||||
| } | |||||
| log.info("[任务队列线程循环]: 正在执行任务"); | |||||
| state.set(ST_WORKING); | |||||
| c_work++; | |||||
| try | |||||
| { | |||||
| task.run(); | |||||
| } | |||||
| catch(Exception e) | |||||
| { | |||||
| c_error++; | |||||
| e.printStackTrace(); | |||||
| } | |||||
| synchronized(this) { | |||||
| currentTask = null; | |||||
| } | |||||
| log.info("[任务队列线程循环]: 当前任务执行完成"); | |||||
| state.set(ST_RUNNING); | |||||
| } | |||||
| log.info("[任务队列线程循环]: 执行结束"); | |||||
| state.set(IsRunning() ? ST_END : ST_TERMINATED); | |||||
| synchronized(this) { | |||||
| thread = null; | |||||
| } | |||||
| } | |||||
| public synchronized int AddTask(Runnable task) | |||||
| { | |||||
| queue.add(task); | |||||
| // 如果有任务, 则唤醒队列循环 | |||||
| synchronized(lock) { | |||||
| lock.notifyAll(); | |||||
| } | |||||
| return queue.size(); | |||||
| } | |||||
| public synchronized int AddTask(List<Runnable> tasks) | |||||
| { | |||||
| queue.addAll(tasks); | |||||
| // 如果有任务, 则唤醒队列循环 | |||||
| synchronized(lock) { | |||||
| lock.notifyAll(); | |||||
| } | |||||
| return queue.size(); | |||||
| } | |||||
| private synchronized Runnable TakeTask() | |||||
| { | |||||
| if(queue.isEmpty()) | |||||
| return null; | |||||
| currentTask = queue.remove(0); | |||||
| return currentTask; | |||||
| } | |||||
| public synchronized boolean HasTask() | |||||
| { | |||||
| return !queue.isEmpty(); | |||||
| } | |||||
| public boolean IsRunning() | |||||
| { | |||||
| int st = state.get(); | |||||
| return st == ST_RUNNING || st == ST_WAITING || st == ST_WORKING; | |||||
| } | |||||
| public synchronized void RequestQuit() | |||||
| { | |||||
| if(!IsRunning()) | |||||
| { | |||||
| log.warn("[请求结束任务队列线程]: 任务队列线程非运行状态 -> " + state.get()); | |||||
| return; | |||||
| } | |||||
| log.info("[请求结束任务队列线程]: 等待当前任务完成后中止"); | |||||
| if(reqQuit) | |||||
| return; | |||||
| reqQuit = true; | |||||
| } | |||||
| public void Quit() | |||||
| { | |||||
| synchronized(this) { | |||||
| if(null == thread) | |||||
| return; | |||||
| } | |||||
| RequestQuit(); | |||||
| try | |||||
| { | |||||
| log.info("[结束任务队列线程]: 等待当前任务完成"); | |||||
| thread.join(); | |||||
| synchronized(this) { | |||||
| thread = null; | |||||
| } | |||||
| } | |||||
| catch(InterruptedException e) | |||||
| { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| private void Reset() | |||||
| { | |||||
| log.info("[重置任务队列线程]: 重置状态"); | |||||
| reqQuit = false; | |||||
| c_loop = 0; | |||||
| c_wait = 0; | |||||
| c_work = 0; | |||||
| c_error = 0; | |||||
| state.set(ST_DILE); | |||||
| currentTask = null; | |||||
| } | |||||
| public synchronized void StartTask(Runnable task) | |||||
| { | |||||
| if(IsRunning()) | |||||
| AddTask(task); | |||||
| else | |||||
| { | |||||
| queue.add(task); | |||||
| Start(); | |||||
| } | |||||
| } | |||||
| public synchronized void StartTask(List<Runnable> task) | |||||
| { | |||||
| if(IsRunning()) | |||||
| AddTask(task); | |||||
| else | |||||
| { | |||||
| queue.addAll(task); | |||||
| Start(); | |||||
| } | |||||
| } | |||||
| public synchronized Runnable GetCurrentTask() | |||||
| { | |||||
| return currentTask; | |||||
| } | |||||
| public synchronized Runnable FindTask(Predicate<Runnable> op) | |||||
| { | |||||
| if(queue.isEmpty()) | |||||
| return null; | |||||
| return queue.stream().filter(op).findFirst().orElse(null); | |||||
| } | |||||
| public synchronized void Start() | |||||
| { | |||||
| if(null != thread) | |||||
| { | |||||
| log.error("[启动任务队列线程]: 上次任务队列线程仍在运行 -> " + thread.getName()); | |||||
| return; | |||||
| } | |||||
| int st = state.get(); | |||||
| if(st != ST_DILE && st != ST_END && st != ST_TERMINATED) | |||||
| { | |||||
| log.error("[启动任务队列线程]: 任务队列线程非空闲/结束/中止状态 -> " + st); | |||||
| return; | |||||
| } | |||||
| Reset(); | |||||
| if(state.get() != ST_DILE) | |||||
| { | |||||
| log.error("[开始任务队列线程]: 任务队列线程非空闲状态"); | |||||
| return; | |||||
| } | |||||
| thread = new Thread(this);thread.interrupt(); | |||||
| thread.setName("任务线程_" + c_run++); | |||||
| state.set(ST_READY); | |||||
| thread.start(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,179 @@ | |||||
| package com.ruoyi.geo.framework; | |||||
| import cn.hutool.core.collection.ListUtil; | |||||
| 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.structs.GeoZYHYCG; | |||||
| import com.ruoyi.resource.domain.TResourceOperation; | |||||
| import com.ruoyi.resource.mapper.TResourceOperationMapper; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import java.util.stream.Collectors; | |||||
| import static com.ruoyi.business.constants.TaskEnums.ImportType; | |||||
| public class GeoZyhycgTask implements GeoDBTaskInterface | |||||
| { | |||||
| private final static String TYPE_NAME = "地块经营"; | |||||
| private final GeoImportTask importTask; | |||||
| private List<GeoZYHYCG> list; | |||||
| public GeoZyhycgTask(GeoImportTask importTask) | |||||
| { | |||||
| this.importTask = importTask; | |||||
| } | |||||
| public int LoadDataList() | |||||
| { | |||||
| list = importTask.parser.GetList(GeoZYHYCG.class); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "shp读取数据条数: " + list.size()); | |||||
| return list.size(); | |||||
| } | |||||
| public void CheckData() | |||||
| { | |||||
| boolean hasEmpty = list.stream().anyMatch((x) -> StringUtils.isEmpty(x.DKBM) || x.DKBM.length() < 12); | |||||
| if(hasEmpty) | |||||
| { | |||||
| importTask.logFile.ErrorLine("shp文件支持源中的行政区划代码缺失或不完整"); | |||||
| return; | |||||
| } | |||||
| List<String> collect = list.stream().map(GeoZYHYCG::Code).distinct().collect(Collectors.toList()); | |||||
| for(String importCode : collect) | |||||
| { | |||||
| SysDept dept = importTask.importDeptMap.get(importCode); | |||||
| if(null == dept) | |||||
| { | |||||
| importTask.logFile.WriteLine("shp文件支持源中的行政区划代码在系统不存在: " + importCode); | |||||
| continue; | |||||
| } | |||||
| if(!dept.getOrgCode().startsWith(importTask.taskImport.getOrgCode())) | |||||
| { | |||||
| importTask.logFile.ErrorLine(TYPE_NAME + "shp文件支持源中的行政区划代码与系统不匹配: 文件({}) != 系统({})", dept.getOrgCode(), importTask.taskImport.getOrgCode()); | |||||
| } | |||||
| } | |||||
| } | |||||
| private List<TResourceOperation> LoadDatabase(String qydm) | |||||
| { | |||||
| TResourceOperation cond = new TResourceOperation(); | |||||
| cond.setImportCode(qydm); | |||||
| List<TResourceOperation> cjqies = GeoImportHandlerService.ResourceOperationMapper().selectTResourceOperationList(cond); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "读取系统已存在的条数: 区划代码={}, 条数={}", qydm, cjqies.size()); | |||||
| return cjqies; | |||||
| } | |||||
| private TResourceOperation ConvertData(GeoZYHYCG src, TResourceOperation dst, SysDept dept) | |||||
| { | |||||
| boolean notExists = null == dst; | |||||
| if(notExists) | |||||
| dst = new TResourceOperation(); | |||||
| dst.setImportCode(dept.getImportCode()); | |||||
| dst.setDkbm(src.DKBM); | |||||
| dst.setDkmc(src.DKMC); | |||||
| dst.setDkdz(src.SYQXZ); | |||||
| dst.setJymj(src.JYMJ); | |||||
| dst.setJydxlx(src.JYDXLX); | |||||
| dst.setJydxmc(src.JYDXMC); | |||||
| dst.setJydxzjlx(src.JYDXZJLX); | |||||
| dst.setJydxzjhm(src.JYDXZJHM); | |||||
| dst.setSfqdht(src.SFQDHT); | |||||
| dst.setJykssj(StrUtil.subPre(src.JYKSSJ, 10)); | |||||
| dst.setJyjssj(StrUtil.subPre(src.JYJSSJ, 10)); | |||||
| dst.setCbje(DecimalUtils.nullToZero(src.CBJE)); | |||||
| dst.setDxje(DecimalUtils.nullToZero(src.DXJE)); | |||||
| dst.setSqje(DecimalUtils.nullToZero(src.SQJE)); | |||||
| dst.setNsy(DecimalUtils.nullToZero(src.NSY)); | |||||
| dst.setBzxx(src.BZXX); | |||||
| dst.setJyfs(src.JYFS); | |||||
| dst.setDeptName(dept.getDeptName()); | |||||
| if(notExists) | |||||
| { | |||||
| dst.setSurveyStatus("1"); | |||||
| dst.setCreateBy(importTask.username); | |||||
| dst.setCreateTime(importTask.now); | |||||
| } | |||||
| else | |||||
| { | |||||
| dst.setUpdateBy(importTask.username); | |||||
| dst.setUpdateTime(importTask.now); | |||||
| } | |||||
| return dst; | |||||
| } | |||||
| private int CleanDatabase(String importCode) | |||||
| { | |||||
| if(ImportType.IT_OVERRIDE.equals(importTask.taskImport.getImportType())) | |||||
| { | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "覆盖导入, 需清空现有数据, 然后再插入, 区划代码={}", importCode); | |||||
| int ret = GeoImportHandlerService.ResourceOperationMapper().deleteByCode(importCode); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "清空现有数据: {}, 区划代码={}", ret, importCode); | |||||
| return ret; | |||||
| } | |||||
| else | |||||
| { | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "增量导入, 无需清空现有数据, 仅执行插入或更新, 区划代码={}", importCode); | |||||
| return -1; | |||||
| } | |||||
| } | |||||
| private int WriteData(List<TResourceOperation> insertList, List<TResourceOperation> updateList, SysDept dept) | |||||
| { | |||||
| TResourceOperationMapper gisCjqyMapper = GeoImportHandlerService.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); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "更新数据: 区划代码={}, 条数={}", dept.getDeptName(), u); | |||||
| return i + u; | |||||
| } | |||||
| private int SaveDeptData(SysDept dept, List<GeoZYHYCG> datas) | |||||
| { | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "开始处理数据: 区划代码={}, 条数={}", dept.getDeptName(), datas.size()); | |||||
| List<TResourceOperation> databases = LoadDatabase(dept.getImportCode()); | |||||
| Map<String, TResourceOperation> exists = databases.stream().collect(Collectors.toMap(TResourceOperation::getDkbm, x->x)); | |||||
| List<TResourceOperation> insertList = new ArrayList<>(); | |||||
| List<TResourceOperation> 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); | |||||
| else | |||||
| updateList.add(db); | |||||
| } | |||||
| CleanDatabase(dept.getImportCode()); | |||||
| int ret = WriteData(insertList, updateList, dept); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "总写入数据: 区划代码={}, 条数={}", dept.getDeptName(), ret); | |||||
| return ret; | |||||
| } | |||||
| public int SaveData() | |||||
| { | |||||
| int ret = 0; | |||||
| Map<String, List<GeoZYHYCG>> group = list.stream().collect(Collectors.groupingBy(GeoZYHYCG::Code)); | |||||
| importTask.logFile.WriteLine(TYPE_NAME + "shp数据: 区划代码类型数={}", group.size()); | |||||
| for(String dm : group.keySet()) | |||||
| { | |||||
| SysDept dept = importTask.importDeptMap.get(dm); | |||||
| if(null == dept) | |||||
| continue; | |||||
| ret = SaveDeptData(dept, group.get(dm)); | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| package com.ruoyi.geo.object; | |||||
| import lombok.Data; | |||||
| @Data | |||||
| public class GeoLogInfo | |||||
| { | |||||
| private Integer length; | |||||
| private String text; | |||||
| private Boolean eof; | |||||
| private String taskStatus; | |||||
| private Long nextPollDelay; | |||||
| } | |||||
| @@ -0,0 +1,247 @@ | |||||
| 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.TTaskImport; | |||||
| import com.ruoyi.business.mapper.TGisCjqyMapper; | |||||
| import com.ruoyi.business.mapper.TTaskImportMapper; | |||||
| import com.ruoyi.common.utils.sql.DB; | |||||
| import com.ruoyi.geo.config.GeoImportTaskConfig; | |||||
| import com.ruoyi.geo.constants.GeoSysDir; | |||||
| import com.ruoyi.geo.framework.GeoImportTask; | |||||
| import com.ruoyi.geo.framework.GeoTaskQueue; | |||||
| import com.ruoyi.geo.object.GeoLogInfo; | |||||
| 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 static com.ruoyi.business.constants.TaskEnums.TaskStatus; | |||||
| 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; | |||||
| @Service | |||||
| @Slf4j | |||||
| public class GeoImportHandlerService | |||||
| { | |||||
| @Resource | |||||
| private SysDeptMapper deptMapper; | |||||
| private static TTaskImportMapper taskImportMapper; | |||||
| private static TGisCjqyMapper gisCjqyMapper; | |||||
| private static TResourceLandMapper resourceLandMapper; | |||||
| private static TResourceOperationMapper resourceOperationMapper; | |||||
| 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) | |||||
| 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 = taskImportMapper.terminateRunningTask(); | |||||
| log.info("已设置运行中的任务状态为中止: " + i); | |||||
| } | |||||
| private void LoadTask() | |||||
| { | |||||
| if(!GeoImportTaskConfig.startOnBoot) | |||||
| return; | |||||
| log.info("拉取排队中的任务......"); | |||||
| TTaskImport cond = new TTaskImport(); | |||||
| cond.setTaskStatus(TaskStatus.ST_WAIT); | |||||
| List<TTaskImport> taskImports = taskImportMapper.selectTTaskImportList(cond); | |||||
| log.info("拉取到排队中的任务: " + taskImports.size()); | |||||
| List<Runnable> tasks = taskImports.stream().map((x) -> new GeoImportTask(x.getId())).collect(Collectors.toList()); | |||||
| if(!tasks.isEmpty()) | |||||
| TaskQueue().StartTask(tasks); | |||||
| } | |||||
| public GeoLogInfo GetImportLog(Long taskId, int offset) | |||||
| { | |||||
| GeoLogInfo info = new GeoLogInfo(); | |||||
| info.setNextPollDelay(GeoImportTaskConfig.logNextPoll); | |||||
| TTaskImport taskImport = taskImportMapper.selectTTaskImportById(taskId); | |||||
| Assert.notNull(taskImport, "导入任务不存在"); | |||||
| info.setTaskStatus(taskImport.getTaskStatus()); | |||||
| if(TaskStatus.ST_READY.equals(taskImport.getTaskStatus())/* || TaskStatus.ST_WAIT.equals(taskImport.getTaskStatus())*/) | |||||
| { | |||||
| info.setEof(true); | |||||
| info.setLength(-1); | |||||
| return info; | |||||
| } | |||||
| String path = GeoSysDir.ImportDir(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) | |||||
| { | |||||
| GeoImportTask task = (GeoImportTask)taskQueue.GetCurrentTask(); | |||||
| Assert.isFalse(null != task && task.GetTaskId().equals(id), "任务正在执行"); | |||||
| boolean exists = null != taskQueue.FindTask((x) -> { | |||||
| GeoImportTask t = (GeoImportTask) x; | |||||
| return(t.GetTaskId().equals(id)); | |||||
| }); | |||||
| Assert.isFalse(exists, "任务已在队列中"); | |||||
| } | |||||
| Object handler = DB.BeginTransaction(); | |||||
| try | |||||
| { | |||||
| TTaskImport taskImport = taskImportMapper.getForUpdate(id); | |||||
| Assert.notNull(taskImport, "任务不存在"); | |||||
| Assert.isTrue(TaskStatus.ST_READY.equals(taskImport.getTaskStatus()), "任务非准备状态"); | |||||
| taskImport.setTaskStatus(TaskStatus.ST_WAIT); | |||||
| taskImportMapper.updateTTaskImport(taskImport); | |||||
| DB.CommitTransaction(handler); | |||||
| } | |||||
| catch(Exception e) | |||||
| { | |||||
| e.printStackTrace(); | |||||
| DB.RollbackTransaction(handler); | |||||
| return 0; | |||||
| } | |||||
| int ret = null != taskQueue && taskQueue.HasTask() ? 1 : 2; | |||||
| TaskQueue().StartTask(new GeoImportTask(id)); | |||||
| return ret; | |||||
| } | |||||
| public void DownloadLog(Long taskId, HttpServletResponse response) | |||||
| { | |||||
| String path = GeoSysDir.ImportDir(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"); | |||||
| TTaskImport taskImport = taskImportMapper.selectTTaskImportById(taskId); | |||||
| if(null == taskImport) | |||||
| { | |||||
| ServletUtil.write(response, "导入任务不存在", "application/octet-stream; charset=UTF-8"); | |||||
| bytes = "导入任务不存在".getBytes(StandardCharsets.UTF_8).length; | |||||
| } | |||||
| File file = new File(path); | |||||
| if(!file.isFile()) | |||||
| { | |||||
| ServletUtil.write(response, "日志文件不存在", "application/octet-stream; charset=UTF-8"); | |||||
| bytes = "日志文件不存在".getBytes(StandardCharsets.UTF_8).length; | |||||
| } | |||||
| ServletUtil.write(response, file); | |||||
| response.addHeader("Content-Length", "" + bytes); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,69 @@ | |||||
| package com.ruoyi.geo.structs; | |||||
| import lombok.ToString; | |||||
| import java.math.BigDecimal; | |||||
| @ToString | |||||
| public final class GeoCJQY | |||||
| { | |||||
| /** | |||||
| * 对象ID | |||||
| */ | |||||
| public Long OBJECTID; | |||||
| /** | |||||
| * 县级区域代码 | |||||
| */ | |||||
| public String XJQYDM; | |||||
| /** | |||||
| * 边界长度(米) | |||||
| */ | |||||
| public BigDecimal Shape_Leng; | |||||
| /** | |||||
| * 县级区域名称 | |||||
| */ | |||||
| public String XJQYMC; | |||||
| /** | |||||
| * 村级区域代码 | |||||
| */ | |||||
| public String CJQYDM; | |||||
| /** | |||||
| * 行政区名称 | |||||
| */ | |||||
| public String XZQMC; | |||||
| /** | |||||
| * 区域面积(平方米) | |||||
| */ | |||||
| public BigDecimal Shape_Area; | |||||
| /** | |||||
| * 村级区域名称 | |||||
| */ | |||||
| public String CJQYMC; | |||||
| /** | |||||
| * 要素代码 | |||||
| */ | |||||
| public String YSDM; | |||||
| /** | |||||
| * 行政区代码 | |||||
| */ | |||||
| public String XZQDM; | |||||
| /** | |||||
| * 标识码 | |||||
| */ | |||||
| public Integer BSM; | |||||
| /** | |||||
| * 几何图形数据(WKT格式) | |||||
| */ | |||||
| public String the_geom; | |||||
| } | |||||
| @@ -0,0 +1,90 @@ | |||||
| package com.ruoyi.geo.structs; | |||||
| import lombok.ToString; | |||||
| import java.math.BigDecimal; | |||||
| @ToString | |||||
| public final class GeoDK | |||||
| { | |||||
| /** 承包人姓名 */ | |||||
| public String ZJRXM; | |||||
| /** 地块唯一标识符 */ | |||||
| public Long OBJECTID_1; | |||||
| /** 土地面积(公顷) */ | |||||
| public BigDecimal TXMJ; | |||||
| /** 是否在一类建设用地区域(1表示是) */ | |||||
| public String SFZWD; | |||||
| /** 所属行政区划代码(天津市代码200000) */ | |||||
| public String YSDM; | |||||
| /** 是否基本农田(1表示是) */ | |||||
| public String SFJBNT; | |||||
| /** 地块唯一标识符 */ | |||||
| public Long OBJECTID; | |||||
| /** 区划单位代码 */ | |||||
| public String QSDWDM; | |||||
| /** 剩余使用权年限(10年) */ | |||||
| public BigDecimal SYQXZ; | |||||
| /** 地块备注信息 */ | |||||
| public String DKBZXX; | |||||
| /** 地块标识码 */ | |||||
| public Integer BSM; | |||||
| /** 地块类型(99表示特殊用地) */ | |||||
| public String DKLB; | |||||
| /** 地块几何坐标(WKT格式) */ | |||||
| public String the_geom; | |||||
| /** 区划单位名称 */ | |||||
| public String QSDWMC; | |||||
| /** 地块性质(承包人姓名) */ | |||||
| public String DKXZ; | |||||
| /** 地块长度(米) */ | |||||
| public BigDecimal Shape_Le_1; | |||||
| /** 土地用途(1表示耕地) */ | |||||
| public String TDYT; | |||||
| /** 土地等级(01表示一级地) */ | |||||
| public String DLDJ; | |||||
| /** 土地来源类型(011表示集体分配) */ | |||||
| public String TDLYLX; | |||||
| /** 地块周长(米) */ | |||||
| public BigDecimal Shape_Leng; | |||||
| /** 实测面积(公顷) */ | |||||
| public BigDecimal SCMJM; | |||||
| /** 地块编码 */ | |||||
| public String DKBM; | |||||
| /** 地块内作物 */ | |||||
| public String DKNZ; | |||||
| /** 地块面积(平方米) */ | |||||
| public BigDecimal Shape_Area; | |||||
| /** 地块名称(孔家) */ | |||||
| public String DKMC; | |||||
| /** 地块地址(道路) */ | |||||
| public String DKDZ; | |||||
| /** 地块备注 */ | |||||
| public String DKBZ; | |||||
| } | |||||
| @@ -0,0 +1,107 @@ | |||||
| package com.ruoyi.geo.structs; | |||||
| import com.ruoyi.common.utils.StringUtils; | |||||
| import lombok.ToString; | |||||
| import java.math.BigDecimal; | |||||
| /** | |||||
| * 地块信息实体类 | |||||
| */ | |||||
| @ToString | |||||
| public final class GeoJTZY | |||||
| { | |||||
| /** 地块名称,空字符串表示未命名 */ | |||||
| public String ZJRXM; | |||||
| /** 地块唯一标识符 */ | |||||
| public Long OBJECTID_1; | |||||
| /** 地块面积(单位:公顷) */ | |||||
| public BigDecimal TXMJ; | |||||
| /** 是否在二类建设用地区域(2表示是) */ | |||||
| public String SFZWD; | |||||
| /** 关联对象ID */ | |||||
| public Long OBJECTID_2; | |||||
| /** 所属行政区划代码(吉林省代码220000) */ | |||||
| public String YSDM; | |||||
| /** 是否基本农田(2表示是) */ | |||||
| public String SFJBNT; | |||||
| /** 地块唯一标识符 */ | |||||
| public Long OBJECTID; | |||||
| /** 区划单位代码 */ | |||||
| public String QSDWDM; | |||||
| /** 所有权性质 */ | |||||
| public String SYQXZ; | |||||
| /** 地块备注信息 */ | |||||
| public String DKBZXX; | |||||
| /** 地块标识码 */ | |||||
| public Integer BSM; | |||||
| /** 地块类型 */ | |||||
| public String DKLB; | |||||
| /** 地块几何坐标(WKT格式) */ | |||||
| public String the_geom; | |||||
| /** 区划单位名称 */ | |||||
| public String QSDWMC; | |||||
| /** 地块性质 */ | |||||
| public String DKXZ; | |||||
| /** 地块长度(米) */ | |||||
| public BigDecimal Shape_Le_1; | |||||
| /** 地块宽度(米) */ | |||||
| public BigDecimal Shape_Le_2; | |||||
| /** 土地用途 */ | |||||
| public String TDYT; | |||||
| /** 土地等级 */ | |||||
| public String DLDJ; | |||||
| /** 土地来源类型 */ | |||||
| public String TDLYLX; | |||||
| /** 地块周长(米) */ | |||||
| public BigDecimal Shape_Leng; | |||||
| /** 实测面积(公顷) */ | |||||
| public BigDecimal SCMJM; | |||||
| /** 地块编码 */ | |||||
| public String DKBM; | |||||
| /** 地块内作物 */ | |||||
| public String DKNZ; | |||||
| /** 地块面积(公顷) */ | |||||
| public BigDecimal Shape_Area; | |||||
| /** 地块名称(200p平以下删除地块) */ | |||||
| public String DKMC; | |||||
| /** 地块地址 */ | |||||
| public String DKDZ; | |||||
| /** 地块备注 */ | |||||
| public String DKBZ; | |||||
| public String Code() | |||||
| { | |||||
| if(StringUtils.isNotEmpty(QSDWDM) && QSDWDM.length() >= 12) | |||||
| return QSDWDM.substring(0, 12); | |||||
| return DKBM.substring(0, 12); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,80 @@ | |||||
| package com.ruoyi.geo.structs; | |||||
| import lombok.ToString; | |||||
| import java.math.BigDecimal; | |||||
| /** | |||||
| * 集体用地信息实体类 | |||||
| */ | |||||
| @ToString | |||||
| public final class GeoZYHYCG | |||||
| { | |||||
| /** 用地类型(1表示集体建设用地) */ | |||||
| public String JYDXLX; | |||||
| /** 补偿金额 */ | |||||
| public BigDecimal CBJE; | |||||
| /** 土地面积(公顷) */ | |||||
| public BigDecimal TXMJ; | |||||
| /** 备注信息(林地未收费) */ | |||||
| public String BZXX; | |||||
| /** 净用地面积(公顷) */ | |||||
| public BigDecimal JYMJ; | |||||
| /** 抵押金额 */ | |||||
| public BigDecimal DXJE; | |||||
| /** 地块唯一标识符 */ | |||||
| public Long OBJECTID; | |||||
| /** 是否签订合同(2表示已签订) */ | |||||
| public String SFQDHT; | |||||
| /** 地块周长(米) */ | |||||
| public BigDecimal Shape_Leng; | |||||
| /** 地块编码 */ | |||||
| public String DKBM; | |||||
| /** 用地性质证明类型 */ | |||||
| public String JYDXZJLX; | |||||
| /** 用地单位名称(村集体) */ | |||||
| public String JYDXMC; | |||||
| /** 用地单位证件号码 */ | |||||
| public String JYDXZJHM; | |||||
| /** 年收益 */ | |||||
| public BigDecimal NSY; | |||||
| /** 使用权性质 */ | |||||
| public String SYQXZ; | |||||
| /** 地块面积(公顷) */ | |||||
| public BigDecimal Shape_Area; | |||||
| /** 地块名称(胜利村屯里) */ | |||||
| public String DKMC; | |||||
| /** 地块几何坐标(WKT格式) */ | |||||
| public String the_geom; | |||||
| /** 经营方式(120表示自主经营) */ | |||||
| public String JYFS; | |||||
| /** 申请金额 */ | |||||
| public BigDecimal SQJE; | |||||
| public String JYKSSJ; | |||||
| public String JYJSSJ; | |||||
| public String Code() | |||||
| { | |||||
| return DKBM.substring(0, 12); | |||||
| } | |||||
| } | |||||
| @@ -22,34 +22,46 @@ public class TBigDataScreen | |||||
| /** 部门名称 */ | /** 部门名称 */ | ||||
| private String deptName; | private String deptName; | ||||
| /** 统计数量1 首页上 资源调查进度统计 - */ | |||||
| /** 统计数量1 */ | |||||
| /** 首页上 资源调查进度统计 - 待调查总数*/ | |||||
| /** 首页下 地块总数*/ | |||||
| private String dataNum1; | private String dataNum1; | ||||
| /** 统计数量2 */ | |||||
| /** 统计数量2*/ | |||||
| /** 首页上 资源调查进度统计 - 已调查总数*/ | |||||
| /** 首页下 待调查总数*/ | |||||
| private String dataNum2; | private String dataNum2; | ||||
| /** 统计数量3 */ | /** 统计数量3 */ | ||||
| /** 首页下 已调查总数*/ | |||||
| private String dataNum3; | private String dataNum3; | ||||
| /** 统计数量4 */ | /** 统计数量4 */ | ||||
| /** 首页下 地块总面积*/ | |||||
| private String dataNum4; | private String dataNum4; | ||||
| /** 统计数量5 */ | /** 统计数量5 */ | ||||
| /** 首页下 机动地总面积*/ | |||||
| private String dataNum5; | private String dataNum5; | ||||
| /** 统计数量6 */ | /** 统计数量6 */ | ||||
| /** 首页下 承包总金额*/ | |||||
| private String dataNum6; | private String dataNum6; | ||||
| /** 统计数量7 */ | /** 统计数量7 */ | ||||
| /** 首页下 兑现总金额*/ | |||||
| private String dataNum7; | private String dataNum7; | ||||
| /** 统计数量8 */ | /** 统计数量8 */ | ||||
| /** 首页下 尚欠总金额*/ | |||||
| private String dataNum8; | private String dataNum8; | ||||
| /** 统计数量9 */ | /** 统计数量9 */ | ||||
| /** 首页下 经营总面积*/ | |||||
| private String dataNum9; | private String dataNum9; | ||||
| /** 统计数量10 */ | /** 统计数量10 */ | ||||
| /** 首页下 年总收益*/ | |||||
| private String dataNum10; | private String dataNum10; | ||||
| } | } | ||||
| @@ -94,5 +94,6 @@ public interface TResourceLandMapper | |||||
| */ | */ | ||||
| public TBigDataScreen homepageDownStatistics(Long deptId); | public TBigDataScreen homepageDownStatistics(Long deptId); | ||||
| public int deleteByCode(String importCode); | |||||
| } | } | ||||
| @@ -77,4 +77,6 @@ public interface TResourceOperationMapper | |||||
| * @return 结果 | * @return 结果 | ||||
| */ | */ | ||||
| public int deleteTResourceOperationByIds(Long[] ids); | public int deleteTResourceOperationByIds(Long[] ids); | ||||
| public int deleteByCode(String importCode); | |||||
| } | } | ||||
| @@ -15,7 +15,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| </resultMap> | </resultMap> | ||||
| <sql id="selectTGisCjqyVo"> | <sql id="selectTGisCjqyVo"> | ||||
| select cjqydm, cjqymc, bsm, ysdm, the_geom, import_code, fid from t_gis_cjqy | |||||
| select cjqydm, cjqymc, bsm, ysdm, ST_AsText(the_geom) as the_geom, import_code, fid from t_gis_cjqy | |||||
| </sql> | </sql> | ||||
| <select id="selectTGisCjqyList" parameterType="TGisCjqy" resultMap="TGisCjqyResult"> | <select id="selectTGisCjqyList" parameterType="TGisCjqy" resultMap="TGisCjqyResult"> | ||||
| @@ -47,7 +47,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| <if test="cjqymc != null and cjqymc != ''">#{cjqymc},</if> | <if test="cjqymc != null and cjqymc != ''">#{cjqymc},</if> | ||||
| <if test="bsm != null">#{bsm},</if> | <if test="bsm != null">#{bsm},</if> | ||||
| <if test="ysdm != null">#{ysdm},</if> | <if test="ysdm != null">#{ysdm},</if> | ||||
| <if test="theGeom != null">#{theGeom},</if> | |||||
| <if test="theGeom != null">ST_GEOMFROMTEXT(#{theGeom}),</if> | |||||
| <if test="importCode != null and importCode != ''">#{importCode},</if> | <if test="importCode != null and importCode != ''">#{importCode},</if> | ||||
| </trim> | </trim> | ||||
| </insert> | </insert> | ||||
| @@ -69,7 +69,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| #{item.cjqymc}, | #{item.cjqymc}, | ||||
| #{item.bsm}, | #{item.bsm}, | ||||
| #{item.ysdm}, | #{item.ysdm}, | ||||
| #{item.theGeom}, | |||||
| ST_GEOMFROMTEXT(#{item.theGeom}), | |||||
| #{item.importCode}, | #{item.importCode}, | ||||
| </trim> | </trim> | ||||
| </foreach> | </foreach> | ||||
| @@ -82,7 +82,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| <if test="cjqymc != null and cjqymc != ''">cjqymc = #{cjqymc},</if> | <if test="cjqymc != null and cjqymc != ''">cjqymc = #{cjqymc},</if> | ||||
| <if test="bsm != null">bsm = #{bsm},</if> | <if test="bsm != null">bsm = #{bsm},</if> | ||||
| <if test="ysdm != null">ysdm = #{ysdm},</if> | <if test="ysdm != null">ysdm = #{ysdm},</if> | ||||
| <if test="theGeom != null">the_geom = #{theGeom},</if> | |||||
| <if test="theGeom != null">the_geom = ST_GEOMFROMTEXT(#{theGeom}),</if> | |||||
| <if test="importCode != null and importCode != ''">import_code = #{importCode},</if> | <if test="importCode != null and importCode != ''">import_code = #{importCode},</if> | ||||
| </trim> | </trim> | ||||
| where fid = #{fid} | where fid = #{fid} | ||||
| @@ -97,7 +97,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| <if test="item.cjqymc != null and item.cjqymc != ''">cjqymc = #{item.cjqymc},</if> | <if test="item.cjqymc != null and item.cjqymc != ''">cjqymc = #{item.cjqymc},</if> | ||||
| <if test="item.bsm != null">bsm = #{item.bsm},</if> | <if test="item.bsm != null">bsm = #{item.bsm},</if> | ||||
| <if test="item.ysdm != null">ysdm = #{item.ysdm},</if> | <if test="item.ysdm != null">ysdm = #{item.ysdm},</if> | ||||
| <if test="item.theGeom != null">the_geom = #{item.theGeom},</if> | |||||
| <if test="item.theGeom != null">the_geom = ST_GEOMFROMTEXT(#{item.theGeom}),</if> | |||||
| <if test="item.importCode != null and item.importCode != ''">import_code = #{item.importCode},</if> | <if test="item.importCode != null and item.importCode != ''">import_code = #{item.importCode},</if> | ||||
| </set> | </set> | ||||
| where fid = #{item.fid} | where fid = #{item.fid} | ||||
| @@ -114,4 +114,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| #{fid} | #{fid} | ||||
| </foreach> | </foreach> | ||||
| </delete> | </delete> | ||||
| <delete id="deleteByCode" parameterType="String"> | |||||
| delete from t_gis_cjqy where import_code = #{importCode} | |||||
| </delete> | |||||
| </mapper> | </mapper> | ||||
| @@ -161,4 +161,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| #{id} | #{id} | ||||
| </foreach> | </foreach> | ||||
| </delete> | </delete> | ||||
| <update id="terminateRunningTask"> | |||||
| update t_task_import | |||||
| set task_status = '5' | |||||
| where task_status = '2' | |||||
| </update> | |||||
| <select id="getForUpdate" parameterType="Long" resultMap="TTaskImportResult"> | |||||
| <include refid="selectTTaskImportVo"/> | |||||
| where id = #{id} FOR UPDATE | |||||
| </select> | |||||
| </mapper> | </mapper> | ||||
| @@ -49,7 +49,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| </resultMap> | </resultMap> | ||||
| <sql id="selectTResourceLandVo"> | <sql id="selectTResourceLandVo"> | ||||
| select fid, BSM, YSDM, DKBM, DKMC, SYQXZ, DKLB, TDLYLX, DLDJ, TDYT, SFJBNT, DKDZ, DKXZ, DKNZ, DKBZ, DKBZXX, ZJRXM, TXMJ, SCMJM, QSDWDM, QSDWMC, SFZWD, survey_status, import_code, dept_name, create_by, create_time, update_by, update_time from t_resource_land | |||||
| select fid, BSM, YSDM, DKBM, DKMC, SYQXZ, DKLB, TDLYLX, DLDJ, TDYT, SFJBNT, DKDZ, DKXZ, DKNZ, DKBZ, DKBZXX, ZJRXM, TXMJ, SCMJM, QSDWDM, QSDWMC, SFZWD, survey_status, import_code, dept_name, ST_AsText(the_geom) as the_geom, create_by, create_time, update_by, update_time from t_resource_land | |||||
| </sql> | </sql> | ||||
| <sql id="selectTResourceLandMap"> | <sql id="selectTResourceLandMap"> | ||||
| @@ -156,7 +156,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| <if test="zjrxm != null">#{zjrxm},</if> | <if test="zjrxm != null">#{zjrxm},</if> | ||||
| <if test="txmj != null">#{txmj},</if> | <if test="txmj != null">#{txmj},</if> | ||||
| <if test="scmjm != null">#{scmjm},</if> | <if test="scmjm != null">#{scmjm},</if> | ||||
| <if test="theGeom != null">#{theGeom},</if> | |||||
| <if test="theGeom != null">ST_GEOMFROMTEXT(#{theGeom}),</if> | |||||
| <if test="qsdwdm != null">#{qsdwdm},</if> | <if test="qsdwdm != null">#{qsdwdm},</if> | ||||
| <if test="qsdwmc != null">#{qsdwmc},</if> | <if test="qsdwmc != null">#{qsdwmc},</if> | ||||
| <if test="sfzwd != null">#{sfzwd},</if> | <if test="sfzwd != null">#{sfzwd},</if> | ||||
| @@ -224,7 +224,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| #{item.zjrxm}, | #{item.zjrxm}, | ||||
| #{item.txmj}, | #{item.txmj}, | ||||
| #{item.scmjm}, | #{item.scmjm}, | ||||
| #{item.theGeom}, | |||||
| ST_GEOMFROMTEXT(#{item.theGeom}), | |||||
| #{item.qsdwdm}, | #{item.qsdwdm}, | ||||
| #{item.qsdwmc}, | #{item.qsdwmc}, | ||||
| #{item.sfzwd}, | #{item.sfzwd}, | ||||
| @@ -260,7 +260,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| <if test="zjrxm != null">ZJRXM = #{zjrxm},</if> | <if test="zjrxm != null">ZJRXM = #{zjrxm},</if> | ||||
| <if test="txmj != null">TXMJ = #{txmj},</if> | <if test="txmj != null">TXMJ = #{txmj},</if> | ||||
| <if test="scmjm != null">SCMJM = #{scmjm},</if> | <if test="scmjm != null">SCMJM = #{scmjm},</if> | ||||
| <if test="theGeom != null">the_geom = #{theGeom},</if> | |||||
| <if test="theGeom != null">the_geom = ST_GEOMFROMTEXT(#{theGeom}),</if> | |||||
| <if test="qsdwdm != null">QSDWDM = #{qsdwdm},</if> | <if test="qsdwdm != null">QSDWDM = #{qsdwdm},</if> | ||||
| <if test="qsdwmc != null">QSDWMC = #{qsdwmc},</if> | <if test="qsdwmc != null">QSDWMC = #{qsdwmc},</if> | ||||
| <if test="sfzwd != null">SFZWD = #{sfzwd},</if> | <if test="sfzwd != null">SFZWD = #{sfzwd},</if> | ||||
| @@ -298,7 +298,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| <if test="item.zjrxm != null">ZJRXM = #{item.zjrxm},</if> | <if test="item.zjrxm != null">ZJRXM = #{item.zjrxm},</if> | ||||
| <if test="item.txmj != null">TXMJ = #{item.txmj},</if> | <if test="item.txmj != null">TXMJ = #{item.txmj},</if> | ||||
| <if test="item.scmjm != null">SCMJM = #{item.scmjm},</if> | <if test="item.scmjm != null">SCMJM = #{item.scmjm},</if> | ||||
| <if test="item.theGeom != null">the_geom = #{item.theGeom},</if> | |||||
| <if test="item.theGeom != null">the_geom = ST_GEOMFROMTEXT(#{item.theGeom}),</if> | |||||
| <if test="item.qsdwdm != null">QSDWDM = #{item.qsdwdm},</if> | <if test="item.qsdwdm != null">QSDWDM = #{item.qsdwdm},</if> | ||||
| <if test="item.qsdwmc != null">QSDWMC = #{item.qsdwmc},</if> | <if test="item.qsdwmc != null">QSDWMC = #{item.qsdwmc},</if> | ||||
| <if test="item.sfzwd != null">SFZWD = #{item.sfzwd},</if> | <if test="item.sfzwd != null">SFZWD = #{item.sfzwd},</if> | ||||
| @@ -345,7 +345,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| SUM(CASE WHEN l.survey_status = '1' THEN 1 ELSE 0 END) AS data_num1, | SUM(CASE WHEN l.survey_status = '1' THEN 1 ELSE 0 END) AS data_num1, | ||||
| SUM(CASE WHEN l.survey_status = '2' THEN 1 ELSE 0 END) AS data_num2 | SUM(CASE WHEN l.survey_status = '2' THEN 1 ELSE 0 END) AS data_num2 | ||||
| FROM sys_dept d | FROM sys_dept d | ||||
| LEFT JOIN t_resource_land l ON l.import_code LIKE concat(d.import_code, '%') WHERE d.parent_id = #{deptId} | |||||
| LEFT JOIN t_resource_land l ON l.import_code LIKE CONCAT(d.import_code, '%') WHERE d.parent_id = #{deptId} | |||||
| GROUP BY d.dept_id, d.dept_name ORDER BY d.dept_id | GROUP BY d.dept_id, d.dept_name ORDER BY d.dept_id | ||||
| </select> | </select> | ||||
| @@ -364,7 +364,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| SUM( o.JYMJ ) AS data_num9,#经营总面积 | SUM( o.JYMJ ) AS data_num9,#经营总面积 | ||||
| SUM( o.NSY ) AS data_num10#年总收益 | SUM( o.NSY ) AS data_num10#年总收益 | ||||
| FROM sys_dept d | FROM sys_dept d | ||||
| LEFT JOIN t_resource_land l ON l.import_code LIKE concat( d.import_code, '%' ) | |||||
| LEFT JOIN t_resource_land l ON l.import_code LIKE CONCAT( d.import_code, '%' ) | |||||
| LEFT JOIN t_resource_operation o ON l.DKBM = o.DKBM WHERE d.dept_id = #{deptId} | LEFT JOIN t_resource_operation o ON l.DKBM = o.DKBM WHERE d.dept_id = #{deptId} | ||||
| </select> | </select> | ||||
| <delete id="deleteByCode" parameterType="String"> | |||||
| delete from t_resource_land where import_code = #{importCode} | |||||
| </delete> | |||||
| </mapper> | </mapper> | ||||
| @@ -281,4 +281,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||
| #{id} | #{id} | ||||
| </foreach> | </foreach> | ||||
| </delete> | </delete> | ||||
| <delete id="deleteByCode" parameterType="String"> | |||||
| delete from t_resource_operation where import_code = #{importCode} | |||||
| </delete> | |||||
| </mapper> | </mapper> | ||||
| @@ -155,6 +155,23 @@ | |||||
| <artifactId>hutool-all</artifactId> | <artifactId>hutool-all</artifactId> | ||||
| </dependency> | </dependency> | ||||
| <!-- 添加GeoTools依赖 --> | |||||
| <dependency> | |||||
| <groupId>org.geotools</groupId> | |||||
| <artifactId>gt-shapefile</artifactId> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>org.geotools</groupId> | |||||
| <artifactId>gt-swing</artifactId> | |||||
| </dependency> | |||||
| <!-- wkt转geojson --> | |||||
| <dependency> | |||||
| <groupId>org.geotools</groupId> | |||||
| <artifactId>gt-geojson</artifactId> | |||||
| </dependency> | |||||
| </dependencies> | </dependencies> | ||||
| @@ -0,0 +1,178 @@ | |||||
| package com.ruoyi.common.geo; | |||||
| import cn.hutool.core.bean.BeanUtil; | |||||
| import cn.hutool.core.bean.copier.CopyOptions; | |||||
| import cn.hutool.core.lang.Assert; | |||||
| import org.geotools.data.shapefile.ShapefileDataStore; | |||||
| import org.geotools.data.simple.SimpleFeatureIterator; | |||||
| import org.geotools.data.simple.SimpleFeatureSource; | |||||
| import org.locationtech.jts.geom.Geometry; | |||||
| 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.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.stream.Collectors; | |||||
| public final class GeoParser implements Closeable | |||||
| { | |||||
| private ShapefileDataStore dataStore; | |||||
| private SimpleFeatureSource source; | |||||
| private Map<Integer, String> columnMap; | |||||
| public GeoParser() | |||||
| { | |||||
| } | |||||
| 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 { | |||||
| dataStore = new ShapefileDataStore(file.toURL()); | |||||
| 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 CheckSource() | |||||
| { | |||||
| Assert.notNull(source, "请先设置数据源"); | |||||
| } | |||||
| public List<String> GetTypeNames() | |||||
| { | |||||
| CheckDataStore(); | |||||
| try { | |||||
| return Arrays.stream(dataStore.getTypeNames()).collect(Collectors.toList()); | |||||
| } catch (Exception e) { | |||||
| e.printStackTrace(); | |||||
| return null; | |||||
| } | |||||
| } | |||||
| public boolean SetSource(String typeName) | |||||
| { | |||||
| CloseSource(); | |||||
| if(null == typeName) | |||||
| return true; | |||||
| CheckDataStore(); | |||||
| try { | |||||
| source = dataStore.getFeatureSource(typeName); | |||||
| return InitSource(); | |||||
| } catch (Exception e) { | |||||
| e.printStackTrace(); | |||||
| return false; | |||||
| } | |||||
| } | |||||
| public boolean SetSource(int index) | |||||
| { | |||||
| CloseSource(); | |||||
| if(index < 0) | |||||
| return true; | |||||
| CheckDataStore(); | |||||
| return SetSource(GetTypeNames().get(index)); | |||||
| } | |||||
| private void CloseSource() | |||||
| { | |||||
| columnMap = null; | |||||
| source = null; | |||||
| } | |||||
| private boolean InitSource() | |||||
| { | |||||
| if(null == source) | |||||
| 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(i, descriptor.getLocalName()); | |||||
| } | |||||
| return true; | |||||
| } catch (Exception e) { | |||||
| e.printStackTrace(); | |||||
| return false; | |||||
| } | |||||
| } | |||||
| public List<Map<String, Object>> GetMapList() | |||||
| { | |||||
| CheckSource(); | |||||
| try { | |||||
| List<Map<String, Object>> ret = new ArrayList<>(); | |||||
| try(SimpleFeatureIterator features = source.getFeatures().features()) { | |||||
| while(features.hasNext()) | |||||
| { | |||||
| SimpleFeature feature = features.next(); | |||||
| Map<String, Object> map = new HashMap<>(); | |||||
| for (int i = 0; i < feature.getAttributeCount(); i++) { | |||||
| Object attribute = feature.getAttribute(i); | |||||
| if(attribute instanceof Geometry) | |||||
| attribute = ((Geometry) attribute).toText(); | |||||
| map.put(columnMap.get(i), attribute); | |||||
| } | |||||
| ret.add(map); | |||||
| } | |||||
| } | |||||
| return ret; | |||||
| } catch (Exception e) { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| public <T> List<T> GetList(Class<T> clazz) | |||||
| { | |||||
| List<Map<String, Object>> maps = GetMapList(); | |||||
| return maps.stream().map((x) -> BeanUtil.mapToBean(x, clazz, false, CopyOptions.create())).collect(Collectors.toList()); | |||||
| } | |||||
| } | |||||
| @@ -487,4 +487,9 @@ public class DecimalUtils { | |||||
| return number.toString(); | return number.toString(); | ||||
| } | } | ||||
| } | } | ||||
| public static BigDecimal nullToZero(BigDecimal o) | |||||
| { | |||||
| return null == o ? BigDecimal.ZERO : o; | |||||
| } | |||||
| } | } | ||||
| @@ -0,0 +1,108 @@ | |||||
| package com.ruoyi.common.utils.sql; | |||||
| import com.ruoyi.common.utils.spring.SpringUtils; | |||||
| import org.springframework.transaction.PlatformTransactionManager; | |||||
| import org.springframework.transaction.TransactionDefinition; | |||||
| import org.springframework.transaction.TransactionStatus; | |||||
| import java.util.function.Supplier; | |||||
| public final class DB | |||||
| { | |||||
| private static class TransactionHandle | |||||
| { | |||||
| private final PlatformTransactionManager manager; | |||||
| private final TransactionStatus transactionStatus; | |||||
| private TransactionHandle(PlatformTransactionManager manager, TransactionStatus transactionStatus) | |||||
| { | |||||
| this.manager = manager; | |||||
| this.transactionStatus = transactionStatus; | |||||
| } | |||||
| private static TransactionHandle Cast(Object handle) | |||||
| { | |||||
| return (TransactionHandle) handle; | |||||
| } | |||||
| } | |||||
| public static Object BeginTransaction() | |||||
| { | |||||
| PlatformTransactionManager manager = SpringUtils.getBean(PlatformTransactionManager.class); | |||||
| TransactionDefinition definition = SpringUtils.getBean(TransactionDefinition.class); | |||||
| TransactionStatus transaction = manager.getTransaction(definition); | |||||
| return new TransactionHandle(manager, transaction); | |||||
| } | |||||
| public static void CommitTransaction(Object handle) | |||||
| { | |||||
| TransactionHandle transaction = (TransactionHandle) handle; | |||||
| transaction.manager.commit(transaction.transactionStatus); | |||||
| } | |||||
| public static void RollbackTransaction(Object handle) | |||||
| { | |||||
| TransactionHandle transaction = TransactionHandle.Cast(handle); | |||||
| transaction.manager.rollback(transaction.transactionStatus); | |||||
| } | |||||
| public static void EndTransaction(Object handle) | |||||
| { | |||||
| if(null == handle) | |||||
| return; | |||||
| TransactionHandle transaction = TransactionHandle.Cast(handle); | |||||
| try | |||||
| { | |||||
| transaction.manager.commit(transaction.transactionStatus); | |||||
| } | |||||
| catch(Exception e) | |||||
| { | |||||
| e.printStackTrace(); | |||||
| transaction.manager.rollback(transaction.transactionStatus); | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| public static void Transaction(Runnable runnable) | |||||
| { | |||||
| PlatformTransactionManager manager = SpringUtils.getBean(PlatformTransactionManager.class); | |||||
| TransactionDefinition definition = SpringUtils.getBean(TransactionDefinition.class); | |||||
| TransactionStatus transaction = manager.getTransaction(definition); | |||||
| try | |||||
| { | |||||
| runnable.run(); | |||||
| manager.commit(transaction); | |||||
| } | |||||
| catch(Exception e) | |||||
| { | |||||
| e.printStackTrace(); | |||||
| manager.rollback(transaction); | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| public static <T> T Transaction(Supplier<T> runnable, T...ifExceptRet) | |||||
| { | |||||
| PlatformTransactionManager manager = SpringUtils.getBean(PlatformTransactionManager.class); | |||||
| TransactionDefinition definition = SpringUtils.getBean(TransactionDefinition.class); | |||||
| TransactionStatus transaction = manager.getTransaction(definition); | |||||
| try | |||||
| { | |||||
| T res = runnable.get(); | |||||
| manager.commit(transaction); | |||||
| return res; | |||||
| } | |||||
| catch(Exception e) | |||||
| { | |||||
| e.printStackTrace(); | |||||
| manager.rollback(transaction); | |||||
| if(null != ifExceptRet && ifExceptRet.length > 0) | |||||
| return ifExceptRet[0]; | |||||
| else | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| private DB() {} | |||||
| } | |||||