Skip to content

Commit 65390cc

Browse files
authored
Merge pull request #87 from YAPP-Github/feat/PRODUCT-185
[Feat] 스토리 상세 조회 기능 구현
2 parents 153a16c + a65f46b commit 65390cc

File tree

18 files changed

+413
-121
lines changed

18 files changed

+413
-121
lines changed

.github/workflows/automatic-erd.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ name: ERD to GitHub Pages
22

33
on:
44
pull_request:
5-
branches: [ "**" ]
6-
paths: [ "**" ]
5+
branches: [ "main", "develop" ]
6+
paths: [ "src/main/resources/db/migration/**" ]
77

88
concurrency:
99
group: ${{ github.workflow }}-${{ github.ref }}

.github/workflows/sonarcloud.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ jobs:
1919
steps:
2020
- name: Checkout code
2121
uses: actions/checkout@v4
22+
with:
23+
fetch-depth: 0
2224

2325
- name: Set up Java
2426
uses: actions/setup-java@v3

.github/workflows/terraform-plan.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ name: Terraform Plan on PR
22

33
on:
44
pull_request:
5-
branches:
6-
- main
7-
- develop
5+
branches: [ "main", "develop" ]
6+
paths: [ "terraform/**", "terraform-bootstrap/**" ]
87

98
permissions:
109
contents: read

src/main/java/eatda/controller/story/FilteredSearchResult.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
public record FilteredSearchResult(
44
String kakaoId,
55
String name,
6-
String address,
6+
String roadAddress,
7+
String lotNumberAddress,
78
String category
89
) {
910
}

src/main/java/eatda/controller/story/StoryController.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
import eatda.controller.web.auth.LoginMember;
44
import eatda.service.story.StoryService;
5+
import jakarta.validation.constraints.Max;
6+
import jakarta.validation.constraints.Min;
57
import lombok.RequiredArgsConstructor;
68
import org.springframework.http.HttpStatus;
79
import org.springframework.http.ResponseEntity;
810
import org.springframework.web.bind.annotation.GetMapping;
11+
import org.springframework.web.bind.annotation.PathVariable;
912
import org.springframework.web.bind.annotation.PostMapping;
13+
import org.springframework.web.bind.annotation.RequestParam;
1014
import org.springframework.web.bind.annotation.RequestPart;
1115
import org.springframework.web.bind.annotation.RestController;
1216
import org.springframework.web.multipart.MultipartFile;
@@ -28,8 +32,14 @@ public ResponseEntity<Void> registerStory(
2832
}
2933

3034
@GetMapping("api/stories")
31-
public ResponseEntity<StoriesResponse> getStories() {
35+
public ResponseEntity<StoriesResponse> getStories(@RequestParam(defaultValue = "5") @Min(1) @Max(50) int size) {
3236
return ResponseEntity.status(HttpStatus.OK)
33-
.body(storyService.getPagedStoryPreviews());
37+
.body(storyService.getPagedStoryPreviews(size));
38+
}
39+
40+
@GetMapping("/api/stories/{storyId}")
41+
public ResponseEntity<StoryResponse> getStory(@PathVariable long storyId) {
42+
return ResponseEntity.status(HttpStatus.OK)
43+
.body(storyService.getStory(storyId));
3444
}
3545
}

src/main/java/eatda/controller/story/StoryResponse.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ public record StoryResponse(
44
String storeKakaoId,
55
String category,
66
String storeName,
7-
String storeAddress,
7+
String storeDistrict,
8+
String storeNeighborhood,
89
String description,
910
String imageUrl
1011
) {

src/main/java/eatda/domain/story/Story.java

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ public class Story extends AuditingEntity {
3838
@Column(name = "store_name", nullable = false)
3939
private String storeName;
4040

41-
@Column(name = "store_address", nullable = false)
42-
private String storeAddress;
41+
@Column(name = "store_road_address", nullable = false)
42+
private String storeRoadAddress;
43+
44+
@Column(name = "store_lot_number_address", nullable = false)
45+
private String storeLotNumberAddress;
4346

4447
@Column(name = "store_category", nullable = false)
4548
private String storeCategory;
@@ -54,21 +57,23 @@ public class Story extends AuditingEntity {
5457
private Story(
5558
Member member,
5659
String storeKakaoId,
57-
String storeName,
58-
String storeAddress,
5960
String storeCategory,
61+
String storeName,
62+
String storeRoadAddress,
63+
String storeLotNumberAddress,
6064
String description,
6165
String imageKey
6266
) {
6367
validateMember(member);
64-
validateStore(storeKakaoId, storeName, storeAddress, storeCategory);
68+
validateStore(storeKakaoId, storeCategory, storeName, storeRoadAddress, storeLotNumberAddress);
6569
validateStory(description, imageKey);
6670

6771
this.member = member;
6872
this.storeKakaoId = storeKakaoId;
69-
this.storeName = storeName;
70-
this.storeAddress = storeAddress;
7173
this.storeCategory = storeCategory;
74+
this.storeName = storeName;
75+
this.storeRoadAddress = storeRoadAddress;
76+
this.storeLotNumberAddress = storeLotNumberAddress;
7277
this.description = description;
7378
this.imageKey = imageKey;
7479
}
@@ -79,11 +84,18 @@ private void validateMember(Member member) {
7984
}
8085
}
8186

82-
private void validateStore(String storeKakaoId, String storeName, String storeAddress, String storeCategory) {
87+
private void validateStore(
88+
String storeKakaoId,
89+
String storeCategory,
90+
String storeName,
91+
String roadAddress,
92+
String lotNumberAddress
93+
) {
8394
validateStoreKakaoId(storeKakaoId);
84-
validateStoreName(storeName);
85-
validateStoreAddress(storeAddress);
8695
validateStoreCategory(storeCategory);
96+
validateStoreName(storeName);
97+
validateStoreRoadAddress(roadAddress);
98+
validateStoreLotNumberAddress(lotNumberAddress);
8799
}
88100

89101
private void validateStory(String description, String imageKey) {
@@ -103,8 +115,14 @@ private void validateStoreName(String storeName) {
103115
}
104116
}
105117

106-
private void validateStoreAddress(String storeAddress) {
107-
if (storeAddress == null || storeAddress.isBlank()) {
118+
private void validateStoreRoadAddress(String roadAddress) {
119+
if (roadAddress == null || roadAddress.isBlank()) {
120+
throw new BusinessException(BusinessErrorCode.INVALID_STORE_ADDRESS);
121+
}
122+
}
123+
124+
private void validateStoreLotNumberAddress(String lotNumberAddress) {
125+
if (lotNumberAddress == null || lotNumberAddress.isBlank()) {
108126
throw new BusinessException(BusinessErrorCode.INVALID_STORE_ADDRESS);
109127
}
110128
}
@@ -126,4 +144,20 @@ private void validateImage(String imageKey) {
126144
throw new BusinessException(BusinessErrorCode.INVALID_STORY_IMAGE_KEY);
127145
}
128146
}
147+
148+
public String getAddressDistrict() {
149+
String[] addressParts = storeLotNumberAddress.split(" ");
150+
if (addressParts.length < 2) {
151+
return "";
152+
}
153+
return addressParts[1];
154+
}
155+
156+
public String getAddressNeighborhood() {
157+
String[] addressParts = storeLotNumberAddress.split(" ");
158+
if (addressParts.length < 3) {
159+
return "";
160+
}
161+
return addressParts[2];
162+
}
129163
}

src/main/java/eatda/exception/BusinessErrorCode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public enum BusinessErrorCode {
4747
INVALID_STORY_IMAGE_KEY("STY002", "스토리 이미지 Key는 필수입니다."),
4848
STORY_MEMBER_REQUIRED("STY003", "스토리 작성 시 회원 정보는 필수입니다."),
4949
STORY_STORE_REQUIRED("STY004", "스토리 작성 시 가게 정보는 필수입니다."),
50-
STORY_NOT_FOUND("STY005", "스토리를 찾을 수 없습니다."),
50+
STORY_NOT_FOUND("STY005", "스토리를 찾을 수 없습니다.", HttpStatus.NOT_FOUND),
5151
INVALID_STORE_ID("STY006", "유효하지 않은 가게 ID입니다."),
5252
INVALID_STORE_KAKAO_ID("STY007", "스토어 Kakao ID는 필수입니다."),
5353
INVALID_STORE_NAME("STY008", "스토어 이름은 필수입니다."),

src/main/java/eatda/service/story/StoryService.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import eatda.controller.story.FilteredSearchResult;
55
import eatda.controller.story.StoriesResponse;
66
import eatda.controller.story.StoryRegisterRequest;
7+
import eatda.controller.story.StoryResponse;
78
import eatda.domain.member.Member;
89
import eatda.domain.story.Story;
910
import eatda.exception.BusinessErrorCode;
@@ -26,7 +27,6 @@
2627
@RequiredArgsConstructor
2728
public class StoryService {
2829
private static final int PAGE_START_NUMBER = 0;
29-
private static final int PAGE_SIZE = 5;
3030

3131
private final StoreService storeService;
3232
private final ImageService imageService;
@@ -44,7 +44,8 @@ public void registerStory(StoryRegisterRequest request, MultipartFile image, Lon
4444
.member(member)
4545
.storeKakaoId(matchedStore.kakaoId())
4646
.storeName(matchedStore.name())
47-
.storeAddress(matchedStore.address())
47+
.storeRoadAddress(matchedStore.roadAddress())
48+
.storeLotNumberAddress(matchedStore.lotNumberAddress())
4849
.storeCategory(matchedStore.category())
4950
.description(request.description())
5051
.imageKey(imageKey)
@@ -61,14 +62,15 @@ private FilteredSearchResult filteredSearchResponse(List<StoreSearchResult> resp
6162
store.kakaoId(),
6263
store.name(),
6364
store.roadAddress(),
65+
store.lotNumberAddress(),
6466
store.categoryName()
6567
))
6668
.orElseThrow(() -> new BusinessException(BusinessErrorCode.STORE_NOT_FOUND));
6769
}
6870

6971
@Transactional(readOnly = true)
70-
public StoriesResponse getPagedStoryPreviews() {
71-
Pageable pageable = PageRequest.of(PAGE_START_NUMBER, PAGE_SIZE);
72+
public StoriesResponse getPagedStoryPreviews(int size) {
73+
Pageable pageable = PageRequest.of(PAGE_START_NUMBER, size);
7274
Page<Story> orderByPage = storyRepository.findAllByOrderByCreatedAtDesc(pageable);
7375

7476
return new StoriesResponse(
@@ -80,4 +82,20 @@ public StoriesResponse getPagedStoryPreviews() {
8082
.toList()
8183
);
8284
}
85+
86+
@Transactional(readOnly = true)
87+
public StoryResponse getStory(long storyId) {
88+
Story story = storyRepository.findById(storyId)
89+
.orElseThrow(() -> new BusinessException(BusinessErrorCode.STORY_NOT_FOUND));
90+
91+
return new StoryResponse(
92+
story.getStoreKakaoId(),
93+
story.getStoreCategory(),
94+
story.getStoreName(),
95+
story.getAddressDistrict(),
96+
story.getAddressNeighborhood(),
97+
story.getDescription(),
98+
imageService.getPresignedUrl(story.getImageKey())
99+
);
100+
}
83101
}
Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
CREATE TABLE `story`
22
(
3-
`id` BIGINT NOT NULL AUTO_INCREMENT,
4-
`member_id` BIGINT NOT NULL,
5-
`store_kakao_id` VARCHAR(255) NOT NULL,
6-
`store_name` VARCHAR(255) NOT NULL,
7-
`store_address` VARCHAR(255) NOT NULL,
8-
`store_category` VARCHAR(50) NOT NULL,
9-
`description` TEXT NOT NULL,
10-
`image_key` VARCHAR(511) NOT NULL,
11-
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
3+
`id` BIGINT NOT NULL AUTO_INCREMENT,
4+
`member_id` BIGINT NOT NULL,
5+
`store_kakao_id` VARCHAR(255) NOT NULL,
6+
`store_name` VARCHAR(255) NOT NULL,
7+
`store_road_address` VARCHAR(255) NOT NULL,
8+
`store_lot_number_address` VARCHAR(255) NOT NULL,
9+
`store_category` VARCHAR(50) NOT NULL,
10+
`description` TEXT NOT NULL,
11+
`image_key` VARCHAR(511) NOT NULL,
12+
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
1213
PRIMARY KEY (`id`)
1314
);

0 commit comments

Comments
 (0)