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
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ dependencies {

// S2
implementation 'com.github.google:s2-geometry-library-java:2.0.0'
implementation 'org.hibernate.orm:hibernate-spatial'
implementation 'org.locationtech.jts:jts-core:1.19.0'

// QueryDSL
implementation "com.querydsl:querydsl-jpa:5.0.0:jakarta"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.knu.ddip.ddipevent.application.dto.*;
import com.knu.ddip.ddipevent.domain.DdipEvent;
import com.knu.ddip.ddipevent.exception.DdipNotFoundException;
import com.knu.ddip.ddipevent.application.util.DistanceConverter;
import com.knu.ddip.user.business.dto.UserEntityDto;
import com.knu.ddip.user.business.service.UserRepository;
import lombok.RequiredArgsConstructor;
Expand All @@ -19,6 +20,7 @@ public class DdipService {

private final DdipEventRepository ddipEventRepository;
private final UserRepository userRepository;
private final DistanceConverter distanceConverter;

@Transactional
public DdipEventDetailDto createDdipEvent(CreateDdipRequestDto dto, UUID requesterId) {
Expand All @@ -35,7 +37,7 @@ public List<DdipEventSummaryDto> getDdipEventFeed(FeedRequestDto dto) {
dto.sw_lat(), dto.sw_lon(), dto.ne_lat(), dto.ne_lon(), dto.sort(), dto.user_lat(), dto.user_lon());

return events.stream()
.map(this::convertToSummaryDto)
.map(event -> convertToSummaryDto(event, dto.user_lat(), dto.user_lon()))
.toList();
}

Expand All @@ -45,8 +47,8 @@ public DdipEventDetailDto getDdipEventDetail(UUID ddipId) {
return convertToDetailDto(event);
}

private DdipEventSummaryDto convertToSummaryDto(DdipEvent event) {
// TODO: distance(요청자와 사용자 사이의 거리) 계산 로직 추가
private DdipEventSummaryDto convertToSummaryDto(DdipEvent event, Double userLat, Double userLon) {
double dist = distanceConverter.haversineMeters(event.getLatitude(), event.getLongitude(), userLat, userLon);
return new DdipEventSummaryDto(
event.getId().toString(),
event.getTitle(),
Expand All @@ -58,7 +60,7 @@ private DdipEventSummaryDto convertToSummaryDto(DdipEvent event) {
event.getCreatedAt().toString(),
event.getApplicants().size(),
event.getContent(),
0.0, // 임시값으로 0.0
dist,
event.getDifficulty()
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.knu.ddip.ddipevent.application.util;

import org.springframework.stereotype.Component;

@Component
public class DistanceConverter {

private final double EARTH_RADIUS_M = 6_371_000.0;

public double haversineMeters(double lat1, double lon1, double lat2, double lon2) {
double phi1 = Math.toRadians(lat1);
double phi2 = Math.toRadians(lat2);
double dPhi = Math.toRadians(lat2 - lat1);
double dLambda = Math.toRadians(lon2 - lon1);

double a = Math.sin(dPhi / 2) * Math.sin(dPhi / 2)
+ Math.cos(phi1) * Math.cos(phi2)
* Math.sin(dLambda / 2) * Math.sin(dLambda / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return EARTH_RADIUS_M * c;
}
}
1 change: 0 additions & 1 deletion src/main/java/com/knu/ddip/ddipevent/domain/DdipEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ public class DdipEvent {
private final UUID requesterId;
private final Double latitude;
private final Double longitude;
private final String cellId;
private final Instant createdAt;
private String title;
private String content;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,24 @@
import com.knu.ddip.ddipevent.infrastructure.entity.DdipEventEntity;
import com.knu.ddip.ddipevent.infrastructure.entity.InteractionEntity;
import com.knu.ddip.ddipevent.infrastructure.entity.PhotoEntity;
import com.knu.ddip.location.application.util.S2Converter;
import lombok.RequiredArgsConstructor;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.PrecisionModel;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@RequiredArgsConstructor
public class DdipMapper {

private final S2Converter s2Converter;
public static final int SRID = 4326;
private GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), SRID);

public DdipEventEntity toEntity(DdipEvent domain) {
DdipEventEntity entity = buildDdipEventEntity(domain);
entity.setPhotos(mapPhotos(domain.getPhotos(), entity));
entity.setInteractions(mapInteractions(domain.getInteractions(), entity));
entity.setCellId(s2Converter.toCellIdString(domain.getLatitude(),domain.getLongitude()));
entity.setLocalPoint(geometryFactory.createPoint(new Coordinate(domain.getLongitude(), domain.getLatitude())));
return entity;
}

Expand Down Expand Up @@ -87,7 +88,6 @@ public DdipEvent toDomain(DdipEventEntity entity) {
.reward(entity.getReward())
.latitude(entity.getLatitude())
.longitude(entity.getLongitude())
.cellId(entity.getCellId())
.createdAt(entity.getCreatedAt())
.status(entity.getStatus())
.selectedResponderId(entity.getSelectedResponderId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.annotations.UuidGenerator;
import org.hibernate.type.SqlTypes;
import org.locationtech.jts.geom.Point;

import java.time.Instant;
import java.util.List;
Expand Down Expand Up @@ -44,9 +45,9 @@ public class DdipEventEntity {
@Column(nullable = false)
private Double longitude;

@Column(nullable = false)
@Column(name = "local_point", columnDefinition = "POINT SRID 4326", nullable = false)
@Setter
private String cellId;
private Point localPoint;

@Column(nullable = false)
private Instant createdAt;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@

import com.knu.ddip.ddipevent.infrastructure.entity.DdipEventEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.UUID;

public interface DdipEventJpaRepository extends JpaRepository<DdipEventEntity, UUID> {
List<DdipEventEntity> findAllByCellIdIn(List<String> cellIds);
@Query(value = """
SELECT * FROM ddip_event
WHERE ST_CONTAINS(ST_Buffer(ST_SRID(POINT(:lng, :lat), 4326), :dist), local_point)
ORDER BY ST_Distance_Sphere(ST_SRID(POINT(:lng, :lat), 4326), local_point)
""", nativeQuery = true)
List<DdipEventEntity> findAllByDistance(@Param("lng") Double lng, @Param("lat") Double lat, @Param("dist") Double dist);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@

import com.knu.ddip.ddipevent.application.service.DdipEventRepository;
import com.knu.ddip.ddipevent.domain.DdipEvent;
import com.knu.ddip.ddipevent.domain.DdipStatus;
import com.knu.ddip.ddipevent.infrastructure.DdipMapper;
import com.knu.ddip.ddipevent.infrastructure.entity.DdipEventEntity;
import com.knu.ddip.location.application.service.LocationService;
import com.knu.ddip.ddipevent.application.util.DistanceConverter;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
Expand All @@ -23,8 +21,7 @@ public class DdipEventRepositoryImpl implements DdipEventRepository {

private final DdipEventJpaRepository ddipEventJpaRepository;
private final DdipMapper ddipMapper;

private final LocationService locationService;
private final DistanceConverter distanceConverter;

@Transactional
@Override
Expand All @@ -41,21 +38,33 @@ public Optional<DdipEvent> findById(UUID id) {

@Override
public List<DdipEvent> findWithinBounds(double swLat, double swLon, double neLat, double neLon, String sort, Double userLat, Double userLon) {
List<String> cellIds = locationService.getNeighborCellIdsToRetrieveNearDdipRequest(swLat, swLon, neLat, neLon);
double dist = boundingBoxRadiusMeters(swLat, swLon, neLat, neLon, userLat, userLon);

return ddipEventJpaRepository.findAllByDistance(userLon, userLat, dist).stream()
.map(ddipMapper::toDomain)
.toList();
}

List<DdipEventEntity> ddipEventEntities = ddipEventJpaRepository.findAllByCellIdIn(cellIds);
private double boundingBoxRadiusMeters(double swLat, double swLon, double neLat, double neLon, Double userLat, Double userLon) {
double[][] locations = new double[][]{
{swLat, swLon},
{neLat, neLon},

Comparator<DdipEventEntity> comparator = (o1, o2) -> {
double dist1 = Math.pow(userLat - o1.getLatitude(), 2) + Math.pow(userLon - o1.getLongitude(), 2);
double dist2 = Math.pow(userLat - o2.getLatitude(), 2) + Math.pow(userLon - o2.getLongitude(), 2);
return dist1 - dist2 >= 0 ? 1 : -1;
{neLat, swLon},
{swLat, neLon},

{neLat, userLon},
{swLat, userLon},

{userLat, neLon},
{userLat, swLon},
};

// 유저와 이벤트 거리 비교해서 거리 가까운 순 정렬
return ddipEventEntities.stream()
.filter(event -> event.getStatus().equals(DdipStatus.OPEN))
.sorted(comparator)
.map(ddipMapper::toDomain)
.toList();
double maxDist = -1;
for (double[] location : locations) {
double dist = distanceConverter.haversineMeters(userLat, userLon, location[0], location[1]);
maxDist = Math.max(maxDist, dist);
}
return maxDist;
}
}
8 changes: 4 additions & 4 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ spring.data.redis.port=${REDIS_PORT}
spring.data.redis.password=${REDIS_PASSWORD}

# JPA
#spring.jpa.properties.hibernate.format_sql=true
#spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
spring.sql.init.mode=always
spring.jpa.defer-datasource-initialization=true
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
#spring.jpa.properties.hibernate.default_batch_fetch_size=1000 # TODO: ????. ?? ????
spring.jpa.properties.hibernate.default_batch_fetch_size=1000
1 change: 1 addition & 0 deletions src/main/resources/sql/spatial_index.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE SPATIAL INDEX idx_ddip_event_local_point ON ddip_event (local_point);
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.knu.ddip.ddipevent.domain.DdipEvent;
import com.knu.ddip.ddipevent.domain.DdipStatus;
import com.knu.ddip.ddipevent.exception.DdipNotFoundException;
import com.knu.ddip.ddipevent.application.util.DistanceConverter;
import com.knu.ddip.user.business.dto.UserEntityDto;
import com.knu.ddip.user.business.service.UserRepository;
import org.junit.jupiter.api.DisplayName;
Expand Down Expand Up @@ -40,6 +41,9 @@ class DdipServiceTest {
@Mock
private UserRepository userRepository;

@Mock
private DistanceConverter distanceConverter;

@DisplayName("띱 이벤트 생성 성공")
@Test
void givenCreateDdipRequest_whenCreateDdipEvent_thenDdipEventDetailDtoIsReturned() {
Expand Down Expand Up @@ -86,6 +90,8 @@ void givenFeedRequest_whenGetDdipEventFeed_thenListOfDdipEventSummaryDtoIsReturn
.requesterId(UUID.randomUUID())
.createdAt(Instant.now())
.applicants(new ArrayList<>())
.latitude(0.0)
.longitude(0.0)
.build();
List<DdipEvent> events = List.of(ddipEvent);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public static DdipEventEntity createDdipEvent(Double lat, Double lon, DdipStatus
.reward(1)
.status(status)
.title("title")
.cellId(cellId)
.build();
return event;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ class DdipMapperTest {

@BeforeEach
void setUp() {
S2Converter s2Converter = new S2Converter();
ddipMapper = new DdipMapper(s2Converter);
ddipMapper = new DdipMapper();
}

@DisplayName("도메인을 엔티티로 변환 - 모든 필드 포함")
Expand Down

This file was deleted.

Loading
Loading