Skip to content

Commit 3a1caba

Browse files
authored
Feature/107 선호물품 등록 엔드포인트 구현 (#112)
* feat: 선호물품 등록 엔드포인트 구현 - 컨트롤러 구현 - 기관 권한 설정에 따른 요청 Dto 수정 - 요청 Dto 변화에 따른 서비스 레이어 파라미터 값 수정 - 테스트 코드 작성및 검증 완 * chore: test displayname 수정 - 도메인 관점의 설명으로 변경 * chore: 코드리뷰 사항 반영 - 응답 객체에 swagger 스키마 적용 - 개행 추
1 parent 934e2d8 commit 3a1caba

File tree

7 files changed

+212
-20
lines changed

7 files changed

+212
-20
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.somemore.center.controller;
2+
3+
import com.somemore.center.dto.request.PreferItemCreateRequestDto;
4+
import com.somemore.center.dto.response.PreferItemCreateResponseDto;
5+
import com.somemore.center.usecase.command.CreatePreferItemUseCase;
6+
import com.somemore.global.common.response.ApiResponse;
7+
import io.swagger.v3.oas.annotations.Operation;
8+
import io.swagger.v3.oas.annotations.tags.Tag;
9+
import jakarta.validation.Valid;
10+
import lombok.RequiredArgsConstructor;
11+
import org.springframework.security.access.annotation.Secured;
12+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
13+
import org.springframework.web.bind.annotation.PostMapping;
14+
import org.springframework.web.bind.annotation.RequestBody;
15+
import org.springframework.web.bind.annotation.RequestMapping;
16+
import org.springframework.web.bind.annotation.RestController;
17+
18+
import java.util.UUID;
19+
20+
@RequiredArgsConstructor
21+
@RestController
22+
@RequestMapping("/api/preferItem")
23+
@Tag(name = "PreferItem Command API", description = "선호 물품 등록, 삭제 기능을 제공합니다")
24+
public class PreferItemCommandApiController {
25+
26+
private final CreatePreferItemUseCase createPreferItemUseCase;
27+
28+
@Secured("ROLE_CENTER")
29+
@Operation(summary = "기관 선호물품 등록 API")
30+
@PostMapping()
31+
public ApiResponse<PreferItemCreateResponseDto> registerPreferItem(@Valid @RequestBody PreferItemCreateRequestDto requestDto,
32+
@AuthenticationPrincipal String userId) {
33+
34+
PreferItemCreateResponseDto responseDto = createPreferItemUseCase.createPreferItem(UUID.fromString(userId), requestDto);
35+
36+
return ApiResponse.ok(200, responseDto, "관심 기관 등록 성공");
37+
}
38+
}

src/main/java/com/somemore/center/dto/request/PreferItemCreateRequestDto.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
package com.somemore.center.dto.request;
22

3-
3+
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
4+
import com.fasterxml.jackson.databind.annotation.JsonNaming;
45
import com.somemore.center.domain.PreferItem;
6+
import io.swagger.v3.oas.annotations.media.Schema;
7+
import jakarta.validation.constraints.NotNull;
58

69
import java.util.UUID;
710

8-
11+
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
912
public record PreferItemCreateRequestDto(
1013

11-
UUID centerId,
14+
@Schema(description = "선호물품 이름", example = "어린이 도서")
15+
@NotNull(message = "물품 이름은 필수값입니다.")
1216
String itemName
1317

1418
) {
15-
public PreferItem createPreferItem() {
19+
public PreferItem toEntity(UUID centerId) {
1620
return PreferItem.create(centerId, itemName);
1721
}
1822

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.somemore.center.dto.response;
2+
3+
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
4+
import com.fasterxml.jackson.databind.annotation.JsonNaming;
5+
import com.somemore.center.domain.PreferItem;
6+
import io.swagger.v3.oas.annotations.media.Schema;
7+
import lombok.Builder;
8+
9+
import java.util.UUID;
10+
11+
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
12+
@Builder
13+
public record PreferItemCreateResponseDto(
14+
@Schema(description = "선호물품의 ID", example = "111")
15+
Long id,
16+
@Schema(description = "기관의 ID", example = "123e4567-e89b-12d3-a456-426614174000")
17+
UUID centerId,
18+
@Schema(description = "선호물품 이름", example = "어린이 도서")
19+
String itemName
20+
) {
21+
public static PreferItemCreateResponseDto from(PreferItem preferItem) {
22+
return PreferItemCreateResponseDto.builder()
23+
.id(preferItem.getId())
24+
.centerId(preferItem.getCenterId())
25+
.itemName(preferItem.getItemName())
26+
.build();
27+
}
28+
}
29+
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package com.somemore.center.service.command;
22

3+
import com.somemore.center.domain.PreferItem;
34
import com.somemore.center.dto.request.PreferItemCreateRequestDto;
5+
import com.somemore.center.dto.response.PreferItemCreateResponseDto;
46
import com.somemore.center.repository.PreferItemRepository;
57
import com.somemore.center.usecase.command.CreatePreferItemUseCase;
68
import com.somemore.center.usecase.query.CenterQueryUseCase;
79
import lombok.RequiredArgsConstructor;
810
import org.springframework.stereotype.Service;
911
import org.springframework.transaction.annotation.Transactional;
1012

13+
import java.util.UUID;
14+
1115
@RequiredArgsConstructor
1216
@Transactional
1317
@Service
@@ -17,11 +21,15 @@ public class CreatePreferItemService implements CreatePreferItemUseCase {
1721
private final PreferItemRepository preferItemRepository;
1822

1923
@Override
20-
public void createPreferItem(PreferItemCreateRequestDto requestDto) {
24+
public PreferItemCreateResponseDto createPreferItem(UUID userId, PreferItemCreateRequestDto requestDto) {
25+
26+
centerQueryUseCase.validateCenterExists(userId);
27+
28+
PreferItem preferItem = requestDto.toEntity(userId);
2129

22-
centerQueryUseCase.validateCenterExists(requestDto.centerId());
30+
preferItemRepository.save(preferItem);
2331

24-
preferItemRepository.save(requestDto.createPreferItem());
32+
return PreferItemCreateResponseDto.from(preferItem);
2533
}
2634

2735
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.somemore.center.usecase.command;
22

33
import com.somemore.center.dto.request.PreferItemCreateRequestDto;
4+
import com.somemore.center.dto.response.PreferItemCreateResponseDto;
5+
6+
import java.util.UUID;
47

58
public interface CreatePreferItemUseCase {
69

7-
void createPreferItem(PreferItemCreateRequestDto requestDto);
10+
PreferItemCreateResponseDto createPreferItem(UUID userId, PreferItemCreateRequestDto requestDto);
811
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.somemore.center.controller;
2+
3+
import com.somemore.ControllerTestSupport;
4+
import com.somemore.WithMockCustomUser;
5+
import com.somemore.center.dto.request.PreferItemCreateRequestDto;
6+
import com.somemore.center.dto.response.PreferItemCreateResponseDto;
7+
import com.somemore.center.usecase.command.CreatePreferItemUseCase;
8+
import com.somemore.global.exception.BadRequestException;
9+
import org.junit.jupiter.api.DisplayName;
10+
import org.junit.jupiter.api.Test;
11+
import org.springframework.boot.test.mock.mockito.MockBean;
12+
import org.springframework.http.MediaType;
13+
14+
import java.util.UUID;
15+
16+
import static org.mockito.BDDMockito.given;
17+
import static org.mockito.Mockito.verify;
18+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
19+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
20+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
21+
22+
class PreferItemCommandApiControllerTest extends ControllerTestSupport {
23+
24+
@MockBean
25+
private CreatePreferItemUseCase createPreferItemUseCase;
26+
27+
28+
@DisplayName("기관은 선호물품을 등록할 수 있다. (controller)")
29+
@Test
30+
@WithMockCustomUser(role = "CENTER")
31+
void registerPreferItem() throws Exception {
32+
// given
33+
UUID userId = UUID.fromString("123e4567-e89b-12d3-a456-426614174000"); // 고정된 UUID 사용
34+
PreferItemCreateRequestDto requestDto = new PreferItemCreateRequestDto("어린이 도서");
35+
PreferItemCreateResponseDto responseDto = new PreferItemCreateResponseDto(
36+
1L,
37+
userId,
38+
"어린이 도서"
39+
);
40+
41+
given(createPreferItemUseCase.createPreferItem(userId, requestDto))
42+
.willReturn(responseDto);
43+
44+
// when & then
45+
mockMvc.perform(post("/api/preferItem")
46+
.contentType(MediaType.APPLICATION_JSON)
47+
.content(objectMapper.writeValueAsString(requestDto))
48+
.principal(() -> userId.toString()))
49+
.andExpect(status().isOk())
50+
.andExpect(jsonPath("$.code").value(200))
51+
.andExpect(jsonPath("$.message").value("관심 기관 등록 성공"))
52+
.andExpect(jsonPath("$.data.id").value(responseDto.id()))
53+
.andExpect(jsonPath("$.data.center_id").value(responseDto.centerId().toString()))
54+
.andExpect(jsonPath("$.data.item_name").value(responseDto.itemName()));
55+
56+
// verify
57+
verify(createPreferItemUseCase).createPreferItem(userId, requestDto);
58+
}
59+
60+
@DisplayName("존재하지 않는 기관 ID로 선호물품을 등록할 수 없다. (controller)")
61+
@Test
62+
@WithMockCustomUser(role = "CENTER")
63+
void registerPreferItem_Fail_WhenCenterNotExists() throws Exception {
64+
// given
65+
UUID userId = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");
66+
PreferItemCreateRequestDto requestDto = new PreferItemCreateRequestDto("어린이 도서");
67+
68+
given(createPreferItemUseCase.createPreferItem(userId, requestDto))
69+
.willThrow(new BadRequestException("존재하지 않는 기관입니다."));
70+
71+
// when & then
72+
mockMvc.perform(post("/api/preferItem")
73+
.contentType(MediaType.APPLICATION_JSON)
74+
.content(objectMapper.writeValueAsString(requestDto))
75+
.principal(() -> userId.toString()))
76+
.andExpect(status().isBadRequest())
77+
.andExpect(jsonPath("$.status").value(400))
78+
.andExpect(jsonPath("$.detail").value("존재하지 않는 기관입니다."));
79+
80+
// verify
81+
verify(createPreferItemUseCase).createPreferItem(userId, requestDto);
82+
}
83+
}

src/test/java/com/somemore/center/service/command/CreatePreferItemServiceTest.java

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66
import com.somemore.center.dto.request.PreferItemCreateRequestDto;
77
import com.somemore.center.repository.CenterRepository;
88
import com.somemore.center.repository.PreferItemRepository;
9+
import com.somemore.global.exception.BadRequestException;
910
import jakarta.transaction.Transactional;
1011
import org.junit.jupiter.api.DisplayName;
1112
import org.junit.jupiter.api.Test;
1213
import org.springframework.beans.factory.annotation.Autowired;
1314

15+
import java.util.UUID;
16+
1417
import static org.assertj.core.api.Assertions.assertThat;
18+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1519

1620
@Transactional
1721
class CreatePreferItemServiceTest extends IntegrationTestSupport {
@@ -29,26 +33,16 @@ class CreatePreferItemServiceTest extends IntegrationTestSupport {
2933
@Test
3034
void createPreferItem() {
3135
//given
32-
Center center = Center.create(
33-
"기본 기관 이름",
34-
"010-1234-5678",
35-
"http://example.com/image.jpg",
36-
"기관 소개 내용",
37-
"http://example.com",
38-
"account123",
39-
"password123"
40-
);
36+
Center center = createCenter();
4137
centerRepository.save(center);
4238
String itemName = "어린이 도서";
4339

44-
4540
PreferItemCreateRequestDto requestDto = new PreferItemCreateRequestDto(
46-
center.getId(),
4741
itemName
4842
);
4943

5044
//when
51-
createPreferItemService.createPreferItem(requestDto);
45+
createPreferItemService.createPreferItem(center.getId(), requestDto);
5246

5347
//then
5448
PreferItem savedItem = preferItemRepository.findAll().stream()
@@ -61,4 +55,37 @@ void createPreferItem() {
6155
assertThat(savedItem.getItemName()).isEqualTo(itemName);
6256
}
6357

58+
@DisplayName("존재하지 않는 기관 아이디로 선호물품을 등록하려고 하면 예외를 발생시킨다.")
59+
@Test
60+
void createPreferItemThrowsExceptionWhenCenterDoesNotExist() {
61+
// given
62+
UUID invalidCenterId = UUID.randomUUID();
63+
String itemName = "어린이 도서";
64+
65+
PreferItemCreateRequestDto requestDto = new PreferItemCreateRequestDto(
66+
itemName
67+
);
68+
69+
// when & then
70+
assertThatThrownBy(() -> createPreferItemService.createPreferItem(invalidCenterId, requestDto))
71+
.isInstanceOf(BadRequestException.class)
72+
.hasMessageContaining("존재하지 않는 기관입니다.");
73+
}
74+
75+
private Center createCenter() {
76+
Center center = Center.create(
77+
"기본 기관 이름",
78+
"010-1234-5678",
79+
"http://example.com/image.jpg",
80+
"기관 소개 내용",
81+
"http://example.com",
82+
"account123",
83+
"password123"
84+
);
85+
86+
centerRepository.save(center);
87+
88+
return center;
89+
}
90+
6491
}

0 commit comments

Comments
 (0)