diff --git a/src/main/java/com/example/betteriter/fo_domain/mypage/controller/MypageController.java b/src/main/java/com/example/betteriter/fo_domain/mypage/controller/MypageController.java index abf7b31..f9eb482 100644 --- a/src/main/java/com/example/betteriter/fo_domain/mypage/controller/MypageController.java +++ b/src/main/java/com/example/betteriter/fo_domain/mypage/controller/MypageController.java @@ -1,25 +1,31 @@ package com.example.betteriter.fo_domain.mypage.controller; +import java.util.List; + +import javax.validation.Valid; + +import org.springframework.data.domain.Page; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; import com.example.betteriter.fo_domain.mypage.converter.MypageResponseConverter; +import com.example.betteriter.fo_domain.mypage.dto.MypageRequest; import com.example.betteriter.fo_domain.mypage.dto.MypageResponse; import com.example.betteriter.fo_domain.mypage.service.MypageService; import com.example.betteriter.fo_domain.review.domain.Review; import com.example.betteriter.fo_domain.review.dto.ReviewResponse; import com.example.betteriter.fo_domain.user.domain.Users; import com.example.betteriter.global.common.response.ResponseDto; + import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Page; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; - @Tag(name = "MypageControllers", description = "Mypage API") @Slf4j @@ -143,4 +149,20 @@ public ResponseDto getPointDetail() { Integer totalScrapCount = mypageService.getTotalScrapCount(user); return ResponseDto.onSuccess(MypageResponseConverter.toPointDetailDto(user, totalLikeCount, totalScrapCount)); } + + /** + * user profile 수정 + * + * @param request 수정할 user 정보 + * @return void + */ + @PutMapping("/profile") + public ResponseDto updateUserProfile( + @RequestPart(value = "files") MultipartFile image, + @Valid @RequestPart(value = "key") MypageRequest.UpdateProfileRequest request + ) { + Users user = mypageService.getCurrentUser(); + mypageService.updateUserProfile(user, request, image); + return ResponseDto.onSuccess(null); + } } diff --git a/src/main/java/com/example/betteriter/fo_domain/mypage/dto/MypageRequest.java b/src/main/java/com/example/betteriter/fo_domain/mypage/dto/MypageRequest.java index 80ebd03..7c56a45 100644 --- a/src/main/java/com/example/betteriter/fo_domain/mypage/dto/MypageRequest.java +++ b/src/main/java/com/example/betteriter/fo_domain/mypage/dto/MypageRequest.java @@ -1,5 +1,18 @@ package com.example.betteriter.fo_domain.mypage.dto; +import com.example.betteriter.global.constant.Job; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + public class MypageRequest { + @Getter + @NoArgsConstructor + @AllArgsConstructor + public class UpdateProfileRequest { + private String nickname; + private Job job; + } } diff --git a/src/main/java/com/example/betteriter/fo_domain/mypage/service/MypageService.java b/src/main/java/com/example/betteriter/fo_domain/mypage/service/MypageService.java index b932a31..98ec8ae 100644 --- a/src/main/java/com/example/betteriter/fo_domain/mypage/service/MypageService.java +++ b/src/main/java/com/example/betteriter/fo_domain/mypage/service/MypageService.java @@ -1,18 +1,27 @@ package com.example.betteriter.fo_domain.mypage.service; +import static com.example.betteriter.global.common.code.status.ErrorStatus.*; + import com.example.betteriter.fo_domain.follow.service.FollowService; import com.example.betteriter.fo_domain.mypage.converter.MypageResponseConverter; +import com.example.betteriter.fo_domain.mypage.dto.MypageRequest; import com.example.betteriter.fo_domain.mypage.dto.MypageResponse; +import com.example.betteriter.fo_domain.mypage.exception.MypageHandler; import com.example.betteriter.fo_domain.review.domain.Review; import com.example.betteriter.fo_domain.review.service.ReviewService; import com.example.betteriter.fo_domain.user.domain.Users; +import com.example.betteriter.fo_domain.user.domain.UsersDetail; import com.example.betteriter.fo_domain.user.service.UserService; +import com.example.betteriter.global.common.code.status.ErrorStatus; +import com.example.betteriter.infra.s3.S3Service; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -22,10 +31,11 @@ public class MypageService { private static final int SIZE = 10; - private final UserService userService; + private final ReviewService reviewService; private final FollowService followService; + private final S3Service s3Service; @Transactional(readOnly = true) public Page getMyReviewList(int page) { @@ -106,4 +116,24 @@ public Page getUserReviewList(Long userId, int page) { Users targetUser = userService.getUserById(userId); return reviewService.getReviewList(targetUser, page, SIZE); } + + public void updateUserProfile(Users user, MypageRequest.UpdateProfileRequest request, MultipartFile image) { + // 1. 프로필 이미지 업로드 + String profileImageUrl = this.uploadProfileImage(user, image); + + // 2. 프로필 정보 수정 + UsersDetail detail = user.getUsersDetail(); + detail.updateProfile(request, profileImageUrl); + } + + private String uploadProfileImage(Users user, MultipartFile image) { + this.checkUploadProfileImageRequestValidation(image); + return s3Service.uploadImage(image, user); + } + + private void checkUploadProfileImageRequestValidation(MultipartFile image) { + if(image == null || image.isEmpty()) { + throw new MypageHandler(_IMAGE_FILE_UPLOAD_REQUEST_IS_NOT_VALID); + } + } } diff --git a/src/main/java/com/example/betteriter/fo_domain/user/domain/UsersDetail.java b/src/main/java/com/example/betteriter/fo_domain/user/domain/UsersDetail.java index 6cabef5..3658901 100644 --- a/src/main/java/com/example/betteriter/fo_domain/user/domain/UsersDetail.java +++ b/src/main/java/com/example/betteriter/fo_domain/user/domain/UsersDetail.java @@ -1,5 +1,6 @@ package com.example.betteriter.fo_domain.user.domain; +import com.example.betteriter.fo_domain.mypage.dto.MypageRequest; import com.example.betteriter.global.common.entity.BaseEntity; import com.example.betteriter.global.constant.Job; import lombok.AccessLevel; @@ -44,4 +45,10 @@ private UsersDetail(String nickName, Job job, String profileImage, this.point = point; this.quizCount = quizCount; } + + public void updateProfile(MypageRequest.UpdateProfileRequest request, String profileImageUrl) { + this.nickName = request.getNickname(); + this.job = request.getJob(); + this.profileImage = profileImageUrl; + } } diff --git a/src/main/java/com/example/betteriter/fo_domain/user/service/UserService.java b/src/main/java/com/example/betteriter/fo_domain/user/service/UserService.java index eabaa1e..5bb4b75 100644 --- a/src/main/java/com/example/betteriter/fo_domain/user/service/UserService.java +++ b/src/main/java/com/example/betteriter/fo_domain/user/service/UserService.java @@ -10,10 +10,13 @@ import com.example.betteriter.global.common.code.status.ErrorStatus; import com.example.betteriter.global.util.RedisUtil; import com.example.betteriter.global.util.SecurityUtil; +import com.example.betteriter.infra.s3.S3Service; + 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.util.Arrays; import java.util.stream.Collectors; @@ -30,6 +33,7 @@ public class UserService { private final UsersWithdrawReasonRepository usersWithdrawReasonRepository; private final RedisUtil redisUtil; private final SecurityUtil securityUtil; + private final S3Service s3Service; /* 로그아웃 */ @Transactional @@ -94,4 +98,5 @@ public Users getUserByEmail(String email) { return this.usersRepository.findByEmail(email) .orElseThrow(() -> new UserHandler(ErrorStatus._USER_NOT_FOUND)); } -} \ No newline at end of file + +} diff --git a/src/main/java/com/example/betteriter/infra/s3/ImageUploadService.java b/src/main/java/com/example/betteriter/infra/s3/ImageUploadService.java index 12167d2..a1af3e8 100644 --- a/src/main/java/com/example/betteriter/infra/s3/ImageUploadService.java +++ b/src/main/java/com/example/betteriter/infra/s3/ImageUploadService.java @@ -2,11 +2,15 @@ import com.example.betteriter.fo_domain.review.domain.Review; import com.example.betteriter.fo_domain.review.domain.ReviewImage; +import com.example.betteriter.fo_domain.user.domain.Users; + import org.springframework.web.multipart.MultipartFile; public interface ImageUploadService { ReviewImage uploadImage(MultipartFile image, Review review, int orderNum); + String uploadImage(MultipartFile image, Users user); + void updateImage(MultipartFile multipartFile, ReviewImage reviewImage); } diff --git a/src/main/java/com/example/betteriter/infra/s3/S3Service.java b/src/main/java/com/example/betteriter/infra/s3/S3Service.java index 8c9682a..bd96184 100644 --- a/src/main/java/com/example/betteriter/infra/s3/S3Service.java +++ b/src/main/java/com/example/betteriter/infra/s3/S3Service.java @@ -10,6 +10,8 @@ import com.example.betteriter.fo_domain.review.domain.Review; import com.example.betteriter.fo_domain.review.domain.ReviewImage; import com.example.betteriter.fo_domain.review.exception.ReviewHandler; +import com.example.betteriter.fo_domain.user.domain.Users; + import java.io.InputStream; import java.util.Optional; import java.util.UUID; @@ -59,6 +61,29 @@ public ReviewImage uploadImage(MultipartFile image, Review review, int orderNum) .build(); } + @Override + public String uploadImage(MultipartFile image, Users user) { + String originalFilename = Optional.ofNullable(image.getOriginalFilename()) + .orElseThrow(() -> new ReviewHandler(_IMAGE_FILE_NAME_IS_NOT_EXIST)); + + String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".")); + String fileName = UUID.randomUUID().toString(); + String key = FOLDER + "/" + user.getEmail() + "/" + user.getId().toString() + "/" + fileName + fileExtension; + + ObjectMetadata objectMetaData = new ObjectMetadata(); + objectMetaData.setContentType(image.getContentType()); + + try (InputStream inputStream = image.getInputStream()) { + + s3Client.putObject(new PutObjectRequest(bucketName, key, inputStream, objectMetaData)); + + } catch (Exception e) { + throw new ReviewHandler(_IMAGE_FILE_UPLOAD_FAILED); + } + + return getImageUrl(key); + } + @Override public void updateImage(MultipartFile multipartFile, ReviewImage reviewImage) { validateImageFileExists(multipartFile);