Skip to content

Commit d150cf3

Browse files
committed
feat: 지도 내 다이어리 클러스터 조회 API 구현 (줌레벨 기준 시/도, 시군구 클러스터)
1 parent c316aa8 commit d150cf3

16 files changed

+434
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.example.log4u.domain.map.controller;
2+
3+
import java.util.List;
4+
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RequestParam;
9+
import org.springframework.web.bind.annotation.RestController;
10+
11+
import com.example.log4u.domain.map.dto.response.DiaryClusterResponseDto;
12+
import com.example.log4u.domain.map.service.MapService;
13+
14+
import io.swagger.v3.oas.annotations.tags.Tag;
15+
import lombok.RequiredArgsConstructor;
16+
17+
@Tag(name = "지도 API")
18+
@RestController
19+
@RequiredArgsConstructor
20+
@RequestMapping("/maps")
21+
public class MapController {
22+
23+
private final MapService mapService;
24+
25+
@GetMapping("/diaries/cluster")
26+
public ResponseEntity<List<DiaryClusterResponseDto>> getDiaryClusters(
27+
@RequestParam double south,
28+
@RequestParam double north,
29+
@RequestParam double west,
30+
@RequestParam double east,
31+
@RequestParam int zoom
32+
) {
33+
List<DiaryClusterResponseDto> clusters = mapService.getDiaryClusters(south, north, west, east, zoom);
34+
return ResponseEntity.ok(clusters);
35+
}
36+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.example.log4u.domain.map.dto.response;
2+
3+
public interface AreaClusterProjection {
4+
Long getId();
5+
String getName();
6+
Double getLat();
7+
Double getLon();
8+
Long getDiaryCount();
9+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.example.log4u.domain.map.dto.response;
2+
3+
public record DiaryClusterResponseDto(
4+
String areaName,
5+
Long areaId,
6+
Double lat,
7+
Double lon,
8+
Long diaryCount
9+
) {
10+
public static DiaryClusterResponseDto of(AreaClusterProjection proj) {
11+
return new DiaryClusterResponseDto(
12+
proj.getName(),
13+
proj.getId(),
14+
proj.getLat(),
15+
proj.getLon(),
16+
proj.getDiaryCount()
17+
);
18+
}
19+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.example.log4u.domain.map.entity;
2+
3+
import jakarta.persistence.*;
4+
import lombok.Getter;
5+
import lombok.NoArgsConstructor;
6+
import org.locationtech.jts.geom.Geometry;
7+
8+
@Entity
9+
@Getter
10+
@NoArgsConstructor
11+
@Table(name = "sido_areas", schema = "public")
12+
public class SidoAreas {
13+
14+
@Id
15+
@GeneratedValue(strategy = GenerationType.IDENTITY)
16+
private Long id;
17+
18+
@Column(nullable = false)
19+
private String code;
20+
21+
@Column(nullable = false)
22+
private String name;
23+
24+
@Column(columnDefinition = "geometry")
25+
private Geometry geom;
26+
27+
@Column(columnDefinition = "geometry")
28+
private Geometry center;
29+
30+
@Column(nullable = false)
31+
private Double lat;
32+
33+
@Column(nullable = false)
34+
private Double lon;
35+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.example.log4u.domain.map.entity;
2+
3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.Id;
6+
import jakarta.persistence.Table;
7+
import lombok.AccessLevel;
8+
import lombok.Getter;
9+
import lombok.NoArgsConstructor;
10+
11+
@Entity
12+
@Table(name = "sido_areas_diary_count", schema = "public")
13+
@Getter
14+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
15+
public class SidoAreasDiaryCount {
16+
17+
@Id
18+
@Column(name = "id")
19+
private Long id;
20+
21+
@Column(name = "diary_count")
22+
private Long diaryCount;
23+
24+
25+
public void incrementCount() {
26+
this.diaryCount++;
27+
}
28+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.example.log4u.domain.map.entity;
2+
3+
import jakarta.persistence.*;
4+
import lombok.Getter;
5+
import lombok.NoArgsConstructor;
6+
7+
@Entity
8+
@Getter
9+
@NoArgsConstructor
10+
@Table(name = "province_code_map", schema = "public")
11+
public class SidoCodeMap {
12+
13+
@Id
14+
@Column(length = 2)
15+
private String code;
16+
17+
@Column(nullable = false)
18+
private String name;
19+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.example.log4u.domain.map.entity;
2+
3+
import jakarta.persistence.*;
4+
import lombok.Getter;
5+
import lombok.NoArgsConstructor;
6+
import org.locationtech.jts.geom.Geometry;
7+
8+
@Entity
9+
@Getter
10+
@NoArgsConstructor
11+
@Table(name = "sigg_areas", schema = "public")
12+
public class SiggAreas {
13+
14+
@Id
15+
@GeneratedValue(strategy = GenerationType.IDENTITY)
16+
private Long gid;
17+
18+
@Column(name = "adm_sect_c")
19+
private String admSectCode;
20+
21+
@Column(name = "sgg_nm")
22+
private String sggName;
23+
24+
@Column(name = "sgg_oid")
25+
private Integer sggOid;
26+
27+
@Column(name = "col_adm_se")
28+
private String colAdmSe;
29+
30+
@Column(columnDefinition = "geometry")
31+
private Geometry geom;
32+
33+
@Column(columnDefinition = "geometry")
34+
private Geometry center;
35+
36+
private Double lat;
37+
38+
private Double lon;
39+
40+
@Column(name = "level")
41+
private String level;
42+
43+
@Column(name = "parent_id")
44+
private Integer parentId;
45+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.example.log4u.domain.map.entity;
2+
3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.Id;
6+
import jakarta.persistence.Table;
7+
import lombok.AccessLevel;
8+
import lombok.Getter;
9+
import lombok.NoArgsConstructor;
10+
11+
@Entity
12+
@Table(name = "sigg_areas_diary_count", schema = "public")
13+
@Getter
14+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
15+
public class SiggAreasDiaryCount {
16+
17+
@Id
18+
@Column(name = "id")
19+
private Long id;
20+
21+
@Column(name = "diary_count", nullable = false)
22+
private Long diaryCount;
23+
24+
public void incrementCount() {
25+
this.diaryCount++;
26+
}
27+
28+
public void decrement() {
29+
this.diaryCount = Math.max(0, this.diaryCount - 1);
30+
}
31+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.example.log4u.domain.map.exception;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
import com.example.log4u.common.exception.base.ErrorCode;
6+
7+
import lombok.Getter;
8+
import lombok.RequiredArgsConstructor;
9+
10+
@Getter
11+
@RequiredArgsConstructor
12+
public enum MapErrorCode implements ErrorCode {
13+
14+
NOT_FOUND_REGION(HttpStatus.NOT_FOUND, "해당 지역(시/군/구)을 찾을 수 없습니다."),
15+
UNAUTHORIZED_MAP_ACCESS(HttpStatus.FORBIDDEN, "지도 리소스에 대한 권한이 없습니다.")
16+
;
17+
18+
private final HttpStatus httpStatus;
19+
private final String message;
20+
21+
@Override
22+
public HttpStatus getHttpStatus() {
23+
return httpStatus;
24+
}
25+
26+
@Override
27+
public String getErrorMessage() {
28+
return message;
29+
}
30+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.example.log4u.domain.map.exception;
2+
3+
import com.example.log4u.common.exception.base.ErrorCode;
4+
import com.example.log4u.common.exception.base.ServiceException;
5+
6+
public class MapException extends ServiceException {
7+
public MapException(ErrorCode errorCode) {
8+
super(errorCode);
9+
}
10+
}

0 commit comments

Comments
 (0)