Browse Source

load local file 버튼 로직 수정

v2
gudae01 1 year ago
parent
commit
76392631f2
  1. 141
      src/main/java/org/mobidgim/mobidigimproject/service/SettingService.java
  2. 186
      src/main/resources/static/index.html

141
src/main/java/org/mobidgim/mobidigimproject/service/SettingService.java

@ -1,7 +1,6 @@
package org.mobidgim.mobidigimproject.service;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
@ -9,51 +8,100 @@ 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.springframework.stereotype.Service;
import javax.swing.text.html.parser.Parser;
import java.io.File;
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.List;
import java.util.Map;
@Service
public class SettingService {
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 = "./temp";
@Autowired
public SettingService(ObjectMapper mapper) {
this.mapper = mapper;
this.mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
}
// 디렉토리 생성 메서드
private void ensureDirectoryExists() throws IOException {
Path dirPath = Paths.get(TEMP_DIRECTORY);
if (!Files.exists(dirPath)) {
Files.createDirectory(dirPath);
}
}
// 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);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(request);
String directoryPath = "./temp";
Path dirPath = Paths.get(directoryPath);
ensureDirectoryExists();
if(!Files.exists(dirPath)){
Files.createDirectory(dirPath);
String filePath = TEMP_DIRECTORY + "/" + filename;
Files.writeString(Paths.get(filePath), json);
}
String filename = "./temp/deviceConfig.json";
Files.writeString(Paths.get(filename), json);
// Device 파일 읽기 (기본 파일명 사용)
public DeviceDTO readFileWithDevice() throws IOException {
return readFileWithDevice(DEFAULT_DEVICE_FILENAME);
}
public DeviceDTO readFileWithDevice() throws IOException {
// 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);
}
String jsonString = Files.readString(path);
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
return mapper.readValue(new File("./temp/deviceConfig.json"), DeviceDTO.class);
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));
}
// 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);
}
@ -66,26 +114,31 @@ public class SettingService {
request.setCAN(null);
}
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(request);
String directoryPath = "./temp";
Path dirPath = Paths.get(directoryPath);
ensureDirectoryExists();
if(!Files.exists(dirPath)){
Files.createDirectory(dirPath);
}
String filename = "./temp/protocolConfig.json";
Files.writeString(Paths.get(filename), json);
String filePath = TEMP_DIRECTORY + "/" + filename;
Files.writeString(Paths.get(filePath), json);
return request;
}
// Protocol 파일 읽기 (기본 파일명 사용)
public RegisterDTO readFileWithRegister() throws IOException {
String filename = "./temp/protocolConfig.json";
Path filePath = Paths.get(filename);
String jsonString = Files.readString(filePath);
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);
}
String jsonString = Files.readString(path);
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
@ -93,4 +146,46 @@ public class SettingService {
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));
}
// temp 디렉토리의 모든 JSON 파일 목록 조회
public List<String> getAvailableDeviceFiles() throws IOException {
return getAvailableFiles("device");
}
public List<String> getAvailableProtocolFiles() throws IOException {
return getAvailableFiles("protocol");
}
private List<String> 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; // 파일이 해당 타입에 맞지 않으면 제외
}
})
.toList();
}
}

186
src/main/resources/static/index.html

@ -55,6 +55,7 @@
<div id="ssid-list"></div>
<button id="add-ssid" class="icon-button" title="add SSID"></button>
<button id="delete-ssid" class="icon-button" title="delete SSID"></button>
</div>
<div class="actions">
<div class="file-upload-wrapper-device"
@ -772,13 +773,6 @@
const selectedDeviceFile = event.target.files[0];
const DeviceFileName = selectedDeviceFile.name;
// 파일명 검증 (data-expected-filename 사용)
if (DeviceFileName !== expectedDeviceFileName){
alert(`Invalid file.'${expectedDeviceFileName}' Please select a file. Current file: ${DeviceFileName} `);
uploadDeviceFileInput.value = ''; // 잘못된 파일 선택 시 input 초기화
return;
}
const reader = new FileReader();
reader.onload = async (e) => {
@ -885,13 +879,6 @@
return;
}
// 파일명 검증 (data-expected-filename 사용)
if (fileName !== expectedFileName){
alert(`Invalid file. '${expectedFileName}' Please select a file. Current file: ${fileName} `);
uploadFileInput.value = ''; // 잘못된 파일 선택 시 input 초기화
return;
}
reader.onload = async (e) => {
try {
const fileContent = e.target.result;
@ -1041,6 +1028,20 @@
const expr = document.getElementById('modbus_expr_input').value;
const mask = document.getElementById('modbus_mask_input').value;
const firstRow = modbusFieldList.querySelector('tr');
// 첫 행이 비어있다면 그 자리에 값을 넣기
if (firstRow && firstRow.querySelector('.field-display').textContent.trim() === '') {
firstRow.querySelector('.field-display').textContent = field;
firstRow.querySelector('.addr-display').textContent = addr;
firstRow.querySelector('.idt-display').textContent = idt;
firstRow.querySelector('.odt-display').textContent = odt;
firstRow.querySelector('.dv-display').textContent = defaultValue;
firstRow.querySelector('.shift-display').textContent = shift;
firstRow.querySelector('.expr-display').textContent = expr;
firstRow.querySelector('.mask-display').textContent = mask;
} else {
// 새로운 행을 추가
const newRow = modbusRowTemplate.content.cloneNode(true);
newRow.querySelector('.field-display').textContent = field;
newRow.querySelector('.addr-display').textContent = addr;
@ -1052,7 +1053,9 @@
newRow.querySelector('.mask-display').textContent = mask;
modbusFieldList.appendChild(newRow);
}
// 입력 필드 초기화
document.getElementById('modbus_field_input').value = '';
document.getElementById('modbus_addr_input').value = '';
document.getElementById('modbus_idt_input').value = '';
@ -1095,6 +1098,20 @@
const expr = document.getElementById('opcua_expr_input').value;
const mask = document.getElementById('opcua_mask_input').value;
const firstRow = opcUaFieldList.querySelector('tr');
// 첫 행이 비어있다면 그 자리에 값을 넣기
if (firstRow && firstRow.querySelector('.opcua-field-display').textContent.trim() === '') {
firstRow.querySelector('.opcua-field-display').textContent = field;
firstRow.querySelector('.opcua-addr-display').textContent = addr;
firstRow.querySelector('.opcua-ns-display').textContent = ns;
firstRow.querySelector('.opcua-odt-display').textContent = odt;
firstRow.querySelector('.opcua-dv-display').textContent = defaultValue;
firstRow.querySelector('.opcua-shift-display').textContent = shift;
firstRow.querySelector('.opcua-expr-display').textContent = expr;
firstRow.querySelector('.opcua-mask-display').textContent = mask;
} else {
// 새로운 행을 추가
const newRow = opcUaRowTemplate.content.cloneNode(true);
newRow.querySelector('.opcua-field-display').textContent = field;
newRow.querySelector('.opcua-addr-display').textContent = addr;
@ -1106,18 +1123,21 @@
newRow.querySelector('.opcua-mask-display').textContent = mask;
opcUaFieldList.appendChild(newRow);
}
document.getElementById('opcua_field_input').value = '';
document.getElementById('opcua_addr_input').value = '';
document.getElementById('opcua_ns_input').value = '';
document.getElementById('opcua_odt_input').value = '';
document.getElementById('opcua_dv_input').value = '';
document.getElementById('opcua_shift_input').value = '';
document.getElementById('opcua_expr_input').value = '';
document.getElementById('opcua_mask_input').value = '';
// 입력 필드 초기화
document.getElementById('modbus_field_input').value = '';
document.getElementById('modbus_addr_input').value = '';
document.getElementById('modbus_idt_input').value = '';
document.getElementById('modbus_odt_input').value = '';
document.getElementById('modbus_dv_input').value = '';
document.getElementById('modbus_shift_input').value = '';
document.getElementById('modbus_expr_input').value = '';
document.getElementById('modbus_mask_input').value = '';
});
document.getElementById('opcua_modify_btn').onclick = function () {
if (!selectedRow) return alert('Please select the row you want to modify');
selectedRow.querySelector('.opcua-field-display').textContent = document.getElementById('opcua_field_input').value;
@ -1437,6 +1457,65 @@
URL.revokeObjectURL(url);
}
/*-----------------------------------------------------*/
// localStorage 자동 저장 (Device)
function autoSaveToLocal() {
const data = collectDeviceData();
localStorage.setItem('deviceConfigAutoSave', JSON.stringify(data));
}
// localStorage 자동 저장 (Protocol)
function autoSaveProtocolToLocal() {
const config = collectProtocolData();
localStorage.setItem('protocolConfigAutoSave', JSON.stringify(config));
}
// localStorage에서 불러오기
function loadFromLocalIfExists() {
const saved = localStorage.getItem('deviceConfigAutoSave');
if (saved) {
try {
loadFromData(JSON.parse(saved));
console.log('localStorage에서 자동 저장된 Device 설정을 불러왔습니다.');
return true;
} catch (e) {
console.warn('localStorage Device 설정 파싱 실패:', e);
}
}
return false;
}
// localStorage에서 불러오기 (Protocol)
function loadProtocolFromLocalIfExists() {
const saved = localStorage.getItem('protocolConfigAutoSave');
if (saved) {
try {
loadFromRegisterJson(JSON.parse(saved));
console.log('localStorage에서 자동 저장된 Protocol 설정을 불러왔습니다.');
return true;
} catch (e) {
console.warn('localStorage Protocol 설정 파싱 실패:', e);
}
}
return false;
}
// input, select 등 값이 바뀔 때마다 자동 저장 (Device)
function bindAutoSaveEvents() {
document.querySelectorAll('input, select').forEach(el => {
el.addEventListener('change', autoSaveToLocal);
});
}
// input, select 등 값이 바뀔 때마다 자동 저장 (Protocol)
function bindAutoSaveProtocolEvents() {
// reg, modbus, opcua, can 페이지 내의 input/select만
const protocolSections = ['#page-reg', '#page-modbus', '#page-opcua', '#page-can'];
protocolSections.forEach(section => {
document.querySelectorAll(section + ' input, ' + section + ' select').forEach(el => {
el.addEventListener('change', autoSaveProtocolToLocal);
});
});
}
/*-----protocol에 설정 데이터를 protocolConfig.json 파일로 변경하여 유저가 다운로드 할수 있게 하는 함수-----*/
function downloadProtocolJson(obj, filename='protocolConfig.json') {
@ -1456,30 +1535,85 @@
/*-------페이지 로드시 서버에 있는 데이터를 불러오는 함수---------*/
async function loadInitialData() {
// 1. localStorage 우선 적용 (Device)
let deviceLoadedFromLocal = loadFromLocalIfExists();
// 2. 서버에서 파일 목록 조회 및 로드 (Device)
if (!deviceLoadedFromLocal) {
try {
// Device 설정 로드
// 사용 가능한 Device 파일 목록 조회
const deviceFilesResponse = await fetch('http://localhost:8080/setting/device-files');
if (deviceFilesResponse.ok) {
const deviceFilesData = await deviceFilesResponse.json();
if (deviceFilesData && deviceFilesData.body && deviceFilesData.body.length > 0) {
// 첫 번째 유효한 Device 파일 로드
const firstDeviceFile = deviceFilesData.body[0];
console.log(`Device 파일 발견: ${firstDeviceFile}`);
const deviceResponse = await fetch(`http://localhost:8080/setting/get-device/${firstDeviceFile}`);
if (deviceResponse.ok) {
const deviceData = await deviceResponse.json();
if (deviceData && deviceData.body) {
loadFromData(deviceData.body);
console.log(`Device 설정 자동 로드 완료: ${firstDeviceFile}`);
}
}
} else {
// 기본 파일명으로 시도
const deviceResponse = await fetch('http://localhost:8080/setting/get-device');
if (deviceResponse.ok) {
const deviceData = await deviceResponse.json();
if (deviceData && deviceData.body) {
loadFromData(deviceData.body);
console.log('Device 설정 자동 로드 완료 (기본 파일)');
}
}
}
}
} catch (error) {
alert('Device configuration file missing or loading failed');
console.log('Device 설정 파일이 없거나 로드 실패, 기본값 사용:', error.message);
}
}
bindAutoSaveEvents();
// 1. localStorage 우선 적용 (Protocol)
let protocolLoadedFromLocal = loadProtocolFromLocalIfExists();
// 2. 서버에서 파일 목록 조회 및 로드 (Protocol)
if (!protocolLoadedFromLocal) {
try {
// Protocol 설정 로드
// 사용 가능한 Protocol 파일 목록 조회
const protocolFilesResponse = await fetch('http://localhost:8080/setting/protocol-files');
if (protocolFilesResponse.ok) {
const protocolFilesData = await protocolFilesResponse.json();
if (protocolFilesData && protocolFilesData.body && protocolFilesData.body.length > 0) {
// 첫 번째 유효한 Protocol 파일 로드
const firstProtocolFile = protocolFilesData.body[0];
console.log(`Protocol 파일 발견: ${firstProtocolFile}`);
const protocolResponse = await fetch(`http://localhost:8080/setting/get-protocol/${firstProtocolFile}`);
if (protocolResponse.ok) {
const protocolData = await protocolResponse.json();
if (protocolData && protocolData.body) {
loadFromRegisterJson(protocolData.body);
console.log(`Protocol 설정 자동 로드 완료: ${firstProtocolFile}`);
}
}
} else {
// 기본 파일명으로 시도
const protocolResponse = await fetch('http://localhost:8080/setting/get-protocol');
if (protocolResponse.ok) {
const protocolData = await protocolResponse.json();
if (protocolData && protocolData.body) {
loadFromRegisterJson(protocolData.body);
console.log('Protocol 설정 자동 로드 완료 (기본 파일)');
}
}
}
}
} catch (error) {
alert('Protocol configuration file missing or loading failed'); }
console.log('Protocol 설정 파일이 없거나 로드 실패, 기본값 사용:', error.message);
}
}
bindAutoSaveProtocolEvents();
}
/*-----------------------------------------------------*/

Loading…
Cancel
Save