#26 pharmacy: direction service - haversine formula
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
package com.example.road.direction.entity;
|
||||
|
||||
import com.example.road.BaseTimeEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity(name = "direction")
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Getter
|
||||
public class Direction extends BaseTimeEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
// 고객
|
||||
private String inputAddress;
|
||||
private double inputLatitude;
|
||||
private double inputLongitude;
|
||||
|
||||
// 약국
|
||||
private String targetPharmacyName;
|
||||
private String targetAddress;
|
||||
private double targetLatitude;
|
||||
private double targetLongitude;
|
||||
|
||||
// 거리
|
||||
private double distance;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.example.road.direction.service;
|
||||
|
||||
import com.example.road.api.dto.DocumentDto;
|
||||
import com.example.road.direction.entity.Direction;
|
||||
import com.example.road.pharmacy.service.PharmacySearchService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DirectionService {
|
||||
|
||||
private static final int MAX_SEARCH_COUNT = 3;
|
||||
private static final double RADIUS_KM = 10.0;
|
||||
|
||||
private final PharmacySearchService pharmacySearchService;
|
||||
|
||||
public List<Direction> buildDirectionList(DocumentDto documentDto) {
|
||||
|
||||
if (Objects.isNull(documentDto)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return pharmacySearchService.searchPharmacyDtoList()
|
||||
.stream().map(pharmacyDto ->
|
||||
Direction.builder()
|
||||
.inputAddress(documentDto.getAddressName())
|
||||
.inputLatitude(documentDto.getLatitude())
|
||||
.inputLongitude(documentDto.getLongitude())
|
||||
.targetPharmacyName(pharmacyDto.getPharmacyName())
|
||||
.targetAddress(pharmacyDto.getPharmacyAddress())
|
||||
.targetLatitude(pharmacyDto.getLatitude())
|
||||
.targetLongitude(pharmacyDto.getLongitude())
|
||||
.distance(
|
||||
calculateDistance(
|
||||
documentDto.getLatitude(), documentDto.getLongitude(),
|
||||
pharmacyDto.getLatitude(), pharmacyDto.getLongitude()
|
||||
)
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.filter(direction -> direction.getDistance() <= RADIUS_KM)
|
||||
.sorted(Comparator.comparing(Direction::getDistance))
|
||||
.limit(MAX_SEARCH_COUNT)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// Haversine formula
|
||||
private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
|
||||
lat1 = Math.toRadians(lat1);
|
||||
lon1 = Math.toRadians(lon1);
|
||||
lat2 = Math.toRadians(lat2);
|
||||
lon2 = Math.toRadians(lon2);
|
||||
|
||||
double earthRadius = 6371; //Kilometers
|
||||
return earthRadius * Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.example.road.pharmacy.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class PharmacyDto {
|
||||
|
||||
private Long id;
|
||||
private String pharmacyName;
|
||||
private String pharmacyAddress;
|
||||
private double latitude;
|
||||
private double longitude;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.example.road.pharmacy.service;
|
||||
|
||||
import com.example.road.pharmacy.dto.PharmacyDto;
|
||||
import com.example.road.pharmacy.entity.Pharmacy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PharmacySearchService {
|
||||
|
||||
private final PharmacyRepositoryService pharmacyRepositoryService;
|
||||
|
||||
public List<PharmacyDto> searchPharmacyDtoList() {
|
||||
|
||||
return pharmacyRepositoryService.findAll()
|
||||
.stream()
|
||||
.map(this::convertToPharmacyDto)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private PharmacyDto convertToPharmacyDto(Pharmacy pharmacy) {
|
||||
return PharmacyDto.builder()
|
||||
.id(pharmacy.getId())
|
||||
.pharmacyAddress(pharmacy.getPharmacyAddress())
|
||||
.pharmacyName(pharmacy.getPharmacyName())
|
||||
.latitude(pharmacy.getLatitude())
|
||||
.longitude(pharmacy.getLongitude())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user