diff --git a/src/main/java/controller/MainController.java b/src/main/java/controller/MainController.java index 7991773..6f7d385 100644 --- a/src/main/java/controller/MainController.java +++ b/src/main/java/controller/MainController.java @@ -7,8 +7,10 @@ import dto.LoginUserDTO; import dto.MemberDTO; import mqtt.MqttManager; -import mqtt.devices.DHtHandler; -import mqtt.devices.ELVHandler; +import mqtt.devices.ELVHandler; +import mqtt.devices.ParkingHandler; +import dao.ParkingDAO; +import dao.ParkingDAOImpl; import service.UserService; import service.UserServiceImpl; import controller.AccessController; @@ -18,7 +20,9 @@ public class MainController { private MemberDTO currentUser = null; // 현재 로그인한 사용자 정보 private final MainUI view = new MainUI(); // 화면을 담당할 View 객체 private MqttManager mqttManager; - private ElevatorController evController; + private ElevatorController evController; + private final ParkingDAO parkingDAO = new ParkingDAOImpl(); + private boolean devicesInitialized = false; public MainController() { @@ -27,25 +31,31 @@ public MainController() { } // 브로커 서버와 연결, subscribe topic 설정 - public void settingDevice(){ - Thread mqttThread = new Thread(mqttManager); - mqttThread.start(); - System.out.println("🚀 Main thread started MQTT connection thread."); - - // 메인 스레드가 바로 종료되는 것을 방지하기 위해 잠시 대기 - try { - // 스레드가 연결될 시간을 잠시 줍니다. - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - // 2. ✅ 각 전문 컨트롤러들을 생성하여 필요한 MqttManager를 주입 (의존성 주입) - evController = new ElevatorController(currentUser, mqttManager); - // DHtController dhtController = new DhtController(mqttManager); // 예시 - // LedController ledController = new LedController(mqttManager); // 예시 - - System.out.println("✅ All device controllers have been initialized and listeners are set."); - } + public void settingDevice(){ + if (!devicesInitialized) { + Thread mqttThread = new Thread(mqttManager); + mqttThread.start(); + System.out.println("🚀 Main thread started MQTT connection thread."); + + // 메인 스레드가 바로 종료되는 것을 방지하기 위해 잠시 대기 + try { + // 스레드가 연결될 시간을 잠시 줍니다. + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + ParkingHandler parkingHandler = new ParkingHandler(parkingDAO); + String parkingTopic = "parking/car/#"; + this.mqttManager.addListener(parkingTopic, parkingHandler); + + System.out.println("✅ All device controllers have been initialized and listeners are set."); + devicesInitialized = true; + } + // 2. ✅ 각 전문 컨트롤러들을 생성하여 필요한 MqttManager를 주입 (의존성 주입) + evController = new ElevatorController(currentUser, mqttManager); + // DHtController dhtController = new DhtController(mqttManager); // 예시 + // LedController ledController = new LedController(mqttManager); // 예시 + } public void run() { while (true) { @@ -168,4 +178,4 @@ private void exitProgram() { // TODO Auto-generated method stub } -} \ No newline at end of file +} diff --git a/src/main/java/dao/ParkingDAO.java b/src/main/java/dao/ParkingDAO.java index 3bbbf9e..4ef3808 100644 --- a/src/main/java/dao/ParkingDAO.java +++ b/src/main/java/dao/ParkingDAO.java @@ -9,4 +9,5 @@ public interface ParkingDAO { public ParkingLogDTO getCurrentParkingStatus(int userId); public List getParkingLogsByUser(int userId); public List getAllSpaces(); + void processVehicleLog(String carNo, String action); } diff --git a/src/main/java/dao/ParkingDAOImpl.java b/src/main/java/dao/ParkingDAOImpl.java index 37400c8..7476a57 100644 --- a/src/main/java/dao/ParkingDAOImpl.java +++ b/src/main/java/dao/ParkingDAOImpl.java @@ -3,12 +3,14 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.List; - -import util.DBUtil; -import dto.ParkingLogDTO; -import dto.ParkingSpaceDTO; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.List; + +import util.DBUtil; +import dto.ParkingLogDTO; +import dto.ParkingSpaceDTO; public class ParkingDAOImpl implements ParkingDAO { @@ -58,12 +60,114 @@ public List getParkingLogsByUser(int userId) { return null; } - - @Override - public List getAllSpaces() { - - return null; - } - - -} \ No newline at end of file + @Override + public List getAllSpaces() { + + return null; + } + + @Override + public void processVehicleLog(String carNo, String action) { + if (carNo == null || carNo.trim().isEmpty()) { + System.out.println("🚗 차량 번호가 비어 있어 로그를 처리할 수 없습니다."); + return; + } + + String normalizedAction = (action == null || action.trim().isEmpty()) ? "IN" : action.trim().toUpperCase(); + try (Connection con = DBUtil.getConnect()) { + + Integer userId = null; + String findUserSql = "SELECT user_id FROM users WHERE vehicle_no = ?"; + try (PreparedStatement findUser = con.prepareStatement(findUserSql)) { + findUser.setString(1, carNo); + try (ResultSet userRs = findUser.executeQuery()) { + if (userRs.next()) { + userId = userRs.getInt("user_id"); + } + } + } + + if (userId == null) { + System.out.printf("🚫 차량 번호 %s 에 해당하는 등록 정보가 없습니다.%n", carNo); + return; + } + + switch (normalizedAction) { + case "IN": + logVehicleEntry(con, userId, carNo); + break; + case "OUT": + logVehicleExit(con, userId, carNo); + break; + default: + System.out.printf("⚠️ 지원하지 않는 차량 액션: %s%n", normalizedAction); + return; + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + private void logVehicleEntry(Connection con, int userId, String carNo) throws SQLException { + String insertSql = """ + INSERT INTO parking_log (user_id, space_id, action, note, in_time) + VALUES (?, ?, 'IN', ?, NOW()) + """; + try (PreparedStatement insert = con.prepareStatement(insertSql)) { + insert.setInt(1, userId); + insert.setNull(2, Types.INTEGER); + insert.setString(3, buildNote("입차", carNo)); + insert.executeUpdate(); + } + } + + private void logVehicleExit(Connection con, int userId, String carNo) throws SQLException { + String findOpenSql = """ + SELECT parking_id, in_time + FROM parking_log + WHERE user_id = ? AND out_time IS NULL + ORDER BY in_time DESC + LIMIT 1 + """; + try (PreparedStatement findOpen = con.prepareStatement(findOpenSql)) { + findOpen.setInt(1, userId); + try (ResultSet openRs = findOpen.executeQuery()) { + if (openRs.next()) { + int parkingId = openRs.getInt("parking_id"); + Timestamp inTime = openRs.getTimestamp("in_time"); + Timestamp now = new Timestamp(System.currentTimeMillis()); + long diff = now.getTime() - (inTime != null ? inTime.getTime() : now.getTime()); + int duration = diff > 0 ? (int) (diff / 60000) : 0; + + String updateSql = """ + UPDATE parking_log + SET out_time = ?, duration_min = ?, action = 'OUT', note = ? + WHERE parking_id = ? + """; + try (PreparedStatement update = con.prepareStatement(updateSql)) { + update.setTimestamp(1, now); + update.setInt(2, duration); + update.setString(3, buildNote("출차", carNo)); + update.setInt(4, parkingId); + update.executeUpdate(); + } + } else { + String insertOutSql = """ + INSERT INTO parking_log (user_id, space_id, action, note, out_time) + VALUES (?, ?, 'OUT', ?, NOW()) + """; + try (PreparedStatement insert = con.prepareStatement(insertOutSql)) { + insert.setInt(1, userId); + insert.setNull(2, Types.INTEGER); + insert.setString(3, buildNote("출차", carNo)); + insert.executeUpdate(); + } + } + } + } + } + + private String buildNote(String prefix, String carNo) { + return String.format("%s: %s", prefix, carNo); + } +} diff --git a/src/main/java/dto/mqttMsg/MqttParkingDTO.java b/src/main/java/dto/mqttMsg/MqttParkingDTO.java new file mode 100644 index 0000000..dbcec98 --- /dev/null +++ b/src/main/java/dto/mqttMsg/MqttParkingDTO.java @@ -0,0 +1,23 @@ +package dto.mqttMsg; + +public class MqttParkingDTO { + private String carNo; + private String action; + + public String getCarNo() { + return carNo; + } + + public void setCarNo(String carNo) { + this.carNo = carNo; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } +} + diff --git a/src/main/java/mqtt/devices/ParkingHandler.java b/src/main/java/mqtt/devices/ParkingHandler.java new file mode 100644 index 0000000..d4f333a --- /dev/null +++ b/src/main/java/mqtt/devices/ParkingHandler.java @@ -0,0 +1,33 @@ +package mqtt.devices; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import dao.ParkingDAO; +import dto.mqttMsg.MqttParkingDTO; +import mqtt.OnMessageCallback; + +public class ParkingHandler implements OnMessageCallback { + + private final ParkingDAO parkingDAO; + private final Gson gson = new Gson(); + + public ParkingHandler(ParkingDAO parkingDAO) { + this.parkingDAO = parkingDAO; + } + + @Override + public void handle(String topic, String payload) { + try { + MqttParkingDTO dto = gson.fromJson(payload, MqttParkingDTO.class); + if (dto == null || dto.getCarNo() == null) { + System.out.printf("⚠️ 파싱된 차량 데이터가 없어 무시합니다. topic=%s payload=%s%n", topic, payload); + return; + } + + parkingDAO.processVehicleLog(dto.getCarNo(), dto.getAction()); + } catch (JsonSyntaxException ex) { + System.out.printf("⚠️ 차량 로그 JSON 파싱 실패: %s%n", ex.getMessage()); + } + } +} +