# Java Spring(전자정부프레임워크) 센서 시스템 개발 가이드 - Part 1 ## 📋 프로젝트 개요 **프로젝트명**: Java Spring 기반 센서 데이터 수집 및 관리 시스템 **기술 스택**: Java 11, Spring Boot 2.7.x, 전자정부프레임워크 4.0.x **아키텍처**: 계층형 아키텍처 + REST API **데이터베이스**: PostgreSQL, Redis **상태**: 개발 가이드 작성 완료 --- ## 🏗️ 시스템 아키텍처 ### 전체 시스템 구성도 ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 센서 디바이스 │────│ Java 브리지 │────│ Spring Boot │ │ (RSNet SDK) │ │ (RSNet SDK) │ │ (REST API) │ │ │ │ (포트: 8020) │ │ (포트: 8080) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 웹 대시보드 │◄───│ PostgreSQL │◄───│ Redis 캐시 │ │ (Thymeleaf) │ │ (데이터 저장) │ │ (실시간 캐시) │ │ (포트: 8080) │ │ (포트: 5432) │ │ (포트: 6379) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ### 서비스 구성 | 서비스 | 기술 스택 | 포트 | 역할 | 상태 | |--------|-----------|------|------|------| | **sensor-spring-app** | Spring Boot + 전자정부프레임워크 | 8080 | 메인 웹 애플리케이션 | 🔄 개발 중 | | **sensor-bridge** | Java + RSNet SDK | 8020 | 센서 데이터 브리지 | ✅ 기존 유지 | | **postgres** | PostgreSQL 15 | 5432 | 메인 데이터베이스 | ✅ 기존 유지 | | **redis** | Redis 7 | 6379 | 실시간 캐시 | ✅ 기존 유지 | --- ## 📁 프로젝트 구조 ### 새로운 Spring 애플리케이션 구조 ``` sensor-spring-app/ ├── 📁 src/ │ ├── 📁 main/ │ │ ├── 📁 java/ │ │ │ └── 📁 com/sensor/spring/ │ │ │ ├── 📁 config/ # 설정 클래스 │ │ │ ├── 📁 controller/ # REST 컨트롤러 │ │ │ ├── 📁 service/ # 비즈니스 로직 │ │ │ ├── 📁 repository/ # 데이터 접근 계층 │ │ │ ├── 📁 entity/ # JPA 엔티티 │ │ │ ├── 📁 dto/ # 데이터 전송 객체 │ │ │ ├── 📁 exception/ # 예외 처리 │ │ │ ├── 📁 util/ # 유틸리티 │ │ │ └── 📄 SensorSpringApplication.java │ │ ├── 📁 resources/ │ │ │ ├── 📁 static/ # 정적 리소스 │ │ │ ├── 📁 templates/ # Thymeleaf 템플릿 │ │ │ ├── 📄 application.yml # Spring 설정 │ │ │ ├── 📄 application-dev.yml # 개발 환경 설정 │ │ │ └── 📄 application-prod.yml # 운영 환경 설정 │ │ └── 📁 webapp/ # 전자정부프레임워크 설정 │ └── 📁 test/ # 테스트 코드 ├── 📄 pom.xml # Maven 프로젝트 설정 ├── 📄 Dockerfile # Docker 이미지 빌드 └── 📄 README.md # 프로젝트 문서 ``` --- ## 🚀 개발 환경 설정 ### 1. 필수 요구사항 - **Java**: JDK 11 이상 - **Maven**: 3.6.x 이상 - **IDE**: IntelliJ IDEA, Eclipse, VS Code - **데이터베이스**: PostgreSQL 15, Redis 7 - **기존 시스템**: sensor-bridge, postgres, redis ### 2. Maven 프로젝트 생성 #### **pom.xml 설정** ```xml 4.0.0 org.springframework.boot spring-boot-starter-parent 2.7.18 com.sensor sensor-spring-app 1.0.0 jar Sensor Spring Application Spring Boot based sensor data management system 11 4.0.0 2.7.18 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-validation org.springframework.boot spring-boot-starter-actuator org.egovframe.rte org.egovframe.rte.ptl.mvc ${egovframework.rte.version} org.egovframe.rte org.egovframe.rte.psl.dataaccess ${egovframework.rte.version} org.egovframe.rte org.egovframe.rte.fdl.idgnr ${egovframework.rte.version} org.postgresql postgresql runtime org.flywaydb flyway-core com.fasterxml.jackson.core jackson-databind com.fasterxml.jackson.datatype jackson-datatype-jsr310 org.springframework.boot spring-boot-starter-logging org.springframework.boot spring-boot-starter-test test org.testcontainers postgresql test org.springframework.boot spring-boot-maven-plugin org.flywaydb flyway-maven-plugin ``` ### 3. Spring Boot 메인 클래스 #### **SensorSpringApplication.java** ```java package com.sensor.spring; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableJpaAuditing @EnableCaching @EnableAsync @EnableScheduling public class SensorSpringApplication { public static void main(String[] args) { SpringApplication.run(SensorSpringApplication.class, args); } } ``` --- ## ⚙️ 설정 파일 ### 1. application.yml (메인 설정) ```yaml spring: profiles: active: dev application: name: sensor-spring-app datasource: url: jdbc:postgresql://localhost:5432/sensor_db username: postgres password: password driver-class-name: org.postgresql.Driver jpa: hibernate: ddl-auto: validate show-sql: false properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect format_sql: true redis: host: localhost port: 6379 timeout: 2000ms lettuce: pool: max-active: 8 max-idle: 8 min-idle: 0 thymeleaf: cache: false prefix: classpath:/templates/ suffix: .html encoding: UTF-8 mode: HTML server: port: 8080 servlet: context-path: / management: endpoints: web: exposure: include: health,info,metrics,prometheus endpoint: health: show-details: always logging: level: com.sensor.spring: DEBUG org.springframework.web: DEBUG org.hibernate.SQL: DEBUG org.hibernate.type.descriptor.sql.BasicBinder: TRACE ``` ### 2. application-dev.yml (개발 환경) ```yaml spring: jpa: show-sql: true hibernate: ddl-auto: create-drop h2: console: enabled: true logging: level: com.sensor.spring: DEBUG org.springframework.web: DEBUG ``` ### 3. application-prod.yml (운영 환경) ```yaml spring: jpa: show-sql: false hibernate: ddl-auto: validate logging: level: com.sensor.spring: INFO org.springframework.web: WARN ``` --- ## 🗄️ 데이터 모델 ### 1. JPA 엔티티 #### **SensorReading.java** ```java package com.sensor.spring.entity; import lombok.*; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import javax.persistence.*; import javax.validation.constraints.NotNull; import java.time.LocalDateTime; @Entity @Table(name = "sensor_readings") @EntityListeners(AuditingEntityListener.class) @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder public class SensorReading { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotNull @Column(name = "device_id", nullable = false) private String deviceId; @Column(name = "node_id") private Integer nodeId; @Column(name = "temperature", precision = 5, scale = 2) private Double temperature; @Column(name = "humidity", precision = 5, scale = 2) private Double humidity; @Column(name = "longitude", precision = 10, scale = 6) private Double longitude; @Column(name = "latitude", precision = 10, scale = 6) private Double latitude; @Column(name = "recorded_time") private LocalDateTime recordedTime; @Column(name = "received_time") private LocalDateTime receivedTime; @CreatedDate @Column(name = "created_at", nullable = false, updatable = false) private LocalDateTime createdAt; @PrePersist protected void onCreate() { if (receivedTime == null) { receivedTime = LocalDateTime.now(); } } } ``` #### **Device.java** ```java package com.sensor.spring.entity; import lombok.*; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import javax.persistence.*; import javax.validation.constraints.NotNull; import java.time.LocalDateTime; @Entity @Table(name = "devices") @EntityListeners(AuditingEntityListener.class) @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder public class Device { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotNull @Column(name = "device_id", unique = true, nullable = false) private String deviceId; @Column(name = "name") private String name; @Column(name = "description") private String description; @Enumerated(EnumType.STRING) @Column(name = "status") private DeviceStatus status; @Column(name = "last_seen") private LocalDateTime lastSeen; @CreatedDate @Column(name = "created_at", nullable = false, updatable = false) private LocalDateTime createdAt; @LastModifiedDate @Column(name = "updated_at", nullable = false) private LocalDateTime updatedAt; public enum DeviceStatus { ACTIVE, INACTIVE, ERROR, MAINTENANCE } } ``` --- **계속...**