diff --git a/http/API-TEST.http b/http/API-TEST.http index f8c951d..26e7304 100644 --- a/http/API-TEST.http +++ b/http/API-TEST.http @@ -19,3 +19,5 @@ POST http://localhost:8080/api/snow-maker/{{resortId}}/vote?isPositive=false ### 설질 투표 API(긍정) POST http://localhost:8080/api/snow-maker/{{resortId}}/vote?isPositive=true +### 혼잡도 조회 +GET http://localhost:8080/api/congestion/{{resortId}} diff --git a/init.sql b/init.sql index 1c8fb53..b996003 100644 --- a/init.sql +++ b/init.sql @@ -23,24 +23,26 @@ DROP TABLE IF EXISTS ski_resorts; CREATE TABLE ski_resorts ( resort_id BIGINT AUTO_INCREMENT PRIMARY KEY, - `name` VARCHAR(255) NOT NULL, - status VARCHAR(255) NOT NULL COMMENT '운영중, 운영종료, 예정', - opening_date DATE NULL, - closing_date DATE NULL, - open_slopes INT NOT NULL DEFAULT 0, - total_slopes INT NOT NULL DEFAULT 0, - day_operating_hours VARCHAR(50) NULL COMMENT '주간 운영시간', - night_operating_hours VARCHAR(50) NULL COMMENT '야간 운영시간', - late_night_operating_hours VARCHAR(50) NULL COMMENT '심야 운영시간', - dawn_operating_hours VARCHAR(50) NULL COMMENT '새벽 운영시간', - midnight_operating_hours VARCHAR(50) NULL COMMENT '자정 운영시간', - snowfall_time VARCHAR(50) NULL COMMENT '정설 시간', - x_coordinate VARCHAR(10) NOT NULL COMMENT '위도 매핑 값', - y_coordinate VARCHAR(10) NOT NULL COMMENT '경도 매핑 값', - detailed_area_code VARCHAR(10) NULL COMMENT '예보 구역 코드(기온 예보에 사용)', - broad_area_code VARCHAR(10) NULL COMMENT '광역 지역 코드(육상 예보에 사용)', - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + `name` VARCHAR(255) NOT NULL, + status VARCHAR(255) NOT NULL COMMENT '운영중, 운영종료, 예정', + opening_date DATE NULL, + closing_date DATE NULL, + open_slopes INT NOT NULL DEFAULT 0, + total_slopes INT NOT NULL DEFAULT 0, + day_operating_hours VARCHAR(50) NULL COMMENT '주간 운영시간', + night_operating_hours VARCHAR(50) NULL COMMENT '야간 운영시간', + late_night_operating_hours VARCHAR(50) NULL COMMENT '심야 운영시간', + dawn_operating_hours VARCHAR(50) NULL COMMENT '새벽 운영시간', + midnight_operating_hours VARCHAR(50) NULL COMMENT '자정 운영시간', + snowfall_time VARCHAR(50) NULL COMMENT '정설 시간', + x_coordinate VARCHAR(10) NOT NULL COMMENT '위도 매핑 값', + y_coordinate VARCHAR(10) NOT NULL COMMENT '경도 매핑 값', + x_real_coordinate DECIMAL(10, 7) NULL COMMENT '위도 실제 값', + y_real_coordinate DECIMAL(10, 7) NULL COMMENT '경도 실제 값', + detailed_area_code VARCHAR(10) NULL COMMENT '예보 구역 코드(기온 예보에 사용)', + broad_area_code VARCHAR(10) NULL COMMENT '광역 지역 코드(육상 예보에 사용)', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); -- 현재 날씨 테이블 @@ -64,7 +66,8 @@ CREATE TABLE hourly_weather ( id BIGINT AUTO_INCREMENT PRIMARY KEY, resort_id BIGINT NOT NULL, - forecast_time DATETIME NOT NULL, + forecast_time VARCHAR(10) NOT NULL COMMENT '예보 시간(오전 8시)', + priority INT NOT NULL COMMENT '우선순위(1, 2, 3, 4, 5)', temperature INT NOT NULL, precipitation_chance INT NOT NULL, `condition` VARCHAR(255) NOT NULL COMMENT '맑음, 흐림, 흐리고 비, 비, 눈, 안개', @@ -108,7 +111,7 @@ CREATE TABLE slopes id BIGINT AUTO_INCREMENT PRIMARY KEY, resort_id BIGINT NOT NULL, `name` VARCHAR(255) NOT NULL, - webcam_number INT NULL, + webcam_number INT NULL, difficulty VARCHAR(255) NOT NULL COMMENT '초급, 중급, 중상급, 최상급, 파크', is_day_operating BOOLEAN DEFAULT FALSE, is_night_operating BOOLEAN DEFAULT FALSE, @@ -124,43 +127,169 @@ CREATE TABLE slopes CREATE TABLE webcams ( id BIGINT AUTO_INCREMENT PRIMARY KEY, - resort_id BIGINT NOT NULL, + resort_id BIGINT NOT NULL, `name` VARCHAR(255) NULL, - number INT NULL, + number INT NULL, description VARCHAR(255) NULL, url VARCHAR(255) NULL, - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + FOREIGN KEY (resort_id) REFERENCES ski_resorts (resort_id) +); + +-- 혼잡도 테이블 +CREATE TABLE congestion +( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + resort_id BIGINT NOT NULL, + congestion INT NOT NULL COMMENT '혼잡도(1, 2, 3, 4)', + description VARCHAR(255) NULL COMMENT '여유(1), 보통(2), 혼잡(3), 매우 혼잡(4)', + time VARCHAR(10) NOT NULL COMMENT '시간(오전 8시)', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (resort_id) REFERENCES ski_resorts (resort_id) ); +INSERT INTO congestion (resort_id, congestion, description, time) +VALUES (1, 1, '여유', '오전 8시'), + (1, 3, '혼잡', '오전 10시'), + (1, 1, '여유', '오후 12시'), + (1, 3, '혼잡', '오후 2시'), + (1, 1, '여유', '오후 4시'), + (1, 3, '혼잡', '오후 6시'), + (1, 1, '여유', '오후 8시'), + (1, 3, '혼잡', '오후 10시'), + (1, 4, '매우 혼잡', '오전 12시'), + (1, 4, '매우 혼잡', '오전 2시'), + (2, 1, '여유', '오전 8시'), + (2, 3, '혼잡', '오전 10시'), + (2, 1, '여유', '오후 12시'), + (2, 3, '혼잡', '오후 2시'), + (2, 1, '여유', '오후 4시'), + (2, 3, '혼잡', '오후 6시'), + (2, 1, '여유', '오후 8시'), + (2, 3, '혼잡', '오후 10시'), + (2, 4, '매우 혼잡', '오전 12시'), + (2, 4, '매우 혼잡', '오전 2시'), + (3, 1, '여유', '오전 8시'), + (3, 3, '혼잡', '오전 10시'), + (3, 1, '여유', '오후 12시'), + (3, 3, '혼잡', '오후 2시'), + (3, 1, '여유', '오후 4시'), + (3, 3, '혼잡', '오후 6시'), + (3, 1, '여유', '오후 8시'), + (3, 3, '혼잡', '오후 10시'), + (3, 4, '매우 혼잡', '오전 12시'), + (3, 4, '매우 혼잡', '오전 2시'), + (4, 1, '여유', '오전 8시'), + (4, 3, '혼잡', '오전 10시'), + (4, 1, '여유', '오후 12시'), + (4, 3, '혼잡', '오후 2시'), + (4, 4, '매우 혼잡', '오후 4시'), + (4, 4, '매우 혼잡', '오후 6시'), + (4, 4, '매우 혼잡', '오후 8시'), + (4, 4, '매우 혼잡', '오후 10시'), + (4, 4, '매우 혼잡', '오전 12시'), + (4, 4, '매우 혼잡', '오전 2시'), + (5, 1, '여유', '오전 8시'), + (5, 3, '혼잡', '오전 10시'), + (5, 1, '여유', '오후 12시'), + (5, 3, '혼잡', '오후 2시'), + (5, 1, '여유', '오후 4시'), + (5, 3, '혼잡', '오후 6시'), + (5, 1, '여유', '오후 8시'), + (5, 3, '혼잡', '오후 10시'), + (5, 4, '매우 혼잡', '오전 12시'), + (5, 4, '매우 혼잡', '오전 2시'), + (6, 1, '여유', '오전 8시'), + (6, 3, '혼잡', '오전 10시'), + (6, 1, '여유', '오후 12시'), + (6, 3, '혼잡', '오후 2시'), + (6, 1, '여유', '오후 4시'), + (6, 3, '혼잡', '오후 6시'), + (6, 1, '여유', '오후 8시'), + (6, 3, '혼잡', '오후 10시'), + (6, 4, '매우 혼잡', '오전 12시'), + (6, 3, '혼잡', '오전 2시'), + (7, 1, '여유', '오전 8시'), + (7, 3, '혼잡', '오전 10시'), + (7, 1, '여유', '오후 12시'), + (7, 3, '혼잡', '오후 2시'), + (7, 1, '여유', '오후 4시'), + (7, 3, '혼잡', '오후 6시'), + (7, 1, '여유', '오후 8시'), + (7, 3, '혼잡', '오후 10시'), + (7, 4, '매우 혼잡', '오전 12시'), + (7, 4, '매우 혼잡', '오전 2시'), + (8, 1, '여유', '오전 8시'), + (8, 3, '혼잡', '오전 10시'), + (8, 1, '여유', '오후 12시'), + (8, 3, '혼잡', '오후 2시'), + (8, 1, '여유', '오후 4시'), + (8, 3, '혼잡', '오후 6시'), + (8, 1, '여유', '오후 8시'), + (8, 3, '혼잡', '오후 10시'), + (8, 4, '매우 혼잡', '오전 12시'), + (8, 4, '매우 혼잡', '오전 2시'), + (9, 1, '여유', '오전 8시'), + (9, 3, '혼잡', '오전 10시'), + (9, 1, '여유', '오후 12시'), + (9, 3, '혼잡', '오후 2시'), + (9, 1, '여유', '오후 4시'), + (9, 3, '혼잡', '오후 6시'), + (9, 1, '여유', '오후 8시'), + (9, 3, '혼잡', '오후 10시'), + (9, 4, '매우 혼잡', '오전 12시'), + (9, 4, '매우 혼잡', '오전 2시'), + (10, 1, '여유', '오전 8시'), + (10, 3, '혼잡', '오전 10시'), + (10, 1, '여유', '오후 12시'), + (10, 3, '혼잡', '오후 2시'), + (10, 1, '여유', '오후 4시'), + (10, 3, '혼잡', '오후 6시'), + (10, 1, '여유', '오후 8시'), + (10, 3, '혼잡', '오후 10시'), + (10, 4, '매우 혼잡', '오전 12시'), + (10, 4, '매우 혼잡', '오전 2시'), + (11, 1, '여유', '오전 8시'), + (11, 3, '혼잡', '오전 10시'), + (11, 1, '여유', '오후 12시'), + (11, 3, '혼잡', '오후 2시'), + (11, 1, '여유', '오후 4시'), + (11, 3, '혼잡', '오후 6시'), + (11, 1, '여유', '오후 8시'), + (11, 3, '혼잡', '오후 10시'), + (11, 4, '매우 혼잡', '오전 12시'), + (11, 4, '매우 혼잡', '오전 2시'); + -- 스키장 정보 INSERT INTO ski_resorts (`name`, status, opening_date, closing_date, open_slopes, total_slopes, day_operating_hours, night_operating_hours, late_night_operating_hours, dawn_operating_hours, - midnight_operating_hours, snowfall_time, x_coordinate, y_coordinate, detailed_area_code, - broad_area_code) + midnight_operating_hours, snowfall_time, x_coordinate, y_coordinate, x_real_coordinate, + y_real_coordinate, detailed_area_code, broad_area_code) VALUES ('지산 리조트', '예정', STR_TO_DATE('2024.12.04', '%Y.%m.%d'), NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, '69', - '119', '11B20701', '11B00000'), + '119', 37.2180444, 127.3458046, '11B20701', '11B00000'), ('곤지암 스키장', '예정', STR_TO_DATE('2024.12.03', '%Y.%m.%d'), NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, '69', - '119', '11B20702', '11B00000'), + '119', 37.3388535, 127.2913164, '11B20702', '11B00000'), ('비발디파크', '예정', STR_TO_DATE('2024.11.25', '%Y.%m.%d'), NULL, 0, 0, '08:30~16:30', '18:30~22:30', NULL, NULL, - NULL, '16:30~18:30', '72', '129', '11D10302', '11D10000'), + NULL, '16:30~18:30', '72', '129', 37.6485927, 127.6816583, '11D10302', '11D10000'), ('엘리시안 강촌', '예정', STR_TO_DATE('2024.11.30', '%Y.%m.%d'), NULL, 0, 0, '09:00~17:00', '18:30~24:00', '18:30~03:00', - NULL, NULL, '17:00~18:30', '71', '132', '11D10301', '11D10000'), + NULL, NULL, '17:00~18:30', '71', '132', 37.8269481, 127.5795879, '11D10301', '11D10000'), ('웰리힐리파크', '예정', STR_TO_DATE('2024.11.30', '%Y.%m.%d'), NULL, 0, 0, '09:00~16:30', '18:30~22:30', '22:30~24:00', - NULL, NULL, '16:30~18:30', '81', '126', '11D10402', '11D10000'), + NULL, NULL, '16:30~18:30', '81', '126', 37.4854756, 128.2431349, '11D10402', '11D10000'), ('휘닉스파크', '예정', STR_TO_DATE('2024.11.22', '%Y.%m.%d'), NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, '14:30~18:00', - '84', '128', '11D10503', '11D10000'), + '84', '128', 37.5837935, 128.3241444, '11D10503', '11D10000'), ('하이원 스키장', '예정', STR_TO_DATE('2024.12.06', '%Y.%m.%d'), NULL, 0, 0, '09:00~16:00', '18:00~22:00', NULL, NULL, - NULL, '16:00~18:00', '92', '120', '11D10502', '11D10000'), + NULL, '16:00~18:00', '92', '120', 37.2085908, 128.8244331, '11D10502', '11D10000'), ('용평스키장 모나', '예정', STR_TO_DATE('2024.11.22', '%Y.%m.%d'), NULL, 0, 0, '09:00~17:00', '19:00~22:00', NULL, NULL, - NULL, '17:00~19:00', '89', '130', '11D20201', '11D20000'), + NULL, '17:00~19:00', '89', '130', 37.6442675, 128.6776039, '11D20201', '11D20000'), ('무주덕유산', '예정', STR_TO_DATE('2024.12.06', '%Y.%m.%d'), NULL, 0, 0, '07:00~16:00', '18:00~21:00', NULL, NULL, - NULL, '16:30~18:30', '75', '93', '11F10302', '11F10000'), + NULL, '16:30~18:30', '75', '93', 35.8942139, 127.7421179, '11F10302', '11F10000'), ('에덴벨리(양산)', '예정', STR_TO_DATE('2024.11.23', '%Y.%m.%d'), NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, - '17:30~19:00', '95', '80', '11H20102', '11H20000'), + '17:30~19:00', '95', '80', 35.4291289, 128.9817966, '11H20102', '11H20000'), ('오투리조트', '예정', STR_TO_DATE('2024.11.29', '%Y.%m.%d'), NULL, 0, 0, '09:30~16:30', '18:00~21:30', NULL, NULL, - NULL, '16:30~18:00', '95', '119', '11D20301', '11D20000'); + NULL, '16:30~18:00', '95', '119', 37.1766149, 128.9402658, '11D20301', '11D20000'); + -- 하이윈 스키장 슬로프 정보 (resort_id = 7) INSERT INTO slopes (resort_id, `name`, difficulty, is_day_operating, is_night_operating, is_late_night_operating, diff --git a/src/main/kotlin/nexters/weski/congestion/Congestion.kt b/src/main/kotlin/nexters/weski/congestion/Congestion.kt new file mode 100644 index 0000000..2cebf8f --- /dev/null +++ b/src/main/kotlin/nexters/weski/congestion/Congestion.kt @@ -0,0 +1,19 @@ +package nexters.weski.congestion + +import jakarta.persistence.* +import nexters.weski.common.BaseEntity +import nexters.weski.ski_resort.SkiResort + +@Entity +@Table(name = "congestion") +data class Congestion( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long = 0, + val time: String, + val congestion: Int, + val description: String, // 여유, 보통, 혼잡, 매우혼잡 + @ManyToOne + @JoinColumn(name = "resort_id") + val skiResort: SkiResort +) : BaseEntity() diff --git a/src/main/kotlin/nexters/weski/congestion/CongestionController.kt b/src/main/kotlin/nexters/weski/congestion/CongestionController.kt new file mode 100644 index 0000000..584cc38 --- /dev/null +++ b/src/main/kotlin/nexters/weski/congestion/CongestionController.kt @@ -0,0 +1,19 @@ +package nexters.weski.congestion + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RestController + +@Tag(name = "혼잡도 정보 조회 API", description = "특정 스키장의 혼잡도 정보 조회") +@RestController +class CongestionController( + private val congestionService: CongestionService +) { + @Operation(summary = "특정 스키장의 혼잡도 조회 API") + @GetMapping("/api/congestion/{resortId}") + fun getResortCongestion(@PathVariable resortId: String): List { + return congestionService.getCongestion(resortId) + } +} diff --git a/src/main/kotlin/nexters/weski/congestion/CongestionRepository.kt b/src/main/kotlin/nexters/weski/congestion/CongestionRepository.kt new file mode 100644 index 0000000..c5684f1 --- /dev/null +++ b/src/main/kotlin/nexters/weski/congestion/CongestionRepository.kt @@ -0,0 +1,7 @@ +package nexters.weski.congestion + +import org.springframework.data.jpa.repository.JpaRepository + +interface CongestionRepository : JpaRepository { + fun findAllBySkiResortResortId(resortId: Long): List +} diff --git a/src/main/kotlin/nexters/weski/congestion/CongestionResponseDto.kt b/src/main/kotlin/nexters/weski/congestion/CongestionResponseDto.kt new file mode 100644 index 0000000..3542089 --- /dev/null +++ b/src/main/kotlin/nexters/weski/congestion/CongestionResponseDto.kt @@ -0,0 +1,20 @@ +package nexters.weski.congestion + +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(description = "스키장 혼잡도 응답 DTO") +data class CongestionResponseDto( + val time: String, + val congestion: Int, + val description: String +) { + companion object { + fun fromEntity(congestion: Congestion): CongestionResponseDto { + return CongestionResponseDto( + time = congestion.time, + congestion = congestion.congestion, + description = congestion.description + ) + } + } +} diff --git a/src/main/kotlin/nexters/weski/congestion/CongestionService.kt b/src/main/kotlin/nexters/weski/congestion/CongestionService.kt new file mode 100644 index 0000000..e0b1630 --- /dev/null +++ b/src/main/kotlin/nexters/weski/congestion/CongestionService.kt @@ -0,0 +1,14 @@ +package nexters.weski.congestion + +import org.springframework.stereotype.Service + +@Service +class CongestionService( + private val congestionRepository: CongestionRepository +) { + fun getCongestion(resortId: String): List { + return congestionRepository.findAllBySkiResortResortId(resortId = resortId.toLong()) + .map { CongestionResponseDto.fromEntity(it) } + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 5c5a034..e921666 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -24,3 +24,6 @@ springdoc: weather: api: key: p6zNXOJrrBY4cuX7OYtdDMtmR8hiGeUaBLf0z6BXnm/qniV8wB0SuPwBgqKDTKV/24EW7xiRY3DCS21Ess/42Q== +tamp: + api: + key: hzztwqD56d3rBN9hEo1rY1yJiCqtfWY55Obn4Ocj