Repository navigation
[#28] 이미지 조회 기능 - #30
[#28] 이미지 조회 기능 #30
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
pjy1368
left a comment
There was a problem hiding this comment.
이미지 경로 공통화, 캐시 정책, 상세 응답 URL의 다운로드 검증에 관한 제안 3개를 남겼습니다.
| List<String> imageKeys = cameraImageRepository.findByCameraId(auction.getCamera().getId()).stream() | ||
| .map(CameraImage::getImageKey) | ||
| List<String> imageUrls = cameraImageRepository.findByCameraId(auction.getCamera().getId()).stream() | ||
| .map(image -> "/api/v1/images/" + image.getId()) |
There was a problem hiding this comment.
이미지 경로와 URL 생성 규칙을 한 곳에서 관리하면 어떨까요?
현재 컨트롤러의 @RequestMapping, 서비스의 "/api/v1/images/", SecurityConfig의 허용 경로가 각각 정의되어 있습니다. 경로를 변경할 때 세 곳을 함께 수정해야 하는 구조예요.
기본 경로와 URL 생성 메서드를 공유하고, 서비스에서는 이미지 ID만 넘기도록 정리하면 좋겠습니다.
기존 FileUtils, TimeUtils의 정적 유틸 구조를 따르는 제안입니다.
package com.chalkak.common.util;
public final class ImageUrls {
public static final String BASE_PATH = "/api/v1/images";
private ImageUrls() {
}
public static String download(Long imageId) {
return BASE_PATH + "/" + imageId;
}
}각 파일에 ImageUrls import를 추가하고:
CameraImageController:
-@RequestMapping("/api/v1/images")
+@RequestMapping(ImageUrls.BASE_PATH)AuctionService:
- .map(image -> "/api/v1/images/" + image.getId())
+ .map(image -> ImageUrls.download(image.getId()))SecurityConfig:
- .requestMatchers(HttpMethod.GET, "/api/v1/images/**").permitAll()
+ .requestMatchers(HttpMethod.GET, ImageUrls.BASE_PATH + "/**").permitAll()| @GetMapping("/{imageId}") | ||
| public ResponseEntity<Resource> download(@PathVariable Long imageId) { | ||
| CameraImageDownload download = cameraImageService.download(imageId); | ||
| return ResponseEntity.ok() |
There was a problem hiding this comment.
(minor) 이미지 응답에는 캐시 정책을 따로 지정하면 어떨까요?
실제 응답을 확인해보니 Spring Security 기본 설정으로 Cache-Control: no-cache, no-store, max-age=0, must-revalidate가 붙습니다. 같은 이미지도 브라우저 캐시를 활용하기 어려운 상태예요.
같은 이미지 ID의 파일을 교체하지 않는 정책이라면, 이 응답에 max-age를 지정해서 반복 다운로드를 줄이면 좋겠습니다.
1시간은 정책 논의를 위한 예시입니다.
+import java.time.Duration;
+import org.springframework.http.CacheControl; return ResponseEntity.ok()
+ .cacheControl(CacheControl.maxAge(Duration.ofHours(1)))
.contentType(download.contentType())
.body(download.resource());There was a problem hiding this comment.
넵 경매 수정 시 이미지 변경 작업은 기존 이미지 삭제 후 재등록하는 정책을 생각하고있었어서 캐싱 적용해도 문제없습니다 ! 캐싱 적용하도록 하겠습니다.
그리고 이미지 수정 시 기존 이미지들은 삭제하고 다시 저장하기때문에 캐싱 기간은 넉넉하게 잡았습니다!
| .andExpect(jsonPath("$.camera.brand").value(AuctionRequestFixture.DEFAULT_BRAND)) | ||
| .andExpect(jsonPath("$.camera.modelName").value(AuctionRequestFixture.DEFAULT_MODEL_NAME)) | ||
| .andExpect(jsonPath("$.camera.imageKeys.length()").value(3)); | ||
| .andExpect(jsonPath("$.camera.imageUrls.length()").value(3)); |
There was a problem hiding this comment.
(minor) 상세 응답에서 받은 imageUrls를 그대로 GET해서 업로드한 바이트까지 확인해보면 어떨까요?
현재는 상세 테스트에서 URL 개수·접두사를 확인하고, 다운로드 테스트에서는 직접 만든 이미지 ID로 호출합니다. 상세 응답의 URL을 실제로 사용하는 구간은 검증하지 않고 있어요.
기존 상세 테스트에 다운로드 검증을 이어 붙이면 이번 변경의 연결 구간을 확인할 수 있을 것 같습니다.
기존 MockMvc, ObjectMapper, MultipartFileFixture를 재사용합니다.
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;- mockMvc.perform(get("/api/v1/auctions/{auctionId}", auctionId))
+ MvcResult result = mockMvc.perform(get("/api/v1/auctions/{auctionId}", auctionId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.camera.brand").value(AuctionRequestFixture.DEFAULT_BRAND))
.andExpect(jsonPath("$.camera.modelName").value(AuctionRequestFixture.DEFAULT_MODEL_NAME))
- .andExpect(jsonPath("$.camera.imageUrls.length()").value(3));
+ .andExpect(jsonPath("$.camera.imageUrls.length()").value(3))
+ .andReturn();
+
+ var imageUrls = objectMapper
+ .readTree(result.getResponse().getContentAsString())
+ .path("camera")
+ .path("imageUrls");
+ byte[] expectedBytes = MultipartFileFixture.image("image1.jpg").getBytes();
+
+ for (var imageUrl : imageUrls) {
+ mockMvc.perform(get(imageUrl.asText()))
+ .andExpect(status().isOk())
+ .andExpect(content().bytes(expectedBytes));
+ }현재 fixture의 이미지 내용은 모두 같으므로, 이 테스트는 URL 연결과 바이트 반환까지 검증합니다.
There was a problem hiding this comment.
넵! 이미지 업로드랑 다운로드 시 이미지 크기 검증 테스트 코드 추가하도록 하겠습니다 !
|



개요
메인 리뷰어 지정 및 Due Date
리뷰 시 참고 사항
TODO
References
[1] 사용된 레퍼런스에 대한 링크를 남겨주세요.
체크리스트