Skip to content

Commit f344cc8

Browse files
committed
feat: 데모 사진 조회 API 구현
1 parent 82415eb commit f344cc8

2 files changed

Lines changed: 112 additions & 0 deletions

File tree

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package com.semosan.api.domain.demo.controller;
2+
3+
import com.semosan.api.common.config.DemoProperties;
4+
import com.semosan.api.common.config.MinioProperties;
5+
import com.semosan.api.common.response.ApiResponse;
6+
import com.semosan.api.common.status.SuccessStatus;
7+
import com.semosan.api.domain.demo.controller.docs.DemoControllerDocs;
8+
import com.semosan.api.domain.tracking.entity.TrackingPhoto;
9+
import com.semosan.api.domain.tracking.repository.TrackingPhotoRepository;
10+
import io.minio.GetPresignedObjectUrlArgs;
11+
import io.minio.MinioClient;
12+
import io.minio.http.Method;
13+
import lombok.RequiredArgsConstructor;
14+
import lombok.extern.slf4j.Slf4j;
15+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
16+
import org.springframework.http.ResponseEntity;
17+
import org.springframework.web.bind.annotation.*;
18+
19+
import java.util.ArrayList;
20+
import java.util.Collections;
21+
import java.util.List;
22+
import java.util.concurrent.TimeUnit;
23+
24+
@Slf4j
25+
@RestController
26+
@RequestMapping("/api/demo")
27+
@RequiredArgsConstructor
28+
@EnableConfigurationProperties(DemoProperties.class)
29+
public class DemoController implements DemoControllerDocs {
30+
31+
private static final String BUCKET = "tracking-photos";
32+
33+
private final DemoProperties demoProperties;
34+
private final MinioClient minioClient;
35+
private final MinioProperties minioProperties;
36+
private final TrackingPhotoRepository trackingPhotoRepository;
37+
38+
@GetMapping("/tracking/sessions/{sessionId}/photos")
39+
@Override
40+
public ResponseEntity<ApiResponse<List<String>>> getDemoPhotos(
41+
@PathVariable Long sessionId,
42+
@RequestParam(defaultValue = "3") int count
43+
) {
44+
List<String> shuffled = new ArrayList<>(demoProperties.photoFilenames());
45+
Collections.shuffle(shuffled);
46+
List<String> randomUrls = shuffled.subList(0, Math.min(count, shuffled.size()))
47+
.stream()
48+
.map(this::presignedGetUrl)
49+
.toList();
50+
51+
List<String> uploadedUrls = trackingPhotoRepository
52+
.findByTrackingSession_IdOrderByMilestoneIndexAsc(sessionId)
53+
.stream()
54+
.map(TrackingPhoto::getImageUrl)
55+
.toList();
56+
57+
List<String> combined = new ArrayList<>(randomUrls);
58+
combined.addAll(uploadedUrls);
59+
60+
return ApiResponse.success(SuccessStatus.TRACKING_PHOTO_LIST_SUCCESS, combined);
61+
}
62+
63+
private String presignedGetUrl(String objectKey) {
64+
try {
65+
String url = minioClient.getPresignedObjectUrl(
66+
GetPresignedObjectUrlArgs.builder()
67+
.method(Method.GET)
68+
.bucket(BUCKET)
69+
.object(objectKey)
70+
.expiry(1, TimeUnit.HOURS)
71+
.build()
72+
);
73+
return url.replace(minioProperties.endpoint(), minioProperties.publicUrl());
74+
} catch (Exception e) {
75+
log.warn("Failed to generate presigned URL for {}", objectKey, e);
76+
return minioProperties.publicUrl() + "/" + BUCKET + "/" + objectKey;
77+
}
78+
}
79+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.semosan.api.domain.demo.controller.docs;
2+
3+
import com.semosan.api.common.response.ApiResponse;
4+
import io.swagger.v3.oas.annotations.Operation;
5+
import io.swagger.v3.oas.annotations.Parameter;
6+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
7+
import io.swagger.v3.oas.annotations.tags.Tag;
8+
import org.springframework.http.ResponseEntity;
9+
import org.springframework.web.bind.annotation.PathVariable;
10+
import org.springframework.web.bind.annotation.RequestParam;
11+
12+
import java.util.List;
13+
14+
@Tag(name = "Demo", description = "시연용 API")
15+
public interface DemoControllerDocs {
16+
17+
@Operation(
18+
summary = "시연용 트래킹 사진 조회",
19+
description = "MinIO에 미리 올려둔 사진 중 랜덤 N개 + 해당 세션에서 직접 촬영한 사진 URL을 합쳐서 반환합니다."
20+
)
21+
@ApiResponses({
22+
@io.swagger.v3.oas.annotations.responses.ApiResponse(
23+
responseCode = "200",
24+
description = "시연용 사진 목록 조회 성공"
25+
)
26+
})
27+
ResponseEntity<ApiResponse<List<String>>> getDemoPhotos(
28+
@Parameter(description = "트래킹 세션 ID", required = true)
29+
@PathVariable Long sessionId,
30+
@Parameter(description = "랜덤 사진 개수 (기본값 3)", required = false)
31+
@RequestParam(defaultValue = "3") int count
32+
);
33+
}

0 commit comments

Comments
 (0)