Skip to content

Commit

Permalink
feat: api endpoint to get nearby courses within radius
Browse files Browse the repository at this point in the history
  • Loading branch information
peageon committed Jun 18, 2024
1 parent a2674cd commit 2464044
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package com.runningmate.backend.route.controller;

import com.runningmate.backend.route.dto.RouteListResponseDto;
import com.runningmate.backend.route.dto.RouteRequestDto;
import com.runningmate.backend.route.dto.RouteResponseDto;
import com.runningmate.backend.route.service.RouteService;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.RequiredArgsConstructor;
import org.apache.coyote.BadRequestException;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/courses")
@RequiredArgsConstructor
Expand All @@ -30,4 +35,14 @@ public RouteResponseDto getRouteById(@PathVariable(name = "routeId") Long routeI
RouteResponseDto routeResponseDto = routeService.getRouteById(routeId);
return routeResponseDto;
}

@GetMapping("/radius")
@ResponseStatus(HttpStatus.OK)
public RouteListResponseDto getCourseWithinRadius(@RequestParam(name = "latitude") double latitude,
@RequestParam(name = "longitude") double longitude,
@RequestParam(name = "radius") @Max(5000) @Min(0) int radius) {
List<RouteResponseDto> routeResponseDtoList = routeService.getRoutesWithinRadius(latitude, longitude, radius);

return new RouteListResponseDto(routeResponseDtoList);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.runningmate.backend.route.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class CoordinateDto {
private double latitude;
private double longitude;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.runningmate.backend.route.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.List;

@AllArgsConstructor
@Getter
public class RouteListResponseDto {
@JsonProperty("courses")
private List<RouteResponseDto> routes;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

import com.runningmate.backend.route.Route;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface RouteRepository extends JpaRepository<Route, Long> {
import java.util.List;

public interface RouteRepository extends JpaRepository<Route, Long> {
@Query(value = "SELECT * FROM route r WHERE " +
"ST_DWithin(r.path, ST_SetSRID(ST_MakePoint(:longitude, :latitude), 4326), :radius)", nativeQuery = true)
List<Route> findRoutesWithinRadius(@Param("latitude") double latitude,
@Param("longitude") double longitude,
@Param("radius") int radius);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.runningmate.backend.route.service;

import com.runningmate.backend.exception.BadRequestException;
import com.runningmate.backend.exception.ResourceNotFoundException;
import com.runningmate.backend.member.dto.MemberDto;
import com.runningmate.backend.member.service.MemberService;
Expand All @@ -9,7 +10,6 @@
import com.runningmate.backend.route.dto.RouteResponseDto;
import com.runningmate.backend.route.repository.RouteRepository;
import lombok.RequiredArgsConstructor;
import org.apache.coyote.BadRequestException;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
Expand All @@ -28,7 +28,7 @@ public class RouteService {
private final MemberService memberService;

@Transactional
public RouteResponseDto saveRoute(RouteRequestDto request, String username) throws BadRequestException {
public RouteResponseDto saveRoute(RouteRequestDto request, String username) {
List<CoordinateDto> coordinateDtos = request.getRoute();
validateCoordinates(coordinateDtos);
LineString lineString = coordinateDtoListToLineString(coordinateDtos);
Expand All @@ -44,6 +44,17 @@ public RouteResponseDto getRouteById(Long routeId) {
return new RouteResponseDto(route, translatedCoordinates);
}

public List<RouteResponseDto> getRoutesWithinRadius(double latitude, double longitude, int radius) {
validateCoordinate(new CoordinateDto(latitude, longitude));
List<Route> routes = routeRepository.findRoutesWithinRadius(latitude, longitude, radius);
List<RouteResponseDto> routeDtos = new ArrayList<>();
for (Route route: routes) {
List<CoordinateDto> translatedCoordinates = lineStringToCoordinateDtoList(route.getPath());
routeDtos.add(new RouteResponseDto(route, translatedCoordinates));
}
return routeDtos;
}

private LineString coordinateDtoListToLineString(List<CoordinateDto> coordinateDtos) {
GeometryFactory geometryFactory = new GeometryFactory();
Coordinate[] coordinates = coordinateDtos.stream()
Expand All @@ -64,14 +75,18 @@ private List<CoordinateDto> lineStringToCoordinateDtoList(LineString lineString)
return coordinateDtos;
}

private void validateCoordinates(List<CoordinateDto> coordinateDTOs) throws BadRequestException {
private void validateCoordinate(CoordinateDto coordinateDto) {
if (coordinateDto.getLatitude() < -90 || coordinateDto.getLatitude() > 90) {
throw new BadRequestException("Invalid latitude: " + coordinateDto.getLatitude() + "\n Latitude must be within -90 and 90");
}
if (coordinateDto.getLongitude() < -180 || coordinateDto.getLongitude() > 180) {
throw new BadRequestException("Invalid longitude: " + coordinateDto.getLongitude() + "\n Longitude must be within -180 and 180");
}
}

private void validateCoordinates(List<CoordinateDto> coordinateDTOs) {
for (CoordinateDto dto : coordinateDTOs) {
if (dto.getLatitude() < -90 || dto.getLatitude() > 90) {
throw new BadRequestException("Invalid latitude: " + dto.getLatitude() + "\n Latitude must be within -90 and 90");
}
if (dto.getLongitude() < -180 || dto.getLongitude() > 180) {
throw new BadRequestException("Invalid longitude: " + dto.getLongitude() + "\n Longitude must be within -180 and 180");
}
validateCoordinate(dto);
}
}
}

0 comments on commit 2464044

Please sign in to comment.