Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

M3-382 픽셀 클러스터링 집계 #88

Merged
merged 26 commits into from
Oct 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
af3fa6b
M3-382 Feat : Region 엔티티 생성
koomin1227 Sep 30, 2024
5276db3
M3-382 Feat : Region repository 생성
koomin1227 Sep 30, 2024
cc51dea
M3-382 Feat : 클러스터링 된 응답 dto 구현
koomin1227 Sep 30, 2024
be8f330
M3-382 Feat : 반경에 속한 지역 조회 쿼리 작성
koomin1227 Sep 30, 2024
c942c1d
M3-382 Feat : 개인전 클러스터된 정보 반환하는 서비스 구현
koomin1227 Sep 30, 2024
c609a74
M3-382 Feat : 개인전 클러스터된 정보 반환하는 api 구현
koomin1227 Sep 30, 2024
a246689
M3-382 Feat : 클러스터 반환 로직 수정
koomin1227 Sep 30, 2024
8fa0859
M3-382 Feat : 경쟁 모드에서 집계 개수를 담을 CompetitionCount 생성
koomin1227 Oct 1, 2024
3c5d7e3
M3-382 Feat : Pixel에 region 컬럼 추가
koomin1227 Oct 1, 2024
565cb53
M3-382 Feat : 지역 별 픽셀 개수 조회 쿼리 수정
koomin1227 Oct 1, 2024
47832ba
M3-382 Feat : 개인전 클러스터링 조회 수정
koomin1227 Oct 1, 2024
f9004a6
M3-382 Feat : 그룹전 클러스터링 구현
koomin1227 Oct 1, 2024
bab472d
M3-382 Feat : 불필요한 GROUP BY 삭제
koomin1227 Oct 2, 2024
f73c115
M3-382 Feat : 네이버 대신 자체 서버로 리버스 지오코딩 로직 변경
koomin1227 Oct 2, 2024
e47bdb9
M3-382 Feat : CompetitionCountRepository 생성
koomin1227 Oct 2, 2024
117f79b
M3-382 Feat : 픽셀 점령 요청시 이번주에 최초 방문이면 지역별로 개수를 늘리는 기능 추가
koomin1227 Oct 2, 2024
5dda1d3
M3-382 Feat : 지역별 개인 기록 집계 엔티티 생성
koomin1227 Oct 2, 2024
7d06ea3
M3-382 Feat : 네이버 api 에 주소 받아오는 로직 삭제
koomin1227 Oct 2, 2024
6eec077
M3-382 Feat : 개인기록 지역별 집계기록 가져오는 쿼리 구현
koomin1227 Oct 2, 2024
3cdef16
M3-382 Feat : 지역별 개인기록 현황을 조회하는 메서드 구현 및 api 완성
koomin1227 Oct 2, 2024
91df65f
M3-382 Feat : 픽셀 점령시 지역별 개인 기록도 업데이트 하는 로직 추가
koomin1227 Oct 2, 2024
fd6d867
M3-382 Test : test 수정
koomin1227 Oct 3, 2024
519617f
Merge branch 'develop' into feature/M3-382-pixelClustering
koomin1227 Oct 3, 2024
af78023
M3-382 Test : 환경변수 추가
koomin1227 Oct 6, 2024
d09194c
M3-382 Chore : cd 스크립트 수정
koomin1227 Oct 6, 2024
78b391b
M3-382 Feat : 깃 충돌 해결
koomin1227 Oct 6, 2024
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/cd_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
echo "APPLE_PRIVATE_KEY=${{ secrets.APPLE_PRIVATE_KEY }}" >> .env
echo "LATEST_VERSION=${{ secrets.LATEST_VERSION }}" >> .env
echo "FORCE_UPDATE_VERSION=${{ secrets.FORCE_UPDATE_VERSION }}" >> .env
echo "GEOCODING_API=${{ secrets.GEOCODING_API }}" >> .env
echo "SPRING_PROFILES_ACTIVE=dev" >> .env
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/cd_prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
echo "APPLE_PRIVATE_KEY=${{ secrets.APPLE_PRIVATE_KEY }}" >> .env
echo "LATEST_VERSION=${{ secrets.LATEST_VERSION_PROD }}" >> .env
echo "FORCE_UPDATE_VERSION=${{ secrets.FORCE_UPDATE_VERSION_PROD }}" >> .env
echo "GEOCODING_API=${{ secrets.GEOCODING_API }}" >> .env
- name: gradlew에 실행 권한 부여
run: chmod +x ./gradlew
Expand Down
53 changes: 53 additions & 0 deletions src/main/java/com/m3pro/groundflip/controller/PixelController.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.springframework.web.bind.annotation.RestController;

import com.m3pro.groundflip.domain.dto.Response;
import com.m3pro.groundflip.domain.dto.pixel.ClusteredPixelCount;
import com.m3pro.groundflip.domain.dto.pixel.CommunityModePixelResponse;
import com.m3pro.groundflip.domain.dto.pixel.CommunityPixelInfoResponse;
import com.m3pro.groundflip.domain.dto.pixel.IndividualHistoryPixelResponse;
Expand All @@ -23,6 +24,7 @@
import com.m3pro.groundflip.domain.dto.pixelUser.IndividualHistoryPixelInfoResponse;
import com.m3pro.groundflip.service.PixelManager;
import com.m3pro.groundflip.service.PixelReader;
import com.m3pro.groundflip.service.RegionService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand All @@ -44,6 +46,7 @@
public class PixelController {
private final PixelManager pixelManager;
private final PixelReader pixelReader;
private final RegionService regionService;

@Operation(summary = "개인전 픽셀 조회", description = "특정 좌표를 중심으로 반경 내 개인전 픽셀 정보를 조회 API")
@Parameters({
Expand Down Expand Up @@ -165,6 +168,56 @@ public Response<PixelCountResponse> getCommunityPixelCount(
return Response.createSuccess(pixelReader.getCommunityPixelCount(communityId));
}

@Operation(summary = "개인전 클러스터링된 픽셀 조회", description = "특정 좌표를 중심으로 반경 내 개인전 클러스터링된 픽셀 정보 API")
@Parameters({
@Parameter(name = "current-latitude", description = "원의 중심 좌표의 위도", example = "37.503717"),
@Parameter(name = "current-longitude", description = "원의 중심 좌표의 경도", example = "127.044317"),
@Parameter(name = "radius", description = "미터 단위의 반경", example = "1000"),
})
@GetMapping("/individual-mode/clustered")
public Response<List<ClusteredPixelCount>> getNearIndividualClusteredPixels(
@RequestParam(name = "current-latitude") @Min(-90) @Max(90) double currentLatitude,
@RequestParam(name = "current-longitude") @Min(-180) @Max(180) double currentLongitude,
@RequestParam(name = "radius") @Min(0) int radius) {

return Response.createSuccess(
regionService.getIndividualModeClusteredPixelCount(currentLatitude, currentLongitude, radius));
}

@Operation(summary = "개인기록 클러스터링된 픽셀 조회", description = "특정 좌표를 중심으로 반경 내 개인기록 클러스터링된 픽셀 정보 API")
@Parameters({
@Parameter(name = "current-latitude", description = "원의 중심 좌표의 위도", example = "37.503717"),
@Parameter(name = "current-longitude", description = "원의 중심 좌표의 경도", example = "127.044317"),
@Parameter(name = "radius", description = "미터 단위의 반경", example = "1000"),
@Parameter(name = "user-id", description = "찾고자 하는 user의 id", example = "127"),
})
@GetMapping("/individual-history/clustered")
public Response<List<ClusteredPixelCount>> getNearIndividualHistoryClusteredPixels(
@RequestParam(name = "current-latitude") @Min(-90) @Max(90) double currentLatitude,
@RequestParam(name = "current-longitude") @Min(-180) @Max(180) double currentLongitude,
@RequestParam(name = "radius") @Min(0) int radius,
@RequestParam(name = "user-id") @NotNull() Long userId) {

return Response.createSuccess(
regionService.getIndividualHistoryClusteredPixelCount(currentLatitude, currentLongitude, radius, userId));
}

@Operation(summary = "그룹전 클러스터링된 픽셀 조회", description = "특정 좌표를 중심으로 반경 내 그룹전 클러스터링된 픽셀 정보를 조회 API")
@Parameters({
@Parameter(name = "current-latitude", description = "원의 중심 좌표의 위도", example = "37.503717"),
@Parameter(name = "current-longitude", description = "원의 중심 좌표의 경도", example = "127.044317"),
@Parameter(name = "radius", description = "미터 단위의 반경", example = "1000"),
})
@GetMapping("/community-mode/clustered")
public Response<List<ClusteredPixelCount>> getNearCommunityClusteredPixels(
@RequestParam(name = "current-latitude") @Min(-90) @Max(90) double currentLatitude,
@RequestParam(name = "current-longitude") @Min(-180) @Max(180) double currentLongitude,
@RequestParam(name = "radius") @Min(0) int radius) {

return Response.createSuccess(
regionService.getCommunityModeClusteredPixelCount(currentLatitude, currentLongitude, radius));
}

@Operation(summary = "주간 픽셀 개수 조회", description = "특정 유저의 주간 방문한 픽셀을 조회하는 api")
@GetMapping("/count/daily/{userId}")
public Response<List<Integer>> getDailyPixel(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.m3pro.groundflip.domain.dto.pixel;

import com.m3pro.groundflip.enums.RegionLevel;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Schema()
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class ClusteredPixelCount {
@Schema(description = "지역 ID", example = "1234")
private Long regionId;

@Schema(description = "지역 이름", example = "홍길동")
private String regionName;

@Schema(description = "지역별 픽셀 개수", example = "3")
private int count;

@Schema(description = "지역의 중심 위도", example = "37.6464")
private double latitude;

@Schema(description = "지역의 중심 경도", example = "127.6897")
private double longitude;

@Schema(description = "집계 단위", example = "127.6897")
private RegionLevel regionLevel;

public static ClusteredPixelCount from(Long regionId, String regionName, int count, double latitude,
double longitude, RegionLevel regionLevel) {
return ClusteredPixelCount.builder()
.regionId(regionId)
.regionName(regionName)
.count(count)
.latitude(latitude)
.longitude(longitude)
.regionLevel(regionLevel)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.m3pro.groundflip.domain.dto.pixel;

public interface RegionInfo {
Long getRegionId();

double getLatitude();

double getLongitude();

String getName();

Integer getCount();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.m3pro.groundflip.domain.dto.pixel.naverApi;

import com.fasterxml.jackson.annotation.JsonProperty;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@Schema(title = "네이버 api json 결과")
public class ReverseGeocodingResult {
@JsonProperty("region")
private String regionName;

@JsonProperty("region_id")
private Long regionId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.m3pro.groundflip.domain.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class CompetitionCount {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "competition_count_id")
private Long id;

private Integer individualModeCount;

private Integer communityModeCount;

private Integer year;

private Integer week;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "region_id")
private Region region;

public void increaseIndividualModeCount() {
this.individualModeCount++;
}

public void increaseCommunityModeCount() {
this.communityModeCount++;
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/m3pro/groundflip/domain/entity/Pixel.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand Down Expand Up @@ -39,6 +42,10 @@ public class Pixel {

private Long communityId;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "region_id")
private Region region;

private LocalDateTime createdAt;

private LocalDateTime userOccupiedAt;
Expand Down
41 changes: 41 additions & 0 deletions src/main/java/com/m3pro/groundflip/domain/entity/Region.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.m3pro.groundflip.domain.entity;

import org.locationtech.jts.geom.Point;

import com.m3pro.groundflip.domain.entity.global.BaseTimeEntity;
import com.m3pro.groundflip.enums.RegionLevel;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class Region extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "region_id")
private Long id;

private String name;

private Long parentId;

@Column(columnDefinition = "POINT SRID 4326 NOT NULL")
private Point coordinate;

@Enumerated(EnumType.STRING)
private RegionLevel regionLevel;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.m3pro.groundflip.domain.entity;

import com.m3pro.groundflip.domain.entity.global.BaseTimeEntity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class UserRegionCount extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_region_count_id")
private Long id;

private Integer count;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "region_id")
private Region region;

public void increaseCount() {
this.count++;
}
}
13 changes: 13 additions & 0 deletions src/main/java/com/m3pro/groundflip/enums/RegionLevel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.m3pro.groundflip.enums;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public enum RegionLevel {
CITY("city"),
PROVINCE("PROVINCE");

private final String level;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.m3pro.groundflip.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.m3pro.groundflip.domain.entity.CompetitionCount;
import com.m3pro.groundflip.domain.entity.Region;

public interface CompetitionCountRepository extends JpaRepository<CompetitionCount, Long> {
@Query("SELECT c FROM CompetitionCount c WHERE c.region = :id AND c.week = :week AND c.year = :year")
Optional<CompetitionCount> findByRegion(
@Param("id") Region region,
@Param("week") int week,
@Param("year") int year
);
}
Loading
Loading