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

feat: 가까운 거리순 정렬 기능 추가 #80

Merged
merged 3 commits into from
Nov 12, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@
import com.gamsa.activity.constant.Category;
import com.gamsa.activity.dto.ActivityDetailResponse;
import com.gamsa.activity.dto.ActivityFilterRequest;
import com.gamsa.activity.dto.ActivityFindDistanceOrderRequest;
import com.gamsa.activity.dto.ActivityFindSliceResponse;
import com.gamsa.activity.service.ActivityService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
Expand All @@ -25,9 +31,10 @@ public Slice<ActivityFindSliceResponse> findSlice(
@RequestParam(defaultValue = "false") boolean teenPossibleOnly,
@RequestParam(defaultValue = "false") boolean beforeDeadlineOnly,
@RequestParam(required = false) String keyword,
@RequestBody(required = false) ActivityFindDistanceOrderRequest distanceOrderRequest,
Pageable pageable) {

ActivityFilterRequest request = ActivityFilterRequest.builder()
ActivityFilterRequest filterRequest = ActivityFilterRequest.builder()
.category(Category.fromValuesForSlice(category))
.sidoGunguCode(sidoGunguCode)
.sidoCode(sidoCode)
Expand All @@ -36,7 +43,7 @@ public Slice<ActivityFindSliceResponse> findSlice(
.keyword(keyword)
.build();

return activityService.findSlice(request, pageable);
return activityService.findSlice(filterRequest, distanceOrderRequest, pageable);
}

@GetMapping("{activity-id}")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.gamsa.activity.dto;

import java.math.BigDecimal;
import lombok.Builder;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@Builder
@RequiredArgsConstructor
public class ActivityFindDistanceOrderRequest {

private final BigDecimal latitude;
private final BigDecimal longitude;
private final int distanceKm;

}
22 changes: 17 additions & 5 deletions src/main/java/com/gamsa/activity/entity/ActivityJpaEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,23 @@
import com.gamsa.activity.constant.CategoryConverter;
import com.gamsa.activity.domain.Activity;
import com.gamsa.common.entity.BaseEntity;
import jakarta.persistence.*;
import lombok.*;

import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
Expand Down Expand Up @@ -68,10 +80,10 @@ public class ActivityJpaEntity extends BaseEntity {
@Column(name = "online_possible")
private boolean onlinePossible;

@Column(name = "latitude")
@Column(name = "latitude", precision = 10, scale = 6)
private BigDecimal latitude;

@Column(name = "longitude")
@Column(name = "longitude", precision = 10, scale = 6)
private BigDecimal longitude;

@Column(name = "act_week")
Expand Down
11 changes: 7 additions & 4 deletions src/main/java/com/gamsa/activity/entity/DistrictJpaEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.*;

import java.math.BigDecimal;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
Expand All @@ -25,10 +28,10 @@ public class DistrictJpaEntity extends BaseEntity {
@Column(name = "sido_code", nullable = false)
private int sidoCode;

@Column(name = "latitude")
@Column(name = "latitude", precision = 10, scale = 6)
private BigDecimal latitude;

@Column(name = "longitude")
@Column(name = "longitude", precision = 10, scale = 6)
private BigDecimal longitude;

@Column(name = "sido_name", length = 15, nullable = false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.gamsa.activity.repository;

import com.gamsa.activity.dto.ActivityFilterRequest;
import com.gamsa.activity.dto.ActivityFindDistanceOrderRequest;
import com.gamsa.activity.entity.ActivityJpaEntity;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
Expand All @@ -9,4 +10,8 @@ public interface ActivityCustomRepository {

Slice<ActivityJpaEntity> findSlice(ActivityFilterRequest request, Pageable pageable);

Slice<ActivityJpaEntity> findSliceDistanceOrder(
ActivityFilterRequest filterRequest,
ActivityFindDistanceOrderRequest distanceOrderRequest,
Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@
import static com.gamsa.activity.entity.QActivityJpaEntity.activityJpaEntity;

import com.gamsa.activity.dto.ActivityFilterRequest;
import com.gamsa.activity.dto.ActivityFindDistanceOrderRequest;
import com.gamsa.activity.entity.ActivityJpaEntity;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberTemplate;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
Expand All @@ -37,6 +42,45 @@ public Slice<ActivityJpaEntity> findSlice(ActivityFilterRequest request, Pageabl
return checkLastPage(pageable, results);
}

@Override
public Slice<ActivityJpaEntity> findSliceDistanceOrder(
ActivityFilterRequest filterRequest,
ActivityFindDistanceOrderRequest distanceOrderRequest,
Pageable pageable) {

final double EARTH_RADIUS_KM = 6371.0; // 지구 반지름 (km)
final BigDecimal latitude = distanceOrderRequest.getLatitude();
final BigDecimal longitude = distanceOrderRequest.getLongitude();
final int distanceKm = distanceOrderRequest.getDistanceKm();

BooleanBuilder filterBuilder = ActivityFilterBuilder.createFilter(filterRequest);

// 하버사인 공식 구현
NumberTemplate<Double> distanceExpression = Expressions.numberTemplate(Double.class,
"({0} * acos(cos(radians({1})) * cos(radians({2})) * cos(radians({3}) - radians({4})) + sin(radians({1})) * sin(radians({2}))))",
EARTH_RADIUS_KM,
latitude,
activityJpaEntity.latitude,
longitude,
activityJpaEntity.longitude
);

List<ActivityJpaEntity> results = jpaQueryFactory
.select(activityJpaEntity, distanceExpression.as("distance"))
.from(activityJpaEntity)
.where(filterBuilder.and(distanceExpression.loe(distanceKm)))
.orderBy(distanceExpression.asc())
.orderBy(activityJpaEntity.actId.asc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch()
.stream()
.map(v -> v.get(activityJpaEntity))
.collect(Collectors.toList());

return checkLastPage(pageable, results);
}

// 무한스크롤 처리
private Slice<ActivityJpaEntity> checkLastPage(Pageable pageable,
List<ActivityJpaEntity> results) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.gamsa.activity.domain.Activity;
import com.gamsa.activity.dto.ActivityFilterRequest;
import com.gamsa.activity.dto.ActivityFindDistanceOrderRequest;
import java.util.Optional;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
Expand All @@ -10,7 +11,12 @@ public interface ActivityRepository {

void save(Activity activity);

Slice<Activity> findSlice(ActivityFilterRequest request, Pageable pageable);
Slice<Activity> findSlice(ActivityFilterRequest filterRequest, Pageable pageable);

Slice<Activity> findSliceDistanceOrder(
ActivityFilterRequest filterRequest,
ActivityFindDistanceOrderRequest distanceOrderRequest,
Pageable pageable);

Optional<Activity> findById(Long activityId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.gamsa.activity.domain.Activity;
import com.gamsa.activity.dto.ActivityFilterRequest;
import com.gamsa.activity.dto.ActivityFindDistanceOrderRequest;
import com.gamsa.activity.entity.ActivityJpaEntity;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
Expand All @@ -26,6 +27,16 @@ public Slice<Activity> findSlice(ActivityFilterRequest request, Pageable pageabl
.map(ActivityJpaEntity::toModel);
}

@Override
public Slice<Activity> findSliceDistanceOrder(
ActivityFilterRequest filterRequest,
ActivityFindDistanceOrderRequest distanceOrderRequest,
Pageable pageable) {
return activityJpaRepository.findSliceDistanceOrder(filterRequest, distanceOrderRequest,
pageable)
.map(ActivityJpaEntity::toModel);
}

@Override
public Optional<Activity> findById(Long activityId) {
return activityJpaRepository.findById(activityId)
Expand Down
28 changes: 17 additions & 11 deletions src/main/java/com/gamsa/activity/service/ActivityService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,47 @@
import com.gamsa.activity.domain.Institute;
import com.gamsa.activity.dto.ActivityDetailResponse;
import com.gamsa.activity.dto.ActivityFilterRequest;
import com.gamsa.activity.dto.ActivityFindDistanceOrderRequest;
import com.gamsa.activity.dto.ActivityFindSliceResponse;
import com.gamsa.activity.dto.ActivitySaveRequest;
import com.gamsa.activity.exception.ActivityException;
import com.gamsa.activity.repository.ActivityRepository;
import com.gamsa.activity.repository.DistrictRepository;
import com.gamsa.activity.repository.InstituteRepository;
import com.gamsa.review.dto.QuestionResponse;
import com.gamsa.review.service.QuestionService;
import com.gamsa.review.service.ReviewService;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@RequiredArgsConstructor
@Service
public class ActivityService {

private final ActivityRepository activityRepository;
private final InstituteRepository instituteRepository;
private final DistrictRepository districtRepository;
private final QuestionService questionService;
private final ReviewService reviewService;

public void save(ActivitySaveRequest saveRequest, Institute institute, District district) {
activityRepository.save(saveRequest.toModel(institute, district));
}

public Slice<ActivityFindSliceResponse> findSlice(ActivityFilterRequest request,
Pageable pageable) {
Slice<Activity> activities = activityRepository.findSlice(request, pageable);
public Slice<ActivityFindSliceResponse> findSlice(ActivityFilterRequest filterRequest,
ActivityFindDistanceOrderRequest distanceOrderRequest,
Pageable pageable) {

Slice<Activity> activities;
// 가까운순 정렬
if (pageable.getSort().toString().contains("distance")) {
activities = activityRepository
.findSliceDistanceOrder(filterRequest, distanceOrderRequest, pageable);
} else {
activities = activityRepository.findSlice(filterRequest, pageable);
}

return activities.map(ActivityFindSliceResponse::from);
}

Expand Down
Loading