Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

게시글 작성 시 이미지 업로드 기능 구현 #132

Merged
merged 8 commits into from
Feb 27, 2024
1 change: 0 additions & 1 deletion src/main/java/balancetalk/global/exception/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ public enum ErrorCode {
INCORRECT_PASSWORD(BAD_REQUEST, "비밀번호가 잘못되었거나 요청 형식이 올바르지 않습니다"),
MIME_TYPE_NULL(BAD_REQUEST, "MIME 타입이 null입니다."),
FILE_UPLOAD_FAILED(BAD_REQUEST, "파일 업로드에 실패했습니다."),
FILE_DOWNLOAD_FAILED(BAD_REQUEST, "파일 다운로드에 실패했습니다."),
FILE_SIZE_EXCEEDED(BAD_REQUEST, "파일 크기가 초과되었습니다."),


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

@Slf4j
@RestControllerAdvice
Expand Down
94 changes: 0 additions & 94 deletions src/main/java/balancetalk/module/file/application/FileService.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package balancetalk.module.file.application;

import balancetalk.global.exception.BalanceTalkException;
import balancetalk.global.exception.ErrorCode;
import balancetalk.module.file.domain.File;
import balancetalk.module.file.domain.FileRepository;
import balancetalk.module.file.domain.FileType;
import balancetalk.module.file.dto.FileDto;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
Expand All @@ -20,7 +21,7 @@

@Service
@RequiredArgsConstructor
public class S3UploadService {
public class FileUploadService {

private final S3Client s3Client;
private final FileRepository fileRepository;
Expand All @@ -29,40 +30,20 @@ public class S3UploadService {
private String bucket;

@Transactional
public List<String> uploadMultipleImage(List<MultipartFile> multipartFiles) {
return multipartFiles.stream()
.map(this::uploadImage)
.collect(Collectors.toList());
}

@Transactional
public String uploadImage(MultipartFile multipartFile) {
public FileDto uploadImage(MultipartFile multipartFile) {
String uploadDir = "balance-talk-images/balance-option/";
String originalName = multipartFile.getOriginalFilename();
String storedName = String.format("%s_%s", UUID.randomUUID(), originalName);
long contentLength = multipartFile.getSize();
FileType fileType = convertMimeTypeToFileType(multipartFile.getContentType());
try (InputStream inputStream = multipartFile.getInputStream()) {

PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(bucket)
.key(uploadDir + storedName)
.build();

s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(inputStream, contentLength));

File file = File.builder()
.originalName(originalName)
.storedName(storedName)
.path(uploadDir)
.type(fileType)
.size(contentLength)
.build();
File saved = fileRepository.save(file);
try (InputStream inputStream = multipartFile.getInputStream()) {
putObjectToS3(uploadDir + storedName, inputStream, contentLength);
File file = fileRepository.save(createFile(originalName, storedName, uploadDir, fileType, contentLength));

return saved.getPath() + saved.getStoredName();
return FileDto.fromEntity(file);
} catch (IOException e) {
throw new RuntimeException(e); // TODO 예외 처리
throw new BalanceTalkException(ErrorCode.FILE_UPLOAD_FAILED);
}
}

Expand All @@ -76,4 +57,25 @@ private FileType convertMimeTypeToFileType(String mimeType) {
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("지원하지 않는 파일 타입 : " + mimeType));
}

private void putObjectToS3(String key, InputStream inputStream, long contentLength) {
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(bucket)
.key(key)
.build();

s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(inputStream, contentLength));
}

private File createFile(String originalName, String storedName, String uploadDir, FileType fileType,
long contentLength) {

return File.builder()
.originalName(originalName)
.storedName(storedName)
.path(uploadDir)
.type(fileType)
.size(contentLength)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package balancetalk.module.file.domain;

import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface FileRepository extends JpaRepository<File, Long> {

Optional<File> findByStoredName(String storedName);
}
2 changes: 1 addition & 1 deletion src/main/java/balancetalk/module/file/domain/FileType.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package balancetalk.module.file.domain;

public enum FileType {
JPEG("image/jpeg", "jpg"),
JPEG("image/jpeg", "jpeg"),
PNG("image/png", "png"),
GIF("image/gif", "gif"),
BMP("image/bmp", "bmp"),
Expand Down
19 changes: 5 additions & 14 deletions src/main/java/balancetalk/module/file/dto/FileDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import balancetalk.module.file.domain.FileType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import org.springframework.web.multipart.MultipartFile;

@Data
@Builder
Expand All @@ -15,7 +14,7 @@ public class FileDto {
private Long id;

@Schema(description = "사용자가 업로드한 파일명", example = "사진1")
private String uploadName;
private String originalName;

@Schema(description = "서버에 저장되는 파일명", example = "d23d2dqwt1251asbds사진1")
private String storedName;
Expand All @@ -31,7 +30,7 @@ public class FileDto {

public File toEntity() {
return File.builder()
.originalName(uploadName)
.originalName(originalName)
.storedName(storedName)
.path(path)
.type(type)
Expand All @@ -41,20 +40,12 @@ public File toEntity() {

public static FileDto fromEntity(File file) {
return FileDto.builder()
.uploadName(file.getOriginalName())
.id(file.getId())
.originalName(file.getOriginalName())
.storedName(file.getStoredName())
.path(file.getPath())
.type(file.getType())
.size(file.getSize())
.build();
}

public static FileDto of(MultipartFile file, String storedFileName, String path, FileType fileType) {
return FileDto.builder()
.uploadName(file.getOriginalFilename())
.storedName(storedFileName)
.path(path)
.type(fileType)
.size(file.getSize())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,37 +1,22 @@
package balancetalk.module.file.presentation;

import balancetalk.module.file.application.FileService;
import balancetalk.module.file.application.S3UploadService;
import java.util.List;
import balancetalk.module.file.application.FileUploadService;
import balancetalk.module.file.dto.FileDto;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;

@RestController
@RequiredArgsConstructor
@RequestMapping("/files")
public class FileController {
private final FileService fileService;
private final S3UploadService s3UploadService;

@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/upload")
public String uploadImage(@RequestParam("file") MultipartFile file) {
return s3UploadService.uploadImage(file);
}
private final FileUploadService fileUploadService;

@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/upload/multiple")
public List<String> uploadMultipleImages(@RequestParam("file") List<MultipartFile> files) {
return s3UploadService.uploadMultipleImage(files);
}

@ResponseStatus(HttpStatus.OK)
@GetMapping("/download/{fileId}")
public String downloadFile(@PathVariable Long fileId) {
fileService.downloadFile(fileId);
return "파일이 다운로드되었습니다.";
@PostMapping("/image/upload")
public FileDto uploadImage(@RequestParam("file") MultipartFile file) {
return fileUploadService.uploadImage(file);
}
}
Loading