diff --git a/gradle/mac/pack_offline_bundle_airgap_macos.sh b/gradle/mac/pack_offline_bundle_airgap_macos.sh new file mode 100755 index 00000000..1a34086b --- /dev/null +++ b/gradle/mac/pack_offline_bundle_airgap_macos.sh @@ -0,0 +1,571 @@ +#!/bin/bash +# pack_offline_bundle_airgap_macos.sh +# ============================================================================ +# Gradle Offline Bundle Packer (macOS) +# ============================================================================ +# Version: 4.0 +# +# WORKFLOW: +# 1. [ONLINE] Build project (./gradlew bootJar) - downloads all deps +# 2. [ONLINE] Test run (./gradlew bootRun) - verify app works +# 3. [OFFLINE TEST] Verify offline build works +# 4. Create bundle with all cached dependencies +# +# REQUIREMENTS: +# - Internet connection (for initial build) +# - Project with gradlew +# - macOS 10.13+ (High Sierra or later) +# ============================================================================ + +set -e + +# ============================================================================ +# Configuration +# ============================================================================ +WRAPPER_SEED_PATH="wrapper_jar_seed" +OFFLINE_HOME_NAME="_offline_gradle_home" +BOOTRUN_TIMEOUT_SECONDS=60 + +# Color codes +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +GRAY='\033[0;90m' +WHITE='\033[1;37m' +NC='\033[0m' # No Color + +echo "" +echo -e "${CYAN}============================================================${NC}" +echo -e "${CYAN} Gradle Offline Bundle Packer v4.0 (macOS)${NC}" +echo -e "${CYAN}============================================================${NC}" +echo "" +echo -e "${WHITE} This script will:${NC}" +echo -e "${GRAY} 1. Build project with internet (download dependencies)${NC}" +echo -e "${GRAY} 2. Test run application (verify it works)${NC}" +echo -e "${GRAY} 3. Test offline build (verify cache is complete)${NC}" +echo -e "${GRAY} 4. Create offline bundle for air-gapped environment${NC}" +echo "" +echo -e "${CYAN}============================================================${NC}" +echo "" + +# ============================================================================ +# [1/20] Check Current Directory +# ============================================================================ +echo -e "${YELLOW}==[1/20] Check Current Directory ==${NC}" +ROOT="$(pwd)" +echo "ROOT_DIR: $ROOT" +echo "" + +# ============================================================================ +# [2/20] Check Required Files +# ============================================================================ +echo -e "${YELLOW}==[2/20] Check Required Files ==${NC}" + +if [ ! -f "./gradlew" ]; then + echo -e "${RED}ERROR: gradlew not found. Run from project root.${NC}" + exit 1 +fi +chmod +x ./gradlew +echo -e "${GREEN}[OK] gradlew${NC}" + +BUILD_FILE="" +if [ -f "./build.gradle" ]; then + BUILD_FILE="build.gradle" +elif [ -f "./build.gradle.kts" ]; then + BUILD_FILE="build.gradle.kts" +else + echo -e "${RED}ERROR: build.gradle(.kts) not found.${NC}" + exit 1 +fi +echo -e "${GREEN}[OK] $BUILD_FILE${NC}" + +SETTINGS_FILE="" +if [ -f "./settings.gradle" ]; then + SETTINGS_FILE="settings.gradle" + echo -e "${GREEN}[OK] $SETTINGS_FILE${NC}" +elif [ -f "./settings.gradle.kts" ]; then + SETTINGS_FILE="settings.gradle.kts" + echo -e "${GREEN}[OK] $SETTINGS_FILE${NC}" +fi +echo "" + +# ============================================================================ +# [3/20] Check Gradle Wrapper +# ============================================================================ +echo -e "${YELLOW}==[3/20] Check Gradle Wrapper ==${NC}" + +WRAPPER_DIR="$ROOT/gradle/wrapper" +WRAPPER_JAR="$WRAPPER_DIR/gradle-wrapper.jar" +WRAPPER_PROP="$WRAPPER_DIR/gradle-wrapper.properties" + +mkdir -p "$WRAPPER_DIR" + +if [ ! -f "$WRAPPER_PROP" ]; then + echo -e "${RED}ERROR: gradle-wrapper.properties not found.${NC}" + exit 1 +fi + +if [ ! -f "$WRAPPER_JAR" ]; then + SEED_JAR="$ROOT/$WRAPPER_SEED_PATH/gradle-wrapper.jar" + if [ -f "$SEED_JAR" ]; then + cp "$SEED_JAR" "$WRAPPER_JAR" + echo -e "${GREEN}[OK] Wrapper jar injected from seed${NC}" + else + echo -e "${RED}ERROR: gradle-wrapper.jar missing${NC}" + exit 1 + fi +else + echo -e "${GREEN}[OK] gradle-wrapper.jar exists${NC}" +fi + +# Create seed backup +SEED_DIR="$ROOT/$WRAPPER_SEED_PATH" +if [ ! -d "$SEED_DIR" ]; then + mkdir -p "$SEED_DIR" + cp "$WRAPPER_JAR" "$SEED_DIR/gradle-wrapper.jar" +fi +echo "" + +# ============================================================================ +# [4/20] Set GRADLE_USER_HOME (Project Local) +# ============================================================================ +echo -e "${YELLOW}==[4/20] Set GRADLE_USER_HOME ==${NC}" + +OFFLINE_HOME="$ROOT/$OFFLINE_HOME_NAME" +mkdir -p "$OFFLINE_HOME" +export GRADLE_USER_HOME="$OFFLINE_HOME" + +echo -e "${CYAN}GRADLE_USER_HOME = $GRADLE_USER_HOME${NC}" +echo -e "${GRAY}[INFO] All dependencies will be cached in project folder${NC}" +echo "" + +# ============================================================================ +# [5/20] Check Internet Connection +# ============================================================================ +echo -e "${YELLOW}==[5/20] Check Internet Connection ==${NC}" + +HAS_INTERNET=false +TEST_HOSTS=("plugins.gradle.org" "repo.maven.apache.org" "repo1.maven.org") + +for TEST_HOST in "${TEST_HOSTS[@]}"; do + # macOS ping doesn't have -W, use -t instead + if ping -c 1 -t 3 "$TEST_HOST" &>/dev/null; then + HAS_INTERNET=true + echo -e "${GREEN}[OK] Connected to $TEST_HOST${NC}" + break + fi +done + +if [ "$HAS_INTERNET" = false ]; then + # Try DNS resolution as fallback + if nslookup google.com &>/dev/null || host google.com &>/dev/null; then + HAS_INTERNET=true + echo -e "${GREEN}[OK] Internet available (DNS)${NC}" + fi +fi + +if [ "$HAS_INTERNET" = false ]; then + echo "" + echo -e "${RED}============================================================${NC}" + echo -e "${RED} ERROR: No Internet Connection!${NC}" + echo -e "${RED}============================================================${NC}" + echo "" + echo -e "${YELLOW}This script requires internet for initial build.${NC}" + echo -e "${YELLOW}Please connect to internet and run again.${NC}" + echo "" + exit 1 +fi +echo "" + +# ============================================================================ +# [6/20] Initial Gradle Setup +# ============================================================================ +echo -e "${YELLOW}==[6/20] Initial Gradle Setup ==${NC}" +echo -e "${GRAY}[INFO] Downloading Gradle distribution...${NC}" + +if ./gradlew --version &>/dev/null; then + GRADLE_VERSION=$(./gradlew --version 2>&1 | grep "^Gradle" | awk '{print $2}') + echo -e "${GREEN}[OK] Gradle $GRADLE_VERSION${NC}" +else + echo -e "${RED}[ERROR] Gradle setup failed${NC}" + exit 1 +fi +echo "" + +# ============================================================================ +# [7/20] ONLINE BUILD - bootJar (Download All Dependencies) +# ============================================================================ +echo -e "${YELLOW}==[7/20] ONLINE BUILD - bootJar ==${NC}" +echo "" +echo -e "${CYAN}============================================================${NC}" +echo -e "${CYAN} ONLINE BUILD (with Internet)${NC}" +echo -e "${CYAN} Downloading all dependencies to local cache${NC}" +echo -e "${CYAN}============================================================${NC}" +echo "" + +BUILD_SUCCESS=false + +./gradlew clean bootJar --no-daemon +if [ $? -eq 0 ]; then + BUILD_SUCCESS=true + echo "" + echo -e "${GREEN}============================================================${NC}" + echo -e "${GREEN} ONLINE BUILD SUCCESS!${NC}" + echo -e "${GREEN}============================================================${NC}" + echo "" + + if [ -d "./build/libs" ]; then + echo -e "${CYAN}JAR files:${NC}" + ls -lh ./build/libs/*.jar 2>/dev/null | awk '{print " " $9 " (" $5 ")"}' + fi +else + echo "" + echo -e "${RED}============================================================${NC}" + echo -e "${RED} BUILD FAILED!${NC}" + echo -e "${RED}============================================================${NC}" + echo "" + echo -e "${YELLOW}Build failed. Cannot continue.${NC}" + exit 1 +fi +echo "" + +# ============================================================================ +# [8/20] Stop Daemons +# ============================================================================ +echo -e "${YELLOW}==[8/20] Stop Daemons ==${NC}" + +./gradlew --stop &>/dev/null || true +sleep 2 +echo -e "${GREEN}[OK] Daemons stopped${NC}" +echo "" + +# ============================================================================ +# [9/20] ONLINE TEST - bootRun (Verify Application Works) +# ============================================================================ +echo -e "${YELLOW}==[9/20] ONLINE TEST - bootRun ==${NC}" +echo "" +echo -e "${CYAN}============================================================${NC}" +echo -e "${CYAN} Testing application startup (timeout: ${BOOTRUN_TIMEOUT_SECONDS}s)${NC}" +echo -e "${CYAN} Will automatically stop after successful startup${NC}" +echo -e "${CYAN}============================================================${NC}" +echo "" + +BOOTRUN_SUCCESS=false + +# macOS uses gtimeout if available, otherwise perl-based timeout +if command -v gtimeout &>/dev/null; then + gtimeout ${BOOTRUN_TIMEOUT_SECONDS}s ./gradlew bootRun --no-daemon & +else + # Fallback: start in background and kill after timeout + ./gradlew bootRun --no-daemon & +fi +BOOTRUN_PID=$! + +sleep 10 + +if ps -p $BOOTRUN_PID &>/dev/null; then + BOOTRUN_SUCCESS=true + echo "" + echo -e "${GREEN}[OK] Application started successfully${NC}" + kill $BOOTRUN_PID &>/dev/null || true + sleep 2 +else + echo "" + echo -e "${YELLOW}[WARN] Application may not have started properly${NC}" +fi + +# Cleanup - macOS process cleanup +pkill -f "gradle.*bootRun" &>/dev/null || true +sleep 2 +echo "" + +# ============================================================================ +# [10/20] Stop Daemons Again +# ============================================================================ +echo -e "${YELLOW}==[10/20] Stop Daemons Again ==${NC}" + +./gradlew --stop &>/dev/null || true +sleep 2 +echo -e "${GREEN}[OK] Daemons stopped${NC}" +echo "" + +# ============================================================================ +# [11/20] OFFLINE BUILD TEST (Verify Cache Completeness) +# ============================================================================ +echo -e "${YELLOW}==[11/20] OFFLINE BUILD TEST ==${NC}" +echo "" +echo -e "${CYAN}============================================================${NC}" +echo -e "${CYAN} OFFLINE BUILD TEST (--offline flag)${NC}" +echo -e "${CYAN} Verifying all dependencies are cached${NC}" +echo -e "${CYAN}============================================================${NC}" +echo "" + +OFFLINE_SUCCESS=false + +./gradlew clean bootJar --offline --no-daemon +if [ $? -eq 0 ]; then + OFFLINE_SUCCESS=true + echo "" + echo -e "${GREEN}============================================================${NC}" + echo -e "${GREEN} OFFLINE BUILD TEST PASSED!${NC}" + echo -e "${GREEN}============================================================${NC}" + echo "" + echo -e "${GREEN}[OK] All dependencies are cached${NC}" +else + echo "" + echo -e "${RED}============================================================${NC}" + echo -e "${RED} OFFLINE BUILD TEST FAILED!${NC}" + echo -e "${RED}============================================================${NC}" + echo "" + echo -e "${YELLOW}Some dependencies may be missing from cache.${NC}" + echo -e "${YELLOW}The bundle may not work in air-gapped environment.${NC}" + echo "" + + read -p "Continue anyway? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + exit 1 + fi +fi +echo "" + +# ============================================================================ +# [12/20] Stop Daemons Before Archive +# ============================================================================ +echo -e "${YELLOW}==[12/20] Stop Daemons Before Archive ==${NC}" + +./gradlew --stop &>/dev/null || true +sleep 2 +echo -e "${GREEN}[OK] Daemons stopped${NC}" +echo "" + +# ============================================================================ +# [13/20] Verify settings.gradle for Offline +# ============================================================================ +echo -e "${YELLOW}==[13/20] Verify settings.gradle ==${NC}" + +if [ -n "$SETTINGS_FILE" ]; then + if grep -q "mavenLocal()" "$SETTINGS_FILE" && grep -q "pluginManagement" "$SETTINGS_FILE"; then + echo -e "${GREEN}[OK] settings.gradle configured for offline${NC}" + else + echo -e "${YELLOW}[WARN] settings.gradle may need offline configuration${NC}" + echo -e "${GRAY}[INFO] Consider adding mavenLocal() to pluginManagement and repositories${NC}" + fi +else + echo -e "${GRAY}[INFO] No settings.gradle found${NC}" +fi +echo "" + +# ============================================================================ +# [14/20] Create Helper Scripts +# ============================================================================ +echo -e "${YELLOW}==[14/20] Create Helper Scripts ==${NC}" + +# run_offline_build.sh +cat > "$ROOT/run_offline_build.sh" << 'EOF' +#!/bin/bash +# run_offline_build.sh - Build JAR offline +export GRADLE_USER_HOME="$(pwd)/_offline_gradle_home" +echo "GRADLE_USER_HOME = $GRADLE_USER_HOME" +echo "" +./gradlew --offline bootJar --no-daemon +if [ $? -eq 0 ]; then + echo "" + echo "BUILD SUCCESS!" + echo "" + echo "JAR files:" + ls -lh ./build/libs/*.jar 2>/dev/null | awk '{print " " $9}' +else + echo "BUILD FAILED" +fi +EOF +chmod +x "$ROOT/run_offline_build.sh" +echo -e "${GREEN}[OK] run_offline_build.sh${NC}" + +# run_offline_bootrun.sh +cat > "$ROOT/run_offline_bootrun.sh" << 'EOF' +#!/bin/bash +# run_offline_bootrun.sh - Run application offline +export GRADLE_USER_HOME="$(pwd)/_offline_gradle_home" +echo "GRADLE_USER_HOME = $GRADLE_USER_HOME" +echo "" +echo "Starting application (Ctrl+C to stop)..." +echo "" +./gradlew --offline bootRun --no-daemon +EOF +chmod +x "$ROOT/run_offline_bootrun.sh" +echo -e "${GREEN}[OK] run_offline_bootrun.sh${NC}" +echo "" + +# ============================================================================ +# [15/20] Final Daemon Cleanup +# ============================================================================ +echo -e "${YELLOW}==[15/20] Final Daemon Cleanup ==${NC}" + +./gradlew --stop &>/dev/null || true +sleep 2 +echo -e "${GREEN}[OK] Daemons stopped${NC}" +echo "" + +# ============================================================================ +# [16/20] Clean Lock Files +# ============================================================================ +echo -e "${YELLOW}==[16/20] Clean Lock Files ==${NC}" + +DAEMON_DIR="$OFFLINE_HOME/daemon" +if [ -d "$DAEMON_DIR" ]; then + rm -rf "$DAEMON_DIR" 2>/dev/null || true +fi + +find "$OFFLINE_HOME" -type f \( -name "*.lock" -o -name "*.log" -o -name "*.tmp" \) -delete 2>/dev/null || true + +echo -e "${GREEN}[OK] Lock files cleaned${NC}" +echo "" + +# ============================================================================ +# [17/20] Calculate Cache Size +# ============================================================================ +echo -e "${YELLOW}==[17/20] Cache Summary ==${NC}" + +CACHES_DIR="$OFFLINE_HOME/caches" +WRAPPER_DISTS="$OFFLINE_HOME/wrapper/dists" + +TOTAL_SIZE=0 + +if [ -d "$CACHES_DIR" ]; then + # macOS uses different options for du + if du -k "$CACHES_DIR" &>/dev/null; then + SIZE=$(du -sk "$CACHES_DIR" 2>/dev/null | cut -f1) + SIZE=$((SIZE * 1024)) # Convert to bytes + else + SIZE=0 + fi + TOTAL_SIZE=$((TOTAL_SIZE + SIZE)) + SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $SIZE / 1048576}") + echo -e "${CYAN}[INFO] Dependencies: ${SIZE_MB} MB${NC}" +fi + +if [ -d "$WRAPPER_DISTS" ]; then + if du -k "$WRAPPER_DISTS" &>/dev/null; then + SIZE=$(du -sk "$WRAPPER_DISTS" 2>/dev/null | cut -f1) + SIZE=$((SIZE * 1024)) + else + SIZE=0 + fi + TOTAL_SIZE=$((TOTAL_SIZE + SIZE)) + SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $SIZE / 1048576}") + echo -e "${CYAN}[INFO] Gradle dist: ${SIZE_MB} MB${NC}" +fi + +TOTAL_MB=$(awk "BEGIN {printf \"%.2f\", $TOTAL_SIZE / 1048576}") +echo -e "${CYAN}[INFO] Total cache: ${TOTAL_MB} MB${NC}" +echo "" + +# ============================================================================ +# [18/20] Create Archive +# ============================================================================ +echo -e "${YELLOW}==[18/20] Create Archive ==${NC}" + +BASE_NAME=$(basename "$ROOT") +TIMESTAMP=$(date +"%Y%m%d_%H%M%S") +PARENT=$(dirname "$ROOT") +ARCHIVE_PATH="${PARENT}/${BASE_NAME}_offline_bundle_${TIMESTAMP}.tar.gz" + +echo "Archive: $ARCHIVE_PATH" +echo -e "${GRAY}[INFO] Creating archive (this may take several minutes)...${NC}" + +# macOS tar with BSD options +tar -czf "$ARCHIVE_PATH" \ + --exclude=".git" \ + --exclude=".idea" \ + --exclude=".DS_Store" \ + --exclude="*.log" \ + --exclude="*.lock" \ + --exclude="_offline_gradle_home/daemon" \ + --exclude="_offline_gradle_home/native" \ + --exclude="_offline_gradle_home/jdks" \ + --exclude="build" \ + --exclude="out" \ + --exclude=".gradle" \ + -C "$ROOT" . + +if [ $? -ne 0 ]; then + echo -e "${RED}ERROR: tar failed${NC}" + exit 1 +fi + +# macOS stat command +ARCHIVE_SIZE=$(stat -f%z "$ARCHIVE_PATH" 2>/dev/null) +ARCHIVE_SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $ARCHIVE_SIZE / 1048576}") +echo -e "${GREEN}[OK] Archive created: ${ARCHIVE_SIZE_MB} MB${NC}" +echo "" + +# ============================================================================ +# [19/20] Verify Archive +# ============================================================================ +echo -e "${YELLOW}==[19/20] Verify Archive ==${NC}" + +CHECKS=( + "gradle/wrapper/gradle-wrapper.jar" + "gradlew" + "_offline_gradle_home/caches" + "run_offline_build.sh" +) + +for CHECK in "${CHECKS[@]}"; do + if tar -tzf "$ARCHIVE_PATH" | grep -q "$CHECK"; then + echo -e " ${GREEN}[OK] $CHECK${NC}" + else + echo -e " ${YELLOW}[WARN] $CHECK${NC}" + fi +done +echo "" + +# ============================================================================ +# [20/20] Complete +# ============================================================================ +echo -e "${GREEN}============================================================${NC}" +echo -e "${GREEN} BUNDLE CREATION COMPLETE!${NC}" +echo -e "${GREEN}============================================================${NC}" +echo "" +echo -e "${CYAN}Archive: $ARCHIVE_PATH${NC}" +echo -e "${CYAN}Size: ${ARCHIVE_SIZE_MB} MB${NC}" +echo "" + +echo -e "${CYAN}============================================================${NC}" +echo -e "${CYAN} Test Results${NC}" +echo -e "${CYAN}============================================================${NC}" +if [ "$BUILD_SUCCESS" = true ]; then + echo -e " Online build (bootJar): ${GREEN}PASSED${NC}" +else + echo -e " Online build (bootJar): ${RED}FAILED${NC}" +fi +if [ "$BOOTRUN_SUCCESS" = true ]; then + echo -e " Online test (bootRun): ${GREEN}PASSED${NC}" +else + echo -e " Online test (bootRun): ${YELLOW}SKIPPED${NC}" +fi +if [ "$OFFLINE_SUCCESS" = true ]; then + echo -e " Offline build test: ${GREEN}PASSED${NC}" +else + echo -e " Offline build test: ${RED}FAILED${NC}" +fi +echo "" + +echo -e "${YELLOW}============================================================${NC}" +echo -e "${YELLOW} Usage in Air-gapped Environment${NC}" +echo -e "${YELLOW}============================================================${NC}" +echo "" +echo -e "${WHITE}Option 1: Use unpack script${NC}" +echo -e "${GRAY} ./unpack_and_offline_build_airgap.sh${NC}" +echo "" +echo -e "${WHITE}Option 2: Manual extraction${NC}" +echo -e "${GRAY} tar -xzf .tar.gz${NC}" +echo -e "${GRAY} cd ${NC}" +echo -e "${GRAY} ./run_offline_build.sh${NC}" +echo "" +echo -e "${WHITE}Option 3: Direct commands${NC}" +echo -e "${GRAY} export GRADLE_USER_HOME=\"./_offline_gradle_home\"${NC}" +echo -e "${GRAY} ./gradlew --offline bootJar --no-daemon${NC}" +echo "" diff --git a/gradle/mac/unpack_and_offline_build_airgap_macos.sh b/gradle/mac/unpack_and_offline_build_airgap_macos.sh new file mode 100755 index 00000000..4ab128eb --- /dev/null +++ b/gradle/mac/unpack_and_offline_build_airgap_macos.sh @@ -0,0 +1,359 @@ +#!/bin/bash +# unpack_and_offline_build_airgap_macos.sh +# ============================================================================ +# Execution Environment: OFFLINE (Air-gapped, No Internet) +# Purpose: Extract bundle and run offline build +# ============================================================================ +# macOS Bash Script +# Version: 3.1 +# +# IMPORTANT: This script automatically: +# 1. Extracts the archive +# 2. Sets GRADLE_USER_HOME to project local cache +# 3. Configures settings.gradle for offline resolution +# 4. Runs build with --offline flag +# ============================================================================ + +set -e + +# ============================================================================ +# Configuration +# ============================================================================ +WRAPPER_SEED_PATH="wrapper_jar_seed" +OFFLINE_HOME_NAME="_offline_gradle_home" + +# Color codes +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +GRAY='\033[0;90m' +WHITE='\033[1;37m' +NC='\033[0m' # No Color + +echo "" +echo -e "${CYAN}============================================================${NC}" +echo -e "${CYAN} Gradle Offline Build Runner (macOS)${NC}" +echo -e "${CYAN} Environment: AIR-GAPPED (No Internet)${NC}" +echo -e "${CYAN} Mode: Fully Offline (--offline enforced)${NC}" +echo -e "${CYAN}============================================================${NC}" +echo "" + +# ============================================================================ +# [1/16] Check Current Directory +# ============================================================================ +echo -e "${YELLOW}==[1/16] Check Current Directory ==${NC}" +START_DIR="$(pwd)" +echo "PWD: $START_DIR" +echo "" + +# ============================================================================ +# [2/16] Select Archive +# ============================================================================ +echo -e "${YELLOW}==[2/16] Select Archive ==${NC}" + +ARCHIVE="" +if [ $# -ge 1 ]; then + ARCHIVE="$1" +fi + +if [ -z "$ARCHIVE" ]; then + # Auto-detect most recent .tar.gz file (macOS compatible) + ARCHIVE=$(find "$START_DIR" -maxdepth 1 -type f \( -name "*.tar.gz" -o -name "*.tgz" \) -exec stat -f "%m %N" {} \; 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-) + + if [ -z "$ARCHIVE" ]; then + echo -e "${RED}[ERROR] No archive found${NC}" + ls -lh "$START_DIR" + exit 1 + fi + + echo -e "${CYAN}[AUTO] $(basename "$ARCHIVE")${NC}" +else + if [ ! -f "$ARCHIVE" ]; then + ARCHIVE="$START_DIR/$ARCHIVE" + fi + echo -e "${CYAN}[USER] $(basename "$ARCHIVE")${NC}" +fi + +if [ ! -f "$ARCHIVE" ]; then + echo -e "${RED}ERROR: Archive not found: $ARCHIVE${NC}" + exit 1 +fi + +# macOS stat command +ARCHIVE_SIZE=$(stat -f%z "$ARCHIVE" 2>/dev/null) +ARCHIVE_SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $ARCHIVE_SIZE / 1048576}") +echo "Size: ${ARCHIVE_SIZE_MB} MB" +echo "" + +# ============================================================================ +# [3/16] Check tar +# ============================================================================ +echo -e "${YELLOW}==[3/16] Check tar ==${NC}" + +if ! command -v tar &>/dev/null; then + echo -e "${RED}ERROR: tar not found${NC}" + exit 1 +fi +echo -e "${GREEN}[OK] tar found${NC}" +echo "" + +# ============================================================================ +# [4/16] Extract Archive +# ============================================================================ +echo -e "${YELLOW}==[4/16] Extract Archive ==${NC}" +echo -e "${GRAY}[INFO] Extracting...${NC}" + +tar -xzf "$ARCHIVE" -C "$START_DIR" +if [ $? -ne 0 ]; then + echo -e "${RED}ERROR: Extraction failed${NC}" + exit 1 +fi +echo -e "${GREEN}[OK] Extracted${NC}" +echo "" + +# ============================================================================ +# [5/16] Set Permissions +# ============================================================================ +echo -e "${YELLOW}==[5/16] Set Permissions ==${NC}" + +chmod -R u+rw "$START_DIR" 2>/dev/null || true +# Remove extended attributes that macOS may add +xattr -cr "$START_DIR" 2>/dev/null || true +echo -e "${GREEN}[OK] Permissions set${NC}" +echo "" + +# ============================================================================ +# [6/16] Find Project Root +# ============================================================================ +echo -e "${YELLOW}==[6/16] Find Project Root ==${NC}" + +GRADLEW=$(find "$START_DIR" -name "gradlew" -type f 2>/dev/null | sort | head -1) +if [ -z "$GRADLEW" ]; then + echo -e "${RED}ERROR: gradlew not found${NC}" + exit 1 +fi + +PROJECT_DIR=$(dirname "$GRADLEW") +echo -e "${CYAN}Project: $PROJECT_DIR${NC}" +cd "$PROJECT_DIR" +echo "" + +# ============================================================================ +# [7/16] Fix Permissions +# ============================================================================ +echo -e "${YELLOW}==[7/16] Fix Permissions ==${NC}" + +chmod +x ./gradlew +find . -name "*.sh" -type f -exec chmod +x {} \; 2>/dev/null || true +# Remove quarantine attributes that macOS adds to downloaded files +xattr -d com.apple.quarantine ./gradlew 2>/dev/null || true +find . -name "*.jar" -exec xattr -d com.apple.quarantine {} \; 2>/dev/null || true +echo -e "${GREEN}[OK] Permissions fixed${NC}" +echo "" + +# ============================================================================ +# [8/16] Verify Wrapper +# ============================================================================ +echo -e "${YELLOW}==[8/16] Verify Wrapper ==${NC}" + +WRAPPER_DIR="$PROJECT_DIR/gradle/wrapper" +WRAPPER_JAR="$WRAPPER_DIR/gradle-wrapper.jar" +WRAPPER_PROP="$WRAPPER_DIR/gradle-wrapper.properties" + +if [ ! -f "$WRAPPER_PROP" ]; then + echo -e "${RED}ERROR: gradle-wrapper.properties missing${NC}" + exit 1 +fi + +if [ ! -f "$WRAPPER_JAR" ]; then + SEED_JAR="$PROJECT_DIR/$WRAPPER_SEED_PATH/gradle-wrapper.jar" + if [ -f "$SEED_JAR" ]; then + mkdir -p "$WRAPPER_DIR" + cp "$SEED_JAR" "$WRAPPER_JAR" + echo -e "${GREEN}[OK] Injected from seed${NC}" + else + echo -e "${RED}ERROR: wrapper jar missing${NC}" + exit 1 + fi +else + echo -e "${GREEN}[OK] Wrapper verified${NC}" +fi +echo "" + +# ============================================================================ +# [9/16] Set GRADLE_USER_HOME +# ============================================================================ +echo -e "${YELLOW}==[9/16] Set GRADLE_USER_HOME ==${NC}" + +OFFLINE_HOME="$PROJECT_DIR/$OFFLINE_HOME_NAME" +if [ ! -d "$OFFLINE_HOME" ]; then + echo -e "${RED}ERROR: _offline_gradle_home not found in archive${NC}" + exit 1 +fi + +export GRADLE_USER_HOME="$OFFLINE_HOME" +echo -e "${CYAN}GRADLE_USER_HOME = $GRADLE_USER_HOME${NC}" + +# Check cache +CACHES_DIR="$OFFLINE_HOME/caches" +if [ -d "$CACHES_DIR" ]; then + # macOS du command + if du -k "$CACHES_DIR" &>/dev/null; then + CACHE_SIZE=$(du -sk "$CACHES_DIR" 2>/dev/null | cut -f1) + CACHE_SIZE=$((CACHE_SIZE * 1024)) + else + CACHE_SIZE=0 + fi + CACHE_SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $CACHE_SIZE / 1048576}") + echo -e "${CYAN}[INFO] Cache size: ${CACHE_SIZE_MB} MB${NC}" +else + echo -e "${YELLOW}[WARN] No cache folder found${NC}" +fi +echo "" + +# ============================================================================ +# [10/16] Verify settings.gradle +# ============================================================================ +echo -e "${YELLOW}==[10/16] Verify settings.gradle ==${NC}" + +SETTINGS_FILE="" +if [ -f "./settings.gradle" ]; then + SETTINGS_FILE="settings.gradle" +elif [ -f "./settings.gradle.kts" ]; then + SETTINGS_FILE="settings.gradle.kts" +fi + +if [ -n "$SETTINGS_FILE" ]; then + if grep -q "mavenLocal()" "$SETTINGS_FILE" && grep -q "pluginManagement" "$SETTINGS_FILE"; then + echo -e "${GREEN}[OK] settings.gradle configured for offline${NC}" + else + echo -e "${YELLOW}[WARN] settings.gradle may not be configured for offline${NC}" + echo -e "${GRAY}[INFO] Build may fail if plugins not cached${NC}" + fi +fi +echo "" + +# ============================================================================ +# [11/16] Test Gradle +# ============================================================================ +echo -e "${YELLOW}==[11/16] Test Gradle ==${NC}" + +GRADLE_WORKS=false +if ./gradlew --offline --version &>/dev/null; then + GRADLE_WORKS=true + echo -e "${GREEN}[OK] Gradle working in offline mode${NC}" +else + echo -e "${YELLOW}[WARN] Gradle --version failed${NC}" +fi +echo "" + +# ============================================================================ +# [12/16] Stop Daemon +# ============================================================================ +echo -e "${YELLOW}==[12/16] Stop Daemon ==${NC}" + +./gradlew --stop &>/dev/null || true +sleep 2 +echo -e "${GREEN}[OK] Daemon stopped${NC}" +echo "" + +# ============================================================================ +# [13/16] Run Offline Build +# ============================================================================ +echo -e "${YELLOW}==[13/16] Run Offline Build ==${NC}" +echo "" +echo -e "${CYAN}============================================================${NC}" +echo -e "${CYAN} Building with --offline flag${NC}" +echo -e "${CYAN} All dependencies from local cache${NC}" +echo -e "${CYAN}============================================================${NC}" +echo "" + +BUILD_SUCCESS=false +BUILD_TASK="" + +# Try bootJar +echo -e "${GRAY}[TRY] --offline bootJar...${NC}" +if ./gradlew --offline clean bootJar --no-daemon; then + BUILD_SUCCESS=true + BUILD_TASK="bootJar" +fi + +# Try jar +if [ "$BUILD_SUCCESS" = false ]; then + echo -e "${GRAY}[TRY] --offline jar...${NC}" + if ./gradlew --offline clean jar --no-daemon; then + BUILD_SUCCESS=true + BUILD_TASK="jar" + fi +fi + +# Try build +if [ "$BUILD_SUCCESS" = false ]; then + echo -e "${GRAY}[TRY] --offline build...${NC}" + if ./gradlew --offline build --no-daemon; then + BUILD_SUCCESS=true + BUILD_TASK="build" + fi +fi + +echo "" +if [ "$BUILD_SUCCESS" = true ]; then + echo -e "${GREEN}============================================================${NC}" + echo -e "${GREEN} BUILD SUCCESS! (task: $BUILD_TASK)${NC}" + echo -e "${GREEN}============================================================${NC}" +else + echo -e "${RED}============================================================${NC}" + echo -e "${RED} BUILD FAILED!${NC}" + echo -e "${RED}============================================================${NC}" + echo "" + echo -e "${YELLOW}Possible causes:${NC}" + echo -e "${WHITE} - Dependencies not in cache${NC}" + echo -e "${WHITE} - Plugin resolution failed${NC}" + echo -e "${WHITE} - Need complete build in online env first${NC}" + exit 1 +fi +echo "" + +# ============================================================================ +# [14/16] Show Build Output +# ============================================================================ +echo -e "${YELLOW}==[14/16] Build Output ==${NC}" + +LIBS_DIR="$PROJECT_DIR/build/libs" +if [ -d "$LIBS_DIR" ]; then + echo -e "${CYAN}build/libs contents:${NC}" + ls -lh "$LIBS_DIR"/*.jar 2>/dev/null | awk '{printf " %-40s %10s\n", $9, $5}' + + MAIN_JAR=$(find "$LIBS_DIR" -name "*.jar" -type f ! -name "*-plain.jar" ! -name "*-sources.jar" ! -name "*-javadoc.jar" 2>/dev/null | head -1) +else + echo -e "${YELLOW}[WARN] build/libs not found${NC}" +fi +echo "" + +# ============================================================================ +# [15/16] Run Instructions +# ============================================================================ +echo -e "${YELLOW}==[15/16] Run Instructions ==${NC}" +echo "" + +if [ -n "$MAIN_JAR" ]; then + echo -e "${CYAN}To run the application:${NC}" + echo -e "${WHITE} java -jar $(basename "$MAIN_JAR")${NC}" + echo "" +fi + +echo -e "${CYAN}To rebuild:${NC}" +echo -e "${WHITE} export GRADLE_USER_HOME=\"./_offline_gradle_home\"${NC}" +echo -e "${WHITE} ./gradlew --offline bootJar --no-daemon${NC}" +echo "" + +# ============================================================================ +# [16/16] Complete +# ============================================================================ +echo -e "${GREEN}============================================================${NC}" +echo -e "${GREEN} Offline Build Complete!${NC}" +echo -e "${GREEN}============================================================${NC}" +echo "" +echo -e "${CYAN}Project: $PROJECT_DIR${NC}" +echo "" diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/dto/ChngDetectMastDto.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/dto/ChngDetectMastDto.java deleted file mode 100644 index 94ec81c1..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/dto/ChngDetectMastDto.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import java.util.List; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.springframework.web.bind.annotation.RequestParam; - -public class ChngDetectMastDto { - - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class Basic { - - private String chnDtctMstId; // 탐지마스터아이디 - private String cprsYr; // 비교년도 2023 - private String crtrYr; // 기준년도 2024 - private String chnDtctSno; // 차수 (1 | 2 | ...) - private String chnDtctId; // 탐지아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 - private String chnDtctCnt; // 탐지객체개수 - private String pnuMpngCnt; // PNU매핑개수 - private String lrmYmd; // 지적도일자 - private String pathNm; // 탐지결과 절대경로명 /kamco_nas/export/{chnDtctId} - private List excnList; // 등록진행상태히스토리 (최근것부터 DESC) - private String excnStepCd; // 실행단계코드 - private String excnStep; // 실행단계코드에 해당하는 영문명 - private String excnPgrt; // 실행단계진행율 - private String excnBngnDt; // 실행단계시작시간 - private String excnEndDt; // 실행단계종료시간 - private String rmk; // 비고 - private String crtDt; // 생성일시 - private String crtEpno; // 생성사원번호 - private String crtIp; // 생성사원아이피 - private String chgDt; // 변경일시 - private String chgEpno; // 변경사원번호 - private String chgIp; // 변경사원아이피 - private String delYn; // 삭제여부 - // - private String reqEpno; // 요청사원번호 - private String reqIp; // 요청사원어이피 - } - - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class ChnDetectMastExcnStepDto { - - private String srno; // 일련번호 - private String chnDtctMstId; // 탐지마스터아이디 - private String excnStepCd; // 실행단계코드 - private String excnStep; // 실행단계코드에 해당하는 영문명 - private String excnPgrt; // 실행단계진행율 - private String excnEndDt; // 실행단계종료시간 - private String errCd; // 오류코드 - private String errMsg; // 오류메세지 - private String crtDt; // 실행단계시작시간 - } - - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class ChnDetectMastReqDto { - private String cprsYr; // 비교년도 2023 - private String crtrYr; // 기준년도 2024 - private String chnDtctSno; // 차수 (1 | 2 | ...) - private String chnDtctId; // 탐지아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 - private String pathNm; // 탐지결과 절대경로명 /kamco_nas/export/{chnDtctId} - private String reqEpno; // 사원번호 - private String reqIp; // 사원아이피 - } - - - - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class ChnDetectContDto { - - private String chnDtctMstId; // 탐지콘텐츠아이디 - private String chnDtctContId; // 탐지마스타아이디 - private String cprsYr; // 비교년도 2023 - private String crtrYr; // 기준년도 2024 - private String chnDtctSno; // 차수 (1 | 2 | ...) - private String mpqdNo; // 도엽번호 - private String chnDtctId; // 탐지아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 - private String chnDtctObjtId; // 탐지객체아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 - private String chnDtctPolygon; // 탐지객체폴리곤 - private String chnDtctSqms; // 탐지객체면적 - private String chnCd; // 변화코드 - private String chnDtctJson; // 변화탐지JSON - private String chnDtctProb; // 변화탐지정확도 - private String bfClsCd; // 이전부류코드 - private String bfClsProb; // 이전분류정확도 - private String afClsCd; // 이후분류코드 - private String afClsProb; // 이후분류정확도 - private String crtDt; // 생성일시 - private String crtEpno; // 생성사원번호 - private String crtIp; // 생성사원아이피 - private String delYn; // 삭제여부 - // - private String reqEpno; // 요청사원번호 - private String reqIp; // 요청사원아이피 - } - - - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class ChnDetectContReqDto { - - private String cprsYr; // 비교년도 2023 - private String crtrYr; // 기준년도 2024 - private String chnDtctSno; // 차수 (1 | 2 | ...) - private String mpqdNo; // 도엽번호 - private String chnDtctId; // 탐지아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 - private String chnDtctObjtId; // 탐지객체아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 - private String reqEpno; // 사원번호 - private String reqIp; - - } - - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class ChngDetectMastSearchDto { - private String chnDtctId; - private String cprsYr; - private String crtrYr; - private String chnDtctSno; - } - - - @Schema(name = "ResReturn", description = "수행 후 리턴") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class ResReturn { - - private String flag; - private String message; - } - -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/core/DetectMastCoreService.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/core/DetectMastCoreService.java deleted file mode 100644 index 6a77bcee..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/core/DetectMastCoreService.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.postgres.core; - -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.Basic; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastReq; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.FeaturePnuDto; -import com.kamco.cd.kamcoback.Innopam.postgres.entity.DetectMastEntity; -import com.kamco.cd.kamcoback.Innopam.postgres.repository.DetectMastRepository; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class DetectMastCoreService { - - private final DetectMastRepository detectMastRepository; - - public void saveDetectMast(DetectMastReq detectMast) { - DetectMastEntity detectMastEntity = new DetectMastEntity(); - detectMastEntity.setCprsBfYr(detectMast.getCprsBfYr()); - detectMastEntity.setCprsAdYr(detectMast.getCprsAdYr()); - detectMastEntity.setDtctSno(detectMast.getDtctSno()); - detectMastEntity.setPathNm(detectMast.getPathNm()); - detectMastEntity.setCrtEpno(detectMast.getCrtEpno()); - detectMastEntity.setCrtIp(detectMast.getCrtIp()); - detectMastRepository.save(detectMastEntity); - } - - public List selectDetectMast(DetectMastSearch detectMast) { - return detectMastRepository.findDetectMastList(detectMast).stream() - .map( - e -> - new DetectMastDto.Basic( - e.getId(), - e.getCprsBfYr(), - e.getCprsAdYr(), - e.getDtctSno(), - e.getPathNm(), - e.getCrtEpno(), - e.getCrtIp())) - .toList(); - } - - public Basic selectDetectMast(Long id) { - DetectMastEntity e = - detectMastRepository.findById(id).orElseThrow(() -> new RuntimeException("등록 데이터가 없습니다.")); - return new DetectMastDto.Basic( - e.getId(), - e.getCprsBfYr(), - e.getCprsAdYr(), - e.getDtctSno(), - e.getPathNm(), - e.getCrtEpno(), - e.getCrtIp()); - } - - public String findPnuData(DetectMastSearch detectMast) { - DetectMastEntity detectMastEntity = detectMastRepository.findPnuData(detectMast); - return detectMastEntity.getPathNm(); - } - - public Integer updatePnu(List list) { - return detectMastRepository.updateGeomPnu(list); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/entity/DetectMastEntity.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/entity/DetectMastEntity.java deleted file mode 100644 index 5d326b83..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/entity/DetectMastEntity.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.postgres.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.time.ZonedDateTime; -import java.util.UUID; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.ColumnDefault; - -@Getter -@Setter -@Entity -@Table(name = "detect_mast") -public class DetectMastEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "detect_mast_id_gen") - @SequenceGenerator( - name = "detect_mast_id_gen", - sequenceName = "seq_detect_mast_id", - allocationSize = 1) - @Column(name = "dtct_mst_id", nullable = false) - private Long id; - - @NotNull - @ColumnDefault("gen_random_uuid()") - @Column(name = "dtct_mst_uuid", nullable = false) - private UUID dtctMstUuid = UUID.randomUUID(); - - @Size(max = 4) - @NotNull - @Column(name = "cprs_bf_yr", nullable = false, length = 4) - private String cprsBfYr; - - @Size(max = 4) - @NotNull - @Column(name = "cprs_ad_yr", nullable = false, length = 4) - private String cprsAdYr; - - @NotNull - @Column(name = "dtct_sno", nullable = false) - private Integer dtctSno; - - @NotNull - @Column(name = "path_nm", nullable = false, length = Integer.MAX_VALUE) - private String pathNm; - - @Size(max = 50) - @Column(name = "feature_id", length = 50) - private String featureId; - - @Size(max = 30) - @NotNull - @Column(name = "crt_epno", nullable = false, length = 30) - private String crtEpno; - - @Size(max = 45) - @NotNull - @Column(name = "crt_ip", nullable = false, length = 45) - private String crtIp; - - @NotNull - @ColumnDefault("now()") - @Column(name = "crt_dttm", nullable = false) - private ZonedDateTime crtDttm = ZonedDateTime.now(); - - @Size(max = 30) - @Column(name = "chg_epno", length = 30) - private String chgEpno; - - @Size(max = 45) - @Column(name = "chg_ip", length = 45) - private String chgIp; - - @Column(name = "chg_dttm") - private ZonedDateTime chgDttm; -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/entity/DetectMastPnuEntity.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/entity/DetectMastPnuEntity.java deleted file mode 100644 index aef47a97..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/entity/DetectMastPnuEntity.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.postgres.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.UUID; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.ColumnDefault; - -@Getter -@Setter -@Entity -@Table(name = "detect_mast_pnu") -public class DetectMastPnuEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "detect_mast_pnu_id_gen") - @SequenceGenerator( - name = "detect_mast_pnu_id_gen", - sequenceName = "seq_detect_mast_pnu_id", - allocationSize = 1) - @Column(name = "dtct_mst_pnu_id", nullable = false) - private Long id; - - @NotNull - @ColumnDefault("gen_random_uuid()") - @Column(name = "detect_mast_pnu_uuid", nullable = false) - private UUID detectMastPnuUuid; - - @NotNull - @Column(name = "dtct_mst_id", nullable = false) - private Long dtctMstId; - - @Size(max = 4) - @NotNull - @Column(name = "pnu", nullable = false, length = 4) - private String pnu; - - @Column(name = "polygon", length = Integer.MAX_VALUE) - private String polygon; -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastPnuRepository.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastPnuRepository.java deleted file mode 100644 index b44f3677..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastPnuRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.postgres.repository; - -import com.kamco.cd.kamcoback.Innopam.postgres.entity.DetectMastPnuEntity; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface DetectMastPnuRepository - extends JpaRepository, DetectMastPnuRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastPnuRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastPnuRepositoryCustom.java deleted file mode 100644 index 3029c658..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastPnuRepositoryCustom.java +++ /dev/null @@ -1,3 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.postgres.repository; - -public interface DetectMastPnuRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepository.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepository.java deleted file mode 100644 index c6aa24f3..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.postgres.repository; - -import com.kamco.cd.kamcoback.Innopam.postgres.entity.DetectMastEntity; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface DetectMastRepository - extends JpaRepository, DetectMastRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryCustom.java deleted file mode 100644 index 47d1ea99..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryCustom.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.postgres.repository; - -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.FeaturePnuDto; -import com.kamco.cd.kamcoback.Innopam.postgres.entity.DetectMastEntity; -import java.util.List; - -public interface DetectMastRepositoryCustom { - - public List findDetectMastList(DetectMastSearch detectMast); - - public DetectMastEntity findPnuData(DetectMastSearch detectMast); - - Integer updateGeomPnu(List list); -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryImpl.java deleted file mode 100644 index 78888af4..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryImpl.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.postgres.repository; - -import static com.kamco.cd.kamcoback.Innopam.postgres.entity.QDetectMastEntity.detectMastEntity; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.FeaturePnuDto; -import com.kamco.cd.kamcoback.Innopam.postgres.entity.DetectMastEntity; -import com.querydsl.core.BooleanBuilder; -import com.querydsl.jpa.impl.JPAQueryFactory; -import jakarta.persistence.EntityManager; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Repository; - -@Repository -@RequiredArgsConstructor -public class DetectMastRepositoryImpl implements DetectMastRepositoryCustom { - - private final EntityManager em; - private final JPAQueryFactory queryFactory; - private final ObjectMapper objectMapper; - - @Override - public List findDetectMastList(DetectMastSearch detectMast) { - - BooleanBuilder whereBuilder = new BooleanBuilder(); - - if (StringUtils.isNotBlank(detectMast.getCprsAdYr())) { - whereBuilder.and(detectMastEntity.cprsAdYr.eq(detectMast.getCprsAdYr())); - } - - if (StringUtils.isNotBlank(detectMast.getCprsBfYr())) { - whereBuilder.and(detectMastEntity.cprsBfYr.eq(detectMast.getCprsBfYr())); - } - - if (detectMast.getDtctSno() != null) { - whereBuilder.and(detectMastEntity.dtctSno.eq(detectMast.getDtctSno())); - } - - return queryFactory.select(detectMastEntity).from(detectMastEntity).where(whereBuilder).fetch(); - } - - @Override - public DetectMastEntity findPnuData(DetectMastSearch detectMast) { - - BooleanBuilder whereBuilder = new BooleanBuilder(); - - whereBuilder.and(detectMastEntity.cprsAdYr.eq(detectMast.getCprsAdYr())); - whereBuilder.and(detectMastEntity.cprsBfYr.eq(detectMast.getCprsBfYr())); - whereBuilder.and(detectMastEntity.dtctSno.eq(detectMast.getDtctSno())); - - if (detectMast.getFeatureId() != null) { - whereBuilder.and(detectMastEntity.featureId.eq(detectMast.getFeatureId())); - } - - return queryFactory - .select(detectMastEntity) - .from(detectMastEntity) - .where(whereBuilder) - .fetchOne(); - } - - @Override - public Integer updateGeomPnu(List list) { - if (list == null || list.isEmpty()) { - return 0; - } - - String sql = - """ - UPDATE tb_map_sheet_anal_data_inference_geom g - SET pnu = j.pnu - FROM ( - SELECT - (elem->>'featureId')::uuid AS feature_uuid, - (elem->>'pnu')::bigint AS pnu - FROM jsonb_array_elements(CAST(:json AS jsonb)) AS elem - ) j - WHERE g.uuid = j.feature_uuid; - """; - - String json = ""; - try { - json = objectMapper.writeValueAsString(list); - } catch (JsonProcessingException e) { - throw new RuntimeException("PNU 업데이트 실패", e); - } - - return em.createNativeQuery(sql).setParameter("json", json).executeUpdate(); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/service/DetectMastService.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/service/DetectMastService.java deleted file mode 100644 index f4485d20..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/service/DetectMastService.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.service; - -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.Basic; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastReq; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.FeaturePnuDto; -import com.kamco.cd.kamcoback.Innopam.postgres.core.DetectMastCoreService; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.Stream; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(readOnly = true) -@RequiredArgsConstructor -public class DetectMastService { - - @Value("${spring.profiles.active:local}") - private String profile; - - private final DetectMastCoreService detectMastCoreService; - private final JsonFactory jsonFactory = new JsonFactory(); - - @Transactional - public void saveDetectMast(DetectMastReq detectMast) { - detectMastCoreService.saveDetectMast(detectMast); - // - // String dirPath = - // "local".equals(profile) - // ? "/Users/bokmin/detect/result/2023_2024/4" - // : detectMast.getPathNm(); - // - // List list = this.extractFeaturePnusRandom(dirPath); - } - - public List selectDetectMast(DetectMastSearch detectMast) { - return detectMastCoreService.selectDetectMast(detectMast); - } - - public Basic selectDetectMast(Long id) { - return detectMastCoreService.selectDetectMast(id); - } - - /** GeoJSON → polygon_id + 랜덤 PNU */ - public List findPnuData(DetectMastSearch detectMast) { - - String dirPath = - "local".equals(profile) - ? "/Users/bokmin/detect/result/" - + detectMast.getCprsBfYr() - + "_" - + detectMast.getCprsAdYr() - + "/" - + detectMast.getDtctSno() - : detectMastCoreService.findPnuData(detectMast); - - return extractFeaturePnusRandom(dirPath); - } - - public FeaturePnuDto selectPnuDetail(UUID uuid) { - FeaturePnuDto dto = new FeaturePnuDto(); - dto.setPnu(randomPnu()); - dto.setFeatureId(uuid.toString()); - return dto; - } - - @Transactional - public Integer updatePnuData(DetectMastSearch detectMast) { - - String dirPath = - "local".equals(profile) - ? "/Users/bokmin/detect/result/" - + detectMast.getCprsBfYr() - + "_" - + detectMast.getCprsAdYr() - + "/" - + detectMast.getDtctSno() - : detectMastCoreService.findPnuData(detectMast); - - List list = extractFeaturePnusRandom(dirPath); - return detectMastCoreService.updatePnu(list); - } - - /** 하위 폴더까지 .geojson 파일들에서 polygon_id만 뽑음 병렬처리(parallel) 제거: IO + parallel은 거의 항상 느려짐 */ - private List extractFeaturePnusRandom(String dirPath) { - - Path basePath = Paths.get(dirPath); - if (!Files.isDirectory(basePath)) { - System.err.println("유효하지 않은 디렉터리: " + dirPath); - return List.of(); - } - - List out = new ArrayList<>(4096); - - try (Stream stream = Files.walk(basePath)) { - stream - .filter(Files::isRegularFile) - .filter(p -> p.toString().toLowerCase().endsWith(".geojson")) - .forEach( - p -> { - try (InputStream in = Files.newInputStream(p); - JsonParser parser = jsonFactory.createParser(in)) { - - while (parser.nextToken() != null) { - if (parser.currentToken() == JsonToken.FIELD_NAME - && "polygon_id".equals(parser.getCurrentName())) { - - JsonToken next = parser.nextToken(); // 값으로 이동 - if (next == JsonToken.VALUE_STRING) { - String polygonId = parser.getValueAsString(); - out.add(new FeaturePnuDto(polygonId, randomPnu())); - } - } - } - - } catch (Exception e) { - // 파일 단위 실패는 최소 로그 - System.err.println("GeoJSON 파싱 실패: " + p.getFileName() + " / " + e.getMessage()); - } - }); - - } catch (Exception e) { - System.err.println("디렉터리 탐색 실패: " + e.getMessage()); - return List.of(); - } - - return out; - } - - /** 랜덤 PNU 생성 (임시) - 법정동코드(5) + 산구분(1) + 본번(4) + 부번(4) = 14자리 */ - private String randomPnu() { - ThreadLocalRandom r = ThreadLocalRandom.current(); - - String dongCode = String.format("%05d", r.nextInt(10000, 99999)); - String san = r.nextBoolean() ? "1" : "2"; - String bon = String.format("%04d", r.nextInt(1, 10000)); - String bu = String.format("%04d", r.nextInt(0, 10000)); - - return dongCode + san + bon + bu; - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/service/InnopamApiService.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/service/InnopamApiService.java deleted file mode 100644 index 31773e84..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/service/InnopamApiService.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.service; - -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.kamco.cd.kamcoback.Innopam.dto.ChngDetectMastDto; -import com.kamco.cd.kamcoback.Innopam.dto.ChngDetectMastDto.ChngDetectMastSearchDto; -import com.kamco.cd.kamcoback.Innopam.dto.ChngDetectMastDto.ResReturn; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.Basic; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastReq; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.FeaturePnuDto; -import com.kamco.cd.kamcoback.Innopam.postgres.core.DetectMastCoreService; -import com.kamco.cd.kamcoback.common.utils.NetUtils; -import com.kamco.cd.kamcoback.common.utils.UserUtil; -import com.kamco.cd.kamcoback.config.api.ApiResponseDto; -import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient; -import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient.ExternalCallResult; -import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.DmlReturn; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.URLEncoder; -import java.net.UnknownHostException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.util.UriComponentsBuilder; - -@Service -@Transactional(readOnly = true) -@RequiredArgsConstructor -public class InnopamApiService { - - @Value("${spring.profiles.active:local}") - private String profile; - - @Value("${innopam.url}") - private String innopamUrl; - - @Value("${innopam.mast}") - private String innopamMastUrl; - - - private final DetectMastCoreService detectMastCoreService; - - private final ExternalHttpClient externalHttpClient; - private final UserUtil userUtil = new UserUtil(); - private final NetUtils netUtils = new NetUtils(); - - private final JsonFactory jsonFactory = new JsonFactory(); - - @Transactional - public ChngDetectMastDto.Basic regist(ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) { - - ChngDetectMastDto.Basic basic = new ChngDetectMastDto.Basic(); - - String url = innopamMastUrl + "/regist"; - //url = "http://localhost:8080/api/kcd/cdi/detect/mast/regist"; - - String myip = netUtils.getLocalIP(); - chnDetectMastReq.setReqIp(myip); - - System.out.println("url == "+ url); - System.out.println("url == "+ myip); - - ExternalCallResult result = - externalHttpClient.call(url, HttpMethod.POST, chnDetectMastReq, netUtils.jsonHeaders(), String.class); - - System.out.println("result == " + result); - - return basic; - } - - @Transactional - public ResReturn remove(ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) { - ChngDetectMastDto.Basic basic = new ChngDetectMastDto.Basic(); - - String url = innopamMastUrl + "/remove"; - //url = "http://localhost:8080/api/kcd/cdi/detect/mast/remove"; - - String myip = netUtils.getLocalIP(); - chnDetectMastReq.setReqIp(myip); - - System.out.println("url == "+ url); - System.out.println("url == "+ myip); - - ExternalCallResult result = - externalHttpClient.call(url, HttpMethod.POST, chnDetectMastReq, netUtils.jsonHeaders(), String.class); - - System.out.println("result == " + result); - - return new ResReturn("success", "탐지결과 삭제 되었습니다."); - } - - @Transactional - public List list(ChngDetectMastDto.ChngDetectMastSearchDto searchDto) { - List masterList = new ArrayList<>(); - - String queryString = netUtils.dtoToQueryString(searchDto, null); - String url = innopamMastUrl+queryString; - - ExternalCallResult result = - externalHttpClient.call(url, HttpMethod.GET, null, netUtils.jsonHeaders(), String.class); - - System.out.println("list result == " + result); - - return masterList; - } - - - - - - -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/GeoJsonGeometryConverter.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/GeoJsonGeometryConverter.java deleted file mode 100644 index c1d8842e..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/GeoJsonGeometryConverter.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.utils; - -import com.fasterxml.jackson.databind.JsonNode; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.GeometryFactory; -import org.locationtech.jts.geom.LinearRing; -import org.locationtech.jts.geom.MultiPolygon; -import org.locationtech.jts.geom.Polygon; - -public class GeoJsonGeometryConverter { - - private static final GeometryFactory GF = new GeometryFactory(); - - public static Geometry toGeometry(JsonNode geomNode) { - String type = geomNode.path("type").asText(); - - if ("Polygon".equals(type)) { - return toPolygon(geomNode.path("coordinates")); - } - if ("MultiPolygon".equals(type)) { - return toMultiPolygon(geomNode.path("coordinates")); - } - return null; - } - - private static Polygon toPolygon(JsonNode coords) { - LinearRing shell = GF.createLinearRing(toCoords(coords.get(0))); - return GF.createPolygon(shell); - } - - private static MultiPolygon toMultiPolygon(JsonNode coords) { - Polygon[] polys = new Polygon[coords.size()]; - for (int i = 0; i < coords.size(); i++) { - polys[i] = toPolygon(coords.get(i)); - } - return GF.createMultiPolygon(polys); - } - - private static Coordinate[] toCoords(JsonNode ring) { - Coordinate[] c = new Coordinate[ring.size() + 1]; - for (int i = 0; i < ring.size(); i++) { - c[i] = new Coordinate(ring.get(i).get(0).asDouble(), ring.get(i).get(1).asDouble()); - } - c[c.length - 1] = c[0]; - return c; - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/GeoJsonLoader.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/GeoJsonLoader.java deleted file mode 100644 index 879cdea4..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/GeoJsonLoader.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.utils; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -public class GeoJsonLoader { - - private final ObjectMapper om = new ObjectMapper(); - - public GeoJsonFile load(File geoJsonFile) throws Exception { - - JsonNode root = om.readTree(geoJsonFile); - - long mapId = root.path("properties").path("map_id").asLong(-1); - if (mapId <= 0) { - throw new IllegalStateException( - "GeoJSON top-level properties.map_id 없음: " + geoJsonFile.getName()); - } - - List features = new ArrayList<>(); - root.path("features").forEach(features::add); - - return new GeoJsonFile(mapId, features); - } - - /** ✅ feature에서 polygon_id 추출 */ - public static String polygonId(JsonNode feature) { - return feature.path("properties").path("polygon_id").asText(null); - } - - public static class GeoJsonFile { - - public final long mapId; - public final List features; - - public GeoJsonFile(long mapId, List features) { - this.mapId = mapId; - this.features = features; - } - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/MapIdUtils.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/MapIdUtils.java deleted file mode 100644 index 2ab92670..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/MapIdUtils.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.utils; - -public class MapIdUtils { - - private MapIdUtils() { - // util class - } - - /** map_id → 시도코드 예: 34602060 → "34" */ - public static String sidoCodeFromMapId(long mapId) { - String s = String.valueOf(mapId); - if (s.length() < 2) { - throw new IllegalArgumentException("잘못된 map_id: " + mapId); - } - return s.substring(0, 2); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/ShpIndexManager.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/ShpIndexManager.java deleted file mode 100644 index 60100995..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/ShpIndexManager.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.utils; - -import java.io.File; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import org.geotools.api.data.DataStore; -import org.geotools.api.data.DataStoreFinder; -import org.geotools.api.data.SimpleFeatureSource; -import org.geotools.api.feature.simple.SimpleFeature; -import org.geotools.data.simple.SimpleFeatureCollection; -import org.geotools.data.simple.SimpleFeatureIterator; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.index.strtree.STRtree; - -public class ShpIndexManager { - - private static final String SHP_ROOT = "/shp"; - private static final String SHP_YYYYMM = "202512"; - private static final String PNU_FIELD = "PNU"; - - private final Map cache = new ConcurrentHashMap<>(); - - public STRtree getIndex(String sidoCode) { - return cache.computeIfAbsent(sidoCode, this::loadIndex); - } - - private STRtree loadIndex(String sidoCode) { - try { - String path = SHP_ROOT + "/LSMD_CONT_LDREG_" + sidoCode + "_" + SHP_YYYYMM + ".shp"; - - File shp = new File(path); - if (!shp.exists()) { - return null; - } - - STRtree index = new STRtree(10); - - DataStore store = DataStoreFinder.getDataStore(Map.of("url", shp.toURI().toURL())); - - String typeName = store.getTypeNames()[0]; - SimpleFeatureSource source = store.getFeatureSource(typeName); - SimpleFeatureCollection col = source.getFeatures(); - - try (SimpleFeatureIterator it = col.features()) { - while (it.hasNext()) { - SimpleFeature f = it.next(); - Geometry geom = (Geometry) f.getDefaultGeometry(); - String pnu = Objects.toString(f.getAttribute(PNU_FIELD), null); - if (geom != null && pnu != null) { - index.insert(geom.getEnvelopeInternal(), new ShpRow(geom, pnu)); - } - } - } - - index.build(); - store.dispose(); - return index; - - } catch (Exception e) { - return null; - } - } - - /** SHP 한 row */ - public static class ShpRow { - - public final Geometry geom; - public final String pnu; - - public ShpRow(Geometry geom, String pnu) { - this.geom = geom; - this.pnu = pnu; - } - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/ShpPnuMatcher.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/ShpPnuMatcher.java deleted file mode 100644 index f61d3852..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/utils/ShpPnuMatcher.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.kamco.cd.kamcoback.Innopam.utils; - -import java.util.List; -import org.locationtech.jts.geom.Envelope; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.prep.PreparedGeometry; -import org.locationtech.jts.geom.prep.PreparedGeometryFactory; -import org.locationtech.jts.index.strtree.STRtree; - -public class ShpPnuMatcher { - - public static String pickByIntersectionMax(STRtree index, Geometry target) { - - Envelope env = target.getEnvelopeInternal(); - - @SuppressWarnings("unchecked") - List rows = index.query(env); - - double best = 0; - String bestPnu = null; - - for (ShpIndexManager.ShpRow row : rows) { - - PreparedGeometry prep = PreparedGeometryFactory.prepare(row.geom); - - if (prep.contains(target) || prep.covers(target)) { - return row.pnu; - } - - if (!prep.intersects(target)) { - continue; - } - - double area = row.geom.intersection(target).getArea(); - if (area > best) { - best = area; - bestPnu = row.pnu; - } - } - return bestPnu; - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/auth/CustomAuthenticationProvider.java b/src/main/java/com/kamco/cd/kamcoback/auth/CustomAuthenticationProvider.java index df3c70cf..464ce996 100644 --- a/src/main/java/com/kamco/cd/kamcoback/auth/CustomAuthenticationProvider.java +++ b/src/main/java/com/kamco/cd/kamcoback/auth/CustomAuthenticationProvider.java @@ -3,8 +3,10 @@ package com.kamco.cd.kamcoback.auth; import com.kamco.cd.kamcoback.common.enums.StatusType; import com.kamco.cd.kamcoback.common.enums.error.AuthErrorCode; import com.kamco.cd.kamcoback.common.exception.CustomApiException; +import com.kamco.cd.kamcoback.common.utils.HeaderUtil; import com.kamco.cd.kamcoback.postgres.entity.MemberEntity; import com.kamco.cd.kamcoback.postgres.repository.members.MembersRepository; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.mindrot.jbcrypt.BCrypt; import org.springframework.security.authentication.AuthenticationProvider; @@ -12,12 +14,16 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; @Component @RequiredArgsConstructor public class CustomAuthenticationProvider implements AuthenticationProvider { private final MembersRepository membersRepository; + ServletRequestAttributes attr = + (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { @@ -52,7 +58,15 @@ public class CustomAuthenticationProvider implements AuthenticationProvider { // 인증 성공 → UserDetails 생성 CustomUserDetails userDetails = new CustomUserDetails(member); - return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + // front에서 전달한 사용자 ip 등록 + HttpServletRequest req = (attr != null) ? attr.getRequest() : null; + String ip = (req != null) ? HeaderUtil.get(req, "X-Forwarded-For") : null; + + UsernamePasswordAuthenticationToken token = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + + token.setDetails(ip); + return token; } @Override diff --git a/src/main/java/com/kamco/cd/kamcoback/common/enums/StatusType.java b/src/main/java/com/kamco/cd/kamcoback/common/enums/StatusType.java index fa7ab678..85599687 100644 --- a/src/main/java/com/kamco/cd/kamcoback/common/enums/StatusType.java +++ b/src/main/java/com/kamco/cd/kamcoback/common/enums/StatusType.java @@ -10,7 +10,7 @@ import lombok.Getter; @AllArgsConstructor public enum StatusType implements EnumType { ACTIVE("사용"), - INACTIVE("미사용"), + INACTIVE("사용중지"), PENDING("계정등록"); private final String desc; diff --git a/src/main/java/com/kamco/cd/kamcoback/common/utils/HeaderUtil.java b/src/main/java/com/kamco/cd/kamcoback/common/utils/HeaderUtil.java new file mode 100644 index 00000000..d7078aa2 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/common/utils/HeaderUtil.java @@ -0,0 +1,23 @@ +package com.kamco.cd.kamcoback.common.utils; + +import jakarta.servlet.http.HttpServletRequest; + +public final class HeaderUtil { + + private HeaderUtil() {} + + /** 특정 Header 값 조회 */ + public static String get(HttpServletRequest request, String headerName) { + if (request == null || headerName == null) { + return null; + } + + String value = request.getHeader(headerName); + return (value != null && !value.isBlank()) ? value : null; + } + + /** 필수 Header 조회 (없으면 null) */ + public static String getRequired(HttpServletRequest request, String headerName) { + return get(request, headerName); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/common/utils/NetUtils.java b/src/main/java/com/kamco/cd/kamcoback/common/utils/NetUtils.java index 55e89daa..ce74d280 100644 --- a/src/main/java/com/kamco/cd/kamcoback/common/utils/NetUtils.java +++ b/src/main/java/com/kamco/cd/kamcoback/common/utils/NetUtils.java @@ -7,15 +7,13 @@ import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; -import java.util.regex.Pattern; import java.util.stream.Collectors; -import org.mindrot.jbcrypt.BCrypt; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; public class NetUtils { - public String getLocalIP(){ + public String getLocalIP() { String ip; { @@ -30,23 +28,26 @@ public class NetUtils { return ip; } - public String dtoToQueryString(Object dto, String queryString) { ObjectMapper objectMapper = new ObjectMapper(); Map map = objectMapper.convertValue(dto, Map.class); - String qStr = map.entrySet().stream() - .filter(entry -> entry.getValue() != null) // null 제외 - .map(entry -> String.format("%s=%s", - entry.getKey(), - URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8))) - .collect(Collectors.joining("&")); + String qStr = + map.entrySet().stream() + .filter(entry -> entry.getValue() != null) // null 제외 + .map( + entry -> + String.format( + "%s=%s", + entry.getKey(), + URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8))) + .collect(Collectors.joining("&")); - if( queryString == null || queryString.isEmpty() ) { - queryString = "?"+qStr; - }else{ - queryString = queryString +"&" + qStr; + if (queryString == null || queryString.isEmpty()) { + queryString = "?" + qStr; + } else { + queryString = queryString + "&" + qStr; } // 2. Map을 쿼리 스트링 문자열로 변환 @@ -60,5 +61,4 @@ public class NetUtils { return headers; } - } diff --git a/src/main/java/com/kamco/cd/kamcoback/common/utils/UserUtil.java b/src/main/java/com/kamco/cd/kamcoback/common/utils/UserUtil.java index ee510208..7e64f0a2 100644 --- a/src/main/java/com/kamco/cd/kamcoback/common/utils/UserUtil.java +++ b/src/main/java/com/kamco/cd/kamcoback/common/utils/UserUtil.java @@ -44,4 +44,11 @@ public class UserUtil { MembersDto.Member user = getCurrentUser(); return user != null ? user.getRole() : null; } + + public String getIp() { + return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication()) + .map(auth -> auth.getDetails()) + .map(Object::toString) + .orElse(null); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/config/FileDownloadInteceptor.java b/src/main/java/com/kamco/cd/kamcoback/config/FileDownloadInteceptor.java index 506d6477..c800c690 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/FileDownloadInteceptor.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/FileDownloadInteceptor.java @@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.kamco.cd.kamcoback.auth.CustomUserDetails; +import com.kamco.cd.kamcoback.common.utils.HeaderUtil; import com.kamco.cd.kamcoback.config.api.ApiLogFunction; import com.kamco.cd.kamcoback.menu.dto.MenuDto; import com.kamco.cd.kamcoback.menu.service.MenuService; @@ -13,6 +14,7 @@ import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; +import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -74,7 +76,8 @@ public class FileDownloadInteceptor implements HandlerInterceptor { request.getRequestURI(), Objects.requireNonNull(basic).getMenuUid(), ip, - response.getStatus()); + response.getStatus(), + UUID.fromString(HeaderUtil.get(request, "kamco-download-uuid"))); auditLogRepository.save(log); } diff --git a/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java b/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java index 8eaea370..755d5322 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java @@ -378,7 +378,7 @@ public class GlobalExceptionHandler { HttpStatus.valueOf(codeName), errorLog.getId()); - return ResponseEntity.status(HttpStatus.UNAUTHORIZED) // 🔥 여기서 401 지정 + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) // 여기서 401 지정 .body(body); } diff --git a/src/main/java/com/kamco/cd/kamcoback/config/api/ApiLogFunction.java b/src/main/java/com/kamco/cd/kamcoback/config/api/ApiLogFunction.java index f9b48d09..29d78648 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/api/ApiLogFunction.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/api/ApiLogFunction.java @@ -9,8 +9,10 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; import org.springframework.web.util.ContentCachingRequestWrapper; +@Slf4j public class ApiLogFunction { // 클라이언트 IP 추출 @@ -35,6 +37,14 @@ public class ApiLogFunction { return ip; } + public static String getXFowardedForIp(HttpServletRequest request) { + String ip = request.getHeader("X-Forwarded-For"); + if (ip != null) { + ip = ip.split(",")[0].trim(); + } + return ip; + } + // 사용자 ID 추출 예시 (Spring Security 기준) public static String getUserId(HttpServletRequest request) { try { @@ -53,15 +63,15 @@ public class ApiLogFunction { return EventType.DOWNLOAD; } if (uri.contains("/print")) { - return EventType.PRINT; + return EventType.OTHER; } // 일반 CRUD return switch (method) { - case "POST" -> EventType.CREATE; - case "GET" -> EventType.READ; - case "DELETE" -> EventType.DELETE; - case "PUT", "PATCH" -> EventType.UPDATE; + case "POST" -> EventType.ADDED; + case "GET" -> EventType.LIST; + case "DELETE" -> EventType.REMOVE; + case "PUT", "PATCH" -> EventType.MODIFIED; default -> EventType.OTHER; }; } diff --git a/src/main/java/com/kamco/cd/kamcoback/config/api/ApiResponseAdvice.java b/src/main/java/com/kamco/cd/kamcoback/config/api/ApiResponseAdvice.java index 72cb50bc..67d22a13 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/api/ApiResponseAdvice.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/api/ApiResponseAdvice.java @@ -2,6 +2,8 @@ package com.kamco.cd.kamcoback.config.api; import com.fasterxml.jackson.databind.ObjectMapper; import com.kamco.cd.kamcoback.auth.CustomUserDetails; +import com.kamco.cd.kamcoback.common.utils.HeaderUtil; +import com.kamco.cd.kamcoback.log.dto.EventType; import com.kamco.cd.kamcoback.menu.dto.MenuDto; import com.kamco.cd.kamcoback.menu.service.MenuService; import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity; @@ -66,12 +68,23 @@ public class ApiResponseAdvice implements ResponseBodyAdvice { if (body instanceof ApiResponseDto apiResponse) { response.setStatusCode(apiResponse.getHttpStatus()); - String ip = ApiLogFunction.getClientIp(servletRequest); - Long userid = null; + String actionType = HeaderUtil.get(servletRequest, "kamco-action-type"); + if (actionType == null) { // actionType 이 없으면 로그 저장하지 않기 + return body; + } - if (servletRequest.getUserPrincipal() instanceof UsernamePasswordAuthenticationToken auth - && auth.getPrincipal() instanceof CustomUserDetails customUserDetails) { - userid = customUserDetails.getMember().getId(); + String ip = ApiLogFunction.getXFowardedForIp(servletRequest); + Long userid = null; + String loginAttemptId = null; + + // 로그인 시도할 때 + if (servletRequest.getRequestURI().contains("/api/auth/signin")) { + loginAttemptId = HeaderUtil.get(servletRequest, "kamco-login-attempt-id"); + } else { + if (servletRequest.getUserPrincipal() instanceof UsernamePasswordAuthenticationToken auth + && auth.getPrincipal() instanceof CustomUserDetails customUserDetails) { + userid = customUserDetails.getMember().getId(); + } } String requestBody; @@ -107,13 +120,15 @@ public class ApiResponseAdvice implements ResponseBodyAdvice { AuditLogEntity log = new AuditLogEntity( userid, - ApiLogFunction.getEventType(servletRequest), + EventType.fromName(actionType), ApiLogFunction.isSuccessFail(apiResponse), ApiLogFunction.getUriMenuInfo(result, servletRequest.getRequestURI()), ip, servletRequest.getRequestURI(), ApiLogFunction.cutRequestBody(requestBody), - apiResponse.getErrorLogUid()); + apiResponse.getErrorLogUid(), + null, + loginAttemptId); auditLogRepository.save(log); } diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/InnopamApiController.java b/src/main/java/com/kamco/cd/kamcoback/gukyuin/GukYuinApiController.java similarity index 62% rename from src/main/java/com/kamco/cd/kamcoback/Innopam/InnopamApiController.java rename to src/main/java/com/kamco/cd/kamcoback/gukyuin/GukYuinApiController.java index cf4d49eb..fe8ea930 100644 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/InnopamApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/gukyuin/GukYuinApiController.java @@ -1,13 +1,16 @@ -package com.kamco.cd.kamcoback.Innopam; +package com.kamco.cd.kamcoback.gukyuin; -import com.kamco.cd.kamcoback.Innopam.dto.ChngDetectMastDto; -import com.kamco.cd.kamcoback.Innopam.dto.ChngDetectMastDto.ChnDetectMastReqDto; -import com.kamco.cd.kamcoback.Innopam.dto.ChngDetectMastDto.ChngDetectMastSearchDto; -import com.kamco.cd.kamcoback.Innopam.dto.ChngDetectMastDto.ResReturn; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.Basic; -import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastReq; -import com.kamco.cd.kamcoback.Innopam.service.InnopamApiService; +import com.kamco.cd.kamcoback.config.api.ApiResponseDto; +import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto; +import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ChnDetectMastReqDto; +import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ChngDetectMastSearchDto; +import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ResReturn; +import com.kamco.cd.kamcoback.gukyuin.dto.DetectMastDto.Basic; +import com.kamco.cd.kamcoback.gukyuin.dto.DetectMastDto.DetectMastReq; +import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkableRes; +import com.kamco.cd.kamcoback.gukyuin.service.GukYuinApiService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -15,21 +18,23 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import java.util.List; +import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -@Tag(name = "이노펨 연동 API", description = "이노펨 연동 API") +@Tag(name = "국유in 연동 API", description = "국유in 연동 API") @RestController @RequiredArgsConstructor -@RequestMapping("/api/innopam/") -public class InnopamApiController { +@RequestMapping("/api/gukyuin/") +public class GukYuinApiController { - private final InnopamApiService innopamApiService; + private final GukYuinApiService gukYuinApiService; /** 탐지결과 등록 */ @Operation(summary = "탐지결과 등록", description = "탐지결과 등록") @@ -48,8 +53,7 @@ public class InnopamApiController { @PostMapping("/mast/regist") public ChngDetectMastDto.Basic regist( @RequestBody @Valid ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) { - // innopamApiService.saveDetectMast(chnDetectMastReq); - return innopamApiService.regist(chnDetectMastReq); + return gukYuinApiService.regist(chnDetectMastReq); } @Operation(summary = "탐지결과 삭제", description = "탐지결과 삭제") @@ -68,7 +72,7 @@ public class InnopamApiController { @PostMapping("/mast/remove") public ResReturn remove( @RequestBody @Valid ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) { - return innopamApiService.remove(chnDetectMastReq); + return gukYuinApiService.remove(chnDetectMastReq); } @Operation(summary = "탐지결과 등록목록 조회", description = "탐지결과 등록목록 조회") @@ -95,6 +99,30 @@ public class InnopamApiController { searchDto.setCprsYr(cprsYr); searchDto.setCrtrYr(crtrYr); searchDto.setChnDtctSno(chnDtctSno); - return innopamApiService.list(searchDto); + return gukYuinApiService.list(searchDto); + } + + @Operation(summary = "국유in연동 가능여부 확인", description = "국유in연동 가능여부 확인") + @GetMapping("/is-link/{uuid}") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "목록 성공", + content = + @Content( + mediaType = "application/json", + schema = + @Schema( + implementation = GukYuinLinkableRes.class, + description = "TRUE:연동가능, FALSE:연동 불가능"))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + public ApiResponseDto getIsLinkGukYuin( + @Parameter(description = "uuid", example = "5799eb21-4780-48b0-a82e-e58dcbb8806b") + @PathVariable + UUID uuid) { + return ApiResponseDto.ok(gukYuinApiService.getIsLinkGukYuin(uuid)); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/ChngDetectMastDto.java b/src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/ChngDetectMastDto.java new file mode 100644 index 00000000..cd38f1d3 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/ChngDetectMastDto.java @@ -0,0 +1,148 @@ +package com.kamco.cd.kamcoback.gukyuin.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +public class ChngDetectMastDto { + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class Basic { + + private String chnDtctMstId; // 탐지마스터아이디 + private String cprsYr; // 비교년도 2023 + private String crtrYr; // 기준년도 2024 + private String chnDtctSno; // 차수 (1 | 2 | ...) + private String chnDtctId; // 탐지아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 + private String chnDtctCnt; // 탐지객체개수 + private String pnuMpngCnt; // PNU매핑개수 + private String lrmYmd; // 지적도일자 + private String pathNm; // 탐지결과 절대경로명 /kamco_nas/export/{chnDtctId} + private List excnList; // 등록진행상태히스토리 (최근것부터 DESC) + private String excnStepCd; // 실행단계코드 + private String excnStep; // 실행단계코드에 해당하는 영문명 + private String excnPgrt; // 실행단계진행율 + private String excnBngnDt; // 실행단계시작시간 + private String excnEndDt; // 실행단계종료시간 + private String rmk; // 비고 + private String crtDt; // 생성일시 + private String crtEpno; // 생성사원번호 + private String crtIp; // 생성사원아이피 + private String chgDt; // 변경일시 + private String chgEpno; // 변경사원번호 + private String chgIp; // 변경사원아이피 + private String delYn; // 삭제여부 + // + private String reqEpno; // 요청사원번호 + private String reqIp; // 요청사원어이피 + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class ChnDetectMastExcnStepDto { + + private String srno; // 일련번호 + private String chnDtctMstId; // 탐지마스터아이디 + private String excnStepCd; // 실행단계코드 + private String excnStep; // 실행단계코드에 해당하는 영문명 + private String excnPgrt; // 실행단계진행율 + private String excnEndDt; // 실행단계종료시간 + private String errCd; // 오류코드 + private String errMsg; // 오류메세지 + private String crtDt; // 실행단계시작시간 + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class ChnDetectMastReqDto { + + private String cprsYr; // 비교년도 2023 + private String crtrYr; // 기준년도 2024 + private String chnDtctSno; // 차수 (1 | 2 | ...) + private String chnDtctId; // 탐지아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 + private String pathNm; // 탐지결과 절대경로명 /kamco_nas/export/{chnDtctId} + private String reqEpno; // 사원번호 + private String reqIp; // 사원아이피 + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class ChnDetectContDto { + + private String chnDtctMstId; // 탐지콘텐츠아이디 + private String chnDtctContId; // 탐지마스타아이디 + private String cprsYr; // 비교년도 2023 + private String crtrYr; // 기준년도 2024 + private String chnDtctSno; // 차수 (1 | 2 | ...) + private String mpqdNo; // 도엽번호 + private String chnDtctId; // 탐지아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 + private String chnDtctObjtId; // 탐지객체아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 + private String chnDtctPolygon; // 탐지객체폴리곤 + private String chnDtctSqms; // 탐지객체면적 + private String chnCd; // 변화코드 + private String chnDtctJson; // 변화탐지JSON + private String chnDtctProb; // 변화탐지정확도 + private String bfClsCd; // 이전부류코드 + private String bfClsProb; // 이전분류정확도 + private String afClsCd; // 이후분류코드 + private String afClsProb; // 이후분류정확도 + private String crtDt; // 생성일시 + private String crtEpno; // 생성사원번호 + private String crtIp; // 생성사원아이피 + private String delYn; // 삭제여부 + // + private String reqEpno; // 요청사원번호 + private String reqIp; // 요청사원아이피 + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class ChnDetectContReqDto { + + private String cprsYr; // 비교년도 2023 + private String crtrYr; // 기준년도 2024 + private String chnDtctSno; // 차수 (1 | 2 | ...) + private String mpqdNo; // 도엽번호 + private String chnDtctId; // 탐지아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 + private String chnDtctObjtId; // 탐지객체아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성 + private String reqEpno; // 사원번호 + private String reqIp; + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class ChngDetectMastSearchDto { + + private String chnDtctId; + private String cprsYr; + private String crtrYr; + private String chnDtctSno; + } + + @Schema(name = "ResReturn", description = "수행 후 리턴") + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class ResReturn { + + private String flag; + private String message; + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/dto/DetectMastDto.java b/src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/DetectMastDto.java similarity index 97% rename from src/main/java/com/kamco/cd/kamcoback/Innopam/dto/DetectMastDto.java rename to src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/DetectMastDto.java index 3a4a7e7e..59c6e866 100644 --- a/src/main/java/com/kamco/cd/kamcoback/Innopam/dto/DetectMastDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/DetectMastDto.java @@ -1,4 +1,4 @@ -package com.kamco.cd.kamcoback.Innopam.dto; +package com.kamco.cd.kamcoback.gukyuin.dto; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/GukYuinDto.java b/src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/GukYuinDto.java new file mode 100644 index 00000000..d236bfb4 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/GukYuinDto.java @@ -0,0 +1,48 @@ +package com.kamco.cd.kamcoback.gukyuin.dto; + +import com.kamco.cd.kamcoback.common.utils.enums.EnumType; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +public class GukYuinDto { + + @Getter + @Setter + public static class GukYuinLinkableRes { + + private boolean linkable; + // private GukYuinLinkFailCode code; + private String message; + } + + /** 실패 코드 enum */ + @Getter + @AllArgsConstructor + public enum GukYuinLinkFailCode implements EnumType { + OK("연동 가능"), + NOT_FOUND("대상 회차가 없습니다."), + SCOPE_PART_NOT_ALLOWED("부분 도엽은 연동 불가능 합니다."), + HAS_RUNNING_INFERENCE("라벨링 진행 중 회차가 있습니다."), + OTHER_GUKYUIN_IN_PROGRESS("국유in 연동 진행 중 회차가 있습니다."); + + private final String desc; + + @Override + public String getId() { + return name(); + } + + @Override + public String getText() { + return desc; + } + } + + // Repository가 반환할 Fact(조회 결과) + public record GukYuinLinkFacts( + boolean existsLearn, + boolean isPartScope, + boolean hasRunningInference, + boolean hasOtherUnfinishedGukYuin) {} +} diff --git a/src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/GukYuinStatus.java b/src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/GukYuinStatus.java new file mode 100644 index 00000000..d9fbb657 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/gukyuin/dto/GukYuinStatus.java @@ -0,0 +1,25 @@ +package com.kamco.cd.kamcoback.gukyuin.dto; + +import com.kamco.cd.kamcoback.common.utils.enums.EnumType; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum GukYuinStatus implements EnumType { + PENDING("대기"), + IN_PROGRESS("사용"), + COMPLETED("완료"); + + private final String desc; + + @Override + public String getId() { + return name(); + } + + @Override + public String getText() { + return desc; + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/gukyuin/service/GukYuinApiService.java b/src/main/java/com/kamco/cd/kamcoback/gukyuin/service/GukYuinApiService.java new file mode 100644 index 00000000..ecea1d61 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/gukyuin/service/GukYuinApiService.java @@ -0,0 +1,136 @@ +package com.kamco.cd.kamcoback.gukyuin.service; + +import com.kamco.cd.kamcoback.common.utils.NetUtils; +import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient; +import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient.ExternalCallResult; +import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto; +import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ResReturn; +import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkFacts; +import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkFailCode; +import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkableRes; +import com.kamco.cd.kamcoback.postgres.core.GukYuinCoreService; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class GukYuinApiService { + + @Value("${spring.profiles.active:local}") + private String profile; + + @Value("${gukyuin.url}") + private String gukyuinUrl; + + @Value("${gukyuin.mast}") + private String gukyuinMastUrl; + + private final GukYuinCoreService gukyuinCoreService; + private final ExternalHttpClient externalHttpClient; + private final NetUtils netUtils = new NetUtils(); + + @Transactional + public ChngDetectMastDto.Basic regist(ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) { + + ChngDetectMastDto.Basic basic = new ChngDetectMastDto.Basic(); + + String url = gukyuinMastUrl + "/regist"; + // url = "http://localhost:8080/api/kcd/cdi/detect/mast/regist"; + + String myip = netUtils.getLocalIP(); + chnDetectMastReq.setReqIp(myip); + + System.out.println("url == " + url); + System.out.println("url == " + myip); + + ExternalCallResult result = + externalHttpClient.call( + url, HttpMethod.POST, chnDetectMastReq, netUtils.jsonHeaders(), String.class); + + System.out.println("result == " + result); + + return basic; + } + + @Transactional + public ResReturn remove(ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) { + ChngDetectMastDto.Basic basic = new ChngDetectMastDto.Basic(); + + String url = gukyuinMastUrl + "/remove"; + // url = "http://localhost:8080/api/kcd/cdi/detect/mast/remove"; + + String myip = netUtils.getLocalIP(); + chnDetectMastReq.setReqIp(myip); + + System.out.println("url == " + url); + System.out.println("url == " + myip); + + ExternalCallResult result = + externalHttpClient.call( + url, HttpMethod.POST, chnDetectMastReq, netUtils.jsonHeaders(), String.class); + + System.out.println("result == " + result); + + return new ResReturn("success", "탐지결과 삭제 되었습니다."); + } + + @Transactional + public List list(ChngDetectMastDto.ChngDetectMastSearchDto searchDto) { + List masterList = new ArrayList<>(); + + String queryString = netUtils.dtoToQueryString(searchDto, null); + String url = gukyuinMastUrl + queryString; + + ExternalCallResult result = + externalHttpClient.call(url, HttpMethod.GET, null, netUtils.jsonHeaders(), String.class); + + System.out.println("list result == " + result); + + return masterList; + } + + /** + * 국유in연동 가능여부 확인 + * + * @param uuid uuid + * @return + */ + public GukYuinLinkableRes getIsLinkGukYuin(UUID uuid) { + GukYuinLinkFacts f = gukyuinCoreService.findLinkFacts(uuid); + GukYuinLinkFailCode code = decideCode(f); + + GukYuinLinkableRes res = new GukYuinLinkableRes(); + // res.setCode(code); + res.setLinkable(code == GukYuinLinkFailCode.OK); + res.setMessage(code.getDesc()); + return res; + } + + private GukYuinLinkFailCode decideCode(GukYuinLinkFacts f) { + + if (!f.existsLearn()) { + return GukYuinLinkFailCode.NOT_FOUND; + } + + if (f.isPartScope()) { + return GukYuinLinkFailCode.SCOPE_PART_NOT_ALLOWED; + } + + if (f.hasRunningInference()) { + return GukYuinLinkFailCode.HAS_RUNNING_INFERENCE; + } + + if (f.hasOtherUnfinishedGukYuin()) { + return GukYuinLinkFailCode.OTHER_GUKYUIN_IN_PROGRESS; + } + + return GukYuinLinkFailCode.OK; + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java b/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java index 0ffde09a..bd5ff6da 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java @@ -204,80 +204,6 @@ public class InferenceResultApiController { return ApiResponseDto.ok(result); } - // @ApiResponses( - // value = { - // @ApiResponse( - // responseCode = "200", - // description = "검색 성공", - // content = - // @Content( - // mediaType = "application/json", - // schema = @Schema(implementation = InferenceDetailDto.AnalResSummary.class))), - // @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @GetMapping("/summary/{id}") - // public ApiResponseDto getInferenceResultSummary( - // @Parameter(description = "목록 id", example = "53") @PathVariable Long id) { - // return ApiResponseDto.ok(inferenceResultService.getInferenceResultSummary(id)); - // } - // - // @Operation(summary = "추론관리 분석결과 상세", description = "분석결과 상제 정보 Summary, DashBoard") - // @ApiResponses( - // value = { - // @ApiResponse( - // responseCode = "200", - // description = "검색 성공", - // content = - // @Content( - // mediaType = "application/json", - // schema = @Schema(implementation = InferenceDetailDto.Detail.class))), - // @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @GetMapping("/detail/{id}") - // public ApiResponseDto getInferenceDetail( - // @Parameter(description = "목록 id", example = "53") @PathVariable Long id) { - // return ApiResponseDto.ok(inferenceResultService.getDetail(id)); - // } - // - // @Operation(summary = "추론관리 분석결과 상세 목록", description = "추론관리 분석결과 상세 목록 geojson 데이터 조회") - // @ApiResponses( - // value = { - // @ApiResponse( - // responseCode = "200", - // description = "검색 성공", - // content = - // @Content( - // mediaType = "application/json", - // schema = @Schema(implementation = Page.class))), - // @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @GetMapping("/geom/{id}") - // public ApiResponseDto> getInferenceResultGeomList( - // @Parameter(description = "분석결과 id", example = "53") @PathVariable Long id, - // @Parameter(description = "기준년도 분류", example = "land") @RequestParam(required = false) - // String targetClass, - // @Parameter(description = "비교년도 분류", example = "waste") @RequestParam(required = false) - // String compareClass, - // @Parameter(description = "5000:1 도협번호 37801011,37801012") @RequestParam(required = false) - // List mapSheetNum, - // @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0") - // int page, - // @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20") - // int size, - // @Parameter(description = "정렬 조건 (형식: 필드명,방향)", example = "name,asc") - // @RequestParam(required = false) - // String sort) { - // InferenceDetailDto.SearchGeoReq searchGeoReq = - // new InferenceDetailDto.SearchGeoReq( - // targetClass, compareClass, mapSheetNum, page, size, sort); - // Page geomList = - // inferenceResultService.getInferenceResultGeomList(id, searchGeoReq); - // return ApiResponseDto.ok(geomList); - // } - @Operation(summary = "추론관리 추론진행 서버 현황", description = "추론관리 추론진행 서버 현황") @ApiResponses( value = { @@ -336,7 +262,7 @@ public class InferenceResultApiController { }) @GetMapping("/infer-result-info") public ApiResponseDto getInferenceResultInfo( - @Parameter(description = "회차 uuid", example = "f30e8817-9625-4fff-ba43-c1e6ed2067c4") + @Parameter(description = "회차 uuid", example = "5799eb21-4780-48b0-a82e-e58dcbb8806b") @RequestParam UUID uuid) { return ApiResponseDto.ok(inferenceResultService.getInferenceResultInfo(uuid)); diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceDetailDto.java b/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceDetailDto.java index c187d03d..f71fe7dc 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceDetailDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceDetailDto.java @@ -3,6 +3,9 @@ package com.kamco.cd.kamcoback.inference.dto; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.kamco.cd.kamcoback.common.enums.DetectionClassification; import com.kamco.cd.kamcoback.common.enums.ImageryFitStatus; import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm; @@ -308,16 +311,16 @@ public class InferenceDetailDto { String mapSheetName; String subUid; String pnu; - String passYn; + String fitState; - @JsonProperty("passYn") - public String getPassYn() { - return this.passYn == null ? null : this.passYn; + @JsonProperty("fitState") + public String getFitState() { + return this.fitState == null ? null : this.fitState; } - @JsonProperty("passYnName") - public String getPassYnName() { - return ImageryFitStatus.getDescByCode(this.passYn); + @JsonProperty("fitStateName") + public String fitStateName() { + return ImageryFitStatus.getDescByCode(this.fitState); } // @JsonIgnore String gemoStr; @@ -339,7 +342,7 @@ public class InferenceDetailDto { String mapSheetName, String subUid, String pnu, - String passYn) { + String fitState) { this.uuid = uuid; this.uid = uid; this.compareYyyy = compareYyyy; @@ -355,7 +358,7 @@ public class InferenceDetailDto { this.mapSheetName = mapSheetName; this.subUid = subUid; this.pnu = pnu; - this.passYn = passYn; + this.fitState = fitState; } } @@ -431,6 +434,7 @@ public class InferenceDetailDto { @Schema(name = "AnalResultInfo", description = "추론결과 기본정보") @Getter + @Setter @AllArgsConstructor @NoArgsConstructor public static class AnalResultInfo { @@ -448,6 +452,31 @@ public class InferenceDetailDto { private Integer stage; private String elapsedDuration; private String subUid; + private Boolean applyYn; + @JsonFormatDttm private ZonedDateTime applyDttm; + + private String bboxGeom; + private String bboxCenterPoint; + + @JsonProperty("bboxGeom") + public JsonNode getBboxGeom() { + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.readTree(this.bboxGeom); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @JsonProperty("bboxCenterPoint") + public JsonNode getBboxCenterPoint() { + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.readTree(this.bboxCenterPoint); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } public AnalResultInfo( String analTitle, @@ -461,7 +490,9 @@ public class InferenceDetailDto { ZonedDateTime inferStartDttm, ZonedDateTime inferEndDttm, Integer stage, - String subUid) { + String subUid, + Boolean applyYn, + ZonedDateTime applyDttm) { this.analTitle = analTitle; this.modelVer1 = modelVer1; this.modelVer2 = modelVer2; @@ -474,6 +505,8 @@ public class InferenceDetailDto { this.inferEndDttm = inferEndDttm; this.stage = stage; this.subUid = subUid; + this.applyYn = applyYn; + this.applyDttm = applyDttm; Duration elapsed = (inferStartDttm != null && inferEndDttm != null) ? Duration.between(inferStartDttm, inferEndDttm) @@ -492,6 +525,16 @@ public class InferenceDetailDto { } } + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class BboxPointDto { + + private String bboxGeom; + private String bboxCenterPoint; + } + @Getter @Setter @NoArgsConstructor diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java index 49709195..36e68a7b 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java @@ -574,6 +574,12 @@ public class InferenceResultService { return dto; } + /** + * 추론결과 기본정보 + * + * @param uuid uuid + * @return + */ public AnalResultInfo getInferenceResultInfo(UUID uuid) { return inferenceResultCoreService.getInferenceResultInfo(uuid); } diff --git a/src/main/java/com/kamco/cd/kamcoback/log/dto/EventType.java b/src/main/java/com/kamco/cd/kamcoback/log/dto/EventType.java index 2f923681..bad76c10 100644 --- a/src/main/java/com/kamco/cd/kamcoback/log/dto/EventType.java +++ b/src/main/java/com/kamco/cd/kamcoback/log/dto/EventType.java @@ -7,16 +7,27 @@ import lombok.Getter; @Getter @AllArgsConstructor public enum EventType implements EnumType { - CREATE("생성"), - READ("조회"), - UPDATE("수정"), - DELETE("삭제"), + LIST("목록"), + DETAIL("상세"), + POPUP("팝업"), + STATUS("상태"), + ADDED("추가"), + MODIFIED("수정"), + REMOVE("삭제"), DOWNLOAD("다운로드"), - PRINT("출력"), + LOGIN("로그인"), OTHER("기타"); private final String desc; + public static EventType fromName(String name) { + try { + return EventType.valueOf(name.toUpperCase()); + } catch (Exception e) { + return OTHER; + } + } + @Override public String getId() { return name(); diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/GukYuinCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/GukYuinCoreService.java new file mode 100644 index 00000000..eb5224a0 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/GukYuinCoreService.java @@ -0,0 +1,24 @@ +package com.kamco.cd.kamcoback.postgres.core; + +import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkFacts; +import com.kamco.cd.kamcoback.postgres.repository.Inference.MapSheetLearnRepository; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class GukYuinCoreService { + + private final MapSheetLearnRepository mapSheetLearnRepository; + + /** + * 국유in연동 가능여부 확인 + * + * @param uuid uuid + * @return + */ + public GukYuinLinkFacts findLinkFacts(UUID uuid) { + return mapSheetLearnRepository.findLinkFacts(uuid); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java index a71ad890..dbf4269b 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java @@ -4,6 +4,7 @@ import com.kamco.cd.kamcoback.common.exception.CustomApiException; import com.kamco.cd.kamcoback.common.utils.UserUtil; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.AnalResultInfo; +import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.BboxPointDto; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Dashboard; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Geom; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.InferenceBatchSheet; @@ -409,8 +410,18 @@ public class InferenceResultCoreService { return dto; } + /** + * 추론결과 기본정보 + * + * @param uuid uuid + * @return + */ public AnalResultInfo getInferenceResultInfo(UUID uuid) { - return mapSheetLearnRepository.getInferenceResultInfo(uuid); + AnalResultInfo resultInfo = mapSheetLearnRepository.getInferenceResultInfo(uuid); + BboxPointDto bboxPointDto = mapSheetLearnRepository.getBboxPoint(uuid); + resultInfo.setBboxGeom(bboxPointDto.getBboxGeom()); + resultInfo.setBboxCenterPoint(bboxPointDto.getBboxCenterPoint()); + return resultInfo; } public List getInferenceClassCountList(UUID uuid) { diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/AuditLogEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/AuditLogEntity.java index c786d59c..d6c56934 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/AuditLogEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/AuditLogEntity.java @@ -12,6 +12,7 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; +import java.util.UUID; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -51,6 +52,12 @@ public class AuditLogEntity extends CommonCreateEntity { @Column(name = "error_log_uid") private Long errorLogUid; + @Column(name = "download_uuid") + private UUID downloadUuid; + + @Column(name = "login_attempt_id") + private String loginAttemptId; + public AuditLogEntity( Long userUid, EventType eventType, @@ -59,7 +66,9 @@ public class AuditLogEntity extends CommonCreateEntity { String ipAddress, String requestUri, String requestBody, - Long errorLogUid) { + Long errorLogUid, + UUID downloadUuid, + String loginAttemptId) { this.userUid = userUid; this.eventType = eventType; this.eventStatus = eventStatus; @@ -68,11 +77,18 @@ public class AuditLogEntity extends CommonCreateEntity { this.requestUri = requestUri; this.requestBody = requestBody; this.errorLogUid = errorLogUid; + this.downloadUuid = downloadUuid; + this.loginAttemptId = loginAttemptId; } /** 파일 다운로드 이력 생성 */ public static AuditLogEntity forFileDownload( - Long userId, String requestUri, String menuUid, String ip, int httpStatus) { + Long userId, + String requestUri, + String menuUid, + String ip, + int httpStatus, + UUID downloadUuid) { return new AuditLogEntity( userId, @@ -82,7 +98,9 @@ public class AuditLogEntity extends CommonCreateEntity { ip, requestUri, null, // requestBody 없음 - null // errorLogUid 없음 + null, // errorLogUid 없음 + downloadUuid, + null // loginAttemptId 없음 ); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalDataInferenceGeomEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalDataInferenceGeomEntity.java index c08fee12..203028b8 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalDataInferenceGeomEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalDataInferenceGeomEntity.java @@ -90,7 +90,6 @@ public class MapSheetAnalDataInferenceGeomEntity { private Long pnu; @Size(max = 20) - @ColumnDefault("'0'") @Column(name = "fit_state", length = 20) private String fitState; @@ -150,12 +149,6 @@ public class MapSheetAnalDataInferenceGeomEntity { @Column(name = "file_created_dttm") private ZonedDateTime fileCreatedDttm; - @Column(name = "pass_yn") - private String passYn; - - @Column(name = "pass_yn_dttm") - private ZonedDateTime passYnDttm; - @Column(name = "result_uid") private String resultUid; diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java index c3b85779..cb7d4aed 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnEntity.java @@ -1,5 +1,6 @@ package com.kamco.cd.kamcoback.postgres.entity; +import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -186,6 +187,12 @@ public class MapSheetLearnEntity { @Column(name = "m3_failed_jobs", nullable = false) private int m3FailedJobs = 0; + @Column(name = "apply_status") + private String applyStatus = GukYuinStatus.PENDING.getId(); + + @Column(name = "apply_status_dttm") + private ZonedDateTime applyStatusDttm; + @Column(name = "uid", nullable = false) private String uid = UUID.randomUUID().toString().replace("-", "").toUpperCase(); diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryCustom.java index fef0cb99..41ad1fa2 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryCustom.java @@ -1,6 +1,8 @@ package com.kamco.cd.kamcoback.postgres.repository.Inference; +import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkFacts; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.AnalResultInfo; +import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.BboxPointDto; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Dashboard; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Geom; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.SearchGeoReq; @@ -34,7 +36,11 @@ public interface MapSheetLearnRepositoryCustom { AnalResultInfo getInferenceResultInfo(UUID uuid); + BboxPointDto getBboxPoint(UUID uuid); + List getInferenceClassCountList(UUID uuid); Page getInferenceGeomList(UUID uuid, SearchGeoReq searchGeoReq); + + GukYuinLinkFacts findLinkFacts(UUID uuid); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java index 813081e5..919cc91c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java @@ -12,7 +12,10 @@ import static com.kamco.cd.kamcoback.postgres.entity.QSystemMetricEntity.systemM import com.kamco.cd.kamcoback.common.exception.CustomApiException; import com.kamco.cd.kamcoback.common.utils.DateRange; +import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkFacts; +import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.AnalResultInfo; +import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.BboxPointDto; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Dashboard; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Geom; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.SearchGeoReq; @@ -20,10 +23,14 @@ import com.kamco.cd.kamcoback.inference.dto.InferenceProgressDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceStatusDetailDto; +import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheetScope; import com.kamco.cd.kamcoback.model.service.ModelMngService; import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnEntity; +import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity; +import com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnEntity; import com.kamco.cd.kamcoback.postgres.entity.QModelMngEntity; import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Expression; import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.CaseBuilder; @@ -319,7 +326,9 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto mapSheetLearnEntity.inferStartDttm, mapSheetLearnEntity.inferEndDttm, mapSheetLearnEntity.stage, - Expressions.stringTemplate("substring({0} from 1 for 8)", mapSheetLearnEntity.uid))) + Expressions.stringTemplate("substring({0} from 1 for 8)", mapSheetLearnEntity.uid), + mapSheetLearnEntity.applyYn, + mapSheetLearnEntity.applyDttm)) .from(mapSheetLearnEntity) .leftJoin(m1) .on(mapSheetLearnEntity.m1ModelUuid.eq(m1.uuid)) @@ -331,6 +340,30 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto .fetchOne(); } + @Override + public BboxPointDto getBboxPoint(UUID uuid) { + Expression bboxGeom = + Expressions.stringTemplate( + "ST_AsGeoJSON(ST_Envelope(ST_Collect({0})))", mapSheetAnalDataInferenceGeomEntity.geom); + + Expression bboxCenterPoint = + Expressions.stringTemplate( + "ST_AsGeoJSON(ST_Centroid(ST_Envelope(ST_Collect({0}))))", + mapSheetAnalDataInferenceGeomEntity.geom); + + return queryFactory + .select(Projections.constructor(BboxPointDto.class, bboxGeom, bboxCenterPoint)) + .from(mapSheetLearnEntity) + .join(mapSheetAnalInferenceEntity) + .on(mapSheetAnalInferenceEntity.learnId.eq(mapSheetLearnEntity.id)) + .join(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalDataInferenceEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) + .join(mapSheetAnalDataInferenceGeomEntity) + .on(mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id)) + .where(mapSheetLearnEntity.uuid.eq(uuid)) + .fetchOne(); + } + @Override public List getInferenceClassCountList(UUID uuid) { @@ -420,7 +453,7 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto StringExpression pnu = Expressions.stringTemplate( - "coalesce(({0}), '')", + "nullif(({0}), '')", JPAExpressions.select(Expressions.stringTemplate("string_agg({0}, ',')", pnuEntity.pnu)) .from(pnuEntity) .where(pnuEntity.geo.geoUid.eq(mapSheetAnalDataInferenceGeomEntity.geoUid))); @@ -446,7 +479,7 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto "substring({0} from 1 for 8)", mapSheetAnalDataInferenceGeomEntity.resultUid), pnu, - mapSheetAnalDataInferenceGeomEntity.passYn)) + mapSheetAnalDataInferenceGeomEntity.fitState)) .from(mapSheetAnalInferenceEntity) .join(mapSheetAnalDataInferenceEntity) .on(mapSheetAnalDataInferenceEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) @@ -474,4 +507,57 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto return new PageImpl<>(content, pageable, total == null ? 0L : total); } + + /** + * 국유in연동 가능여부 확인 + * + * @param uuid uuid + * @return + */ + @Override + public GukYuinLinkFacts findLinkFacts(UUID uuid) { + + MapSheetLearnEntity learn = + queryFactory + .selectFrom(QMapSheetLearnEntity.mapSheetLearnEntity) + .where(QMapSheetLearnEntity.mapSheetLearnEntity.uuid.eq(uuid)) + .fetchOne(); + + if (learn == null) { + return new GukYuinLinkFacts(false, false, false, false); + } + + boolean isPartScope = MapSheetScope.PART.getId().equals(learn.getMapSheetScope()); + + QMapSheetAnalInferenceEntity inf = QMapSheetAnalInferenceEntity.mapSheetAnalInferenceEntity; + QMapSheetLearnEntity learn2 = new QMapSheetLearnEntity("learn2"); + QMapSheetLearnEntity learnQ = QMapSheetLearnEntity.mapSheetLearnEntity; + + boolean hasRunningInference = + queryFactory + .selectOne() + .from(inf) + .join(learn2) + .on(inf.learnId.eq(learn2.id)) + .where( + learn2.compareYyyy.eq(learn.getCompareYyyy()), + learn2.targetYyyy.eq(learn.getTargetYyyy()), + inf.analState.in("ASSIGNED", "ING")) + .fetchFirst() + != null; + + boolean hasOtherUnfinishedGukYuin = + queryFactory + .selectOne() + .from(learnQ) + .where( + learnQ.compareYyyy.eq(learn.getCompareYyyy()), + learnQ.targetYyyy.eq(learn.getTargetYyyy()), + learnQ.applyStatus.eq(GukYuinStatus.IN_PROGRESS.getId()), + learnQ.uuid.ne(learn.getUuid())) + .fetchFirst() + != null; + + return new GukYuinLinkFacts(true, isPartScope, hasRunningInference, hasOtherUnfinishedGukYuin); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java index 930c334a..01b4091a 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/changedetection/ChangeDetectionRepositoryImpl.java @@ -67,10 +67,8 @@ public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport mapSheetAnalSttcEntity.id.classAfterCd.as("classNm"), // 앞단 CoreService 에서 한글명으로 변환 mapSheetAnalSttcEntity.classAfterCnt.sum())) .from(mapSheetAnalInferenceEntity) - .innerJoin(mapSheetAnalDataInferenceEntity) - .on(mapSheetAnalDataInferenceEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) .innerJoin(mapSheetAnalSttcEntity) - .on(mapSheetAnalSttcEntity.id.dataUid.eq(mapSheetAnalDataInferenceEntity.id)) + .on(mapSheetAnalSttcEntity.id.analUid.eq(mapSheetAnalInferenceEntity.id)) .where( mapSheetAnalInferenceEntity.uuid.eq(uuid), mapScaleTypeSearchExpression(scale, mapSheetNum)) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java index fd9631b6..304f8d59 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java @@ -1152,7 +1152,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 날짜별 전체 건수 Expression dailyTotalCnt = Expressions.numberTemplate(Long.class, "COUNT(*)"); - // ⭐ 전체 기간 총 건수 (윈도우 함수) + // 전체 기간 총 건수 (윈도우 함수) Expression totalCnt = Expressions.numberTemplate(Long.class, "SUM(COUNT(*)) OVER ()"); // 상태별 카운트 (Postgres FILTER 사용) @@ -1192,7 +1192,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto LabelingStatDto.class, workDate, dailyTotalCnt, - totalCnt, // ⭐ 전체 일자 배정 건수 + totalCnt, // 전체 일자 배정 건수 assignedCnt, skipCnt, completeCnt, @@ -1233,7 +1233,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto // 날짜별 전체 건수 Expression dailyTotalCnt = Expressions.numberTemplate(Long.class, "COUNT(*)"); - // ⭐ 전체 기간 총 건수 (윈도우 함수) + // 전체 기간 총 건수 (윈도우 함수) Expression totalCnt = Expressions.numberTemplate(Long.class, "SUM(COUNT(*)) OVER ()"); // 상태별 카운트 (Postgres FILTER 사용) @@ -1277,7 +1277,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto LabelingStatDto.class, workDate, dailyTotalCnt, - totalCnt, // ⭐ 전체 일자 배정 건수 + totalCnt, // 전체 일자 배정 건수 assignedCnt, skipCnt, completeCnt, diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/log/AuditLogRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/log/AuditLogRepositoryImpl.java index ff72fb73..5818fe5a 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/log/AuditLogRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/log/AuditLogRepositoryImpl.java @@ -488,7 +488,7 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport private NumberExpression readCount() { return new CaseBuilder() - .when(auditLogEntity.eventType.eq(EventType.READ)) + .when(auditLogEntity.eventType.in(EventType.LIST, EventType.DETAIL)) .then(1) .otherwise(0) .sum(); @@ -496,7 +496,7 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport private NumberExpression cudCount() { return new CaseBuilder() - .when(auditLogEntity.eventType.in(EventType.CREATE, EventType.UPDATE, EventType.DELETE)) + .when(auditLogEntity.eventType.in(EventType.ADDED, EventType.MODIFIED, EventType.REMOVE)) .then(1) .otherwise(0) .sum(); @@ -504,7 +504,7 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport private NumberExpression printCount() { return new CaseBuilder() - .when(auditLogEntity.eventType.eq(EventType.PRINT)) + .when(auditLogEntity.eventType.eq(EventType.OTHER)) .then(1) .otherwise(0) .sum(); diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java index d979e192..99cb8012 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java @@ -426,7 +426,7 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport "concat({0}, substring({1}, 1, 5))", mapInkx5kEntity.mapidNm, mapSheetMngHstEntity.mapSheetNum), - // ✅ 튜플 방지: concat으로 문자열 생성 + // 튜플 방지: concat으로 문자열 생성 Expressions.stringTemplate( "concat('(', {0}, ',', {1}, ')')", mapInkx5kEntity.mapidNm, mapSheetMngHstEntity.mapSheetNum), @@ -437,7 +437,7 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport // fid 타입 주의 (Long이면 DTO도 Long으로 맞추는 걸 추천) mapInkx5kEntity.fid, // 또는 mapInkx5kEntity.fid.intValue() - // ✅ createdDate 말고 ZonedDateTime으로 매핑된 필드로 + // createdDate 말고 ZonedDateTime으로 매핑된 필드로 mapSheetMngHstEntity.createdDate, // (예시) mapSheetMngHstEntity.syncState, mapSheetMngHstEntity.syncTfwFileName, diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 93f944db..c22952d8 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -19,6 +19,7 @@ spring: datasource: url: jdbc:postgresql://192.168.2.127:15432/kamco_cds + #url: jdbc:postgresql://localhost:15432/kamco_cds username: kamco_cds password: kamco_cds_Q!W@E#R$ hikari: @@ -109,7 +110,7 @@ inference: geojson-dir: /kamco-nfs/requests/ jar-path: /kamco-nfs/dataset/shp_exporter-1.0.0.jar -innopam: +gukyuin: #url: http://localhost:8080 - url: http://192.168.2.129:5301 - mast : ${innopam.url}/api/kcd/cdi/chn/mast + url: http://192.168.2.129:5301 + mast: ${gukyuin.url}/api/kcd/cdi/chn/mast diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 0636775d..431d5c67 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -15,8 +15,8 @@ spring: format_sql: true # ⚠️ 선택 - SQL 포맷팅 (가독성) datasource: - #url: jdbc:postgresql://192.168.2.127:15432/kamco_cds - url: jdbc:postgresql://localhost:25432/kamco_cds + url: jdbc:postgresql://192.168.2.127:15432/kamco_cds + #url: jdbc:postgresql://localhost:15432/kamco_cds username: kamco_cds password: kamco_cds_Q!W@E#R$ hikari: @@ -25,12 +25,9 @@ spring: data: redis: - #host: 192.168.2.109 - #port: 6379 - #password: kamco - host: localhost + host: 192.168.2.109 port: 6379 - password: + password: kamco servlet: multipart: @@ -68,13 +65,13 @@ mapsheet: shp: baseurl: /Users/bokmin/detect/result + + file: sync-root-dir: D:/kamco-nfs/images/ #sync-root-dir: /kamco-nfs/images/ sync-tmp-dir: ${file.sync-root-dir}/tmp sync-file-extention: tfw,tif - sync-auto-exception-start-year: 2025 - sync-auto-exception-before-year-cnt: 3 dataset-dir: D:/kamco-nfs/dataset/ #dataset-dir: /kamco-nfs/dataset/export/ @@ -90,8 +87,3 @@ inference: batch-url: http://10.100.0.11:8000/batches geojson-dir: /kamco-nfs/requests/ jar-path: jar/makeshp-1.0.0.jar - -innopam: - #url: http://localhost:8080 - url: http://192.168.2.129:5301 - mast : ${innopam.url}/api/kcd/cdi/chn/mast diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index d3eafec4..7af3bb53 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -63,3 +63,7 @@ inference: geojson-dir: /kamco-nfs/requests/ jar-path: /kamco-nfs/dataset/shp_exporter-1.0.0.jar +gukyuin: + #url: http://localhost:8080 + url: http://192.168.2.129:5301 + mast: ${gukyuin.url}/api/kcd/cdi/chn/mast