赞
踩
工作空间可以看作是包含数据的容器
存储仓库是数据的具体存放地
图层名是发布服务的名称
1.压缩包:一个包含.shp,.shx和.dbf的zip压缩包(必要参数)
2.发布图层名(可选参数)
1.压缩包需要里面不包含文件夹(即解压一级目录直接是.shp等文件)
2.压缩包和里面的内部文件如.shp,.shx,.dbf等文件需要名称一致!
3.java发布图层服务的时候,尽量不要用中文名,因为发布的图层会拼接一个http的url,因为编码报错。我们项目的思路是将服务名为时间戳(确保了唯一),将中文名和服务名字时间戳变成一条记录,插入到mysql
package com.ruoyi.gis.controller; import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.gis.common.Result; import com.ruoyi.gis.dto.GeoServerDTO; import com.ruoyi.gis.model.Demo; import com.ruoyi.gis.model.YzghyMajorProjectGisfile; import com.ruoyi.gis.service.YzghyMajorProjectGisfileService; import com.ruoyi.gis.utlis.GeoserverUtils; import com.ruoyi.gis.utlis.ShpToGeoJsonConverter; import com.ruoyi.gis.utlis.ZipExtractor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; /** * @BelongsProject: geoserver-manager * @BelongsPackage: com.mr.xi.enums * @Author: cuiYong * @CreateTime: 2024-03-20 17:12 * @Description: TODO * @Version: 1.0 */ @RestController @RequestMapping("/geoserver") public class GeoServerController { // private static final String GEOSERVER_DATA_DIR = "http://20.14.52.236/geoserverdata/E:\\geoserverdata\\data"; private static final String GEOSERVER_DATA_DIR = "E:\\geoserverdata\\data"; // private static final String GEOSERVER_DATA_DIR = "E:\\geoserverdata\\data"; @Autowired private YzghyMajorProjectGisfileService yzghyMajorProjectGisfileService; @Anonymous @PostMapping("/publishLayerService") public Result publishLayerService(@RequestParam("layerName") String layerName, @RequestParam("zipFile") MultipartFile zipFile, @RequestParam("author") String author) throws IOException { String mysqlLayerName =layerName; layerName = GeoserverUtils.getCurrentTimeStamp(); if (zipFile.isEmpty()) { throw new IllegalArgumentException("zip文件未上传"); } String originalFileName = zipFile.getOriginalFilename(); if (originalFileName != null && !originalFileName.isEmpty()) { String fileSuffix = originalFileName.substring(originalFileName.lastIndexOf(".") + 1).toLowerCase(); if (!fileSuffix.equals("zip")) { return Result.fail(400, "您上传的是" + fileSuffix + "文件,请上传压缩包zip文件"); } } else { return Result.fail(400, "无法获取上传文件的名称"); } String zipFileName = zipFile.getOriginalFilename(); if (zipFileName == null) { return Result.fail(400, "zip文件名获取失败"); } // 查询zip是否已经转为geojson或者是否已经发布过了 if (zipFile.getSize() < 5 * 1024 * 1024) { Integer result = yzghyMajorProjectGisfileService.checkNameExistence(mysqlLayerName, "geojson"); System.out.println("result===>"+result); if (result != null && result > 0) { return Result.fail(601, "该相同名称的文件已存在,请重新起一个新的文件名称"); } } else { Integer result = yzghyMajorProjectGisfileService.checkNameExistence(mysqlLayerName, "geoserver"); if (result != null && result > 0) { return Result.fail(601, "该相同名称的GeoServer服务已存在,请重新起一个新的文件名称"); } } String directoryPath = GEOSERVER_DATA_DIR + "\\" + layerName; String temporary = directoryPath + File.separator + GeoserverUtils.getCurrentTimeStamp(); File directoryTime = new File(temporary); if (!directoryTime.exists() && !directoryTime.mkdirs()) { return Result.fail(500, "无法创建目录: " + temporary); } File shpTempFile = new File(temporary, layerName + ".zip"); zipFile.transferTo(shpTempFile); // temporary 临时文件夹路径,shpTempFile 是 ZIP 文件 File outputFolder = new File(temporary); // 如果temporary是临时路径,在那一层解压 try { ZipExtractor.unzipShpFile(shpTempFile, outputFolder, layerName); ZipExtractor.rezipShapeFiles(outputFolder, shpTempFile, layerName); } catch (IllegalArgumentException e) { // 这里捕获了具体的 IllegalArgumentException 异常,并提供了一个明确的错误消息 System.out.println(e.getMessage()); return Result.fail(500, "解压ZIP文件失败:文件可能损坏或格式不正确。"); } catch (IOException e) { // 其他 I/O 异常的错误处理 e.printStackTrace(); return Result.fail(500, "处理ZIP文件时出现I/O异常:" + e.getMessage()); } YzghyMajorProjectGisfile yzghyMajorProjectGisfile = new YzghyMajorProjectGisfile(); yzghyMajorProjectGisfile.setName(mysqlLayerName); yzghyMajorProjectGisfile.setOwner(author); yzghyMajorProjectGisfile.setCoordinate("4326"); yzghyMajorProjectGisfile.setCreateTime(LocalDateTime.now()); yzghyMajorProjectGisfile.setDescription(""); if (zipFile.getSize() < 5 * 1024 * 1024) { // 小于5MB System.out.println("temporary + File.separator + layerName + "+temporary + File.separator + layerName + ".shp"); System.out.println(GEOSERVER_DATA_DIR + File.separator + "geojson" + File.separator + mysqlLayerName + ".geojson"); ShpToGeoJsonConverter.transformShpToGeoJson(temporary + File.separator + layerName + ".shp", "F:\\fileServer\\geojson\\" + mysqlLayerName + ".geojson"); GeoserverUtils.deleteDirectoryWithContents(directoryTime); yzghyMajorProjectGisfile.setType("geojson"); yzghyMajorProjectGisfile.setUrl("geojson" + "/" + mysqlLayerName + ".geojson"); Integer result = yzghyMajorProjectGisfileService.insertGeoServerInfo(yzghyMajorProjectGisfile); if (result == 0) { return Result.fail(500, "插入数据库失败"); } yzghyMajorProjectGisfile.setId(yzghyMajorProjectGisfile.getId()); return Result.success(yzghyMajorProjectGisfile); } else { publishToGeoserver(temporary, layerName); yzghyMajorProjectGisfile.setType("geoserver"); yzghyMajorProjectGisfile.setUrl("ghy:"+layerName); Integer result = yzghyMajorProjectGisfileService.insertGeoServerInfo(yzghyMajorProjectGisfile); if (result == 0) { return Result.fail(500, "插入数据库失败"); } yzghyMajorProjectGisfile.setId(yzghyMajorProjectGisfile.getId()); return Result.success(yzghyMajorProjectGisfile); } } private void publishToGeoserver(String directoryPath, String layerName) throws IOException { String geoserverUrl = "http://localhost:8888/geoserver"; String workspace = "ghy"; String storeName = "yzghy"; String srs = "EPSG:4326"; File zipShpFile = new File(directoryPath, layerName + ".zip"); GeoserverUtils.GeoserverPublishShapefileData(geoserverUrl, "admin", "geoserver", workspace, storeName, srs, zipShpFile, layerName, "file:data/" + layerName + "/" + layerName + ".shp"); } }
大致逻辑为:大于5mb的文件发布GeoServer服务,小于5mb的文件转为geojson保存到指定目录
细分逻辑:
1.先判断上传的zip格式是否合法,如:是否为zip文件\是否为空等
2.不过zip里面是否包含文件夹,或压缩包内的.shp,.shx,.dbf与zip不同名(我这里的发布服务的名字按照时间戳来 确保唯一)都给他转为当前时间戳
3.发布服务或转geojson文件,事先在mysql数据库查明,是否已经发布过了,逻辑很简单,举个例子:那前端传过来的layerName去数据库查询这个名字在不在就行,这里的代码就不贴了
4.判断zip是否大于5mb,小于则转为geojson保存到指定目录,大于则发布geoserver服务(其中不管是转geojson还是发布geoserver服务 我都会忘数据库插入命令记录,sql语句是insert into ghy_major_project_gisfile values('${name}','${owner}','${url}','${description}','${coordinate}','${createTime}','${type}')
)
package com.ruoyi.gis.utlis; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import org.geotools.data.*; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.geojson.feature.FeatureJSON; import org.opengis.feature.simple.SimpleFeatureType; public class ShpToGeoJsonConverter { public static boolean transformShpToGeoJson(String shpPath, String geojsonPath) { FileDataStore myData = null; try { File file = new File(shpPath); myData = FileDataStoreFinder.getDataStore(file); // 设置解码方式 ((ShapefileDataStore) myData).setCharset(StandardCharsets.UTF_8); SimpleFeatureSource source = myData.getFeatureSource(); SimpleFeatureType schema = source.getSchema(); Query query = new Query(schema.getTypeName()); SimpleFeatureCollection collection = source.getFeatures(query); FeatureJSON fjson = new FeatureJSON(); try (StringWriter writer = new StringWriter()) { writer.write("{\"type\":\"FeatureCollection\",\"crs\":"); fjson.writeCRS(schema.getCoordinateReferenceSystem(), writer); writer.write(",\"features\":"); fjson.writeFeatureCollection(collection, writer); writer.write("}"); try (BufferedWriter buffer = Files.newBufferedWriter(new File(geojsonPath).toPath(), StandardCharsets.UTF_8)) { buffer.write(writer.toString()); } return true; } } catch (IOException e) { return false; } finally { if (myData != null) { // 关闭FileDataStore释放资源 myData.dispose(); } } } }
去除zip中的文件夹,只保留文件/并且将压缩包内的文件夹去除后,文件名字与zip统一后保留压缩包
package com.ruoyi.gis.utlis; import java.io.*; import java.nio.charset.Charset; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.zip.ZipOutputStream; public class ZipExtractor { private static final Set<String> ALLOWED_FILE_EXTENSIONS = new HashSet<>(Arrays.asList("shp", "shx", "dbf")); private static String getFileExtension(String fileName) { int lastIndex = fileName.lastIndexOf('.'); if (lastIndex > -1) { return fileName.substring(lastIndex + 1).toLowerCase(); } return ""; } private static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException { File destinationFile = new File(destinationDir, zipEntry.getName()); String destDirPath = destinationDir.getCanonicalPath(); String destFilePath = destinationFile.getCanonicalPath(); if (!destFilePath.startsWith(destDirPath + File.separator)) { throw new IOException("Entry is outside of the target dir: " + zipEntry.getName()); } return destinationFile; } private static void moveValidFilesAndCleanup(File directory, File outputFolder, String layerName) throws IOException { File[] files = directory.listFiles(); if (files != null) { for (File file : files) { if (file.isDirectory()) { // 递归调用,处理子目录 moveValidFilesAndCleanup(file, outputFolder, layerName); } else { String fileExtension = getFileExtension(file.getName()); if (ALLOWED_FILE_EXTENSIONS.contains(fileExtension)) { // 根据layerName重命名文件。例如: "my_layer.shp" File renamedFile = new File(outputFolder, layerName + "." + fileExtension); if (!file.renameTo(renamedFile)) { throw new IOException("Failed to move and rename file: " + file.getName()); } } } } } // 删除临时目录/文件夹 deleteDirectory(directory); } // 递归删除目录 private static void deleteDirectory(File directory) throws IOException { File[] files = directory.listFiles(); if (files != null) { // 删除目录中的所有文件和子目录 for (File file : files) { if (file.isDirectory()) { deleteDirectory(file); } else { if (!file.delete()) { throw new IOException("Failed to delete file: " + file.getName()); } } } } // 删除当前目录 if (!directory.delete()) { throw new IOException("Failed to delete directory: " + directory.getName()); } } public static void unzipShpFile(File zipFile, File outputFolder, String layerName) throws IOException { // 解压缩到临时目录,防止覆盖其他文件 File tempDirectory = new File(outputFolder, "temp_unzip"); tempDirectory.mkdirs(); // 确保临时目录存在 byte[] buffer = new byte[1024]; // 使用指定字符集创建ZipInputStream ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile), Charset.forName("GBK")); ZipEntry zipEntry = zis.getNextEntry(); while (zipEntry != null) { File newFile = newFile(tempDirectory, zipEntry); if (!zipEntry.isDirectory() && ALLOWED_FILE_EXTENSIONS.contains(getFileExtension(newFile.getName()))) { File parent = newFile.getParentFile(); if (!parent.isDirectory() && !parent.mkdirs()) { throw new IOException("Failed to create directory " + parent); } try (FileOutputStream fos = new FileOutputStream(newFile)) { int len; while ((len = zis.read(buffer)) > 0) { fos.write(buffer, 0, len); } } } zipEntry = zis.getNextEntry(); } zis.closeEntry(); zis.close(); // 移动有效文件到输出目录,并重命名,然后删除临时目录 moveValidFilesAndCleanup(tempDirectory, outputFolder, layerName); } public static void rezipShapeFiles(File inputFolder, File originalZipFile, String layerName) throws IOException { File[] shapeFiles = inputFolder.listFiles((dir, name) -> ALLOWED_FILE_EXTENSIONS.contains(getFileExtension(name))); if (shapeFiles == null || shapeFiles.length == 0) { throw new IOException("No valid shape files found to zip in directory: " + inputFolder.getPath()); } // 删除原始的zip文件 if (originalZipFile.exists() && !originalZipFile.delete()) { throw new IOException("Failed to delete original zip file: " + originalZipFile.getName()); } // 创建新的Zip文件 File zipOutputFile = new File(inputFolder, layerName + ".zip"); try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipOutputFile))) { byte[] buffer = new byte[1024]; for (File shapeFile : shapeFiles) { try (FileInputStream fis = new FileInputStream(shapeFile)) { // 创建一个新的ZipEntry,不要包含任何父路径 ZipEntry zipEntry = new ZipEntry(shapeFile.getName()); zos.putNextEntry(zipEntry); int length; while ((length = fis.read(buffer)) > 0) { zos.write(buffer, 0, length); } } zos.closeEntry(); } } } }
上效果图:
zip工具类已经将这个zip格式规范化,只要他zip有这三个文件,我通通都给他规范化,保你发布服务成功!(保留了shp等文件)
代码非常细致,考虑了很多隐藏错误,都解决了!!!
发布GeoServer服务的核心工具:记住几个传的参数就行了很简单,这里我简单说一下这几个参数(String url, String username,String passwd, String ws,String storeName, String srs, File zipFile, String layerName, String urlDatastore):
1 url:geoserver的服务地址和端口
2.username:geoserver的登录用户名
3.passwd:geoserver的登录密码
4.ws:工作区名称
5.storeName:存储仓库名称
6.srs:标记坐标(这个坐标是不具备转坐标的功能,只能说是标记一下文件的坐标,需要自己手动写死)
7.zipFile:包含.shp,.shx,.dbf等shapefile的必要文件的zip(我前面zip工具类已经将这个zip格式规范化,只要他zip有这三个文件,我通通都给他规范化,保你发布服务成功!)
8.layerName:发布图层名称(再说一句,发布图层名和zip和shp的名称都需统一,我用的是当前时间戳作为名称统一的)
9.urlDatastore:shp的地址(我当时也在纳闷,都有包含shp的zip了为什么还需要指定shp的地址/不过我的zip都给他规范好了)
package com.ruoyi.gis.utlis; import it.geosolutions.geoserver.rest.GeoServerRESTManager; import it.geosolutions.geoserver.rest.GeoServerRESTPublisher; import it.geosolutions.geoserver.rest.decoder.RESTDataStore; import it.geosolutions.geoserver.rest.decoder.RESTLayer; import it.geosolutions.geoserver.rest.encoder.datastore.GSShapefileDatastoreEncoder; import lombok.extern.slf4j.Slf4j; import java.io.File; import java.io.IOException; import java.net.URL; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; @Slf4j public class GeoserverUtils { public static void main(String[] args) throws IOException { //GeoServer的连接配置 String url = "http://localhost:8888/geoserver"; String username = "admin"; String passwd = "geoserver"; String ws = "testshape"; //待创建和发布图层的工作区名称workspace String storeName = "testShapeStore1"; //待创建和发布图层的数据存储名称store String srs = "EPSG:4528"; //压缩文件的完整路径 File zipFile = new File("E:/geoserverdata/data/shapefile/cs.zip"); String layerName = "cs";//图层名称 //shp文件所在的位置 String urlDatastore = "file:data/shapefile/c123s.shp"; GeoserverPublishShapefileData(url, username, passwd, ws, storeName, srs, zipFile, layerName, urlDatastore); } //发布shapefile数据 public static void GeoserverPublishShapefileData(String url, String username, String passwd, String ws, String storeName, String srs, File zipFile, String layerName, String urlDatastore) throws IOException { URL u = new URL(url); //获取管理对象 GeoServerRESTManager manager = new GeoServerRESTManager(u, username, passwd); //获取发布对象 GeoServerRESTPublisher publisher = manager.getPublisher(); //获取所有的工作空间名称 List<String> workspaces = manager.getReader().getWorkspaceNames(); //判断工作空间是否存在 if (!workspaces.contains(ws)) { //创建一个新的存储空间 boolean createws = publisher.createWorkspace(ws); System.out.println("create ws : " + createws); } else { System.out.println("workspace已经存在了,ws :" + ws); } //判断数据存储(datastore)是否已经存在,不存在则创建 URL urlShapefile = new URL(urlDatastore); RESTDataStore restStore = manager.getReader().getDatastore(ws, storeName); if (restStore == null) { //创建shape文件存储 GSShapefileDatastoreEncoder store = new GSShapefileDatastoreEncoder(storeName, urlShapefile); boolean createStore = manager.getStoreManager().create(ws, store); System.out.println("create store : " + createStore); } else { System.out.println("数据存储已经存在了,store:" + storeName); } //判断图层是否已经存在,不存在则创建并发布 RESTLayer layer = manager.getReader().getLayer(ws, layerName); if (layer == null) { //发布图层 boolean publish = manager.getPublisher().publishShp(ws, storeName, layerName, zipFile, srs); System.out.println("publish : " + publish); } else { System.out.println("图层已经存在了" + layerName); } } public static String getCurrentTimeStamp() { LocalDateTime now = LocalDateTime.now(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); return now.format(formatter); } // 添加一个用于递归删除文件夹及其所有内容的辅助方法 public static void deleteDirectoryWithContents(File directory) { File[] allContents = directory.listFiles(); if (allContents != null) { for (File file : allContents) { deleteDirectoryWithContents(file); } } if (!directory.delete()) { System.out.println("警告:无法删除临时文件夹 " + directory.getAbsolutePath()); } } }
最后只有俩sql方法没贴了:
一个sql是查询数据库有没有用这个layerName发布的服务或geojson
一个是插入发布记录
都是很简单的SQL
下面是我给的一些建议,大家在借鉴我的代码时可以一个方法一个方法测试,如果有不懂的可以私信我,也可以在评论区留意,我会回复滴。祝大家工作顺利!!谢谢
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。