From e82709cc66d8498c5ef968660672d7b114c5eb52 Mon Sep 17 00:00:00 2001 From: gudae01 Date: Wed, 5 Nov 2025 13:47:42 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 12 +- identifier.sqlite | 0 .../MobidigimProjectApplication.java | 7 + .../config/corsconfig/CorsConfig.java | 18 ++ .../objectmapper/ObjectMapperConfig.java | 10 +- .../config/swagger/SwaggerConfig.java | 15 - .../controller/Controller.java | 12 +- .../mobidigimproject/domain/BoardConfig.java | 23 ++ .../mobidigimproject/domain/EventHistory.java | 23 ++ .../model/device/DeviceDTO.java | 3 + .../model/device/enums/Rs485Parity.java | 19 ++ .../model/device/subDTO/Log.java | 18 ++ .../model/device/subDTO/Rs485.java | 11 +- .../model/device/subDTO/Server.java | 2 + .../model/device/subDTO/WifiSSIDS.java | 4 +- .../model/register/MeidDeserializer.java | 16 + .../model/register/RegisterDTO.java | 25 +- .../model/register/enums/DeviceType.java | 4 +- .../model/register/enums/FourByte.java | 14 + .../model/register/enums/OutputDataType.java | 18 ++ .../model/register/enums/Protocol.java | 9 + .../model/register/enums/TwoByte.java | 11 + .../repository/BoardConfigRepository.java | 8 + .../repository/EventHistoryRepository.java | 7 + .../service/SettingService.java | 190 +++++------- .../sqlite/SQLiteDialect.java | 27 ++ .../sqlite/SQLiteIdentityColumnSupport.java | 9 + src/main/resources/application.yaml | 20 ++ src/main/resources/static/index.html | 274 ++++++++++++------ 29 files changed, 557 insertions(+), 252 deletions(-) create mode 100644 identifier.sqlite create mode 100644 src/main/java/org/mobidgim/mobidigimproject/config/corsconfig/CorsConfig.java delete mode 100644 src/main/java/org/mobidgim/mobidigimproject/config/swagger/SwaggerConfig.java create mode 100644 src/main/java/org/mobidgim/mobidigimproject/domain/BoardConfig.java create mode 100644 src/main/java/org/mobidgim/mobidigimproject/domain/EventHistory.java create mode 100644 src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Log.java create mode 100644 src/main/java/org/mobidgim/mobidigimproject/model/register/MeidDeserializer.java create mode 100644 src/main/java/org/mobidgim/mobidigimproject/repository/BoardConfigRepository.java create mode 100644 src/main/java/org/mobidgim/mobidigimproject/repository/EventHistoryRepository.java create mode 100644 src/main/java/org/mobidgim/mobidigimproject/sqlite/SQLiteDialect.java create mode 100644 src/main/java/org/mobidgim/mobidigimproject/sqlite/SQLiteIdentityColumnSupport.java diff --git a/build.gradle b/build.gradle index 30779b7..be7feef 100644 --- a/build.gradle +++ b/build.gradle @@ -26,12 +26,14 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' - compileOnly 'org.projectlombok:lombok:1.18.30' - annotationProcessor 'org.projectlombok:lombok:1.18.30' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + + implementation 'org.xerial:sqlite-jdbc:3.45.3.0' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' -// implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.3' } diff --git a/identifier.sqlite b/identifier.sqlite new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/org/mobidgim/mobidigimproject/MobidigimProjectApplication.java b/src/main/java/org/mobidgim/mobidigimproject/MobidigimProjectApplication.java index 066aed8..77243e4 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/MobidigimProjectApplication.java +++ b/src/main/java/org/mobidgim/mobidigimproject/MobidigimProjectApplication.java @@ -2,8 +2,15 @@ package org.mobidgim.mobidigimproject; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; @SpringBootApplication +// (exclude = { +// DataSourceAutoConfiguration.class, +// HibernateJpaAutoConfiguration.class +//}) + public class MobidigimProjectApplication { public static void main(String[] args) { diff --git a/src/main/java/org/mobidgim/mobidigimproject/config/corsconfig/CorsConfig.java b/src/main/java/org/mobidgim/mobidigimproject/config/corsconfig/CorsConfig.java new file mode 100644 index 0000000..36264b5 --- /dev/null +++ b/src/main/java/org/mobidgim/mobidigimproject/config/corsconfig/CorsConfig.java @@ -0,0 +1,18 @@ +package org.mobidgim.mobidigimproject.config.corsconfig; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class CorsConfig implements WebMvcConfigurer { + @Override + public void addCorsMappings(CorsRegistry reg) { + reg.addMapping("/**") // 모든 경로 + .allowedOriginPatterns("*") // 모든 오리진 허용(패턴) + .allowedMethods("*") // 모든 메서드 + .allowedHeaders("*") // 모든 헤더 + .allowCredentials(true) // 쿠키/세션 허용 + .maxAge(3600); + } +} diff --git a/src/main/java/org/mobidgim/mobidigimproject/config/objectmapper/ObjectMapperConfig.java b/src/main/java/org/mobidgim/mobidigimproject/config/objectmapper/ObjectMapperConfig.java index 7479f50..eea5632 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/config/objectmapper/ObjectMapperConfig.java +++ b/src/main/java/org/mobidgim/mobidigimproject/config/objectmapper/ObjectMapperConfig.java @@ -1,9 +1,6 @@ package org.mobidgim.mobidigimproject.config.objectmapper; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.context.annotation.Bean; @@ -21,7 +18,10 @@ public class ObjectMapperConfig { objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false); objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); -// objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.SnakeCaseStrategy()); + objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.SnakeCaseStrategy()); + + objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true); + return objectMapper; } diff --git a/src/main/java/org/mobidgim/mobidigimproject/config/swagger/SwaggerConfig.java b/src/main/java/org/mobidgim/mobidigimproject/config/swagger/SwaggerConfig.java deleted file mode 100644 index dd5dd15..0000000 --- a/src/main/java/org/mobidgim/mobidigimproject/config/swagger/SwaggerConfig.java +++ /dev/null @@ -1,15 +0,0 @@ -//package org.mobidgim.mobidigimproject.config.swagger; -// -//import com.fasterxml.jackson.databind.ObjectMapper; -//import io.swagger.v3.core.jackson.ModelResolver; -//import org.springframework.context.annotation.Bean; -//import org.springframework.context.annotation.Configuration; -// -//@Configuration -//public class SwaggerConfig { -// @Bean -// public ModelResolver modelResolver(ObjectMapper objectMapper) { -// return new ModelResolver(objectMapper); -// } -//} -// diff --git a/src/main/java/org/mobidgim/mobidigimproject/controller/Controller.java b/src/main/java/org/mobidgim/mobidigimproject/controller/Controller.java index f6700df..73aeedc 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/controller/Controller.java +++ b/src/main/java/org/mobidgim/mobidigimproject/controller/Controller.java @@ -39,8 +39,10 @@ public class Controller { @GetMapping("/get-device") public ResponseEntity getDevice() throws IOException { - DeviceDTO entity = settingService.readFileWithDevice(); - return ResponseEntity.ok(entity); + if (!settingService.deviceFileExists()) { // DB에 없음 + return ResponseEntity.noContent().build(); // 204 + } + return ResponseEntity.ok(settingService.readFileWithDevice()); } @PostMapping("/protocol") @@ -51,8 +53,10 @@ public class Controller { @GetMapping("/get-protocol") public ResponseEntity getRegister() throws IOException { - RegisterDTO entity = settingService.readFileWithRegister(); - return ResponseEntity.ok(entity); + if (!settingService.protocolFileExists()) { // DB에 없음 + return ResponseEntity.noContent().build(); // 204 + } + return ResponseEntity.ok(settingService.readFileWithRegister()); } } diff --git a/src/main/java/org/mobidgim/mobidigimproject/domain/BoardConfig.java b/src/main/java/org/mobidgim/mobidigimproject/domain/BoardConfig.java new file mode 100644 index 0000000..d92ecde --- /dev/null +++ b/src/main/java/org/mobidgim/mobidigimproject/domain/BoardConfig.java @@ -0,0 +1,23 @@ +package org.mobidgim.mobidigimproject.domain; + +import javax.persistence.*; + +import lombok.*; + +import java.sql.Timestamp; + +@Entity +@Table(name = "board_config") +@Getter +@Setter +@NoArgsConstructor +public class BoardConfig { + + @Id + @Column(name = "`key`", nullable = false) // key는 예약어 충돌 회피를 위해 백틱 유지 + private String key; + + + @Column(name = "value", columnDefinition = "TEXT", nullable = false) + private String value; +} diff --git a/src/main/java/org/mobidgim/mobidigimproject/domain/EventHistory.java b/src/main/java/org/mobidgim/mobidigimproject/domain/EventHistory.java new file mode 100644 index 0000000..2d4f21f --- /dev/null +++ b/src/main/java/org/mobidgim/mobidigimproject/domain/EventHistory.java @@ -0,0 +1,23 @@ +package org.mobidgim.mobidigimproject.domain; + +import javax.persistence.*; +import lombok.Getter; +import lombok.Setter; +import java.sql.Timestamp; + +@Entity +@Table(name = "event_history") +@Getter @Setter +public class EventHistory { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + + @Column(name = "data", columnDefinition = "TEXT", nullable = false) + private String data; + + @Column(name = "created_at", insertable = false, updatable = false) + private Timestamp createdAt; +} diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/device/DeviceDTO.java b/src/main/java/org/mobidgim/mobidigimproject/model/device/DeviceDTO.java index c0833e0..d65d66e 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/model/device/DeviceDTO.java +++ b/src/main/java/org/mobidgim/mobidigimproject/model/device/DeviceDTO.java @@ -36,6 +36,9 @@ public class DeviceDTO { @JsonUnwrapped private Lte lteConfig; + @JsonUnwrapped + private Log logConfig; + @JsonProperty("WIFI_SSID") private List wifiSsid; } \ No newline at end of file diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/device/enums/Rs485Parity.java b/src/main/java/org/mobidgim/mobidigimproject/model/device/enums/Rs485Parity.java index 0d5c876..94d320a 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/model/device/enums/Rs485Parity.java +++ b/src/main/java/org/mobidgim/mobidigimproject/model/device/enums/Rs485Parity.java @@ -1,5 +1,6 @@ package org.mobidgim.mobidigimproject.model.device.enums; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import lombok.AllArgsConstructor; @@ -14,4 +15,22 @@ public enum Rs485Parity { public String getValue() { return value; } + + @JsonCreator + public static Rs485Parity from(String raw) { // 역직렬화 시: 문자열 받아 enum으로 + if (raw == null) return null; + String v = raw.trim().toLowerCase(); + switch (v) { + case "no": + case "none": + case "n": + return NONE; + case "even": + return EVEN; + case "odd": + return ODD; + default: + throw new IllegalArgumentException("Unknown parity: " + raw); + } + } } diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Log.java b/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Log.java new file mode 100644 index 0000000..f5abba1 --- /dev/null +++ b/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Log.java @@ -0,0 +1,18 @@ +package org.mobidgim.mobidigimproject.model.device.subDTO; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Log { + @JsonProperty("log_save") + private String logSave; + @JsonProperty("log_max_size") + private Integer logMaxSize; + @JsonProperty("log_max_duration") + private Integer logMaxDuration; +} \ No newline at end of file diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Rs485.java b/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Rs485.java index d730030..2d06ff8 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Rs485.java +++ b/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Rs485.java @@ -1,12 +1,17 @@ package org.mobidgim.mobidigimproject.model.device.subDTO; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import lombok.Setter; import org.mobidgim.mobidigimproject.model.device.enums.Rs485Parity; import org.mobidgim.mobidigimproject.model.device.enums.Rs485Baudrate; import org.mobidgim.mobidigimproject.model.device.enums.Rs485Mode; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; + @Getter @Setter @JsonInclude(JsonInclude.Include.NON_NULL) @@ -16,9 +21,11 @@ public class Rs485 { private Rs485Baudrate rs485Baudrate; - private Integer rs485DataBits; + private Integer rs485Databits; + @Enumerated(EnumType.STRING) + @JsonProperty("rs485_parity") private Rs485Parity rs485Parity; - private Integer rs485StopBits; + private Integer rs485Stopbits; } diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Server.java b/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Server.java index 3ea4c74..faa72e0 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Server.java +++ b/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Server.java @@ -17,4 +17,6 @@ public class Server { private Integer opcUaServerPort; private String modbusServerIp; private Integer modbusServerPort; + private String lteServerIp; + private Integer lteServerPort; } diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/WifiSSIDS.java b/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/WifiSSIDS.java index 5e81ce0..a89126a 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/WifiSSIDS.java +++ b/src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/WifiSSIDS.java @@ -13,8 +13,8 @@ public class WifiSSIDS { @JsonProperty("wifi_ssid") private String wifiSsid; - @JsonProperty("wifi_password") - private String wifiPassword; + @JsonProperty("wifi_passwd") + private String wifiPasswd; private WiFiSecurity wifiSecurity; } diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/register/MeidDeserializer.java b/src/main/java/org/mobidgim/mobidigimproject/model/register/MeidDeserializer.java new file mode 100644 index 0000000..0c41920 --- /dev/null +++ b/src/main/java/org/mobidgim/mobidigimproject/model/register/MeidDeserializer.java @@ -0,0 +1,16 @@ +package org.mobidgim.mobidigimproject.model.register; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; + +import java.io.IOException; + +public class MeidDeserializer extends JsonDeserializer { + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + JsonNode node = p.getCodec().readTree(p); + return node.asText(); // 숫자든 문자열이든 "문자열"로 강제 + } +} diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/register/RegisterDTO.java b/src/main/java/org/mobidgim/mobidigimproject/model/register/RegisterDTO.java index cf3c353..946fc2b 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/model/register/RegisterDTO.java +++ b/src/main/java/org/mobidgim/mobidigimproject/model/register/RegisterDTO.java @@ -1,8 +1,10 @@ package org.mobidgim.mobidigimproject.model.register; +import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import lombok.Getter; import lombok.Setter; import org.mobidgim.mobidigimproject.model.register.enums.*; @@ -36,38 +38,51 @@ public class RegisterDTO { private AnalogPort di3; + @JsonProperty("can_input") private CanInput canInput; - private DeviceType deviceType; + @JsonProperty("dev_type") + private DeviceType devType; + @JsonProperty("dr_on") private DR drOn; private Equipment equipment; - private TwoByte twoByte; + @JsonProperty("two_byte_order") + private TwoByte twoByteOrder; - private FourByte fourByte; + @JsonProperty("four_byte_order") + private FourByte fourByteOrder; private Protocol protocol; - private SpeedDataSource speedDataSource; + @JsonProperty("speed_data") + private SpeedDataSource speedData; private String version; + @JsonProperty("equipment_id") private String equipmentId; + @JsonProperty("MEID") + @JsonDeserialize(using = MeidDeserializer.class) private String meid; + @JsonProperty("heading_on") private HeadingOn headingOn; + @JsonProperty("heading_imu_on") private HeadingImuOn headingImuOn; - private FixmodeOn fixmodeOn; + @JsonProperty("fix_mode_on") + private FixmodeOn fixModeOn; @JsonProperty("MODBUS") private List MODBUS; @JsonProperty("OPC_UA") + @JsonAlias({"OPC_UA","OPC-UA"}) private List OPC_UA; @JsonProperty("CAN") diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/DeviceType.java b/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/DeviceType.java index f12eb56..887f26c 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/DeviceType.java +++ b/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/DeviceType.java @@ -7,11 +7,11 @@ import lombok.AllArgsConstructor; public enum DeviceType { TIOT("TIOT"), RTLS("RTLS"); - private final String Device; + private final String Dev; @JsonValue public String getType() { - return Device; + return Dev; } } \ No newline at end of file diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/FourByte.java b/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/FourByte.java index b184860..9513e3e 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/FourByte.java +++ b/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/FourByte.java @@ -1,5 +1,6 @@ package org.mobidgim.mobidigimproject.model.register.enums; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import lombok.AllArgsConstructor; @@ -15,4 +16,17 @@ public enum FourByte { public String getFourByte() { return fourByte; } + + @JsonCreator + public static FourByte from(String v) { + if (v == null) return null; + String x = v.trim().toLowerCase().replace("_","").replace("-",""); + switch (x) { + case "little": return LITTLE; + case "littleswap": return LITTLE_SWAP; + case "bigswap": return BIG_SWAP; + case "big": return BIG; + default: throw new IllegalArgumentException("Unknown FourByte: " + v); + } + } } diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/OutputDataType.java b/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/OutputDataType.java index 2ac6e8d..8b29393 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/OutputDataType.java +++ b/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/OutputDataType.java @@ -1,5 +1,6 @@ package org.mobidgim.mobidigimproject.model.register.enums; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import lombok.AllArgsConstructor; @@ -15,4 +16,21 @@ public enum OutputDataType { public String getOdt() { return odt; } + + @JsonCreator + public static OutputDataType from(String v){ + if (v==null) return null; + String x = v.trim().toLowerCase(); + switch (x){ + case "integer": return integer; + case "float64": + case "float": + case "double": return float64; + case "boolean": + case "bool": return bool; + case "string": + case "str": return String; + default: throw new IllegalArgumentException("Unknown OutputDataType: " + v); + } + } } diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/Protocol.java b/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/Protocol.java index fec2027..d03d5ce 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/Protocol.java +++ b/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/Protocol.java @@ -1,5 +1,6 @@ package org.mobidgim.mobidigimproject.model.register.enums; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import lombok.AllArgsConstructor; @@ -15,4 +16,12 @@ public enum Protocol { public String getProtocol() { return protocol; } + + @JsonCreator + public static Protocol from(String v) { + if (v == null) return null; + return Protocol.valueOf( + v.trim().toUpperCase().replace('-', '_').replace(' ', '_') + ); + } } diff --git a/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/TwoByte.java b/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/TwoByte.java index 6651d43..2a3e027 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/TwoByte.java +++ b/src/main/java/org/mobidgim/mobidigimproject/model/register/enums/TwoByte.java @@ -1,5 +1,6 @@ package org.mobidgim.mobidigimproject.model.register.enums; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import lombok.AllArgsConstructor; @@ -13,4 +14,14 @@ public enum TwoByte { public String getTwoByte() { return twoByte; } + + @JsonCreator + public static TwoByte from(String v) { + if (v == null) return null; + switch (v.trim().toLowerCase()) { + case "little": return LITTLE; + case "big": return BIG; + default: throw new IllegalArgumentException("Unknown TwoByte: " + v); + } + } } diff --git a/src/main/java/org/mobidgim/mobidigimproject/repository/BoardConfigRepository.java b/src/main/java/org/mobidgim/mobidigimproject/repository/BoardConfigRepository.java new file mode 100644 index 0000000..4486337 --- /dev/null +++ b/src/main/java/org/mobidgim/mobidigimproject/repository/BoardConfigRepository.java @@ -0,0 +1,8 @@ +package org.mobidgim.mobidigimproject.repository; + +import org.mobidgim.mobidigimproject.domain.BoardConfig; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface BoardConfigRepository extends JpaRepository { + +} diff --git a/src/main/java/org/mobidgim/mobidigimproject/repository/EventHistoryRepository.java b/src/main/java/org/mobidgim/mobidigimproject/repository/EventHistoryRepository.java new file mode 100644 index 0000000..8870813 --- /dev/null +++ b/src/main/java/org/mobidgim/mobidigimproject/repository/EventHistoryRepository.java @@ -0,0 +1,7 @@ +package org.mobidgim.mobidigimproject.repository; + +import org.mobidgim.mobidigimproject.domain.EventHistory; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface EventHistoryRepository extends JpaRepository { +} diff --git a/src/main/java/org/mobidgim/mobidigimproject/service/SettingService.java b/src/main/java/org/mobidgim/mobidigimproject/service/SettingService.java index edd2a09..c8a8994 100644 --- a/src/main/java/org/mobidgim/mobidigimproject/service/SettingService.java +++ b/src/main/java/org/mobidgim/mobidigimproject/service/SettingService.java @@ -1,193 +1,145 @@ package org.mobidgim.mobidigimproject.service; -import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import lombok.RequiredArgsConstructor; +import org.mobidgim.mobidigimproject.domain.BoardConfig; import org.mobidgim.mobidigimproject.model.device.DeviceDTO; import org.mobidgim.mobidigimproject.model.register.RegisterDTO; import org.mobidgim.mobidigimproject.model.register.enums.CanInput; import org.mobidgim.mobidigimproject.model.register.enums.Protocol; -import org.mobidgim.mobidigimproject.model.register.sebDTO.CanField; -import org.mobidgim.mobidigimproject.model.register.sebDTO.ModbusField; -import org.mobidgim.mobidigimproject.model.register.sebDTO.OpcUaField; -import org.springframework.beans.factory.annotation.Autowired; +import org.mobidgim.mobidigimproject.repository.BoardConfigRepository; import org.springframework.stereotype.Service; -import javax.swing.text.html.parser.Parser; -import java.io.File; +import javax.annotation.PostConstruct; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.Path; -import java.util.Arrays; +import java.util.Collections; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; @Service +@RequiredArgsConstructor public class SettingService { + private final BoardConfigRepository boardConfigRepository; private final ObjectMapper mapper; + private static final String DEFAULT_DEVICE_FILENAME = "deviceConfig.json"; private static final String DEFAULT_PROTOCOL_FILENAME = "protocolConfig.json"; - private static final String TEMP_DIRECTORY = System.getProperty("user.home") + "/config"; + private static final String KEY_DEVICE = "device_config"; + private static final String KEY_PROTOCOL = "protocol_config"; - @Autowired - public SettingService(ObjectMapper mapper) { - this.mapper = mapper; - this.mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); + @PostConstruct + void initMapper() { + mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } - // 디렉토리 생성 메서드 - private void ensureDirectoryExists() throws IOException { - Path dirPath = Paths.get(TEMP_DIRECTORY); - if (!Files.exists(dirPath)) { - Files.createDirectory(dirPath); - } - } + /* ===================== Device ===================== */ - // Device 파일 저장 (기본 파일명 사용) public void saveFileWithDevice(DeviceDTO request) throws IOException { saveFileWithDevice(request, DEFAULT_DEVICE_FILENAME); } - // Device 파일 저장 (사용자 지정 파일명) public void saveFileWithDevice(DeviceDTO request, String filename) throws IOException { - mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); - String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(request); - - ensureDirectoryExists(); - - String filePath = TEMP_DIRECTORY + "/" + filename; - Files.write(Paths.get(filePath), json.getBytes(StandardCharsets.UTF_8)); + try { + String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(request); + BoardConfig row = new BoardConfig(); + row.setKey(KEY_DEVICE); + row.setValue(json); + boardConfigRepository.save(row); // upsert (PK=`key`) + } catch (Exception e) { + throw new IOException("Failed to save device_config to DB", e); + } } - // Device 파일 읽기 (기본 파일명 사용) public DeviceDTO readFileWithDevice() throws IOException { return readFileWithDevice(DEFAULT_DEVICE_FILENAME); } - // Device 파일 읽기 (사용자 지정 파일명) public DeviceDTO readFileWithDevice(String filename) throws IOException { - String filePath = TEMP_DIRECTORY + "/" + filename; - Path path = Paths.get(filePath); - - if (!Files.exists(path)) { - throw new IOException("Device configuration file not found: " + filename); + try { + return boardConfigRepository.findById(KEY_DEVICE) + .map(bc -> { + try { return mapper.readValue(bc.getValue(), DeviceDTO.class); } + catch (Exception ex) { throw new RuntimeException(ex); } + }) + .orElseGet(DeviceDTO::new); // 없으면 빈 객체 + } catch (RuntimeException re) { + Throwable cause = (re.getCause() != null ? re.getCause() : re); + throw new IOException("Failed to read device_config from DB", cause); } - - String jsonString = new String(Files.readAllBytes(path), StandardCharsets.UTF_8); - ObjectMapper mapper = new ObjectMapper(); - mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - return mapper.readValue(jsonString, DeviceDTO.class); } - // Device 파일 존재 여부 확인 public boolean deviceFileExists() { return deviceFileExists(DEFAULT_DEVICE_FILENAME); } public boolean deviceFileExists(String filename) { - String filePath = TEMP_DIRECTORY + "/" + filename; - return Files.exists(Paths.get(filePath)); + return boardConfigRepository.existsById(KEY_DEVICE); } - // Protocol 파일 저장 (기본 파일명 사용) + /* ===================== Protocol ===================== */ + public RegisterDTO saveFileWithRegister(RegisterDTO request) throws IOException { return saveFileWithRegister(request, DEFAULT_PROTOCOL_FILENAME); } - // Protocol 파일 저장 (사용자 지정 파일명) public RegisterDTO saveFileWithRegister(RegisterDTO request, String filename) throws IOException { - // 프로토콜에 따른 데이터 정리 - if (request.getProtocol() != Protocol.OPC_UA) { - request.setOPC_UA(null); + // 기존 정리 로직 유지 + if (request.getProtocol() != Protocol.OPC_UA) request.setOPC_UA(null); + if (request.getProtocol() != Protocol.MODBUS) request.setMODBUS(null); + if (request.getCanInput() != CanInput.ON) request.setCAN(null); + + try { + String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(request); + BoardConfig row = new BoardConfig(); + row.setKey(KEY_PROTOCOL); + row.setValue(json); + boardConfigRepository.save(row); + return request; + } catch (Exception e) { + throw new IOException("Failed to save protocol_config to DB", e); } - - if (request.getProtocol() != Protocol.MODBUS) { - request.setMODBUS(null); - } - - if (request.getCanInput() != CanInput.ON) { - request.setCAN(null); - } - - String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(request); - - ensureDirectoryExists(); - - String filePath = TEMP_DIRECTORY + "/" + filename; - Path path = Paths.get(filePath); - Files.write(path, json.getBytes(StandardCharsets.UTF_8)); - - return request; } - // Protocol 파일 읽기 (기본 파일명 사용) public RegisterDTO readFileWithRegister() throws IOException { return readFileWithRegister(DEFAULT_PROTOCOL_FILENAME); } - // Protocol 파일 읽기 (사용자 지정 파일명) public RegisterDTO readFileWithRegister(String filename) throws IOException { - String filePath = TEMP_DIRECTORY + "/" + filename; - Path path = Paths.get(filePath); - - if (!Files.exists(path)) { - throw new IOException("Protocol configuration file not found: " + filename); + try { + return boardConfigRepository.findById(KEY_PROTOCOL) + .map(bc -> { + try { return mapper.readValue(bc.getValue(), RegisterDTO.class); } + catch (Exception ex) { throw new RuntimeException(ex); } + }) + .orElseGet(RegisterDTO::new); + } catch (RuntimeException re) { + Throwable cause = (re.getCause() != null ? re.getCause() : re); + throw new IOException("Failed to read protocol_config from DB", cause); } - - String jsonString = new String(Files.readAllBytes(path), StandardCharsets.UTF_8); - ObjectMapper mapper = new ObjectMapper(); - mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - RegisterDTO registerDTO = mapper.readValue(jsonString, RegisterDTO.class); - return registerDTO; } - // Protocol 파일 존재 여부 확인 public boolean protocolFileExists() { return protocolFileExists(DEFAULT_PROTOCOL_FILENAME); } public boolean protocolFileExists(String filename) { - String filePath = TEMP_DIRECTORY + "/" + filename; - return Files.exists(Paths.get(filePath)); + return boardConfigRepository.existsById(KEY_PROTOCOL); } - // temp 디렉토리의 모든 JSON 파일 목록 조회 + /* ===================== 목록 대체 ===================== */ + public List getAvailableDeviceFiles() throws IOException { - return getAvailableFiles("device"); + return boardConfigRepository.existsById(KEY_DEVICE) + ? Collections.singletonList(DEFAULT_DEVICE_FILENAME) + : Collections.emptyList(); } public List getAvailableProtocolFiles() throws IOException { - return getAvailableFiles("protocol"); - } - - private List getAvailableFiles(String type) throws IOException { - ensureDirectoryExists(); - Path dirPath = Paths.get(TEMP_DIRECTORY); - - return Files.list(dirPath) - .filter(path -> path.toString().endsWith(".json")) - .map(path -> path.getFileName().toString()) - .filter(filename -> { - try { - if ("device".equals(type)) { - readFileWithDevice(filename); - return true; - } else if ("protocol".equals(type)) { - readFileWithRegister(filename); - return true; - } - return false; - } catch (Exception e) { - return false; // 파일이 해당 타입에 맞지 않으면 제외 - } - }) - .collect(Collectors.toList()); + return boardConfigRepository.existsById(KEY_PROTOCOL) + ? Collections.singletonList(DEFAULT_PROTOCOL_FILENAME) + : Collections.emptyList(); } -} \ No newline at end of file +} diff --git a/src/main/java/org/mobidgim/mobidigimproject/sqlite/SQLiteDialect.java b/src/main/java/org/mobidgim/mobidigimproject/sqlite/SQLiteDialect.java new file mode 100644 index 0000000..587a645 --- /dev/null +++ b/src/main/java/org/mobidgim/mobidigimproject/sqlite/SQLiteDialect.java @@ -0,0 +1,27 @@ +package org.mobidgim.mobidigimproject.sqlite; + +import java.sql.Types; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.identity.IdentityColumnSupport; +import org.hibernate.type.StandardBasicTypes; +import org.hibernate.dialect.function.*; + +public class SQLiteDialect extends Dialect { + public SQLiteDialect() { + registerColumnType(Types.INTEGER, "integer"); + registerColumnType(Types.BIGINT, "bigint"); + registerColumnType(Types.VARCHAR, "varchar"); + registerColumnType(Types.LONGVARCHAR, "longvarchar"); + registerColumnType(Types.BOOLEAN, "boolean"); + registerColumnType(Types.BLOB, "blob"); + registerColumnType(Types.CLOB, "text"); + registerColumnType(Types.TIMESTAMP, "datetime"); + + registerFunction("concat", new VarArgsSQLFunction(StandardBasicTypes.STRING, "", "||", "")); + registerFunction("substr", new StandardSQLFunction("substr", StandardBasicTypes.STRING)); + registerFunction("substring", new StandardSQLFunction("substr", StandardBasicTypes.STRING)); + registerFunction("mod", new SQLFunctionTemplate(StandardBasicTypes.INTEGER, "?1 % ?2")); + } + + @Override public IdentityColumnSupport getIdentityColumnSupport() { return new SQLiteIdentityColumnSupport(); } +} diff --git a/src/main/java/org/mobidgim/mobidigimproject/sqlite/SQLiteIdentityColumnSupport.java b/src/main/java/org/mobidgim/mobidigimproject/sqlite/SQLiteIdentityColumnSupport.java new file mode 100644 index 0000000..9d70f59 --- /dev/null +++ b/src/main/java/org/mobidgim/mobidigimproject/sqlite/SQLiteIdentityColumnSupport.java @@ -0,0 +1,9 @@ +package org.mobidgim.mobidigimproject.sqlite; + +import org.hibernate.dialect.identity.IdentityColumnSupportImpl; + +public class SQLiteIdentityColumnSupport extends IdentityColumnSupportImpl { + @Override public boolean supportsIdentityColumns() { return true; } + @Override public String getIdentityColumnString(int type) { return "integer"; } + @Override public boolean hasDataTypeInIdentityColumn() { return false; } +} \ No newline at end of file diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index e69de29..291b6fd 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -0,0 +1,20 @@ +spring: + datasource: + url: "jdbc:sqlite:${user.home}/db/dynamic_data.db?busy_timeout=5000" + driver-class-name: "org.sqlite.JDBC" + hikari: + maximum-pool-size: 1 + # username/password 필요 없음 + + jpa: + hibernate: + ddl-auto: none # 초기엔 update, 이후 none 권장 + properties: + hibernate: + format_sql: true + # 커스텀 SQLite Dialect 경로 (아래 3번) + database-platform: "org.mobidgim.mobidigimproject.sqlite.SQLiteDialect" + +server: + port: 8080 + diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index f4a835a..d638b2e 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -16,6 +16,7 @@ +