-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[BSVR-91] 경기장 등록 API & 이미지 업로드 컴포넌트 (#33)
* feat: 경기장 생성 컨트롤러 추가 * fix: response dto mapping 에러 수정 * feat: bucketName config 상수로 변경 * refactor: 가독성 개선 * test: FileNameGeneratorTest 수정
- Loading branch information
Showing
20 changed files
with
272 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
...ication/src/main/java/org/depromeet/spot/application/stadium/CreateStadiumController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package org.depromeet.spot.application.stadium; | ||
|
||
import org.depromeet.spot.application.stadium.dto.response.StadiumResponse; | ||
import org.depromeet.spot.domain.stadium.Stadium; | ||
import org.depromeet.spot.usecase.port.in.stadium.CreateStadiumUsecase; | ||
import org.depromeet.spot.usecase.port.in.stadium.CreateStadiumUsecase.CreateStadiumReq; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.ResponseStatus; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@RestController | ||
@Tag(name = "경기장") | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/v1/stadiums") | ||
public class CreateStadiumController { | ||
|
||
private final CreateStadiumUsecase createStadiumUsecase; | ||
|
||
@PostMapping | ||
@ResponseStatus(HttpStatus.CREATED) | ||
@Operation(summary = "신규 야구 경기장을 등록한다.") | ||
public StadiumResponse create( | ||
@RequestParam("name") String name, | ||
@RequestParam("mainImage") MultipartFile mainImage, | ||
@RequestParam("seatingChartImage") MultipartFile seatingChartImage, | ||
@RequestParam("labeledSeatingChartImage") MultipartFile labeledSeatingChartImage, | ||
@RequestParam("isActive") boolean isActive) { | ||
CreateStadiumReq req = | ||
CreateStadiumReq.builder() | ||
.name(name) | ||
.mainImage(mainImage) | ||
.seatingChartImage(seatingChartImage) | ||
.labeledSeatingChartImage(labeledSeatingChartImage) | ||
.isActive(isActive) | ||
.build(); | ||
Stadium stadium = createStadiumUsecase.create(req); | ||
return StadiumResponse.from(stadium); | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
...on/src/main/java/org/depromeet/spot/application/stadium/dto/response/StadiumResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package org.depromeet.spot.application.stadium.dto.response; | ||
|
||
import org.depromeet.spot.domain.stadium.Stadium; | ||
|
||
import lombok.Builder; | ||
|
||
@Builder | ||
public record StadiumResponse( | ||
Long id, | ||
String name, | ||
String mainImage, | ||
String seatingChartImage, | ||
String labeledSeatingChartImage, | ||
boolean isActive) { | ||
|
||
public static StadiumResponse from(Stadium stadium) { | ||
return StadiumResponse.builder() | ||
.id(stadium.getId()) | ||
.name(stadium.getName()) | ||
.mainImage(stadium.getMainImage()) | ||
.seatingChartImage(stadium.getSeatingChartImage()) | ||
.labeledSeatingChartImage(stadium.getLabeledSeatingChartImage()) | ||
.isActive(stadium.isActive()) | ||
.build(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 14 additions & 2 deletions
16
domain/src/main/java/org/depromeet/spot/domain/media/MediaProperty.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,19 @@ | ||
package org.depromeet.spot.domain.media; | ||
|
||
import lombok.Getter; | ||
|
||
@Getter | ||
public enum MediaProperty { | ||
REVIEW, | ||
STADIUM, | ||
REVIEW("review-images"), | ||
STADIUM("stadium-images"), | ||
STADIUM_SEAT("stadium-seat-charts"), | ||
STADIUM_SEAT_LABEL("stadium-seat-label-charts"), | ||
TEAM_LOGO("team-logos"), | ||
; | ||
|
||
private final String folderName; | ||
|
||
MediaProperty(final String folderName) { | ||
this.folderName = folderName; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91 changes: 91 additions & 0 deletions
91
infrastructure/ncp/src/main/java/org/depromeet/spot/ncp/objectstorage/ImageUploader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package org.depromeet.spot.ncp.objectstorage; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
||
import org.depromeet.spot.common.exception.media.MediaException.InvalidExtensionException; | ||
import org.depromeet.spot.common.exception.media.MediaException.UploadFailException; | ||
import org.depromeet.spot.domain.media.MediaProperty; | ||
import org.depromeet.spot.domain.media.extension.ImageExtension; | ||
import org.depromeet.spot.domain.media.extension.StadiumSeatMediaExtension; | ||
import org.depromeet.spot.ncp.config.ObjectStorageConfig; | ||
import org.depromeet.spot.usecase.port.out.media.ImageUploadPort; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.util.StringUtils; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import com.amazonaws.services.s3.AmazonS3; | ||
import com.amazonaws.services.s3.model.CannedAccessControlList; | ||
import com.amazonaws.services.s3.model.ObjectMetadata; | ||
import com.amazonaws.services.s3.model.PutObjectRequest; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class ImageUploader implements ImageUploadPort { | ||
|
||
private final AmazonS3 amazonS3; | ||
|
||
@Override | ||
public String upload(String targetName, MultipartFile file, MediaProperty property) { | ||
if (file == null || file.isEmpty()) return null; | ||
|
||
final String fileExtension = StringUtils.getFilenameExtension(file.getOriginalFilename()); | ||
checkValidExtension(fileExtension, property); | ||
|
||
final String bucketName = ObjectStorageConfig.BUCKET_NAME; | ||
final String fileName = createFileName(targetName, property.getFolderName(), fileExtension); | ||
ObjectMetadata objectMetadata = createObjectMetadata(file); | ||
|
||
try (InputStream inputStream = file.getInputStream()) { | ||
uploadToS3(bucketName, fileName, inputStream, objectMetadata); | ||
} catch (IOException e) { | ||
throw new UploadFailException(); | ||
} | ||
|
||
return amazonS3.getUrl(bucketName, fileName).toString(); | ||
} | ||
|
||
private ObjectMetadata createObjectMetadata(MultipartFile file) { | ||
ObjectMetadata metadata = new ObjectMetadata(); | ||
metadata.setContentLength(file.getSize()); | ||
metadata.setContentType(file.getContentType()); | ||
return metadata; | ||
} | ||
|
||
private void uploadToS3( | ||
String bucketName, String fileName, InputStream inputStream, ObjectMetadata metadata) { | ||
amazonS3.putObject( | ||
new PutObjectRequest(bucketName, fileName, inputStream, metadata) | ||
.withCannedAcl(CannedAccessControlList.PublicRead)); | ||
} | ||
|
||
private void checkValidExtension(final String fileExtension, MediaProperty property) { | ||
if (property == MediaProperty.STADIUM_SEAT | ||
|| property == MediaProperty.STADIUM_SEAT_LABEL) { | ||
checkValidSeatExtension(fileExtension); | ||
} else { | ||
checkValidImageExtension(fileExtension); | ||
} | ||
} | ||
|
||
private void checkValidSeatExtension(final String fileExtension) { | ||
if (!StadiumSeatMediaExtension.isValid(fileExtension)) { | ||
throw new InvalidExtensionException(fileExtension); | ||
} | ||
} | ||
|
||
private void checkValidImageExtension(final String fileExtension) { | ||
if (!ImageExtension.isValid(fileExtension)) { | ||
throw new InvalidExtensionException(fileExtension); | ||
} | ||
} | ||
|
||
private String createFileName( | ||
final String targetName, final String folderName, final String fileExtension) { | ||
return folderName + "/" + targetName + "." + fileExtension; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 0 additions & 7 deletions
7
...astructure/ncp/src/main/java/org/depromeet/spot/ncp/property/ReviewStorageProperties.java
This file was deleted.
Oops, something went wrong.
7 changes: 0 additions & 7 deletions
7
...structure/ncp/src/main/java/org/depromeet/spot/ncp/property/StadiumStorageProperties.java
This file was deleted.
Oops, something went wrong.
8 changes: 1 addition & 7 deletions
8
infrastructure/ncp/src/main/java/org/depromeet/spot/ncp/resources/application.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,4 @@ | ||
ncp: | ||
object-storage: | ||
accessKey: ${NCP_OBJECT_STORAGE_ACCESS_KEY} | ||
secretKey: ${NCP_OBJECT_STORAGE_SECRET_KEY} | ||
review-storage: | ||
bucketName: "spot-image-bucket" | ||
folderName: "review-images" | ||
stadium-storage: | ||
bucketName: "spot-image-bucket" | ||
folderName: "stadium-images" | ||
secretKey: ${NCP_OBJECT_STORAGE_SECRET_KEY} |
Oops, something went wrong.