-
Notifications
You must be signed in to change notification settings - Fork 1
[BUILD FAIL] Feature/49 봉사 모집글 조회 기능 #72
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
Changes from all commits
65226d3
7585a2e
4167c57
0799ec0
81303be
de3a4fa
594c200
4a31b23
85fa126
9990908
b42fb0f
5157d67
fc4e571
51ffdff
da9dfd7
8315364
56019c1
5dd55e3
5d1d480
624e132
420c61f
a93b332
c27b961
b737683
a8afe60
e2bfae0
2974fc8
9ba4cb6
3ee132e
a04afbd
8609f23
38795fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package com.somemore.center.dto.response; | ||
|
|
||
| import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; | ||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
| import com.somemore.center.domain.Center; | ||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import java.util.UUID; | ||
| import lombok.Builder; | ||
|
|
||
| @Builder | ||
| @JsonNaming(SnakeCaseStrategy.class) | ||
| @Schema(description = "기관 정보 응답 DTO") | ||
| public record CenterSimpleInfoResponseDto( | ||
| @Schema(description = "기관 아이디", example = "123e4567-e89b-12d3-a456-426614174000") | ||
| UUID id, | ||
| @Schema(description = "기관 이름", example = "환경 봉사 센터") | ||
| String name | ||
| ) { | ||
|
|
||
| public static CenterSimpleInfoResponseDto from(Center center) { | ||
| return CenterSimpleInfoResponseDto.builder() | ||
| .id(center.getId()) | ||
| .name(center.getName()) | ||
| .build(); | ||
| } | ||
|
|
||
| public static CenterSimpleInfoResponseDto of(UUID centerId, String name) { | ||
| return CenterSimpleInfoResponseDto.builder() | ||
| .id(centerId) | ||
| .name(name) | ||
| .build(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| package com.somemore.location.dto.response; | ||
|
|
||
| import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; | ||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||
| import com.somemore.location.domain.Location; | ||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import java.math.BigDecimal; | ||
| import lombok.Builder; | ||
|
|
||
| @Builder | ||
| @JsonNaming(SnakeCaseStrategy.class) | ||
| @Schema(description = "위치 조회 응답 DTO") | ||
| public record LocationResponseDto( | ||
| @Schema(description = "주소", example = "서울특별시 강남구 테헤란로 123") | ||
| String address, | ||
| @Schema(description = "위도", example = "37.5665") | ||
| BigDecimal latitude, | ||
| @Schema(description = "경도", example = "126.9780") | ||
| BigDecimal longitude | ||
| ) { | ||
|
|
||
| public static LocationResponseDto from(Location location) { | ||
| return LocationResponseDto.builder() | ||
| .address(location.getAddress()) | ||
| .latitude(location.getLatitude()) | ||
| .longitude(location.getLongitude()) | ||
| .build(); | ||
| } | ||
|
|
||
| public static LocationResponseDto of(String address, BigDecimal latitude, | ||
| BigDecimal longitude) { | ||
| return LocationResponseDto.builder() | ||
| .address(address) | ||
| .latitude(latitude) | ||
| .longitude(longitude) | ||
| .build(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,9 @@ | ||
| package com.somemore.location.usecase.query; | ||
|
|
||
| import com.somemore.location.domain.Location; | ||
| import java.util.Optional; | ||
|
|
||
| public interface LocationQueryUseCase { | ||
|
|
||
| Optional<Location> findById(Long id); | ||
| Location getById(Long id); | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package com.somemore.location.utils; | ||
|
|
||
| import static lombok.AccessLevel.PRIVATE; | ||
|
|
||
| import lombok.NoArgsConstructor; | ||
|
|
||
| @NoArgsConstructor(access = PRIVATE) | ||
| public class GeoUtils { | ||
|
|
||
| private static final double EARTH_RADIUS = 6371.0; | ||
|
|
||
| public static double[] calculateMaxMinCoordinates(double latitude, double longitude, | ||
| double radius) { | ||
| double latRad = Math.toRadians(latitude); | ||
| double latDiff = radius / EARTH_RADIUS; | ||
| double maxLatRad = latRad + latDiff; | ||
| double minLatRad = latRad - latDiff; | ||
|
|
||
| double maxLat = Math.toDegrees(maxLatRad); | ||
| double minLat = Math.toDegrees(minLatRad); | ||
|
|
||
| double lonDiff = radius / (EARTH_RADIUS * Math.cos(latRad)); | ||
| double maxLon = longitude + Math.toDegrees(lonDiff); | ||
| double minLon = longitude - Math.toDegrees(lonDiff); | ||
|
|
||
| return new double[]{minLat, minLon, maxLat, maxLon}; | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| package com.somemore.recruitboard.controller; | ||
|
|
||
| import static org.springframework.data.domain.Sort.Direction.DESC; | ||
|
|
||
| import com.somemore.global.common.response.ApiResponse; | ||
| import com.somemore.recruitboard.domain.RecruitStatus; | ||
| import com.somemore.recruitboard.domain.VolunteerType; | ||
| import com.somemore.recruitboard.dto.condition.RecruitBoardNearByCondition; | ||
| import com.somemore.recruitboard.dto.condition.RecruitBoardSearchCondition; | ||
| import com.somemore.recruitboard.dto.response.RecruitBoardDetailResponseDto; | ||
| import com.somemore.recruitboard.dto.response.RecruitBoardResponseDto; | ||
| import com.somemore.recruitboard.dto.response.RecruitBoardWithCenterResponseDto; | ||
| import com.somemore.recruitboard.dto.response.RecruitBoardWithLocationResponseDto; | ||
| import com.somemore.recruitboard.usecase.query.RecruitBoardQueryUseCase; | ||
| import io.swagger.v3.oas.annotations.Operation; | ||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||
| import java.util.UUID; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.data.domain.Page; | ||
| import org.springframework.data.domain.Pageable; | ||
| import org.springframework.data.web.PageableDefault; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RequestParam; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @Tag(name = "Recruit Board Query API", description = "봉사 활동 모집 조회 관련 API") | ||
| @RequiredArgsConstructor | ||
| @RequestMapping("/api") | ||
| @RestController | ||
| public class RecruitBoardQueryController { | ||
|
|
||
| private final RecruitBoardQueryUseCase recruitBoardQueryUseCase; | ||
|
|
||
| @GetMapping("/recruit-board/{id}") | ||
| @Operation(summary = "봉사 모집글 상세 조회", description = "특정 모집글의 상세 정보를 조회합니다.") | ||
| public ApiResponse<RecruitBoardWithLocationResponseDto> getById( | ||
| @PathVariable Long id | ||
| ) { | ||
| return ApiResponse.ok( | ||
| 200, | ||
| recruitBoardQueryUseCase.getWithLocationById(id), | ||
| "봉사 활동 모집 상세 조회 성공" | ||
| ); | ||
| } | ||
|
|
||
| @GetMapping("/recruit-boards") | ||
| @Operation(summary = "전체 모집글 조회", description = "모든 봉사 모집글 목록을 조회합니다.") | ||
| public ApiResponse<Page<RecruitBoardWithCenterResponseDto>> getAll( | ||
| @PageableDefault(sort = "created_at", direction = DESC) | ||
| Pageable pageable | ||
| ) { | ||
| RecruitBoardSearchCondition condition = RecruitBoardSearchCondition.builder() | ||
| .pageable(pageable) | ||
| .build(); | ||
|
|
||
| return ApiResponse.ok( | ||
| 200, | ||
| recruitBoardQueryUseCase.getAllWithCenter(condition), | ||
| "봉사 활동 모집글 리스트 조회 성공" | ||
| ); | ||
| } | ||
|
|
||
| @GetMapping("/recruit-boards/search") | ||
| @Operation(summary = "모집글 검색 조회", description = "검색 조건을 기반으로 모집글을 조회합니다.") | ||
| public ApiResponse<Page<RecruitBoardWithCenterResponseDto>> getAllBySearch( | ||
| @PageableDefault(sort = "created_at", direction = DESC) Pageable pageable, | ||
| @RequestParam(required = false) String keyword, | ||
| @RequestParam(required = false) VolunteerType type, | ||
| @RequestParam(required = false) String region, | ||
| @RequestParam(required = false) Boolean admitted, | ||
| @RequestParam(required = false) RecruitStatus status | ||
| ) { | ||
| RecruitBoardSearchCondition condition = RecruitBoardSearchCondition.builder() | ||
| .keyword(keyword) | ||
| .type(type) | ||
| .region(region) | ||
| .admitted(admitted) | ||
| .status(status) | ||
| .pageable(pageable) | ||
| .build(); | ||
|
|
||
| return ApiResponse.ok( | ||
| 200, | ||
| recruitBoardQueryUseCase.getAllWithCenter(condition), | ||
| "봉사 활동 모집글 검색 조회 성공" | ||
| ); | ||
| } | ||
|
|
||
| @GetMapping("/recruit-boards/nearby") | ||
| @Operation(summary = "근처 모집글 조회", description = "주변 반경 내의 봉사 모집글을 조회합니다.") | ||
| public ApiResponse<Page<RecruitBoardDetailResponseDto>> getNearby( | ||
| @RequestParam double latitude, | ||
| @RequestParam double longitude, | ||
| @RequestParam(required = false, defaultValue = "5") double radius, | ||
| @RequestParam(required = false) String keyword, | ||
| @PageableDefault(sort = "created_at", direction = DESC) Pageable pageable | ||
| ) { | ||
| RecruitBoardNearByCondition condition = RecruitBoardNearByCondition.builder() | ||
| .latitude(latitude) | ||
| .longitude(longitude) | ||
| .radius(radius) | ||
| .keyword(keyword) | ||
| .pageable(pageable) | ||
| .build(); | ||
|
|
||
| return ApiResponse.ok( | ||
| 200, | ||
| recruitBoardQueryUseCase.getRecruitBoardsNearby(condition), | ||
| "근처 봉사 활동 모집글 조회 성공" | ||
| ); | ||
| } | ||
|
|
||
| @GetMapping("/recruit-boards/center/{centerId}") | ||
| @Operation(summary = "특정 기관 모집글 조회", description = "특정 기관의 봉사 모집글을 조회합니다.") | ||
| public ApiResponse<Page<RecruitBoardResponseDto>> getRecruitBoardsByCenterId( | ||
| @PathVariable UUID centerId, | ||
| @PageableDefault(sort = "created_at", direction = DESC) Pageable pageable, | ||
| @RequestParam(required = false) String keyword, | ||
| @RequestParam(required = false) VolunteerType type, | ||
| @RequestParam(required = false) String region, | ||
| @RequestParam(required = false) Boolean admitted, | ||
| @RequestParam(required = false) RecruitStatus status | ||
| ) { | ||
| RecruitBoardSearchCondition condition = RecruitBoardSearchCondition.builder() | ||
| .keyword(keyword) | ||
| .type(type) | ||
| .region(region) | ||
| .admitted(admitted) | ||
| .status(status) | ||
| .pageable(pageable) | ||
| .build(); | ||
|
|
||
| return ApiResponse.ok( | ||
| 200, | ||
| recruitBoardQueryUseCase.getRecruitBoardsByCenterId(centerId, condition), | ||
| "기관 봉사 활동 모집글 조회 성공" | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package com.somemore.recruitboard.dto.condition; | ||
|
|
||
| import lombok.Builder; | ||
| import org.springframework.data.domain.Pageable; | ||
|
|
||
| @Builder | ||
| public record RecruitBoardNearByCondition( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 컨디션 클래스는 가져올 필드들을 명시하는 클래스인건가요?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 동적 쿼리 파라미터를 위한 레코드 클래스입니다.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RecruitBoardSearchCondition 레코드 클래스 보시는게 더 이해하시기 좋을거에요 |
||
| Double latitude, | ||
| Double longitude, | ||
| Double radius, | ||
| String keyword, | ||
| Pageable pageable | ||
| ) { | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package com.somemore.recruitboard.dto.condition; | ||
|
|
||
| import com.somemore.recruitboard.domain.RecruitStatus; | ||
| import com.somemore.recruitboard.domain.VolunteerType; | ||
| import lombok.Builder; | ||
| import org.springframework.data.domain.Pageable; | ||
|
|
||
| @Builder | ||
| public record RecruitBoardSearchCondition( | ||
| String keyword, | ||
| VolunteerType type, | ||
| String region, | ||
| Boolean admitted, | ||
| RecruitStatus status, | ||
| Pageable pageable | ||
| ) { | ||
|
|
||
| } |
Uh oh!
There was an error while loading. Please reload this page.