Skip to content

Commit

Permalink
feat: 그룹 썸네일 업로드 기능 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
SangWoon123 committed May 22, 2024
1 parent b6f0793 commit 97a7c1e
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

Expand All @@ -24,6 +25,8 @@ public class GroupRoomController {

private final GroupRoomService groupRoomService;

//TODO: 그룹 클릭시 보여지는 데이터

@Operation(summary = "그룹에 속한 유저 조회")
@GetMapping("/{groupId}")
public CommonResponse<?> getUserByGroup(@PathVariable Long groupId) {
Expand All @@ -33,8 +36,10 @@ public CommonResponse<?> getUserByGroup(@PathVariable Long groupId) {

@Operation(summary = "그룹 생성")
@PostMapping()
public CommonResponse<GroupResponse> createGroupRoom(@AuthenticationPrincipal UserInfo userInfo, @RequestBody GroupCreateRequest createGroupRoom) {
GroupResponse groupResponse = groupRoomService.createGroupRoom(userInfo, createGroupRoom);
public CommonResponse<GroupResponse> createGroupRoom(@AuthenticationPrincipal UserInfo userInfo,
@RequestPart(value = "request") GroupCreateRequest createGroupRoom,
@RequestPart(value = "thumbnail") MultipartFile thumbnailFile) {
GroupResponse groupResponse = groupRoomService.createGroupRoom(userInfo, createGroupRoom, thumbnailFile);
return CommonUtils.success(groupResponse);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ public record GroupResponse(
String name,
String description,
String code,
String ownerCode
String ownerCode,
String thumbnailPath
) {
public static GroupResponse from(GroupRoom groupRoom) {
return new GroupResponse(groupRoom.getId(), groupRoom.getName(), groupRoom.getDescription(), groupRoom.getGroupCode(), groupRoom.getOwner());
return new GroupResponse(groupRoom.getId(), groupRoom.getName(), groupRoom.getDescription(), groupRoom.getGroupCode(), groupRoom.getOwner(), groupRoom.getThumbnail());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public class GroupRoom extends BaseEntity {
@Column(name = "group_code", nullable = false, unique = true)
private String groupCode; // 그룹방 고유 식별값

@Column(name = "thumbnail")
private String thumbnail;

@OneToMany(mappedBy = "groupRoom", cascade = CascadeType.ALL, orphanRemoval = true)
private final Set<UserGroup> userGroups = new HashSet<>();

Expand Down Expand Up @@ -72,4 +75,8 @@ public void updateDescription(String description) {
this.description = description;
}

public void updateThumbnail(String thumbnail) {
this.thumbnail = thumbnail;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.tukorea.planding.domain.group.service;

import com.tukorea.planding.domain.group.dto.request.GroupCreateRequest;
import com.tukorea.planding.domain.group.entity.GroupRoom;
import com.tukorea.planding.domain.user.entity.User;
import com.tukorea.planding.global.config.s3.S3Uploader;
import com.tukorea.planding.global.error.BusinessException;
import com.tukorea.planding.global.error.ErrorCode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@Component
@RequiredArgsConstructor
public class GroupRoomFactory {

private final S3Uploader s3Uploader;

public GroupRoom createGroupRoom(GroupCreateRequest createGroupRoom, User user, MultipartFile thumbnailFile) {
GroupRoom newGroupRoom = GroupRoom.createGroupRoom(createGroupRoom, user);

if (thumbnailFile != null && !thumbnailFile.isEmpty()) {
try {
String thumbnailUrl = s3Uploader.saveGroup(thumbnailFile);
newGroupRoom.updateThumbnail(thumbnailUrl);
} catch (IOException e) {
throw new BusinessException(ErrorCode.FILE_UPLOAD_ERROR);
}
}

return newGroupRoom;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
import com.tukorea.planding.domain.user.dto.UserInfo;
import com.tukorea.planding.domain.user.entity.User;
import com.tukorea.planding.domain.user.service.UserQueryService;
import com.tukorea.planding.global.config.s3.S3Uploader;
import com.tukorea.planding.global.error.BusinessException;
import com.tukorea.planding.global.error.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

Expand All @@ -30,14 +33,14 @@ public class GroupRoomService {
private final UserQueryService userQueryService;
private final UserGroupQueryService userGroupQueryService;
private final GroupQueryService groupQueryService;
private final GroupRoomFactory groupRoomFactory;

@Transactional
public GroupResponse createGroupRoom(UserInfo userInfo, GroupCreateRequest createGroupRoom) {
public GroupResponse createGroupRoom(UserInfo userInfo, GroupCreateRequest createGroupRoom, MultipartFile thumbnailFile) {
User user = userQueryService.getUserByUserCode(userInfo.getUserCode());

GroupRoom newGroupRoom = GroupRoom.createGroupRoom(createGroupRoom, user);
GroupRoom newGroupRoom = groupRoomFactory.createGroupRoom(createGroupRoom, user, thumbnailFile);
GroupRoom savedGroupRoom = groupQueryService.createGroup(newGroupRoom);

final UserGroup userGroup = UserGroup.createUserGroup(user, savedGroupRoom);

// 중간테이블에 유저, 그룹 정보 저장
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/com/tukorea/planding/global/config/s3/S3Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.tukorea.planding.global.config.s3;

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;

@Configuration
public class S3Config {
@Value("${cloud.aws.credentials.access-key}")
private String accessKey;
@Value("${cloud.aws.credentials.secret-key}")
private String secretKey;
@Value("${cloud.aws.region.static}")
private String region;

@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCredentials= new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.tukorea.planding.global.config.s3;

import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Optional;
import java.util.UUID;

@RequiredArgsConstructor
@Service
@Slf4j
public class S3Uploader {
private final AmazonS3Client amazonS3Client;

@Value("${cloud.aws.s3.bucket}")
private String bucket;

private final String PROFILE_IMG_DIR = "profile/";
private final String GROUP_THUMBNAIL = "thumbnail/";

public String saveProfile(MultipartFile multipartFile) throws IOException {
File uploadFile = convert(multipartFile)
.orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File 전환 실패"));
return uploadT(uploadFile, PROFILE_IMG_DIR);
}

public String saveGroup(MultipartFile multipartFile) throws IOException {
File uploadFile = convert(multipartFile)
.orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File 전환 실패"));
return uploadT(uploadFile, GROUP_THUMBNAIL);
}

private String uploadT(File uploadFile, String dirName) {
String fileName = dirName + "/" + UUID.randomUUID() + uploadFile.getName();
String uploadImageUrl = putS3(uploadFile, fileName);
removeNewFile(uploadFile); // 로컬에 생성된 File 삭제 (MultipartFile -> File 전환 하며 로컬에 파일 생성됨)
return uploadImageUrl; // 업로드된 파일의 S3 URL 주소 반환
}

private void removeNewFile(File targetFile) {
if (targetFile.delete()) {
log.info("파일이 삭제되었습니다.");
} else {
log.info("파일이 삭제되지 못했습니다.");
}
}

private String putS3(File uploadFile, String fileName) {
amazonS3Client.putObject(
new PutObjectRequest(bucket, fileName, uploadFile)
.withCannedAcl(CannedAccessControlList.PublicRead) // PublicRead 권한으로 업로드 됨
);
return amazonS3Client.getUrl(bucket, fileName).toString();
}

public Optional<File> convert(MultipartFile file) throws IOException {
// mac 환경에서 파일이름에 공백이 허용이 되기때문에 공백을 다른문자로 대체해야함
String newFilename = file.getOriginalFilename().replaceAll("\\s+", "_");

// 임시 파일 생성
File convertFile = Files.createTempFile(newFilename, null).toFile();
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
} catch (IOException e) {
// 파일 변환 실패 시 임시 파일 삭제
convertFile.delete();
throw e;
}
return Optional.of(convertFile);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public enum ErrorCode {
FAVORITE_ALREADY_ADD("GROUP-006", "이미 즐겨찾기에 등록하였습니다.", HttpStatus.UNAUTHORIZED),
FAVORITE_ALREADY_DELETE("GROUP-007", "즐겨찾기에 등록된 그룹이 아닙니다.", HttpStatus.UNAUTHORIZED),
USER_ALREADY_IN_GROUP("GROUP-008", "이미 그룹에 존재하는 유저입니다.", HttpStatus.CONFLICT),
FILE_UPLOAD_ERROR("GROUP-009", "썸네일 업로드중 오류가 발생했습니다.", HttpStatus.BAD_REQUEST),

/**
* Invite Error
Expand Down

0 comments on commit 97a7c1e

Please sign in to comment.