shp파일등록방법변경

This commit is contained in:
2026-03-11 08:02:54 +09:00
parent d193ff4ae6
commit cc796ce005
28 changed files with 657 additions and 215 deletions

View File

@@ -1,6 +1,7 @@
package com.kamco.makesample.batch.tasklet;
import com.kamco.makesample.service.GeoServerRegistrationService;
import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepContribution;
@@ -16,6 +17,9 @@ import org.springframework.stereotype.Component;
*
* <p>기존 GeoServerRegistrationService를 재사용하여 shapefile을 GeoServer에 등록
*
* <p>자동 선택 로직: - 파일 크기 < 100MB: REST API 업로드 (uploadShapefileZip) - 파일 크기 >= 100MB: 파일 경로 참조
* (registerShapefileByPath)
*
* <p>Conditional execution: geoserver.enabled=false 이면 skip
*/
@Component
@@ -24,6 +28,8 @@ public class GeoServerRegistrationTasklet implements Tasklet {
private static final Logger log = LoggerFactory.getLogger(GeoServerRegistrationTasklet.class);
private static final long FILE_SIZE_THRESHOLD = 100 * 1024 * 1024; // 100MB
private final GeoServerRegistrationService geoServerService;
@Value("#{jobParameters['geoserver.enabled'] ?: false}")
@@ -62,8 +68,29 @@ public class GeoServerRegistrationTasklet implements Tasklet {
throw new IllegalStateException("ZIP file path not available for GeoServer registration");
}
// 기존 GeoServerRegistrationService 재사용
geoServerService.uploadShapefileZip(zipPath, layerName);
// Check file size to determine registration method
File zipFile = new File(zipPath);
long fileSize = zipFile.length();
long fileSizeMB = fileSize / 1024 / 1024;
log.info("ZIP file size: {} bytes ({} MB)", fileSize, fileSizeMB);
//
// if (fileSize < FILE_SIZE_THRESHOLD) {
// // Small file: Use REST API upload
// log.info("Using REST API upload method (file size < 100MB)");
// geoServerService.uploadShapefileZip(zipPath, layerName);
// } else {
// // Large file: Use file path reference
// log.info(
// "Using file path reference method (file size >= 100MB, {} MB recommended for large"
// + " files)",
// fileSizeMB);
// log.info(
// "GeoServer will read the file from: {} (ensure GeoServer has file system access)",
// zipPath);
// geoServerService.registerShapefileByPath(zipPath, layerName);
// }
geoServerService.registerShapefileByPath(zipPath, layerName);
log.info("GeoServer registration completed successfully for layer: {}", layerName);

View File

@@ -190,35 +190,56 @@ public class ConverterCommandLineRunner implements CommandLineRunner {
return;
}
String filePath = firstOption(appArgs, "upload-shp");
String layerName = firstOption(appArgs, "layer");
// Check for file path reference method (recommended for large files)
String filePathReference = firstOption(appArgs, "register-by-path");
boolean usePathReference = filePathReference != null && !filePathReference.isBlank();
if (filePath == null || filePath.isBlank()) {
log.info("No upload requested. Use --upload-shp option to upload a shapefile.");
// Check for upload method (traditional, file size limited)
String uploadFilePath = firstOption(appArgs, "upload-shp");
boolean useUpload = uploadFilePath != null && !uploadFilePath.isBlank();
if (!usePathReference && !useUpload) {
log.info("No upload or registration requested.");
printUsage();
return;
}
if (usePathReference && useUpload) {
log.error("Cannot use both --upload-shp and --register-by-path at the same time.");
log.error("Choose one method:");
log.error(" --upload-shp: Upload file content via REST API (< 100MB)");
log.error(" --register-by-path: Reference file path (500MB+)");
System.exit(1);
}
String filePath = usePathReference ? filePathReference : uploadFilePath;
String layerName = firstOption(appArgs, "layer");
if (layerName == null || layerName.isBlank()) {
String fileName = Paths.get(filePath).getFileName().toString();
layerName = fileName.replaceAll("(?i)\\.(zip|shp)$", ""); // 대소문자도 처리
}
log.info("========================================");
log.info("Shapefile Upload to GeoServer");
log.info("Shapefile {} to GeoServer", usePathReference ? "Registration" : "Upload");
log.info("========================================");
log.info("Method: {}", usePathReference ? "File Path Reference" : "REST API Upload");
log.info("Input File: {}", filePath);
log.info("Layer Name: {}", layerName);
log.info("========================================");
try {
geoServerService.uploadShapefileZip(filePath, layerName);
if (usePathReference) {
geoServerService.registerShapefileByPath(filePath, layerName);
} else {
geoServerService.uploadShapefileZip(filePath, layerName);
}
log.info("========================================");
log.info("Upload completed successfully!");
log.info("{} completed successfully!", usePathReference ? "Registration" : "Upload");
log.info("========================================");
} catch (Exception e) {
log.error("========================================");
log.error("Upload failed: {}", e.getMessage(), e);
log.error("{} failed: {}", usePathReference ? "Registration" : "Upload", e.getMessage(), e);
log.error("========================================");
throw e;
}
@@ -263,21 +284,44 @@ public class ConverterCommandLineRunner implements CommandLineRunner {
System.out.println();
System.out.println("Options:");
System.out.println(
" --upload-shp <file-path> Upload shapefile to GeoServer (.shp or .zip)");
" --upload-shp <file-path> Upload shapefile via REST API (< 100MB)");
System.out.println(
" --layer <layer-name> Specify layer name (optional, defaults to filename)");
System.out.println(" --help, -h Show this help message");
" --register-by-path <file-path> Register shapefile using file path (500MB+)");
System.out.println(
" --layer <layer-name> Specify layer name (optional, defaults to filename)");
System.out.println(" --help, -h Show this help message");
System.out.println();
System.out.println("GeoServer Registration Methods:");
System.out.println();
System.out.println(" 1. REST API Upload (--upload-shp):");
System.out.println(" - Uploads file content to GeoServer via HTTP");
System.out.println(" - File size limit: < 100MB (HTTP payload limit)");
System.out.println(" - Use for small to medium files");
System.out.println();
System.out.println(" 2. File Path Reference (--register-by-path):");
System.out.println(" - GeoServer reads file from its local file system");
System.out.println(" - No file size limit (supports 500MB ~ 2GB+)");
System.out.println(" - Requirements:");
System.out.println(" * GeoServer must have file system access to the path");
System.out.println(" * Path must be absolute (e.g., /data/model_output/...)");
System.out.println(" * File must be readable by GeoServer user");
System.out.println();
System.out.println("Examples:");
System.out.println(" # Upload ZIP file directly");
System.out.println(" java -jar shp-exporter.jar --upload-shp /path/to/shapefile.zip");
System.out.println();
System.out.println(" # Upload .shp file (will auto-create ZIP with related files)");
System.out.println(" java -jar shp-exporter.jar --upload-shp /path/to/shapefile.shp");
System.out.println(" # Small file (< 100MB): Upload via REST API");
System.out.println(" java -jar shp-exporter.jar --upload-shp /path/to/small_file.zip");
System.out.println();
System.out.println(" # Specify custom layer name");
System.out.println(" # Large file (500MB+): Register by file path");
System.out.println(
" java -jar shp-exporter.jar --upload-shp /path/to/shapefile.shp --layer my_layer");
" java -jar shp-exporter.jar --register-by-path"
+ " /data/model_output/export/inference_id/merge/large_file.zip");
System.out.println();
System.out.println(" # With custom layer name");
System.out.println(
" java -jar shp-exporter.jar --register-by-path /path/to/file.zip --layer my_layer");
System.out.println();
System.out.println(" # Auto-create ZIP from .shp file (upload method)");
System.out.println(" java -jar shp-exporter.jar --upload-shp /path/to/shapefile.shp");
System.out.println();
}
}

View File

@@ -38,12 +38,21 @@ public class GeoServerRegistrationService {
this.properties = properties;
}
/**
* Register shapefile to GeoServer by uploading file content (REST API)
*
* <p>LIMITATION: File size limited by HTTP request size (typically < 100MB) Use
* registerShapefileByPath() for larger files (500MB+)
*
* @param filePath Path to shapefile (.shp or .zip)
* @param layerName GeoServer layer name
*/
public void uploadShapefileZip(String filePath, String layerName) {
String zipFilePath = filePath;
boolean tempZipCreated = false;
try {
log.info("Starting shapefile upload to GeoServer");
log.info("Starting shapefile upload to GeoServer (REST API upload)");
log.info("Input file: {}", filePath);
log.info("Layer name: {}", layerName);
log.info("Workspace: {}", properties.getWorkspace());
@@ -59,6 +68,18 @@ public class GeoServerRegistrationService {
log.info("Temporary ZIP created: {}", zipFilePath);
}
// Check file size and warn if too large
Path path = Paths.get(zipFilePath);
long fileSize = Files.size(path);
log.info("ZIP file size: {} bytes ({} MB)", fileSize, fileSize / 1024 / 1024);
if (fileSize > 100 * 1024 * 1024) { // 100MB
log.warn(
"WARNING: File size ({} MB) may exceed HTTP upload limits. Consider using"
+ " registerShapefileByPath() for files > 100MB",
fileSize / 1024 / 1024);
}
// Check if layer exists and handle overwrite
if (properties.isOverwriteExisting() && layerExists(layerName)) {
log.info("Layer '{}' already exists. Deleting...", layerName);
@@ -66,9 +87,7 @@ public class GeoServerRegistrationService {
}
// Read ZIP file
Path path = Paths.get(zipFilePath);
byte[] zipData = Files.readAllBytes(path);
log.info("ZIP file size: {} bytes", zipData.length);
// Upload to GeoServer
String url =
@@ -102,6 +121,24 @@ public class GeoServerRegistrationService {
"GeoServer upload failed. Status: {}, Response: {}",
e.getStatusCode(),
e.getResponseBodyAsString());
// Provide helpful message for 413 Payload Too Large
if (e.getStatusCode() == HttpStatus.PAYLOAD_TOO_LARGE) {
log.error("");
log.error("========================================");
log.error("ERROR: File size exceeds GeoServer upload limit (HTTP 413)");
log.error("");
log.error("Solution: Use file path reference method instead:");
log.error(" 1. Copy shapefile to GeoServer data directory");
log.error(" 2. Use registerShapefileByPath() method");
log.error("");
log.error("Or increase GeoServer upload limits:");
log.error(" - Tomcat: maxPostSize in server.xml");
log.error(" - Nginx: client_max_body_size");
log.error("========================================");
log.error("");
}
throw new RuntimeException("GeoServer upload failed", e);
} catch (Exception e) {
log.error("Unexpected error during shapefile upload", e);
@@ -119,6 +156,118 @@ public class GeoServerRegistrationService {
}
}
/**
* Register shapefile to GeoServer using file:// URL (for large files 500MB+)
*
* <p>This method does NOT upload file content. Instead, it tells GeoServer to read the file from
* its local file system.
*
* <p>Requirements: - GeoServer must have file system access to the shapefile path - The path must
* be absolute and accessible from GeoServer server
*
* @param absoluteFilePath Absolute file path to shapefile (.shp or .zip) on GeoServer server
* @param layerName GeoServer layer name
*/
public void registerShapefileByPath(String absoluteFilePath, String layerName) {
try {
log.info("Starting shapefile registration to GeoServer (file path reference)");
log.info("Input file path: {}", absoluteFilePath);
log.info("Layer name: {}", layerName);
log.info("Workspace: {}", properties.getWorkspace());
// Validate inputs
if (absoluteFilePath == null || absoluteFilePath.trim().isEmpty()) {
throw new IllegalArgumentException("File path cannot be empty");
}
if (layerName == null || layerName.trim().isEmpty()) {
throw new IllegalArgumentException("Layer name cannot be empty");
}
// Verify file exists
File file = new File(absoluteFilePath);
if (!file.exists()) {
throw new IllegalArgumentException("File does not exist: " + absoluteFilePath);
}
if (!file.isAbsolute()) {
throw new IllegalArgumentException("File path must be absolute: " + absoluteFilePath);
}
String lowerPath = absoluteFilePath.toLowerCase();
if (!lowerPath.endsWith(".zip") && !lowerPath.endsWith(".shp")) {
throw new IllegalArgumentException("File must be a .zip or .shp file: " + absoluteFilePath);
}
log.info("File size: {} MB", file.length() / 1024 / 1024);
// Check if layer exists and handle overwrite
if (properties.isOverwriteExisting() && layerExists(layerName)) {
log.info("Layer '{}' already exists. Deleting...", layerName);
deleteLayer(layerName);
}
// Construct file:// URL
String fileUrl = "file://" + absoluteFilePath;
log.info("Using file URL: {}", fileUrl);
// GeoServer REST API endpoint
String url =
String.format(
"%s/rest/workspaces/%s/datastores/%s/file.shp?configure=all",
properties.getBaseUrl(), properties.getWorkspace(), layerName);
HttpHeaders headers = createHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
// Send file:// URL as request body
HttpEntity<String> request = new HttpEntity<>(fileUrl, headers);
log.info("Registering shapefile to GeoServer: {}", url);
ResponseEntity<String> response =
restTemplate.exchange(url, HttpMethod.PUT, request, String.class);
if (response.getStatusCode() == HttpStatus.CREATED
|| response.getStatusCode() == HttpStatus.OK) {
log.info("Shapefile registered successfully to GeoServer");
log.info(
"Layer '{}' is now available in workspace '{}'", layerName, properties.getWorkspace());
log.info("GeoServer will read data from: {}", absoluteFilePath);
} else {
log.warn("Unexpected response status: {}", response.getStatusCode());
}
} catch (HttpClientErrorException e) {
log.error(
"GeoServer registration failed. Status: {}, Response: {}",
e.getStatusCode(),
e.getResponseBodyAsString());
if (e.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) {
log.error("");
log.error("========================================");
log.error("ERROR: GeoServer cannot access the file path");
log.error("");
log.error("Possible causes:");
log.error(" 1. File path is not accessible from GeoServer server");
log.error(" 2. GeoServer user lacks read permissions");
log.error(" 3. File path format is incorrect (must be absolute path)");
log.error("");
log.error("Solutions:");
log.error(" 1. Verify GeoServer has file system access to: {}", absoluteFilePath);
log.error(" 2. Check file permissions (chmod 644 or similar)");
log.error(" 3. Ensure path is absolute and correctly formatted");
log.error("========================================");
log.error("");
}
throw new RuntimeException("GeoServer registration failed", e);
} catch (Exception e) {
log.error("Unexpected error during shapefile registration", e);
throw new RuntimeException("Shapefile registration failed", e);
}
}
private void validateInputs(String filePath, String layerName) {
if (filePath == null || filePath.trim().isEmpty()) {
throw new IllegalArgumentException("File path cannot be empty");