Skip to content

Commit b5918cb

Browse files
committed
Refactor: 멘토링 수정 시 이미지 s3 업로드 및 url db 저장
1 parent 21e038d commit b5918cb

File tree

7 files changed

+59
-41
lines changed

7 files changed

+59
-41
lines changed

back/src/main/java/com/back/domain/mentoring/mentoring/controller/MentoringController.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import com.back.global.rq.Rq;
1111
import com.back.global.rsData.RsData;
1212
import io.swagger.v3.oas.annotations.Operation;
13+
import io.swagger.v3.oas.annotations.Parameter;
14+
import io.swagger.v3.oas.annotations.media.Content;
1315
import io.swagger.v3.oas.annotations.tags.Tag;
1416
import jakarta.validation.Valid;
1517
import lombok.RequiredArgsConstructor;
@@ -79,7 +81,8 @@ public RsData<MentoringResponse> getMentoring(
7981
@PreAuthorize("hasRole('MENTOR')")
8082
@Operation(summary = "멘토링 생성", description = "멘토링을 생성합니다. 로그인한 멘토만 생성할 수 있습니다.")
8183
public RsData<MentoringResponse> createMentoring(
82-
@RequestPart("reqDto") @Valid MentoringRequest reqDto,
84+
@Parameter(content = @Content(mediaType = "application/json"))
85+
@RequestPart(value = "reqDto") @Valid MentoringRequest reqDto,
8386
@RequestPart(value = "thumb", required = false) MultipartFile thumb
8487
) {
8588
Mentor mentor = memberStorage.findMentorByMember(rq.getActor());
@@ -92,14 +95,17 @@ public RsData<MentoringResponse> createMentoring(
9295
);
9396
}
9497

95-
@PutMapping("/{mentoringId}")
98+
@PutMapping(value = "/{mentoringId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
99+
@PreAuthorize("hasRole('MENTOR')")
96100
@Operation(summary = "멘토링 수정", description = "멘토링을 수정합니다. 멘토링 작성자만 접근할 수 있습니다.")
97101
public RsData<MentoringResponse> updateMentoring(
98102
@PathVariable Long mentoringId,
99-
@RequestBody @Valid MentoringRequest reqDto
103+
@Parameter(content = @Content(mediaType = "application/json"))
104+
@RequestPart(value = "reqDto") @Valid MentoringRequest reqDto,
105+
@RequestPart(value = "thumb", required = false) MultipartFile thumb
100106
) {
101107
Mentor mentor = memberStorage.findMentorByMember(rq.getActor());
102-
MentoringResponse resDto = mentoringService.updateMentoring(mentoringId, reqDto, mentor);
108+
MentoringResponse resDto = mentoringService.updateMentoring(mentoringId, reqDto, thumb, mentor);
103109

104110
return new RsData<>(
105111
"200",
@@ -109,6 +115,7 @@ public RsData<MentoringResponse> updateMentoring(
109115
}
110116

111117
@DeleteMapping("/{mentoringId}")
118+
@PreAuthorize("hasRole('MENTOR')")
112119
@Operation(summary = "멘토링 삭제", description = "멘토링을 삭제합니다. 멘토링 작성자만 접근할 수 있습니다.")
113120
public RsData<Void> deleteMentoring(
114121
@PathVariable Long mentoringId

back/src/main/java/com/back/domain/mentoring/mentoring/dto/request/MentoringRequest.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ public record MentoringRequest(
1616

1717
@Schema(description = "멘토링 소개", example = "bio")
1818
@NotNull
19-
String bio,
20-
21-
@Schema(description = "멘토링 썸네일", example = "test.png")
22-
String thumb
19+
String bio
2320
) {
2421
}

back/src/main/java/com/back/domain/mentoring/mentoring/entity/Mentoring.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,9 @@ public Mentoring(Mentor mentor, String title, String bio) {
4040
this.bio = bio;
4141
}
4242

43-
public void update(String title, String bio, List<Tag> tags, String thumb) {
43+
public void update(String title, String bio, List<Tag> tags) {
4444
this.title = title;
4545
this.bio = bio;
46-
this.thumb = thumb;
4746

4847
updateTags(tags);
4948
}

back/src/main/java/com/back/domain/mentoring/mentoring/service/MentoringService.java

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,7 @@ public MentoringResponse createMentoring(MentoringRequest reqDto, MultipartFile
7676

7777
mentoringRepository.saveAndFlush(mentoring);
7878

79-
if (thumb != null && !thumb.isEmpty()) {
80-
String imageUrl = null;
81-
try {
82-
String path = "mentoring/" + mentoring.getId();
83-
imageUrl = s3ImageUploader.upload(thumb, path);
84-
} catch (IOException e) {
85-
throw new ServiceException(ImageErrorCode.IMAGE_UPLOAD_FAILED);
86-
}
87-
88-
mentoring.updateThumb(imageUrl);
89-
}
79+
uploadThumb(thumb, mentoring);
9080

9181
return new MentoringResponse(
9282
MentoringDetailDto.from(mentoring),
@@ -95,15 +85,16 @@ public MentoringResponse createMentoring(MentoringRequest reqDto, MultipartFile
9585
}
9686

9787
@Transactional
98-
public MentoringResponse updateMentoring(Long mentoringId, MentoringRequest reqDto, Mentor mentor) {
88+
public MentoringResponse updateMentoring(Long mentoringId, MentoringRequest reqDto, MultipartFile thumb, Mentor mentor) {
9989
Mentoring mentoring = mentoringStorage.findMentoring(mentoringId);
10090

10191
validateOwner(mentoring, mentor);
10292
validateMentoringTitleForUpdate(mentor.getId(), reqDto.title(), mentoringId);
10393

10494
List<Tag> tags = getOrCreateTags(reqDto.tags());
10595

106-
mentoring.update(reqDto.title(), reqDto.bio(), tags, reqDto.thumb());
96+
mentoring.update(reqDto.title(), reqDto.bio(), tags);
97+
uploadThumb(thumb, mentoring);
10798

10899
return new MentoringResponse(
109100
MentoringDetailDto.from(mentoring),
@@ -162,6 +153,23 @@ private List<Tag> createNewTags(List<String> tagNames, Set<String> existingNames
162153
}
163154

164155

156+
// ===== 썸네일 =====
157+
158+
private void uploadThumb(MultipartFile thumb, Mentoring mentoring) {
159+
if (thumb != null && !thumb.isEmpty()) {
160+
String imageUrl = null;
161+
try {
162+
String path = "mentoring/" + mentoring.getId();
163+
imageUrl = s3ImageUploader.upload(thumb, path);
164+
} catch (IOException e) {
165+
throw new ServiceException(ImageErrorCode.IMAGE_UPLOAD_FAILED);
166+
}
167+
168+
mentoring.updateThumb(imageUrl);
169+
}
170+
}
171+
172+
165173
// ===== 유효성 검사 =====
166174

167175
private void validateOwner(Mentoring mentoring, Mentor mentor) {

back/src/main/java/com/back/global/initData/SessionInitData.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public CommandLineRunner initData() {
4343
Mentee mentee = menteeRepository.findByMemberIdWithMember(menteeMember.getId()).orElseThrow();
4444

4545
// 멘토링 생성
46-
MentoringRequest mentoringRequest = new MentoringRequest("Test Mentoring", Arrays.asList("Java", "Spring"), "This is a test mentoring.", null);
46+
MentoringRequest mentoringRequest = new MentoringRequest("Test Mentoring", Arrays.asList("Java", "Spring"), "This is a test mentoring.");
4747
MentoringResponse mentoringResponse = mentoringService.createMentoring(mentoringRequest, null, mentor);
4848

4949
// 멘토 슬롯 생성

back/src/test/java/com/back/domain/mentoring/mentoring/controller/MentoringControllerTest.java

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.beans.factory.annotation.Autowired;
2020
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
2121
import org.springframework.boot.test.context.SpringBootTest;
22+
import org.springframework.http.HttpMethod;
2223
import org.springframework.http.MediaType;
2324
import org.springframework.mock.web.MockMultipartFile;
2425
import org.springframework.test.context.ActiveProfiles;
@@ -236,15 +237,20 @@ void updateMentoringSuccess() throws Exception {
236237
MentoringRequest reqDto = new MentoringRequest(
237238
"Next.js 멘토링",
238239
List.of("Next.js", "React"),
239-
"Next.js를 활용한 프론트 개발 입문",
240-
"https://example.com/thumb.jpg"
240+
"Next.js를 활용한 프론트 개발 입문"
241+
);
242+
243+
MockMultipartFile jsonPart = new MockMultipartFile(
244+
"reqDto",
245+
"",
246+
"application/json",
247+
Ut.json.toString(reqDto).getBytes(StandardCharsets.UTF_8)
241248
);
242249

243250
ResultActions resultActions = mvc.perform(
244-
put(MENTORING_URL + "/" + mentoring.getId())
251+
multipart(HttpMethod.PUT, MENTORING_URL + "/" + mentoring.getId())
252+
.file(jsonPart)
245253
.cookie(new Cookie(TOKEN, mentorToken))
246-
.contentType(MediaType.APPLICATION_JSON)
247-
.content(Ut.json.toString(reqDto))
248254
)
249255
.andDo(print());
250256

@@ -260,8 +266,7 @@ void updateMentoringSuccess() throws Exception {
260266
.andExpect(jsonPath("$.data.mentoring.title").value(reqDto.title()))
261267
.andExpect(jsonPath("$.data.mentoring.tags[0]").value(reqDto.tags().get(0)))
262268
.andExpect(jsonPath("$.data.mentoring.tags[1]").value(reqDto.tags().get(1)))
263-
.andExpect(jsonPath("$.data.mentoring.bio").value(reqDto.bio()))
264-
.andExpect(jsonPath("$.data.mentoring.thumb").value(reqDto.thumb()));
269+
.andExpect(jsonPath("$.data.mentoring.bio").value(reqDto.bio()));
265270
}
266271

267272
@Test
@@ -369,17 +374,21 @@ private ResultActions performUpdateMentoring(Long mentoringId, String token) thr
369374
{
370375
"title": "Next.js 멘토링",
371376
"tags": ["Next.js", "React"],
372-
"bio": "Next.js를 활용한 프론트 개발 입문",
373-
"thumb": "https://example.com/thumb.jpg"
377+
"bio": "Next.js를 활용한 프론트 개발 입문"
374378
}
375379
""";
380+
MockMultipartFile jsonPart = new MockMultipartFile(
381+
"reqDto",
382+
"",
383+
"application/json",
384+
req.getBytes(StandardCharsets.UTF_8)
385+
);
376386

377387
return mvc
378388
.perform(
379-
put(MENTORING_URL + "/" + mentoringId)
389+
multipart(HttpMethod.PUT, MENTORING_URL + "/" + mentoringId)
390+
.file(jsonPart)
380391
.cookie(new Cookie(TOKEN, token))
381-
.contentType(MediaType.APPLICATION_JSON)
382-
.content(req)
383392
)
384393
.andDo(print())
385394
.andExpect(handler().handlerType(MentoringController.class))

back/src/test/java/com/back/domain/mentoring/mentoring/service/MentoringServiceTest.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ void setUp() {
7272
request = new MentoringRequest(
7373
"Spring Boot 멘토링",
7474
List.of("Spring", "Java"),
75-
"Spring Boot를 활용한 백엔드 개발 입문",
76-
"https://example.com/thumb.jpg"
75+
"Spring Boot를 활용한 백엔드 개발 입문"
7776
);
7877
}
7978

@@ -292,14 +291,13 @@ void updateMentoring() {
292291
.thenReturn(mentoring1);
293292

294293
// when
295-
MentoringResponse result = mentoringService.updateMentoring(mentoringId, request, mentor1);
294+
MentoringResponse result = mentoringService.updateMentoring(mentoringId, request, null, mentor1);
296295

297296
// then
298297
assertThat(result).isNotNull();
299298
assertThat(result.mentoring().title()).isEqualTo(request.title());
300299
assertThat(result.mentoring().bio()).isEqualTo(request.bio());
301300
assertThat(result.mentoring().tags()).isEqualTo(request.tags());
302-
assertThat(result.mentoring().thumb()).isEqualTo(request.thumb());
303301

304302
verify(mentoringStorage).findMentoring(mentoringId);
305303
verify(tagRepository).findByNameIn(request.tags());
@@ -315,7 +313,7 @@ void throwExceptionWhenNotOwner() {
315313
.thenReturn(mentoring1);
316314

317315
// when & then
318-
assertThatThrownBy(() -> mentoringService.updateMentoring(mentoringId, request, mentor2))
316+
assertThatThrownBy(() -> mentoringService.updateMentoring(mentoringId, request,null, mentor2))
319317
.isInstanceOf(ServiceException.class)
320318
.hasFieldOrPropertyWithValue("resultCode", MentoringErrorCode.FORBIDDEN_NOT_OWNER.getCode());
321319
}

0 commit comments

Comments
 (0)