Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/backend-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ jobs:
SPRING_DATASOURCE_USERNAME: testuser
SPRING_DATASOURCE_PASSWORD: testpassword
CORS_ALLOWED_ORIGINS: ${{ secrets.CORS_ALLOWED_ORIGINS }}
CCTV_STREAM_URL_PREFIX: ${{ secrets.CCTV_STREAM_URL_PREFIX }}
run: ./gradlew test

dependency-submission:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.example.backend.dashboard.controller;

import com.example.backend.dashboard.dto.CctvInfoResponse;
import com.example.backend.dashboard.service.CctvService;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/v1/cctv")
@RequiredArgsConstructor
public class CctvController {


private final CctvService CctvService;

@GetMapping("")
public ResponseEntity<?> getCctvInfo(HttpSession session) {
List<CctvInfoResponse> cctvs = CctvService.getCctvInfo(session);
return ResponseEntity.ok(cctvs);
}

@GetMapping("/{id}")
public ResponseEntity<?> getCctvLive(@PathVariable("id") int id, HttpSession session) {
CctvInfoResponse cctv = CctvService.getCctvLive(id, session);
return ResponseEntity.ok(cctv);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
public class CaseDetectRequest {
private Integer officeId; // 사무소 ID
private Integer cctvId; // CCTV ID
private Integer level; // 위험 레벨
private int level; // 위험 레벨
private String category; // "fire", "assault" 등
private String video; // 스토리지에 저장된 영상 URL
private String memo; // 기타 메모
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.backend.dashboard.dto;

import com.example.backend.common.domain.CctvEntity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CctvInfoResponse {
private Integer id; // CCTV ID
private double latitude;
private double longitude;
private String address; // CCTV 주소
private String liveUrl; // 생략 가능: getCctvInfo에는 필요 없음

public static CctvInfoResponse fromEntity(CctvEntity entity, String urlPrefix) {
return CctvInfoResponse.builder()
.id(entity.getId())
.latitude(entity.getLatitude())
.longitude(entity.getLongitude())
.address(entity.getAddress())
.liveUrl(urlPrefix + entity.getId() + ".m3u8")
.build();
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class DashboardResponse {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime date;

private Integer level;
private int level;
private CaseCategory category;
private CaseState state;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.backend.dashboard.repository;

import com.example.backend.common.domain.CctvEntity;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface CctvInfoRepository extends JpaRepository<CctvEntity, Integer> {
List<CctvEntity> findAllByOfficeIdOrderById(int officeId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.example.backend.dashboard.service;

import com.example.backend.common.domain.CctvEntity;
import com.example.backend.dashboard.dto.CctvInfoResponse;
import com.example.backend.dashboard.repository.CctvInfoRepository;
import com.example.backend.user.dto.UserResponseDto;
import jakarta.persistence.EntityNotFoundException;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional
@RequiredArgsConstructor
public class CctvService {

private final CctvInfoRepository cctvRepository;

@Value("${cctv.stream-url-prefix}")
private String streamUrlPrefix;

// 세션에서 officeId 추출
private int getAuthenticatedOfficeId(HttpSession session) {
UserResponseDto user = (UserResponseDto) session.getAttribute("user");
if (user == null) {
throw new IllegalStateException("세션이 만료되었거나 로그인되지 않았습니다.");
}
return user.getOfficeId();
}

public List<CctvInfoResponse> getCctvInfo(HttpSession session) {
int officeId = getAuthenticatedOfficeId(session);
List<CctvEntity> cctvs = cctvRepository.findAllByOfficeIdOrderById(officeId);

return cctvs.stream()
.map(entity -> CctvInfoResponse.fromEntity(entity, streamUrlPrefix))
.toList();
}

public CctvInfoResponse getCctvLive(int cctvId, HttpSession session) {
getAuthenticatedOfficeId(session);

CctvEntity entity = cctvRepository.findById(cctvId)
.orElseThrow(() -> new EntityNotFoundException("해당 CCTV를 찾을 수 없습니다."));

return CctvInfoResponse.fromEntity(entity, streamUrlPrefix);
}

}
Loading