Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ dependencies {
testImplementation 'org.awaitility:awaitility:4.2.0'

// Etc
implementation platform('software.amazon.awssdk:bom:2.41.4')
implementation 'software.amazon.awssdk:s3'
implementation 'org.hibernate.validator:hibernate-validator'
implementation 'com.amazonaws:aws-java-sdk-s3:1.12.782'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.example.solidconnection.mentor.repository.MentorRepository;
import com.example.solidconnection.siteuser.domain.SiteUser;
import com.example.solidconnection.siteuser.repository.SiteUserRepository;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
Expand All @@ -39,6 +40,7 @@
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

@Service
public class ChatService {
Expand Down Expand Up @@ -240,16 +242,19 @@ public void sendChatImage(ChatImageSendRequest chatImageSendRequest, long siteUs
ChatRoom chatRoom = chatRoomRepository.findById(roomId)
.orElseThrow(() -> new CustomException(INVALID_CHAT_ROOM_STATE));

ChatMessage chatMessage = new ChatMessage(
"",
senderId,
chatRoom
);
ChatMessage chatMessage = new ChatMessage("", senderId, chatRoom);

// 이미지 판별을 위한 확장자 리스트
List<String> imageExtensions = Arrays.asList("jpg", "jpeg", "png", "webp");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 상수로 빼는 건 어떤가요 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용하는 게 여기 밖에 없어서 상수로 빼는 게 나을까요??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

상수로 빼서 별도 클래스로 관리하도록 수정했습니당


for (String imageUrl : chatImageSendRequest.imageUrls()) {
String thumbnailUrl = generateThumbnailUrl(imageUrl);
String extension = StringUtils.getFilenameExtension(imageUrl);

ChatAttachment attachment = new ChatAttachment(true, imageUrl, thumbnailUrl, null);
boolean isImage = extension != null && imageExtensions.contains(extension.toLowerCase());

String thumbnailUrl = isImage ? generateThumbnailUrl(imageUrl) : null;

ChatAttachment attachment = new ChatAttachment(isImage, imageUrl, thumbnailUrl, null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thumbnailUrl이 null인 경우에 대해 방어 로직이 존재하나요?? 이번 pr 상에서는 안보여서...

(개인적으로 gif나 avif 이미지 파일 확장자도 잘 쓰인다고 생각해서 확인 한 번 해주시면 감사드리겠습니다!)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제 생각에 해당 부분은 프론트에서 null일 경우 대체 이미지로 보여주는 게 맞는 것 같은데 어떻게 생각하시나요.......?
gif나 avif는 썸네일 생성이 되는지 알아보겠습니당 얘는 람다도 수정해야해서요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확장자 고정해서 수정했습니다

chatMessage.addAttachment(attachment);
}

Expand All @@ -268,11 +273,9 @@ private String generateThumbnailUrl(String originalUrl) {

String thumbnailFileName = nameWithoutExt + "_thumb" + extension;

String thumbnailUrl = originalUrl.replace("chat/images/", "chat/thumbnails/")
return originalUrl.replace("chat/files/", "chat/thumbnails/")
.replace(fileName, thumbnailFileName);

return thumbnailUrl;

} catch (Exception e) {
return originalUrl;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.example.solidconnection.common.constant;

import java.util.List;
import java.util.stream.Stream;

public final class FileConstants {
private FileConstants() {}

public static final List<String> IMAGE_EXTENSIONS = List.of(
"jpg", "jpeg", "png", "webp", "avif", "heic", "heif", "tiff"
);

public static final List<String> DOCUMENT_EXTENSIONS = List.of(
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "hwp", "hwpx", "pdf", "txt"
);

public static final List<String> ARCHIVE_EXTENSIONS = List.of(
"zip", "7z", "rar"
);

public static final List<String> ALL_ALLOWED_EXTENSIONS = Stream.of(
IMAGE_EXTENSIONS, DOCUMENT_EXTENSIONS, ARCHIVE_EXTENSIONS)
.flatMap(List::stream)
.toList();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import com.example.solidconnection.community.post.dto.PostUpdateRequest;
import com.example.solidconnection.community.post.dto.PostUpdateResponse;
import com.example.solidconnection.community.post.repository.PostRepository;
import com.example.solidconnection.s3.domain.ImgType;
import com.example.solidconnection.s3.domain.UploadPath;
import com.example.solidconnection.s3.dto.UploadedFileUrlResponse;
import com.example.solidconnection.s3.service.S3Service;
import com.example.solidconnection.siteuser.domain.SiteUser;
Expand Down Expand Up @@ -88,7 +88,7 @@ private void savePostImages(List<MultipartFile> imageFile, Post post) {
if (imageFile.isEmpty()) {
return;
}
List<UploadedFileUrlResponse> uploadedFileUrlResponseList = s3Service.uploadFiles(imageFile, ImgType.COMMUNITY);
List<UploadedFileUrlResponse> uploadedFileUrlResponseList = s3Service.uploadFiles(imageFile, UploadPath.COMMUNITY);
for (UploadedFileUrlResponse uploadedFileUrlResponse : uploadedFileUrlResponseList) {
PostImage postImage = new PostImage(uploadedFileUrlResponse.fileUrl());
postImage.setPost(post);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import com.example.solidconnection.mentor.domain.MentorApplicationStatus;
import com.example.solidconnection.mentor.dto.MentorApplicationRequest;
import com.example.solidconnection.mentor.repository.MentorApplicationRepository;
import com.example.solidconnection.s3.domain.ImgType;
import com.example.solidconnection.s3.domain.UploadPath;
import com.example.solidconnection.s3.dto.UploadedFileUrlResponse;
import com.example.solidconnection.s3.service.S3Service;
import com.example.solidconnection.siteuser.domain.SiteUser;
Expand Down Expand Up @@ -45,7 +45,7 @@ public void submitMentorApplication(
.orElseThrow(() -> new CustomException(USER_NOT_FOUND));
Term term = termRepository.findByName(mentorApplicationRequest.term())
.orElseThrow(() -> new CustomException(TERM_NOT_FOUND));
UploadedFileUrlResponse uploadedFile = s3Service.uploadFile(file, ImgType.MENTOR_PROOF);
UploadedFileUrlResponse uploadedFile = s3Service.uploadFile(file, UploadPath.MENTOR_PROOF);
MentorApplication mentorApplication = new MentorApplication(
siteUser.getId(),
mentorApplicationRequest.country(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import com.example.solidconnection.news.dto.NewsCreateRequest;
import com.example.solidconnection.news.dto.NewsUpdateRequest;
import com.example.solidconnection.news.repository.NewsRepository;
import com.example.solidconnection.s3.domain.ImgType;
import com.example.solidconnection.s3.domain.UploadPath;
import com.example.solidconnection.s3.dto.UploadedFileUrlResponse;
import com.example.solidconnection.s3.service.S3Service;
import com.example.solidconnection.siteuser.domain.Role;
Expand Down Expand Up @@ -41,7 +41,7 @@ public NewsCommandResponse createNews(long siteUserId, NewsCreateRequest newsCre

private String getImageUrl(MultipartFile imageFile) {
if (imageFile != null && !imageFile.isEmpty()) {
UploadedFileUrlResponse uploadedFile = s3Service.uploadFile(imageFile, ImgType.NEWS);
UploadedFileUrlResponse uploadedFile = s3Service.uploadFile(imageFile, UploadPath.NEWS);
return uploadedFile.fileUrl();
}
return newsProperties.defaultThumbnailUrl();
Expand Down Expand Up @@ -73,7 +73,7 @@ private void updateThumbnail(News news, MultipartFile imageFile, Boolean resetTo
deleteCustomImage(news.getThumbnailUrl());
news.updateThumbnailUrl(newsProperties.defaultThumbnailUrl());
} else if (imageFile != null && !imageFile.isEmpty()) {
UploadedFileUrlResponse uploadedFile = s3Service.uploadFile(imageFile, ImgType.NEWS);
UploadedFileUrlResponse uploadedFile = s3Service.uploadFile(imageFile, UploadPath.NEWS);
deleteCustomImage(news.getThumbnailUrl());
news.updateThumbnailUrl(uploadedFile.fileUrl());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.example.solidconnection.s3.config;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

@Configuration
public class AmazonS3Config {
Expand All @@ -21,12 +21,12 @@ public class AmazonS3Config {
private String region;

@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder
.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(credentials))
public S3Client s3Client() {
AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey);

return S3Client.builder()
.region(Region.of(region))
.credentialsProvider(StaticCredentialsProvider.create(credentials))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.example.solidconnection.s3.controller;

import com.example.solidconnection.common.resolver.AuthorizedUser;
import com.example.solidconnection.s3.domain.ImgType;
import com.example.solidconnection.s3.domain.UploadPath;
import com.example.solidconnection.s3.dto.UploadedFileUrlResponse;
import com.example.solidconnection.s3.dto.urlPrefixResponse;
import com.example.solidconnection.s3.dto.UrlPrefixResponse;
import com.example.solidconnection.s3.service.S3Service;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -39,7 +39,7 @@ public class S3Controller {
public ResponseEntity<UploadedFileUrlResponse> uploadPreProfileImage(
@RequestParam("file") MultipartFile imageFile
) {
UploadedFileUrlResponse profileImageUrl = s3Service.uploadFile(imageFile, ImgType.PROFILE);
UploadedFileUrlResponse profileImageUrl = s3Service.uploadFile(imageFile, UploadPath.PROFILE);
return ResponseEntity.ok(profileImageUrl);
}

Expand All @@ -48,7 +48,7 @@ public ResponseEntity<UploadedFileUrlResponse> uploadPostProfileImage(
@AuthorizedUser long siteUserId,
@RequestParam("file") MultipartFile imageFile
) {
UploadedFileUrlResponse profileImageUrl = s3Service.uploadFile(imageFile, ImgType.PROFILE);
UploadedFileUrlResponse profileImageUrl = s3Service.uploadFile(imageFile, UploadPath.PROFILE);
s3Service.deleteExProfile(siteUserId);
return ResponseEntity.ok(profileImageUrl);
}
Expand All @@ -57,28 +57,28 @@ public ResponseEntity<UploadedFileUrlResponse> uploadPostProfileImage(
public ResponseEntity<UploadedFileUrlResponse> uploadGpaImage(
@RequestParam("file") MultipartFile imageFile
) {
UploadedFileUrlResponse profileImageUrl = s3Service.uploadFile(imageFile, ImgType.GPA);
UploadedFileUrlResponse profileImageUrl = s3Service.uploadFile(imageFile, UploadPath.GPA);
return ResponseEntity.ok(profileImageUrl);
}

@PostMapping("/language-test")
public ResponseEntity<UploadedFileUrlResponse> uploadLanguageImage(
@RequestParam("file") MultipartFile imageFile
) {
UploadedFileUrlResponse profileImageUrl = s3Service.uploadFile(imageFile, ImgType.LANGUAGE_TEST);
UploadedFileUrlResponse profileImageUrl = s3Service.uploadFile(imageFile, UploadPath.LANGUAGE_TEST);
return ResponseEntity.ok(profileImageUrl);
}

@PostMapping("/chat")
public ResponseEntity<List<UploadedFileUrlResponse>> uploadChatImage(
@RequestParam("files") List<MultipartFile> imageFiles
public ResponseEntity<List<UploadedFileUrlResponse>> uploadChatFile(
@RequestParam("files") List<MultipartFile> files
) {
List<UploadedFileUrlResponse> chatImageUrls = s3Service.uploadFiles(imageFiles, ImgType.CHAT);
List<UploadedFileUrlResponse> chatImageUrls = s3Service.uploadFiles(files, UploadPath.CHAT);
return ResponseEntity.ok(chatImageUrls);
}

@GetMapping("/s3-url-prefix")
public ResponseEntity<urlPrefixResponse> getS3UrlPrefix() {
return ResponseEntity.ok(new urlPrefixResponse(s3Default, s3Uploaded, cloudFrontDefault, cloudFrontUploaded));
public ResponseEntity<UrlPrefixResponse> getS3UrlPrefix() {
return ResponseEntity.ok(new UrlPrefixResponse(s3Default, s3Uploaded, cloudFrontDefault, cloudFrontUploaded));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.example.solidconnection.s3.domain;

import com.example.solidconnection.common.constant.FileConstants;
import com.example.solidconnection.common.exception.CustomException;
import com.example.solidconnection.common.exception.ErrorCode;
import lombok.Getter;

@Getter
public enum UploadPath {
PROFILE("profile"),
GPA("gpa"),
LANGUAGE_TEST("language"),
COMMUNITY("community"),
NEWS("news"),
CHAT("chat/files"),
MENTOR_PROOF("mentor-proof"),
;

private final String type;

UploadPath(String type) {
this.type = type;
}

public boolean isResizable(long fileSize, String extension, long maxSizeBytes) {
if (!isImage(extension)) return false;

if (this == CHAT) return false;

return fileSize >= maxSizeBytes;
}
public void validateExtension(String extension) {
if (extension == null || !FileConstants.ALL_ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) {
throw new CustomException(ErrorCode.NOT_ALLOWED_FILE_EXTENSIONS,
"허용된 형식: " + getAllowedExtensionsMessage());
}
}

public boolean isImage(String extension) {
return extension != null && FileConstants.IMAGE_EXTENSIONS.contains(extension.toLowerCase());
}

public String getAllowedExtensionsMessage() {
return String.join(", ", FileConstants.ALL_ALLOWED_EXTENSIONS);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.example.solidconnection.s3.dto;

public record urlPrefixResponse(
public record UrlPrefixResponse(
String s3Default,
String s3Uploaded,
String cloudFrontDefault,
Expand Down
Loading
Loading